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 | ||
9b4f09ba | 30 | use mod_forum\local\exporters\post as post_exporter; |
99bda8a7 | 31 | use mod_forum\local\exporters\discussion as discussion_exporter; |
9b4f09ba | 32 | |
2b9fe87d MN |
33 | class mod_forum_external extends external_api { |
34 | ||
35 | /** | |
a9a0cb69 | 36 | * Describes the parameters for get_forum. |
2b9fe87d | 37 | * |
9db43c73 | 38 | * @return external_function_parameters |
2b9fe87d MN |
39 | * @since Moodle 2.5 |
40 | */ | |
41 | public static function get_forums_by_courses_parameters() { | |
42 | return new external_function_parameters ( | |
43 | array( | |
44 | 'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'course ID', | |
a69c9abd | 45 | VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 'Array of Course IDs', VALUE_DEFAULT, array()), |
2b9fe87d MN |
46 | ) |
47 | ); | |
48 | } | |
49 | ||
50 | /** | |
51 | * Returns a list of forums in a provided list of courses, | |
52 | * if no list is provided all forums that the user can view | |
53 | * will be returned. | |
54 | * | |
55 | * @param array $courseids the course ids | |
56 | * @return array the forum details | |
57 | * @since Moodle 2.5 | |
58 | */ | |
59 | public static function get_forums_by_courses($courseids = array()) { | |
c8f1d8a0 | 60 | global $CFG; |
2b9fe87d MN |
61 | |
62 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
63 | ||
a9a0cb69 MN |
64 | $params = self::validate_parameters(self::get_forums_by_courses_parameters(), array('courseids' => $courseids)); |
65 | ||
583b02e4 | 66 | $courses = array(); |
a9a0cb69 | 67 | if (empty($params['courseids'])) { |
583b02e4 FM |
68 | $courses = enrol_get_my_courses(); |
69 | $params['courseids'] = array_keys($courses); | |
2b9fe87d MN |
70 | } |
71 | ||
72 | // Array to store the forums to return. | |
73 | $arrforums = array(); | |
ea5b910b | 74 | $warnings = array(); |
2b9fe87d | 75 | |
0c246ae5 | 76 | // Ensure there are courseids to loop through. |
ea5b910b JL |
77 | if (!empty($params['courseids'])) { |
78 | ||
583b02e4 | 79 | list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses); |
c8f1d8a0 JL |
80 | |
81 | // Get the forums in this course. This function checks users visibility permissions. | |
ea5b910b JL |
82 | $forums = get_all_instances_in_courses("forum", $courses); |
83 | foreach ($forums as $forum) { | |
84 | ||
85 | $course = $courses[$forum->course]; | |
86 | $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id); | |
87 | $context = context_module::instance($cm->id); | |
88 | ||
89 | // Skip forums we are not allowed to see discussions. | |
90 | if (!has_capability('mod/forum:viewdiscussion', $context)) { | |
91 | continue; | |
2b9fe87d | 92 | } |
ea5b910b | 93 | |
5b587c75 | 94 | $forum->name = external_format_string($forum->name, $context->id); |
ea5b910b | 95 | // Format the intro before being returning using the format setting. |
dfd48815 JL |
96 | $options = array('noclean' => true); |
97 | list($forum->intro, $forum->introformat) = | |
98 | external_format_text($forum->intro, $forum->introformat, $context->id, 'mod_forum', 'intro', null, $options); | |
7ef49bd3 | 99 | $forum->introfiles = external_util::get_area_files($context->id, 'mod_forum', 'intro', false, false); |
ea5b910b JL |
100 | // Discussions count. This function does static request cache. |
101 | $forum->numdiscussions = forum_count_discussions($forum, $cm, $course); | |
102 | $forum->cmid = $forum->coursemodule; | |
103 | $forum->cancreatediscussions = forum_user_can_post_discussion($forum, null, -1, $cm, $context); | |
4669389d | 104 | $forum->istracked = forum_tp_is_tracked($forum); |
2256bb74 JL |
105 | if ($forum->istracked) { |
106 | $forum->unreadpostscount = forum_tp_count_forum_unread_posts($cm, $course); | |
107 | } | |
ea5b910b JL |
108 | |
109 | // Add the forum to the array to return. | |
110 | $arrforums[$forum->id] = $forum; | |
2b9fe87d MN |
111 | } |
112 | } | |
113 | ||
114 | return $arrforums; | |
115 | } | |
116 | ||
117 | /** | |
a9a0cb69 | 118 | * Describes the get_forum return value. |
2b9fe87d MN |
119 | * |
120 | * @return external_single_structure | |
121 | * @since Moodle 2.5 | |
122 | */ | |
0f3bbfd4 | 123 | public static function get_forums_by_courses_returns() { |
2b9fe87d MN |
124 | return new external_multiple_structure( |
125 | new external_single_structure( | |
126 | array( | |
127 | 'id' => new external_value(PARAM_INT, 'Forum id'), | |
5b587c75 | 128 | 'course' => new external_value(PARAM_INT, 'Course id'), |
2b9fe87d | 129 | 'type' => new external_value(PARAM_TEXT, 'The forum type'), |
5b587c75 | 130 | 'name' => new external_value(PARAM_RAW, 'Forum name'), |
2b9fe87d MN |
131 | 'intro' => new external_value(PARAM_RAW, 'The forum intro'), |
132 | 'introformat' => new external_format_value('intro'), | |
7ef49bd3 | 133 | 'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL), |
99bcb318 SR |
134 | 'duedate' => new external_value(PARAM_INT, 'duedate for the user', VALUE_OPTIONAL), |
135 | 'cutoffdate' => new external_value(PARAM_INT, 'cutoffdate for the user', VALUE_OPTIONAL), | |
2b9fe87d MN |
136 | 'assessed' => new external_value(PARAM_INT, 'Aggregate type'), |
137 | 'assesstimestart' => new external_value(PARAM_INT, 'Assess start time'), | |
138 | 'assesstimefinish' => new external_value(PARAM_INT, 'Assess finish time'), | |
139 | 'scale' => new external_value(PARAM_INT, 'Scale'), | |
140 | 'maxbytes' => new external_value(PARAM_INT, 'Maximum attachment size'), | |
141 | 'maxattachments' => new external_value(PARAM_INT, 'Maximum number of attachments'), | |
142 | 'forcesubscribe' => new external_value(PARAM_INT, 'Force users to subscribe'), | |
143 | 'trackingtype' => new external_value(PARAM_INT, 'Subscription mode'), | |
144 | 'rsstype' => new external_value(PARAM_INT, 'RSS feed for this activity'), | |
145 | 'rssarticles' => new external_value(PARAM_INT, 'Number of RSS recent articles'), | |
146 | 'timemodified' => new external_value(PARAM_INT, 'Time modified'), | |
147 | 'warnafter' => new external_value(PARAM_INT, 'Post threshold for warning'), | |
148 | 'blockafter' => new external_value(PARAM_INT, 'Post threshold for blocking'), | |
149 | 'blockperiod' => new external_value(PARAM_INT, 'Time period for blocking'), | |
150 | 'completiondiscussions' => new external_value(PARAM_INT, 'Student must create discussions'), | |
151 | 'completionreplies' => new external_value(PARAM_INT, 'Student must post replies'), | |
152 | 'completionposts' => new external_value(PARAM_INT, 'Student must post discussions or replies'), | |
7ea6ada3 | 153 | 'cmid' => new external_value(PARAM_INT, 'Course module id'), |
ea5b910b JL |
154 | 'numdiscussions' => new external_value(PARAM_INT, 'Number of discussions in the forum', VALUE_OPTIONAL), |
155 | 'cancreatediscussions' => new external_value(PARAM_BOOL, 'If the user can create discussions', VALUE_OPTIONAL), | |
0f3bbfd4 | 156 | 'lockdiscussionafter' => new external_value(PARAM_INT, 'After what period a discussion is locked', VALUE_OPTIONAL), |
4669389d | 157 | 'istracked' => new external_value(PARAM_BOOL, 'If the user is tracking the forum', VALUE_OPTIONAL), |
2256bb74 JL |
158 | 'unreadpostscount' => new external_value(PARAM_INT, 'The number of unread posts for tracked forums', |
159 | VALUE_OPTIONAL), | |
2b9fe87d MN |
160 | ), 'forum' |
161 | ) | |
162 | ); | |
163 | } | |
a9a0cb69 | 164 | |
bc4c7337 AN |
165 | /** |
166 | * Get the forum posts in the specified discussion. | |
167 | * | |
168 | * @param int $discussionid | |
169 | * @param string $sortby | |
170 | * @param string $sortdirection | |
171 | * @return array | |
172 | */ | |
173 | public static function get_discussion_posts(int $discussionid, ?string $sortby, ?string $sortdirection) { | |
174 | global $USER; | |
175 | // Validate the parameter. | |
176 | $params = self::validate_parameters(self::get_discussion_posts_parameters(), [ | |
177 | 'discussionid' => $discussionid, | |
178 | 'sortby' => $sortby, | |
179 | 'sortdirection' => $sortdirection, | |
180 | ]); | |
181 | $warnings = []; | |
182 | ||
183 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
184 | ||
185 | $discussionvault = $vaultfactory->get_discussion_vault(); | |
186 | $discussion = $discussionvault->get_from_id($params['discussionid']); | |
187 | ||
188 | $forumvault = $vaultfactory->get_forum_vault(); | |
189 | $forum = $forumvault->get_from_id($discussion->get_forum_id()); | |
190 | ||
191 | $sortby = $params['sortby']; | |
192 | $sortdirection = $params['sortdirection']; | |
193 | $sortallowedvalues = ['id', 'created', 'modified']; | |
194 | $directionallowedvalues = ['ASC', 'DESC']; | |
195 | ||
196 | if (!in_array(strtolower($sortby), $sortallowedvalues)) { | |
197 | throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . | |
198 | 'allowed values are: ' . implode(', ', $sortallowedvalues)); | |
199 | } | |
200 | ||
201 | $sortdirection = strtoupper($sortdirection); | |
202 | if (!in_array($sortdirection, $directionallowedvalues)) { | |
203 | throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . | |
204 | 'allowed values are: ' . implode(',', $directionallowedvalues)); | |
205 | } | |
206 | ||
207 | $managerfactory = mod_forum\local\container::get_manager_factory(); | |
208 | $capabilitymanager = $managerfactory->get_capability_manager($forum); | |
209 | ||
210 | $postvault = $vaultfactory->get_post_vault(); | |
211 | $posts = $postvault->get_from_discussion_id( | |
212 | $USER, | |
213 | $discussion->get_id(), | |
214 | $capabilitymanager->can_view_any_private_reply($USER), | |
215 | "{$sortby} {$sortdirection}" | |
216 | ); | |
217 | ||
218 | $builderfactory = mod_forum\local\container::get_builder_factory(); | |
219 | $postbuilder = $builderfactory->get_exported_posts_builder(); | |
220 | ||
221 | $legacydatamapper = mod_forum\local\container::get_legacy_data_mapper_factory(); | |
222 | ||
223 | return [ | |
224 | 'posts' => $postbuilder->build($USER, [$forum], [$discussion], $posts), | |
225 | 'ratinginfo' => \core_rating\external\util::get_rating_info( | |
226 | $legacydatamapper->get_forum_data_mapper()->to_legacy_object($forum), | |
227 | $forum->get_context(), | |
228 | 'mod_forum', | |
229 | 'post', | |
230 | $legacydatamapper->get_post_data_mapper()->to_legacy_objects($posts) | |
231 | ), | |
232 | 'warnings' => $warnings, | |
233 | ]; | |
234 | } | |
235 | ||
236 | /** | |
237 | * Describe the post parameters. | |
238 | * | |
239 | * @return external_function_parameters | |
240 | */ | |
241 | public static function get_discussion_posts_parameters() { | |
242 | return new external_function_parameters ([ | |
243 | 'discussionid' => new external_value(PARAM_INT, 'The ID of the discussion from which to fetch posts.', VALUE_REQUIRED), | |
244 | 'sortby' => new external_value(PARAM_ALPHA, 'Sort by this element: id, created or modified', VALUE_DEFAULT, 'created'), | |
245 | 'sortdirection' => new external_value(PARAM_ALPHA, 'Sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC') | |
246 | ]); | |
247 | } | |
248 | ||
249 | /** | |
250 | * Describe the post return format. | |
251 | * | |
252 | * @return external_single_structure | |
253 | */ | |
254 | public static function get_discussion_posts_returns() { | |
255 | return new external_single_structure([ | |
256 | 'posts' => new external_multiple_structure(\mod_forum\local\exporters\post::get_read_structure()), | |
257 | 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), | |
258 | 'warnings' => new external_warnings() | |
259 | ]); | |
260 | } | |
261 | ||
e2ede426 JL |
262 | /** |
263 | * Describes the parameters for get_forum_discussion_posts. | |
264 | * | |
9db43c73 | 265 | * @return external_function_parameters |
e2ede426 JL |
266 | * @since Moodle 2.7 |
267 | */ | |
268 | public static function get_forum_discussion_posts_parameters() { | |
269 | return new external_function_parameters ( | |
270 | array( | |
271 | 'discussionid' => new external_value(PARAM_INT, 'discussion ID', VALUE_REQUIRED), | |
272 | 'sortby' => new external_value(PARAM_ALPHA, | |
273 | 'sort by this element: id, created or modified', VALUE_DEFAULT, 'created'), | |
274 | 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC') | |
275 | ) | |
276 | ); | |
277 | } | |
278 | ||
279 | /** | |
280 | * Returns a list of forum posts for a discussion | |
281 | * | |
282 | * @param int $discussionid the post ids | |
283 | * @param string $sortby sort by this element (id, created or modified) | |
284 | * @param string $sortdirection sort direction: ASC or DESC | |
285 | * | |
286 | * @return array the forum post details | |
287 | * @since Moodle 2.7 | |
8245daba | 288 | * @todo MDL-65252 This will be removed in Moodle 4.1 |
e2ede426 | 289 | */ |
fb8840d2 | 290 | public static function get_forum_discussion_posts($discussionid, $sortby = "created", $sortdirection = "DESC") { |
d85bedf7 | 291 | global $CFG, $DB, $USER, $PAGE; |
e2ede426 | 292 | |
b1aa7dfa | 293 | $posts = array(); |
e2ede426 JL |
294 | $warnings = array(); |
295 | ||
296 | // Validate the parameter. | |
297 | $params = self::validate_parameters(self::get_forum_discussion_posts_parameters(), | |
298 | array( | |
299 | 'discussionid' => $discussionid, | |
300 | 'sortby' => $sortby, | |
301 | 'sortdirection' => $sortdirection)); | |
302 | ||
303 | // Compact/extract functions are not recommended. | |
304 | $discussionid = $params['discussionid']; | |
305 | $sortby = $params['sortby']; | |
306 | $sortdirection = $params['sortdirection']; | |
307 | ||
308 | $sortallowedvalues = array('id', 'created', 'modified'); | |
309 | if (!in_array($sortby, $sortallowedvalues)) { | |
310 | throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . | |
311 | 'allowed values are: ' . implode(',', $sortallowedvalues)); | |
312 | } | |
313 | ||
314 | $sortdirection = strtoupper($sortdirection); | |
315 | $directionallowedvalues = array('ASC', 'DESC'); | |
316 | if (!in_array($sortdirection, $directionallowedvalues)) { | |
317 | throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . | |
318 | 'allowed values are: ' . implode(',', $directionallowedvalues)); | |
319 | } | |
320 | ||
321 | $discussion = $DB->get_record('forum_discussions', array('id' => $discussionid), '*', MUST_EXIST); | |
322 | $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST); | |
323 | $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST); | |
324 | $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST); | |
325 | ||
326 | // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..). | |
327 | $modcontext = context_module::instance($cm->id); | |
328 | self::validate_context($modcontext); | |
329 | ||
330 | // This require must be here, see mod/forum/discuss.php. | |
331 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
332 | ||
333 | // Check they have the view forum capability. | |
334 | require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum'); | |
335 | ||
336 | if (! $post = forum_get_post_full($discussion->firstpost)) { | |
337 | throw new moodle_exception('notexists', 'forum'); | |
338 | } | |
339 | ||
340 | // This function check groups, qanda, timed discussions, etc. | |
341 | if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { | |
342 | throw new moodle_exception('noviewdiscussionspermission', 'forum'); | |
343 | } | |
344 | ||
345 | $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext); | |
346 | ||
347 | // We will add this field in the response. | |
348 | $canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext); | |
349 | ||
350 | $forumtracked = forum_tp_is_tracked($forum); | |
351 | ||
352 | $sort = 'p.' . $sortby . ' ' . $sortdirection; | |
b1aa7dfa | 353 | $allposts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked); |
e2ede426 | 354 | |
b1aa7dfa | 355 | foreach ($allposts as $post) { |
3e95e09b | 356 | if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm, false)) { |
e2ede426 JL |
357 | $warning = array(); |
358 | $warning['item'] = 'post'; | |
359 | $warning['itemid'] = $post->id; | |
360 | $warning['warningcode'] = '1'; | |
361 | $warning['message'] = 'You can\'t see this post'; | |
362 | $warnings[] = $warning; | |
363 | continue; | |
364 | } | |
365 | ||
366 | // Function forum_get_all_discussion_posts adds postread field. | |
f47eeafd JL |
367 | // Note that the value returned can be a boolean or an integer. The WS expects a boolean. |
368 | if (empty($post->postread)) { | |
b1aa7dfa | 369 | $post->postread = false; |
f47eeafd | 370 | } else { |
b1aa7dfa | 371 | $post->postread = true; |
e2ede426 | 372 | } |
f47eeafd | 373 | |
bc4c7337 AN |
374 | $post->isprivatereply = !empty($post->privatereplyto); |
375 | ||
b1aa7dfa JL |
376 | $post->canreply = $canreply; |
377 | if (!empty($post->children)) { | |
378 | $post->children = array_keys($post->children); | |
fb8840d2 | 379 | } else { |
b1aa7dfa | 380 | $post->children = array(); |
e2ede426 JL |
381 | } |
382 | ||
3e95e09b AN |
383 | if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) { |
384 | // The post is available, but has been marked as deleted. | |
385 | // It will still be available but filled with a placeholder. | |
386 | $post->userid = null; | |
387 | $post->userfullname = null; | |
388 | $post->userpictureurl = null; | |
389 | ||
390 | $post->subject = get_string('privacy:request:delete:post:subject', 'mod_forum'); | |
391 | $post->message = get_string('privacy:request:delete:post:message', 'mod_forum'); | |
392 | ||
393 | $post->deleted = true; | |
394 | $posts[] = $post; | |
395 | ||
396 | continue; | |
397 | } | |
398 | $post->deleted = false; | |
399 | ||
30861fbd JL |
400 | if (forum_is_author_hidden($post, $forum)) { |
401 | $post->userid = null; | |
402 | $post->userfullname = null; | |
403 | $post->userpictureurl = null; | |
404 | } else { | |
405 | $user = new stdclass(); | |
406 | $user->id = $post->userid; | |
407 | $user = username_load_fields_from_object($user, $post, null, array('picture', 'imagealt', 'email')); | |
408 | $post->userfullname = fullname($user, $canviewfullname); | |
81f810dc | 409 | |
30861fbd JL |
410 | $userpicture = new user_picture($user); |
411 | $userpicture->size = 1; // Size f1. | |
412 | $post->userpictureurl = $userpicture->get_url($PAGE)->out(false); | |
413 | } | |
14ebc396 | 414 | |
55bb8189 | 415 | $post->subject = external_format_string($post->subject, $modcontext->id); |
48fb0250 | 416 | // Rewrite embedded images URLs. |
29cc69f3 | 417 | $options = array('trusted' => $post->messagetrust); |
48fb0250 | 418 | list($post->message, $post->messageformat) = |
29cc69f3 JL |
419 | external_format_text($post->message, $post->messageformat, $modcontext->id, 'mod_forum', 'post', $post->id, |
420 | $options); | |
48fb0250 JL |
421 | |
422 | // List attachments. | |
423 | if (!empty($post->attachment)) { | |
14590070 | 424 | $post->attachments = external_util::get_area_files($modcontext->id, 'mod_forum', 'attachment', $post->id); |
48fb0250 | 425 | } |
c8743f62 JL |
426 | $messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post', $post->id); |
427 | if (!empty($messageinlinefiles)) { | |
428 | $post->messageinlinefiles = $messageinlinefiles; | |
429 | } | |
6c344ff2 JL |
430 | // Post tags. |
431 | $post->tags = \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $post->id); | |
e2ede426 | 432 | |
b1aa7dfa | 433 | $posts[] = $post; |
e2ede426 JL |
434 | } |
435 | ||
436 | $result = array(); | |
437 | $result['posts'] = $posts; | |
b7ce46df | 438 | $result['ratinginfo'] = \core_rating\external\util::get_rating_info($forum, $modcontext, 'mod_forum', 'post', $posts); |
e2ede426 JL |
439 | $result['warnings'] = $warnings; |
440 | return $result; | |
441 | } | |
442 | ||
443 | /** | |
444 | * Describes the get_forum_discussion_posts return value. | |
445 | * | |
446 | * @return external_single_structure | |
447 | * @since Moodle 2.7 | |
448 | */ | |
449 | public static function get_forum_discussion_posts_returns() { | |
450 | return new external_single_structure( | |
451 | array( | |
452 | 'posts' => new external_multiple_structure( | |
453 | new external_single_structure( | |
454 | array( | |
455 | 'id' => new external_value(PARAM_INT, 'Post id'), | |
456 | 'discussion' => new external_value(PARAM_INT, 'Discussion id'), | |
457 | 'parent' => new external_value(PARAM_INT, 'Parent id'), | |
458 | 'userid' => new external_value(PARAM_INT, 'User id'), | |
459 | 'created' => new external_value(PARAM_INT, 'Creation time'), | |
460 | 'modified' => new external_value(PARAM_INT, 'Time modified'), | |
461 | 'mailed' => new external_value(PARAM_INT, 'Mailed?'), | |
462 | 'subject' => new external_value(PARAM_TEXT, 'The post subject'), | |
463 | 'message' => new external_value(PARAM_RAW, 'The post message'), | |
48fb0250 | 464 | 'messageformat' => new external_format_value('message'), |
e2ede426 | 465 | 'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'), |
c8743f62 | 466 | 'messageinlinefiles' => new external_files('post message inline files', VALUE_OPTIONAL), |
48fb0250 | 467 | 'attachment' => new external_value(PARAM_RAW, 'Has attachments?'), |
14590070 | 468 | 'attachments' => new external_files('attachments', VALUE_OPTIONAL), |
e2ede426 JL |
469 | 'totalscore' => new external_value(PARAM_INT, 'The post message total score'), |
470 | 'mailnow' => new external_value(PARAM_INT, 'Mail now?'), | |
471 | 'children' => new external_multiple_structure(new external_value(PARAM_INT, 'children post id')), | |
472 | 'canreply' => new external_value(PARAM_BOOL, 'The user can reply to posts?'), | |
473 | 'postread' => new external_value(PARAM_BOOL, 'The post was read'), | |
694bf0c7 | 474 | 'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'), |
3e95e09b AN |
475 | 'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.', VALUE_OPTIONAL), |
476 | 'deleted' => new external_value(PARAM_BOOL, 'This post has been removed.'), | |
bc4c7337 | 477 | 'isprivatereply' => new external_value(PARAM_BOOL, 'The post is a private reply'), |
6c344ff2 JL |
478 | 'tags' => new external_multiple_structure( |
479 | \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL | |
480 | ), | |
e2ede426 JL |
481 | ), 'post' |
482 | ) | |
483 | ), | |
b7ce46df | 484 | 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), |
e2ede426 JL |
485 | 'warnings' => new external_warnings() |
486 | ) | |
487 | ); | |
488 | } | |
489 | ||
bc4c7337 AN |
490 | /** |
491 | * Mark the get_forum_discussion_posts web service as deprecated. | |
492 | * | |
493 | * @return bool | |
494 | */ | |
495 | public static function get_forum_discussion_posts_is_deprecated() { | |
496 | return true; | |
497 | } | |
498 | ||
7c51b40a JL |
499 | /** |
500 | * Describes the parameters for get_forum_discussions_paginated. | |
501 | * | |
1a9c60e9 | 502 | * @deprecated since 3.7 |
9db43c73 | 503 | * @return external_function_parameters |
7c51b40a JL |
504 | * @since Moodle 2.8 |
505 | */ | |
506 | public static function get_forum_discussions_paginated_parameters() { | |
507 | return new external_function_parameters ( | |
508 | array( | |
509 | 'forumid' => new external_value(PARAM_INT, 'forum instance id', VALUE_REQUIRED), | |
510 | 'sortby' => new external_value(PARAM_ALPHA, | |
511 | 'sort by this element: id, timemodified, timestart or timeend', VALUE_DEFAULT, 'timemodified'), | |
512 | 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC'), | |
513 | 'page' => new external_value(PARAM_INT, 'current page', VALUE_DEFAULT, -1), | |
514 | 'perpage' => new external_value(PARAM_INT, 'items per page', VALUE_DEFAULT, 0), | |
515 | ) | |
516 | ); | |
517 | } | |
518 | ||
519 | /** | |
520 | * Returns a list of forum discussions optionally sorted and paginated. | |
521 | * | |
1a9c60e9 | 522 | * @deprecated since 3.7 |
7c51b40a JL |
523 | * @param int $forumid the forum instance id |
524 | * @param string $sortby sort by this element (id, timemodified, timestart or timeend) | |
525 | * @param string $sortdirection sort direction: ASC or DESC | |
526 | * @param int $page page number | |
527 | * @param int $perpage items per page | |
528 | * | |
529 | * @return array the forum discussion details including warnings | |
530 | * @since Moodle 2.8 | |
531 | */ | |
532 | public static function get_forum_discussions_paginated($forumid, $sortby = 'timemodified', $sortdirection = 'DESC', | |
1a9c60e9 | 533 | $page = -1, $perpage = 0) { |
d85bedf7 | 534 | global $CFG, $DB, $USER, $PAGE; |
7c51b40a JL |
535 | |
536 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
537 | ||
538 | $warnings = array(); | |
039c81f0 | 539 | $discussions = array(); |
7c51b40a JL |
540 | |
541 | $params = self::validate_parameters(self::get_forum_discussions_paginated_parameters(), | |
542 | array( | |
543 | 'forumid' => $forumid, | |
544 | 'sortby' => $sortby, | |
545 | 'sortdirection' => $sortdirection, | |
546 | 'page' => $page, | |
547 | 'perpage' => $perpage | |
548 | ) | |
549 | ); | |
550 | ||
551 | // Compact/extract functions are not recommended. | |
552 | $forumid = $params['forumid']; | |
553 | $sortby = $params['sortby']; | |
554 | $sortdirection = $params['sortdirection']; | |
555 | $page = $params['page']; | |
556 | $perpage = $params['perpage']; | |
557 | ||
558 | $sortallowedvalues = array('id', 'timemodified', 'timestart', 'timeend'); | |
559 | if (!in_array($sortby, $sortallowedvalues)) { | |
560 | throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . | |
561 | 'allowed values are: ' . implode(',', $sortallowedvalues)); | |
562 | } | |
563 | ||
564 | $sortdirection = strtoupper($sortdirection); | |
565 | $directionallowedvalues = array('ASC', 'DESC'); | |
566 | if (!in_array($sortdirection, $directionallowedvalues)) { | |
567 | throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . | |
568 | 'allowed values are: ' . implode(',', $directionallowedvalues)); | |
569 | } | |
570 | ||
571 | $forum = $DB->get_record('forum', array('id' => $forumid), '*', MUST_EXIST); | |
572 | $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST); | |
573 | $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST); | |
574 | ||
575 | // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..). | |
576 | $modcontext = context_module::instance($cm->id); | |
577 | self::validate_context($modcontext); | |
578 | ||
579 | // Check they have the view forum capability. | |
580 | require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum'); | |
581 | ||
5f219cf1 | 582 | $sort = 'd.pinned DESC, d.' . $sortby . ' ' . $sortdirection; |
4f3a2d21 | 583 | $alldiscussions = forum_get_discussions($cm, $sort, true, -1, -1, true, $page, $perpage, FORUM_POSTS_ALL_USER_GROUPS); |
7c51b40a | 584 | |
039c81f0 | 585 | if ($alldiscussions) { |
7c51b40a JL |
586 | $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext); |
587 | ||
588 | // Get the unreads array, this takes a forum id and returns data for all discussions. | |
589 | $unreads = array(); | |
590 | if ($cantrack = forum_tp_can_track_forums($forum)) { | |
591 | if ($forumtracked = forum_tp_is_tracked($forum)) { | |
592 | $unreads = forum_get_discussions_unread($cm); | |
593 | } | |
594 | } | |
595 | // The forum function returns the replies for all the discussions in a given forum. | |
bc4c7337 | 596 | $canseeprivatereplies = has_capability('mod/forum:readprivatereplies', $modcontext); |
565cccfa | 597 | $canlock = has_capability('moodle/course:manageactivities', $modcontext, $USER); |
bc4c7337 | 598 | $replies = forum_count_discussion_replies($forumid, $sort, -1, $page, $perpage, $canseeprivatereplies); |
7c51b40a | 599 | |
039c81f0 JL |
600 | foreach ($alldiscussions as $discussion) { |
601 | ||
7c51b40a | 602 | // This function checks for qanda forums. |
039c81f0 JL |
603 | // Note that the forum_get_discussions returns as id the post id, not the discussion id so we need to do this. |
604 | $discussionrec = clone $discussion; | |
605 | $discussionrec->id = $discussion->discussion; | |
606 | if (!forum_user_can_see_discussion($forum, $discussionrec, $modcontext)) { | |
7c51b40a JL |
607 | $warning = array(); |
608 | // Function forum_get_discussions returns forum_posts ids not forum_discussions ones. | |
609 | $warning['item'] = 'post'; | |
610 | $warning['itemid'] = $discussion->id; | |
611 | $warning['warningcode'] = '1'; | |
612 | $warning['message'] = 'You can\'t see this discussion'; | |
613 | $warnings[] = $warning; | |
614 | continue; | |
615 | } | |
616 | ||
617 | $discussion->numunread = 0; | |
618 | if ($cantrack && $forumtracked) { | |
619 | if (isset($unreads[$discussion->discussion])) { | |
620 | $discussion->numunread = (int) $unreads[$discussion->discussion]; | |
621 | } | |
622 | } | |
623 | ||
624 | $discussion->numreplies = 0; | |
625 | if (!empty($replies[$discussion->discussion])) { | |
626 | $discussion->numreplies = (int) $replies[$discussion->discussion]->replies; | |
627 | } | |
628 | ||
55bb8189 JL |
629 | $discussion->name = external_format_string($discussion->name, $modcontext->id); |
630 | $discussion->subject = external_format_string($discussion->subject, $modcontext->id); | |
7c51b40a | 631 | // Rewrite embedded images URLs. |
29cc69f3 | 632 | $options = array('trusted' => $discussion->messagetrust); |
7c51b40a JL |
633 | list($discussion->message, $discussion->messageformat) = |
634 | external_format_text($discussion->message, $discussion->messageformat, | |
29cc69f3 | 635 | $modcontext->id, 'mod_forum', 'post', $discussion->id, $options); |
7c51b40a JL |
636 | |
637 | // List attachments. | |
638 | if (!empty($discussion->attachment)) { | |
14590070 JL |
639 | $discussion->attachments = external_util::get_area_files($modcontext->id, 'mod_forum', 'attachment', |
640 | $discussion->id); | |
7c51b40a | 641 | } |
c8743f62 JL |
642 | $messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post', $discussion->id); |
643 | if (!empty($messageinlinefiles)) { | |
644 | $discussion->messageinlinefiles = $messageinlinefiles; | |
645 | } | |
7c51b40a | 646 | |
565cccfa P |
647 | $discussion->locked = forum_discussion_is_locked($forum, $discussion); |
648 | $discussion->canlock = $canlock; | |
0f3bbfd4 AN |
649 | $discussion->canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext); |
650 | ||
30861fbd JL |
651 | if (forum_is_author_hidden($discussion, $forum)) { |
652 | $discussion->userid = null; | |
653 | $discussion->userfullname = null; | |
654 | $discussion->userpictureurl = null; | |
655 | ||
656 | $discussion->usermodified = null; | |
657 | $discussion->usermodifiedfullname = null; | |
658 | $discussion->usermodifiedpictureurl = null; | |
659 | } else { | |
660 | $picturefields = explode(',', user_picture::fields()); | |
661 | ||
662 | // Load user objects from the results of the query. | |
663 | $user = new stdclass(); | |
664 | $user->id = $discussion->userid; | |
665 | $user = username_load_fields_from_object($user, $discussion, null, $picturefields); | |
666 | // Preserve the id, it can be modified by username_load_fields_from_object. | |
667 | $user->id = $discussion->userid; | |
668 | $discussion->userfullname = fullname($user, $canviewfullname); | |
669 | ||
670 | $userpicture = new user_picture($user); | |
671 | $userpicture->size = 1; // Size f1. | |
672 | $discussion->userpictureurl = $userpicture->get_url($PAGE)->out(false); | |
673 | ||
674 | $usermodified = new stdclass(); | |
675 | $usermodified->id = $discussion->usermodified; | |
676 | $usermodified = username_load_fields_from_object($usermodified, $discussion, 'um', $picturefields); | |
677 | // Preserve the id (it can be overwritten due to the prefixed $picturefields). | |
678 | $usermodified->id = $discussion->usermodified; | |
679 | $discussion->usermodifiedfullname = fullname($usermodified, $canviewfullname); | |
680 | ||
681 | $userpicture = new user_picture($usermodified); | |
682 | $userpicture->size = 1; // Size f1. | |
683 | $discussion->usermodifiedpictureurl = $userpicture->get_url($PAGE)->out(false); | |
684 | } | |
685 | ||
039c81f0 | 686 | $discussions[] = $discussion; |
7c51b40a JL |
687 | } |
688 | } | |
689 | ||
690 | $result = array(); | |
691 | $result['discussions'] = $discussions; | |
692 | $result['warnings'] = $warnings; | |
693 | return $result; | |
694 | ||
695 | } | |
696 | ||
697 | /** | |
698 | * Describes the get_forum_discussions_paginated return value. | |
699 | * | |
1a9c60e9 | 700 | * @deprecated since 3.7 |
7c51b40a JL |
701 | * @return external_single_structure |
702 | * @since Moodle 2.8 | |
703 | */ | |
704 | public static function get_forum_discussions_paginated_returns() { | |
705 | return new external_single_structure( | |
706 | array( | |
707 | 'discussions' => new external_multiple_structure( | |
708 | new external_single_structure( | |
709 | array( | |
710 | 'id' => new external_value(PARAM_INT, 'Post id'), | |
711 | 'name' => new external_value(PARAM_TEXT, 'Discussion name'), | |
712 | 'groupid' => new external_value(PARAM_INT, 'Group id'), | |
713 | 'timemodified' => new external_value(PARAM_INT, 'Time modified'), | |
714 | 'usermodified' => new external_value(PARAM_INT, 'The id of the user who last modified'), | |
715 | 'timestart' => new external_value(PARAM_INT, 'Time discussion can start'), | |
716 | 'timeend' => new external_value(PARAM_INT, 'Time discussion ends'), | |
717 | 'discussion' => new external_value(PARAM_INT, 'Discussion id'), | |
718 | 'parent' => new external_value(PARAM_INT, 'Parent id'), | |
719 | 'userid' => new external_value(PARAM_INT, 'User who started the discussion id'), | |
720 | 'created' => new external_value(PARAM_INT, 'Creation time'), | |
721 | 'modified' => new external_value(PARAM_INT, 'Time modified'), | |
722 | 'mailed' => new external_value(PARAM_INT, 'Mailed?'), | |
723 | 'subject' => new external_value(PARAM_TEXT, 'The post subject'), | |
724 | 'message' => new external_value(PARAM_RAW, 'The post message'), | |
725 | 'messageformat' => new external_format_value('message'), | |
726 | 'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'), | |
c8743f62 | 727 | 'messageinlinefiles' => new external_files('post message inline files', VALUE_OPTIONAL), |
7c51b40a | 728 | 'attachment' => new external_value(PARAM_RAW, 'Has attachments?'), |
14590070 | 729 | 'attachments' => new external_files('attachments', VALUE_OPTIONAL), |
7c51b40a JL |
730 | 'totalscore' => new external_value(PARAM_INT, 'The post message total score'), |
731 | 'mailnow' => new external_value(PARAM_INT, 'Mail now?'), | |
732 | 'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'), | |
733 | 'usermodifiedfullname' => new external_value(PARAM_TEXT, 'Post modifier full name'), | |
734 | 'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.'), | |
735 | 'usermodifiedpictureurl' => new external_value(PARAM_URL, 'Post modifier picture.'), | |
28c2f2b2 | 736 | 'numreplies' => new external_value(PARAM_INT, 'The number of replies in the discussion'), |
5f219cf1 | 737 | 'numunread' => new external_value(PARAM_INT, 'The number of unread discussions.'), |
0f3bbfd4 AN |
738 | 'pinned' => new external_value(PARAM_BOOL, 'Is the discussion pinned'), |
739 | 'locked' => new external_value(PARAM_BOOL, 'Is the discussion locked'), | |
740 | 'canreply' => new external_value(PARAM_BOOL, 'Can the user reply to the discussion'), | |
565cccfa | 741 | 'canlock' => new external_value(PARAM_BOOL, 'Can the user lock the discussion'), |
7c51b40a JL |
742 | ), 'post' |
743 | ) | |
744 | ), | |
745 | 'warnings' => new external_warnings() | |
746 | ) | |
747 | ); | |
748 | } | |
749 | ||
1a9c60e9 MG |
750 | /** |
751 | * Describes the parameters for get_forum_discussions. | |
752 | * | |
753 | * @return external_function_parameters | |
754 | * @since Moodle 3.7 | |
755 | */ | |
756 | public static function get_forum_discussions_parameters() { | |
757 | return new external_function_parameters ( | |
758 | array( | |
759 | 'forumid' => new external_value(PARAM_INT, 'forum instance id', VALUE_REQUIRED), | |
760 | 'sortorder' => new external_value(PARAM_INT, | |
761 | 'sort by this element: numreplies, , created or timemodified', VALUE_DEFAULT, -1), | |
762 | 'page' => new external_value(PARAM_INT, 'current page', VALUE_DEFAULT, -1), | |
763 | 'perpage' => new external_value(PARAM_INT, 'items per page', VALUE_DEFAULT, 0), | |
764 | 'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0), | |
765 | ) | |
766 | ); | |
767 | } | |
768 | ||
769 | /** | |
770 | * Returns a list of forum discussions optionally sorted and paginated. | |
771 | * | |
772 | * @param int $forumid the forum instance id | |
773 | * @param int $sortorder The sort order | |
774 | * @param int $page page number | |
775 | * @param int $perpage items per page | |
776 | * @param int $groupid the user course group | |
777 | * | |
778 | * | |
779 | * @return array the forum discussion details including warnings | |
780 | * @since Moodle 3.7 | |
781 | */ | |
782 | public static function get_forum_discussions(int $forumid, ?int $sortorder = -1, ?int $page = -1, | |
783 | ?int $perpage = 0, ?int $groupid = 0) { | |
784 | ||
785 | global $CFG, $DB, $USER; | |
786 | ||
787 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
788 | ||
789 | $warnings = array(); | |
790 | $discussions = array(); | |
791 | ||
792 | $params = self::validate_parameters(self::get_forum_discussions_parameters(), | |
793 | array( | |
794 | 'forumid' => $forumid, | |
795 | 'sortorder' => $sortorder, | |
796 | 'page' => $page, | |
797 | 'perpage' => $perpage, | |
798 | 'groupid' => $groupid | |
799 | ) | |
800 | ); | |
801 | ||
802 | // Compact/extract functions are not recommended. | |
803 | $forumid = $params['forumid']; | |
804 | $sortorder = $params['sortorder']; | |
805 | $page = $params['page']; | |
806 | $perpage = $params['perpage']; | |
807 | $groupid = $params['groupid']; | |
808 | ||
809 | $vaultfactory = \mod_forum\local\container::get_vault_factory(); | |
810 | $discussionlistvault = $vaultfactory->get_discussions_in_forum_vault(); | |
811 | ||
812 | $sortallowedvalues = array( | |
813 | $discussionlistvault::SORTORDER_LASTPOST_DESC, | |
814 | $discussionlistvault::SORTORDER_LASTPOST_ASC, | |
815 | $discussionlistvault::SORTORDER_CREATED_DESC, | |
816 | $discussionlistvault::SORTORDER_CREATED_ASC, | |
817 | $discussionlistvault::SORTORDER_REPLIES_DESC, | |
818 | $discussionlistvault::SORTORDER_REPLIES_ASC | |
819 | ); | |
820 | ||
821 | // If sortorder not defined set a default one. | |
822 | if ($sortorder == -1) { | |
823 | $sortorder = $discussionlistvault::SORTORDER_LASTPOST_DESC; | |
824 | } | |
825 | ||
826 | if (!in_array($sortorder, $sortallowedvalues)) { | |
827 | throw new invalid_parameter_exception('Invalid value for sortorder parameter (value: ' . $sortorder . '),' . | |
828 | ' allowed values are: ' . implode(',', $sortallowedvalues)); | |
829 | } | |
830 | ||
831 | $managerfactory = \mod_forum\local\container::get_manager_factory(); | |
832 | $urlfactory = \mod_forum\local\container::get_url_factory(); | |
833 | $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); | |
834 | ||
835 | $forumvault = $vaultfactory->get_forum_vault(); | |
836 | $forum = $forumvault->get_from_id($forumid); | |
2a80ecb5 MG |
837 | if (!$forum) { |
838 | throw new \moodle_exception("Unable to find forum with id {$forumid}"); | |
839 | } | |
1a9c60e9 MG |
840 | $forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper(); |
841 | $forumrecord = $forumdatamapper->to_legacy_object($forum); | |
842 | ||
843 | $capabilitymanager = $managerfactory->get_capability_manager($forum); | |
844 | ||
845 | $course = $DB->get_record('course', array('id' => $forum->get_course_id()), '*', MUST_EXIST); | |
846 | $cm = get_coursemodule_from_instance('forum', $forum->get_id(), $course->id, false, MUST_EXIST); | |
847 | ||
848 | // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..). | |
849 | $modcontext = context_module::instance($cm->id); | |
850 | self::validate_context($modcontext); | |
851 | ||
852 | $canseeanyprivatereply = $capabilitymanager->can_view_any_private_reply($USER); | |
853 | ||
854 | // Check they have the view forum capability. | |
855 | if (!$capabilitymanager->can_view_discussions($USER)) { | |
856 | throw new moodle_exception('noviewdiscussionspermission', 'forum'); | |
857 | } | |
858 | ||
b84f79ec | 859 | $alldiscussions = mod_forum_get_discussion_summaries($forum, $USER, $groupid, $sortorder, $page, $perpage); |
1a9c60e9 MG |
860 | |
861 | if ($alldiscussions) { | |
862 | $discussionids = array_keys($alldiscussions); | |
863 | ||
864 | $postvault = $vaultfactory->get_post_vault(); | |
f31c531c | 865 | $postdatamapper = $legacydatamapperfactory->get_post_data_mapper(); |
1a9c60e9 MG |
866 | // Return the reply count for each discussion in a given forum. |
867 | $replies = $postvault->get_reply_count_for_discussion_ids($USER, $discussionids, $canseeanyprivatereply); | |
868 | // Return the first post for each discussion in a given forum. | |
869 | $firstposts = $postvault->get_first_post_for_discussion_ids($discussionids); | |
870 | ||
871 | // Get the unreads array, this takes a forum id and returns data for all discussions. | |
872 | $unreads = array(); | |
873 | if ($cantrack = forum_tp_can_track_forums($forumrecord)) { | |
874 | if ($forumtracked = forum_tp_is_tracked($forumrecord)) { | |
875 | $unreads = $postvault->get_unread_count_for_discussion_ids($USER, $discussionids, $canseeanyprivatereply); | |
876 | } | |
877 | } | |
878 | ||
879 | $canlock = $capabilitymanager->can_manage_forum($USER); | |
880 | ||
121ccf15 MG |
881 | $usercontext = context_user::instance($USER->id); |
882 | $ufservice = core_favourites\service_factory::get_service_for_user_context($usercontext); | |
883 | ||
884 | $canfavourite = has_capability('mod/forum:cantogglefavourite', $modcontext, $USER); | |
885 | ||
1a9c60e9 MG |
886 | foreach ($alldiscussions as $discussionsummary) { |
887 | $discussion = $discussionsummary->get_discussion(); | |
888 | $firstpostauthor = $discussionsummary->get_first_post_author(); | |
889 | $latestpostauthor = $discussionsummary->get_latest_post_author(); | |
890 | ||
891 | // This function checks for qanda forums. | |
892 | $canviewdiscussion = $capabilitymanager->can_view_discussion($USER, $discussion); | |
893 | if (!$canviewdiscussion) { | |
894 | $warning = array(); | |
895 | // Function forum_get_discussions returns forum_posts ids not forum_discussions ones. | |
896 | $warning['item'] = 'post'; | |
897 | $warning['itemid'] = $discussion->get_id(); | |
898 | $warning['warningcode'] = '1'; | |
899 | $warning['message'] = 'You can\'t see this discussion'; | |
900 | $warnings[] = $warning; | |
901 | continue; | |
902 | } | |
903 | ||
f31c531c RW |
904 | $firstpost = $firstposts[$discussion->get_first_post_id()]; |
905 | $discussionobject = $postdatamapper->to_legacy_object($firstpost); | |
906 | // Fix up the types for these properties. | |
907 | $discussionobject->mailed = $discussionobject->mailed ? 1 : 0; | |
908 | $discussionobject->messagetrust = $discussionobject->messagetrust ? 1 : 0; | |
909 | $discussionobject->mailnow = $discussionobject->mailnow ? 1 : 0; | |
1a9c60e9 MG |
910 | $discussionobject->groupid = $discussion->get_group_id(); |
911 | $discussionobject->timemodified = $discussion->get_time_modified(); | |
912 | $discussionobject->usermodified = $discussion->get_user_modified(); | |
913 | $discussionobject->timestart = $discussion->get_time_start(); | |
914 | $discussionobject->timeend = $discussion->get_time_end(); | |
915 | $discussionobject->pinned = $discussion->is_pinned(); | |
916 | ||
917 | $discussionobject->numunread = 0; | |
918 | if ($cantrack && $forumtracked) { | |
919 | if (isset($unreads[$discussion->get_id()])) { | |
920 | $discussionobject->numunread = (int) $unreads[$discussion->get_id()]; | |
921 | } | |
922 | } | |
923 | ||
924 | $discussionobject->numreplies = 0; | |
925 | if (!empty($replies[$discussion->get_id()])) { | |
926 | $discussionobject->numreplies = (int) $replies[$discussion->get_id()]; | |
927 | } | |
928 | ||
929 | $discussionobject->name = external_format_string($discussion->get_name(), $modcontext->id); | |
930 | $discussionobject->subject = external_format_string($discussionobject->subject, $modcontext->id); | |
931 | // Rewrite embedded images URLs. | |
29cc69f3 | 932 | $options = array('trusted' => $discussionobject->messagetrust); |
1a9c60e9 MG |
933 | list($discussionobject->message, $discussionobject->messageformat) = |
934 | external_format_text($discussionobject->message, $discussionobject->messageformat, | |
29cc69f3 | 935 | $modcontext->id, 'mod_forum', 'post', $discussionobject->id, $options); |
1a9c60e9 MG |
936 | |
937 | // List attachments. | |
938 | if (!empty($discussionobject->attachment)) { | |
939 | $discussionobject->attachments = external_util::get_area_files($modcontext->id, 'mod_forum', | |
940 | 'attachment', $discussionobject->id); | |
941 | } | |
942 | $messageinlinefiles = external_util::get_area_files($modcontext->id, 'mod_forum', 'post', | |
943 | $discussionobject->id); | |
944 | if (!empty($messageinlinefiles)) { | |
945 | $discussionobject->messageinlinefiles = $messageinlinefiles; | |
946 | } | |
947 | ||
948 | $discussionobject->locked = $forum->is_discussion_locked($discussion); | |
949 | $discussionobject->canlock = $canlock; | |
121ccf15 MG |
950 | $discussionobject->starred = !empty($ufservice) ? $ufservice->favourite_exists('mod_forum', 'discussions', |
951 | $discussion->get_id(), $modcontext) : false; | |
1a9c60e9 | 952 | $discussionobject->canreply = $capabilitymanager->can_post_in_discussion($USER, $discussion); |
121ccf15 | 953 | $discussionobject->canfavourite = $canfavourite; |
1a9c60e9 MG |
954 | |
955 | if (forum_is_author_hidden($discussionobject, $forumrecord)) { | |
956 | $discussionobject->userid = null; | |
957 | $discussionobject->userfullname = null; | |
958 | $discussionobject->userpictureurl = null; | |
959 | ||
960 | $discussionobject->usermodified = null; | |
961 | $discussionobject->usermodifiedfullname = null; | |
962 | $discussionobject->usermodifiedpictureurl = null; | |
963 | ||
964 | } else { | |
965 | $discussionobject->userfullname = $firstpostauthor->get_full_name(); | |
6489aa2a | 966 | $discussionobject->userpictureurl = $urlfactory->get_author_profile_image_url($firstpostauthor, null, 2) |
1a9c60e9 MG |
967 | ->out(false); |
968 | ||
969 | $discussionobject->usermodifiedfullname = $latestpostauthor->get_full_name(); | |
6489aa2a RW |
970 | $discussionobject->usermodifiedpictureurl = $urlfactory->get_author_profile_image_url( |
971 | $latestpostauthor, null, 2)->out(false); | |
1a9c60e9 MG |
972 | } |
973 | ||
974 | $discussions[] = (array) $discussionobject; | |
975 | } | |
976 | } | |
977 | $result = array(); | |
978 | $result['discussions'] = $discussions; | |
979 | $result['warnings'] = $warnings; | |
980 | ||
981 | return $result; | |
982 | } | |
983 | ||
984 | /** | |
985 | * Describes the get_forum_discussions return value. | |
986 | * | |
987 | * @return external_single_structure | |
988 | * @since Moodle 3.7 | |
989 | */ | |
990 | public static function get_forum_discussions_returns() { | |
991 | return new external_single_structure( | |
992 | array( | |
993 | 'discussions' => new external_multiple_structure( | |
994 | new external_single_structure( | |
995 | array( | |
996 | 'id' => new external_value(PARAM_INT, 'Post id'), | |
997 | 'name' => new external_value(PARAM_TEXT, 'Discussion name'), | |
998 | 'groupid' => new external_value(PARAM_INT, 'Group id'), | |
999 | 'timemodified' => new external_value(PARAM_INT, 'Time modified'), | |
1000 | 'usermodified' => new external_value(PARAM_INT, 'The id of the user who last modified'), | |
1001 | 'timestart' => new external_value(PARAM_INT, 'Time discussion can start'), | |
1002 | 'timeend' => new external_value(PARAM_INT, 'Time discussion ends'), | |
1003 | 'discussion' => new external_value(PARAM_INT, 'Discussion id'), | |
1004 | 'parent' => new external_value(PARAM_INT, 'Parent id'), | |
1005 | 'userid' => new external_value(PARAM_INT, 'User who started the discussion id'), | |
1006 | 'created' => new external_value(PARAM_INT, 'Creation time'), | |
1007 | 'modified' => new external_value(PARAM_INT, 'Time modified'), | |
1008 | 'mailed' => new external_value(PARAM_INT, 'Mailed?'), | |
1009 | 'subject' => new external_value(PARAM_TEXT, 'The post subject'), | |
1010 | 'message' => new external_value(PARAM_RAW, 'The post message'), | |
1011 | 'messageformat' => new external_format_value('message'), | |
1012 | 'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'), | |
1013 | 'messageinlinefiles' => new external_files('post message inline files', VALUE_OPTIONAL), | |
1014 | 'attachment' => new external_value(PARAM_RAW, 'Has attachments?'), | |
1015 | 'attachments' => new external_files('attachments', VALUE_OPTIONAL), | |
1016 | 'totalscore' => new external_value(PARAM_INT, 'The post message total score'), | |
1017 | 'mailnow' => new external_value(PARAM_INT, 'Mail now?'), | |
1018 | 'userfullname' => new external_value(PARAM_TEXT, 'Post author full name'), | |
1019 | 'usermodifiedfullname' => new external_value(PARAM_TEXT, 'Post modifier full name'), | |
1020 | 'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.'), | |
1021 | 'usermodifiedpictureurl' => new external_value(PARAM_URL, 'Post modifier picture.'), | |
1022 | 'numreplies' => new external_value(PARAM_INT, 'The number of replies in the discussion'), | |
1023 | 'numunread' => new external_value(PARAM_INT, 'The number of unread discussions.'), | |
1024 | 'pinned' => new external_value(PARAM_BOOL, 'Is the discussion pinned'), | |
1025 | 'locked' => new external_value(PARAM_BOOL, 'Is the discussion locked'), | |
121ccf15 | 1026 | 'starred' => new external_value(PARAM_BOOL, 'Is the discussion starred'), |
1a9c60e9 MG |
1027 | 'canreply' => new external_value(PARAM_BOOL, 'Can the user reply to the discussion'), |
1028 | 'canlock' => new external_value(PARAM_BOOL, 'Can the user lock the discussion'), | |
121ccf15 | 1029 | 'canfavourite' => new external_value(PARAM_BOOL, 'Can the user star the discussion'), |
1a9c60e9 MG |
1030 | ), 'post' |
1031 | ) | |
1032 | ), | |
1033 | 'warnings' => new external_warnings() | |
1034 | ) | |
1035 | ); | |
1036 | } | |
1037 | ||
4a1e44a1 JL |
1038 | /** |
1039 | * Returns description of method parameters | |
1040 | * | |
1041 | * @return external_function_parameters | |
1042 | * @since Moodle 2.9 | |
1043 | */ | |
1044 | public static function view_forum_parameters() { | |
1045 | return new external_function_parameters( | |
1046 | array( | |
1047 | 'forumid' => new external_value(PARAM_INT, 'forum instance id') | |
1048 | ) | |
1049 | ); | |
1050 | } | |
1051 | ||
1052 | /** | |
1c2b7882 | 1053 | * Trigger the course module viewed event and update the module completion status. |
4a1e44a1 JL |
1054 | * |
1055 | * @param int $forumid the forum instance id | |
1056 | * @return array of warnings and status result | |
1057 | * @since Moodle 2.9 | |
1058 | * @throws moodle_exception | |
1059 | */ | |
1060 | public static function view_forum($forumid) { | |
1061 | global $DB, $CFG; | |
1062 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
1063 | ||
1064 | $params = self::validate_parameters(self::view_forum_parameters(), | |
1065 | array( | |
1066 | 'forumid' => $forumid | |
1067 | )); | |
1068 | $warnings = array(); | |
1069 | ||
1070 | // Request and permission validation. | |
ca7e2fc2 | 1071 | $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST); |
4a1e44a1 JL |
1072 | list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum'); |
1073 | ||
1074 | $context = context_module::instance($cm->id); | |
1075 | self::validate_context($context); | |
1076 | ||
ea2fa324 JL |
1077 | require_capability('mod/forum:viewdiscussion', $context, null, true, 'noviewdiscussionspermission', 'forum'); |
1078 | ||
4a1e44a1 JL |
1079 | // Call the forum/lib API. |
1080 | forum_view($forum, $course, $cm, $context); | |
1081 | ||
1082 | $result = array(); | |
1083 | $result['status'] = true; | |
1084 | $result['warnings'] = $warnings; | |
1085 | return $result; | |
1086 | } | |
1087 | ||
1088 | /** | |
1089 | * Returns description of method result value | |
1090 | * | |
1091 | * @return external_description | |
1092 | * @since Moodle 2.9 | |
1093 | */ | |
1094 | public static function view_forum_returns() { | |
1095 | return new external_single_structure( | |
1096 | array( | |
1097 | 'status' => new external_value(PARAM_BOOL, 'status: true if success'), | |
1098 | 'warnings' => new external_warnings() | |
1099 | ) | |
1100 | ); | |
1101 | } | |
1102 | ||
a3c315dd JL |
1103 | /** |
1104 | * Returns description of method parameters | |
1105 | * | |
1106 | * @return external_function_parameters | |
1107 | * @since Moodle 2.9 | |
1108 | */ | |
1109 | public static function view_forum_discussion_parameters() { | |
1110 | return new external_function_parameters( | |
1111 | array( | |
1112 | 'discussionid' => new external_value(PARAM_INT, 'discussion id') | |
1113 | ) | |
1114 | ); | |
1115 | } | |
1116 | ||
1117 | /** | |
1c2b7882 | 1118 | * Trigger the discussion viewed event. |
a3c315dd JL |
1119 | * |
1120 | * @param int $discussionid the discussion id | |
1121 | * @return array of warnings and status result | |
1122 | * @since Moodle 2.9 | |
1123 | * @throws moodle_exception | |
1124 | */ | |
1125 | public static function view_forum_discussion($discussionid) { | |
db3c9ff8 | 1126 | global $DB, $CFG, $USER; |
a3c315dd JL |
1127 | require_once($CFG->dirroot . "/mod/forum/lib.php"); |
1128 | ||
1129 | $params = self::validate_parameters(self::view_forum_discussion_parameters(), | |
1130 | array( | |
1131 | 'discussionid' => $discussionid | |
1132 | )); | |
1133 | $warnings = array(); | |
1134 | ||
1135 | $discussion = $DB->get_record('forum_discussions', array('id' => $params['discussionid']), '*', MUST_EXIST); | |
1136 | $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST); | |
1137 | list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum'); | |
1138 | ||
1139 | // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..). | |
1140 | $modcontext = context_module::instance($cm->id); | |
1141 | self::validate_context($modcontext); | |
1142 | ||
ea2fa324 JL |
1143 | require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum'); |
1144 | ||
a3c315dd JL |
1145 | // Call the forum/lib API. |
1146 | forum_discussion_view($modcontext, $forum, $discussion); | |
1147 | ||
db3c9ff8 PFO |
1148 | // Mark as read if required. |
1149 | if (!$CFG->forum_usermarksread && forum_tp_is_tracked($forum)) { | |
1150 | forum_tp_mark_discussion_read($USER, $discussion->id); | |
1151 | } | |
1152 | ||
a3c315dd JL |
1153 | $result = array(); |
1154 | $result['status'] = true; | |
1155 | $result['warnings'] = $warnings; | |
1156 | return $result; | |
1157 | } | |
1158 | ||
1159 | /** | |
1160 | * Returns description of method result value | |
1161 | * | |
1162 | * @return external_description | |
1163 | * @since Moodle 2.9 | |
1164 | */ | |
1165 | public static function view_forum_discussion_returns() { | |
1166 | return new external_single_structure( | |
1167 | array( | |
1168 | 'status' => new external_value(PARAM_BOOL, 'status: true if success'), | |
1169 | 'warnings' => new external_warnings() | |
1170 | ) | |
1171 | ); | |
1172 | } | |
1173 | ||
50a20317 JL |
1174 | /** |
1175 | * Returns description of method parameters | |
1176 | * | |
1177 | * @return external_function_parameters | |
1178 | * @since Moodle 3.0 | |
1179 | */ | |
1180 | public static function add_discussion_post_parameters() { | |
1181 | return new external_function_parameters( | |
1182 | array( | |
1183 | 'postid' => new external_value(PARAM_INT, 'the post id we are going to reply to | |
1184 | (can be the initial discussion post'), | |
1185 | 'subject' => new external_value(PARAM_TEXT, 'new post subject'), | |
f2eb04c1 | 1186 | 'message' => new external_value(PARAM_RAW, 'new post message (html assumed if messageformat is not provided)'), |
50a20317 JL |
1187 | 'options' => new external_multiple_structure ( |
1188 | new external_single_structure( | |
1189 | array( | |
1190 | 'name' => new external_value(PARAM_ALPHANUM, | |
1191 | 'The allowed keys (value format) are: | |
1192 | discussionsubscribe (bool); subscribe to the discussion?, default to true | |
bc4c7337 | 1193 | private (bool); make this reply private to the author of the parent post, default to false. |
48143990 | 1194 | inlineattachmentsid (int); the draft file area id for inline attachments |
e881c4f5 | 1195 | attachmentsid (int); the draft file area id for attachments |
117e4bd4 | 1196 | topreferredformat (bool); convert the message & messageformat to FORMAT_HTML, defaults to false |
50a20317 JL |
1197 | '), |
1198 | 'value' => new external_value(PARAM_RAW, 'the value of the option, | |
1199 | this param is validated in the external function.' | |
1200 | ) | |
1201 | ) | |
f2eb04c1 EL |
1202 | ), 'Options', VALUE_DEFAULT, array()), |
1203 | 'messageformat' => new external_format_value('message', VALUE_DEFAULT) | |
50a20317 JL |
1204 | ) |
1205 | ); | |
1206 | } | |
1207 | ||
1208 | /** | |
1209 | * Create new posts into an existing discussion. | |
1210 | * | |
1211 | * @param int $postid the post id we are going to reply to | |
1212 | * @param string $subject new post subject | |
f2eb04c1 | 1213 | * @param string $message new post message (html assumed if messageformat is not provided) |
50a20317 | 1214 | * @param array $options optional settings |
f2eb04c1 | 1215 | * @param string $messageformat The format of the message, defaults to FORMAT_HTML for BC |
50a20317 JL |
1216 | * @return array of warnings and the new post id |
1217 | * @since Moodle 3.0 | |
1218 | * @throws moodle_exception | |
1219 | */ | |
f2eb04c1 | 1220 | public static function add_discussion_post($postid, $subject, $message, $options = array(), $messageformat = FORMAT_HTML) { |
a0c9b6af | 1221 | global $CFG, $USER; |
50a20317 JL |
1222 | require_once($CFG->dirroot . "/mod/forum/lib.php"); |
1223 | ||
9b4f09ba P |
1224 | // Get all the factories that are required. |
1225 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
1226 | $entityfactory = mod_forum\local\container::get_entity_factory(); | |
1227 | $datamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); | |
1228 | $managerfactory = mod_forum\local\container::get_manager_factory(); | |
1229 | $discussionvault = $vaultfactory->get_discussion_vault(); | |
1230 | $forumvault = $vaultfactory->get_forum_vault(); | |
1231 | $discussiondatamapper = $datamapperfactory->get_discussion_data_mapper(); | |
1232 | $forumdatamapper = $datamapperfactory->get_forum_data_mapper(); | |
1233 | ||
50a20317 | 1234 | $params = self::validate_parameters(self::add_discussion_post_parameters(), |
609a1073 JL |
1235 | array( |
1236 | 'postid' => $postid, | |
1237 | 'subject' => $subject, | |
1238 | 'message' => $message, | |
f2eb04c1 EL |
1239 | 'options' => $options, |
1240 | 'messageformat' => $messageformat, | |
609a1073 JL |
1241 | ) |
1242 | ); | |
bc4c7337 | 1243 | |
609a1073 JL |
1244 | $warnings = array(); |
1245 | ||
1246 | if (!$parent = forum_get_post_full($params['postid'])) { | |
1247 | throw new moodle_exception('invalidparentpostid', 'forum'); | |
1248 | } | |
1249 | ||
9b4f09ba | 1250 | if (!$discussion = $discussionvault->get_from_id($parent->discussion)) { |
609a1073 JL |
1251 | throw new moodle_exception('notpartofdiscussion', 'forum'); |
1252 | } | |
1253 | ||
1254 | // Request and permission validation. | |
9b4f09ba P |
1255 | $forum = $forumvault->get_from_id($discussion->get_forum_id()); |
1256 | $capabilitymanager = $managerfactory->get_capability_manager($forum); | |
1257 | $course = $forum->get_course_record(); | |
1258 | $cm = $forum->get_course_module_record(); | |
609a1073 | 1259 | |
9b4f09ba P |
1260 | $discussionrecord = $discussiondatamapper->to_legacy_object($discussion); |
1261 | $forumrecord = $forumdatamapper->to_legacy_object($forum); | |
609a1073 JL |
1262 | $context = context_module::instance($cm->id); |
1263 | self::validate_context($context); | |
1264 | ||
d411a1c1 MG |
1265 | $coursecontext = \context_course::instance($forum->get_course_id()); |
1266 | $discussionsubscribe = \mod_forum\subscriptions::get_user_default_subscription($forumrecord, $coursecontext, | |
1267 | $cm, null); | |
1268 | ||
50a20317 JL |
1269 | // Validate options. |
1270 | $options = array( | |
d411a1c1 | 1271 | 'discussionsubscribe' => $discussionsubscribe, |
bc4c7337 | 1272 | 'private' => false, |
48143990 | 1273 | 'inlineattachmentsid' => 0, |
f2eb04c1 | 1274 | 'attachmentsid' => null, |
117e4bd4 | 1275 | 'topreferredformat' => false |
50a20317 JL |
1276 | ); |
1277 | foreach ($params['options'] as $option) { | |
1278 | $name = trim($option['name']); | |
1279 | switch ($name) { | |
1280 | case 'discussionsubscribe': | |
1281 | $value = clean_param($option['value'], PARAM_BOOL); | |
1282 | break; | |
bc4c7337 AN |
1283 | case 'private': |
1284 | $value = clean_param($option['value'], PARAM_BOOL); | |
1285 | break; | |
48143990 | 1286 | case 'inlineattachmentsid': |
41182118 BK |
1287 | $value = clean_param($option['value'], PARAM_INT); |
1288 | break; | |
e881c4f5 BK |
1289 | case 'attachmentsid': |
1290 | $value = clean_param($option['value'], PARAM_INT); | |
609a1073 JL |
1291 | // Ensure that the user has permissions to create attachments. |
1292 | if (!has_capability('mod/forum:createattachment', $context)) { | |
1293 | $value = 0; | |
1294 | } | |
e881c4f5 | 1295 | break; |
117e4bd4 | 1296 | case 'topreferredformat': |
f2eb04c1 EL |
1297 | $value = clean_param($option['value'], PARAM_BOOL); |
1298 | break; | |
50a20317 JL |
1299 | default: |
1300 | throw new moodle_exception('errorinvalidparam', 'webservice', '', $name); | |
1301 | } | |
1302 | $options[$name] = $value; | |
1303 | } | |
1304 | ||
9b4f09ba | 1305 | if (!$capabilitymanager->can_post_in_discussion($USER, $discussion)) { |
50a20317 JL |
1306 | throw new moodle_exception('nopostforum', 'forum'); |
1307 | } | |
1308 | ||
9b4f09ba | 1309 | $thresholdwarning = forum_check_throttling($forumrecord, $cm); |
50a20317 JL |
1310 | forum_check_blocking_threshold($thresholdwarning); |
1311 | ||
117e4bd4 EL |
1312 | // If we want to force a conversion to the preferred format, let's do it now. |
1313 | if ($options['topreferredformat']) { | |
1314 | // We always are going to honor the preferred format. We are creating a new post. | |
1315 | $preferredformat = editors_get_preferred_format(); | |
1316 | // If the post is not HTML and the preferred format is HTML, convert to it. | |
1317 | if ($params['messageformat'] != FORMAT_HTML and $preferredformat == FORMAT_HTML) { | |
1318 | $params['message'] = format_text($params['message'], $params['messageformat'], ['context' => $context]); | |
1319 | } | |
1320 | $params['messageformat'] = $preferredformat; | |
f2eb04c1 EL |
1321 | } |
1322 | ||
50a20317 JL |
1323 | // Create the post. |
1324 | $post = new stdClass(); | |
9b4f09ba | 1325 | $post->discussion = $discussion->get_id(); |
50a20317 JL |
1326 | $post->parent = $parent->id; |
1327 | $post->subject = $params['subject']; | |
1328 | $post->message = $params['message']; | |
f2eb04c1 | 1329 | $post->messageformat = $params['messageformat']; |
50a20317 | 1330 | $post->messagetrust = trusttext_trusted($context); |
48143990 | 1331 | $post->itemid = $options['inlineattachmentsid']; |
3e95e09b | 1332 | $post->attachments = $options['attachmentsid']; |
bc4c7337 | 1333 | $post->isprivatereply = $options['private']; |
3e95e09b | 1334 | $post->deleted = 0; |
e881c4f5 BK |
1335 | $fakemform = $post->attachments; |
1336 | if ($postid = forum_add_new_post($post, $fakemform)) { | |
50a20317 JL |
1337 | |
1338 | $post->id = $postid; | |
1339 | ||
1340 | // Trigger events and completion. | |
1341 | $params = array( | |
1342 | 'context' => $context, | |
1343 | 'objectid' => $post->id, | |
1344 | 'other' => array( | |
9b4f09ba P |
1345 | 'discussionid' => $discussion->get_id(), |
1346 | 'forumid' => $forum->get_id(), | |
1347 | 'forumtype' => $forum->get_type(), | |
50a20317 JL |
1348 | ) |
1349 | ); | |
1350 | $event = \mod_forum\event\post_created::create($params); | |
1351 | $event->add_record_snapshot('forum_posts', $post); | |
9b4f09ba | 1352 | $event->add_record_snapshot('forum_discussions', $discussionrecord); |
50a20317 JL |
1353 | $event->trigger(); |
1354 | ||
1355 | // Update completion state. | |
1356 | $completion = new completion_info($course); | |
1357 | if ($completion->is_enabled($cm) && | |
9b4f09ba | 1358 | ($forum->get_completion_replies() || $forum->get_completion_posts())) { |
50a20317 JL |
1359 | $completion->update_state($cm, COMPLETION_COMPLETE); |
1360 | } | |
1361 | ||
d411a1c1 MG |
1362 | if ($options['discussionsubscribe']) { |
1363 | $settings = new stdClass(); | |
1364 | $settings->discussionsubscribe = $options['discussionsubscribe']; | |
1365 | forum_post_subscription($settings, $forumrecord, $discussionrecord); | |
1366 | } | |
50a20317 JL |
1367 | } else { |
1368 | throw new moodle_exception('couldnotadd', 'forum'); | |
1369 | } | |
1370 | ||
9b4f09ba P |
1371 | $builderfactory = \mod_forum\local\container::get_builder_factory(); |
1372 | $exportedpostsbuilder = $builderfactory->get_exported_posts_builder(); | |
1373 | $postentity = $entityfactory->get_post_from_stdClass($post); | |
1374 | $exportedposts = $exportedpostsbuilder->build($USER, [$forum], [$discussion], [$postentity]); | |
1375 | $exportedpost = $exportedposts[0]; | |
1376 | ||
a0c9b6af P |
1377 | $message = []; |
1378 | $message[] = [ | |
1379 | 'type' => 'success', | |
1380 | 'message' => get_string("postaddedsuccess", "forum") | |
1381 | ]; | |
1382 | ||
1383 | $message[] = [ | |
1384 | 'type' => 'success', | |
1385 | 'message' => get_string("postaddedtimeleft", "forum", format_time($CFG->maxeditingtime)) | |
1386 | ]; | |
1387 | ||
50a20317 JL |
1388 | $result = array(); |
1389 | $result['postid'] = $postid; | |
1390 | $result['warnings'] = $warnings; | |
9b4f09ba | 1391 | $result['post'] = $exportedpost; |
a0c9b6af | 1392 | $result['messages'] = $message; |
50a20317 JL |
1393 | return $result; |
1394 | } | |
1395 | ||
1396 | /** | |
1397 | * Returns description of method result value | |
1398 | * | |
1399 | * @return external_description | |
1400 | * @since Moodle 3.0 | |
1401 | */ | |
1402 | public static function add_discussion_post_returns() { | |
1403 | return new external_single_structure( | |
1404 | array( | |
1405 | 'postid' => new external_value(PARAM_INT, 'new post id'), | |
9b4f09ba | 1406 | 'warnings' => new external_warnings(), |
a0c9b6af P |
1407 | 'post' => post_exporter::get_read_structure(), |
1408 | 'messages' => new external_multiple_structure( | |
1409 | new external_single_structure( | |
1410 | array( | |
1411 | 'type' => new external_value(PARAM_TEXT, "The classification to be used in the client side", VALUE_REQUIRED), | |
1412 | 'message' => new external_value(PARAM_TEXT,'untranslated english message to explain the warning', VALUE_REQUIRED) | |
1413 | ), 'Messages'), 'list of warnings', VALUE_OPTIONAL | |
1414 | ), | |
1415 | //'alertmessage' => new external_value(PARAM_RAW, 'Success message to be displayed to the user.'), | |
50a20317 JL |
1416 | ) |
1417 | ); | |
1418 | } | |
1419 | ||
309e8698 P |
1420 | /** |
1421 | * Toggle the favouriting value for the discussion provided | |
1422 | * | |
309e8698 P |
1423 | * @param int $discussionid The discussion we need to favourite |
1424 | * @param bool $targetstate The state of the favourite value | |
1425 | * @return array The exported discussion | |
1426 | */ | |
8885cd57 | 1427 | public static function toggle_favourite_state($discussionid, $targetstate) { |
99bda8a7 P |
1428 | global $DB, $PAGE, $USER; |
1429 | ||
1430 | $params = self::validate_parameters(self::toggle_favourite_state_parameters(), [ | |
99bda8a7 P |
1431 | 'discussionid' => $discussionid, |
1432 | 'targetstate' => $targetstate | |
1433 | ]); | |
1434 | ||
1435 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
8885cd57 P |
1436 | // Get the discussion vault and the corresponding discussion entity. |
1437 | $discussionvault = $vaultfactory->get_discussion_vault(); | |
1438 | $discussion = $discussionvault->get_from_id($params['discussionid']); | |
1439 | ||
99bda8a7 | 1440 | $forumvault = $vaultfactory->get_forum_vault(); |
8885cd57 | 1441 | $forum = $forumvault->get_from_id($discussion->get_forum_id()); |
99bda8a7 | 1442 | $forumcontext = $forum->get_context(); |
99bda8a7 P |
1443 | self::validate_context($forumcontext); |
1444 | ||
1445 | $managerfactory = mod_forum\local\container::get_manager_factory(); | |
1446 | $capabilitymanager = $managerfactory->get_capability_manager($forum); | |
1447 | ||
99bda8a7 | 1448 | // Does the user have the ability to favourite the discussion? |
b4a1bbbb | 1449 | if (!$capabilitymanager->can_favourite_discussion($USER)) { |
99bda8a7 P |
1450 | throw new moodle_exception('cannotfavourite', 'forum'); |
1451 | } | |
d3cac88d | 1452 | $usercontext = context_user::instance($USER->id); |
99bda8a7 P |
1453 | $ufservice = \core_favourites\service_factory::get_service_for_user_context($usercontext); |
1454 | $isfavourited = $ufservice->favourite_exists('mod_forum', 'discussions', $discussion->get_id(), $forumcontext); | |
1455 | ||
1456 | $favouritefunction = $targetstate ? 'create_favourite' : 'delete_favourite'; | |
1457 | if ($isfavourited != (bool) $params['targetstate']) { | |
1458 | $ufservice->{$favouritefunction}('mod_forum', 'discussions', $discussion->get_id(), $forumcontext); | |
1459 | } | |
1460 | ||
1461 | $exporterfactory = mod_forum\local\container::get_exporter_factory(); | |
13cd05ac P |
1462 | $builder = mod_forum\local\container::get_builder_factory()->get_exported_discussion_builder(); |
1463 | $favourited = ($builder->is_favourited($discussion, $forumcontext, $USER) ? [$discussion->get_id()] : []); | |
1464 | $exporter = $exporterfactory->get_discussion_exporter($USER, $forum, $discussion, [], $favourited); | |
99bda8a7 P |
1465 | return $exporter->export($PAGE->get_renderer('mod_forum')); |
1466 | } | |
1467 | ||
1468 | /** | |
1469 | * Returns description of method result value | |
1470 | * | |
1471 | * @return external_description | |
1472 | * @since Moodle 3.0 | |
1473 | */ | |
1474 | public static function toggle_favourite_state_returns() { | |
1475 | return discussion_exporter::get_read_structure(); | |
1476 | } | |
1477 | ||
309e8698 P |
1478 | /** |
1479 | * Defines the parameters for the toggle_favourite_state method | |
1480 | * | |
1481 | * @return external_function_parameters | |
1482 | */ | |
897ac0de | 1483 | public static function toggle_favourite_state_parameters() { |
99bda8a7 P |
1484 | return new external_function_parameters( |
1485 | [ | |
99bda8a7 P |
1486 | 'discussionid' => new external_value(PARAM_INT, 'The discussion to subscribe or unsubscribe'), |
1487 | 'targetstate' => new external_value(PARAM_BOOL, 'The target state') | |
1488 | ] | |
1489 | ); | |
1490 | } | |
1491 | ||
7ab43ac8 JL |
1492 | /** |
1493 | * Returns description of method parameters | |
1494 | * | |
1495 | * @return external_function_parameters | |
1496 | * @since Moodle 3.0 | |
1497 | */ | |
1498 | public static function add_discussion_parameters() { | |
1499 | return new external_function_parameters( | |
1500 | array( | |
7267daa8 AN |
1501 | 'forumid' => new external_value(PARAM_INT, 'Forum instance ID'), |
1502 | 'subject' => new external_value(PARAM_TEXT, 'New Discussion subject'), | |
1503 | 'message' => new external_value(PARAM_RAW, 'New Discussion message (only html format allowed)'), | |
aa9059b9 | 1504 | 'groupid' => new external_value(PARAM_INT, 'The group, default to 0', VALUE_DEFAULT, 0), |
7ab43ac8 JL |
1505 | 'options' => new external_multiple_structure ( |
1506 | new external_single_structure( | |
1507 | array( | |
1508 | 'name' => new external_value(PARAM_ALPHANUM, | |
1509 | 'The allowed keys (value format) are: | |
1510 | discussionsubscribe (bool); subscribe to the discussion?, default to true | |
5f219cf1 | 1511 | discussionpinned (bool); is the discussion pinned, default to false |
48143990 | 1512 | inlineattachmentsid (int); the draft file area id for inline attachments |
e881c4f5 | 1513 | attachmentsid (int); the draft file area id for attachments |
7ab43ac8 | 1514 | '), |
7267daa8 AN |
1515 | 'value' => new external_value(PARAM_RAW, 'The value of the option, |
1516 | This param is validated in the external function.' | |
7ab43ac8 JL |
1517 | ) |
1518 | ) | |
1519 | ), 'Options', VALUE_DEFAULT, array()) | |
1520 | ) | |
1521 | ); | |
1522 | } | |
1523 | ||
1524 | /** | |
1525 | * Add a new discussion into an existing forum. | |
1526 | * | |
1527 | * @param int $forumid the forum instance id | |
1528 | * @param string $subject new discussion subject | |
1529 | * @param string $message new discussion message (only html format allowed) | |
1530 | * @param int $groupid the user course group | |
1531 | * @param array $options optional settings | |
1532 | * @return array of warnings and the new discussion id | |
1533 | * @since Moodle 3.0 | |
1534 | * @throws moodle_exception | |
1535 | */ | |
aa9059b9 | 1536 | public static function add_discussion($forumid, $subject, $message, $groupid = 0, $options = array()) { |
7ab43ac8 JL |
1537 | global $DB, $CFG; |
1538 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
1539 | ||
1540 | $params = self::validate_parameters(self::add_discussion_parameters(), | |
1541 | array( | |
1542 | 'forumid' => $forumid, | |
1543 | 'subject' => $subject, | |
1544 | 'message' => $message, | |
1545 | 'groupid' => $groupid, | |
1546 | 'options' => $options | |
1547 | )); | |
609a1073 JL |
1548 | |
1549 | $warnings = array(); | |
1550 | ||
1551 | // Request and permission validation. | |
1552 | $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST); | |
1553 | list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum'); | |
1554 | ||
1555 | $context = context_module::instance($cm->id); | |
1556 | self::validate_context($context); | |
1557 | ||
7ab43ac8 JL |
1558 | // Validate options. |
1559 | $options = array( | |
5f219cf1 | 1560 | 'discussionsubscribe' => true, |
41182118 | 1561 | 'discussionpinned' => false, |
48143990 | 1562 | 'inlineattachmentsid' => 0, |
e881c4f5 | 1563 | 'attachmentsid' => null |
7ab43ac8 JL |
1564 | ); |
1565 | foreach ($params['options'] as $option) { | |
1566 | $name = trim($option['name']); | |
1567 | switch ($name) { | |
1568 | case 'discussionsubscribe': | |
1569 | $value = clean_param($option['value'], PARAM_BOOL); | |
1570 | break; | |
5f219cf1 BK |
1571 | case 'discussionpinned': |
1572 | $value = clean_param($option['value'], PARAM_BOOL); | |
1573 | break; | |
48143990 | 1574 | case 'inlineattachmentsid': |
41182118 BK |
1575 | $value = clean_param($option['value'], PARAM_INT); |
1576 | break; | |
e881c4f5 BK |
1577 | case 'attachmentsid': |
1578 | $value = clean_param($option['value'], PARAM_INT); | |
609a1073 JL |
1579 | // Ensure that the user has permissions to create attachments. |
1580 | if (!has_capability('mod/forum:createattachment', $context)) { | |
1581 | $value = 0; | |
1582 | } | |
e881c4f5 | 1583 | break; |
7ab43ac8 JL |
1584 | default: |
1585 | throw new moodle_exception('errorinvalidparam', 'webservice', '', $name); | |
1586 | } | |
1587 | $options[$name] = $value; | |
1588 | } | |
1589 | ||
7ab43ac8 JL |
1590 | // Normalize group. |
1591 | if (!groups_get_activity_groupmode($cm)) { | |
1592 | // Groups not supported, force to -1. | |
1593 | $groupid = -1; | |
1594 | } else { | |
1595 | // Check if we receive the default or and empty value for groupid, | |
1596 | // in this case, get the group for the user in the activity. | |
aa9059b9 | 1597 | if (empty($params['groupid'])) { |
7ab43ac8 JL |
1598 | $groupid = groups_get_activity_group($cm); |
1599 | } else { | |
1600 | // Here we rely in the group passed, forum_user_can_post_discussion will validate the group. | |
1601 | $groupid = $params['groupid']; | |
1602 | } | |
1603 | } | |
1604 | ||
1605 | if (!forum_user_can_post_discussion($forum, $groupid, -1, $cm, $context)) { | |
1606 | throw new moodle_exception('cannotcreatediscussion', 'forum'); | |
1607 | } | |
1608 | ||
1609 | $thresholdwarning = forum_check_throttling($forum, $cm); | |
1610 | forum_check_blocking_threshold($thresholdwarning); | |
1611 | ||
1612 | // Create the discussion. | |
1613 | $discussion = new stdClass(); | |
1614 | $discussion->course = $course->id; | |
1615 | $discussion->forum = $forum->id; | |
1616 | $discussion->message = $params['message']; | |
1617 | $discussion->messageformat = FORMAT_HTML; // Force formatting for now. | |
1618 | $discussion->messagetrust = trusttext_trusted($context); | |
48143990 | 1619 | $discussion->itemid = $options['inlineattachmentsid']; |
7ab43ac8 JL |
1620 | $discussion->groupid = $groupid; |
1621 | $discussion->mailnow = 0; | |
1622 | $discussion->subject = $params['subject']; | |
1623 | $discussion->name = $discussion->subject; | |
1624 | $discussion->timestart = 0; | |
1625 | $discussion->timeend = 0; | |
2893812e | 1626 | $discussion->timelocked = 0; |
e881c4f5 BK |
1627 | $discussion->attachments = $options['attachmentsid']; |
1628 | ||
5f219cf1 BK |
1629 | if (has_capability('mod/forum:pindiscussions', $context) && $options['discussionpinned']) { |
1630 | $discussion->pinned = FORUM_DISCUSSION_PINNED; | |
1631 | } else { | |
1632 | $discussion->pinned = FORUM_DISCUSSION_UNPINNED; | |
1633 | } | |
e881c4f5 BK |
1634 | $fakemform = $options['attachmentsid']; |
1635 | if ($discussionid = forum_add_discussion($discussion, $fakemform)) { | |
7ab43ac8 JL |
1636 | |
1637 | $discussion->id = $discussionid; | |
1638 | ||
1639 | // Trigger events and completion. | |
1640 | ||
1641 | $params = array( | |
1642 | 'context' => $context, | |
1643 | 'objectid' => $discussion->id, | |
1644 | 'other' => array( | |
1645 | 'forumid' => $forum->id, | |
1646 | ) | |
1647 | ); | |
1648 | $event = \mod_forum\event\discussion_created::create($params); | |
1649 | $event->add_record_snapshot('forum_discussions', $discussion); | |
1650 | $event->trigger(); | |
1651 | ||
1652 | $completion = new completion_info($course); | |
1653 | if ($completion->is_enabled($cm) && | |
1654 | ($forum->completiondiscussions || $forum->completionposts)) { | |
1655 | $completion->update_state($cm, COMPLETION_COMPLETE); | |
1656 | } | |
1657 | ||
1658 | $settings = new stdClass(); | |
1659 | $settings->discussionsubscribe = $options['discussionsubscribe']; | |
1660 | forum_post_subscription($settings, $forum, $discussion); | |
1661 | } else { | |
1662 | throw new moodle_exception('couldnotadd', 'forum'); | |
1663 | } | |
1664 | ||
1665 | $result = array(); | |
1666 | $result['discussionid'] = $discussionid; | |
1667 | $result['warnings'] = $warnings; | |
1668 | return $result; | |
1669 | } | |
1670 | ||
1671 | /** | |
1672 | * Returns description of method result value | |
1673 | * | |
1674 | * @return external_description | |
1675 | * @since Moodle 3.0 | |
1676 | */ | |
1677 | public static function add_discussion_returns() { | |
1678 | return new external_single_structure( | |
1679 | array( | |
7267daa8 | 1680 | 'discussionid' => new external_value(PARAM_INT, 'New Discussion ID'), |
7ab43ac8 JL |
1681 | 'warnings' => new external_warnings() |
1682 | ) | |
1683 | ); | |
1684 | } | |
1685 | ||
04cd8ae3 JL |
1686 | /** |
1687 | * Returns description of method parameters | |
1688 | * | |
1689 | * @return external_function_parameters | |
1690 | * @since Moodle 3.1 | |
1691 | */ | |
1692 | public static function can_add_discussion_parameters() { | |
1693 | return new external_function_parameters( | |
1694 | array( | |
1695 | 'forumid' => new external_value(PARAM_INT, 'Forum instance ID'), | |
1696 | 'groupid' => new external_value(PARAM_INT, 'The group to check, default to active group. | |
1697 | Use -1 to check if the user can post in all the groups.', VALUE_DEFAULT, null) | |
1698 | ) | |
1699 | ); | |
1700 | } | |
1701 | ||
1702 | /** | |
1703 | * Check if the current user can add discussions in the given forum (and optionally for the given group). | |
1704 | * | |
1705 | * @param int $forumid the forum instance id | |
1706 | * @param int $groupid the group to check, default to active group. Use -1 to check if the user can post in all the groups. | |
1707 | * @return array of warnings and the status (true if the user can add discussions) | |
1708 | * @since Moodle 3.1 | |
1709 | * @throws moodle_exception | |
1710 | */ | |
1711 | public static function can_add_discussion($forumid, $groupid = null) { | |
1712 | global $DB, $CFG; | |
1713 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
1714 | ||
1715 | $params = self::validate_parameters(self::can_add_discussion_parameters(), | |
1716 | array( | |
1717 | 'forumid' => $forumid, | |
1718 | 'groupid' => $groupid, | |
1719 | )); | |
1720 | $warnings = array(); | |
1721 | ||
1722 | // Request and permission validation. | |
1723 | $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST); | |
1724 | list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum'); | |
1725 | ||
1726 | $context = context_module::instance($cm->id); | |
1727 | self::validate_context($context); | |
1728 | ||
1729 | $status = forum_user_can_post_discussion($forum, $params['groupid'], -1, $cm, $context); | |
1730 | ||
1731 | $result = array(); | |
1732 | $result['status'] = $status; | |
581e75bf JL |
1733 | $result['canpindiscussions'] = has_capability('mod/forum:pindiscussions', $context); |
1734 | $result['cancreateattachment'] = forum_can_create_attachment($forum, $context); | |
04cd8ae3 JL |
1735 | $result['warnings'] = $warnings; |
1736 | return $result; | |
1737 | } | |
1738 | ||
1739 | /** | |
1740 | * Returns description of method result value | |
1741 | * | |
1742 | * @return external_description | |
1743 | * @since Moodle 3.1 | |
1744 | */ | |
1745 | public static function can_add_discussion_returns() { | |
1746 | return new external_single_structure( | |
1747 | array( | |
1748 | 'status' => new external_value(PARAM_BOOL, 'True if the user can add discussions, false otherwise.'), | |
581e75bf JL |
1749 | 'canpindiscussions' => new external_value(PARAM_BOOL, 'True if the user can pin discussions, false otherwise.', |
1750 | VALUE_OPTIONAL), | |
1751 | 'cancreateattachment' => new external_value(PARAM_BOOL, 'True if the user can add attachments, false otherwise.', | |
1752 | VALUE_OPTIONAL), | |
04cd8ae3 JL |
1753 | 'warnings' => new external_warnings() |
1754 | ) | |
1755 | ); | |
1756 | } | |
1757 | ||
4daa0d08 JL |
1758 | /** |
1759 | * Describes the parameters for get_forum_access_information. | |
1760 | * | |
1761 | * @return external_external_function_parameters | |
1762 | * @since Moodle 3.7 | |
1763 | */ | |
1764 | public static function get_forum_access_information_parameters() { | |
1765 | return new external_function_parameters ( | |
1766 | array( | |
1767 | 'forumid' => new external_value(PARAM_INT, 'Forum instance id.') | |
1768 | ) | |
1769 | ); | |
1770 | } | |
1771 | ||
1772 | /** | |
1773 | * Return access information for a given forum. | |
1774 | * | |
1775 | * @param int $forumid forum instance id | |
1776 | * @return array of warnings and the access information | |
1777 | * @since Moodle 3.7 | |
1778 | * @throws moodle_exception | |
1779 | */ | |
1780 | public static function get_forum_access_information($forumid) { | |
1781 | global $DB; | |
1782 | ||
1783 | $params = self::validate_parameters(self::get_forum_access_information_parameters(), array('forumid' => $forumid)); | |
1784 | ||
1785 | // Request and permission validation. | |
1786 | $forum = $DB->get_record('forum', array('id' => $params['forumid']), '*', MUST_EXIST); | |
1787 | $cm = get_coursemodule_from_instance('forum', $forum->id); | |
1788 | ||
1789 | $context = context_module::instance($cm->id); | |
1790 | self::validate_context($context); | |
1791 | ||
1792 | $result = array(); | |
1793 | // Return all the available capabilities. | |
1794 | $capabilities = load_capability_def('mod_forum'); | |
1795 | foreach ($capabilities as $capname => $capdata) { | |
1796 | // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules. | |
1797 | $field = 'can' . str_replace('mod/forum:', '', $capname); | |
1798 | $result[$field] = has_capability($capname, $context); | |
1799 | } | |
1800 | ||
1801 | $result['warnings'] = array(); | |
1802 | return $result; | |
1803 | } | |
1804 | ||
1805 | /** | |
1806 | * Describes the get_forum_access_information return value. | |
1807 | * | |
1808 | * @return external_single_structure | |
1809 | * @since Moodle 3.7 | |
1810 | */ | |
1811 | public static function get_forum_access_information_returns() { | |
1812 | ||
1813 | $structure = array( | |
1814 | 'warnings' => new external_warnings() | |
1815 | ); | |
1816 | ||
1817 | $capabilities = load_capability_def('mod_forum'); | |
1818 | foreach ($capabilities as $capname => $capdata) { | |
1819 | // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules. | |
1820 | $field = 'can' . str_replace('mod/forum:', '', $capname); | |
1821 | $structure[$field] = new external_value(PARAM_BOOL, 'Whether the user has the capability ' . $capname . ' allowed.', | |
1822 | VALUE_OPTIONAL); | |
1823 | } | |
1824 | ||
1825 | return new external_single_structure($structure); | |
1826 | } | |
2646e9d6 RW |
1827 | |
1828 | /** | |
1829 | * Set the subscription state. | |
1830 | * | |
1831 | * @param int $forumid | |
1832 | * @param int $discussionid | |
1833 | * @param bool $targetstate | |
1834 | * @return \stdClass | |
1835 | */ | |
1836 | public static function set_subscription_state($forumid, $discussionid, $targetstate) { | |
f30f46db | 1837 | global $PAGE, $USER; |
2646e9d6 RW |
1838 | |
1839 | $params = self::validate_parameters(self::set_subscription_state_parameters(), [ | |
1840 | 'forumid' => $forumid, | |
1841 | 'discussionid' => $discussionid, | |
1842 | 'targetstate' => $targetstate | |
1843 | ]); | |
1844 | ||
1845 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
1846 | $forumvault = $vaultfactory->get_forum_vault(); | |
1847 | $forum = $forumvault->get_from_id($params['forumid']); | |
2646e9d6 | 1848 | $coursemodule = $forum->get_course_module_record(); |
96a49734 | 1849 | $context = $forum->get_context(); |
2646e9d6 | 1850 | |
96a49734 | 1851 | self::validate_context($context); |
2646e9d6 | 1852 | |
2646e9d6 RW |
1853 | $discussionvault = $vaultfactory->get_discussion_vault(); |
1854 | $discussion = $discussionvault->get_from_id($params['discussionid']); | |
1855 | $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); | |
1856 | ||
1857 | $forumrecord = $legacydatamapperfactory->get_forum_data_mapper()->to_legacy_object($forum); | |
1858 | $discussionrecord = $legacydatamapperfactory->get_discussion_data_mapper()->to_legacy_object($discussion); | |
1859 | ||
1860 | if (!\mod_forum\subscriptions::is_subscribable($forumrecord)) { | |
1861 | // Nothing to do. We won't actually output any content here though. | |
1862 | throw new \moodle_exception('cannotsubscribe', 'mod_forum'); | |
1863 | } | |
1864 | ||
1865 | $issubscribed = \mod_forum\subscriptions::is_subscribed( | |
1866 | $USER->id, | |
1867 | $forumrecord, | |
1868 | $discussion->get_id(), | |
1869 | $coursemodule | |
1870 | ); | |
1871 | ||
1872 | // If the current state doesn't equal the desired state then update the current | |
1873 | // state to the desired state. | |
1874 | if ($issubscribed != (bool) $params['targetstate']) { | |
1875 | if ($params['targetstate']) { | |
1876 | \mod_forum\subscriptions::subscribe_user_to_discussion($USER->id, $discussionrecord, $context); | |
1877 | } else { | |
1878 | \mod_forum\subscriptions::unsubscribe_user_from_discussion($USER->id, $discussionrecord, $context); | |
1879 | } | |
1880 | } | |
1881 | ||
1882 | $exporterfactory = mod_forum\local\container::get_exporter_factory(); | |
1883 | $exporter = $exporterfactory->get_discussion_exporter($USER, $forum, $discussion); | |
1884 | return $exporter->export($PAGE->get_renderer('mod_forum')); | |
1885 | } | |
1886 | ||
1887 | /** | |
1888 | * Returns description of method parameters. | |
1889 | * | |
1890 | * @return external_function_parameters | |
1891 | */ | |
1892 | public static function set_subscription_state_parameters() { | |
1893 | return new external_function_parameters( | |
1894 | [ | |
1895 | 'forumid' => new external_value(PARAM_INT, 'Forum that the discussion is in'), | |
1896 | 'discussionid' => new external_value(PARAM_INT, 'The discussion to subscribe or unsubscribe'), | |
1897 | 'targetstate' => new external_value(PARAM_BOOL, 'The target state') | |
1898 | ] | |
1899 | ); | |
1900 | } | |
1901 | ||
1902 | /** | |
1903 | * Returns description of method result value. | |
1904 | * | |
1905 | * @return external_description | |
1906 | */ | |
1907 | public static function set_subscription_state_returns() { | |
8885cd57 | 1908 | return discussion_exporter::get_read_structure(); |
2646e9d6 | 1909 | } |
2893812e | 1910 | |
2893812e P |
1911 | /** |
1912 | * Set the lock state. | |
1913 | * | |
1914 | * @param int $forumid | |
1915 | * @param int $discussionid | |
1916 | * @param string $targetstate | |
1917 | * @return \stdClass | |
1918 | */ | |
1919 | public static function set_lock_state($forumid, $discussionid, $targetstate) { | |
1920 | global $DB, $PAGE, $USER; | |
1921 | ||
1922 | $params = self::validate_parameters(self::set_lock_state_parameters(), [ | |
1923 | 'forumid' => $forumid, | |
1924 | 'discussionid' => $discussionid, | |
1925 | 'targetstate' => $targetstate | |
1926 | ]); | |
1927 | ||
1928 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
1929 | $forumvault = $vaultfactory->get_forum_vault(); | |
1930 | $forum = $forumvault->get_from_id($params['forumid']); | |
2893812e P |
1931 | |
1932 | $managerfactory = mod_forum\local\container::get_manager_factory(); | |
1933 | $capabilitymanager = $managerfactory->get_capability_manager($forum); | |
bdb4a87d P |
1934 | if (!$capabilitymanager->can_manage_forum($USER)) { |
1935 | throw new moodle_exception('errorcannotlock', 'forum'); | |
1936 | } | |
1937 | ||
1938 | // If the targetstate(currentstate) is not 0 then it should be set to the current time. | |
1939 | $lockedvalue = $targetstate ? 0 : time(); | |
1940 | self::validate_context($forum->get_context()); | |
1941 | ||
2893812e P |
1942 | $discussionvault = $vaultfactory->get_discussion_vault(); |
1943 | $discussion = $discussionvault->get_from_id($params['discussionid']); | |
2893812e | 1944 | |
c475fe41 | 1945 | // If the current state doesn't equal the desired state then update the current. |
2893812e | 1946 | // state to the desired state. |
bdb4a87d P |
1947 | $discussion->toggle_locked_state($lockedvalue); |
1948 | $response = $discussionvault->update_discussion($discussion); | |
1949 | $discussion = !$response ? $response : $discussion; | |
a7260536 | 1950 | $exporterfactory = mod_forum\local\container::get_exporter_factory(); |
1951 | $exporter = $exporterfactory->get_discussion_exporter($USER, $forum, $discussion); | |
1952 | return $exporter->export($PAGE->get_renderer('mod_forum')); | |
1953 | } | |
1954 | ||
cda9da99 P |
1955 | /** |
1956 | * Returns description of method parameters. | |
1957 | * | |
1958 | * @return external_function_parameters | |
1959 | */ | |
1960 | public static function set_lock_state_parameters() { | |
1961 | return new external_function_parameters( | |
1962 | [ | |
1963 | 'forumid' => new external_value(PARAM_INT, 'Forum that the discussion is in'), | |
1964 | 'discussionid' => new external_value(PARAM_INT, 'The discussion to lock / unlock'), | |
1965 | 'targetstate' => new external_value(PARAM_INT, 'The timestamp for the lock state') | |
1966 | ] | |
1967 | ); | |
1968 | } | |
1969 | ||
1970 | /** | |
1971 | * Returns description of method result value. | |
1972 | * | |
1973 | * @return external_description | |
1974 | */ | |
1975 | public static function set_lock_state_returns() { | |
1976 | return new external_single_structure([ | |
1977 | 'id' => new external_value(PARAM_INT, 'The discussion we are locking.'), | |
1978 | 'locked' => new external_value(PARAM_BOOL, 'The locked state of the discussion.'), | |
1979 | 'times' => new external_single_structure([ | |
1980 | 'locked' => new external_value(PARAM_INT, 'The locked time of the discussion.'), | |
1981 | ]) | |
1982 | ]); | |
1983 | } | |
1984 | ||
a7260536 | 1985 | /** |
1986 | * Set the pin state. | |
1987 | * | |
a7260536 | 1988 | * @param int $discussionid |
1989 | * @param bool $targetstate | |
1990 | * @return \stdClass | |
1991 | */ | |
8885cd57 | 1992 | public static function set_pin_state($discussionid, $targetstate) { |
a7260536 | 1993 | global $PAGE, $USER; |
1994 | $params = self::validate_parameters(self::set_pin_state_parameters(), [ | |
a7260536 | 1995 | 'discussionid' => $discussionid, |
1996 | 'targetstate' => $targetstate, | |
1997 | ]); | |
1998 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
309e8698 | 1999 | $managerfactory = mod_forum\local\container::get_manager_factory(); |
a7260536 | 2000 | $forumvault = $vaultfactory->get_forum_vault(); |
2001 | $discussionvault = $vaultfactory->get_discussion_vault(); | |
8885cd57 P |
2002 | $discussion = $discussionvault->get_from_id($params['discussionid']); |
2003 | $forum = $forumvault->get_from_id($discussion->get_forum_id()); | |
309e8698 | 2004 | $capabilitymanager = $managerfactory->get_capability_manager($forum); |
a7260536 | 2005 | |
2006 | self::validate_context($forum->get_context()); | |
24962ee1 P |
2007 | |
2008 | $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); | |
309e8698 | 2009 | if (!$capabilitymanager->can_pin_discussions($USER)) { |
a7260536 | 2010 | // Nothing to do. We won't actually output any content here though. |
309e8698 | 2011 | throw new \moodle_exception('cannotpindiscussions', 'mod_forum'); |
a7260536 | 2012 | } |
2013 | ||
a7260536 | 2014 | $discussion->set_pinned($targetstate); |
cda9da99 | 2015 | $discussionvault->update_discussion($discussion); |
2893812e P |
2016 | |
2017 | $exporterfactory = mod_forum\local\container::get_exporter_factory(); | |
2018 | $exporter = $exporterfactory->get_discussion_exporter($USER, $forum, $discussion); | |
2019 | return $exporter->export($PAGE->get_renderer('mod_forum')); | |
2020 | } | |
2021 | ||
a7260536 | 2022 | /** |
2023 | * Returns description of method parameters. | |
2024 | * | |
2025 | * @return external_function_parameters | |
2026 | */ | |
2027 | public static function set_pin_state_parameters() { | |
2028 | return new external_function_parameters( | |
2029 | [ | |
309e8698 P |
2030 | 'discussionid' => new external_value(PARAM_INT, 'The discussion to pin or unpin', VALUE_REQUIRED, |
2031 | null, NULL_NOT_ALLOWED), | |
2032 | 'targetstate' => new external_value(PARAM_INT, 'The target state', VALUE_REQUIRED, | |
2033 | null, NULL_NOT_ALLOWED), | |
a7260536 | 2034 | ] |
2035 | ); | |
2036 | } | |
2037 | ||
a7260536 | 2038 | /** |
2039 | * Returns description of method result value. | |
2040 | * | |
2041 | * @return external_single_structure | |
2042 | */ | |
2043 | public static function set_pin_state_returns() { | |
8885cd57 | 2044 | return discussion_exporter::get_read_structure(); |
a7260536 | 2045 | } |
56444a60 JL |
2046 | |
2047 | /** | |
2048 | * Returns description of method parameters | |
2049 | * | |
2050 | * @return external_function_parameters | |
2051 | * @since Moodle 3.8 | |
2052 | */ | |
2053 | public static function delete_post_parameters() { | |
2054 | return new external_function_parameters( | |
2055 | array( | |
2056 | 'postid' => new external_value(PARAM_INT, 'Post to be deleted. It can be a discussion topic post.'), | |
2057 | ) | |
2058 | ); | |
2059 | } | |
2060 | ||
2061 | /** | |
2062 | * Deletes a post or a discussion completely when the post is the discussion topic. | |
2063 | * | |
2064 | * @param int $postid post to be deleted, it can be a discussion topic post. | |
2065 | * @return array of warnings and the status (true if the post/discussion was deleted) | |
2066 | * @since Moodle 3.8 | |
2067 | * @throws moodle_exception | |
2068 | */ | |
2069 | public static function delete_post($postid) { | |
2070 | global $USER, $CFG; | |
2071 | require_once($CFG->dirroot . "/mod/forum/lib.php"); | |
2072 | ||
2073 | $params = self::validate_parameters(self::delete_post_parameters(), | |
2074 | array( | |
2075 | 'postid' => $postid, | |
2076 | ) | |
2077 | ); | |
2078 | $warnings = array(); | |
2079 | $vaultfactory = mod_forum\local\container::get_vault_factory(); | |
2080 | $forumvault = $vaultfactory->get_forum_vault(); | |
2081 | $discussionvault = $vaultfactory->get_discussion_vault(); | |
2082 | $postvault = $vaultfactory->get_post_vault(); | |
2083 | $postentity = $postvault->get_from_id($params['postid']); | |
2084 | ||
2085 | if (empty($postentity)) { | |
2086 | throw new moodle_exception('invalidpostid', 'forum'); | |
2087 | } | |
2088 | ||
2089 | $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id()); | |
2090 | ||
2091 | if (empty($discussionentity)) { | |
2092 | throw new moodle_exception('notpartofdiscussion', 'forum'); | |
2093 | } | |
2094 | ||
2095 | $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id()); | |
2096 | if (empty($forumentity)) { | |
2097 | throw new moodle_exception('invalidforumid', 'forum'); | |
2098 | } | |
2099 | ||
2100 | $context = $forumentity->get_context(); | |
2101 | ||
2102 | self::validate_context($context); | |
2103 | ||
2104 | $managerfactory = mod_forum\local\container::get_manager_factory(); | |
2105 | $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); | |
2106 | $capabilitymanager = $managerfactory->get_capability_manager($forumentity); | |
2107 | $forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper(); | |
2108 | $discussiondatamapper = $legacydatamapperfactory->get_discussion_data_mapper(); | |
2109 | $postdatamapper = $legacydatamapperfactory->get_post_data_mapper(); | |
2110 | ||
2111 | $replycount = $postvault->get_reply_count_for_post_id_in_discussion_id($USER, $postentity->get_id(), | |
2112 | $discussionentity->get_id(), true); | |
2113 | $hasreplies = $replycount > 0; | |
2114 | ||
2115 | $capabilitymanager->validate_delete_post($USER, $discussionentity, $postentity, $hasreplies); | |
2116 | ||
2117 | if (!$postentity->has_parent()) { | |
2118 | $status = forum_delete_discussion( | |
2119 | $discussiondatamapper->to_legacy_object($discussionentity), | |
2120 | false, | |
2121 | $forumentity->get_course_record(), | |
2122 | $forumentity->get_course_module_record(), | |
2123 | $forumdatamapper->to_legacy_object($forumentity) | |
2124 | ); | |
2125 | } else { | |
2126 | $status = forum_delete_post( | |
2127 | $postdatamapper->to_legacy_object($postentity), | |
2128 | has_capability('mod/forum:deleteanypost', $context), | |
2129 | $forumentity->get_course_record(), | |
2130 | $forumentity->get_course_module_record(), | |
2131 | $forumdatamapper->to_legacy_object($forumentity) | |
2132 | ); | |
2133 | } | |
2134 | ||
2135 | $result = array(); | |
2136 | $result['status'] = $status; | |
2137 | $result['warnings'] = $warnings; | |
2138 | return $result; | |
2139 | } | |
2140 | ||
2141 | /** | |
2142 | * Returns description of method result value | |
2143 | * | |
2144 | * @return external_description | |
2145 | * @since Moodle 3.8 | |
2146 | */ | |
2147 | public static function delete_post_returns() { | |
2148 | return new external_single_structure( | |
2149 | array( | |
2150 | 'status' => new external_value(PARAM_BOOL, 'True if the post/discussion was deleted, false otherwise.'), | |
2151 | 'warnings' => new external_warnings() | |
2152 | ) | |
2153 | ); | |
2154 | } | |
2b9fe87d | 2155 | } |