MDL-57407 core_rating: Add new external util class for handling ratings
[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(),
278 'warnings' => array(),
279 );
694bf0c7 280
d85bedf7 281 // User pictures are initially empty, we should get the links once the external function is called.
e2ede426
JL
282 $expectedposts['posts'][] = array(
283 'id' => $discussion1reply2->id,
284 'discussion' => $discussion1reply2->discussion,
285 'parent' => $discussion1reply2->parent,
48fb0250 286 'userid' => (int) $discussion1reply2->userid,
e2ede426
JL
287 'created' => $discussion1reply2->created,
288 'modified' => $discussion1reply2->modified,
289 'mailed' => $discussion1reply2->mailed,
290 'subject' => $discussion1reply2->subject,
291 'message' => file_rewrite_pluginfile_urls($discussion1reply2->message, 'pluginfile.php',
292 $forum1context->id, 'mod_forum', 'post', $discussion1reply2->id),
48fb0250 293 'messageformat' => 1, // This value is usually changed by external_format_text() function.
e2ede426
JL
294 'messagetrust' => $discussion1reply2->messagetrust,
295 'attachment' => $discussion1reply2->attachment,
296 'totalscore' => $discussion1reply2->totalscore,
297 'mailnow' => $discussion1reply2->mailnow,
298 'children' => array(),
299 'canreply' => true,
300 'postread' => false,
694bf0c7 301 'userfullname' => fullname($user3),
d85bedf7 302 'userpictureurl' => ''
e2ede426 303 );
694bf0c7 304
e2ede426
JL
305 $expectedposts['posts'][] = array(
306 'id' => $discussion1reply1->id,
307 'discussion' => $discussion1reply1->discussion,
308 'parent' => $discussion1reply1->parent,
48fb0250 309 'userid' => (int) $discussion1reply1->userid,
e2ede426
JL
310 'created' => $discussion1reply1->created,
311 'modified' => $discussion1reply1->modified,
312 'mailed' => $discussion1reply1->mailed,
313 'subject' => $discussion1reply1->subject,
314 'message' => file_rewrite_pluginfile_urls($discussion1reply1->message, 'pluginfile.php',
315 $forum1context->id, 'mod_forum', 'post', $discussion1reply1->id),
48fb0250 316 'messageformat' => 1, // This value is usually changed by external_format_text() function.
e2ede426
JL
317 'messagetrust' => $discussion1reply1->messagetrust,
318 'attachment' => $discussion1reply1->attachment,
c8743f62
JL
319 'messageinlinefiles' => array(
320 array(
321 'filename' => $filename,
322 'filepath' => '/',
323 'filesize' => '27',
324 'fileurl' => moodle_url::make_webservice_pluginfile_url($forum1context->id, 'mod_forum', 'post',
325 $discussion1reply1->id, '/', $filename),
326 'timemodified' => $timepost,
327 'mimetype' => 'image/jpeg',
1104a9fa 328 'isexternalfile' => false,
c8743f62
JL
329 )
330 ),
e2ede426
JL
331 'totalscore' => $discussion1reply1->totalscore,
332 'mailnow' => $discussion1reply1->mailnow,
d2c58b95 333 'children' => array($discussion1reply2->id),
e2ede426
JL
334 'canreply' => true,
335 'postread' => false,
694bf0c7 336 'userfullname' => fullname($user2),
d85bedf7 337 'userpictureurl' => ''
e2ede426
JL
338 );
339
340 // Test a discussion with two additional posts (total 3 posts).
341 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
342 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
343 $this->assertEquals(3, count($posts['posts']));
344
d85bedf7
JL
345 // Generate here the pictures because we need to wait to the external function to init the theme.
346 $userpicture = new user_picture($user3);
347 $userpicture->size = 1; // Size f1.
348 $expectedposts['posts'][0]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
349
350 $userpicture = new user_picture($user2);
351 $userpicture->size = 1; // Size f1.
352 $expectedposts['posts'][1]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
353
e2ede426
JL
354 // Unset the initial discussion post.
355 array_pop($posts['posts']);
356 $this->assertEquals($expectedposts, $posts);
357
2256bb74
JL
358 // Check we receive the unread count correctly on tracked forum.
359 forum_tp_count_forum_unread_posts($forum2cm, $course1, true); // Reset static cache.
360 $result = mod_forum_external::get_forums_by_courses(array($course1->id));
361 $result = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $result);
362 foreach ($result as $f) {
363 if ($f['id'] == $forum2->id) {
364 $this->assertEquals(1, $f['unreadpostscount']);
365 }
366 }
367
e2ede426
JL
368 // Test discussion without additional posts. There should be only one post (the one created by the discussion).
369 $posts = mod_forum_external::get_forum_discussion_posts($discussion2->id, 'modified', 'DESC');
370 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
371 $this->assertEquals(1, count($posts['posts']));
372
db3c9ff8
PFO
373 // Test discussion tracking on not tracked forum.
374 $result = mod_forum_external::view_forum_discussion($discussion1->id);
375 $result = external_api::clean_returnvalue(mod_forum_external::view_forum_discussion_returns(), $result);
376 $this->assertTrue($result['status']);
377 $this->assertEmpty($result['warnings']);
378
379 // Test posts have not been marked as read.
380 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
381 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
382 foreach ($posts['posts'] as $post) {
383 $this->assertFalse($post['postread']);
384 }
385
386 // Test discussion tracking on tracked forum.
387 $result = mod_forum_external::view_forum_discussion($discussion3->id);
388 $result = external_api::clean_returnvalue(mod_forum_external::view_forum_discussion_returns(), $result);
389 $this->assertTrue($result['status']);
390 $this->assertEmpty($result['warnings']);
391
392 // Test posts have been marked as read.
393 $posts = mod_forum_external::get_forum_discussion_posts($discussion3->id, 'modified', 'DESC');
394 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
395 foreach ($posts['posts'] as $post) {
396 $this->assertTrue($post['postread']);
397 }
2256bb74
JL
398
399 // Check we receive 0 unread posts.
400 forum_tp_count_forum_unread_posts($forum2cm, $course1, true); // Reset static cache.
401 $result = mod_forum_external::get_forums_by_courses(array($course1->id));
402 $result = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $result);
403 foreach ($result as $f) {
404 if ($f['id'] == $forum2->id) {
405 $this->assertEquals(0, $f['unreadpostscount']);
406 }
407 }
e2ede426 408 }
c2586672 409
b1aa7dfa
JL
410 /**
411 * Test get forum posts (qanda forum)
412 */
413 public function test_mod_forum_get_forum_discussion_posts_qanda() {
414 global $CFG, $DB;
415
416 $this->resetAfterTest(true);
417
418 $record = new stdClass();
419 $user1 = self::getDataGenerator()->create_user($record);
420 $user2 = self::getDataGenerator()->create_user();
421
422 // Set the first created user to the test user.
423 self::setUser($user1);
424
425 // Create course to add the module.
426 $course1 = self::getDataGenerator()->create_course();
427 $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
428 $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
429
430 // Forum with tracking off.
431 $record = new stdClass();
432 $record->course = $course1->id;
433 $record->type = 'qanda';
434 $forum1 = self::getDataGenerator()->create_module('forum', $record);
435 $forum1context = context_module::instance($forum1->cmid);
436
437 // Add discussions to the forums.
438 $record = new stdClass();
439 $record->course = $course1->id;
440 $record->userid = $user2->id;
441 $record->forum = $forum1->id;
442 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
443
444 // Add 1 reply (not the actual user).
445 $record = new stdClass();
446 $record->discussion = $discussion1->id;
447 $record->parent = $discussion1->firstpost;
448 $record->userid = $user2->id;
449 $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
450
451 // We still see only the original post.
452 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
453 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
454 $this->assertEquals(1, count($posts['posts']));
455
456 // Add a new reply, the user is going to be able to see only the original post and their new post.
457 $record = new stdClass();
458 $record->discussion = $discussion1->id;
459 $record->parent = $discussion1->firstpost;
460 $record->userid = $user1->id;
461 $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
462
463 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
464 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
465 $this->assertEquals(2, count($posts['posts']));
466
467 // Now, we can fake the time of the user post, so he can se the rest of the discussion posts.
468 $discussion1reply2->created -= $CFG->maxeditingtime * 2;
469 $DB->update_record('forum_posts', $discussion1reply2);
470
471 $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
472 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
473 $this->assertEquals(3, count($posts['posts']));
b1aa7dfa
JL
474 }
475
c2586672
JL
476 /**
477 * Test get forum discussions paginated
478 */
479 public function test_mod_forum_get_forum_discussions_paginated() {
d85bedf7 480 global $USER, $CFG, $DB, $PAGE;
c2586672
JL
481
482 $this->resetAfterTest(true);
483
484 // Set the CFG variable to allow track forums.
485 $CFG->forum_trackreadposts = true;
486
487 // Create a user who can track forums.
488 $record = new stdClass();
489 $record->trackforums = true;
490 $user1 = self::getDataGenerator()->create_user($record);
491 // Create a bunch of other users to post.
492 $user2 = self::getDataGenerator()->create_user();
493 $user3 = self::getDataGenerator()->create_user();
494 $user4 = self::getDataGenerator()->create_user();
495
496 // Set the first created user to the test user.
497 self::setUser($user1);
498
499 // Create courses to add the modules.
500 $course1 = self::getDataGenerator()->create_course();
501
502 // First forum with tracking off.
503 $record = new stdClass();
504 $record->course = $course1->id;
505 $record->trackingtype = FORUM_TRACKING_OFF;
506 $forum1 = self::getDataGenerator()->create_module('forum', $record);
507
508 // Add discussions to the forums.
509 $record = new stdClass();
510 $record->course = $course1->id;
511 $record->userid = $user1->id;
512 $record->forum = $forum1->id;
513 $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
514
515 // Add three replies to the discussion 1 from different users.
516 $record = new stdClass();
517 $record->discussion = $discussion1->id;
518 $record->parent = $discussion1->firstpost;
519 $record->userid = $user2->id;
520 $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
521
522 $record->parent = $discussion1reply1->id;
523 $record->userid = $user3->id;
524 $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
525
526 $record->userid = $user4->id;
527 $discussion1reply3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
528
529 // Enrol the user in the first course.
530 $enrol = enrol_get_plugin('manual');
531
532 // We don't use the dataGenerator as we need to get the $instance2 to unenrol later.
533 $enrolinstances = enrol_get_instances($course1->id, true);
534 foreach ($enrolinstances as $courseenrolinstance) {
535 if ($courseenrolinstance->enrol == "manual") {
536 $instance1 = $courseenrolinstance;
537 break;
538 }
539 }
540 $enrol->enrol_user($instance1, $user1->id);
541
81f810dc
JL
542 // Delete one user.
543 delete_user($user4);
544
c2586672
JL
545 // Assign capabilities to view discussions for forum 1.
546 $cm = get_coursemodule_from_id('forum', $forum1->cmid, 0, false, MUST_EXIST);
547 $context = context_module::instance($cm->id);
548 $newrole = create_role('Role 2', 'role2', 'Role 2 description');
549 $this->assignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole);
550
551 // Create what we expect to be returned when querying the forums.
552
553 $post1 = $DB->get_record('forum_posts', array('id' => $discussion1->firstpost), '*', MUST_EXIST);
c2586672 554
d85bedf7 555 // User pictures are initially empty, we should get the links once the external function is called.
c2586672
JL
556 $expecteddiscussions = array(
557 'id' => $discussion1->firstpost,
558 'name' => $discussion1->name,
559 'groupid' => $discussion1->groupid,
560 'timemodified' => $discussion1reply3->created,
561 'usermodified' => $discussion1reply3->userid,
562 'timestart' => $discussion1->timestart,
563 'timeend' => $discussion1->timeend,
564 'discussion' => $discussion1->id,
565 'parent' => 0,
566 'userid' => $discussion1->userid,
567 'created' => $post1->created,
568 'modified' => $post1->modified,
569 'mailed' => $post1->mailed,
570 'subject' => $post1->subject,
571 'message' => $post1->message,
572 'messageformat' => $post1->messageformat,
573 'messagetrust' => $post1->messagetrust,
574 'attachment' => $post1->attachment,
575 'totalscore' => $post1->totalscore,
576 'mailnow' => $post1->mailnow,
577 'userfullname' => fullname($user1),
578 'usermodifiedfullname' => fullname($user4),
d85bedf7
JL
579 'userpictureurl' => '',
580 'usermodifiedpictureurl' => '',
c2586672 581 'numreplies' => 3,
5f219cf1 582 'numunread' => 0,
0f3bbfd4
AN
583 'pinned' => FORUM_DISCUSSION_UNPINNED,
584 'locked' => false,
585 'canreply' => false,
c2586672
JL
586 );
587
588 // Call the external function passing forum id.
589 $discussions = mod_forum_external::get_forum_discussions_paginated($forum1->id);
590 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
591 $expectedreturn = array(
592 'discussions' => array($expecteddiscussions),
593 'warnings' => array()
594 );
d85bedf7
JL
595
596 // Wait the theme to be loaded (the external_api call does that) to generate the user profiles.
597 $userpicture = new user_picture($user1);
598 $userpicture->size = 1; // Size f1.
599 $expectedreturn['discussions'][0]['userpictureurl'] = $userpicture->get_url($PAGE)->out(false);
600
601 $userpicture = new user_picture($user4);
602 $userpicture->size = 1; // Size f1.
603 $expectedreturn['discussions'][0]['usermodifiedpictureurl'] = $userpicture->get_url($PAGE)->out(false);
604
c2586672
JL
605 $this->assertEquals($expectedreturn, $discussions);
606
607 // Call without required view discussion capability.
608 $this->unassignUserCapability('mod/forum:viewdiscussion', $context->id, $newrole);
609 try {
610 mod_forum_external::get_forum_discussions_paginated($forum1->id);
611 $this->fail('Exception expected due to missing capability.');
612 } catch (moodle_exception $e) {
613 $this->assertEquals('noviewdiscussionspermission', $e->errorcode);
614 }
615
616 // Unenrol user from second course.
617 $enrol->unenrol_user($instance1, $user1->id);
618
619 // Call for the second course we unenrolled the user from, make sure exception thrown.
620 try {
621 mod_forum_external::get_forum_discussions_paginated($forum1->id);
622 $this->fail('Exception expected due to being unenrolled from the course.');
623 } catch (moodle_exception $e) {
624 $this->assertEquals('requireloginerror', $e->errorcode);
625 }
626 }
039c81f0
JL
627
628 /**
629 * Test get forum discussions paginated (qanda forums)
630 */
631 public function test_mod_forum_get_forum_discussions_paginated_qanda() {
632
633 $this->resetAfterTest(true);
634
635 // Create courses to add the modules.
636 $course = self::getDataGenerator()->create_course();
637
638 $user1 = self::getDataGenerator()->create_user();
639 $user2 = self::getDataGenerator()->create_user();
640
641 // First forum with tracking off.
642 $record = new stdClass();
643 $record->course = $course->id;
644 $record->type = 'qanda';
645 $forum = self::getDataGenerator()->create_module('forum', $record);
646
647 // Add discussions to the forums.
648 $discussionrecord = new stdClass();
649 $discussionrecord->course = $course->id;
650 $discussionrecord->userid = $user2->id;
651 $discussionrecord->forum = $forum->id;
652 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($discussionrecord);
653
654 self::setAdminUser();
655 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
656 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
657
658 $this->assertCount(1, $discussions['discussions']);
659 $this->assertCount(0, $discussions['warnings']);
660
661 self::setUser($user1);
662 $this->getDataGenerator()->enrol_user($user1->id, $course->id);
663
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 }
50a20317
JL
671
672 /**
673 * Test add_discussion_post
674 */
675 public function test_add_discussion_post() {
e881c4f5 676 global $CFG;
50a20317
JL
677
678 $this->resetAfterTest(true);
679
680 $user = self::getDataGenerator()->create_user();
681 $otheruser = self::getDataGenerator()->create_user();
682
683 self::setAdminUser();
684
685 // Create course to add the module.
686 $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0));
687
688 // Forum with tracking off.
689 $record = new stdClass();
690 $record->course = $course->id;
691 $forum = self::getDataGenerator()->create_module('forum', $record);
692 $cm = get_coursemodule_from_id('forum', $forum->cmid, 0, false, MUST_EXIST);
693 $forumcontext = context_module::instance($forum->cmid);
694
695 // Add discussions to the forums.
696 $record = new stdClass();
697 $record->course = $course->id;
698 $record->userid = $user->id;
699 $record->forum = $forum->id;
700 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
701
702 // Try to post (user not enrolled).
703 self::setUser($user);
704 try {
705 mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
706 $this->fail('Exception expected due to being unenrolled from the course.');
707 } catch (moodle_exception $e) {
708 $this->assertEquals('requireloginerror', $e->errorcode);
709 }
710
711 $this->getDataGenerator()->enrol_user($user->id, $course->id);
712 $this->getDataGenerator()->enrol_user($otheruser->id, $course->id);
713
41182118
BK
714 $createdpost = mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
715 $createdpost = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $createdpost);
50a20317
JL
716
717 $posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
718 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
719 // We receive the discussion and the post.
720 $this->assertEquals(2, count($posts['posts']));
43ff833d
JL
721
722 $tested = false;
41182118
BK
723 foreach ($posts['posts'] as $thispost) {
724 if ($createdpost['postid'] == $thispost['id']) {
725 $this->assertEquals('some subject', $thispost['subject']);
726 $this->assertEquals('some text here...', $thispost['message']);
43ff833d
JL
727 $tested = true;
728 }
729 }
730 $this->assertTrue($tested);
50a20317 731
e881c4f5 732 // Test inline and regular attachment in post
41182118
BK
733 // Create a file in a draft area for inline attachments.
734 $draftidinlineattach = file_get_unused_draft_itemid();
e881c4f5 735 $draftidattach = file_get_unused_draft_itemid();
41182118
BK
736 self::setUser($user);
737 $usercontext = context_user::instance($user->id);
738 $filepath = '/';
739 $filearea = 'draft';
740 $component = 'user';
741 $filenameimg = 'shouldbeanimage.txt';
e881c4f5 742 $filerecordinline = array(
41182118
BK
743 'contextid' => $usercontext->id,
744 'component' => $component,
745 'filearea' => $filearea,
746 'itemid' => $draftidinlineattach,
747 'filepath' => $filepath,
748 'filename' => $filenameimg,
749 );
750 $fs = get_file_storage();
41182118 751
e881c4f5
BK
752 // Create a file in a draft area for regular attachments.
753 $filerecordattach = $filerecordinline;
754 $attachfilename = 'attachment.txt';
755 $filerecordattach['filename'] = $attachfilename;
756 $filerecordattach['itemid'] = $draftidattach;
757 $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
758 $fs->create_file_from_string($filerecordattach, 'simple text attachment');
759
48143990 760 $options = array(array('name' => 'inlineattachmentsid', 'value' => $draftidinlineattach),
e881c4f5 761 array('name' => 'attachmentsid', 'value' => $draftidattach));
41182118
BK
762 $dummytext = 'Here is an inline image: <img src="' . $CFG->wwwroot
763 . "/draftfile.php/{$usercontext->id}/user/draft/{$draftidinlineattach}/{$filenameimg}"
764 . '" alt="inlineimage">.';
765 $createdpost = mod_forum_external::add_discussion_post($discussion->firstpost, 'new post inline attachment',
766 $dummytext, $options);
767 $createdpost = external_api::clean_returnvalue(mod_forum_external::add_discussion_post_returns(), $createdpost);
768
769 $posts = mod_forum_external::get_forum_discussion_posts($discussion->id);
770 $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
771 // We receive the discussion and the post.
772 // Can't guarantee order of posts during tests.
773 $postfound = false;
774 foreach ($posts['posts'] as $thispost) {
775 if ($createdpost['postid'] == $thispost['id']) {
776 $this->assertEquals($createdpost['postid'], $thispost['id']);
e881c4f5
BK
777 $this->assertEquals($thispost['attachment'], 1, "There should be a non-inline attachment");
778 $this->assertCount(1, $thispost['attachments'], "There should be 1 attachment");
779 $this->assertEquals($thispost['attachments'][0]['filename'], $attachfilename, "There should be 1 attachment");
41182118
BK
780 $this->assertContains('pluginfile.php', $thispost['message']);
781 $postfound = true;
e881c4f5 782 break;
41182118
BK
783 }
784 }
785
786 $this->assertTrue($postfound);
787
50a20317
JL
788 // Check not posting in groups the user is not member of.
789 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
790 groups_add_member($group->id, $otheruser->id);
791
792 $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
793 $record->forum = $forum->id;
794 $record->userid = $otheruser->id;
795 $record->groupid = $group->id;
796 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
797
798 try {
799 mod_forum_external::add_discussion_post($discussion->firstpost, 'some subject', 'some text here...');
800 $this->fail('Exception expected due to invalid permissions for posting.');
801 } catch (moodle_exception $e) {
50a20317
JL
802 $this->assertEquals('nopostforum', $e->errorcode);
803 }
804
805 }
7ab43ac8
JL
806
807 /*
808 * Test add_discussion. A basic test since all the API functions are already covered by unit tests.
809 */
810 public function test_add_discussion() {
41182118 811 global $CFG, $USER;
7ab43ac8
JL
812 $this->resetAfterTest(true);
813
814 // Create courses to add the modules.
815 $course = self::getDataGenerator()->create_course();
816
817 $user1 = self::getDataGenerator()->create_user();
818 $user2 = self::getDataGenerator()->create_user();
819
820 // First forum with tracking off.
821 $record = new stdClass();
822 $record->course = $course->id;
823 $record->type = 'news';
824 $forum = self::getDataGenerator()->create_module('forum', $record);
825
826 self::setUser($user1);
827 $this->getDataGenerator()->enrol_user($user1->id, $course->id);
828
829 try {
830 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
831 $this->fail('Exception expected due to invalid permissions.');
832 } catch (moodle_exception $e) {
833 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
834 }
835
836 self::setAdminUser();
41182118
BK
837 $createddiscussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
838 $createddiscussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $createddiscussion);
7ab43ac8
JL
839
840 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
841 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
842
843 $this->assertCount(1, $discussions['discussions']);
844 $this->assertCount(0, $discussions['warnings']);
845
41182118 846 $this->assertEquals($createddiscussion['discussionid'], $discussions['discussions'][0]['discussion']);
7ab43ac8
JL
847 $this->assertEquals(-1, $discussions['discussions'][0]['groupid']);
848 $this->assertEquals('the subject', $discussions['discussions'][0]['subject']);
849 $this->assertEquals('some text here...', $discussions['discussions'][0]['message']);
850
5f219cf1
BK
851 $discussion2pinned = mod_forum_external::add_discussion($forum->id, 'the pinned subject', 'some 2 text here...', -1,
852 array('options' => array('name' => 'discussionpinned',
853 'value' => true)));
854 $discussion3 = mod_forum_external::add_discussion($forum->id, 'the non pinnedsubject', 'some 3 text here...');
855 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
856 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
857 $this->assertCount(3, $discussions['discussions']);
858 $this->assertEquals($discussion2pinned['discussionid'], $discussions['discussions'][0]['discussion']);
41182118 859
e881c4f5 860 // Test inline and regular attachment in new discussion
41182118 861 // Create a file in a draft area for inline attachments.
e881c4f5
BK
862
863 $fs = get_file_storage();
864
41182118 865 $draftidinlineattach = file_get_unused_draft_itemid();
e881c4f5
BK
866 $draftidattach = file_get_unused_draft_itemid();
867
41182118
BK
868 $usercontext = context_user::instance($USER->id);
869 $filepath = '/';
870 $filearea = 'draft';
871 $component = 'user';
872 $filenameimg = 'shouldbeanimage.txt';
873 $filerecord = array(
874 'contextid' => $usercontext->id,
875 'component' => $component,
876 'filearea' => $filearea,
877 'itemid' => $draftidinlineattach,
878 'filepath' => $filepath,
879 'filename' => $filenameimg,
880 );
e881c4f5 881
e881c4f5
BK
882 // Create a file in a draft area for regular attachments.
883 $filerecordattach = $filerecord;
884 $attachfilename = 'attachment.txt';
885 $filerecordattach['filename'] = $attachfilename;
886 $filerecordattach['itemid'] = $draftidattach;
41182118 887 $fs->create_file_from_string($filerecord, 'image contents (not really)');
e881c4f5
BK
888 $fs->create_file_from_string($filerecordattach, 'simple text attachment');
889
41182118
BK
890 $dummytext = 'Here is an inline image: <img src="' . $CFG->wwwroot .
891 "/draftfile.php/{$usercontext->id}/user/draft/{$draftidinlineattach}/{$filenameimg}" .
892 '" alt="inlineimage">.';
893
48143990 894 $options = array(array('name' => 'inlineattachmentsid', 'value' => $draftidinlineattach),
e881c4f5 895 array('name' => 'attachmentsid', 'value' => $draftidattach));
41182118
BK
896 $createddiscussion = mod_forum_external::add_discussion($forum->id, 'the inline attachment subject',
897 $dummytext, -1, $options);
898 $createddiscussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $createddiscussion);
899
900 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
901 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
902
903 $this->assertCount(4, $discussions['discussions']);
904 $this->assertCount(0, $createddiscussion['warnings']);
905 // Can't guarantee order of posts during tests.
906 $postfound = false;
907 foreach ($discussions['discussions'] as $thisdiscussion) {
908 if ($createddiscussion['discussionid'] == $thisdiscussion['discussion']) {
e881c4f5
BK
909 $this->assertEquals($thisdiscussion['attachment'], 1, "There should be a non-inline attachment");
910 $this->assertCount(1, $thisdiscussion['attachments'], "There should be 1 attachment");
911 $this->assertEquals($thisdiscussion['attachments'][0]['filename'], $attachfilename, "There should be 1 attachment");
41182118
BK
912 $this->assertNotContains('draftfile.php', $thisdiscussion['message']);
913 $this->assertContains('pluginfile.php', $thisdiscussion['message']);
914 $postfound = true;
e881c4f5 915 break;
41182118
BK
916 }
917 }
918
919 $this->assertTrue($postfound);
7ab43ac8
JL
920 }
921
922 /**
923 * Test adding discussions in a course with gorups
924 */
925 public function test_add_discussion_in_course_with_groups() {
926 global $CFG;
927
928 $this->resetAfterTest(true);
929
930 // Create course to add the module.
931 $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0));
932 $user = self::getDataGenerator()->create_user();
933 $this->getDataGenerator()->enrol_user($user->id, $course->id);
934
935 // Forum forcing separate gropus.
936 $record = new stdClass();
937 $record->course = $course->id;
938 $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
939
940 // Try to post (user not enrolled).
941 self::setUser($user);
942
943 // The user is not enroled in any group, try to post in a forum with separate groups.
944 try {
945 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
946 $this->fail('Exception expected due to invalid group permissions.');
947 } catch (moodle_exception $e) {
948 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
949 }
950
951 try {
952 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', 0);
953 $this->fail('Exception expected due to invalid group permissions.');
954 } catch (moodle_exception $e) {
955 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
956 }
957
958 // Create a group.
959 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
960
961 // Try to post in a group the user is not enrolled.
962 try {
963 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', $group->id);
964 $this->fail('Exception expected due to invalid group permissions.');
965 } catch (moodle_exception $e) {
966 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
967 }
968
969 // Add the user to a group.
970 groups_add_member($group->id, $user->id);
971
972 // Try to post in a group the user is not enrolled.
973 try {
974 mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', $group->id + 1);
975 $this->fail('Exception expected due to invalid group.');
976 } catch (moodle_exception $e) {
977 $this->assertEquals('cannotcreatediscussion', $e->errorcode);
978 }
979
980 // Nost add the discussion using a valid group.
981 $discussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...', $group->id);
982 $discussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $discussion);
983
984 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
985 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
986
987 $this->assertCount(1, $discussions['discussions']);
988 $this->assertCount(0, $discussions['warnings']);
989 $this->assertEquals($discussion['discussionid'], $discussions['discussions'][0]['discussion']);
990 $this->assertEquals($group->id, $discussions['discussions'][0]['groupid']);
991
992 // Now add a discussions without indicating a group. The function should guess the correct group.
993 $discussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
994 $discussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $discussion);
995
996 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
997 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
998
999 $this->assertCount(2, $discussions['discussions']);
1000 $this->assertCount(0, $discussions['warnings']);
1001 $this->assertEquals($group->id, $discussions['discussions'][0]['groupid']);
1002 $this->assertEquals($group->id, $discussions['discussions'][1]['groupid']);
1003
1004 // Enrol the same user in other group.
1005 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1006 groups_add_member($group2->id, $user->id);
1007
1008 // Now add a discussions without indicating a group. The function should guess the correct group (the first one).
1009 $discussion = mod_forum_external::add_discussion($forum->id, 'the subject', 'some text here...');
1010 $discussion = external_api::clean_returnvalue(mod_forum_external::add_discussion_returns(), $discussion);
1011
1012 $discussions = mod_forum_external::get_forum_discussions_paginated($forum->id);
1013 $discussions = external_api::clean_returnvalue(mod_forum_external::get_forum_discussions_paginated_returns(), $discussions);
1014
1015 $this->assertCount(3, $discussions['discussions']);
1016 $this->assertCount(0, $discussions['warnings']);
1017 $this->assertEquals($group->id, $discussions['discussions'][0]['groupid']);
1018 $this->assertEquals($group->id, $discussions['discussions'][1]['groupid']);
1019 $this->assertEquals($group->id, $discussions['discussions'][2]['groupid']);
1020
1021 }
1022
04cd8ae3
JL
1023 /*
1024 * Test can_add_discussion. A basic test since all the API functions are already covered by unit tests.
1025 */
1026 public function test_can_add_discussion() {
581e75bf 1027 global $DB;
04cd8ae3
JL
1028 $this->resetAfterTest(true);
1029
1030 // Create courses to add the modules.
1031 $course = self::getDataGenerator()->create_course();
1032
1033 $user = self::getDataGenerator()->create_user();
1034
1035 // First forum with tracking off.
1036 $record = new stdClass();
1037 $record->course = $course->id;
1038 $record->type = 'news';
1039 $forum = self::getDataGenerator()->create_module('forum', $record);
1040
1041 // User with no permissions to add in a news forum.
1042 self::setUser($user);
1043 $this->getDataGenerator()->enrol_user($user->id, $course->id);
1044
1045 $result = mod_forum_external::can_add_discussion($forum->id);
1046 $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
1047 $this->assertFalse($result['status']);
581e75bf
JL
1048 $this->assertFalse($result['canpindiscussions']);
1049 $this->assertTrue($result['cancreateattachment']);
1050
1051 // Disable attachments.
1052 $DB->set_field('forum', 'maxattachments', 0, array('id' => $forum->id));
1053 $result = mod_forum_external::can_add_discussion($forum->id);
1054 $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
1055 $this->assertFalse($result['status']);
1056 $this->assertFalse($result['canpindiscussions']);
1057 $this->assertFalse($result['cancreateattachment']);
1058 $DB->set_field('forum', 'maxattachments', 1, array('id' => $forum->id)); // Enable attachments again.
04cd8ae3
JL
1059
1060 self::setAdminUser();
1061 $result = mod_forum_external::can_add_discussion($forum->id);
1062 $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
1063 $this->assertTrue($result['status']);
581e75bf
JL
1064 $this->assertTrue($result['canpindiscussions']);
1065 $this->assertTrue($result['cancreateattachment']);
04cd8ae3
JL
1066
1067 }
1068
2b9fe87d 1069}