MDL-22077 forum: Deprecate unused helper trait
[moodle.git] / mod / forum / externallib.php
CommitLineData
2b9fe87d
MN
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * External forum API
20 *
21 * @package mod_forum
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
28require_once("$CFG->libdir/externallib.php");
29
30class mod_forum_external extends external_api {
31
32 /**
a9a0cb69 33 * Describes the parameters for get_forum.
2b9fe87d 34 *
9db43c73 35 * @return external_function_parameters
2b9fe87d
MN
36 * @since Moodle 2.5
37 */
38 public static function get_forums_by_courses_parameters() {
39 return new external_function_parameters (
40 array(
41 'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'course ID',
a69c9abd 42 VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 'Array of Course IDs', VALUE_DEFAULT, array()),
2b9fe87d
MN
43 )
44 );
45 }
46
47 /**
48 * Returns a list of forums in a provided list of courses,
49 * if no list is provided all forums that the user can view
50 * will be returned.
51 *
52 * @param array $courseids the course ids
53 * @return array the forum details
54 * @since Moodle 2.5
55 */
56 public static function get_forums_by_courses($courseids = array()) {
c8f1d8a0 57 global $CFG;
2b9fe87d
MN
58
59 require_once($CFG->dirroot . "/mod/forum/lib.php");
60
a9a0cb69
MN
61 $params = self::validate_parameters(self::get_forums_by_courses_parameters(), array('courseids' => $courseids));
62
583b02e4 63 $courses = array();
a9a0cb69 64 if (empty($params['courseids'])) {
583b02e4
FM
65 $courses = enrol_get_my_courses();
66 $params['courseids'] = array_keys($courses);
2b9fe87d
MN
67 }
68
69 // Array to store the forums to return.
70 $arrforums = array();
ea5b910b 71 $warnings = array();
2b9fe87d 72
0c246ae5 73 // Ensure there are courseids to loop through.
ea5b910b
JL
74 if (!empty($params['courseids'])) {
75
583b02e4 76 list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses);
c8f1d8a0
JL
77
78 // Get the forums in this course. This function checks users visibility permissions.
ea5b910b
JL
79 $forums = get_all_instances_in_courses("forum", $courses);
80 foreach ($forums as $forum) {
81
82 $course = $courses[$forum->course];
83 $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id);
84 $context = context_module::instance($cm->id);
85
86 // Skip forums we are not allowed to see discussions.
87 if (!has_capability('mod/forum:viewdiscussion', $context)) {
88 continue;
2b9fe87d 89 }
ea5b910b 90
5b587c75 91 $forum->name = external_format_string($forum->name, $context->id);
ea5b910b
JL
92 // Format the intro before being returning using the format setting.
93 list($forum->intro, $forum->introformat) = external_format_text($forum->intro, $forum->introformat,
d33c67bc 94 $context->id, 'mod_forum', 'intro', null);
7ef49bd3 95 $forum->introfiles = external_util::get_area_files($context->id, 'mod_forum', 'intro', false, false);
ea5b910b
JL
96 // Discussions count. This function does static request cache.
97 $forum->numdiscussions = forum_count_discussions($forum, $cm, $course);
98 $forum->cmid = $forum->coursemodule;
99 $forum->cancreatediscussions = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
4669389d 100 $forum->istracked = forum_tp_is_tracked($forum);
2256bb74
JL
101 if ($forum->istracked) {
102 $forum->unreadpostscount = forum_tp_count_forum_unread_posts($cm, $course);
103 }
ea5b910b
JL
104
105 // Add the forum to the array to return.
106 $arrforums[$forum->id] = $forum;
2b9fe87d
MN
107 }
108 }
109
110 return $arrforums;
111 }
112
113 /**
a9a0cb69 114 * Describes the get_forum return value.
2b9fe87d
MN
115 *
116 * @return external_single_structure
117 * @since Moodle 2.5
118 */
0f3bbfd4 119 public static function get_forums_by_courses_returns() {
2b9fe87d
MN
120 return new external_multiple_structure(
121 new external_single_structure(
122 array(
123 'id' => new external_value(PARAM_INT, 'Forum id'),
5b587c75 124 'course' => new external_value(PARAM_INT, 'Course id'),
2b9fe87d 125 'type' => new external_value(PARAM_TEXT, 'The forum type'),
5b587c75 126 'name' => new external_value(PARAM_RAW, 'Forum name'),
2b9fe87d
MN
127 'intro' => new external_value(PARAM_RAW, 'The forum intro'),
128 'introformat' => new external_format_value('intro'),
7ef49bd3 129 'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL),
2b9fe87d
MN
130 'assessed' => new external_value(PARAM_INT, 'Aggregate type'),
131 'assesstimestart' => new external_value(PARAM_INT, 'Assess start time'),
132 'assesstimefinish' => new external_value(PARAM_INT, 'Assess finish time'),
133 'scale' => new external_value(PARAM_INT, 'Scale'),
134 'maxbytes' => new external_value(PARAM_INT, 'Maximum attachment size'),
135 'maxattachments' => new external_value(PARAM_INT, 'Maximum number of attachments'),
136 'forcesubscribe' => new external_value(PARAM_INT, 'Force users to subscribe'),
137 'trackingtype' => new external_value(PARAM_INT, 'Subscription mode'),
138 'rsstype' => new external_value(PARAM_INT, 'RSS feed for this activity'),
139 'rssarticles' => new external_value(PARAM_INT, 'Number of RSS recent articles'),
140 'timemodified' => new external_value(PARAM_INT, 'Time modified'),
141 'warnafter' => new external_value(PARAM_INT, 'Post threshold for warning'),
142 'blockafter' => new external_value(PARAM_INT, 'Post threshold for blocking'),
143 'blockperiod' => new external_value(PARAM_INT, 'Time period for blocking'),
144 'completiondiscussions' => new external_value(PARAM_INT, 'Student must create discussions'),
145 'completionreplies' => new external_value(PARAM_INT, 'Student must post replies'),
146 'completionposts' => new external_value(PARAM_INT, 'Student must post discussions or replies'),
7ea6ada3 147 'cmid' => new external_value(PARAM_INT, 'Course module id'),
ea5b910b
JL
148 'numdiscussions' => new external_value(PARAM_INT, 'Number of discussions in the forum', VALUE_OPTIONAL),
149 'cancreatediscussions' => new external_value(PARAM_BOOL, 'If the user can create discussions', VALUE_OPTIONAL),
0f3bbfd4 150 'lockdiscussionafter' => new external_value(PARAM_INT, 'After what period a discussion is locked', VALUE_OPTIONAL),
4669389d 151 'istracked' => new external_value(PARAM_BOOL, 'If the user is tracking the forum', VALUE_OPTIONAL),
2256bb74
JL
152 'unreadpostscount' => new external_value(PARAM_INT, 'The number of unread posts for tracked forums',
153 VALUE_OPTIONAL),
2b9fe87d
MN
154 ), 'forum'
155 )
156 );
157 }
a9a0cb69 158
e2ede426
JL
159 /**
160 * Describes the parameters for get_forum_discussion_posts.
161 *
9db43c73 162 * @return external_function_parameters
e2ede426
JL
163 * @since Moodle 2.7
164 */
165 public static function get_forum_discussion_posts_parameters() {
166 return new external_function_parameters (
167 array(
168 'discussionid' => new external_value(PARAM_INT, 'discussion ID', VALUE_REQUIRED),
169 'sortby' => new external_value(PARAM_ALPHA,
170 'sort by this element: id, created or modified', VALUE_DEFAULT, 'created'),
171 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC')
172 )
173 );
174 }
175
176 /**
177 * Returns a list of forum posts for a discussion
178 *
179 * @param int $discussionid the post ids
180 * @param string $sortby sort by this element (id, created or modified)
181 * @param string $sortdirection sort direction: ASC or DESC
182 *
183 * @return array the forum post details
184 * @since Moodle 2.7
185 */
fb8840d2 186 public static function get_forum_discussion_posts($discussionid, $sortby = "created", $sortdirection = "DESC") {
d85bedf7 187 global $CFG, $DB, $USER, $PAGE;
e2ede426 188
b1aa7dfa 189 $posts = array();
e2ede426
JL
190 $warnings = array();
191
192 // Validate the parameter.
193 $params = self::validate_parameters(self::get_forum_discussion_posts_parameters(),
194 array(
195 'discussionid' => $discussionid,
196 'sortby' => $sortby,
197 'sortdirection' => $sortdirection));
198
199 // Compact/extract functions are not recommended.
200 $discussionid = $params['discussionid'];
201 $sortby = $params['sortby'];
202 $sortdirection = $params['sortdirection'];
203
204 $sortallowedvalues = array('id', 'created', 'modified');
205 if (!in_array($sortby, $sortallowedvalues)) {
206 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' .
207 'allowed values are: ' . implode(',', $sortallowedvalues));
208 }
209
210 $sortdirection = strtoupper($sortdirection);
211 $directionallowedvalues = array('ASC', 'DESC');
212 if (!in_array($sortdirection, $directionallowedvalues)) {
213 throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' .
214 'allowed values are: ' . implode(',', $directionallowedvalues));
215 }
216
217 $discussion = $DB->get_record('forum_discussions', array('id' => $discussionid), '*', MUST_EXIST);
218 $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
219 $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST);
220 $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST);
221
222 // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..).
223 $modcontext = context_module::instance($cm->id);
224 self::validate_context($modcontext);
225
226 // This require must be here, see mod/forum/discuss.php.
227 require_once($CFG->dirroot . "/mod/forum/lib.php");
228
229 // Check they have the view forum capability.
230 require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum');
231
232 if (! $post = forum_get_post_full($discussion->firstpost)) {
233 throw new moodle_exception('notexists', 'forum');
234 }
235
236 // This function check groups, qanda, timed discussions, etc.
237 if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
238 throw new moodle_exception('noviewdiscussionspermission', 'forum');
239 }
240
241 $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext);
242
243 // We will add this field in the response.
244 $canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
245
246 $forumtracked = forum_tp_is_tracked($forum);
247
248 $sort = 'p.' . $sortby . ' ' . $sortdirection;
b1aa7dfa 249 $allposts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
e2ede426 250
b1aa7dfa 251 foreach ($allposts as $post) {
3e95e09b 252 if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) {
e2ede426
JL
253 $warning = array();
254 $warning['item'] = 'post';
255 $warning['itemid'] = $post->id;
256 $warning['warningcode'] = '1';
257 $warning['message'] = 'You can\'t see this post';
258 $warnings[] = $warning;
259 continue;
260 }
261
262 // Function forum_get_all_discussion_posts adds postread field.
f47eeafd
JL
263 // Note that the value returned can be a boolean or an integer. The WS expects a boolean.
264 if (empty($post->postread)) {
b1aa7dfa 265 $post->postread = false;
f47eeafd 266 } else {
b1aa7dfa 267 $post->postread = true;
e2ede426 268 }
f47eeafd 269
b1aa7dfa
JL
270 $post->canreply = $canreply;
271 if (!empty($post->children)) {
272 $post->children = array_keys($post->children);
fb8840d2 273 } else {
b1aa7dfa 274 $post->children = array();
e2ede426
JL
275 }
276
3e95e09b
AN
277 if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
278 // The post is available, but has been marked as deleted.
279 // It will still be available but filled with a placeholder.
280 $post->userid = null;
281 $post->userfullname = null;
282 $post->userpictureurl = null;
283
284 $post->subject = get_string('privacy:request:delete:post:subject', 'mod_forum');
285 $post->message = get_string('privacy:request:delete:post:message', 'mod_forum');
286
287 $post->deleted = true;
288 $posts[] = $post;
289
290 continue;
291 }
292 $post->deleted = false;
293
30861fbd
JL
294 if (forum_is_author_hidden($post, $forum)) {
295 $post->userid = null;
296 $post->userfullname = null;
297 $post->userpictureurl = null;
298 } else {
299 $user = new stdclass();
300 $user->id = $post->userid;
301 $user = username_load_fields_from_object($user, $post, null, array('picture', 'imagealt', 'email'));
302 $post->userfullname = fullname($user, $canviewfullname);
81f810dc 303
30861fbd
JL
304 $userpicture = new user_picture($user);
305 $userpicture->size = 1; // Size f1.
306 $post->userpictureurl = $userpicture->get_url($PAGE)->out(false);
307 }
14ebc396 308
55bb8189 309 $post->subject = external_format_string($post->subject, $modcontext->id);
48fb0250
JL
310 // Rewrite embedded images URLs.
311 list($post->message, $post->messageformat) =
312 external_format_text($post->message, $post->messageformat, $modcontext->id, 'mod_forum', 'post', $post->id);
313
314 // List attachments.
315 if (!empty($post->attachment)) {
14590070 316 $post->attachments = external_util::get_area_files($modcontext->id, 'mod_forum', 'attachment', $post->id);
48fb0250 317 }
c8743f62
JL
318 $messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post', $post->id);
319 if (!empty($messageinlinefiles)) {
320 $post->messageinlinefiles = $messageinlinefiles;
321 }
e2ede426 322
b1aa7dfa 323 $posts[] = $post;
e2ede426
JL
324 }
325
326 $result = array();
327 $result['posts'] = $posts;
b7ce46df 328 $result['ratinginfo'] = \core_rating\external\util::get_rating_info($forum, $modcontext, 'mod_forum', 'post', $posts);
e2ede426
JL
329 $result['warnings'] = $warnings;
330 return $result;
331 }
332
333 /**
334 * Describes the get_forum_discussion_posts return value.
335 *
336 * @return external_single_structure
337 * @since Moodle 2.7
338 */
339 public static function get_forum_discussion_posts_returns() {
340 return new external_single_structure(
341 array(
342 'posts' => new external_multiple_structure(
343 new external_single_structure(
344 array(
345 'id' => new external_value(PARAM_INT, 'Post id'),
346 'discussion' => new external_value(PARAM_INT, 'Discussion id'),
347 'parent' => new external_value(PARAM_INT, 'Parent id'),
348 'userid' => new external_value(PARAM_INT, 'User id'),
349 'created' => new external_value(PARAM_INT, 'Creation time'),
350 'modified' => new external_value(PARAM_INT, 'Time modified'),
351 'mailed' => new external_value(PARAM_INT, 'Mailed?'),
352 'subject' => new external_value(PARAM_TEXT, 'The post subject'),
353 'message' => new external_value(PARAM_RAW, 'The post message'),
48fb0250 354 'messageformat' => new external_format_value('message'),
e2ede426 355 'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'),
c8743f62 356 'messageinlinefiles' => new external_files('post message inline files', VALUE_OPTIONAL),
48fb0250 357 'attachment' => new external_value(PARAM_RAW, 'Has attachments?'),
14590070 358 'attachments' => new external_files('attachments', VALUE_OPTIONAL),
e2ede426
JL
359 'totalscore' => new external_value(PARAM_INT, 'The post message total score'),
360 'mailnow' => new external_value(PARAM_INT, 'Mail now?'),
361 'children' => new external_multiple_structure(new external_value(PARAM_INT, 'children post id')),
362 'canreply' => new external_value(PARAM_BOOL, 'The user can reply to posts?'),
363 'postread' => new external_value(PARAM_BOOL, 'The post was read'),
694bf0c7 364 'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'),
3e95e09b
AN
365 'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.', VALUE_OPTIONAL),
366 'deleted' => new external_value(PARAM_BOOL, 'This post has been removed.'),
e2ede426
JL
367 ), 'post'
368 )
369 ),
b7ce46df 370 'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
e2ede426
JL
371 'warnings' => new external_warnings()
372 )
373 );
374 }
375
7c51b40a
JL
376 /**
377 * Describes the parameters for get_forum_discussions_paginated.
378 *
9db43c73 379 * @return external_function_parameters
7c51b40a
JL
380 * @since Moodle 2.8
381 */
382 public static function get_forum_discussions_paginated_parameters() {
383 return new external_function_parameters (
384 array(
385 'forumid' => new external_value(PARAM_INT, 'forum instance id', VALUE_REQUIRED),
386 'sortby' => new external_value(PARAM_ALPHA,
387 'sort by this element: id, timemodified, timestart or timeend', VALUE_DEFAULT, 'timemodified'),
388 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC'),
389 'page' => new external_value(PARAM_INT, 'current page', VALUE_DEFAULT, -1),
390 'perpage' => new external_value(PARAM_INT, 'items per page', VALUE_DEFAULT, 0),
391 )
392 );
393 }
394
395 /**
396 * Returns a list of forum discussions optionally sorted and paginated.
397 *
398 * @param int $forumid the forum instance id
399 * @param string $sortby sort by this element (id, timemodified, timestart or timeend)
400 * @param string $sortdirection sort direction: ASC or DESC
401 * @param int $page page number
402 * @param int $perpage items per page
403 *
404 * @return array the forum discussion details including warnings
405 * @since Moodle 2.8
406 */
407 public static function get_forum_discussions_paginated($forumid, $sortby = 'timemodified', $sortdirection = 'DESC',
408 $page = -1, $perpage = 0) {
d85bedf7 409 global $CFG, $DB, $USER, $PAGE;
7c51b40a
JL
410
411 require_once($CFG->dirroot . "/mod/forum/lib.php");
412
413 $warnings = array();
039c81f0 414 $discussions = array();
7c51b40a
JL
415
416 $params = self::validate_parameters(self::get_forum_discussions_paginated_parameters(),
417 array(
418 'forumid' => $forumid,
419 'sortby' => $sortby,
420 'sortdirection' => $sortdirection,
421 'page' => $page,
422 'perpage' => $perpage
423 )
424 );
425
426 // Compact/extract functions are not recommended.
427 $forumid = $params['forumid'];
428 $sortby = $params['sortby'];
429 $sortdirection = $params['sortdirection'];
430 $page = $params['page'];
431 $perpage = $params['perpage'];
432
433 $sortallowedvalues = array('id', 'timemodified', 'timestart', 'timeend');
434 if (!in_array($sortby, $sortallowedvalues)) {
435 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' .
436 'allowed values are: ' . implode(',', $sortallowedvalues));
437 }
438
439 $sortdirection = strtoupper($sortdirection);
440 $directionallowedvalues = array('ASC', 'DESC');
441 if (!in_array($sortdirection, $directionallowedvalues)) {
442 throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' .
443 'allowed values are: ' . implode(',', $directionallowedvalues));
444 }
445
446 $forum = $DB->get_record('forum', array('id' => $forumid), '*', MUST_EXIST);
447 $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST);
448 $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST);
449
450 // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..).
451 $modcontext = context_module::instance($cm->id);
452 self::validate_context($modcontext);
453
454 // Check they have the view forum capability.
455 require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum');
456
5f219cf1 457 $sort = 'd.pinned DESC, d.' . $sortby . ' ' . $sortdirection;
4f3a2d21 458 $alldiscussions = forum_get_discussions($cm, $sort, true, -1, -1, true, $page, $perpage, FORUM_POSTS_ALL_USER_GROUPS);
7c51b40a 459
039c81f0 460 if ($alldiscussions) {
7c51b40a
JL
461 $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext);
462
463 // Get the unreads array, this takes a forum id and returns data for all discussions.
464 $unreads = array();
465 if ($cantrack = forum_tp_can_track_forums($forum)) {
466 if ($forumtracked = forum_tp_is_tracked($forum)) {
467 $unreads = forum_get_discussions_unread($cm);
468 }
469 }
470 // The forum function returns the replies for all the discussions in a given forum.
471 $replies = forum_count_discussion_replies($forumid, $sort, -1, $page, $perpage);
472
039c81f0
JL
473 foreach ($alldiscussions as $discussion) {
474
7c51b40a 475 // This function checks for qanda forums.
039c81f0
JL
476 // Note that the forum_get_discussions returns as id the post id, not the discussion id so we need to do this.
477 $discussionrec = clone $discussion;
478 $discussionrec->id = $discussion->discussion;
479 if (!forum_user_can_see_discussion($forum, $discussionrec, $modcontext)) {
7c51b40a
JL
480 $warning = array();
481 // Function forum_get_discussions returns forum_posts ids not forum_discussions ones.
482 $warning['item'] = 'post';
483 $warning['itemid'] = $discussion->id;
484 $warning['warningcode'] = '1';
485 $warning['message'] = 'You can\'t see this discussion';
486 $warnings[] = $warning;
487 continue;
488 }
489
490 $discussion->numunread = 0;
491 if ($cantrack && $forumtracked) {
492 if (isset($unreads[$discussion->discussion])) {
493 $discussion->numunread = (int) $unreads[$discussion->discussion];
494 }
495 }
496
497 $discussion->numreplies = 0;
498 if (!empty($replies[$discussion->discussion])) {
499 $discussion->numreplies = (int) $replies[$discussion->discussion]->replies;
500 }
501
55bb8189
JL
502 $discussion->name = external_format_string($discussion->name, $modcontext->id);
503 $discussion->subject = external_format_string($discussion->subject, $modcontext->id);
7c51b40a
JL
504 // Rewrite embedded images URLs.
505 list($discussion->message, $discussion->messageformat) =
506 external_format_text($discussion->message, $discussion->messageformat,
507 $modcontext->id, 'mod_forum', 'post', $discussion->id);
508
509 // List attachments.
510 if (!empty($discussion->attachment)) {
14590070
JL
511 $discussion->attachments = external_util::get_area_files($modcontext->id, 'mod_forum', 'attachment',
512 $discussion->id);
7c51b40a 513 }
c8743f62
JL
514 $messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post', $discussion->id);
515 if (!empty($messageinlinefiles)) {
516 $discussion->messageinlinefiles = $messageinlinefiles;
517 }
7c51b40a 518
0f3bbfd4
AN
519 $discussion->locked = forum_discussion_is_locked($forum, $discussion);
520 $discussion->canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
521
30861fbd
JL
522 if (forum_is_author_hidden($discussion, $forum)) {
523 $discussion->userid = null;
524 $discussion->userfullname = null;
525 $discussion->userpictureurl = null;
526
527 $discussion->usermodified = null;
528 $discussion->usermodifiedfullname = null;
529 $discussion->usermodifiedpictureurl = null;
530 } else {
531 $picturefields = explode(',', user_picture::fields());
532
533 // Load user objects from the results of the query.
534 $user = new stdclass();
535 $user->id = $discussion->userid;
536 $user = username_load_fields_from_object($user, $discussion, null, $picturefields);
537 // Preserve the id, it can be modified by username_load_fields_from_object.
538 $user->id = $discussion->userid;
539 $discussion->userfullname = fullname($user, $canviewfullname);
540
541 $userpicture = new user_picture($user);
542 $userpicture->size = 1; // Size f1.
543 $discussion->userpictureurl = $userpicture->get_url($PAGE)->out(false);
544
545 $usermodified = new stdclass();
546 $usermodified->id = $discussion->usermodified;
547 $usermodified = username_load_fields_from_object($usermodified, $discussion, 'um', $picturefields);
548 // Preserve the id (it can be overwritten due to the prefixed $picturefields).
549 $usermodified->id = $discussion->usermodified;
550 $discussion->usermodifiedfullname = fullname($usermodified, $canviewfullname);
551
552 $userpicture = new user_picture($usermodified);
553 $userpicture->size = 1; // Size f1.
554 $discussion->usermodifiedpictureurl = $userpicture->get_url($PAGE)->out(false);
555 }
556
039c81f0 557 $discussions[] = $discussion;
7c51b40a
JL
558 }
559 }
560
561 $result = array();
562 $result['discussions'] = $discussions;
563 $result['warnings'] = $warnings;
564 return $result;
565
566 }
567
568 /**
569 * Describes the get_forum_discussions_paginated return value.
570 *
571 * @return external_single_structure
572 * @since Moodle 2.8
573 */
574 public static function get_forum_discussions_paginated_returns() {
575 return new external_single_structure(
576 array(
577 'discussions' => new external_multiple_structure(
578 new external_single_structure(
579 array(
580 'id' => new external_value(PARAM_INT, 'Post id'),
581 'name' => new external_value(PARAM_TEXT, 'Discussion name'),
582 'groupid' => new external_value(PARAM_INT, 'Group id'),
583 'timemodified' => new external_value(PARAM_INT, 'Time modified'),
584 'usermodified' => new external_value(PARAM_INT, 'The id of the user who last modified'),
585 'timestart' => new external_value(PARAM_INT, 'Time discussion can start'),
586 'timeend' => new external_value(PARAM_INT, 'Time discussion ends'),
587 'discussion' => new external_value(PARAM_INT, 'Discussion id'),
588 'parent' => new external_value(PARAM_INT, 'Parent id'),
589 'userid' => new external_value(PARAM_INT, 'User who started the discussion id'),
590 'created' => new external_value(PARAM_INT, 'Creation time'),
591 'modified' => new external_value(PARAM_INT, 'Time modified'),
592 'mailed' => new external_value(PARAM_INT, 'Mailed?'),
593 'subject' => new external_value(PARAM_TEXT, 'The post subject'),
594 'message' => new external_value(PARAM_RAW, 'The post message'),
595 'messageformat' => new external_format_value('message'),
596 'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'),
c8743f62 597 'messageinlinefiles' => new external_files('post message inline files', VALUE_OPTIONAL),
7c51b40a 598 'attachment' => new external_value(PARAM_RAW, 'Has attachments?'),
14590070 599 'attachments' => new external_files('attachments', VALUE_OPTIONAL),
7c51b40a
JL
600 'totalscore' => new external_value(PARAM_INT, 'The post message total score'),
601 'mailnow' => new external_value(PARAM_INT, 'Mail now?'),
602 'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'),
603 'usermodifiedfullname' => new external_value(PARAM_TEXT, 'Post modifier full name'),
604 'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.'),
605 'usermodifiedpictureurl' => new external_value(PARAM_URL, 'Post modifier picture.'),
606 'numreplies' => new external_value(PARAM_TEXT, 'The number of replies in the discussion'),
5f219cf1 607 'numunread' => new external_value(PARAM_INT, 'The number of unread discussions.'),
0f3bbfd4
AN
608 'pinned' => new external_value(PARAM_BOOL, 'Is the discussion pinned'),
609 'locked' => new external_value(PARAM_BOOL, 'Is the discussion locked'),
610 'canreply' => new external_value(PARAM_BOOL, 'Can the user reply to the discussion'),
7c51b40a
JL
611 ), 'post'
612 )
613 ),
614 'warnings' => new external_warnings()
615 )
616 );
617 }
618
4a1e44a1
JL
619 /**
620 * Returns description of method parameters
621 *
622 * @return external_function_parameters
623 * @since Moodle 2.9
624 */
625 public static function view_forum_parameters() {
626 return new external_function_parameters(
627 array(
628 'forumid' => new external_value(PARAM_INT, 'forum instance id')
629 )
630 );
631 }
632
633 /**
1c2b7882 634 * Trigger the course module viewed event and update the module completion status.
4a1e44a1
JL
635 *
636 * @param int $forumid the forum instance id
637 * @return array of warnings and status result
638 * @since Moodle 2.9
639 * @throws moodle_exception
640 */
641 public static function view_forum($forumid) {
642 global $DB, $CFG;
643 require_once($CFG->dirroot . "/mod/forum/lib.php");
644
645 $params = self::validate_parameters(self::view_forum_parameters(),
646 array(
647 'forumid' => $forumid
648 ));
649 $warnings = array();
650
651 // Request and permission validation.
ca7e2fc2 652 $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST);
4a1e44a1
JL
653 list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
654
655 $context = context_module::instance($cm->id);
656 self::validate_context($context);
657
ea2fa324
JL
658 require_capability('mod/forum:viewdiscussion', $context, null, true, 'noviewdiscussionspermission', 'forum');
659
4a1e44a1
JL
660 // Call the forum/lib API.
661 forum_view($forum, $course, $cm, $context);
662
663 $result = array();
664 $result['status'] = true;
665 $result['warnings'] = $warnings;
666 return $result;
667 }
668
669 /**
670 * Returns description of method result value
671 *
672 * @return external_description
673 * @since Moodle 2.9
674 */
675 public static function view_forum_returns() {
676 return new external_single_structure(
677 array(
678 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
679 'warnings' => new external_warnings()
680 )
681 );
682 }
683
a3c315dd
JL
684 /**
685 * Returns description of method parameters
686 *
687 * @return external_function_parameters
688 * @since Moodle 2.9
689 */
690 public static function view_forum_discussion_parameters() {
691 return new external_function_parameters(
692 array(
693 'discussionid' => new external_value(PARAM_INT, 'discussion id')
694 )
695 );
696 }
697
698 /**
1c2b7882 699 * Trigger the discussion viewed event.
a3c315dd
JL
700 *
701 * @param int $discussionid the discussion id
702 * @return array of warnings and status result
703 * @since Moodle 2.9
704 * @throws moodle_exception
705 */
706 public static function view_forum_discussion($discussionid) {
db3c9ff8 707 global $DB, $CFG, $USER;
a3c315dd
JL
708 require_once($CFG->dirroot . "/mod/forum/lib.php");
709
710 $params = self::validate_parameters(self::view_forum_discussion_parameters(),
711 array(
712 'discussionid' => $discussionid
713 ));
714 $warnings = array();
715
716 $discussion = $DB->get_record('forum_discussions', array('id' => $params['discussionid']), '*', MUST_EXIST);
717 $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
718 list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
719
720 // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..).
721 $modcontext = context_module::instance($cm->id);
722 self::validate_context($modcontext);
723
ea2fa324
JL
724 require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum');
725
a3c315dd
JL
726 // Call the forum/lib API.
727 forum_discussion_view($modcontext, $forum, $discussion);
728
db3c9ff8
PFO
729 // Mark as read if required.
730 if (!$CFG->forum_usermarksread && forum_tp_is_tracked($forum)) {
731 forum_tp_mark_discussion_read($USER, $discussion->id);
732 }
733
a3c315dd
JL
734 $result = array();
735 $result['status'] = true;
736 $result['warnings'] = $warnings;
737 return $result;
738 }
739
740 /**
741 * Returns description of method result value
742 *
743 * @return external_description
744 * @since Moodle 2.9
745 */
746 public static function view_forum_discussion_returns() {
747 return new external_single_structure(
748 array(
749 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
750 'warnings' => new external_warnings()
751 )
752 );
753 }
754
50a20317
JL
755 /**
756 * Returns description of method parameters
757 *
758 * @return external_function_parameters
759 * @since Moodle 3.0
760 */
761 public static function add_discussion_post_parameters() {
762 return new external_function_parameters(
763 array(
764 'postid' => new external_value(PARAM_INT, 'the post id we are going to reply to
765 (can be the initial discussion post'),
766 'subject' => new external_value(PARAM_TEXT, 'new post subject'),
767 'message' => new external_value(PARAM_RAW, 'new post message (only html format allowed)'),
768 'options' => new external_multiple_structure (
769 new external_single_structure(
770 array(
771 'name' => new external_value(PARAM_ALPHANUM,
772 'The allowed keys (value format) are:
773 discussionsubscribe (bool); subscribe to the discussion?, default to true
48143990 774 inlineattachmentsid (int); the draft file area id for inline attachments
e881c4f5 775 attachmentsid (int); the draft file area id for attachments
50a20317
JL
776 '),
777 'value' => new external_value(PARAM_RAW, 'the value of the option,
778 this param is validated in the external function.'
779 )
780 )
781 ), 'Options', VALUE_DEFAULT, array())
782 )
783 );
784 }
785
786 /**
787 * Create new posts into an existing discussion.
788 *
789 * @param int $postid the post id we are going to reply to
790 * @param string $subject new post subject
791 * @param string $message new post message (only html format allowed)
792 * @param array $options optional settings
793 * @return array of warnings and the new post id
794 * @since Moodle 3.0
795 * @throws moodle_exception
796 */
797 public static function add_discussion_post($postid, $subject, $message, $options = array()) {
798 global $DB, $CFG, $USER;
799 require_once($CFG->dirroot . "/mod/forum/lib.php");
800
801 $params = self::validate_parameters(self::add_discussion_post_parameters(),
609a1073
JL
802 array(
803 'postid' => $postid,
804 'subject' => $subject,
805 'message' => $message,
806 'options' => $options
807 )
808 );
809 $warnings = array();
810
811 if (!$parent = forum_get_post_full($params['postid'])) {
812 throw new moodle_exception('invalidparentpostid', 'forum');
813 }
814
815 if (!$discussion = $DB->get_record("forum_discussions", array("id" => $parent->discussion))) {
816 throw new moodle_exception('notpartofdiscussion', 'forum');
817 }
818
819 // Request and permission validation.
820 $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
821 list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
822
823 $context = context_module::instance($cm->id);
824 self::validate_context($context);
825
50a20317
JL
826 // Validate options.
827 $options = array(
41182118 828 'discussionsubscribe' => true,
48143990 829 'inlineattachmentsid' => 0,
e881c4f5 830 'attachmentsid' => null
50a20317
JL
831 );
832 foreach ($params['options'] as $option) {
833 $name = trim($option['name']);
834 switch ($name) {
835 case 'discussionsubscribe':
836 $value = clean_param($option['value'], PARAM_BOOL);
837 break;
48143990 838 case 'inlineattachmentsid':
41182118
BK
839 $value = clean_param($option['value'], PARAM_INT);
840 break;
e881c4f5
BK
841 case 'attachmentsid':
842 $value = clean_param($option['value'], PARAM_INT);
609a1073
JL
843 // Ensure that the user has permissions to create attachments.
844 if (!has_capability('mod/forum:createattachment', $context)) {
845 $value = 0;
846 }
e881c4f5 847 break;
50a20317
JL
848 default:
849 throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
850 }
851 $options[$name] = $value;
852 }
853
50a20317
JL
854 if (!forum_user_can_post($forum, $discussion, $USER, $cm, $course, $context)) {
855 throw new moodle_exception('nopostforum', 'forum');
856 }
857
858 $thresholdwarning = forum_check_throttling($forum, $cm);
859 forum_check_blocking_threshold($thresholdwarning);
860
861 // Create the post.
862 $post = new stdClass();
863 $post->discussion = $discussion->id;
864 $post->parent = $parent->id;
865 $post->subject = $params['subject'];
866 $post->message = $params['message'];
867 $post->messageformat = FORMAT_HTML; // Force formatting for now.
868 $post->messagetrust = trusttext_trusted($context);
48143990 869 $post->itemid = $options['inlineattachmentsid'];
3e95e09b
AN
870 $post->attachments = $options['attachmentsid'];
871 $post->deleted = 0;
e881c4f5
BK
872 $fakemform = $post->attachments;
873 if ($postid = forum_add_new_post($post, $fakemform)) {
50a20317
JL
874
875 $post->id = $postid;
876
877 // Trigger events and completion.
878 $params = array(
879 'context' => $context,
880 'objectid' => $post->id,
881 'other' => array(
882 'discussionid' => $discussion->id,
883 'forumid' => $forum->id,
884 'forumtype' => $forum->type,
885 )
886 );
887 $event = \mod_forum\event\post_created::create($params);
888 $event->add_record_snapshot('forum_posts', $post);
889 $event->add_record_snapshot('forum_discussions', $discussion);
890 $event->trigger();
891
892 // Update completion state.
893 $completion = new completion_info($course);
894 if ($completion->is_enabled($cm) &&
895 ($forum->completionreplies || $forum->completionposts)) {
896 $completion->update_state($cm, COMPLETION_COMPLETE);
897 }
898
899 $settings = new stdClass();
900 $settings->discussionsubscribe = $options['discussionsubscribe'];
901 forum_post_subscription($settings, $forum, $discussion);
902 } else {
903 throw new moodle_exception('couldnotadd', 'forum');
904 }
905
906 $result = array();
907 $result['postid'] = $postid;
908 $result['warnings'] = $warnings;
909 return $result;
910 }
911
912 /**
913 * Returns description of method result value
914 *
915 * @return external_description
916 * @since Moodle 3.0
917 */
918 public static function add_discussion_post_returns() {
919 return new external_single_structure(
920 array(
921 'postid' => new external_value(PARAM_INT, 'new post id'),
922 'warnings' => new external_warnings()
923 )
924 );
925 }
926
7ab43ac8
JL
927 /**
928 * Returns description of method parameters
929 *
930 * @return external_function_parameters
931 * @since Moodle 3.0
932 */
933 public static function add_discussion_parameters() {
934 return new external_function_parameters(
935 array(
7267daa8
AN
936 'forumid' => new external_value(PARAM_INT, 'Forum instance ID'),
937 'subject' => new external_value(PARAM_TEXT, 'New Discussion subject'),
938 'message' => new external_value(PARAM_RAW, 'New Discussion message (only html format allowed)'),
aa9059b9 939 'groupid' => new external_value(PARAM_INT, 'The group, default to 0', VALUE_DEFAULT, 0),
7ab43ac8
JL
940 'options' => new external_multiple_structure (
941 new external_single_structure(
942 array(
943 'name' => new external_value(PARAM_ALPHANUM,
944 'The allowed keys (value format) are:
945 discussionsubscribe (bool); subscribe to the discussion?, default to true
5f219cf1 946 discussionpinned (bool); is the discussion pinned, default to false
48143990 947 inlineattachmentsid (int); the draft file area id for inline attachments
e881c4f5 948 attachmentsid (int); the draft file area id for attachments
7ab43ac8 949 '),
7267daa8
AN
950 'value' => new external_value(PARAM_RAW, 'The value of the option,
951 This param is validated in the external function.'
7ab43ac8
JL
952 )
953 )
954 ), 'Options', VALUE_DEFAULT, array())
955 )
956 );
957 }
958
959 /**
960 * Add a new discussion into an existing forum.
961 *
962 * @param int $forumid the forum instance id
963 * @param string $subject new discussion subject
964 * @param string $message new discussion message (only html format allowed)
965 * @param int $groupid the user course group
966 * @param array $options optional settings
967 * @return array of warnings and the new discussion id
968 * @since Moodle 3.0
969 * @throws moodle_exception
970 */
aa9059b9 971 public static function add_discussion($forumid, $subject, $message, $groupid = 0, $options = array()) {
7ab43ac8
JL
972 global $DB, $CFG;
973 require_once($CFG->dirroot . "/mod/forum/lib.php");
974
975 $params = self::validate_parameters(self::add_discussion_parameters(),
976 array(
977 'forumid' => $forumid,
978 'subject' => $subject,
979 'message' => $message,
980 'groupid' => $groupid,
981 'options' => $options
982 ));
609a1073
JL
983
984 $warnings = array();
985
986 // Request and permission validation.
987 $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST);
988 list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
989
990 $context = context_module::instance($cm->id);
991 self::validate_context($context);
992
7ab43ac8
JL
993 // Validate options.
994 $options = array(
5f219cf1 995 'discussionsubscribe' => true,
41182118 996 'discussionpinned' => false,
48143990 997 'inlineattachmentsid' => 0,
e881c4f5 998 'attachmentsid' => null
7ab43ac8
JL
999 );
1000 foreach ($params['options'] as $option) {
1001 $name = trim($option['name']);
1002 switch ($name) {
1003 case 'discussionsubscribe':
1004 $value = clean_param($option['value'], PARAM_BOOL);
1005 break;
5f219cf1
BK
1006 case 'discussionpinned':
1007 $value = clean_param($option['value'], PARAM_BOOL);
1008 break;
48143990 1009 case 'inlineattachmentsid':
41182118
BK
1010 $value = clean_param($option['value'], PARAM_INT);
1011 break;
e881c4f5
BK
1012 case 'attachmentsid':
1013 $value = clean_param($option['value'], PARAM_INT);
609a1073
JL
1014 // Ensure that the user has permissions to create attachments.
1015 if (!has_capability('mod/forum:createattachment', $context)) {
1016 $value = 0;
1017 }
e881c4f5 1018 break;
7ab43ac8
JL
1019 default:
1020 throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
1021 }
1022 $options[$name] = $value;
1023 }
1024
7ab43ac8
JL
1025 // Normalize group.
1026 if (!groups_get_activity_groupmode($cm)) {
1027 // Groups not supported, force to -1.
1028 $groupid = -1;
1029 } else {
1030 // Check if we receive the default or and empty value for groupid,
1031 // in this case, get the group for the user in the activity.
aa9059b9 1032 if (empty($params['groupid'])) {
7ab43ac8
JL
1033 $groupid = groups_get_activity_group($cm);
1034 } else {
1035 // Here we rely in the group passed, forum_user_can_post_discussion will validate the group.
1036 $groupid = $params['groupid'];
1037 }
1038 }
1039
1040 if (!forum_user_can_post_discussion($forum, $groupid, -1, $cm, $context)) {
1041 throw new moodle_exception('cannotcreatediscussion', 'forum');
1042 }
1043
1044 $thresholdwarning = forum_check_throttling($forum, $cm);
1045 forum_check_blocking_threshold($thresholdwarning);
1046
1047 // Create the discussion.
1048 $discussion = new stdClass();
1049 $discussion->course = $course->id;
1050 $discussion->forum = $forum->id;
1051 $discussion->message = $params['message'];
1052 $discussion->messageformat = FORMAT_HTML; // Force formatting for now.
1053 $discussion->messagetrust = trusttext_trusted($context);
48143990 1054 $discussion->itemid = $options['inlineattachmentsid'];
7ab43ac8
JL
1055 $discussion->groupid = $groupid;
1056 $discussion->mailnow = 0;
1057 $discussion->subject = $params['subject'];
1058 $discussion->name = $discussion->subject;
1059 $discussion->timestart = 0;
1060 $discussion->timeend = 0;
e881c4f5
BK
1061 $discussion->attachments = $options['attachmentsid'];
1062
5f219cf1
BK
1063 if (has_capability('mod/forum:pindiscussions', $context) && $options['discussionpinned']) {
1064 $discussion->pinned = FORUM_DISCUSSION_PINNED;
1065 } else {
1066 $discussion->pinned = FORUM_DISCUSSION_UNPINNED;
1067 }
e881c4f5
BK
1068 $fakemform = $options['attachmentsid'];
1069 if ($discussionid = forum_add_discussion($discussion, $fakemform)) {
7ab43ac8
JL
1070
1071 $discussion->id = $discussionid;
1072
1073 // Trigger events and completion.
1074
1075 $params = array(
1076 'context' => $context,
1077 'objectid' => $discussion->id,
1078 'other' => array(
1079 'forumid' => $forum->id,
1080 )
1081 );
1082 $event = \mod_forum\event\discussion_created::create($params);
1083 $event->add_record_snapshot('forum_discussions', $discussion);
1084 $event->trigger();
1085
1086 $completion = new completion_info($course);
1087 if ($completion->is_enabled($cm) &&
1088 ($forum->completiondiscussions || $forum->completionposts)) {
1089 $completion->update_state($cm, COMPLETION_COMPLETE);
1090 }
1091
1092 $settings = new stdClass();
1093 $settings->discussionsubscribe = $options['discussionsubscribe'];
1094 forum_post_subscription($settings, $forum, $discussion);
1095 } else {
1096 throw new moodle_exception('couldnotadd', 'forum');
1097 }
1098
1099 $result = array();
1100 $result['discussionid'] = $discussionid;
1101 $result['warnings'] = $warnings;
1102 return $result;
1103 }
1104
1105 /**
1106 * Returns description of method result value
1107 *
1108 * @return external_description
1109 * @since Moodle 3.0
1110 */
1111 public static function add_discussion_returns() {
1112 return new external_single_structure(
1113 array(
7267daa8 1114 'discussionid' => new external_value(PARAM_INT, 'New Discussion ID'),
7ab43ac8
JL
1115 'warnings' => new external_warnings()
1116 )
1117 );
1118 }
1119
04cd8ae3
JL
1120 /**
1121 * Returns description of method parameters
1122 *
1123 * @return external_function_parameters
1124 * @since Moodle 3.1
1125 */
1126 public static function can_add_discussion_parameters() {
1127 return new external_function_parameters(
1128 array(
1129 'forumid' => new external_value(PARAM_INT, 'Forum instance ID'),
1130 'groupid' => new external_value(PARAM_INT, 'The group to check, default to active group.
1131 Use -1 to check if the user can post in all the groups.', VALUE_DEFAULT, null)
1132 )
1133 );
1134 }
1135
1136 /**
1137 * Check if the current user can add discussions in the given forum (and optionally for the given group).
1138 *
1139 * @param int $forumid the forum instance id
1140 * @param int $groupid the group to check, default to active group. Use -1 to check if the user can post in all the groups.
1141 * @return array of warnings and the status (true if the user can add discussions)
1142 * @since Moodle 3.1
1143 * @throws moodle_exception
1144 */
1145 public static function can_add_discussion($forumid, $groupid = null) {
1146 global $DB, $CFG;
1147 require_once($CFG->dirroot . "/mod/forum/lib.php");
1148
1149 $params = self::validate_parameters(self::can_add_discussion_parameters(),
1150 array(
1151 'forumid' => $forumid,
1152 'groupid' => $groupid,
1153 ));
1154 $warnings = array();
1155
1156 // Request and permission validation.
1157 $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST);
1158 list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
1159
1160 $context = context_module::instance($cm->id);
1161 self::validate_context($context);
1162
1163 $status = forum_user_can_post_discussion($forum, $params['groupid'], -1, $cm, $context);
1164
1165 $result = array();
1166 $result['status'] = $status;
581e75bf
JL
1167 $result['canpindiscussions'] = has_capability('mod/forum:pindiscussions', $context);
1168 $result['cancreateattachment'] = forum_can_create_attachment($forum, $context);
04cd8ae3
JL
1169 $result['warnings'] = $warnings;
1170 return $result;
1171 }
1172
1173 /**
1174 * Returns description of method result value
1175 *
1176 * @return external_description
1177 * @since Moodle 3.1
1178 */
1179 public static function can_add_discussion_returns() {
1180 return new external_single_structure(
1181 array(
1182 'status' => new external_value(PARAM_BOOL, 'True if the user can add discussions, false otherwise.'),
581e75bf
JL
1183 'canpindiscussions' => new external_value(PARAM_BOOL, 'True if the user can pin discussions, false otherwise.',
1184 VALUE_OPTIONAL),
1185 'cancreateattachment' => new external_value(PARAM_BOOL, 'True if the user can add attachments, false otherwise.',
1186 VALUE_OPTIONAL),
04cd8ae3
JL
1187 'warnings' => new external_warnings()
1188 )
1189 );
1190 }
1191
4daa0d08
JL
1192 /**
1193 * Describes the parameters for get_forum_access_information.
1194 *
1195 * @return external_external_function_parameters
1196 * @since Moodle 3.7
1197 */
1198 public static function get_forum_access_information_parameters() {
1199 return new external_function_parameters (
1200 array(
1201 'forumid' => new external_value(PARAM_INT, 'Forum instance id.')
1202 )
1203 );
1204 }
1205
1206 /**
1207 * Return access information for a given forum.
1208 *
1209 * @param int $forumid forum instance id
1210 * @return array of warnings and the access information
1211 * @since Moodle 3.7
1212 * @throws moodle_exception
1213 */
1214 public static function get_forum_access_information($forumid) {
1215 global $DB;
1216
1217 $params = self::validate_parameters(self::get_forum_access_information_parameters(), array('forumid' => $forumid));
1218
1219 // Request and permission validation.
1220 $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST);
1221 $cm = get_coursemodule_from_instance('forum', $forum->id);
1222
1223 $context = context_module::instance($cm->id);
1224 self::validate_context($context);
1225
1226 $result = array();
1227 // Return all the available capabilities.
1228 $capabilities = load_capability_def('mod_forum');
1229 foreach ($capabilities as $capname => $capdata) {
1230 // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
1231 $field = 'can' . str_replace('mod/forum:', '', $capname);
1232 $result[$field] = has_capability($capname, $context);
1233 }
1234
1235 $result['warnings'] = array();
1236 return $result;
1237 }
1238
1239 /**
1240 * Describes the get_forum_access_information return value.
1241 *
1242 * @return external_single_structure
1243 * @since Moodle 3.7
1244 */
1245 public static function get_forum_access_information_returns() {
1246
1247 $structure = array(
1248 'warnings' => new external_warnings()
1249 );
1250
1251 $capabilities = load_capability_def('mod_forum');
1252 foreach ($capabilities as $capname => $capdata) {
1253 // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
1254 $field = 'can' . str_replace('mod/forum:', '', $capname);
1255 $structure[$field] = new external_value(PARAM_BOOL, 'Whether the user has the capability ' . $capname . ' allowed.',
1256 VALUE_OPTIONAL);
1257 }
1258
1259 return new external_single_structure($structure);
1260 }
2646e9d6
RW
1261
1262 /**
1263 * Set the subscription state.
1264 *
1265 * @param int $forumid
1266 * @param int $discussionid
1267 * @param bool $targetstate
1268 * @return \stdClass
1269 */
1270 public static function set_subscription_state($forumid, $discussionid, $targetstate) {
f30f46db 1271 global $PAGE, $USER;
2646e9d6
RW
1272
1273 $params = self::validate_parameters(self::set_subscription_state_parameters(), [
1274 'forumid' => $forumid,
1275 'discussionid' => $discussionid,
1276 'targetstate' => $targetstate
1277 ]);
1278
1279 $vaultfactory = mod_forum\local\container::get_vault_factory();
1280 $forumvault = $vaultfactory->get_forum_vault();
1281 $forum = $forumvault->get_from_id($params['forumid']);
2646e9d6 1282 $coursemodule = $forum->get_course_module_record();
96a49734 1283 $context = $forum->get_context();
2646e9d6 1284
96a49734 1285 self::validate_context($context);
2646e9d6 1286
2646e9d6
RW
1287 $discussionvault = $vaultfactory->get_discussion_vault();
1288 $discussion = $discussionvault->get_from_id($params['discussionid']);
1289 $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
1290
1291 $forumrecord = $legacydatamapperfactory->get_forum_data_mapper()->to_legacy_object($forum);
1292 $discussionrecord = $legacydatamapperfactory->get_discussion_data_mapper()->to_legacy_object($discussion);
1293
1294 if (!\mod_forum\subscriptions::is_subscribable($forumrecord)) {
1295 // Nothing to do. We won't actually output any content here though.
1296 throw new \moodle_exception('cannotsubscribe', 'mod_forum');
1297 }
1298
1299 $issubscribed = \mod_forum\subscriptions::is_subscribed(
1300 $USER->id,
1301 $forumrecord,
1302 $discussion->get_id(),
1303 $coursemodule
1304 );
1305
1306 // If the current state doesn't equal the desired state then update the current
1307 // state to the desired state.
1308 if ($issubscribed != (bool) $params['targetstate']) {
1309 if ($params['targetstate']) {
1310 \mod_forum\subscriptions::subscribe_user_to_discussion($USER->id, $discussionrecord, $context);
1311 } else {
1312 \mod_forum\subscriptions::unsubscribe_user_from_discussion($USER->id, $discussionrecord, $context);
1313 }
1314 }
1315
1316 $exporterfactory = mod_forum\local\container::get_exporter_factory();
1317 $exporter = $exporterfactory->get_discussion_exporter($USER, $forum, $discussion);
1318 return $exporter->export($PAGE->get_renderer('mod_forum'));
1319 }
1320
1321 /**
1322 * Returns description of method parameters.
1323 *
1324 * @return external_function_parameters
1325 */
1326 public static function set_subscription_state_parameters() {
1327 return new external_function_parameters(
1328 [
1329 'forumid' => new external_value(PARAM_INT, 'Forum that the discussion is in'),
1330 'discussionid' => new external_value(PARAM_INT, 'The discussion to subscribe or unsubscribe'),
1331 'targetstate' => new external_value(PARAM_BOOL, 'The target state')
1332 ]
1333 );
1334 }
1335
1336 /**
1337 * Returns description of method result value.
1338 *
1339 * @return external_description
1340 */
1341 public static function set_subscription_state_returns() {
1342 return \mod_forum\local\exporters\discussion::get_read_structure();
1343 }
2b9fe87d 1344}