MDL-61309 mod_forum: Implement the Privacy API
[moodle.git] / mod / forum / tests / externallib_test.php
CommitLineData
2b9fe87d 1<?php
2b9fe87d
MN
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * The module forums external functions unit tests
19 *
20 * @package mod_forum
21 * @category external
22 * @copyright 2012 Mark Nelson <markn@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28global $CFG;
29
30require_once($CFG->dirroot . '/webservice/tests/helpers.php');
4669389d 31require_once($CFG->dirroot . '/mod/forum/lib.php');
2b9fe87d
MN
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
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.
4669389d 63 $user = self::getDataGenerator()->create_user(array('trackforums' => 1));
2b9fe87d
MN
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;
4669389d 76 $record->trackingtype = FORUM_TRACKING_FORCED;
2b9fe87d
MN
77 $forum1 = self::getDataGenerator()->create_module('forum', $record);
78
79 // Second forum.
80 $record = new stdClass();
81 $record->introformat = FORMAT_HTML;
82 $record->course = $course2->id;
4669389d 83 $record->trackingtype = FORUM_TRACKING_OFF;
2b9fe87d 84 $forum2 = self::getDataGenerator()->create_module('forum', $record);
7ef49bd3 85 $forum2->introfiles = [];
2b9fe87d 86
7ea6ada3
JL
87 // Add discussions to the forums.
88 $record = new stdClass();
89 $record->course = $course1->id;
90 $record->userid = $user->id;
91 $record->forum = $forum1->id;
92 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
93 // Expect one discussion.
94 $forum1->numdiscussions = 1;
ea5b910b 95 $forum1->cancreatediscussions = true;
4669389d 96 $forum1->istracked = true;
2256bb74 97 $forum1->unreadpostscount = 0;
7ef49bd3 98 $forum1->introfiles = [];
7ea6ada3
JL
99
100 $record = new stdClass();
101 $record->course = $course2->id;
102 $record->userid = $user->id;
103 $record->forum = $forum2->id;
104 $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
105 $discussion3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
106 // Expect two discussions.
107 $forum2->numdiscussions = 2;
ea5b910b
JL
108 // Default limited role, no create discussion capability enabled.
109 $forum2->cancreatediscussions = false;
4669389d 110 $forum2->istracked = false;
7ea6ada3 111
2b9fe87d
MN
112 // Check the forum was correctly created.
113 $this->assertEquals(2, $DB->count_records_select('forum', 'id = :forum1 OR id = :forum2',
114 array('forum1' => $forum1->id, 'forum2' => $forum2->id)));
115
116 // Enrol the user in two courses.
909f27ac
JM
117 // DataGenerator->enrol_user automatically sets a role for the user with the permission mod/form:viewdiscussion.
118 $this->getDataGenerator()->enrol_user($user->id, $course1->id, null, 'manual');
119 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
2b9fe87d 120 $enrol = enrol_get_plugin('manual');
2b9fe87d
MN
121 $enrolinstances = enrol_get_instances($course2->id, true);
122 foreach ($enrolinstances as $courseenrolinstance) {
123 if ($courseenrolinstance->enrol == "manual") {
124 $instance2 = $courseenrolinstance;
125 break;
126 }
127 }
128 $enrol->enrol_user($instance2, $user->id);
129
2b9fe87d 130 // Assign capabilities to view forums for forum 2.
74b63eae 131 $cm2 = get_coursemodule_from_id('forum', $forum2->cmid, 0, false, MUST_EXIST);
2b9fe87d
MN
132 $context2 = context_module::instance($cm2->id);
133 $newrole = create_role('Role 2', 'role2', 'Role 2 description');
134 $roleid2 = $this->assignUserCapability('mod/forum:viewdiscussion', $context2->id, $newrole);
135
136 // Create what we expect to be returned when querying the two courses.
c8f1d8a0
JL
137 unset($forum1->displaywordcount);
138 unset($forum2->displaywordcount);
139
2b9fe87d
MN
140 $expectedforums = array();
141 $expectedforums[$forum1->id] = (array) $forum1;
142 $expectedforums[$forum2->id] = (array) $forum2;
143
144 // Call the external function passing course ids.
145 $forums = mod_forum_external::get_forums_by_courses(array($course1->id, $course2->id));
c8f1d8a0
JL
146 $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
147 $this->assertCount(2, $forums);
148 foreach ($forums as $forum) {
149 $this->assertEquals($expectedforums[$forum['id']], $forum);
150 }
2b9fe87d
MN
151
152 // Call the external function without passing course id.
153 $forums = mod_forum_external::get_forums_by_courses();
c8f1d8a0
JL
154 $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
155 $this->assertCount(2, $forums);
156 foreach ($forums as $forum) {
157 $this->assertEquals($expectedforums[$forum['id']], $forum);
158 }
2b9fe87d
MN
159
160 // Unenrol user from second course and alter expected forums.
161 $enrol->unenrol_user($instance2, $user->id);
162 unset($expectedforums[$forum2->id]);
163
164 // Call the external function without passing course id.
165 $forums = mod_forum_external::get_forums_by_courses();
c8f1d8a0
JL
166 $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
167 $this->assertCount(1, $forums);
168 $this->assertEquals($expectedforums[$forum1->id], $forums[0]);
ea5b910b
JL
169 $this->assertTrue($forums[0]['cancreatediscussions']);
170
171 // Change the type of the forum, the user shouldn't be able to add discussions.
172 $DB->set_field('forum', 'type', 'news', array('id' => $forum1->id));
173 $forums = mod_forum_external::get_forums_by_courses();
174 $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
175 $this->assertFalse($forums[0]['cancreatediscussions']);
c8f1d8a0
JL
176
177 // Call for the second course we unenrolled the user from.
178 $forums = mod_forum_external::get_forums_by_courses(array($course2->id));
179 $forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
180 $this->assertCount(0, $forums);
a9a0cb69
MN
181 }
182
e2ede426
JL
183 /**
184 * Test get forum posts
185 */
186 public function test_mod_forum_get_forum_discussion_posts() {
d85bedf7 187 global $CFG, $PAGE;
e2ede426
JL
188
189 $this->resetAfterTest(true);
190
191 // Set the CFG variable to allow track forums.
192 $CFG->forum_trackreadposts = true;
193
194 // Create a user who can track forums.
195 $record = new stdClass();
196 $record->trackforums = true;
197 $user1 = self::getDataGenerator()->create_user($record);
198 // Create a bunch of other users to post.
199 $user2 = self::getDataGenerator()->create_user();
200 $user3 = self::getDataGenerator()->create_user();
201
202 // Set the first created user to the test user.
203 self::setUser($user1);
204
205 // Create course to add the module.
206 $course1 = self::getDataGenerator()->create_course();
207
208 // Forum with tracking off.
209 $record = new stdClass();
210 $record->course = $course1->id;
211 $record->trackingtype = FORUM_TRACKING_OFF;
212 $forum1 = self::getDataGenerator()->create_module('forum', $record);
213 $forum1context = context_module::instance($forum1->cmid);
214
db3c9ff8
PFO
215 // Forum with tracking enabled.
216 $record = new stdClass();
217 $record->course = $course1->id;
218 $forum2 = self::getDataGenerator()->create_module('forum', $record);
2256bb74 219 $forum2cm = get_coursemodule_from_id('forum', $forum2->cmid);
db3c9ff8
PFO
220 $forum2context = context_module::instance($forum2->cmid);
221
e2ede426
JL
222 // Add discussions to the forums.
223 $record = new stdClass();
224 $record->course = $course1->id;
225 $record->userid = $user1->id;
226 $record->forum = $forum1->id;
227 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
228
229 $record = new stdClass();
230 $record->course = $course1->id;
231 $record->userid = $user2->id;
232 $record->forum = $forum1->id;
233 $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
234
db3c9ff8
PFO
235 $record = new stdClass();
236 $record->course = $course1->id;
237 $record->userid = $user2->id;
238 $record->forum = $forum2->id;
239 $discussion3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
240
e2ede426
JL
241 // Add 2 replies to the discussion 1 from different users.
242 $record = new stdClass();
243 $record->discussion = $discussion1->id;
244 $record->parent = $discussion1->firstpost;
245 $record->userid = $user2->id;
246 $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
c8743f62
JL
247 $filename = 'shouldbeanimage.jpg';
248 // Add a fake inline image to the post.
249 $filerecordinline = array(
250 'contextid' => $forum1context->id,
251 'component' => 'mod_forum',
252 'filearea' => 'post',
253 'itemid' => $discussion1reply1->id,
254 'filepath' => '/',
255 'filename' => $filename,
256 );
257 $fs = get_file_storage();
258 $timepost = time();
259 $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
e2ede426
JL
260
261 $record->parent = $discussion1reply1->id;
262 $record->userid = $user3->id;
263 $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
264
265 // Enrol the user in the course.
266 $enrol = enrol_get_plugin('manual');
267 // Following line enrol and assign default role id to the user.
268 // So the user automatically gets mod/forum:viewdiscussion on all forums of the course.
269 $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
270 $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
81f810dc
JL
271
272 // Delete one user, to test that we still receive posts by this user.
273 delete_user($user3);
e2ede426
JL
274
275 // Create what we expect to be returned when querying the discussion.
276 $expectedposts = array(
277 'posts' => array(),
b7ce46df
JL
278 'ratinginfo' => array(
279 'contextid' => $forum1context->id,
280 'component' => 'mod_forum',
281 'ratingarea' => 'post',
282 'canviewall' => null,
283 'canviewany' => null,
284 'scales' => array(),
285 'ratings' => array(),
286 ),
e2ede426
JL
287 'warnings' => array(),
288 );
694bf0c7 289
d85bedf7 290 // User pictures are initially empty, we should get the links once the external function is called.
e2ede426
JL
291 $expectedposts['posts'][] = array(
292 'id' => $discussion1reply2->id,
293 'discussion' => $discussion1reply2->discussion,
294 'parent' => $discussion1reply2->parent,
48fb0250 295 'userid' => (int) $discussion1reply2->userid,
e2ede426
JL
296 'created' => $discussion1reply2->created,
297 'modified' => $discussion1reply2->modified,
298 'mailed' => $discussion1reply2->mailed,
299 'subject' => $discussion1reply2->subject,
300 'message' => file_rewrite_pluginfile_urls($discussion1reply2->message, 'pluginfile.php',
301 $forum1context->id, 'mod_forum', 'post', $discussion1reply2->id),
48fb0250 302 'messageformat' => 1, // This value is usually changed by external_format_text() function.
e2ede426
JL
303 'messagetrust' => $discussion1reply2->messagetrust,
304 'attachment' => $discussion1reply2->attachment,
305 'totalscore' => $discussion1reply2->totalscore,
306 'mailnow' => $discussion1reply2->mailnow,
307 'children' => array(),
308 'canreply' => true,
309 'postread' => false,
694bf0c7 310 'userfullname' => fullname($user3),
d85bedf7 311 'userpictureurl' => ''
e2ede426 312 );
694bf0c7 313
e2ede426
JL
314 $expectedposts['posts'][] = array(
315 'id' => $discussion1reply1->id,
316 'discussion' => $discussion1reply1->discussion,
317 'parent' => $discussion1reply1->parent,
48fb0250 318 'userid' => (int) $discussion1reply1->userid,
e2ede426
JL
319 'created' => $discussion1reply1->created,
320 'modified' => $discussion1reply1->modified,
321 'mailed' => $discussion1reply1->mailed,
322 'subject' => $discussion1reply1->subject,
323 'message' => file_rewrite_pluginfile_urls($discussion1reply1->message, 'pluginfile.php',
324 $forum1context->id, 'mod_forum', 'post', $discussion1reply1->id),
48fb0250 325 'messageformat' => 1, // This value is usually changed by external_format_text() function.
e2ede426
JL
326 'messagetrust' => $discussion1reply1->messagetrust,
327 'attachment' => $discussion1reply1->attachment,
c8743f62
JL
328 'messageinlinefiles' => array(
329 array(
330 'filename' => $filename,
331 'filepath' => '/',
332 'filesize' => '27',
333 'fileurl' => moodle_url::make_webservice_pluginfile_url($forum1context->id, 'mod_forum', 'post',
334 $discussion1reply1->id, '/', $filename),
335 'timemodified' => $timepost,
336 'mimetype' => 'image/jpeg',
1104a9fa 337 'isexternalfile' => false,
c8743f62
JL
338 )
339 ),
e2ede426
JL
340 'totalscore' => $discussion1reply1->totalscore,
341 'mailnow' => $discussion1reply1->mailnow,
d2c58b95 342 'children' => array($discussion1reply2->id),
e2ede426
JL
343 'canreply' => true,
344 'postread' => false,
694bf0c7 345 'userfullname' => fullname($user2),
d85bedf7 346 'userpictureurl' => ''
e2ede426
JL
347 );
348
349 // Test a discussion with two additional posts (total 3 posts).
350 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
351 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
352 $this->assertEquals(3, count($posts['posts']));
353
d85bedf7
JL
354 // Generate here the pictures because we need to wait to the external function to init the theme.
355 $userpicture = new user_picture($user3);
356 $userpicture->size = 1; // Size f1.
357 $expectedposts['posts'][0]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
358
359 $userpicture = new user_picture($user2);
360 $userpicture->size = 1; // Size f1.
361 $expectedposts['posts'][1]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
362
e2ede426
JL
363 // Unset the initial discussion post.
364 array_pop($posts['posts']);
365 $this->assertEquals($expectedposts, $posts);
366
2256bb74
JL
367 // Check we receive the unread count correctly on tracked forum.
368 forum_tp_count_forum_unread_posts($forum2cm, $course1, true); // Reset static cache.
369 $result = mod_forum_external::get_forums_by_courses(array($course1->id));
370 $result = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $result);
371 foreach ($result as $f) {
372 if ($f['id'] == $forum2->id) {
373 $this->assertEquals(1, $f['unreadpostscount']);
374 }
375 }
376
e2ede426
JL
377 // Test discussion without additional posts. There should be only one post (the one created by the discussion).
378 $posts = mod_forum_external::get_forum_discussion_posts($discussion2->id, 'modified', 'DESC');
379 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
380 $this->assertEquals(1, count($posts['posts']));
381
db3c9ff8
PFO
382 // Test discussion tracking on not tracked forum.
383 $result = mod_forum_external::view_forum_discussion($discussion1->id);
384 $result = external_api::clean_returnvalue(mod_forum_external::view_forum_discussion_returns(), $result);
385 $this->assertTrue($result['status']);
386 $this->assertEmpty($result['warnings']);
387
388 // Test posts have not been marked as read.
389 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
390 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
391 foreach ($posts['posts'] as $post) {
392 $this->assertFalse($post['postread']);
393 }
394
395 // Test discussion tracking on tracked forum.
396 $result = mod_forum_external::view_forum_discussion($discussion3->id);
397 $result = external_api::clean_returnvalue(mod_forum_external::view_forum_discussion_returns(), $result);
398 $this->assertTrue($result['status']);
399 $this->assertEmpty($result['warnings']);
400
401 // Test posts have been marked as read.
402 $posts = mod_forum_external::get_forum_discussion_posts($discussion3->id, 'modified', 'DESC');
403 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
404 foreach ($posts['posts'] as $post) {
405 $this->assertTrue($post['postread']);
406 }
2256bb74
JL
407
408 // Check we receive 0 unread posts.
409 forum_tp_count_forum_unread_posts($forum2cm, $course1, true); // Reset static cache.
410 $result = mod_forum_external::get_forums_by_courses(array($course1->id));
411 $result = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $result);
412 foreach ($result as $f) {
413 if ($f['id'] == $forum2->id) {
414 $this->assertEquals(0, $f['unreadpostscount']);
415 }
416 }
e2ede426 417 }
c2586672 418
b1aa7dfa
JL
419 /**
420 * Test get forum posts (qanda forum)
421 */
422 public function test_mod_forum_get_forum_discussion_posts_qanda() {
423 global $CFG, $DB;
424
425 $this->resetAfterTest(true);
426
427 $record = new stdClass();
428 $user1 = self::getDataGenerator()->create_user($record);
429 $user2 = self::getDataGenerator()->create_user();
430
431 // Set the first created user to the test user.
432 self::setUser($user1);
433
434 // Create course to add the module.
435 $course1 = self::getDataGenerator()->create_course();
436 $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
437 $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
438
439 // Forum with tracking off.
440 $record = new stdClass();
441 $record->course = $course1->id;
442 $record->type = 'qanda';
443 $forum1 = self::getDataGenerator()->create_module('forum', $record);
444 $forum1context = context_module::instance($forum1->cmid);
445
446 // Add discussions to the forums.
447 $record = new stdClass();
448 $record->course = $course1->id;
449 $record->userid = $user2->id;
450 $record->forum = $forum1->id;
451 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
452
453 // Add 1 reply (not the actual user).
454 $record = new stdClass();
455 $record->discussion = $discussion1->id;
456 $record->parent = $discussion1->firstpost;
457 $record->userid = $user2->id;
458 $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
459
460 // We still see only the original post.
461 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
462 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
463 $this->assertEquals(1, count($posts['posts']));
464
465 // Add a new reply, the user is going to be able to see only the original post and their new post.
466 $record = new stdClass();
467 $record->discussion = $discussion1->id;
468 $record->parent = $discussion1->firstpost;
469 $record->userid = $user1->id;
470 $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
471
472 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
473 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
474 $this->assertEquals(2, count($posts['posts']));
475
476 // Now, we can fake the time of the user post, so he can se the rest of the discussion posts.
477 $discussion1reply2->created -= $CFG->maxeditingtime * 2;
478 $DB->update_record('forum_posts', $discussion1reply2);
479
480 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
481 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
482 $this->assertEquals(3, count($posts['posts']));
b1aa7dfa
JL
483 }
484
c2586672
JL
485 /**
486 * Test get forum discussions paginated
487 */
488 public function test_mod_forum_get_forum_discussions_paginated() {
d85bedf7 489 global $USER, $CFG, $DB, $PAGE;
c2586672
JL
490
491 $this->resetAfterTest(true);
492
493 // Set the CFG variable to allow track forums.
494 $CFG->forum_trackreadposts = true;
495
496 // Create a user who can track forums.
497 $record = new stdClass();
498 $record->trackforums = true;
499 $user1 = self::getDataGenerator()->create_user($record);
500 // Create a bunch of other users to post.
501 $user2 = self::getDataGenerator()->create_user();
502 $user3 = self::getDataGenerator()->create_user();
503 $user4 = self::getDataGenerator()->create_user();
504
505 // Set the first created user to the test user.
506 self::setUser($user1);
507
508 // Create courses to add the modules.
509 $course1 = self::getDataGenerator()->create_course();
510
511 // First forum with tracking off.
512 $record = new stdClass();
513 $record->course = $course1->id;
514 $record->trackingtype = FORUM_TRACKING_OFF;
515 $forum1 = self::getDataGenerator()->create_module('forum', $record);
516
517 // Add discussions to the forums.
518 $record = new stdClass();
519 $record->course = $course1->id;
520 $record->userid = $user1->id;
521 $record->forum = $forum1->id;
522 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
523
524 // Add three replies to the discussion 1 from different users.
525 $record = new stdClass();
526 $record->discussion = $discussion1->id;
527 $record->parent = $discussion1->firstpost;
528 $record->userid = $user2->id;
529 $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
530
531 $record->parent = $discussion1reply1->id;
532 $record->userid = $user3->id;
533 $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
534
535 $record->userid = $user4->id;
536 $discussion1reply3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
537
538 // Enrol the user in the first course.
539 $enrol = enrol_get_plugin('manual');
540
541 // We don't use the dataGenerator as we need to get the $instance2 to unenrol later.
542 $enrolinstances = enrol_get_instances($course1->id, true);
543 foreach ($enrolinstances as $courseenrolinstance) {
544 if ($courseenrolinstance->enrol == "manual") {
545 $instance1 = $courseenrolinstance;
546 break;
547 }
548 }
549 $enrol->enrol_user($instance1, $user1->id);
550
81f810dc
JL
551 // Delete one user.
552 delete_user($user4);
553
c2586672
JL
554 // Assign capabilities to view discussions for forum 1.
555 $cm = get_coursemodule_from_id('forum', $forum1->cmid, 0, false, MUST_EXIST);
556 $context = context_module::instance($cm->id);
557 $newrole = create_role('Role 2', 'role2', 'Role 2 description');
558 $this->assignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole);
559
560 // Create what we expect to be returned when querying the forums.
561
562 $post1 = $DB->get_record('forum_posts', array('id' => $discussion1->firstpost), '*', MUST_EXIST);
c2586672 563
d85bedf7 564 // User pictures are initially empty, we should get the links once the external function is called.
c2586672
JL
565 $expecteddiscussions = array(
566 'id' => $discussion1->firstpost,
567 'name' => $discussion1->name,
568 'groupid' => $discussion1->groupid,
569 'timemodified' => $discussion1reply3->created,
570 'usermodified' => $discussion1reply3->userid,
571 'timestart' => $discussion1->timestart,
572 'timeend' => $discussion1->timeend,
573 'discussion' => $discussion1->id,
574 'parent' => 0,
575 'userid' => $discussion1->userid,
576 'created' => $post1->created,
577 'modified' => $post1->modified,
578 'mailed' => $post1->mailed,
579 'subject' => $post1->subject,
580 'message' => $post1->message,
581 'messageformat' => $post1->messageformat,
582 'messagetrust' => $post1->messagetrust,
583 'attachment' => $post1->attachment,
584 'totalscore' => $post1->totalscore,
585 'mailnow' => $post1->mailnow,
586 'userfullname' => fullname($user1),
587 'usermodifiedfullname' => fullname($user4),
d85bedf7
JL
588 'userpictureurl' => '',
589 'usermodifiedpictureurl' => '',
c2586672 590 'numreplies' => 3,
5f219cf1 591 'numunread' => 0,
0f3bbfd4
AN
592 'pinned' => FORUM_DISCUSSION_UNPINNED,
593 'locked' => false,
594 'canreply' => false,
c2586672
JL
595 );
596
597 // Call the external function passing forum id.
598 $discussions = mod_forum_external::get_forum_discussions_paginated($forum1->id);
599 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
600 $expectedreturn = array(
601 'discussions' => array($expecteddiscussions),
602 'warnings' => array()
603 );
d85bedf7
JL
604
605 // Wait the theme to be loaded (the external_api call does that) to generate the user profiles.
606 $userpicture = new user_picture($user1);
607 $userpicture->size = 1; // Size f1.
608 $expectedreturn['discussions'][0]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
609
610 $userpicture = new user_picture($user4);
611 $userpicture->size = 1; // Size f1.
612 $expectedreturn['discussions'][0]['usermodifiedpictureurl'] = $userpicture->get_url($PAGE)->out(false);
613
c2586672
JL
614 $this->assertEquals($expectedreturn, $discussions);
615
616 // Call without required view discussion capability.
617 $this->unassignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole);
618 try {
619 mod_forum_external::get_forum_discussions_paginated($forum1->id);
620 $this->fail('Exception expected due to missing capability.');
621 } catch (moodle_exception $e) {
622 $this->assertEquals('noviewdiscussionspermission', $e->errorcode);
623 }
624
625 // Unenrol user from second course.
626 $enrol->unenrol_user($instance1, $user1->id);
627
628 // Call for the second course we unenrolled the user from, make sure exception thrown.
629 try {
630 mod_forum_external::get_forum_discussions_paginated($forum1->id);
631 $this->fail('Exception expected due to being unenrolled from the course.');
632 } catch (moodle_exception $e) {
633 $this->assertEquals('requireloginerror', $e->errorcode);
634 }
635 }
039c81f0
JL
636
637 /**
638 * Test get forum discussions paginated (qanda forums)
639 */
640 public function test_mod_forum_get_forum_discussions_paginated_qanda() {
641
642 $this->resetAfterTest(true);
643
644 // Create courses to add the modules.
645 $course = self::getDataGenerator()->create_course();
646
647 $user1 = self::getDataGenerator()->create_user();
648 $user2 = self::getDataGenerator()->create_user();
649
650 // First forum with tracking off.
651 $record = new stdClass();
652 $record->course = $course->id;
653 $record->type = 'qanda';
654 $forum = self::getDataGenerator()->create_module('forum', $record);
655
656 // Add discussions to the forums.
657 $discussionrecord = new stdClass();
658 $discussionrecord->course = $course->id;
659 $discussionrecord->userid = $user2->id;
660 $discussionrecord->forum = $forum->id;
661 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($discussionrecord);
662
663 self::setAdminUser();
664 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
665 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
666
667 $this->assertCount(1, $discussions['discussions']);
668 $this->assertCount(0, $discussions['warnings']);
669
670 self::setUser($user1);
671 $this->getDataGenerator()->enrol_user($user1->id, $course->id);
672
673 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
674 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
675
676 $this->assertCount(1, $discussions['discussions']);
677 $this->assertCount(0, $discussions['warnings']);
678
679 }
50a20317
JL
680
681 /**
682 * Test add_discussion_post
683 */
684 public function test_add_discussion_post() {
e881c4f5 685 global $CFG;
50a20317
JL
686
687 $this->resetAfterTest(true);
688
689 $user = self::getDataGenerator()->create_user();
690 $otheruser = self::getDataGenerator()->create_user();
691
692 self::setAdminUser();
693
694 // Create course to add the module.
695 $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0));
696
697 // Forum with tracking off.
698 $record = new stdClass();
699 $record->course = $course->id;
700 $forum = self::getDataGenerator()->create_module('forum', $record);
701 $cm = get_coursemodule_from_id('forum', $forum->cmid, 0, false, MUST_EXIST);
702 $forumcontext = context_module::instance($forum->cmid);
703
704 // Add discussions to the forums.
705 $record = new stdClass();
706 $record->course = $course->id;
707 $record->userid = $user->id;
708 $record->forum = $forum->id;
709 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
710
711 // Try to post (user not enrolled).
712 self::setUser($user);
713 try {
714 mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
715 $this->fail('Exception expected due to being unenrolled from the course.');
716 } catch (moodle_exception $e) {
717 $this->assertEquals('requireloginerror', $e->errorcode);
718 }
719
720 $this->getDataGenerator()->enrol_user($user->id, $course->id);
721 $this->getDataGenerator()->enrol_user($otheruser->id, $course->id);
722
41182118
BK
723 $createdpost = mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
724 $createdpost = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $createdpost);
50a20317
JL
725
726 $posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
727 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
728 // We receive the discussion and the post.
729 $this->assertEquals(2, count($posts['posts']));
43ff833d
JL
730
731 $tested = false;
41182118
BK
732 foreach ($posts['posts'] as $thispost) {
733 if ($createdpost['postid'] == $thispost['id']) {
734 $this->assertEquals('some subject', $thispost['subject']);
735 $this->assertEquals('some text here...', $thispost['message']);
43ff833d
JL
736 $tested = true;
737 }
738 }
739 $this->assertTrue($tested);
50a20317 740
e881c4f5 741 // Test inline and regular attachment in post
41182118
BK
742 // Create a file in a draft area for inline attachments.
743 $draftidinlineattach = file_get_unused_draft_itemid();
e881c4f5 744 $draftidattach = file_get_unused_draft_itemid();
41182118
BK
745 self::setUser($user);
746 $usercontext = context_user::instance($user->id);
747 $filepath = '/';
748 $filearea = 'draft';
749 $component = 'user';
750 $filenameimg = 'shouldbeanimage.txt';
e881c4f5 751 $filerecordinline = array(
41182118
BK
752 'contextid' => $usercontext->id,
753 'component' => $component,
754 'filearea' => $filearea,
755 'itemid' => $draftidinlineattach,
756 'filepath' => $filepath,
757 'filename' => $filenameimg,
758 );
759 $fs = get_file_storage();
41182118 760
e881c4f5
BK
761 // Create a file in a draft area for regular attachments.
762 $filerecordattach = $filerecordinline;
763 $attachfilename = 'attachment.txt';
764 $filerecordattach['filename'] = $attachfilename;
765 $filerecordattach['itemid'] = $draftidattach;
766 $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
767 $fs->create_file_from_string($filerecordattach, 'simple text attachment');
768
48143990 769 $options = array(array('name' => 'inlineattachmentsid', 'value' => $draftidinlineattach),
e881c4f5 770 array('name' => 'attachmentsid', 'value' => $draftidattach));
41182118
BK
771 $dummytext = 'Here is an inline image: <img src="' . $CFG->wwwroot
772 . "/draftfile.php/{$usercontext->id}/user/draft/{$draftidinlineattach}/{$filenameimg}"
773 . '" alt="inlineimage">.';
774 $createdpost = mod_forum_external::add_discussion_post($discussion->firstpost, 'new post inline attachment',
775 $dummytext, $options);
776 $createdpost = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $createdpost);
777
778 $posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
779 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
780 // We receive the discussion and the post.
781 // Can't guarantee order of posts during tests.
782 $postfound = false;
783 foreach ($posts['posts'] as $thispost) {
784 if ($createdpost['postid'] == $thispost['id']) {
785 $this->assertEquals($createdpost['postid'], $thispost['id']);
e881c4f5
BK
786 $this->assertEquals($thispost['attachment'], 1, "There should be a non-inline attachment");
787 $this->assertCount(1, $thispost['attachments'], "There should be 1 attachment");
788 $this->assertEquals($thispost['attachments'][0]['filename'], $attachfilename, "There should be 1 attachment");
41182118
BK
789 $this->assertContains('pluginfile.php', $thispost['message']);
790 $postfound = true;
e881c4f5 791 break;
41182118
BK
792 }
793 }
794
795 $this->assertTrue($postfound);
796
50a20317
JL
797 // Check not posting in groups the user is not member of.
798 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
799 groups_add_member($group->id, $otheruser->id);
800
801 $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
802 $record->forum = $forum->id;
803 $record->userid = $otheruser->id;
804 $record->groupid = $group->id;
805 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
806
807 try {
808 mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
809 $this->fail('Exception expected due to invalid permissions for posting.');
810 } catch (moodle_exception $e) {
50a20317
JL
811 $this->assertEquals('nopostforum', $e->errorcode);
812 }
813
814 }
7ab43ac8
JL
815
816 /*
817 * Test add_discussion. A basic test since all the API functions are already covered by unit tests.
818 */
819 public function test_add_discussion() {
41182118 820 global $CFG, $USER;
7ab43ac8
JL
821 $this->resetAfterTest(true);
822
823 // Create courses to add the modules.
824 $course = self::getDataGenerator()->create_course();
825
826 $user1 = self::getDataGenerator()->create_user();
827 $user2 = self::getDataGenerator()->create_user();
828
829 // First forum with tracking off.
830 $record = new stdClass();
831 $record->course = $course->id;
832 $record->type = 'news';
833 $forum = self::getDataGenerator()->create_module('forum', $record);
834
835 self::setUser($user1);
836 $this->getDataGenerator()->enrol_user($user1->id, $course->id);
837
838 try {
839 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
840 $this->fail('Exception expected due to invalid permissions.');
841 } catch (moodle_exception $e) {
842 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
843 }
844
845 self::setAdminUser();
41182118
BK
846 $createddiscussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
847 $createddiscussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $createddiscussion);
7ab43ac8
JL
848
849 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
850 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
851
852 $this->assertCount(1, $discussions['discussions']);
853 $this->assertCount(0, $discussions['warnings']);
854
41182118 855 $this->assertEquals($createddiscussion['discussionid'], $discussions['discussions'][0]['discussion']);
7ab43ac8
JL
856 $this->assertEquals(-1, $discussions['discussions'][0]['groupid']);
857 $this->assertEquals('the subject', $discussions['discussions'][0]['subject']);
858 $this->assertEquals('some text here...', $discussions['discussions'][0]['message']);
859
5f219cf1
BK
860 $discussion2pinned = mod_forum_external::add_discussion($forum->id, 'the pinned subject', 'some 2 text here...', -1,
861 array('options' => array('name' => 'discussionpinned',
862 'value' => true)));
863 $discussion3 = mod_forum_external::add_discussion($forum->id, 'the non pinnedsubject', 'some 3 text here...');
864 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
865 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
866 $this->assertCount(3, $discussions['discussions']);
867 $this->assertEquals($discussion2pinned['discussionid'], $discussions['discussions'][0]['discussion']);
41182118 868
e881c4f5 869 // Test inline and regular attachment in new discussion
41182118 870 // Create a file in a draft area for inline attachments.
e881c4f5
BK
871
872 $fs = get_file_storage();
873
41182118 874 $draftidinlineattach = file_get_unused_draft_itemid();
e881c4f5
BK
875 $draftidattach = file_get_unused_draft_itemid();
876
41182118
BK
877 $usercontext = context_user::instance($USER->id);
878 $filepath = '/';
879 $filearea = 'draft';
880 $component = 'user';
881 $filenameimg = 'shouldbeanimage.txt';
882 $filerecord = array(
883 'contextid' => $usercontext->id,
884 'component' => $component,
885 'filearea' => $filearea,
886 'itemid' => $draftidinlineattach,
887 'filepath' => $filepath,
888 'filename' => $filenameimg,
889 );
e881c4f5 890
e881c4f5
BK
891 // Create a file in a draft area for regular attachments.
892 $filerecordattach = $filerecord;
893 $attachfilename = 'attachment.txt';
894 $filerecordattach['filename'] = $attachfilename;
895 $filerecordattach['itemid'] = $draftidattach;
41182118 896 $fs->create_file_from_string($filerecord, 'image contents (not really)');
e881c4f5
BK
897 $fs->create_file_from_string($filerecordattach, 'simple text attachment');
898
41182118
BK
899 $dummytext = 'Here is an inline image: <img src="' . $CFG->wwwroot .
900 "/draftfile.php/{$usercontext->id}/user/draft/{$draftidinlineattach}/{$filenameimg}" .
901 '" alt="inlineimage">.';
902
48143990 903 $options = array(array('name' => 'inlineattachmentsid', 'value' => $draftidinlineattach),
e881c4f5 904 array('name' => 'attachmentsid', 'value' => $draftidattach));
41182118
BK
905 $createddiscussion = mod_forum_external::add_discussion($forum->id, 'the inline attachment subject',
906 $dummytext, -1, $options);
907 $createddiscussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $createddiscussion);
908
909 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
910 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
911
912 $this->assertCount(4, $discussions['discussions']);
913 $this->assertCount(0, $createddiscussion['warnings']);
914 // Can't guarantee order of posts during tests.
915 $postfound = false;
916 foreach ($discussions['discussions'] as $thisdiscussion) {
917 if ($createddiscussion['discussionid'] == $thisdiscussion['discussion']) {
e881c4f5
BK
918 $this->assertEquals($thisdiscussion['attachment'], 1, "There should be a non-inline attachment");
919 $this->assertCount(1, $thisdiscussion['attachments'], "There should be 1 attachment");
920 $this->assertEquals($thisdiscussion['attachments'][0]['filename'], $attachfilename, "There should be 1 attachment");
41182118
BK
921 $this->assertNotContains('draftfile.php', $thisdiscussion['message']);
922 $this->assertContains('pluginfile.php', $thisdiscussion['message']);
923 $postfound = true;
e881c4f5 924 break;
41182118
BK
925 }
926 }
927
928 $this->assertTrue($postfound);
7ab43ac8
JL
929 }
930
931 /**
932 * Test adding discussions in a course with gorups
933 */
934 public function test_add_discussion_in_course_with_groups() {
935 global $CFG;
936
937 $this->resetAfterTest(true);
938
939 // Create course to add the module.
940 $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0));
941 $user = self::getDataGenerator()->create_user();
942 $this->getDataGenerator()->enrol_user($user->id, $course->id);
943
944 // Forum forcing separate gropus.
945 $record = new stdClass();
946 $record->course = $course->id;
947 $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
948
949 // Try to post (user not enrolled).
950 self::setUser($user);
951
952 // The user is not enroled in any group, try to post in a forum with separate groups.
953 try {
954 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
955 $this->fail('Exception expected due to invalid group permissions.');
956 } catch (moodle_exception $e) {
957 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
958 }
959
960 try {
961 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', 0);
962 $this->fail('Exception expected due to invalid group permissions.');
963 } catch (moodle_exception $e) {
964 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
965 }
966
967 // Create a group.
968 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
969
970 // Try to post in a group the user is not enrolled.
971 try {
972 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', $group->id);
973 $this->fail('Exception expected due to invalid group permissions.');
974 } catch (moodle_exception $e) {
975 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
976 }
977
978 // Add the user to a group.
979 groups_add_member($group->id, $user->id);
980
981 // Try to post in a group the user is not enrolled.
982 try {
983 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', $group->id + 1);
984 $this->fail('Exception expected due to invalid group.');
985 } catch (moodle_exception $e) {
986 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
987 }
988
989 // Nost add the discussion using a valid group.
990 $discussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', $group->id);
991 $discussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $discussion);
992
993 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
994 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
995
996 $this->assertCount(1, $discussions['discussions']);
997 $this->assertCount(0, $discussions['warnings']);
998 $this->assertEquals($discussion['discussionid'], $discussions['discussions'][0]['discussion']);
999 $this->assertEquals($group->id, $discussions['discussions'][0]['groupid']);
1000
1001 // Now add a discussions without indicating a group. The function should guess the correct group.
1002 $discussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
1003 $discussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $discussion);
1004
1005 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
1006 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
1007
1008 $this->assertCount(2, $discussions['discussions']);
1009 $this->assertCount(0, $discussions['warnings']);
1010 $this->assertEquals($group->id, $discussions['discussions'][0]['groupid']);
1011 $this->assertEquals($group->id, $discussions['discussions'][1]['groupid']);
1012
1013 // Enrol the same user in other group.
1014 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1015 groups_add_member($group2->id, $user->id);
1016
1017 // Now add a discussions without indicating a group. The function should guess the correct group (the first one).
1018 $discussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
1019 $discussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $discussion);
1020
1021 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
1022 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
1023
1024 $this->assertCount(3, $discussions['discussions']);
1025 $this->assertCount(0, $discussions['warnings']);
1026 $this->assertEquals($group->id, $discussions['discussions'][0]['groupid']);
1027 $this->assertEquals($group->id, $discussions['discussions'][1]['groupid']);
1028 $this->assertEquals($group->id, $discussions['discussions'][2]['groupid']);
1029
1030 }
1031
04cd8ae3
JL
1032 /*
1033 * Test can_add_discussion. A basic test since all the API functions are already covered by unit tests.
1034 */
1035 public function test_can_add_discussion() {
581e75bf 1036 global $DB;
04cd8ae3
JL
1037 $this->resetAfterTest(true);
1038
1039 // Create courses to add the modules.
1040 $course = self::getDataGenerator()->create_course();
1041
1042 $user = self::getDataGenerator()->create_user();
1043
1044 // First forum with tracking off.
1045 $record = new stdClass();
1046 $record->course = $course->id;
1047 $record->type = 'news';
1048 $forum = self::getDataGenerator()->create_module('forum', $record);
1049
1050 // User with no permissions to add in a news forum.
1051 self::setUser($user);
1052 $this->getDataGenerator()->enrol_user($user->id, $course->id);
1053
1054 $result = mod_forum_external::can_add_discussion($forum->id);
1055 $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
1056 $this->assertFalse($result['status']);
581e75bf
JL
1057 $this->assertFalse($result['canpindiscussions']);
1058 $this->assertTrue($result['cancreateattachment']);
1059
1060 // Disable attachments.
1061 $DB->set_field('forum', 'maxattachments', 0, array('id' => $forum->id));
1062 $result = mod_forum_external::can_add_discussion($forum->id);
1063 $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
1064 $this->assertFalse($result['status']);
1065 $this->assertFalse($result['canpindiscussions']);
1066 $this->assertFalse($result['cancreateattachment']);
1067 $DB->set_field('forum', 'maxattachments', 1, array('id' => $forum->id)); // Enable attachments again.
04cd8ae3
JL
1068
1069 self::setAdminUser();
1070 $result = mod_forum_external::can_add_discussion($forum->id);
1071 $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
1072 $this->assertTrue($result['status']);
581e75bf
JL
1073 $this->assertTrue($result['canpindiscussions']);
1074 $this->assertTrue($result['cancreateattachment']);
04cd8ae3
JL
1075
1076 }
1077
b7ce46df
JL
1078 /**
1079 * Test get forum posts discussions including rating information.
1080 */
1081 public function test_mod_forum_get_forum_discussion_rating_information() {
1082 global $DB, $CFG;
1083 require_once($CFG->dirroot . '/rating/lib.php');
1084
1085 $this->resetAfterTest(true);
1086
1087 $user1 = self::getDataGenerator()->create_user();
1088 $user2 = self::getDataGenerator()->create_user();
1089 $user3 = self::getDataGenerator()->create_user();
1090 $teacher = self::getDataGenerator()->create_user();
1091
1092 // Create course to add the module.
1093 $course = self::getDataGenerator()->create_course();
1094
1095 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1096 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
1097 $this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id, 'manual');
1098 $this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id, 'manual');
1099 $this->getDataGenerator()->enrol_user($user3->id, $course->id, $studentrole->id, 'manual');
1100 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
1101
1102 // Create the forum.
1103 $record = new stdClass();
1104 $record->course = $course->id;
1105 // Set Aggregate type = Average of ratings.
1106 $record->assessed = RATING_AGGREGATE_AVERAGE;
1107 $record->scale = 100;
1108 $forum = self::getDataGenerator()->create_module('forum', $record);
1109 $context = context_module::instance($forum->cmid);
1110
1111 // Add discussion to the forum.
1112 $record = new stdClass();
1113 $record->course = $course->id;
1114 $record->userid = $user1->id;
1115 $record->forum = $forum->id;
1116 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1117
1118 // Retrieve the first post.
1119 $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1120
1121 // Rate the discussion as user2.
1122 $rating1 = new stdClass();
1123 $rating1->contextid = $context->id;
1124 $rating1->component = 'mod_forum';
1125 $rating1->ratingarea = 'post';
1126 $rating1->itemid = $post->id;
1127 $rating1->rating = 50;
1128 $rating1->scaleid = 100;
1129 $rating1->userid = $user2->id;
1130 $rating1->timecreated = time();
1131 $rating1->timemodified = time();
1132 $rating1->id = $DB->insert_record('rating', $rating1);
1133
1134 // Rate the discussion as user3.
1135 $rating2 = new stdClass();
1136 $rating2->contextid = $context->id;
1137 $rating2->component = 'mod_forum';
1138 $rating2->ratingarea = 'post';
1139 $rating2->itemid = $post->id;
1140 $rating2->rating = 100;
1141 $rating2->scaleid = 100;
1142 $rating2->userid = $user3->id;
1143 $rating2->timecreated = time() + 1;
1144 $rating2->timemodified = time() + 1;
1145 $rating2->id = $DB->insert_record('rating', $rating2);
1146
1147 // Retrieve the rating for the post as student.
1148 $this->setUser($user1);
1149 $posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
1150 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
1151 $this->assertCount(1, $posts['ratinginfo']['ratings']);
1152 $this->assertTrue($posts['ratinginfo']['ratings'][0]['canviewaggregate']);
1153 $this->assertFalse($posts['ratinginfo']['canviewall']);
1154 $this->assertFalse($posts['ratinginfo']['ratings'][0]['canrate']);
1155 $this->assertEquals(2, $posts['ratinginfo']['ratings'][0]['count']);
1156 $this->assertEquals(($rating1->rating + $rating2->rating) / 2, $posts['ratinginfo']['ratings'][0]['aggregate']);
1157
1158 // Retrieve the rating for the post as teacher.
1159 $this->setUser($teacher);
1160 $posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
1161 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
1162 $this->assertCount(1, $posts['ratinginfo']['ratings']);
1163 $this->assertTrue($posts['ratinginfo']['ratings'][0]['canviewaggregate']);
1164 $this->assertTrue($posts['ratinginfo']['canviewall']);
1165 $this->assertTrue($posts['ratinginfo']['ratings'][0]['canrate']);
1166 $this->assertEquals(2, $posts['ratinginfo']['ratings'][0]['count']);
1167 $this->assertEquals(($rating1->rating + $rating2->rating) / 2, $posts['ratinginfo']['ratings'][0]['aggregate']);
1168 }
2b9fe87d 1169}