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