MDL-50537 mod_chat: New WS mod_chat_get_chats_by_courses
[moodle.git] / mod / chat / classes / external.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Chat external API
19  *
20  * @package    mod_chat
21  * @category   external
22  * @copyright  2015 Juan Leyva <juan@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      Moodle 3.0
25  */
27 defined('MOODLE_INTERNAL') || die;
29 require_once($CFG->libdir . '/externallib.php');
30 require_once($CFG->dirroot . '/mod/chat/lib.php');
32 /**
33  * Chat external functions
34  *
35  * @package    mod_chat
36  * @category   external
37  * @copyright  2015 Juan Leyva <juan@moodle.com>
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since      Moodle 3.0
40  */
41 class mod_chat_external extends external_api {
43     /**
44      * Returns description of method parameters
45      *
46      * @return external_function_parameters
47      * @since Moodle 3.0
48      */
49     public static function login_user_parameters() {
50         return new external_function_parameters(
51             array(
52                 'chatid' => new external_value(PARAM_INT, 'chat instance id'),
53                 'groupid' => new external_value(PARAM_INT, 'group id, 0 means that the function will determine the user group',
54                                                 VALUE_DEFAULT, 0),
55             )
56         );
57     }
59     /**
60      * Log the current user into a chat room in the given chat.
61      *
62      * @param int $chatid the chat instance id
63      * @param int $groupid the user group id
64      * @return array of warnings and the chat unique session id
65      * @since Moodle 3.0
66      * @throws moodle_exception
67      */
68     public static function login_user($chatid, $groupid = 0) {
69         global $DB;
71         $params = self::validate_parameters(self::login_user_parameters(),
72                                             array(
73                                                 'chatid' => $chatid,
74                                                 'groupid' => $groupid
75                                             ));
76         $warnings = array();
78         // Request and permission validation.
79         $chat = $DB->get_record('chat', array('id' => $params['chatid']), '*', MUST_EXIST);
80         list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
82         $context = context_module::instance($cm->id);
83         self::validate_context($context);
85         require_capability('mod/chat:chat', $context);
87         if (!empty($params['groupid'])) {
88             $groupid = $params['groupid'];
89             // Determine is the group is visible to user.
90             if (!groups_group_visible($groupid, $course, $cm)) {
91                 throw new moodle_exception('notingroup');
92             }
93         } else {
94             // Check to see if groups are being used here.
95             if ($groupmode = groups_get_activity_groupmode($cm)) {
96                 $groupid = groups_get_activity_group($cm);
97                 // Determine is the group is visible to user (this is particullary for the group 0).
98                 if (!groups_group_visible($groupid, $course, $cm)) {
99                     throw new moodle_exception('notingroup');
100                 }
101             } else {
102                 $groupid = 0;
103             }
104         }
106         // Get the unique chat session id.
107         // Since we are going to use the chat via Web Service requests we set the ajax version (since it's the most similar).
108         if (!$chatsid = chat_login_user($chat->id, 'ajax', $groupid, $course)) {
109             throw moodle_exception('cantlogin', 'chat');
110         }
112         $result = array();
113         $result['chatsid'] = $chatsid;
114         $result['warnings'] = $warnings;
115         return $result;
116     }
118     /**
119      * Returns description of method result value
120      *
121      * @return external_description
122      * @since Moodle 3.0
123      */
124     public static function login_user_returns() {
125         return new external_single_structure(
126             array(
127                 'chatsid' => new external_value(PARAM_ALPHANUM, 'unique chat session id'),
128                 'warnings' => new external_warnings()
129             )
130         );
131     }
133     /**
134      * Returns description of method parameters
135      *
136      * @return external_function_parameters
137      * @since Moodle 3.0
138      */
139     public static function get_chat_users_parameters() {
140         return new external_function_parameters(
141             array(
142                 'chatsid' => new external_value(PARAM_ALPHANUM, 'chat session id (obtained via mod_chat_login_user)')
143             )
144         );
145     }
147     /**
148      * Get the list of users in the given chat session.
149      *
150      * @param int $chatsid the chat session id
151      * @return array of warnings and the user lists
152      * @since Moodle 3.0
153      * @throws moodle_exception
154      */
155     public static function get_chat_users($chatsid) {
156         global $DB;
158         $params = self::validate_parameters(self::get_chat_users_parameters(),
159                                             array(
160                                                 'chatsid' => $chatsid
161                                             ));
162         $warnings = array();
164         // Request and permission validation.
165         if (!$chatuser = $DB->get_record('chat_users', array('sid' => $params['chatsid']))) {
166             throw new moodle_exception('notlogged', 'chat');
167         }
168         $chat = $DB->get_record('chat', array('id' => $chatuser->chatid), '*', MUST_EXIST);
169         list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
171         $context = context_module::instance($cm->id);
172         self::validate_context($context);
174         require_capability('mod/chat:chat', $context);
176         // First, delete old users from the chats.
177         chat_delete_old_users();
179         $users = chat_get_users($chatuser->chatid, $chatuser->groupid, $cm->groupingid);
180         $returnedusers = array();
182         foreach ($users as $user) {
183             $usercontext = context_user::instance($user->id, IGNORE_MISSING);
184             $profileimageurl = '';
186             if ($usercontext) {
187                 $profileimageurl = moodle_url::make_webservice_pluginfile_url(
188                                     $usercontext->id, 'user', 'icon', null, '/', 'f1')->out(false);
189             }
191             $returnedusers[] = array(
192                 'id' => $user->id,
193                 'fullname' => fullname($user),
194                 'profileimageurl' => $profileimageurl
195             );
196         }
198         $result = array();
199         $result['users'] = $returnedusers;
200         $result['warnings'] = $warnings;
201         return $result;
202     }
204     /**
205      * Returns description of method result value
206      *
207      * @return external_description
208      * @since Moodle 3.0
209      */
210     public static function get_chat_users_returns() {
211         return new external_single_structure(
212             array(
213                 'users' => new external_multiple_structure(
214                     new external_single_structure(
215                         array(
216                             'id' => new external_value(PARAM_INT, 'user id'),
217                             'fullname' => new external_value(PARAM_NOTAGS, 'user full name'),
218                             'profileimageurl' => new external_value(PARAM_URL, 'user picture URL'),
219                         )
220                     ),
221                     'list of users'
222                 ),
223                 'warnings' => new external_warnings()
224             )
225         );
226     }
228     /**
229      * Returns description of method parameters
230      *
231      * @return external_function_parameters
232      * @since Moodle 3.0
233      */
234     public static function send_chat_message_parameters() {
235         return new external_function_parameters(
236             array(
237                 'chatsid' => new external_value(PARAM_ALPHANUM, 'chat session id (obtained via mod_chat_login_user)'),
238                 'messagetext' => new external_value(PARAM_RAW, 'the message text'),
239                 'beepid' => new external_value(PARAM_RAW, 'the beep id', VALUE_DEFAULT, ''),
241             )
242         );
243     }
245     /**
246      * Send a message on the given chat session.
247      *
248      * @param int $chatsid the chat session id
249      * @param string $messagetext the message text
250      * @param string $beepid the beep message id
251      * @return array of warnings and the new message id (0 if the message was empty)
252      * @since Moodle 3.0
253      * @throws moodle_exception
254      */
255     public static function send_chat_message($chatsid, $messagetext, $beepid = '') {
256         global $DB;
258         $params = self::validate_parameters(self::send_chat_message_parameters(),
259                                             array(
260                                                 'chatsid' => $chatsid,
261                                                 'messagetext' => $messagetext,
262                                                 'beepid' => $beepid
263                                             ));
264         $warnings = array();
266         // Request and permission validation.
267         if (!$chatuser = $DB->get_record('chat_users', array('sid' => $params['chatsid']))) {
268             throw new moodle_exception('notlogged', 'chat');
269         }
270         $chat = $DB->get_record('chat', array('id' => $chatuser->chatid), '*', MUST_EXIST);
271         list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
273         $context = context_module::instance($cm->id);
274         self::validate_context($context);
276         require_capability('mod/chat:chat', $context);
278         $chatmessage = clean_text($params['messagetext'], FORMAT_MOODLE);
280         if (!empty($params['beepid'])) {
281             $chatmessage = 'beep ' . $params['beepid'];
282         }
284         if (!empty($chatmessage)) {
285             // Send the message.
286             $messageid = chat_send_chatmessage($chatuser, $chatmessage, 0, $cm);
287             // Update ping time.
288             $chatuser->lastmessageping = time() - 2;
289             $DB->update_record('chat_users', $chatuser);
290         } else {
291             $messageid = 0;
292         }
294         $result = array();
295         $result['messageid'] = $messageid;
296         $result['warnings'] = $warnings;
297         return $result;
298     }
300     /**
301      * Returns description of method result value
302      *
303      * @return external_description
304      * @since Moodle 3.0
305      */
306     public static function send_chat_message_returns() {
307         return new external_single_structure(
308             array(
309                 'messageid' => new external_value(PARAM_INT, 'message sent id'),
310                 'warnings' => new external_warnings()
311             )
312         );
313     }
315     /**
316      * Returns description of method parameters
317      *
318      * @return external_function_parameters
319      * @since Moodle 3.0
320      */
321     public static function get_chat_latest_messages_parameters() {
322         return new external_function_parameters(
323             array(
324                 'chatsid' => new external_value(PARAM_ALPHANUM, 'chat session id (obtained via mod_chat_login_user)'),
325                 'chatlasttime' => new external_value(PARAM_INT, 'last time messages were retrieved (epoch time)', VALUE_DEFAULT, 0)
326             )
327         );
328     }
330     /**
331      * Get the latest messages from the given chat session.
332      *
333      * @param int $chatsid the chat session id
334      * @param int $chatlasttime last time messages were retrieved (epoch time)
335      * @return array of warnings and the new message id (0 if the message was empty)
336      * @since Moodle 3.0
337      * @throws moodle_exception
338      */
339     public static function get_chat_latest_messages($chatsid, $chatlasttime = 0) {
340         global $DB, $CFG;
342         $params = self::validate_parameters(self::get_chat_latest_messages_parameters(),
343                                             array(
344                                                 'chatsid' => $chatsid,
345                                                 'chatlasttime' => $chatlasttime
346                                             ));
347         $warnings = array();
349         // Request and permission validation.
350         if (!$chatuser = $DB->get_record('chat_users', array('sid' => $params['chatsid']))) {
351             throw new moodle_exception('notlogged', 'chat');
352         }
353         $chat = $DB->get_record('chat', array('id' => $chatuser->chatid), '*', MUST_EXIST);
354         list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
356         $context = context_module::instance($cm->id);
357         self::validate_context($context);
359         require_capability('mod/chat:chat', $context);
361         $chatlasttime = $params['chatlasttime'];
362         if ((time() - $chatlasttime) > $CFG->chat_old_ping) {
363             chat_delete_old_users();
364         }
366         // Set default chat last time (to not retrieve all the conversations).
367         if ($chatlasttime == 0) {
368             $chatlasttime = time() - $CFG->chat_old_ping;
369         }
371         if ($latestmessage = chat_get_latest_message($chatuser->chatid, $chatuser->groupid)) {
372             $chatnewlasttime = $latestmessage->timestamp;
373         } else {
374             $chatnewlasttime = 0;
375         }
377         $messages = chat_get_latest_messages($chatuser, $chatlasttime);
378         $returnedmessages = array();
380         foreach ($messages as $message) {
382             // FORMAT_MOODLE is mandatory in the chat plugin.
383             list($messageformatted, $format) = external_format_text($message->message, FORMAT_MOODLE, $context->id, 'mod_chat',
384                                                                     '', 0);
386             $returnedmessages[] = array(
387                 'id' => $message->id,
388                 'userid' => $message->userid,
389                 'system' => (bool) $message->system,
390                 'message' => $messageformatted,
391                 'timestamp' => $message->timestamp,
392             );
393         }
395         // Update our status since we are active in the chat.
396         $DB->set_field('chat_users', 'lastping', time(), array('id' => $chatuser->id));
398         $result = array();
399         $result['messages'] = $returnedmessages;
400         $result['chatnewlasttime'] = $chatnewlasttime;
401         $result['warnings'] = $warnings;
402         return $result;
403     }
405     /**
406      * Returns description of method result value
407      *
408      * @return external_description
409      * @since Moodle 3.0
410      */
411     public static function get_chat_latest_messages_returns() {
412         return new external_single_structure(
413             array(
414                 'messages' => new external_multiple_structure(
415                     new external_single_structure(
416                         array(
417                             'id' => new external_value(PARAM_INT, 'message id'),
418                             'userid' => new external_value(PARAM_INT, 'user id'),
419                             'system' => new external_value(PARAM_BOOL, 'true if is a system message (like user joined)'),
420                             'message' => new external_value(PARAM_RAW, 'message text'),
421                             'timestamp' => new external_value(PARAM_INT, 'timestamp for the message'),
422                         )
423                     ),
424                     'list of users'
425                 ),
426                 'chatnewlasttime' => new external_value(PARAM_INT, 'new last time'),
427                 'warnings' => new external_warnings()
428             )
429         );
430     }
432     /**
433      * Returns description of method parameters
434      *
435      * @return external_function_parameters
436      * @since Moodle 3.0
437      */
438     public static function view_chat_parameters() {
439         return new external_function_parameters(
440             array(
441                 'chatid' => new external_value(PARAM_INT, 'chat instance id')
442             )
443         );
444     }
446     /**
447      * Trigger the course module viewed event and update the module completion status.
448      *
449      * @param int $chatid the chat instance id
450      * @return array of warnings and status result
451      * @since Moodle 3.0
452      * @throws moodle_exception
453      */
454     public static function view_chat($chatid) {
455         global $DB, $CFG;
457         $params = self::validate_parameters(self::view_chat_parameters(),
458                                             array(
459                                                 'chatid' => $chatid
460                                             ));
461         $warnings = array();
463         // Request and permission validation.
464         $chat = $DB->get_record('chat', array('id' => $params['chatid']), '*', MUST_EXIST);
465         list($course, $cm) = get_course_and_cm_from_instance($chat, 'chat');
467         $context = context_module::instance($cm->id);
468         self::validate_context($context);
470         require_capability('mod/chat:chat', $context);
472         // Call the url/lib API.
473         chat_view($chat, $course, $cm, $context);
475         $result = array();
476         $result['status'] = true;
477         $result['warnings'] = $warnings;
478         return $result;
479     }
481     /**
482      * Returns description of method result value
483      *
484      * @return external_description
485      * @since Moodle 3.0
486      */
487     public static function view_chat_returns() {
488         return new external_single_structure(
489             array(
490                 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
491                 'warnings' => new external_warnings()
492             )
493         );
494     }
496     /**
497      * Describes the parameters for get_chats_by_courses.
498      *
499      * @return external_external_function_parameters
500      * @since Moodle 3.0
501      */
502     public static function get_chats_by_courses_parameters() {
503         return new external_function_parameters (
504             array(
505                 'courseids' => new external_multiple_structure(
506                     new external_value(PARAM_INT, 'course id'),
507                     'Array of course ids', VALUE_DEFAULT, array()
508                 ),
509             )
510         );
511     }
512     /**
513      * Returns a list of chats in a provided list of courses,
514      * if no list is provided all chats that the user can view will be returned.
515      *
516      * @param array $courseids the course ids
517      * @return array of chats details
518      * @since Moodle 3.0
519      */
520     public static function get_chats_by_courses($courseids = array()) {
521         global $CFG;
522         $params = self::validate_parameters(self::get_chats_by_courses_parameters(), array('courseids' => $courseids));
523         $warnings = array();
524         if (!empty($params['courseids'])) {
525             $courses = array();
526             $courseids = $params['courseids'];
527         } else {
528             $courses = enrol_get_my_courses();
529             $courseids = array_keys($courses);
530         }
531         // Array to store the chats to return.
532         $arrchats = array();
533         // Ensure there are courseids to loop through.
534         if (!empty($courseids)) {
535             // Array of the courses we are going to retrieve the chats from.
536             $arraycourses = array();
537             // Go through the courseids.
538             foreach ($courseids as $cid) {
539                 // Check the user can function in this context.
540                 try {
541                     $context = context_course::instance($cid);
542                     self::validate_context($context);
543                     // Check if this course was already loaded (by enrol_get_my_courses).
544                     if (!isset($courses[$cid])) {
545                         $courses[$cid] = get_course($cid);
546                     }
547                     $arraycourses[$cid] = $courses[$cid];
548                 } catch (Exception $e) {
549                     $warnings[] = array(
550                         'item' => 'course',
551                         'itemid' => $cid,
552                         'warningcode' => '1',
553                         'message' => 'No access rights in course context '.$e->getMessage()
554                     );
555                 }
556             }
557             // Get the chats in this course, this function checks users visibility permissions.
558             // We can avoid then additional validate_context calls.
559             $chats = get_all_instances_in_courses("chat", $arraycourses);
560             foreach ($chats as $chat) {
561                 $chatcontext = context_module::instance($chat->coursemodule);
562                 // Entry to return.
563                 $chatdetails = array();
564                 // First, we return information that any user can see in the web interface.
565                 $chatdetails['id'] = $chat->id;
566                 $chatdetails['coursemodule']      = $chat->coursemodule;
567                 $chatdetails['course']            = $chat->course;
568                 $chatdetails['name']              = $chat->name;
569                 // Format intro.
570                 list($chatdetails['intro'], $chatdetails['introformat']) =
571                     external_format_text($chat->intro, $chat->introformat,
572                                             $chatcontext->id, 'mod_chat', 'intro', null);
573                 if (has_capability('moodle/course:manageactivities', $chatcontext)) {
574                     $chatdetails['keepdays']      = $chat->keepdays;
575                     $chatdetails['studentlogs']   = $chat->studentlogs;
576                     $chatdetails['chattime']      = $chat->chattime;
577                     $chatdetails['schedule']      = $chat->schedule;
578                     $chatdetails['timemodified']  = $chat->timemodified;
579                     $chatdetails['section']       = $chat->section;
580                     $chatdetails['visible']       = $chat->visible;
581                     $chatdetails['groupmode']     = $chat->groupmode;
582                     $chatdetails['groupingid']    = $chat->groupingid;
583                 }
584                 $arrchats[] = $chatdetails;
585             }
586         }
587         $result = array();
588         $result['chats'] = $arrchats;
589         $result['warnings'] = $warnings;
590         return $result;
591     }
592     /**
593      * Describes the get_chats_by_courses return value.
594      *
595      * @return external_single_structure
596      * @since Moodle 3.0
597      */
598     public static function get_chats_by_courses_returns() {
599         return new external_single_structure(
600             array(
601                 'chats' => new external_multiple_structure(
602                     new external_single_structure(
603                         array(
604                             'id' => new external_value(PARAM_INT, 'Chat id'),
605                             'coursemodule' => new external_value(PARAM_INT, 'Course module id'),
606                             'course' => new external_value(PARAM_TEXT, 'Course id'),
607                             'name' => new external_value(PARAM_TEXT, 'Chat name'),
608                             'intro' => new external_value(PARAM_RAW, 'The Chat intro'),
609                             'introformat' => new external_format_value('intro'),
610                             'keepdays' => new external_value(PARAM_INT, 'keep days', VALUE_OPTIONAL),
611                             'studentlogs' => new external_value(PARAM_INT, 'student logs visible to everyone', VALUE_OPTIONAL),
612                             'chattime' => new external_value(PARAM_RAW, 'chat time', VALUE_OPTIONAL),
613                             'schedule' => new external_value(PARAM_INT, 'schedule type', VALUE_OPTIONAL),
614                             'timemodified' => new external_value(PARAM_RAW, 'time of last modification', VALUE_OPTIONAL),
615                             'section' => new external_value(PARAM_INT, 'course section id', VALUE_OPTIONAL),
616                             'visible' => new external_value(PARAM_BOOL, 'visible', VALUE_OPTIONAL),
617                             'groupmode' => new external_value(PARAM_INT, 'group mode', VALUE_OPTIONAL),
618                             'groupingid' => new external_value(PARAM_INT, 'group id', VALUE_OPTIONAL),
619                         ), 'Chats'
620                     )
621                 ),
622                 'warnings' => new external_warnings(),
623             )
624         );
625     }