Moodle release 2.7rc1
[moodle.git] / mod / forum / tests / externallib_test.php
CommitLineData
2b9fe87d
MN
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * The module forums external functions unit tests
20 *
21 * @package mod_forum
22 * @category external
23 * @copyright 2012 Mark Nelson <markn@moodle.com>
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30
31require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32
33class mod_forum_external_testcase extends externallib_advanced_testcase {
34
35 /**
36 * Tests set up
37 */
38 protected function setUp() {
39 global $CFG;
40
41 require_once($CFG->dirroot . '/mod/forum/externallib.php');
42 }
43
44 /**
45 * Test get forums
46 */
47 public function test_mod_forum_get_forums_by_courses() {
48 global $USER, $CFG, $DB;
49
50 $this->resetAfterTest(true);
51
52 // Create a user.
53 $user = self::getDataGenerator()->create_user();
54
55 // Set to the user.
56 self::setUser($user);
57
58 // Create courses to add the modules.
59 $course1 = self::getDataGenerator()->create_course();
60 $course2 = self::getDataGenerator()->create_course();
61
62 // First forum.
63 $record = new stdClass();
64 $record->introformat = FORMAT_HTML;
65 $record->course = $course1->id;
66 $forum1 = self::getDataGenerator()->create_module('forum', $record);
67
68 // Second forum.
69 $record = new stdClass();
70 $record->introformat = FORMAT_HTML;
71 $record->course = $course2->id;
72 $forum2 = self::getDataGenerator()->create_module('forum', $record);
73
74 // Check the forum was correctly created.
75 $this->assertEquals(2, $DB->count_records_select('forum', 'id = :forum1 OR id = :forum2',
76 array('forum1' => $forum1->id, 'forum2' => $forum2->id)));
77
78 // Enrol the user in two courses.
909f27ac
JM
79 // DataGenerator->enrol_user automatically sets a role for the user with the permission mod/form:viewdiscussion.
80 $this->getDataGenerator()->enrol_user($user->id, $course1->id, null, 'manual');
81 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
2b9fe87d 82 $enrol = enrol_get_plugin('manual');
2b9fe87d
MN
83 $enrolinstances = enrol_get_instances($course2->id, true);
84 foreach ($enrolinstances as $courseenrolinstance) {
85 if ($courseenrolinstance->enrol == "manual") {
86 $instance2 = $courseenrolinstance;
87 break;
88 }
89 }
90 $enrol->enrol_user($instance2, $user->id);
91
2b9fe87d 92 // Assign capabilities to view forums for forum 2.
74b63eae 93 $cm2 = get_coursemodule_from_id('forum', $forum2->cmid, 0, false, MUST_EXIST);
2b9fe87d
MN
94 $context2 = context_module::instance($cm2->id);
95 $newrole = create_role('Role 2', 'role2', 'Role 2 description');
96 $roleid2 = $this->assignUserCapability('mod/forum:viewdiscussion', $context2->id, $newrole);
97
98 // Create what we expect to be returned when querying the two courses.
99 $expectedforums = array();
100 $expectedforums[$forum1->id] = (array) $forum1;
101 $expectedforums[$forum2->id] = (array) $forum2;
102
103 // Call the external function passing course ids.
104 $forums = mod_forum_external::get_forums_by_courses(array($course1->id, $course2->id));
2b9fe87d 105 external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
a9a0cb69 106 $this->assertEquals($expectedforums, $forums);
2b9fe87d
MN
107
108 // Call the external function without passing course id.
109 $forums = mod_forum_external::get_forums_by_courses();
2b9fe87d 110 external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
a9a0cb69 111 $this->assertEquals($expectedforums, $forums);
2b9fe87d
MN
112
113 // Unenrol user from second course and alter expected forums.
114 $enrol->unenrol_user($instance2, $user->id);
115 unset($expectedforums[$forum2->id]);
116
117 // Call the external function without passing course id.
118 $forums = mod_forum_external::get_forums_by_courses();
2b9fe87d 119 external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
a9a0cb69 120 $this->assertEquals($expectedforums, $forums);
2b9fe87d 121
a9a0cb69
MN
122 // Call for the second course we unenrolled the user from, ensure exception thrown.
123 try {
124 mod_forum_external::get_forums_by_courses(array($course2->id));
125 $this->fail('Exception expected due to being unenrolled from the course.');
126 } catch (moodle_exception $e) {
127 $this->assertEquals('requireloginerror', $e->errorcode);
128 }
129
130 // Call without required capability, ensure exception thrown.
909f27ac 131 $this->unassignUserCapability('mod/forum:viewdiscussion', null, null, $course1->id);
a9a0cb69 132 try {
909f27ac 133 $forums = mod_forum_external::get_forums_by_courses(array($course1->id));
a9a0cb69
MN
134 $this->fail('Exception expected due to missing capability.');
135 } catch (moodle_exception $e) {
136 $this->assertEquals('nopermissions', $e->errorcode);
137 }
138 }
139
140 /**
141 * Test get forum discussions
142 */
143 public function test_mod_forum_get_forum_discussions() {
144 global $USER, $CFG, $DB;
145
146 $this->resetAfterTest(true);
147
148 // Set the CFG variable to allow track forums.
149 $CFG->forum_trackreadposts = true;
150
151 // Create a user who can track forums.
152 $record = new stdClass();
153 $record->trackforums = true;
154 $user1 = self::getDataGenerator()->create_user($record);
155 // Create a bunch of other users to post.
156 $user2 = self::getDataGenerator()->create_user();
157 $user3 = self::getDataGenerator()->create_user();
158 $user4 = self::getDataGenerator()->create_user();
159
160 // Set the first created user to the test user.
161 self::setUser($user1);
162
163 // Create courses to add the modules.
164 $course1 = self::getDataGenerator()->create_course();
165 $course2 = self::getDataGenerator()->create_course();
166
167 // First forum with tracking off.
168 $record = new stdClass();
169 $record->course = $course1->id;
170 $record->trackingtype = FORUM_TRACKING_OFF;
171 $forum1 = self::getDataGenerator()->create_module('forum', $record);
172
173 // Second forum of type 'qanda' with tracking enabled.
174 $record = new stdClass();
175 $record->course = $course2->id;
176 $record->type = 'qanda';
bd8f5d45 177 $record->trackingtype = FORUM_TRACKING_FORCED;
a9a0cb69
MN
178 $forum2 = self::getDataGenerator()->create_module('forum', $record);
179
180 // Third forum where we will only have one discussion with no replies.
181 $record = new stdClass();
182 $record->course = $course2->id;
183 $forum3 = self::getDataGenerator()->create_module('forum', $record);
184
185 // Add discussions to the forums.
186 $record = new stdClass();
187 $record->course = $course1->id;
188 $record->userid = $user1->id;
189 $record->forum = $forum1->id;
c3f31a3d 190 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
a9a0cb69
MN
191
192 $record = new stdClass();
193 $record->course = $course2->id;
194 $record->userid = $user2->id;
195 $record->forum = $forum2->id;
c3f31a3d 196 $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
a9a0cb69
MN
197
198 $record = new stdClass();
199 $record->course = $course2->id;
200 $record->userid = $user2->id;
201 $record->forum = $forum3->id;
c3f31a3d 202 $discussion3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
a9a0cb69
MN
203
204 // Add three replies to the discussion 1 from different users.
205 $record = new stdClass();
206 $record->discussion = $discussion1->id;
207 $record->parent = $discussion1->firstpost;
208 $record->userid = $user2->id;
c3f31a3d 209 $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
2b9fe87d 210
a9a0cb69
MN
211 $record->parent = $discussion1reply1->id;
212 $record->userid = $user3->id;
c3f31a3d 213 $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
a9a0cb69
MN
214
215 $record->userid = $user4->id;
c3f31a3d 216 $discussion1reply3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
a9a0cb69
MN
217
218 // Add two replies to discussion 2 from different users.
219 $record = new stdClass();
220 $record->discussion = $discussion2->id;
221 $record->parent = $discussion2->firstpost;
222 $record->userid = $user1->id;
c3f31a3d 223 $discussion2reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
a9a0cb69
MN
224
225 $record->parent = $discussion2reply1->id;
226 $record->userid = $user3->id;
c3f31a3d 227 $discussion2reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
a9a0cb69
MN
228
229 // Check the forums were correctly created.
230 $this->assertEquals(3, $DB->count_records_select('forum', 'id = :forum1 OR id = :forum2 OR id = :forum3',
231 array('forum1' => $forum1->id, 'forum2' => $forum2->id, 'forum3' => $forum3->id)));
232
233 // Check the discussions were correctly created.
234 $this->assertEquals(3, $DB->count_records_select('forum_discussions', 'forum = :forum1 OR forum = :forum2
235 OR id = :forum3', array('forum1' => $forum1->id, 'forum2' => $forum2->id, 'forum3' => $forum3->id)));
236
237 // Check the posts were correctly created, don't forget each discussion created also creates a post.
238 $this->assertEquals(7, $DB->count_records_select('forum_posts', 'discussion = :discussion1 OR discussion = :discussion2',
239 array('discussion1' => $discussion1->id, 'discussion2' => $discussion2->id)));
240
241 // Enrol the user in the first course.
242 $enrol = enrol_get_plugin('manual');
909f27ac
JM
243 // Following line enrol and assign default role id to the user.
244 // So the user automatically gets mod/forum:viewdiscussion on all forums of the course.
245 $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
a9a0cb69
MN
246
247 // Now enrol into the second course.
909f27ac 248 // We don't use the dataGenerator as we need to get the $instance2 to unenrol later.
a9a0cb69
MN
249 $enrolinstances = enrol_get_instances($course2->id, true);
250 foreach ($enrolinstances as $courseenrolinstance) {
251 if ($courseenrolinstance->enrol == "manual") {
252 $instance2 = $courseenrolinstance;
253 break;
254 }
255 }
256 $enrol->enrol_user($instance2, $user1->id);
257
a9a0cb69 258 // Assign capabilities to view discussions for forum 2.
74b63eae 259 $cm = get_coursemodule_from_id('forum', $forum2->cmid, 0, false, MUST_EXIST);
a9a0cb69
MN
260 $context = context_module::instance($cm->id);
261 $newrole = create_role('Role 2', 'role2', 'Role 2 description');
262 $this->assignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole);
263
264 // Assign capabilities to view discussions for forum 3.
74b63eae 265 $cm = get_coursemodule_from_id('forum', $forum3->cmid, 0, false, MUST_EXIST);
a9a0cb69
MN
266 $context = context_module::instance($cm->id);
267 $this->assignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole);
268
269 // Create what we expect to be returned when querying the forums.
270 $expecteddiscussions = array();
271 $expecteddiscussions[$discussion1->id] = array(
272 'id' => $discussion1->id,
273 'course' => $discussion1->course,
274 'forum' => $discussion1->forum,
275 'name' => $discussion1->name,
276 'firstpost' => $discussion1->firstpost,
277 'userid' => $discussion1->userid,
278 'groupid' => $discussion1->groupid,
279 'assessed' => $discussion1->assessed,
280 'timemodified' => $discussion1reply3->created,
281 'usermodified' => $discussion1reply3->userid,
282 'timestart' => $discussion1->timestart,
283 'timeend' => $discussion1->timeend,
284 'firstuserfullname' => fullname($user1),
285 'firstuserimagealt' => $user1->imagealt,
286 'firstuserpicture' => $user1->picture,
287 'firstuseremail' => $user1->email,
288 'subject' => $discussion1->name,
289 'numreplies' => 3,
290 'numunread' => '',
291 'lastpost' => $discussion1reply3->id,
292 'lastuserid' => $user4->id,
293 'lastuserfullname' => fullname($user4),
294 'lastuserimagealt' => $user4->imagealt,
295 'lastuserpicture' => $user4->picture,
296 'lastuseremail' => $user4->email
297 );
298 $expecteddiscussions[$discussion2->id] = array(
299 'id' => $discussion2->id,
300 'course' => $discussion2->course,
301 'forum' => $discussion2->forum,
302 'name' => $discussion2->name,
303 'firstpost' => $discussion2->firstpost,
304 'userid' => $discussion2->userid,
305 'groupid' => $discussion2->groupid,
306 'assessed' => $discussion2->assessed,
307 'timemodified' => $discussion2reply2->created,
308 'usermodified' => $discussion2reply2->userid,
309 'timestart' => $discussion2->timestart,
310 'timeend' => $discussion2->timeend,
311 'firstuserfullname' => fullname($user2),
312 'firstuserimagealt' => $user2->imagealt,
313 'firstuserpicture' => $user2->picture,
314 'firstuseremail' => $user2->email,
315 'subject' => $discussion2->name,
316 'numreplies' => 2,
317 'numunread' => 3,
318 'lastpost' => $discussion2reply2->id,
319 'lastuserid' => $user3->id,
320 'lastuserfullname' => fullname($user3),
321 'lastuserimagealt' => $user3->imagealt,
322 'lastuserpicture' => $user3->picture,
323 'lastuseremail' => $user3->email
324 );
325 $expecteddiscussions[$discussion3->id] = array(
326 'id' => $discussion3->id,
327 'course' => $discussion3->course,
328 'forum' => $discussion3->forum,
329 'name' => $discussion3->name,
330 'firstpost' => $discussion3->firstpost,
331 'userid' => $discussion3->userid,
332 'groupid' => $discussion3->groupid,
333 'assessed' => $discussion3->assessed,
334 'timemodified' => $discussion3->timemodified,
335 'usermodified' => $discussion3->usermodified,
336 'timestart' => $discussion3->timestart,
337 'timeend' => $discussion3->timeend,
338 'firstuserfullname' => fullname($user2),
339 'firstuserimagealt' => $user2->imagealt,
340 'firstuserpicture' => $user2->picture,
341 'firstuseremail' => $user2->email,
342 'subject' => $discussion3->name,
343 'numreplies' => 0,
344 'numunread' => 1,
345 'lastpost' => $discussion3->firstpost,
346 'lastuserid' => $user2->id,
347 'lastuserfullname' => fullname($user2),
348 'lastuserimagealt' => $user2->imagealt,
349 'lastuserpicture' => $user2->picture,
350 'lastuseremail' => $user2->email
351 );
352
353 // Call the external function passing forum ids.
354 $discussions = mod_forum_external::get_forum_discussions(array($forum1->id, $forum2->id, $forum3->id));
355 external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_returns(), $discussions);
356 $this->assertEquals($expecteddiscussions, $discussions);
357
358 // Remove the users post from the qanda forum and ensure they can not return the discussion.
359 $DB->delete_records('forum_posts', array('id' => $discussion2reply1->id));
360 try {
361 mod_forum_external::get_forum_discussions(array($forum2->id));
362 $this->fail('Exception expected due to attempting to access qanda forum without posting.');
363 } catch (moodle_exception $e) {
364 $this->assertEquals('nopermissions', $e->errorcode);
365 }
366
367 // Call without required view discussion capability.
909f27ac 368 $this->unassignUserCapability('mod/forum:viewdiscussion', null, null, $course1->id);
a9a0cb69
MN
369 try {
370 mod_forum_external::get_forum_discussions(array($forum1->id));
371 $this->fail('Exception expected due to missing capability.');
372 } catch (moodle_exception $e) {
373 $this->assertEquals('nopermissions', $e->errorcode);
374 }
375
376 // Unenrol user from second course.
377 $enrol->unenrol_user($instance2, $user1->id);
378
379 // Call for the second course we unenrolled the user from, make sure exception thrown.
380 try {
381 mod_forum_external::get_forum_discussions(array($forum2->id));
382 $this->fail('Exception expected due to being unenrolled from the course.');
383 } catch (moodle_exception $e) {
384 $this->assertEquals('requireloginerror', $e->errorcode);
385 }
2b9fe87d
MN
386 }
387}