Commit | Line | Data |
---|---|---|
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 | ||
27 | defined('MOODLE_INTERNAL') || die(); | |
28 | ||
29 | global $CFG; | |
30 | ||
31 | require_once($CFG->dirroot . '/webservice/tests/helpers.php'); | |
32 | ||
33 | class mod_forum_external_testcase extends externallib_advanced_testcase { | |
34 | ||
35 | /** | |
36 | * Tests set up | |
37 | */ | |
38 | protected function setUp() { | |
39 | global $CFG; | |
40 | ||
59075a43 AN |
41 | // We must clear the subscription caches. This has to be done both before each test, and after in case of other |
42 | // tests using these functions. | |
43 | \mod_forum\subscriptions::reset_forum_cache(); | |
44 | ||
2b9fe87d MN |
45 | require_once($CFG->dirroot . '/mod/forum/externallib.php'); |
46 | } | |
47 | ||
59075a43 AN |
48 | public function tearDown() { |
49 | // We must clear the subscription caches. This has to be done both before each test, and after in case of other | |
50 | // tests using these functions. | |
51 | \mod_forum\subscriptions::reset_forum_cache(); | |
52 | } | |
53 | ||
2b9fe87d MN |
54 | /** |
55 | * Test get forums | |
56 | */ | |
57 | public function test_mod_forum_get_forums_by_courses() { | |
58 | global $USER, $CFG, $DB; | |
59 | ||
60 | $this->resetAfterTest(true); | |
61 | ||
62 | // Create a user. | |
63 | $user = self::getDataGenerator()->create_user(); | |
64 | ||
65 | // Set to the user. | |
66 | self::setUser($user); | |
67 | ||
68 | // Create courses to add the modules. | |
69 | $course1 = self::getDataGenerator()->create_course(); | |
70 | $course2 = self::getDataGenerator()->create_course(); | |
71 | ||
72 | // First forum. | |
73 | $record = new stdClass(); | |
74 | $record->introformat = FORMAT_HTML; | |
75 | $record->course = $course1->id; | |
76 | $forum1 = self::getDataGenerator()->create_module('forum', $record); | |
77 | ||
78 | // Second forum. | |
79 | $record = new stdClass(); | |
80 | $record->introformat = FORMAT_HTML; | |
81 | $record->course = $course2->id; | |
82 | $forum2 = self::getDataGenerator()->create_module('forum', $record); | |
83 | ||
7ea6ada3 JL |
84 | // Add discussions to the forums. |
85 | $record = new stdClass(); | |
86 | $record->course = $course1->id; | |
87 | $record->userid = $user->id; | |
88 | $record->forum = $forum1->id; | |
89 | $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
90 | // Expect one discussion. | |
91 | $forum1->numdiscussions = 1; | |
92 | ||
93 | $record = new stdClass(); | |
94 | $record->course = $course2->id; | |
95 | $record->userid = $user->id; | |
96 | $record->forum = $forum2->id; | |
97 | $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
98 | $discussion3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
99 | // Expect two discussions. | |
100 | $forum2->numdiscussions = 2; | |
101 | ||
2b9fe87d MN |
102 | // Check the forum was correctly created. |
103 | $this->assertEquals(2, $DB->count_records_select('forum', 'id = :forum1 OR id = :forum2', | |
104 | array('forum1' => $forum1->id, 'forum2' => $forum2->id))); | |
105 | ||
106 | // Enrol the user in two courses. | |
909f27ac JM |
107 | // DataGenerator->enrol_user automatically sets a role for the user with the permission mod/form:viewdiscussion. |
108 | $this->getDataGenerator()->enrol_user($user->id, $course1->id, null, 'manual'); | |
109 | // Execute real Moodle enrolment as we'll call unenrol() method on the instance later. | |
2b9fe87d | 110 | $enrol = enrol_get_plugin('manual'); |
2b9fe87d MN |
111 | $enrolinstances = enrol_get_instances($course2->id, true); |
112 | foreach ($enrolinstances as $courseenrolinstance) { | |
113 | if ($courseenrolinstance->enrol == "manual") { | |
114 | $instance2 = $courseenrolinstance; | |
115 | break; | |
116 | } | |
117 | } | |
118 | $enrol->enrol_user($instance2, $user->id); | |
119 | ||
2b9fe87d | 120 | // Assign capabilities to view forums for forum 2. |
74b63eae | 121 | $cm2 = get_coursemodule_from_id('forum', $forum2->cmid, 0, false, MUST_EXIST); |
2b9fe87d MN |
122 | $context2 = context_module::instance($cm2->id); |
123 | $newrole = create_role('Role 2', 'role2', 'Role 2 description'); | |
124 | $roleid2 = $this->assignUserCapability('mod/forum:viewdiscussion', $context2->id, $newrole); | |
125 | ||
126 | // Create what we expect to be returned when querying the two courses. | |
c8f1d8a0 JL |
127 | unset($forum1->displaywordcount); |
128 | unset($forum2->displaywordcount); | |
129 | ||
2b9fe87d MN |
130 | $expectedforums = array(); |
131 | $expectedforums[$forum1->id] = (array) $forum1; | |
132 | $expectedforums[$forum2->id] = (array) $forum2; | |
133 | ||
134 | // Call the external function passing course ids. | |
135 | $forums = mod_forum_external::get_forums_by_courses(array($course1->id, $course2->id)); | |
c8f1d8a0 JL |
136 | $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums); |
137 | $this->assertCount(2, $forums); | |
138 | foreach ($forums as $forum) { | |
139 | $this->assertEquals($expectedforums[$forum['id']], $forum); | |
140 | } | |
2b9fe87d MN |
141 | |
142 | // Call the external function without passing course id. | |
143 | $forums = mod_forum_external::get_forums_by_courses(); | |
c8f1d8a0 JL |
144 | $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums); |
145 | $this->assertCount(2, $forums); | |
146 | foreach ($forums as $forum) { | |
147 | $this->assertEquals($expectedforums[$forum['id']], $forum); | |
148 | } | |
2b9fe87d MN |
149 | |
150 | // Unenrol user from second course and alter expected forums. | |
151 | $enrol->unenrol_user($instance2, $user->id); | |
152 | unset($expectedforums[$forum2->id]); | |
153 | ||
154 | // Call the external function without passing course id. | |
155 | $forums = mod_forum_external::get_forums_by_courses(); | |
c8f1d8a0 JL |
156 | $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums); |
157 | $this->assertCount(1, $forums); | |
158 | $this->assertEquals($expectedforums[$forum1->id], $forums[0]); | |
159 | ||
160 | // Call for the second course we unenrolled the user from. | |
161 | $forums = mod_forum_external::get_forums_by_courses(array($course2->id)); | |
162 | $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums); | |
163 | $this->assertCount(0, $forums); | |
a9a0cb69 MN |
164 | } |
165 | ||
166 | /** | |
167 | * Test get forum discussions | |
168 | */ | |
169 | public function test_mod_forum_get_forum_discussions() { | |
170 | global $USER, $CFG, $DB; | |
171 | ||
172 | $this->resetAfterTest(true); | |
173 | ||
174 | // Set the CFG variable to allow track forums. | |
175 | $CFG->forum_trackreadposts = true; | |
176 | ||
177 | // Create a user who can track forums. | |
178 | $record = new stdClass(); | |
179 | $record->trackforums = true; | |
180 | $user1 = self::getDataGenerator()->create_user($record); | |
181 | // Create a bunch of other users to post. | |
182 | $user2 = self::getDataGenerator()->create_user(); | |
183 | $user3 = self::getDataGenerator()->create_user(); | |
184 | $user4 = self::getDataGenerator()->create_user(); | |
185 | ||
186 | // Set the first created user to the test user. | |
187 | self::setUser($user1); | |
188 | ||
189 | // Create courses to add the modules. | |
190 | $course1 = self::getDataGenerator()->create_course(); | |
191 | $course2 = self::getDataGenerator()->create_course(); | |
192 | ||
193 | // First forum with tracking off. | |
194 | $record = new stdClass(); | |
195 | $record->course = $course1->id; | |
196 | $record->trackingtype = FORUM_TRACKING_OFF; | |
197 | $forum1 = self::getDataGenerator()->create_module('forum', $record); | |
198 | ||
199 | // Second forum of type 'qanda' with tracking enabled. | |
200 | $record = new stdClass(); | |
201 | $record->course = $course2->id; | |
202 | $record->type = 'qanda'; | |
bd8f5d45 | 203 | $record->trackingtype = FORUM_TRACKING_FORCED; |
a9a0cb69 MN |
204 | $forum2 = self::getDataGenerator()->create_module('forum', $record); |
205 | ||
a9a0cb69 MN |
206 | // Add discussions to the forums. |
207 | $record = new stdClass(); | |
208 | $record->course = $course1->id; | |
209 | $record->userid = $user1->id; | |
210 | $record->forum = $forum1->id; | |
c3f31a3d | 211 | $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); |
a9a0cb69 MN |
212 | |
213 | $record = new stdClass(); | |
214 | $record->course = $course2->id; | |
215 | $record->userid = $user2->id; | |
216 | $record->forum = $forum2->id; | |
c3f31a3d | 217 | $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); |
a9a0cb69 | 218 | |
a9a0cb69 MN |
219 | // Add three replies to the discussion 1 from different users. |
220 | $record = new stdClass(); | |
221 | $record->discussion = $discussion1->id; | |
222 | $record->parent = $discussion1->firstpost; | |
223 | $record->userid = $user2->id; | |
c3f31a3d | 224 | $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); |
2b9fe87d | 225 | |
a9a0cb69 MN |
226 | $record->parent = $discussion1reply1->id; |
227 | $record->userid = $user3->id; | |
c3f31a3d | 228 | $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); |
a9a0cb69 MN |
229 | |
230 | $record->userid = $user4->id; | |
c3f31a3d | 231 | $discussion1reply3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); |
a9a0cb69 MN |
232 | |
233 | // Add two replies to discussion 2 from different users. | |
234 | $record = new stdClass(); | |
235 | $record->discussion = $discussion2->id; | |
236 | $record->parent = $discussion2->firstpost; | |
237 | $record->userid = $user1->id; | |
c3f31a3d | 238 | $discussion2reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); |
a9a0cb69 MN |
239 | |
240 | $record->parent = $discussion2reply1->id; | |
241 | $record->userid = $user3->id; | |
c3f31a3d | 242 | $discussion2reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); |
a9a0cb69 MN |
243 | |
244 | // Check the forums were correctly created. | |
40afeb40 JL |
245 | $this->assertEquals(2, $DB->count_records_select('forum', 'id = :forum1 OR id = :forum2', |
246 | array('forum1' => $forum1->id, 'forum2' => $forum2->id))); | |
a9a0cb69 MN |
247 | |
248 | // Check the discussions were correctly created. | |
40afeb40 JL |
249 | $this->assertEquals(2, $DB->count_records_select('forum_discussions', 'forum = :forum1 OR forum = :forum2', |
250 | array('forum1' => $forum1->id, 'forum2' => $forum2->id))); | |
a9a0cb69 MN |
251 | |
252 | // Check the posts were correctly created, don't forget each discussion created also creates a post. | |
253 | $this->assertEquals(7, $DB->count_records_select('forum_posts', 'discussion = :discussion1 OR discussion = :discussion2', | |
254 | array('discussion1' => $discussion1->id, 'discussion2' => $discussion2->id))); | |
255 | ||
256 | // Enrol the user in the first course. | |
257 | $enrol = enrol_get_plugin('manual'); | |
909f27ac JM |
258 | // Following line enrol and assign default role id to the user. |
259 | // So the user automatically gets mod/forum:viewdiscussion on all forums of the course. | |
260 | $this->getDataGenerator()->enrol_user($user1->id, $course1->id); | |
a9a0cb69 MN |
261 | |
262 | // Now enrol into the second course. | |
909f27ac | 263 | // We don't use the dataGenerator as we need to get the $instance2 to unenrol later. |
a9a0cb69 MN |
264 | $enrolinstances = enrol_get_instances($course2->id, true); |
265 | foreach ($enrolinstances as $courseenrolinstance) { | |
266 | if ($courseenrolinstance->enrol == "manual") { | |
267 | $instance2 = $courseenrolinstance; | |
268 | break; | |
269 | } | |
270 | } | |
271 | $enrol->enrol_user($instance2, $user1->id); | |
272 | ||
a9a0cb69 | 273 | // Assign capabilities to view discussions for forum 2. |
74b63eae | 274 | $cm = get_coursemodule_from_id('forum', $forum2->cmid, 0, false, MUST_EXIST); |
a9a0cb69 MN |
275 | $context = context_module::instance($cm->id); |
276 | $newrole = create_role('Role 2', 'role2', 'Role 2 description'); | |
277 | $this->assignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole); | |
278 | ||
a9a0cb69 MN |
279 | // Create what we expect to be returned when querying the forums. |
280 | $expecteddiscussions = array(); | |
9a3f7a48 | 281 | $expecteddiscussions[] = array( |
a9a0cb69 MN |
282 | 'id' => $discussion1->id, |
283 | 'course' => $discussion1->course, | |
284 | 'forum' => $discussion1->forum, | |
285 | 'name' => $discussion1->name, | |
286 | 'firstpost' => $discussion1->firstpost, | |
287 | 'userid' => $discussion1->userid, | |
288 | 'groupid' => $discussion1->groupid, | |
289 | 'assessed' => $discussion1->assessed, | |
290 | 'timemodified' => $discussion1reply3->created, | |
291 | 'usermodified' => $discussion1reply3->userid, | |
292 | 'timestart' => $discussion1->timestart, | |
293 | 'timeend' => $discussion1->timeend, | |
294 | 'firstuserfullname' => fullname($user1), | |
295 | 'firstuserimagealt' => $user1->imagealt, | |
296 | 'firstuserpicture' => $user1->picture, | |
297 | 'firstuseremail' => $user1->email, | |
298 | 'subject' => $discussion1->name, | |
299 | 'numreplies' => 3, | |
300 | 'numunread' => '', | |
301 | 'lastpost' => $discussion1reply3->id, | |
302 | 'lastuserid' => $user4->id, | |
303 | 'lastuserfullname' => fullname($user4), | |
304 | 'lastuserimagealt' => $user4->imagealt, | |
305 | 'lastuserpicture' => $user4->picture, | |
306 | 'lastuseremail' => $user4->email | |
307 | ); | |
9a3f7a48 | 308 | $expecteddiscussions[] = array( |
a9a0cb69 MN |
309 | 'id' => $discussion2->id, |
310 | 'course' => $discussion2->course, | |
311 | 'forum' => $discussion2->forum, | |
312 | 'name' => $discussion2->name, | |
313 | 'firstpost' => $discussion2->firstpost, | |
314 | 'userid' => $discussion2->userid, | |
315 | 'groupid' => $discussion2->groupid, | |
316 | 'assessed' => $discussion2->assessed, | |
317 | 'timemodified' => $discussion2reply2->created, | |
318 | 'usermodified' => $discussion2reply2->userid, | |
319 | 'timestart' => $discussion2->timestart, | |
320 | 'timeend' => $discussion2->timeend, | |
321 | 'firstuserfullname' => fullname($user2), | |
322 | 'firstuserimagealt' => $user2->imagealt, | |
323 | 'firstuserpicture' => $user2->picture, | |
324 | 'firstuseremail' => $user2->email, | |
325 | 'subject' => $discussion2->name, | |
326 | 'numreplies' => 2, | |
327 | 'numunread' => 3, | |
328 | 'lastpost' => $discussion2reply2->id, | |
329 | 'lastuserid' => $user3->id, | |
330 | 'lastuserfullname' => fullname($user3), | |
331 | 'lastuserimagealt' => $user3->imagealt, | |
332 | 'lastuserpicture' => $user3->picture, | |
333 | 'lastuseremail' => $user3->email | |
334 | ); | |
a9a0cb69 MN |
335 | |
336 | // Call the external function passing forum ids. | |
40afeb40 | 337 | $discussions = mod_forum_external::get_forum_discussions(array($forum1->id, $forum2->id)); |
9a3f7a48 | 338 | $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_returns(), $discussions); |
a9a0cb69 | 339 | $this->assertEquals($expecteddiscussions, $discussions); |
40afeb40 JL |
340 | // Some debugging is going to be produced, this is because we switch PAGE contexts in the get_forum_discussions function, |
341 | // the switch happens when the validate_context function is called inside a foreach loop. | |
342 | // See MDL-41746 for more information. | |
343 | $this->assertDebuggingCalled(); | |
a9a0cb69 | 344 | |
039c81f0 | 345 | // Remove the users post from the qanda forum and ensure they can still see the discussion. |
a9a0cb69 | 346 | $DB->delete_records('forum_posts', array('id' => $discussion2reply1->id)); |
40afeb40 JL |
347 | $discussions = mod_forum_external::get_forum_discussions(array($forum2->id)); |
348 | $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_returns(), $discussions); | |
039c81f0 | 349 | $this->assertEquals(1, count($discussions)); |
a9a0cb69 MN |
350 | |
351 | // Call without required view discussion capability. | |
909f27ac | 352 | $this->unassignUserCapability('mod/forum:viewdiscussion', null, null, $course1->id); |
a9a0cb69 MN |
353 | try { |
354 | mod_forum_external::get_forum_discussions(array($forum1->id)); | |
355 | $this->fail('Exception expected due to missing capability.'); | |
356 | } catch (moodle_exception $e) { | |
357 | $this->assertEquals('nopermissions', $e->errorcode); | |
358 | } | |
40afeb40 | 359 | $this->assertDebuggingCalled(); |
a9a0cb69 MN |
360 | |
361 | // Unenrol user from second course. | |
362 | $enrol->unenrol_user($instance2, $user1->id); | |
363 | ||
364 | // Call for the second course we unenrolled the user from, make sure exception thrown. | |
365 | try { | |
366 | mod_forum_external::get_forum_discussions(array($forum2->id)); | |
367 | $this->fail('Exception expected due to being unenrolled from the course.'); | |
368 | } catch (moodle_exception $e) { | |
369 | $this->assertEquals('requireloginerror', $e->errorcode); | |
370 | } | |
2b9fe87d | 371 | } |
e2ede426 JL |
372 | |
373 | /** | |
374 | * Test get forum posts | |
375 | */ | |
376 | public function test_mod_forum_get_forum_discussion_posts() { | |
377 | global $CFG; | |
378 | ||
379 | $this->resetAfterTest(true); | |
380 | ||
381 | // Set the CFG variable to allow track forums. | |
382 | $CFG->forum_trackreadposts = true; | |
383 | ||
384 | // Create a user who can track forums. | |
385 | $record = new stdClass(); | |
386 | $record->trackforums = true; | |
387 | $user1 = self::getDataGenerator()->create_user($record); | |
388 | // Create a bunch of other users to post. | |
389 | $user2 = self::getDataGenerator()->create_user(); | |
390 | $user3 = self::getDataGenerator()->create_user(); | |
391 | ||
392 | // Set the first created user to the test user. | |
393 | self::setUser($user1); | |
394 | ||
395 | // Create course to add the module. | |
396 | $course1 = self::getDataGenerator()->create_course(); | |
397 | ||
398 | // Forum with tracking off. | |
399 | $record = new stdClass(); | |
400 | $record->course = $course1->id; | |
401 | $record->trackingtype = FORUM_TRACKING_OFF; | |
402 | $forum1 = self::getDataGenerator()->create_module('forum', $record); | |
403 | $forum1context = context_module::instance($forum1->cmid); | |
404 | ||
405 | // Add discussions to the forums. | |
406 | $record = new stdClass(); | |
407 | $record->course = $course1->id; | |
408 | $record->userid = $user1->id; | |
409 | $record->forum = $forum1->id; | |
410 | $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
411 | ||
412 | $record = new stdClass(); | |
413 | $record->course = $course1->id; | |
414 | $record->userid = $user2->id; | |
415 | $record->forum = $forum1->id; | |
416 | $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
417 | ||
418 | // Add 2 replies to the discussion 1 from different users. | |
419 | $record = new stdClass(); | |
420 | $record->discussion = $discussion1->id; | |
421 | $record->parent = $discussion1->firstpost; | |
422 | $record->userid = $user2->id; | |
423 | $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
424 | ||
425 | $record->parent = $discussion1reply1->id; | |
426 | $record->userid = $user3->id; | |
427 | $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
428 | ||
429 | // Enrol the user in the course. | |
430 | $enrol = enrol_get_plugin('manual'); | |
431 | // Following line enrol and assign default role id to the user. | |
432 | // So the user automatically gets mod/forum:viewdiscussion on all forums of the course. | |
433 | $this->getDataGenerator()->enrol_user($user1->id, $course1->id); | |
434 | $this->getDataGenerator()->enrol_user($user2->id, $course1->id); | |
81f810dc JL |
435 | |
436 | // Delete one user, to test that we still receive posts by this user. | |
437 | delete_user($user3); | |
e2ede426 JL |
438 | |
439 | // Create what we expect to be returned when querying the discussion. | |
440 | $expectedposts = array( | |
441 | 'posts' => array(), | |
442 | 'warnings' => array(), | |
443 | ); | |
694bf0c7 | 444 | |
81f810dc JL |
445 | // Empty picture since it's a user deleted (user3). |
446 | $userpictureurl = ''; | |
694bf0c7 | 447 | |
e2ede426 JL |
448 | $expectedposts['posts'][] = array( |
449 | 'id' => $discussion1reply2->id, | |
450 | 'discussion' => $discussion1reply2->discussion, | |
451 | 'parent' => $discussion1reply2->parent, | |
48fb0250 | 452 | 'userid' => (int) $discussion1reply2->userid, |
e2ede426 JL |
453 | 'created' => $discussion1reply2->created, |
454 | 'modified' => $discussion1reply2->modified, | |
455 | 'mailed' => $discussion1reply2->mailed, | |
456 | 'subject' => $discussion1reply2->subject, | |
457 | 'message' => file_rewrite_pluginfile_urls($discussion1reply2->message, 'pluginfile.php', | |
458 | $forum1context->id, 'mod_forum', 'post', $discussion1reply2->id), | |
48fb0250 | 459 | 'messageformat' => 1, // This value is usually changed by external_format_text() function. |
e2ede426 JL |
460 | 'messagetrust' => $discussion1reply2->messagetrust, |
461 | 'attachment' => $discussion1reply2->attachment, | |
462 | 'totalscore' => $discussion1reply2->totalscore, | |
463 | 'mailnow' => $discussion1reply2->mailnow, | |
464 | 'children' => array(), | |
465 | 'canreply' => true, | |
466 | 'postread' => false, | |
694bf0c7 JL |
467 | 'userfullname' => fullname($user3), |
468 | 'userpictureurl' => $userpictureurl | |
e2ede426 | 469 | ); |
694bf0c7 | 470 | |
da1be050 JL |
471 | $userpictureurl = moodle_url::make_webservice_pluginfile_url( |
472 | context_user::instance($discussion1reply1->userid)->id, 'user', 'icon', null, '/', 'f1')->out(false); | |
694bf0c7 | 473 | |
e2ede426 JL |
474 | $expectedposts['posts'][] = array( |
475 | 'id' => $discussion1reply1->id, | |
476 | 'discussion' => $discussion1reply1->discussion, | |
477 | 'parent' => $discussion1reply1->parent, | |
48fb0250 | 478 | 'userid' => (int) $discussion1reply1->userid, |
e2ede426 JL |
479 | 'created' => $discussion1reply1->created, |
480 | 'modified' => $discussion1reply1->modified, | |
481 | 'mailed' => $discussion1reply1->mailed, | |
482 | 'subject' => $discussion1reply1->subject, | |
483 | 'message' => file_rewrite_pluginfile_urls($discussion1reply1->message, 'pluginfile.php', | |
484 | $forum1context->id, 'mod_forum', 'post', $discussion1reply1->id), | |
48fb0250 | 485 | 'messageformat' => 1, // This value is usually changed by external_format_text() function. |
e2ede426 JL |
486 | 'messagetrust' => $discussion1reply1->messagetrust, |
487 | 'attachment' => $discussion1reply1->attachment, | |
488 | 'totalscore' => $discussion1reply1->totalscore, | |
489 | 'mailnow' => $discussion1reply1->mailnow, | |
d2c58b95 | 490 | 'children' => array($discussion1reply2->id), |
e2ede426 JL |
491 | 'canreply' => true, |
492 | 'postread' => false, | |
694bf0c7 JL |
493 | 'userfullname' => fullname($user2), |
494 | 'userpictureurl' => $userpictureurl | |
e2ede426 JL |
495 | ); |
496 | ||
497 | // Test a discussion with two additional posts (total 3 posts). | |
498 | $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC'); | |
499 | $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); | |
500 | $this->assertEquals(3, count($posts['posts'])); | |
501 | ||
502 | // Unset the initial discussion post. | |
503 | array_pop($posts['posts']); | |
504 | $this->assertEquals($expectedposts, $posts); | |
505 | ||
506 | // Test discussion without additional posts. There should be only one post (the one created by the discussion). | |
507 | $posts = mod_forum_external::get_forum_discussion_posts($discussion2->id, 'modified', 'DESC'); | |
508 | $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); | |
509 | $this->assertEquals(1, count($posts['posts'])); | |
510 | ||
511 | } | |
c2586672 | 512 | |
b1aa7dfa JL |
513 | /** |
514 | * Test get forum posts (qanda forum) | |
515 | */ | |
516 | public function test_mod_forum_get_forum_discussion_posts_qanda() { | |
517 | global $CFG, $DB; | |
518 | ||
519 | $this->resetAfterTest(true); | |
520 | ||
521 | $record = new stdClass(); | |
522 | $user1 = self::getDataGenerator()->create_user($record); | |
523 | $user2 = self::getDataGenerator()->create_user(); | |
524 | ||
525 | // Set the first created user to the test user. | |
526 | self::setUser($user1); | |
527 | ||
528 | // Create course to add the module. | |
529 | $course1 = self::getDataGenerator()->create_course(); | |
530 | $this->getDataGenerator()->enrol_user($user1->id, $course1->id); | |
531 | $this->getDataGenerator()->enrol_user($user2->id, $course1->id); | |
532 | ||
533 | // Forum with tracking off. | |
534 | $record = new stdClass(); | |
535 | $record->course = $course1->id; | |
536 | $record->type = 'qanda'; | |
537 | $forum1 = self::getDataGenerator()->create_module('forum', $record); | |
538 | $forum1context = context_module::instance($forum1->cmid); | |
539 | ||
540 | // Add discussions to the forums. | |
541 | $record = new stdClass(); | |
542 | $record->course = $course1->id; | |
543 | $record->userid = $user2->id; | |
544 | $record->forum = $forum1->id; | |
545 | $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
546 | ||
547 | // Add 1 reply (not the actual user). | |
548 | $record = new stdClass(); | |
549 | $record->discussion = $discussion1->id; | |
550 | $record->parent = $discussion1->firstpost; | |
551 | $record->userid = $user2->id; | |
552 | $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
553 | ||
554 | // We still see only the original post. | |
555 | $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC'); | |
556 | $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); | |
557 | $this->assertEquals(1, count($posts['posts'])); | |
558 | ||
559 | // Add a new reply, the user is going to be able to see only the original post and their new post. | |
560 | $record = new stdClass(); | |
561 | $record->discussion = $discussion1->id; | |
562 | $record->parent = $discussion1->firstpost; | |
563 | $record->userid = $user1->id; | |
564 | $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
565 | ||
566 | $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC'); | |
567 | $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); | |
568 | $this->assertEquals(2, count($posts['posts'])); | |
569 | ||
570 | // Now, we can fake the time of the user post, so he can se the rest of the discussion posts. | |
571 | $discussion1reply2->created -= $CFG->maxeditingtime * 2; | |
572 | $DB->update_record('forum_posts', $discussion1reply2); | |
573 | ||
574 | $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC'); | |
575 | $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); | |
576 | $this->assertEquals(3, count($posts['posts'])); | |
b1aa7dfa JL |
577 | } |
578 | ||
c2586672 JL |
579 | /** |
580 | * Test get forum discussions paginated | |
581 | */ | |
582 | public function test_mod_forum_get_forum_discussions_paginated() { | |
583 | global $USER, $CFG, $DB; | |
584 | ||
585 | $this->resetAfterTest(true); | |
586 | ||
587 | // Set the CFG variable to allow track forums. | |
588 | $CFG->forum_trackreadposts = true; | |
589 | ||
590 | // Create a user who can track forums. | |
591 | $record = new stdClass(); | |
592 | $record->trackforums = true; | |
593 | $user1 = self::getDataGenerator()->create_user($record); | |
594 | // Create a bunch of other users to post. | |
595 | $user2 = self::getDataGenerator()->create_user(); | |
596 | $user3 = self::getDataGenerator()->create_user(); | |
597 | $user4 = self::getDataGenerator()->create_user(); | |
598 | ||
599 | // Set the first created user to the test user. | |
600 | self::setUser($user1); | |
601 | ||
602 | // Create courses to add the modules. | |
603 | $course1 = self::getDataGenerator()->create_course(); | |
604 | ||
605 | // First forum with tracking off. | |
606 | $record = new stdClass(); | |
607 | $record->course = $course1->id; | |
608 | $record->trackingtype = FORUM_TRACKING_OFF; | |
609 | $forum1 = self::getDataGenerator()->create_module('forum', $record); | |
610 | ||
611 | // Add discussions to the forums. | |
612 | $record = new stdClass(); | |
613 | $record->course = $course1->id; | |
614 | $record->userid = $user1->id; | |
615 | $record->forum = $forum1->id; | |
616 | $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
617 | ||
618 | // Add three replies to the discussion 1 from different users. | |
619 | $record = new stdClass(); | |
620 | $record->discussion = $discussion1->id; | |
621 | $record->parent = $discussion1->firstpost; | |
622 | $record->userid = $user2->id; | |
623 | $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
624 | ||
625 | $record->parent = $discussion1reply1->id; | |
626 | $record->userid = $user3->id; | |
627 | $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
628 | ||
629 | $record->userid = $user4->id; | |
630 | $discussion1reply3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); | |
631 | ||
632 | // Enrol the user in the first course. | |
633 | $enrol = enrol_get_plugin('manual'); | |
634 | ||
635 | // We don't use the dataGenerator as we need to get the $instance2 to unenrol later. | |
636 | $enrolinstances = enrol_get_instances($course1->id, true); | |
637 | foreach ($enrolinstances as $courseenrolinstance) { | |
638 | if ($courseenrolinstance->enrol == "manual") { | |
639 | $instance1 = $courseenrolinstance; | |
640 | break; | |
641 | } | |
642 | } | |
643 | $enrol->enrol_user($instance1, $user1->id); | |
644 | ||
81f810dc JL |
645 | // Delete one user. |
646 | delete_user($user4); | |
647 | ||
c2586672 JL |
648 | // Assign capabilities to view discussions for forum 1. |
649 | $cm = get_coursemodule_from_id('forum', $forum1->cmid, 0, false, MUST_EXIST); | |
650 | $context = context_module::instance($cm->id); | |
651 | $newrole = create_role('Role 2', 'role2', 'Role 2 description'); | |
652 | $this->assignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole); | |
653 | ||
654 | // Create what we expect to be returned when querying the forums. | |
655 | ||
656 | $post1 = $DB->get_record('forum_posts', array('id' => $discussion1->firstpost), '*', MUST_EXIST); | |
81f810dc | 657 | $userpictureurl = moodle_url::make_webservice_pluginfile_url( |
c2586672 | 658 | context_user::instance($user1->id)->id, 'user', 'icon', null, '/', 'f1'); |
c2586672 | 659 | |
81f810dc JL |
660 | // We expect an empty URL since we deleted the user4. |
661 | $usermodifiedpictureurl = ''; | |
c2586672 JL |
662 | |
663 | $expecteddiscussions = array( | |
664 | 'id' => $discussion1->firstpost, | |
665 | 'name' => $discussion1->name, | |
666 | 'groupid' => $discussion1->groupid, | |
667 | 'timemodified' => $discussion1reply3->created, | |
668 | 'usermodified' => $discussion1reply3->userid, | |
669 | 'timestart' => $discussion1->timestart, | |
670 | 'timeend' => $discussion1->timeend, | |
671 | 'discussion' => $discussion1->id, | |
672 | 'parent' => 0, | |
673 | 'userid' => $discussion1->userid, | |
674 | 'created' => $post1->created, | |
675 | 'modified' => $post1->modified, | |
676 | 'mailed' => $post1->mailed, | |
677 | 'subject' => $post1->subject, | |
678 | 'message' => $post1->message, | |
679 | 'messageformat' => $post1->messageformat, | |
680 | 'messagetrust' => $post1->messagetrust, | |
681 | 'attachment' => $post1->attachment, | |
682 | 'totalscore' => $post1->totalscore, | |
683 | 'mailnow' => $post1->mailnow, | |
684 | 'userfullname' => fullname($user1), | |
685 | 'usermodifiedfullname' => fullname($user4), | |
686 | 'userpictureurl' => $userpictureurl, | |
687 | 'usermodifiedpictureurl' => $usermodifiedpictureurl, | |
688 | 'numreplies' => 3, | |
689 | 'numunread' => 0 | |
690 | ); | |
691 | ||
692 | // Call the external function passing forum id. | |
693 | $discussions = mod_forum_external::get_forum_discussions_paginated($forum1->id); | |
694 | $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions); | |
695 | $expectedreturn = array( | |
696 | 'discussions' => array($expecteddiscussions), | |
697 | 'warnings' => array() | |
698 | ); | |
699 | $this->assertEquals($expectedreturn, $discussions); | |
700 | ||
701 | // Call without required view discussion capability. | |
702 | $this->unassignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole); | |
703 | try { | |
704 | mod_forum_external::get_forum_discussions_paginated($forum1->id); | |
705 | $this->fail('Exception expected due to missing capability.'); | |
706 | } catch (moodle_exception $e) { | |
707 | $this->assertEquals('noviewdiscussionspermission', $e->errorcode); | |
708 | } | |
709 | ||
710 | // Unenrol user from second course. | |
711 | $enrol->unenrol_user($instance1, $user1->id); | |
712 | ||
713 | // Call for the second course we unenrolled the user from, make sure exception thrown. | |
714 | try { | |
715 | mod_forum_external::get_forum_discussions_paginated($forum1->id); | |
716 | $this->fail('Exception expected due to being unenrolled from the course.'); | |
717 | } catch (moodle_exception $e) { | |
718 | $this->assertEquals('requireloginerror', $e->errorcode); | |
719 | } | |
720 | } | |
039c81f0 JL |
721 | |
722 | /** | |
723 | * Test get forum discussions paginated (qanda forums) | |
724 | */ | |
725 | public function test_mod_forum_get_forum_discussions_paginated_qanda() { | |
726 | ||
727 | $this->resetAfterTest(true); | |
728 | ||
729 | // Create courses to add the modules. | |
730 | $course = self::getDataGenerator()->create_course(); | |
731 | ||
732 | $user1 = self::getDataGenerator()->create_user(); | |
733 | $user2 = self::getDataGenerator()->create_user(); | |
734 | ||
735 | // First forum with tracking off. | |
736 | $record = new stdClass(); | |
737 | $record->course = $course->id; | |
738 | $record->type = 'qanda'; | |
739 | $forum = self::getDataGenerator()->create_module('forum', $record); | |
740 | ||
741 | // Add discussions to the forums. | |
742 | $discussionrecord = new stdClass(); | |
743 | $discussionrecord->course = $course->id; | |
744 | $discussionrecord->userid = $user2->id; | |
745 | $discussionrecord->forum = $forum->id; | |
746 | $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($discussionrecord); | |
747 | ||
748 | self::setAdminUser(); | |
749 | $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id); | |
750 | $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions); | |
751 | ||
752 | $this->assertCount(1, $discussions['discussions']); | |
753 | $this->assertCount(0, $discussions['warnings']); | |
754 | ||
755 | self::setUser($user1); | |
756 | $this->getDataGenerator()->enrol_user($user1->id, $course->id); | |
757 | ||
758 | $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id); | |
759 | $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions); | |
760 | ||
761 | $this->assertCount(1, $discussions['discussions']); | |
762 | $this->assertCount(0, $discussions['warnings']); | |
763 | ||
764 | } | |
50a20317 JL |
765 | |
766 | /** | |
767 | * Test add_discussion_post | |
768 | */ | |
769 | public function test_add_discussion_post() { | |
770 | global $CFG; | |
771 | ||
772 | $this->resetAfterTest(true); | |
773 | ||
774 | $user = self::getDataGenerator()->create_user(); | |
775 | $otheruser = self::getDataGenerator()->create_user(); | |
776 | ||
777 | self::setAdminUser(); | |
778 | ||
779 | // Create course to add the module. | |
780 | $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0)); | |
781 | ||
782 | // Forum with tracking off. | |
783 | $record = new stdClass(); | |
784 | $record->course = $course->id; | |
785 | $forum = self::getDataGenerator()->create_module('forum', $record); | |
786 | $cm = get_coursemodule_from_id('forum', $forum->cmid, 0, false, MUST_EXIST); | |
787 | $forumcontext = context_module::instance($forum->cmid); | |
788 | ||
789 | // Add discussions to the forums. | |
790 | $record = new stdClass(); | |
791 | $record->course = $course->id; | |
792 | $record->userid = $user->id; | |
793 | $record->forum = $forum->id; | |
794 | $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
795 | ||
796 | // Try to post (user not enrolled). | |
797 | self::setUser($user); | |
798 | try { | |
799 | mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...'); | |
800 | $this->fail('Exception expected due to being unenrolled from the course.'); | |
801 | } catch (moodle_exception $e) { | |
802 | $this->assertEquals('requireloginerror', $e->errorcode); | |
803 | } | |
804 | ||
805 | $this->getDataGenerator()->enrol_user($user->id, $course->id); | |
806 | $this->getDataGenerator()->enrol_user($otheruser->id, $course->id); | |
807 | ||
808 | $post = mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...'); | |
809 | $post = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $post); | |
810 | ||
811 | $posts = mod_forum_external::get_forum_discussion_posts($discussion->id); | |
812 | $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); | |
813 | // We receive the discussion and the post. | |
814 | $this->assertEquals(2, count($posts['posts'])); | |
815 | $this->assertEquals($post['postid'], $posts['posts'][1]['id']); | |
816 | $this->assertEquals('some subject', $posts['posts'][1]['subject']); | |
817 | $this->assertEquals('some text here...', $posts['posts'][1]['message']); | |
818 | ||
819 | // Check not posting in groups the user is not member of. | |
820 | $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); | |
821 | groups_add_member($group->id, $otheruser->id); | |
822 | ||
823 | $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS)); | |
824 | $record->forum = $forum->id; | |
825 | $record->userid = $otheruser->id; | |
826 | $record->groupid = $group->id; | |
827 | $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); | |
828 | ||
829 | try { | |
830 | mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...'); | |
831 | $this->fail('Exception expected due to invalid permissions for posting.'); | |
832 | } catch (moodle_exception $e) { | |
833 | // Expect debugging since we are switching context, and this is something WS_SERVER mode don't like. | |
834 | $this->assertDebuggingCalled(); | |
835 | $this->assertEquals('nopostforum', $e->errorcode); | |
836 | } | |
837 | ||
838 | } | |
2b9fe87d | 839 | } |