Merge branch 'MDL-69520-master' of git://github.com/sarjona/moodle
[moodle.git] / mod / glossary / 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  * Glossary module external API.
19  *
20  * @package    mod_glossary
21  * @category   external
22  * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      Moodle 3.1
25  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->libdir . '/externallib.php');
30 require_once($CFG->dirroot . '/mod/glossary/lib.php');
32 /**
33  * Glossary module external functions.
34  *
35  * @package    mod_glossary
36  * @category   external
37  * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since      Moodle 3.1
40  */
41 class mod_glossary_external extends external_api {
43     /**
44      * Get the browse modes from the display format.
45      *
46      * This returns some of the terms that can be used when reporting a glossary being viewed.
47      *
48      * @param  string $format The display format of the glossary.
49      * @return array Containing some of all of the following: letter, cat, date, author.
50      */
51     protected static function get_browse_modes_from_display_format($format) {
52         global $DB;
54         $formats = array();
55         $dp = $DB->get_record('glossary_formats', array('name' => $format), '*', IGNORE_MISSING);
56         if ($dp) {
57             $formats = glossary_get_visible_tabs($dp);
58         }
60         // Always add 'letter'.
61         $modes = array('letter');
63         if (in_array('category', $formats)) {
64             $modes[] = 'cat';
65         }
66         if (in_array('date', $formats)) {
67             $modes[] = 'date';
68         }
69         if (in_array('author', $formats)) {
70             $modes[] = 'author';
71         }
73         return $modes;
74     }
76     /**
77      * Get the return value of an entry.
78      *
79      * @param bool $includecat Whether the definition should include category info.
80      * @return external_definition
81      */
82     protected static function get_entry_return_structure($includecat = false) {
83         $params = array(
84             'id' => new external_value(PARAM_INT, 'The entry ID'),
85             'glossaryid' => new external_value(PARAM_INT, 'The glossary ID'),
86             'userid' => new external_value(PARAM_INT, 'Author ID'),
87             'userfullname' => new external_value(PARAM_NOTAGS, 'Author full name'),
88             'userpictureurl' => new external_value(PARAM_URL, 'Author picture'),
89             'concept' => new external_value(PARAM_RAW, 'The concept'),
90             'definition' => new external_value(PARAM_RAW, 'The definition'),
91             'definitionformat' => new external_format_value('definition'),
92             'definitiontrust' => new external_value(PARAM_BOOL, 'The definition trust flag'),
93             'definitioninlinefiles' => new external_files('entry definition inline files', VALUE_OPTIONAL),
94             'attachment' => new external_value(PARAM_BOOL, 'Whether or not the entry has attachments'),
95             'attachments' => new external_files('attachments', VALUE_OPTIONAL),
96             'timecreated' => new external_value(PARAM_INT, 'Time created'),
97             'timemodified' => new external_value(PARAM_INT, 'Time modified'),
98             'teacherentry' => new external_value(PARAM_BOOL, 'The entry was created by a teacher, or equivalent.'),
99             'sourceglossaryid' => new external_value(PARAM_INT, 'The source glossary ID'),
100             'usedynalink' => new external_value(PARAM_BOOL, 'Whether the concept should be automatically linked'),
101             'casesensitive' => new external_value(PARAM_BOOL, 'When true, the matching is case sensitive'),
102             'fullmatch' => new external_value(PARAM_BOOL, 'When true, the matching is done on full words only'),
103             'approved' => new external_value(PARAM_BOOL, 'Whether the entry was approved'),
104             'tags' => new external_multiple_structure(
105                 \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
106             ),
107         );
109         if ($includecat) {
110             $params['categoryid'] = new external_value(PARAM_INT, 'The category ID. This may be' .
111                 ' \''. GLOSSARY_SHOW_NOT_CATEGORISED . '\' when the entry is not categorised', VALUE_DEFAULT,
112                 GLOSSARY_SHOW_NOT_CATEGORISED);
113             $params['categoryname'] = new external_value(PARAM_RAW, 'The category name. May be empty when the entry is' .
114                 ' not categorised, or the request was limited to one category.', VALUE_DEFAULT, '');
115         }
117         return new external_single_structure($params);
118     }
120     /**
121      * Fill in an entry object.
122      *
123      * This adds additional required fields for the external function to return.
124      *
125      * @param  stdClass $entry   The entry.
126      * @param  context  $context The context the entry belongs to.
127      * @return void
128      */
129     protected static function fill_entry_details($entry, $context) {
130         global $PAGE;
131         $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
133         // Format concept and definition.
134         $entry->concept = external_format_string($entry->concept, $context->id);
135         list($entry->definition, $entry->definitionformat) = external_format_text($entry->definition, $entry->definitionformat,
136             $context->id, 'mod_glossary', 'entry', $entry->id);
138         // Author details.
139         $user = mod_glossary_entry_query_builder::get_user_from_record($entry);
140         $userpicture = new user_picture($user);
141         $userpicture->size = 1;
142         $entry->userfullname = fullname($user, $canviewfullnames);
143         $entry->userpictureurl = $userpicture->get_url($PAGE)->out(false);
145         // Fetch attachments.
146         $entry->attachment = !empty($entry->attachment) ? 1 : 0;
147         $entry->attachments = array();
148         if ($entry->attachment) {
149             $entry->attachments = external_util::get_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
150         }
151         $definitioninlinefiles = external_util::get_area_files($context->id, 'mod_glossary', 'entry', $entry->id);
152         if (!empty($definitioninlinefiles)) {
153             $entry->definitioninlinefiles = $definitioninlinefiles;
154         }
156         $entry->tags = \core_tag\external\util::get_item_tags('mod_glossary', 'glossary_entries', $entry->id);
157     }
159     /**
160      * Validate a glossary via ID.
161      *
162      * @param  int $id The glossary ID.
163      * @return array Contains glossary, context, course and cm.
164      */
165     public static function validate_glossary($id) {
166         global $DB;
167         $glossary = $DB->get_record('glossary', array('id' => $id), '*', MUST_EXIST);
168         list($course, $cm) = get_course_and_cm_from_instance($glossary, 'glossary');
169         $context = context_module::instance($cm->id);
170         self::validate_context($context);
171         return array($glossary, $context, $course, $cm);
172     }
174     /**
175      * Describes the parameters for get_glossaries_by_courses.
176      *
177      * @return external_function_parameters
178      * @since Moodle 3.1
179      */
180     public static function get_glossaries_by_courses_parameters() {
181         return new external_function_parameters (
182             array(
183                 'courseids' => new external_multiple_structure(
184                     new external_value(PARAM_INT, 'course id'),
185                     'Array of course IDs', VALUE_DEFAULT, array()
186                 ),
187             )
188         );
189     }
191     /**
192      * Returns a list of glossaries in a provided list of courses.
193      *
194      * If no list is provided all glossaries that the user can view will be returned.
195      *
196      * @param array $courseids the course IDs.
197      * @return array of glossaries
198      * @since Moodle 3.1
199      */
200     public static function get_glossaries_by_courses($courseids = array()) {
201         $params = self::validate_parameters(self::get_glossaries_by_courses_parameters(), array('courseids' => $courseids));
203         $warnings = array();
204         $courses = array();
205         $courseids = $params['courseids'];
207         if (empty($courseids)) {
208             $courses = enrol_get_my_courses();
209             $courseids = array_keys($courses);
210         }
212         // Array to store the glossaries to return.
213         $glossaries = array();
214         $modes = array();
216         // Ensure there are courseids to loop through.
217         if (!empty($courseids)) {
218             list($courses, $warnings) = external_util::validate_courses($courseids, $courses);
220             // Get the glossaries in these courses, this function checks users visibility permissions.
221             $glossaries = get_all_instances_in_courses('glossary', $courses);
222             foreach ($glossaries as $glossary) {
223                 $context = context_module::instance($glossary->coursemodule);
224                 $glossary->name = external_format_string($glossary->name, $context->id);
225                 $options = array('noclean' => true);
226                 list($glossary->intro, $glossary->introformat) =
227                     external_format_text($glossary->intro, $glossary->introformat, $context->id, 'mod_glossary', 'intro', null,
228                         $options);
229                 $glossary->introfiles = external_util::get_area_files($context->id, 'mod_glossary', 'intro', false, false);
231                 // Make sure we have a number of entries per page.
232                 if (!$glossary->entbypage) {
233                     $glossary->entbypage = $CFG->glossary_entbypage;
234                 }
236                 // Add the list of browsing modes.
237                 if (!isset($modes[$glossary->displayformat])) {
238                     $modes[$glossary->displayformat] = self::get_browse_modes_from_display_format($glossary->displayformat);
239                 }
240                 $glossary->browsemodes = $modes[$glossary->displayformat];
241                 $glossary->canaddentry = has_capability('mod/glossary:write', $context) ? 1 : 0;
242             }
243         }
245         $result = array();
246         $result['glossaries'] = $glossaries;
247         $result['warnings'] = $warnings;
248         return $result;
249     }
251     /**
252      * Describes the get_glossaries_by_courses return value.
253      *
254      * @return external_single_structure
255      * @since Moodle 3.1
256      */
257     public static function get_glossaries_by_courses_returns() {
258         return new external_single_structure(array(
259             'glossaries' => new external_multiple_structure(
260                 new external_single_structure(array(
261                     'id' => new external_value(PARAM_INT, 'Glossary id'),
262                     'coursemodule' => new external_value(PARAM_INT, 'Course module id'),
263                     'course' => new external_value(PARAM_INT, 'Course id'),
264                     'name' => new external_value(PARAM_RAW, 'Glossary name'),
265                     'intro' => new external_value(PARAM_RAW, 'The Glossary intro'),
266                     'introformat' => new external_format_value('intro'),
267                     'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL),
268                     'allowduplicatedentries' => new external_value(PARAM_INT, 'If enabled, multiple entries can have the' .
269                         ' same concept name'),
270                     'displayformat' => new external_value(PARAM_TEXT, 'Display format type'),
271                     'mainglossary' => new external_value(PARAM_INT, 'If enabled this glossary is a main glossary.'),
272                     'showspecial' => new external_value(PARAM_INT, 'If enabled, participants can browse the glossary by' .
273                         ' special characters, such as @ and #'),
274                     'showalphabet' => new external_value(PARAM_INT, 'If enabled, participants can browse the glossary by' .
275                         ' letters of the alphabet'),
276                     'showall' => new external_value(PARAM_INT, 'If enabled, participants can browse all entries at once'),
277                     'allowcomments' => new external_value(PARAM_INT, 'If enabled, all participants with permission to' .
278                         ' create comments will be able to add comments to glossary entries'),
279                     'allowprintview' => new external_value(PARAM_INT, 'If enabled, students are provided with a link to a' .
280                         ' printer-friendly version of the glossary. The link is always available to teachers'),
281                     'usedynalink' => new external_value(PARAM_INT, 'If site-wide glossary auto-linking has been enabled' .
282                         ' by an administrator and this checkbox is ticked, the entry will be automatically linked' .
283                         ' wherever the concept words and phrases appear throughout the rest of the course.'),
284                     'defaultapproval' => new external_value(PARAM_INT, 'If set to no, entries require approving by a' .
285                         ' teacher before they are viewable by everyone.'),
286                     'approvaldisplayformat' => new external_value(PARAM_TEXT, 'When approving glossary items you may wish' .
287                         ' to use a different display format'),
288                     'globalglossary' => new external_value(PARAM_INT, ''),
289                     'entbypage' => new external_value(PARAM_INT, 'Entries shown per page'),
290                     'editalways' => new external_value(PARAM_INT, 'Always allow editing'),
291                     'rsstype' => new external_value(PARAM_INT, 'To enable the RSS feed for this activity, select either' .
292                         ' concepts with author or concepts without author to be included in the feed'),
293                     'rssarticles' => new external_value(PARAM_INT, 'This setting specifies the number of glossary entry' .
294                         ' concepts to include in the RSS feed. Between 5 and 20 generally acceptable'),
295                     'assessed' => new external_value(PARAM_INT, 'Aggregate type'),
296                     'assesstimestart' => new external_value(PARAM_INT, 'Restrict rating to items created after this'),
297                     'assesstimefinish' => new external_value(PARAM_INT, 'Restrict rating to items created before this'),
298                     'scale' => new external_value(PARAM_INT, 'Scale ID'),
299                     'timecreated' => new external_value(PARAM_INT, 'Time created'),
300                     'timemodified' => new external_value(PARAM_INT, 'Time modified'),
301                     'completionentries' => new external_value(PARAM_INT, 'Number of entries to complete'),
302                     'section' => new external_value(PARAM_INT, 'Section'),
303                     'visible' => new external_value(PARAM_INT, 'Visible'),
304                     'groupmode' => new external_value(PARAM_INT, 'Group mode'),
305                     'groupingid' => new external_value(PARAM_INT, 'Grouping ID'),
306                     'browsemodes' => new external_multiple_structure(
307                         new external_value(PARAM_ALPHA, 'Modes of browsing allowed')
308                     ),
309                     'canaddentry' => new external_value(PARAM_INT, 'Whether the user can add a new entry', VALUE_OPTIONAL),
310                 ), 'Glossaries')
311             ),
312             'warnings' => new external_warnings())
313         );
314     }
316     /**
317      * Returns the description of the external function parameters.
318      *
319      * @return external_function_parameters
320      * @since Moodle 3.1
321      */
322     public static function view_glossary_parameters() {
323         return new external_function_parameters(array(
324             'id' => new external_value(PARAM_INT, 'Glossary instance ID'),
325             'mode' => new external_value(PARAM_ALPHA, 'The mode in which the glossary is viewed'),
326         ));
327     }
329     /**
330      * Notify that the course module was viewed.
331      *
332      * @param int $id The glossary instance ID.
333      * @param string $mode The view mode.
334      * @return array of warnings and status result
335      * @since Moodle 3.1
336      * @throws moodle_exception
337      */
338     public static function view_glossary($id, $mode) {
339         $params = self::validate_parameters(self::view_glossary_parameters(), array(
340             'id' => $id,
341             'mode' => $mode
342         ));
343         $id = $params['id'];
344         $mode = $params['mode'];
345         $warnings = array();
347         // Get and validate the glossary.
348         list($glossary, $context, $course, $cm) = self::validate_glossary($id);
350         // Trigger module viewed event.
351         glossary_view($glossary, $course, $cm, $context, $mode);
353         return array(
354             'status' => true,
355             'warnings' => $warnings
356         );
357     }
359     /**
360      * Returns the description of the external function return value.
361      *
362      * @return external_description
363      * @since Moodle 3.1
364      */
365     public static function view_glossary_returns() {
366         return new external_single_structure(array(
367             'status' => new external_value(PARAM_BOOL, 'True on success'),
368             'warnings' => new external_warnings()
369         ));
370     }
372     /**
373      * Returns the description of the external function parameters.
374      *
375      * @return external_function_parameters
376      * @since Moodle 3.1
377      */
378     public static function view_entry_parameters() {
379         return new external_function_parameters(array(
380             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
381         ));
382     }
384     /**
385      * Notify that the entry was viewed.
386      *
387      * @param int $id The entry ID.
388      * @return array of warnings and status result
389      * @since Moodle 3.1
390      * @throws moodle_exception
391      * @throws invalid_parameter_exception
392      */
393     public static function view_entry($id) {
394         global $DB, $USER;
396         $params = self::validate_parameters(self::view_entry_parameters(), array('id' => $id));
397         $id = $params['id'];
398         $warnings = array();
400         // Get and validate the glossary.
401         $entry = $DB->get_record('glossary_entries', array('id' => $id), '*', MUST_EXIST);
402         list($glossary, $context, $course, $cm) = self::validate_glossary($entry->glossaryid);
404         if (!glossary_can_view_entry($entry, $cm)) {
405             throw new invalid_parameter_exception('invalidentry');
406         }
408         // Trigger view.
409         glossary_entry_view($entry, $context);
411         return array(
412             'status' => true,
413             'warnings' => $warnings
414         );
415     }
417     /**
418      * Returns the description of the external function return value.
419      *
420      * @return external_description
421      * @since Moodle 3.1
422      */
423     public static function view_entry_returns() {
424         return new external_single_structure(array(
425             'status' => new external_value(PARAM_BOOL, 'True on success'),
426             'warnings' => new external_warnings()
427         ));
428     }
430     /**
431      * Returns the description of the external function parameters.
432      *
433      * @return external_function_parameters
434      * @since Moodle 3.1
435      */
436     public static function get_entries_by_letter_parameters() {
437         return new external_function_parameters(array(
438             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
439             'letter' => new external_value(PARAM_ALPHA, 'A letter, or either keywords: \'ALL\' or \'SPECIAL\'.'),
440             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
441             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
442             'options' => new external_single_structure(array(
443                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
444                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
445             ), 'An array of options', VALUE_DEFAULT, array())
446         ));
447     }
449     /**
450      * Browse a glossary entries by letter.
451      *
452      * @param int $id The glossary ID.
453      * @param string $letter A letter, or a special keyword.
454      * @param int $from Start returning records from here.
455      * @param int $limit Number of records to return.
456      * @param array $options Array of options.
457      * @return array Containing count, entries and warnings.
458      * @since Moodle 3.1
459      * @throws moodle_exception
460      * @throws invalid_parameter_exception
461      */
462     public static function get_entries_by_letter($id, $letter, $from, $limit, $options) {
463         $params = self::validate_parameters(self::get_entries_by_letter_parameters(), array(
464             'id' => $id,
465             'letter' => $letter,
466             'from' => $from,
467             'limit' => $limit,
468             'options' => $options,
469         ));
470         $id = $params['id'];
471         $letter = $params['letter'];
472         $from = $params['from'];
473         $limit = $params['limit'];
474         $options = $params['options'];
475         $warnings = array();
477         // Get and validate the glossary.
478         list($glossary, $context) = self::validate_glossary($id);
480         // Validate the mode.
481         $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
482         if (!in_array('letter', $modes)) {
483             throw new invalid_parameter_exception('invalidbrowsemode');
484         }
486         $entries = array();
487         list($records, $count) = glossary_get_entries_by_letter($glossary, $context, $letter, $from, $limit, $options);
488         foreach ($records as $key => $record) {
489             self::fill_entry_details($record, $context);
490             $entries[] = $record;
491         }
493         return array(
494             'count' => $count,
495             'entries' => $entries,
496             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
497             'warnings' => $warnings
498         );
499     }
501     /**
502      * Returns the description of the external function return value.
503      *
504      * @return external_description
505      * @since Moodle 3.1
506      */
507     public static function get_entries_by_letter_returns() {
508         return new external_single_structure(array(
509             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
510             'entries' => new external_multiple_structure(
511                 self::get_entry_return_structure()
512             ),
513             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
514             'warnings' => new external_warnings()
515         ));
516     }
518     /**
519      * Returns the description of the external function parameters.
520      *
521      * @return external_function_parameters
522      * @since Moodle 3.1
523      */
524     public static function get_entries_by_date_parameters() {
525         return new external_function_parameters(array(
526             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
527             'order' => new external_value(PARAM_ALPHA, 'Order the records by: \'CREATION\' or \'UPDATE\'.',
528                 VALUE_DEFAULT, 'UPDATE'),
529             'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'DESC'),
530             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
531             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
532             'options' => new external_single_structure(array(
533                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
534                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
535             ), 'An array of options', VALUE_DEFAULT, array())
536         ));
537     }
539     /**
540      * Browse a glossary entries by date.
541      *
542      * @param int $id The glossary ID.
543      * @param string $order The way to order the records.
544      * @param string $sort The direction of the order.
545      * @param int $from Start returning records from here.
546      * @param int $limit Number of records to return.
547      * @param array $options Array of options.
548      * @return array Containing count, entries and warnings.
549      * @since Moodle 3.1
550      * @throws moodle_exception
551      * @throws invalid_parameter_exception
552      */
553     public static function get_entries_by_date($id, $order, $sort, $from, $limit, $options) {
554         $params = self::validate_parameters(self::get_entries_by_date_parameters(), array(
555             'id' => $id,
556             'order' => core_text::strtoupper($order),
557             'sort' => core_text::strtoupper($sort),
558             'from' => $from,
559             'limit' => $limit,
560             'options' => $options,
561         ));
562         $id = $params['id'];
563         $order = $params['order'];
564         $sort = $params['sort'];
565         $from = $params['from'];
566         $limit = $params['limit'];
567         $options = $params['options'];
568         $warnings = array();
570         if (!in_array($order, array('CREATION', 'UPDATE'))) {
571             throw new invalid_parameter_exception('invalidorder');
572         } else if (!in_array($sort, array('ASC', 'DESC'))) {
573             throw new invalid_parameter_exception('invalidsort');
574         }
576         // Get and validate the glossary.
577         list($glossary, $context) = self::validate_glossary($id);
579         // Validate the mode.
580         $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
581         if (!in_array('date', $modes)) {
582             throw new invalid_parameter_exception('invalidbrowsemode');
583         }
585         $entries = array();
586         list($records, $count) = glossary_get_entries_by_date($glossary, $context, $order, $sort, $from, $limit, $options);
587         foreach ($records as $key => $record) {
588             self::fill_entry_details($record, $context);
589             $entries[] = $record;
590         }
592         return array(
593             'count' => $count,
594             'entries' => $entries,
595             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
596             'warnings' => $warnings
597         );
598     }
600     /**
601      * Returns the description of the external function return value.
602      *
603      * @return external_description
604      * @since Moodle 3.1
605      */
606     public static function get_entries_by_date_returns() {
607         return new external_single_structure(array(
608             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
609             'entries' => new external_multiple_structure(
610                 self::get_entry_return_structure()
611             ),
612             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
613             'warnings' => new external_warnings()
614         ));
615     }
617     /**
618      * Returns the description of the external function parameters.
619      *
620      * @return external_function_parameters
621      * @since Moodle 3.1
622      */
623     public static function get_categories_parameters() {
624         return new external_function_parameters(array(
625             'id' => new external_value(PARAM_INT, 'The glossary ID'),
626             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
627             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20)
628         ));
629     }
631     /**
632      * Get the categories of a glossary.
633      *
634      * @param int $id The glossary ID.
635      * @param int $from Start returning records from here.
636      * @param int $limit Number of records to return.
637      * @return array Containing count, categories and warnings.
638      * @since Moodle 3.1
639      * @throws moodle_exception
640      */
641     public static function get_categories($id, $from, $limit) {
642         $params = self::validate_parameters(self::get_categories_parameters(), array(
643             'id' => $id,
644             'from' => $from,
645             'limit' => $limit
646         ));
647         $id = $params['id'];
648         $from = $params['from'];
649         $limit = $params['limit'];
650         $warnings = array();
652         // Get and validate the glossary.
653         list($glossary, $context) = self::validate_glossary($id);
655         // Fetch the categories.
656         $categories = array();
657         list($records, $count) = glossary_get_categories($glossary, $from, $limit);
658         foreach ($records as $category) {
659             $category->name = external_format_string($category->name, $context->id);
660             $categories[] = $category;
661         }
663         return array(
664             'count' => $count,
665             'categories' => $categories,
666             'warnings' => array(),
667         );
668     }
670     /**
671      * Returns the description of the external function return value.
672      *
673      * @return external_description
674      * @since Moodle 3.1
675      */
676     public static function get_categories_returns() {
677         return new external_single_structure(array(
678             'count' => new external_value(PARAM_INT, 'The total number of records.'),
679             'categories' => new external_multiple_structure(
680                 new external_single_structure(array(
681                     'id' => new external_value(PARAM_INT, 'The category ID'),
682                     'glossaryid' => new external_value(PARAM_INT, 'The glossary ID'),
683                     'name' => new external_value(PARAM_RAW, 'The name of the category'),
684                     'usedynalink' => new external_value(PARAM_BOOL, 'Whether the category is automatically linked'),
685                 ))
686             ),
687             'warnings' => new external_warnings()
688         ));
689     }
691     /**
692      * Returns the description of the external function parameters.
693      *
694      * @return external_function_parameters
695      * @since Moodle 3.1
696      */
697     public static function get_entries_by_category_parameters() {
698         return new external_function_parameters(array(
699             'id' => new external_value(PARAM_INT, 'The glossary ID.'),
700             'categoryid' => new external_value(PARAM_INT, 'The category ID. Use \'' . GLOSSARY_SHOW_ALL_CATEGORIES . '\' for all' .
701                 ' categories, or \'' . GLOSSARY_SHOW_NOT_CATEGORISED . '\' for uncategorised entries.'),
702             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
703             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
704             'options' => new external_single_structure(array(
705                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
706                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
707             ), 'An array of options', VALUE_DEFAULT, array())
708         ));
709     }
711     /**
712      * Browse a glossary entries by category.
713      *
714      * @param int $id The glossary ID.
715      * @param int $categoryid The category ID.
716      * @param int $from Start returning records from here.
717      * @param int $limit Number of records to return.
718      * @param array $options Array of options.
719      * @return array Containing count, entries and warnings.
720      * @since Moodle 3.1
721      * @throws moodle_exception
722      * @throws invalid_parameter_exception
723      */
724     public static function get_entries_by_category($id, $categoryid, $from, $limit, $options) {
725         global $DB;
727         $params = self::validate_parameters(self::get_entries_by_category_parameters(), array(
728             'id' => $id,
729             'categoryid' => $categoryid,
730             'from' => $from,
731             'limit' => $limit,
732             'options' => $options,
733         ));
734         $id = $params['id'];
735         $categoryid = $params['categoryid'];
736         $from = $params['from'];
737         $limit = $params['limit'];
738         $options = $params['options'];
739         $warnings = array();
741         // Get and validate the glossary.
742         list($glossary, $context) = self::validate_glossary($id);
744         // Validate the mode.
745         $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
746         if (!in_array('cat', $modes)) {
747             throw new invalid_parameter_exception('invalidbrowsemode');
748         }
750         // Validate the category.
751         if (in_array($categoryid, array(GLOSSARY_SHOW_ALL_CATEGORIES, GLOSSARY_SHOW_NOT_CATEGORISED))) {
752             // All good.
753         } else if (!$DB->record_exists('glossary_categories', array('id' => $categoryid, 'glossaryid' => $id))) {
754             throw new invalid_parameter_exception('invalidcategory');
755         }
757         // Fetching the entries.
758         $entries = array();
759         list($records, $count) = glossary_get_entries_by_category($glossary, $context, $categoryid, $from, $limit, $options);
760         foreach ($records as $key => $record) {
761             self::fill_entry_details($record, $context);
762             if ($record->categoryid === null) {
763                 $record->categoryid = GLOSSARY_SHOW_NOT_CATEGORISED;
764             }
765             if (isset($record->categoryname)) {
766                 $record->categoryname = external_format_string($record->categoryname, $context->id);
767             }
768             $entries[] = $record;
769         }
771         return array(
772             'count' => $count,
773             'entries' => $entries,
774             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
775             'warnings' => $warnings
776         );
777     }
779     /**
780      * Returns the description of the external function return value.
781      *
782      * @return external_description
783      * @since Moodle 3.1
784      */
785     public static function get_entries_by_category_returns() {
786         return new external_single_structure(array(
787             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
788             'entries' => new external_multiple_structure(
789                 self::get_entry_return_structure(true)
790             ),
791             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
792             'warnings' => new external_warnings()
793         ));
794     }
796     /**
797      * Returns the description of the external function parameters.
798      *
799      * @return external_function_parameters
800      * @since Moodle 3.1
801      */
802     public static function get_authors_parameters() {
803         return new external_function_parameters(array(
804             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
805             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
806             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
807             'options' => new external_single_structure(array(
808                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes self even if all of their entries' .
809                     ' require approval. When true, also includes authors only having entries pending approval.', VALUE_DEFAULT, 0)
810             ), 'An array of options', VALUE_DEFAULT, array())
811         ));
812     }
814     /**
815      * Get the authors of a glossary.
816      *
817      * @param int $id The glossary ID.
818      * @param int $from Start returning records from here.
819      * @param int $limit Number of records to return.
820      * @param array $options Array of options.
821      * @return array Containing count, authors and warnings.
822      * @since Moodle 3.1
823      * @throws moodle_exception
824      */
825     public static function get_authors($id, $from, $limit, $options) {
826         global $PAGE;
828         $params = self::validate_parameters(self::get_authors_parameters(), array(
829             'id' => $id,
830             'from' => $from,
831             'limit' => $limit,
832             'options' => $options,
833         ));
834         $id = $params['id'];
835         $from = $params['from'];
836         $limit = $params['limit'];
837         $options = $params['options'];
838         $warnings = array();
840         // Get and validate the glossary.
841         list($glossary, $context) = self::validate_glossary($id);
843         // Fetching the entries.
844         list($users, $count) = glossary_get_authors($glossary, $context, $limit, $from, $options);
846         $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
847         foreach ($users as $user) {
848             $userpicture = new user_picture($user);
849             $userpicture->size = 1;
851             $author = new stdClass();
852             $author->id = $user->id;
853             $author->fullname = fullname($user, $canviewfullnames);
854             $author->pictureurl = $userpicture->get_url($PAGE)->out(false);
855             $authors[] = $author;
856         }
857         $users->close();
859         return array(
860             'count' => $count,
861             'authors' => $authors,
862             'warnings' => array(),
863         );
864     }
866     /**
867      * Returns the description of the external function return value.
868      *
869      * @return external_description
870      * @since Moodle 3.1
871      */
872     public static function get_authors_returns() {
873         return new external_single_structure(array(
874             'count' => new external_value(PARAM_INT, 'The total number of records.'),
875             'authors' => new external_multiple_structure(
876                 new external_single_structure(array(
877                     'id' => new external_value(PARAM_INT, 'The user ID'),
878                     'fullname' => new external_value(PARAM_NOTAGS, 'The fullname'),
879                     'pictureurl' => new external_value(PARAM_URL, 'The picture URL'),
880                 ))
881             ),
882             'warnings' => new external_warnings()
883         ));
884     }
886     /**
887      * Returns the description of the external function parameters.
888      *
889      * @return external_function_parameters
890      * @since Moodle 3.1
891      */
892     public static function get_entries_by_author_parameters() {
893         return new external_function_parameters(array(
894             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
895             'letter' => new external_value(PARAM_ALPHA, 'First letter of firstname or lastname, or either keywords:'
896                 . ' \'ALL\' or \'SPECIAL\'.'),
897             'field' => new external_value(PARAM_ALPHA, 'Search and order using: \'FIRSTNAME\' or \'LASTNAME\'', VALUE_DEFAULT,
898                 'LASTNAME'),
899             'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
900             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
901             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
902             'options' => new external_single_structure(array(
903                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
904                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
905             ), 'An array of options', VALUE_DEFAULT, array())
906         ));
907     }
909     /**
910      * Browse a glossary entries by author.
911      *
912      * @param int $id The glossary ID.
913      * @param string $letter A letter, or a special keyword.
914      * @param string $field The field to search from.
915      * @param string $sort The direction of the order.
916      * @param int $from Start returning records from here.
917      * @param int $limit Number of records to return.
918      * @param array $options Array of options.
919      * @return array Containing count, entries and warnings.
920      * @since Moodle 3.1
921      * @throws moodle_exception
922      * @throws invalid_parameter_exception
923      */
924     public static function get_entries_by_author($id, $letter, $field, $sort, $from, $limit, $options) {
925         $params = self::validate_parameters(self::get_entries_by_author_parameters(), array(
926             'id' => $id,
927             'letter' => $letter,
928             'field' => core_text::strtoupper($field),
929             'sort' => core_text::strtoupper($sort),
930             'from' => $from,
931             'limit' => $limit,
932             'options' => $options,
933         ));
934         $id = $params['id'];
935         $letter = $params['letter'];
936         $field = $params['field'];
937         $sort = $params['sort'];
938         $from = $params['from'];
939         $limit = $params['limit'];
940         $options = $params['options'];
941         $warnings = array();
943         if (!in_array($field, array('FIRSTNAME', 'LASTNAME'))) {
944             throw new invalid_parameter_exception('invalidfield');
945         } else if (!in_array($sort, array('ASC', 'DESC'))) {
946             throw new invalid_parameter_exception('invalidsort');
947         }
949         // Get and validate the glossary.
950         list($glossary, $context) = self::validate_glossary($id);
952         // Validate the mode.
953         $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
954         if (!in_array('author', $modes)) {
955             throw new invalid_parameter_exception('invalidbrowsemode');
956         }
958         // Fetching the entries.
959         $entries = array();
960         list($records, $count) = glossary_get_entries_by_author($glossary, $context, $letter, $field, $sort, $from, $limit,
961             $options);
962         foreach ($records as $key => $record) {
963             self::fill_entry_details($record, $context);
964             $entries[] = $record;
965         }
967         return array(
968             'count' => $count,
969             'entries' => $entries,
970             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
971             'warnings' => $warnings
972         );
973     }
975     /**
976      * Returns the description of the external function return value.
977      *
978      * @return external_description
979      * @since Moodle 3.1
980      */
981     public static function get_entries_by_author_returns() {
982         return new external_single_structure(array(
983             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
984             'entries' => new external_multiple_structure(
985                 self::get_entry_return_structure()
986             ),
987             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
988             'warnings' => new external_warnings()
989         ));
990     }
992     /**
993      * Returns the description of the external function parameters.
994      *
995      * @return external_function_parameters
996      * @since Moodle 3.1
997      */
998     public static function get_entries_by_author_id_parameters() {
999         return new external_function_parameters(array(
1000             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1001             'authorid' => new external_value(PARAM_INT, 'The author ID'),
1002             'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT,
1003                 'CONCEPT'),
1004             'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
1005             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1006             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1007             'options' => new external_single_structure(array(
1008                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
1009                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
1010             ), 'An array of options', VALUE_DEFAULT, array())
1011         ));
1012     }
1014     /**
1015      * Browse a glossary entries by author.
1016      *
1017      * @param int $id The glossary ID.
1018      * @param int $authorid The author ID.
1019      * @param string $order The way to order the results.
1020      * @param string $sort The direction of the order.
1021      * @param int $from Start returning records from here.
1022      * @param int $limit Number of records to return.
1023      * @param array $options Array of options.
1024      * @return array Containing count, entries and warnings.
1025      * @since Moodle 3.1
1026      * @throws moodle_exception
1027      * @throws invalid_parameter_exception
1028      */
1029     public static function get_entries_by_author_id($id, $authorid, $order, $sort, $from, $limit, $options) {
1030         $params = self::validate_parameters(self::get_entries_by_author_id_parameters(), array(
1031             'id' => $id,
1032             'authorid' => $authorid,
1033             'order' => core_text::strtoupper($order),
1034             'sort' => core_text::strtoupper($sort),
1035             'from' => $from,
1036             'limit' => $limit,
1037             'options' => $options,
1038         ));
1039         $id = $params['id'];
1040         $authorid = $params['authorid'];
1041         $order = $params['order'];
1042         $sort = $params['sort'];
1043         $from = $params['from'];
1044         $limit = $params['limit'];
1045         $options = $params['options'];
1046         $warnings = array();
1048         if (!in_array($order, array('CONCEPT', 'CREATION', 'UPDATE'))) {
1049             throw new invalid_parameter_exception('invalidorder');
1050         } else if (!in_array($sort, array('ASC', 'DESC'))) {
1051             throw new invalid_parameter_exception('invalidsort');
1052         }
1054         // Get and validate the glossary.
1055         list($glossary, $context) = self::validate_glossary($id);
1057         // Validate the mode.
1058         $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
1059         if (!in_array('author', $modes)) {
1060             throw new invalid_parameter_exception('invalidbrowsemode');
1061         }
1063         // Fetching the entries.
1064         $entries = array();
1065         list($records, $count) = glossary_get_entries_by_author_id($glossary, $context, $authorid, $order, $sort, $from,
1066             $limit, $options);
1067         foreach ($records as $key => $record) {
1068             self::fill_entry_details($record, $context);
1069             $entries[] = $record;
1070         }
1072         return array(
1073             'count' => $count,
1074             'entries' => $entries,
1075             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1076             'warnings' => $warnings
1077         );
1078     }
1080     /**
1081      * Returns the description of the external function return value.
1082      *
1083      * @return external_description
1084      * @since Moodle 3.1
1085      */
1086     public static function get_entries_by_author_id_returns() {
1087         return new external_single_structure(array(
1088             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1089             'entries' => new external_multiple_structure(
1090                 self::get_entry_return_structure()
1091             ),
1092             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1093             'warnings' => new external_warnings()
1094         ));
1095     }
1097     /**
1098      * Returns the description of the external function parameters.
1099      *
1100      * @return external_function_parameters
1101      * @since Moodle 3.1
1102      */
1103     public static function get_entries_by_search_parameters() {
1104         return new external_function_parameters(array(
1105             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1106             'query' => new external_value(PARAM_NOTAGS, 'The query string'),
1107             'fullsearch' => new external_value(PARAM_BOOL, 'The query', VALUE_DEFAULT, 1),
1108             'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT,
1109                 'CONCEPT'),
1110             'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
1111             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1112             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1113             'options' => new external_single_structure(array(
1114                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
1115                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
1116             ), 'An array of options', VALUE_DEFAULT, array())
1117         ));
1118     }
1120     /**
1121      * Browse a glossary entries using the search.
1122      *
1123      * @param int $id The glossary ID.
1124      * @param string $query The search query.
1125      * @param bool $fullsearch Whether or not full search is required.
1126      * @param string $order The way to order the results.
1127      * @param string $sort The direction of the order.
1128      * @param int $from Start returning records from here.
1129      * @param int $limit Number of records to return.
1130      * @param array $options Array of options.
1131      * @return array Containing count, entries and warnings.
1132      * @since Moodle 3.1
1133      * @throws moodle_exception
1134      * @throws invalid_parameter_exception
1135      */
1136     public static function get_entries_by_search($id, $query, $fullsearch, $order, $sort, $from, $limit, $options) {
1137         $params = self::validate_parameters(self::get_entries_by_search_parameters(), array(
1138             'id' => $id,
1139             'query' => $query,
1140             'fullsearch' => $fullsearch,
1141             'order' => core_text::strtoupper($order),
1142             'sort' => core_text::strtoupper($sort),
1143             'from' => $from,
1144             'limit' => $limit,
1145             'options' => $options,
1146         ));
1147         $id = $params['id'];
1148         $query = $params['query'];
1149         $fullsearch = $params['fullsearch'];
1150         $order = $params['order'];
1151         $sort = $params['sort'];
1152         $from = $params['from'];
1153         $limit = $params['limit'];
1154         $options = $params['options'];
1155         $warnings = array();
1157         if (!in_array($order, array('CONCEPT', 'CREATION', 'UPDATE'))) {
1158             throw new invalid_parameter_exception('invalidorder');
1159         } else if (!in_array($sort, array('ASC', 'DESC'))) {
1160             throw new invalid_parameter_exception('invalidsort');
1161         }
1163         // Get and validate the glossary.
1164         list($glossary, $context) = self::validate_glossary($id);
1166         // Fetching the entries.
1167         $entries = array();
1168         list($records, $count) = glossary_get_entries_by_search($glossary, $context, $query, $fullsearch, $order, $sort, $from,
1169             $limit, $options);
1170         foreach ($records as $key => $record) {
1171             self::fill_entry_details($record, $context);
1172             $entries[] = $record;
1173         }
1175         return array(
1176             'count' => $count,
1177             'entries' => $entries,
1178             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1179             'warnings' => $warnings
1180         );
1181     }
1183     /**
1184      * Returns the description of the external function return value.
1185      *
1186      * @return external_description
1187      * @since Moodle 3.1
1188      */
1189     public static function get_entries_by_search_returns() {
1190         return new external_single_structure(array(
1191             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1192             'entries' => new external_multiple_structure(
1193                 self::get_entry_return_structure()
1194             ),
1195             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1196             'warnings' => new external_warnings()
1197         ));
1198     }
1200     /**
1201      * Returns the description of the external function parameters.
1202      *
1203      * @return external_function_parameters
1204      * @since Moodle 3.1
1205      */
1206     public static function get_entries_by_term_parameters() {
1207         return new external_function_parameters(array(
1208             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1209             'term' => new external_value(PARAM_NOTAGS, 'The entry concept, or alias'),
1210             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1211             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1212             'options' => new external_single_structure(array(
1213                 'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
1214                     ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
1215             ), 'An array of options', VALUE_DEFAULT, array())
1216         ));
1217     }
1219     /**
1220      * Browse a glossary entries using a term matching the concept or alias.
1221      *
1222      * @param int $id The glossary ID.
1223      * @param string $term The term.
1224      * @param int $from Start returning records from here.
1225      * @param int $limit Number of records to return.
1226      * @param array $options Array of options.
1227      * @return array Containing count, entries and warnings.
1228      * @since Moodle 3.1
1229      * @throws moodle_exception
1230      */
1231     public static function get_entries_by_term($id, $term, $from, $limit, $options) {
1232         $params = self::validate_parameters(self::get_entries_by_term_parameters(), array(
1233             'id' => $id,
1234             'term' => $term,
1235             'from' => $from,
1236             'limit' => $limit,
1237             'options' => $options,
1238         ));
1239         $id = $params['id'];
1240         $term = $params['term'];
1241         $from = $params['from'];
1242         $limit = $params['limit'];
1243         $options = $params['options'];
1244         $warnings = array();
1246         // Get and validate the glossary.
1247         list($glossary, $context) = self::validate_glossary($id);
1249         // Fetching the entries.
1250         $entries = array();
1251         list($records, $count) = glossary_get_entries_by_term($glossary, $context, $term, $from, $limit, $options);
1252         foreach ($records as $key => $record) {
1253             self::fill_entry_details($record, $context);
1254             $entries[] = $record;
1255         }
1257         return array(
1258             'count' => $count,
1259             'entries' => $entries,
1260             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1261             'warnings' => $warnings
1262         );
1263     }
1265     /**
1266      * Returns the description of the external function return value.
1267      *
1268      * @return external_description
1269      * @since Moodle 3.1
1270      */
1271     public static function get_entries_by_term_returns() {
1272         return new external_single_structure(array(
1273             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1274             'entries' => new external_multiple_structure(
1275                 self::get_entry_return_structure()
1276             ),
1277             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1278             'warnings' => new external_warnings()
1279         ));
1280     }
1282     /**
1283      * Returns the description of the external function parameters.
1284      *
1285      * @return external_function_parameters
1286      * @since Moodle 3.1
1287      */
1288     public static function get_entries_to_approve_parameters() {
1289         return new external_function_parameters(array(
1290             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1291             'letter' => new external_value(PARAM_ALPHA, 'A letter, or either keywords: \'ALL\' or \'SPECIAL\'.'),
1292             'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT,
1293                 'CONCEPT'),
1294             'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
1295             'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1296             'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1297             'options' => new external_single_structure(array(), 'An array of options', VALUE_DEFAULT, array())
1298         ));
1299     }
1301     /**
1302      * Browse a glossary entries using a term matching the concept or alias.
1303      *
1304      * @param int $id The glossary ID.
1305      * @param string $letter A letter, or a special keyword.
1306      * @param string $order The way to order the records.
1307      * @param string $sort The direction of the order.
1308      * @param int $from Start returning records from here.
1309      * @param int $limit Number of records to return.
1310      * @return array Containing count, entries and warnings.
1311      * @since Moodle 3.1
1312      * @throws moodle_exception
1313      */
1314     public static function get_entries_to_approve($id, $letter, $order, $sort, $from, $limit) {
1315         $params = self::validate_parameters(self::get_entries_to_approve_parameters(), array(
1316             'id' => $id,
1317             'letter' => $letter,
1318             'order' => $order,
1319             'sort' => $sort,
1320             'from' => $from,
1321             'limit' => $limit
1322         ));
1323         $id = $params['id'];
1324         $letter = $params['letter'];
1325         $order = $params['order'];
1326         $sort = $params['sort'];
1327         $from = $params['from'];
1328         $limit = $params['limit'];
1329         $warnings = array();
1331         // Get and validate the glossary.
1332         list($glossary, $context) = self::validate_glossary($id);
1334         // Check the permissions.
1335         require_capability('mod/glossary:approve', $context);
1337         // Fetching the entries.
1338         $entries = array();
1339         list($records, $count) = glossary_get_entries_to_approve($glossary, $context, $letter, $order, $sort, $from, $limit);
1340         foreach ($records as $key => $record) {
1341             self::fill_entry_details($record, $context);
1342             $entries[] = $record;
1343         }
1345         return array(
1346             'count' => $count,
1347             'entries' => $entries,
1348             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1349             'warnings' => $warnings
1350         );
1351     }
1353     /**
1354      * Returns the description of the external function return value.
1355      *
1356      * @return external_description
1357      * @since Moodle 3.1
1358      */
1359     public static function get_entries_to_approve_returns() {
1360         return new external_single_structure(array(
1361             'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1362             'entries' => new external_multiple_structure(
1363                 self::get_entry_return_structure()
1364             ),
1365             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1366             'warnings' => new external_warnings()
1367         ));
1368     }
1370     /**
1371      * Returns the description of the external function parameters.
1372      *
1373      * @return external_function_parameters
1374      * @since Moodle 3.1
1375      */
1376     public static function get_entry_by_id_parameters() {
1377         return new external_function_parameters(array(
1378             'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1379         ));
1380     }
1382     /**
1383      * Get an entry.
1384      *
1385      * @param int $id The entry ID.
1386      * @return array Containing entry and warnings.
1387      * @since Moodle 3.1
1388      * @throws moodle_exception
1389      * @throws invalid_parameter_exception
1390      */
1391     public static function get_entry_by_id($id) {
1392         global $DB, $USER;
1394         $params = self::validate_parameters(self::get_entry_by_id_parameters(), array('id' => $id));
1395         $id = $params['id'];
1396         $warnings = array();
1398         // Get and validate the glossary.
1399         $entry = $DB->get_record('glossary_entries', array('id' => $id), '*', MUST_EXIST);
1400         list($glossary, $context, $course, $cm) = self::validate_glossary($entry->glossaryid);
1402         if (empty($entry->approved) && $entry->userid != $USER->id && !has_capability('mod/glossary:approve', $context)) {
1403             throw new invalid_parameter_exception('invalidentry');
1404         }
1406         $entry = glossary_get_entry_by_id($id);
1407         self::fill_entry_details($entry, $context);
1409         // Permissions (for entry edition).
1410         $permissions = [
1411             'candelete' => mod_glossary_can_delete_entry($entry, $glossary, $context),
1412             'canupdate' => mod_glossary_can_update_entry($entry, $glossary, $context, $cm),
1413         ];
1415         return array(
1416             'entry' => $entry,
1417             'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry',
1418                 array($entry)),
1419             'permissions' => $permissions,
1420             'warnings' => $warnings
1421         );
1422     }
1424     /**
1425      * Returns the description of the external function return value.
1426      *
1427      * @return external_description
1428      * @since Moodle 3.1
1429      */
1430     public static function get_entry_by_id_returns() {
1431         return new external_single_structure(array(
1432             'entry' => self::get_entry_return_structure(),
1433             'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1434             'permissions' => new external_single_structure(
1435                 [
1436                     'candelete' => new external_value(PARAM_BOOL, 'Whether the user can delete the entry.'),
1437                     'canupdate' => new external_value(PARAM_BOOL, 'Whether the user can update the entry.'),
1438                 ],
1439                 'User permissions for the managing the entry.', VALUE_OPTIONAL
1440             ),
1441             'warnings' => new external_warnings()
1442         ));
1443     }
1445     /**
1446      * Returns the description of the external function parameters.
1447      *
1448      * @return external_function_parameters
1449      * @since Moodle 3.2
1450      */
1451     public static function add_entry_parameters() {
1452         return new external_function_parameters(array(
1453             'glossaryid' => new external_value(PARAM_INT, 'Glossary id'),
1454             'concept' => new external_value(PARAM_TEXT, 'Glossary concept'),
1455             'definition' => new external_value(PARAM_RAW, 'Glossary concept definition'),
1456             'definitionformat' => new external_format_value('definition'),
1457             'options' => new external_multiple_structure (
1458                 new external_single_structure(
1459                     array(
1460                         'name' => new external_value(PARAM_ALPHANUM,
1461                             'The allowed keys (value format) are:
1462                             inlineattachmentsid (int); the draft file area id for inline attachments
1463                             attachmentsid (int); the draft file area id for attachments
1464                             categories (comma separated int); comma separated category ids
1465                             aliases (comma separated str); comma separated aliases
1466                             usedynalink (bool); whether the entry should be automatically linked.
1467                             casesensitive (bool); whether the entry is case sensitive.
1468                             fullmatch (bool); whether to match whole words only.'),
1469                         'value' => new external_value(PARAM_RAW, 'the value of the option (validated inside the function)')
1470                     )
1471                 ), 'Optional settings', VALUE_DEFAULT, array()
1472             )
1473         ));
1474     }
1477     /**
1478      * Add a new entry to a given glossary.
1479      *
1480      * @param int $glossaryid the glosary id
1481      * @param string $concept    the glossary concept
1482      * @param string $definition the concept definition
1483      * @param int $definitionformat the concept definition format
1484      * @param array  $options    additional settings
1485      * @return array Containing entry and warnings.
1486      * @since Moodle 3.2
1487      * @throws moodle_exception
1488      * @throws invalid_parameter_exception
1489      */
1490     public static function add_entry($glossaryid, $concept, $definition, $definitionformat, $options = array()) {
1491         global $CFG;
1493         $params = self::validate_parameters(self::add_entry_parameters(), array(
1494             'glossaryid' => $glossaryid,
1495             'concept' => $concept,
1496             'definition' => $definition,
1497             'definitionformat' => $definitionformat,
1498             'options' => $options,
1499         ));
1500         $warnings = array();
1502         // Get and validate the glossary.
1503         list($glossary, $context, $course, $cm) = self::validate_glossary($params['glossaryid']);
1504         require_capability('mod/glossary:write', $context);
1506         if (!$glossary->allowduplicatedentries) {
1507             if (glossary_concept_exists($glossary, $params['concept'])) {
1508                 throw new moodle_exception('errconceptalreadyexists', 'glossary');
1509             }
1510         }
1512         // Prepare the entry object.
1513         $entry = new stdClass;
1514         $entry->id = null;
1515         $entry->aliases = '';
1516         $entry->usedynalink = $CFG->glossary_linkentries;
1517         $entry->casesensitive = $CFG->glossary_casesensitive;
1518         $entry->fullmatch = $CFG->glossary_fullmatch;
1519         $entry->concept = $params['concept'];
1520         $entry->definition_editor = array(
1521             'text' => $params['definition'],
1522             'format' => $params['definitionformat'],
1523         );
1524         // Options.
1525         foreach ($params['options'] as $option) {
1526             $name = trim($option['name']);
1527             switch ($name) {
1528                 case 'inlineattachmentsid':
1529                     $entry->definition_editor['itemid'] = clean_param($option['value'], PARAM_INT);
1530                     break;
1531                 case 'attachmentsid':
1532                     $entry->attachment_filemanager = clean_param($option['value'], PARAM_INT);
1533                     break;
1534                 case 'categories':
1535                     $entry->categories = clean_param($option['value'], PARAM_SEQUENCE);
1536                     $entry->categories = explode(',', $entry->categories);
1537                     break;
1538                 case 'aliases':
1539                     $entry->aliases = clean_param($option['value'], PARAM_NOTAGS);
1540                     // Convert to the expected format.
1541                     $entry->aliases = str_replace(",", "\n", $entry->aliases);
1542                     break;
1543                 case 'usedynalink':
1544                 case 'casesensitive':
1545                 case 'fullmatch':
1546                     // Only allow if linking is enabled.
1547                     if ($glossary->usedynalink) {
1548                         $entry->{$name} = clean_param($option['value'], PARAM_BOOL);
1549                     }
1550                     break;
1551                 default:
1552                     throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
1553             }
1554         }
1556         $entry = glossary_edit_entry($entry, $course, $cm, $glossary, $context);
1558         return array(
1559             'entryid' => $entry->id,
1560             'warnings' => $warnings
1561         );
1562     }
1564     /**
1565      * Returns the description of the external function return value.
1566      *
1567      * @return external_description
1568      * @since Moodle 3.2
1569      */
1570     public static function add_entry_returns() {
1571         return new external_single_structure(array(
1572             'entryid' => new external_value(PARAM_INT, 'New glossary entry ID'),
1573             'warnings' => new external_warnings()
1574         ));
1575     }