MDL-57407 mod_data: Return ratings in mod_data_get_entry
[moodle.git] / mod / data / classes / external.php
CommitLineData
2ab34819
JL
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/>.
16
17/**
18 * Database module external API
19 *
20 * @package mod_data
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 2.9
25 */
26
27defined('MOODLE_INTERNAL') || die;
28
29require_once("$CFG->libdir/externallib.php");
9fac7c86 30require_once($CFG->dirroot . "/mod/data/locallib.php");
2ab34819 31
f97305b0 32use mod_data\external\database_summary_exporter;
ef6aea9d
JL
33use mod_data\external\record_exporter;
34use mod_data\external\content_exporter;
a934c896 35use mod_data\external\field_exporter;
f97305b0 36
2ab34819
JL
37/**
38 * Database module external functions
39 *
40 * @package mod_data
41 * @category external
42 * @copyright 2015 Juan Leyva <juan@moodle.com>
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 * @since Moodle 2.9
45 */
46class mod_data_external extends external_api {
47
48 /**
49 * Describes the parameters for get_databases_by_courses.
50 *
9db43c73 51 * @return external_function_parameters
2ab34819
JL
52 * @since Moodle 2.9
53 */
54 public static function get_databases_by_courses_parameters() {
55 return new external_function_parameters (
56 array(
57 'courseids' => new external_multiple_structure(
58 new external_value(PARAM_INT, 'course id', VALUE_REQUIRED),
59 'Array of course ids', VALUE_DEFAULT, array()
60 ),
61 )
62 );
63 }
64
65 /**
66 * Returns a list of databases in a provided list of courses,
67 * if no list is provided all databases that the user can view will be returned.
68 *
69 * @param array $courseids the course ids
70 * @return array the database details
71 * @since Moodle 2.9
72 */
73 public static function get_databases_by_courses($courseids = array()) {
f97305b0 74 global $PAGE;
2ab34819
JL
75
76 $params = self::validate_parameters(self::get_databases_by_courses_parameters(), array('courseids' => $courseids));
77 $warnings = array();
78
052da730
DP
79 $mycourses = array();
80 if (empty($params['courseids'])) {
81 $mycourses = enrol_get_my_courses();
82 $params['courseids'] = array_keys($mycourses);
2ab34819
JL
83 }
84
85 // Array to store the databases to return.
86 $arrdatabases = array();
87
88 // Ensure there are courseids to loop through.
052da730
DP
89 if (!empty($params['courseids'])) {
90
91 list($dbcourses, $warnings) = external_util::validate_courses($params['courseids'], $mycourses);
2ab34819
JL
92
93 // Get the databases in this course, this function checks users visibility permissions.
94 // We can avoid then additional validate_context calls.
95 $databases = get_all_instances_in_courses("data", $dbcourses);
96
97 foreach ($databases as $database) {
98
f97305b0
JL
99 $context = context_module::instance($database->coursemodule);
100 // Remove fields added by get_all_instances_in_courses.
101 unset($database->coursemodule, $database->section, $database->visible, $database->groupmode, $database->groupingid);
2ab34819
JL
102
103 // This information should be only available if the user can see the database entries.
f97305b0
JL
104 if (!has_capability('mod/data:viewentry', $context)) {
105 $fields = array('comments', 'timeavailablefrom', 'timeavailableto', 'timeviewfrom',
106 'timeviewto', 'requiredentries', 'requiredentriestoview', 'maxentries', 'rssarticles',
107 'singletemplate', 'listtemplate', 'listtemplateheader', 'listtemplatefooter', 'addtemplate',
108 'rsstemplate', 'rsstitletemplate', 'csstemplate', 'jstemplate', 'asearchtemplate', 'approval',
109 'manageapproved', 'defaultsort', 'defaultsortdir');
110
111 foreach ($fields as $field) {
112 unset($database->{$field});
2ab34819
JL
113 }
114 }
115
116 // Check additional permissions for returning optional private settings.
117 // I avoid intentionally to use can_[add|update]_moduleinfo.
f97305b0
JL
118 if (!has_capability('moodle/course:manageactivities', $context)) {
119
120 $fields = array('scale', 'assessed', 'assesstimestart', 'assesstimefinish', 'editany', 'notification',
121 'timemodified');
122
123 foreach ($fields as $field) {
124 unset($database->{$field});
2ab34819
JL
125 }
126 }
f97305b0
JL
127 $exporter = new database_summary_exporter($database, array('context' => $context));
128 $arrdatabases[] = $exporter->export($PAGE->get_renderer('core'));
2ab34819
JL
129 }
130 }
131
132 $result = array();
133 $result['databases'] = $arrdatabases;
134 $result['warnings'] = $warnings;
135 return $result;
136 }
137
138 /**
139 * Describes the get_databases_by_courses return value.
140 *
141 * @return external_single_structure
142 * @since Moodle 2.9
143 */
144 public static function get_databases_by_courses_returns() {
145
146 return new external_single_structure(
147 array(
148 'databases' => new external_multiple_structure(
f97305b0 149 database_summary_exporter::get_read_structure()
2ab34819
JL
150 ),
151 'warnings' => new external_warnings(),
152 )
153 );
154 }
155
cac43b9b
JL
156 /**
157 * Utility function for validating a database.
158 *
159 * @param int $databaseid database instance id
160 * @return array array containing the database object, course, context and course module objects
161 * @since Moodle 3.3
162 */
163 protected static function validate_database($databaseid) {
164 global $DB;
165
166 // Request and permission validation.
167 $database = $DB->get_record('data', array('id' => $databaseid), '*', MUST_EXIST);
168 list($course, $cm) = get_course_and_cm_from_instance($database, 'data');
169
170 $context = context_module::instance($cm->id);
171 self::validate_context($context);
172 require_capability('mod/data:viewentry', $context);
173
174 return array($database, $course, $cm, $context);
175 }
176
9fac7c86
JL
177 /**
178 * Returns description of method parameters
179 *
180 * @return external_function_parameters
181 * @since Moodle 3.3
182 */
183 public static function view_database_parameters() {
184 return new external_function_parameters(
185 array(
186 'databaseid' => new external_value(PARAM_INT, 'data instance id')
187 )
188 );
189 }
190
191 /**
192 * Simulate the data/view.php web interface page: trigger events, completion, etc...
193 *
194 * @param int $databaseid the data instance id
195 * @return array of warnings and status result
196 * @since Moodle 3.3
197 * @throws moodle_exception
198 */
199 public static function view_database($databaseid) {
9fac7c86
JL
200
201 $params = self::validate_parameters(self::view_database_parameters(), array('databaseid' => $databaseid));
202 $warnings = array();
203
cac43b9b 204 list($database, $course, $cm, $context) = self::validate_database($params['databaseid']);
9fac7c86
JL
205
206 // Call the data/lib API.
cac43b9b 207 data_view($database, $course, $cm, $context);
9fac7c86
JL
208
209 $result = array();
210 $result['status'] = true;
211 $result['warnings'] = $warnings;
212 return $result;
213 }
214
215 /**
216 * Returns description of method result value
217 *
218 * @return external_description
219 * @since Moodle 3.3
220 */
221 public static function view_database_returns() {
222 return new external_single_structure(
223 array(
224 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
225 'warnings' => new external_warnings()
226 )
227 );
228 }
229
cac43b9b
JL
230 /**
231 * Returns description of method parameters.
232 *
233 * @return external_function_parameters
234 * @since Moodle 3.3
235 */
236 public static function get_data_access_information_parameters() {
237 return new external_function_parameters(
238 array(
239 'databaseid' => new external_value(PARAM_INT, 'Database instance id.'),
240 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.',
241 VALUE_DEFAULT, 0),
242 )
243 );
244 }
245
246 /**
247 * Return access information for a given database.
248 *
249 * @param int $databaseid the database instance id
250 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
251 * @return array of warnings and access information
252 * @since Moodle 3.3
253 * @throws moodle_exception
254 */
255 public static function get_data_access_information($databaseid, $groupid = 0) {
256
257 $params = array('databaseid' => $databaseid, 'groupid' => $groupid);
258 $params = self::validate_parameters(self::get_data_access_information_parameters(), $params);
259 $warnings = array();
260
261 list($database, $course, $cm, $context) = self::validate_database($params['databaseid']);
262
263 $result = array(
264 'warnings' => $warnings
265 );
266
267 $groupmode = groups_get_activity_groupmode($cm);
268 if (!empty($params['groupid'])) {
269 $groupid = $params['groupid'];
270 // Determine is the group is visible to user.
271 if (!groups_group_visible($groupid, $course, $cm)) {
272 throw new moodle_exception('notingroup');
273 }
274 } else {
275 // Check to see if groups are being used here.
276 if ($groupmode) {
277 $groupid = groups_get_activity_group($cm);
278 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
279 if (!groups_group_visible($groupid, $course, $cm)) {
280 throw new moodle_exception('notingroup');
281 }
282 } else {
283 $groupid = 0;
284 }
285 }
286 // Group related information.
287 $result['groupid'] = $groupid;
288 $result['canaddentry'] = data_user_can_add_entry($database, $groupid, $groupmode, $context);
289
290 // Now capabilities.
291 $result['canmanageentries'] = has_capability('mod/data:manageentries', $context);
292 $result['canapprove'] = has_capability('mod/data:approve', $context);
293
294 // Now time access restrictions.
295 list($result['timeavailable'], $warnings) = data_get_time_availability_status($database, $result['canmanageentries']);
296
297 // Other information.
298 $result['numentries'] = data_numentries($database);
299 $result['entrieslefttoadd'] = data_get_entries_left_to_add($database, $result['numentries'], $result['canmanageentries']);
300 $result['entrieslefttoview'] = data_get_entries_left_to_view($database, $result['numentries'], $result['canmanageentries']);
301 $result['inreadonlyperiod'] = data_in_readonly_period($database);
302
303 return $result;
304 }
305
306 /**
307 * Returns description of method result value.
308 *
309 * @return external_description
310 * @since Moodle 3.3
311 */
312 public static function get_data_access_information_returns() {
313 return new external_single_structure(
314 array(
315 'groupid' => new external_value(PARAM_INT, 'User current group id (calculated)'),
316 'canaddentry' => new external_value(PARAM_BOOL, 'Whether the user can add entries or not.'),
317 'canmanageentries' => new external_value(PARAM_BOOL, 'Whether the user can manage entries or not.'),
318 'canapprove' => new external_value(PARAM_BOOL, 'Whether the user can approve entries or not.'),
319 'timeavailable' => new external_value(PARAM_BOOL, 'Whether the database is available or not by time restrictions.'),
320 'inreadonlyperiod' => new external_value(PARAM_BOOL, 'Whether the database is in read mode only.'),
321 'numentries' => new external_value(PARAM_INT, 'The number of entries the current user added.'),
322 'entrieslefttoadd' => new external_value(PARAM_INT, 'The number of entries left to complete the activity.'),
323 'entrieslefttoview' => new external_value(PARAM_INT, 'The number of entries left to view other users entries.'),
324 'warnings' => new external_warnings()
325 )
326 );
327 }
ef6aea9d
JL
328
329 /**
330 * Returns description of method parameters
331 *
332 * @return external_function_parameters
333 * @since Moodle 3.3
334 */
335 public static function get_entries_parameters() {
336 return new external_function_parameters(
337 array(
338 'databaseid' => new external_value(PARAM_INT, 'data instance id'),
339 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
340 VALUE_DEFAULT, 0),
341 'returncontents' => new external_value(PARAM_BOOL, 'Whether to return contents or not. This will return each entry
342 raw contents and the complete list view (using the template).',
343 VALUE_DEFAULT, false),
344 'sort' => new external_value(PARAM_INT, 'Sort the records by this field id, reserved ids are:
345 0: timeadded
346 -1: firstname
347 -2: lastname
348 -3: approved
349 -4: timemodified.
350 Empty for using the default database setting.', VALUE_DEFAULT, null),
351 'order' => new external_value(PARAM_ALPHA, 'The direction of the sorting: \'ASC\' or \'DESC\'.
352 Empty for using the default database setting.', VALUE_DEFAULT, null),
353 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
354 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page', VALUE_DEFAULT, 0),
355 )
356 );
357 }
358
359 /**
360 * Return access information for a given feedback
361 *
362 * @param int $databaseid the data instance id
363 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
364 * @param bool $returncontents Whether to return the entries contents or not
365 * @param str $sort sort by this field
366 * @param int $order the direction of the sorting
367 * @param int $page page of records to return
368 * @param int $perpage number of records to return per page
369 * @return array of warnings and the entries
370 * @since Moodle 3.3
371 * @throws moodle_exception
372 */
373 public static function get_entries($databaseid, $groupid = 0, $returncontents = false, $sort = null, $order = null,
374 $page = 0, $perpage = 0) {
375 global $PAGE, $DB;
376
377 $params = array('databaseid' => $databaseid, 'groupid' => $groupid, 'returncontents' => $returncontents ,
378 'sort' => $sort, 'order' => $order, 'page' => $page, 'perpage' => $perpage);
379 $params = self::validate_parameters(self::get_entries_parameters(), $params);
380 $warnings = array();
381
382 if (!empty($params['order'])) {
383 $params['order'] = strtoupper($params['order']);
384 if ($params['order'] != 'ASC' && $params['order'] != 'DESC') {
385 throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $params['order'] . ')');
386 }
387 }
388
389 list($database, $course, $cm, $context) = self::validate_database($params['databaseid']);
390 // Check database is open in time.
391 data_require_time_available($database, null, $context);
392
393 if (!empty($params['groupid'])) {
394 $groupid = $params['groupid'];
395 // Determine is the group is visible to user.
396 if (!groups_group_visible($groupid, $course, $cm)) {
397 throw new moodle_exception('notingroup');
398 }
399 } else {
400 // Check to see if groups are being used here.
401 if ($groupmode = groups_get_activity_groupmode($cm)) {
402 $groupid = groups_get_activity_group($cm);
403 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
404 if (!groups_group_visible($groupid, $course, $cm)) {
405 throw new moodle_exception('notingroup');
406 }
407 } else {
408 $groupid = 0;
409 }
410 }
411
412 list($records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
413 data_search_entries($database, $cm, $context, 'list', $groupid, '', $params['sort'], $params['order'],
414 $params['page'], $params['perpage']);
415
416 $entries = [];
417 $contentsids = []; // Store here the content ids of the records returned.
418 foreach ($records as $record) {
419 $user = user_picture::unalias($record, null, 'userid');
420 $related = array('context' => $context, 'database' => $database, 'user' => $user);
421
422 $contents = $DB->get_records('data_content', array('recordid' => $record->id));
423 $contentsids = array_merge($contentsids, array_keys($contents));
424 if ($params['returncontents']) {
425 $related['contents'] = $contents;
426 } else {
427 $related['contents'] = null;
428 }
429
430 $exporter = new record_exporter($record, $related);
431 $entries[] = $exporter->export($PAGE->get_renderer('core'));
432 }
433
434 // Retrieve total files size for the records retrieved.
435 $totalfilesize = 0;
436 $fs = get_file_storage();
437 $files = $fs->get_area_files($context->id, 'mod_data', 'content');
438 foreach ($files as $file) {
439 if ($file->is_directory() || !in_array($file->get_itemid(), $contentsids)) {
440 continue;
441 }
442 $totalfilesize += $file->get_filesize();
443 }
444
445 $result = array(
446 'entries' => $entries,
447 'totalcount' => $totalcount,
448 'totalfilesize' => $totalfilesize,
449 'warnings' => $warnings
450 );
451
452 // Check if we should return the list rendered.
453 if ($params['returncontents']) {
454 ob_start();
455 // The return parameter stops the execution after the first record.
456 data_print_template('listtemplate', $records, $database, '', $page, false);
457 $result['listviewcontents'] = ob_get_contents();
458 ob_end_clean();
459 }
460
461 return $result;
462 }
463
464 /**
465 * Returns description of method result value
466 *
467 * @return external_description
468 * @since Moodle 3.3
469 */
470 public static function get_entries_returns() {
471 return new external_single_structure(
472 array(
473 'entries' => new external_multiple_structure(
474 record_exporter::get_read_structure()
475 ),
476 'totalcount' => new external_value(PARAM_INT, 'Total count of records.'),
477 'totalfilesize' => new external_value(PARAM_INT, 'Total size (bytes) of the files included in the records.'),
478 'listviewcontents' => new external_value(PARAM_RAW, 'The list view contents as is rendered in the site.',
479 VALUE_OPTIONAL),
480 'warnings' => new external_warnings()
481 )
482 );
483 }
771effef
JL
484
485 /**
486 * Returns description of method parameters
487 *
488 * @return external_function_parameters
489 * @since Moodle 3.3
490 */
491 public static function get_entry_parameters() {
492 return new external_function_parameters(
493 array(
494 'entryid' => new external_value(PARAM_INT, 'record entry id'),
495 'returncontents' => new external_value(PARAM_BOOL, 'Whether to return contents or not.', VALUE_DEFAULT, false),
496 )
497 );
498 }
499
500 /**
501 * Return one entry record from the database, including contents optionally.
502 *
503 * @param int $entryid the record entry id id
504 * @param bool $returncontents whether to return the entries contents or not
505 * @return array of warnings and the entries
506 * @since Moodle 3.3
507 * @throws moodle_exception
508 */
509 public static function get_entry($entryid, $returncontents = false) {
510 global $PAGE, $DB;
511
512 $params = array('entryid' => $entryid, 'returncontents' => $returncontents);
513 $params = self::validate_parameters(self::get_entry_parameters(), $params);
514 $warnings = array();
515
516 $record = $DB->get_record('data_records', array('id' => $params['entryid']), '*', MUST_EXIST);
517 list($database, $course, $cm, $context) = self::validate_database($record->dataid);
518
519 // Check database is open in time.
520 $canmanageentries = has_capability('mod/data:manageentries', $context);
521 data_require_time_available($database, $canmanageentries);
522
523 if ($record->groupid !== 0) {
524 if (!groups_group_visible($record->groupid, $course, $cm)) {
525 throw new moodle_exception('notingroup');
526 }
527 }
528
529 // Check correct record entry. Group check was done before.
530 if (!data_can_view_record($database, $record, $record->groupid, $canmanageentries)) {
531 throw new moodle_exception('notapproved', 'data');
532 }
533
534 $related = array('context' => $context, 'database' => $database, 'user' => null);
535 if ($params['returncontents']) {
536 $related['contents'] = $DB->get_records('data_content', array('recordid' => $record->id));
537 } else {
538 $related['contents'] = null;
539 }
540 $exporter = new record_exporter($record, $related);
541 $entry = $exporter->export($PAGE->get_renderer('core'));
542
543 $result = array(
544 'entry' => $entry,
26d8bcea 545 'ratinginfo' => \core_rating\external\util::get_rating_info($database, $context, 'mod_data', 'entry', array($record)),
771effef
JL
546 'warnings' => $warnings
547 );
548 // Check if we should return the entry rendered.
549 if ($params['returncontents']) {
550 $records = [$record];
551 $result['entryviewcontents'] = data_print_template('singletemplate', $records, $database, '', 0, true);
552 }
553
554 return $result;
555 }
556
557 /**
558 * Returns description of method result value
559 *
560 * @return external_description
561 * @since Moodle 3.3
562 */
563 public static function get_entry_returns() {
564 return new external_single_structure(
565 array(
566 'entry' => record_exporter::get_read_structure(),
567 'entryviewcontents' => new external_value(PARAM_RAW, 'The entry as is rendered in the site.', VALUE_OPTIONAL),
26d8bcea 568 'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
771effef
JL
569 'warnings' => new external_warnings()
570 )
571 );
572 }
a934c896
JL
573
574 /**
575 * Returns description of method parameters
576 *
577 * @return external_function_parameters
578 * @since Moodle 3.3
579 */
580 public static function get_fields_parameters() {
581 return new external_function_parameters(
582 array(
583 'databaseid' => new external_value(PARAM_INT, 'Database instance id.'),
584 )
585 );
586 }
587
588 /**
589 * Return the list of configured fields for the given database.
590 *
591 * @param int $databaseid the database id
592 * @return array of warnings and the fields
593 * @since Moodle 3.3
594 * @throws moodle_exception
595 */
596 public static function get_fields($databaseid) {
597 global $PAGE;
598
599 $params = array('databaseid' => $databaseid);
600 $params = self::validate_parameters(self::get_fields_parameters(), $params);
84c2a87b 601 $fields = $warnings = array();
a934c896
JL
602
603 list($database, $course, $cm, $context) = self::validate_database($params['databaseid']);
604
605 // Check database is open in time.
606 $canmanageentries = has_capability('mod/data:manageentries', $context);
607 data_require_time_available($database, $canmanageentries);
608
609 $fieldinstances = data_get_field_instances($database);
610
611 foreach ($fieldinstances as $fieldinstance) {
612 $record = $fieldinstance->field;
613 // Now get the configs the user can see with his current permissions.
614 $configs = $fieldinstance->get_config_for_external();
615 foreach ($configs as $name => $value) {
616 // Overwrite.
617 $record->{$name} = $value;
618 }
619
620 $exporter = new field_exporter($record, array('context' => $context));
621 $fields[] = $exporter->export($PAGE->get_renderer('core'));
622 }
623
624 $result = array(
625 'fields' => $fields,
626 'warnings' => $warnings
627 );
628 return $result;
629 }
630
631 /**
632 * Returns description of method result value
633 *
634 * @return external_description
635 * @since Moodle 3.3
636 */
637 public static function get_fields_returns() {
638 return new external_single_structure(
639 array(
640 'fields' => new external_multiple_structure(
641 field_exporter::get_read_structure()
642 ),
643 'warnings' => new external_warnings()
644 )
645 );
646 }
56b8edcb
JL
647
648 /**
649 * Returns description of method parameters
650 *
651 * @return external_function_parameters
652 * @since Moodle 3.3
653 */
654 public static function search_entries_parameters() {
655 return new external_function_parameters(
656 array(
657 'databaseid' => new external_value(PARAM_INT, 'data instance id'),
658 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
659 VALUE_DEFAULT, 0),
660 'returncontents' => new external_value(PARAM_BOOL, 'Whether to return contents or not.', VALUE_DEFAULT, false),
661 'search' => new external_value(PARAM_NOTAGS, 'search string (empty when using advanced)', VALUE_DEFAULT, ''),
662 'advsearch' => new external_multiple_structure(
663 new external_single_structure(
664 array(
665 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field key for search.
666 Use fn or ln for first or last name'),
667 'value' => new external_value(PARAM_RAW, 'JSON encoded value for search'),
668 )
669 ), 'Advanced search', VALUE_DEFAULT, array()
670 ),
671 'sort' => new external_value(PARAM_INT, 'Sort the records by this field id, reserved ids are:
672 0: timeadded
673 -1: firstname
674 -2: lastname
675 -3: approved
676 -4: timemodified.
677 Empty for using the default database setting.', VALUE_DEFAULT, null),
678 'order' => new external_value(PARAM_ALPHA, 'The direction of the sorting: \'ASC\' or \'DESC\'.
679 Empty for using the default database setting.', VALUE_DEFAULT, null),
680 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
681 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page', VALUE_DEFAULT, 0),
682 )
683 );
684 }
685
686 /**
687 * Return access information for a given feedback
688 *
689 * @param int $databaseid the data instance id
690 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
691 * @param bool $returncontents whether to return contents or not
692 * @param str $search search text
693 * @param array $advsearch advanced search data
694 * @param str $sort sort by this field
695 * @param int $order the direction of the sorting
696 * @param int $page page of records to return
697 * @param int $perpage number of records to return per page
698 * @return array of warnings and the entries
699 * @since Moodle 3.3
700 * @throws moodle_exception
701 */
702 public static function search_entries($databaseid, $groupid = 0, $returncontents = false, $search = '', $advsearch = [],
703 $sort = null, $order = null, $page = 0, $perpage = 0) {
704 global $PAGE, $DB;
705
706 $params = array('databaseid' => $databaseid, 'groupid' => $groupid, 'returncontents' => $returncontents, 'search' => $search,
707 'advsearch' => $advsearch, 'sort' => $sort, 'order' => $order, 'page' => $page, 'perpage' => $perpage);
708 $params = self::validate_parameters(self::search_entries_parameters(), $params);
709 $warnings = array();
710
711 if (!empty($params['order'])) {
712 $params['order'] = strtoupper($params['order']);
713 if ($params['order'] != 'ASC' && $params['order'] != 'DESC') {
714 throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $params['order'] . ')');
715 }
716 }
717
718 list($database, $course, $cm, $context) = self::validate_database($params['databaseid']);
719 // Check database is open in time.
720 data_require_time_available($database, null, $context);
721
722 if (!empty($params['groupid'])) {
723 $groupid = $params['groupid'];
724 // Determine is the group is visible to user.
725 if (!groups_group_visible($groupid, $course, $cm)) {
726 throw new moodle_exception('notingroup');
727 }
728 } else {
729 // Check to see if groups are being used here.
730 if ($groupmode = groups_get_activity_groupmode($cm)) {
731 $groupid = groups_get_activity_group($cm);
732 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
733 if (!groups_group_visible($groupid, $course, $cm)) {
734 throw new moodle_exception('notingroup');
735 }
736 } else {
737 $groupid = 0;
738 }
739 }
740
741 if (!empty($params['advsearch'])) {
742 $advanced = true;
743 $defaults = [];
744 $fn = $ln = ''; // Defaults for first and last name.
745 // Force defaults for advanced search.
746 foreach ($params['advsearch'] as $adv) {
8cc04bcc
JL
747 if ($adv['name'] == 'fn') {
748 $fn = json_decode($adv['value']);
749 continue;
750 }
751 if ($adv['name'] == 'ln') {
752 $ln = json_decode($adv['value']);
56b8edcb
JL
753 continue;
754 }
755 $defaults[$adv['name']] = json_decode($adv['value']);
756 }
757 list($searcharray, $params['search']) = data_build_search_array($database, false, [], $defaults, $fn, $ln);
758 } else {
759 $advanced = null;
760 $searcharray = null;
761 }
762
763 list($records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
764 data_search_entries($database, $cm, $context, 'list', $groupid, $params['search'], $params['sort'], $params['order'],
765 $params['page'], $params['perpage'], $advanced, $searcharray);
766
767 $entries = [];
768 foreach ($records as $record) {
769 $user = user_picture::unalias($record, null, 'userid');
770 $related = array('context' => $context, 'database' => $database, 'user' => $user);
771 if ($params['returncontents']) {
772 $related['contents'] = $DB->get_records('data_content', array('recordid' => $record->id));
773 } else {
774 $related['contents'] = null;
775 }
776
777 $exporter = new record_exporter($record, $related);
778 $entries[] = $exporter->export($PAGE->get_renderer('core'));
779 }
780
781 $result = array(
782 'entries' => $entries,
783 'totalcount' => $totalcount,
784 'maxcount' => $maxcount,
785 'warnings' => $warnings
786 );
787
788 // Check if we should return the list rendered.
789 if ($params['returncontents']) {
790 ob_start();
791 // The return parameter stops the execution after the first record.
792 data_print_template('listtemplate', $records, $database, '', $page, false);
793 $result['listviewcontents'] = ob_get_contents();
794 ob_end_clean();
795 }
796
797 return $result;
798 }
799
800 /**
801 * Returns description of method result value
802 *
803 * @return external_description
804 * @since Moodle 3.3
805 */
806 public static function search_entries_returns() {
807 return new external_single_structure(
808 array(
809 'entries' => new external_multiple_structure(
810 record_exporter::get_read_structure()
811 ),
be4bdab7
JL
812 'totalcount' => new external_value(PARAM_INT, 'Total count of records returned by the search.'),
813 'maxcount' => new external_value(PARAM_INT, 'Total count of records that the user could see in the database
814 (if all the search criterias were removed).', VALUE_OPTIONAL),
56b8edcb
JL
815 'listviewcontents' => new external_value(PARAM_RAW, 'The list view contents as is rendered in the site.',
816 VALUE_OPTIONAL),
817 'warnings' => new external_warnings()
818 )
819 );
820 }
229158fe
JL
821
822 /**
823 * Returns description of method parameters
824 *
825 * @return external_function_parameters
826 * @since Moodle 3.3
827 */
828 public static function approve_entry_parameters() {
829 return new external_function_parameters(
830 array(
831 'entryid' => new external_value(PARAM_INT, 'Record entry id.'),
832 'approve' => new external_value(PARAM_BOOL, 'Whether to approve (true) or unapprove the entry.',
833 VALUE_DEFAULT, true),
834 )
835 );
836 }
837
838 /**
839 * Approves or unapproves an entry.
840 *
841 * @param int $entryid the record entry id id
842 * @param bool $approve whether to approve (true) or unapprove the entry
843 * @return array of warnings and the entries
844 * @since Moodle 3.3
845 * @throws moodle_exception
846 */
847 public static function approve_entry($entryid, $approve = true) {
848 global $PAGE, $DB;
849
850 $params = array('entryid' => $entryid, 'approve' => $approve);
851 $params = self::validate_parameters(self::approve_entry_parameters(), $params);
852 $warnings = array();
853
854 $record = $DB->get_record('data_records', array('id' => $params['entryid']), '*', MUST_EXIST);
855 list($database, $course, $cm, $context) = self::validate_database($record->dataid);
856 // Check database is open in time.
857 data_require_time_available($database, null, $context);
858 // Check specific capabilities.
859 require_capability('mod/data:approve', $context);
860
861 data_approve_entry($record->id, $params['approve']);
862
863 $result = array(
864 'status' => true,
865 'warnings' => $warnings
866 );
867 return $result;
868 }
869
870 /**
871 * Returns description of method result value
872 *
873 * @return external_description
874 * @since Moodle 3.3
875 */
876 public static function approve_entry_returns() {
877 return new external_single_structure(
878 array(
879 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
880 'warnings' => new external_warnings()
881 )
882 );
883 }
67bb168e
JL
884
885 /**
886 * Returns description of method parameters
887 *
888 * @return external_function_parameters
889 * @since Moodle 3.3
890 */
891 public static function delete_entry_parameters() {
892 return new external_function_parameters(
893 array(
894 'entryid' => new external_value(PARAM_INT, 'Record entry id.'),
895 )
896 );
897 }
898
899 /**
900 * Deletes an entry.
901 *
902 * @param int $entryid the record entry id
903 * @return array of warnings success status
904 * @since Moodle 3.3
905 * @throws moodle_exception
906 */
907 public static function delete_entry($entryid) {
908 global $PAGE, $DB;
909
910 $params = array('entryid' => $entryid);
911 $params = self::validate_parameters(self::delete_entry_parameters(), $params);
912 $warnings = array();
913
914 $record = $DB->get_record('data_records', array('id' => $params['entryid']), '*', MUST_EXIST);
915 list($database, $course, $cm, $context) = self::validate_database($record->dataid);
916
917 if (data_user_can_manage_entry($record, $database, $context)) {
918 data_delete_record($record->id, $database, $course->id, $cm->id);
919 } else {
920 throw new moodle_exception('noaccess', 'data');
921 }
922
923 $result = array(
924 'status' => true,
925 'warnings' => $warnings
926 );
927 return $result;
928 }
929
930 /**
931 * Returns description of method result value
932 *
933 * @return external_description
934 * @since Moodle 3.3
935 */
936 public static function delete_entry_returns() {
937 return new external_single_structure(
938 array(
939 'status' => new external_value(PARAM_BOOL, 'Always true. If we see this field it means that the entry was deleted.'),
940 'warnings' => new external_warnings()
941 )
942 );
943 }
61c640c1
JL
944
945 /**
946 * Returns description of method parameters
947 *
948 * @return external_function_parameters
949 * @since Moodle 3.3
950 */
951 public static function add_entry_parameters() {
952 return new external_function_parameters(
953 array(
954 'databaseid' => new external_value(PARAM_INT, 'data instance id'),
955 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group',
956 VALUE_DEFAULT, 0),
957 'data' => new external_multiple_structure(
958 new external_single_structure(
959 array(
960 'fieldid' => new external_value(PARAM_INT, 'The field id.'),
961 'subfield' => new external_value(PARAM_NOTAGS, 'The subfield name (if required).', VALUE_DEFAULT, ''),
962 'value' => new external_value(PARAM_RAW, 'The contents for the field always JSON encoded.'),
963 )
964 ), 'The fields data to be created'
965 ),
966 )
967 );
968 }
969
970 /**
971 * Adds a new entry to a database
972 *
973 * @param int $databaseid the data instance id
974 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
975 * @param array $data the fields data to be created
976 * @return array of warnings and status result
977 * @since Moodle 3.3
978 * @throws moodle_exception
979 */
980 public static function add_entry($databaseid, $groupid, $data) {
981 global $DB;
982
983 $params = array('databaseid' => $databaseid, 'groupid' => $groupid, 'data' => $data);
984 $params = self::validate_parameters(self::add_entry_parameters(), $params);
985 $warnings = array();
986 $fieldnotifications = array();
987
988 list($database, $course, $cm, $context) = self::validate_database($params['databaseid']);
989 // Check database is open in time.
990 data_require_time_available($database, null, $context);
991
992 $groupmode = groups_get_activity_groupmode($cm);
993 if (!empty($params['groupid'])) {
994 $groupid = $params['groupid'];
995 // Determine is the group is visible to user.
996 if (!groups_group_visible($groupid, $course, $cm)) {
997 throw new moodle_exception('notingroup');
998 }
999 } else {
1000 // Check to see if groups are being used here.
1001 if ($groupmode) {
1002 $groupid = groups_get_activity_group($cm);
1003 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1004 if (!groups_group_visible($groupid, $course, $cm)) {
1005 throw new moodle_exception('notingroup');
1006 }
1007 } else {
1008 $groupid = 0;
1009 }
1010 }
1011
1012 if (!data_user_can_add_entry($database, $groupid, $groupmode, $context)) {
1013 throw new moodle_exception('noaccess', 'data');
1014 }
1015
1016 // Prepare the data as is expected by the API.
1017 $datarecord = new stdClass;
1018 foreach ($params['data'] as $data) {
1019 $subfield = ($data['subfield'] !== '') ? '_' . $data['subfield'] : '';
1020 // We ask for JSON encoded values because of multiple choice forms or checkboxes that use array parameters.
1021 $datarecord->{'field_' . $data['fieldid'] . $subfield} = json_decode($data['value']);
1022 }
1023 // Validate to ensure that enough data was submitted.
1024 $fields = $DB->get_records('data_fields', array('dataid' => $database->id));
1025 $processeddata = data_process_submission($database, $fields, $datarecord);
1026
1027 // Format notifications.
1028 if (!empty($processeddata->fieldnotifications)) {
1029 foreach ($processeddata->fieldnotifications as $field => $notififications) {
1030 foreach ($notififications as $notif) {
1031 $fieldnotifications[] = [
1032 'fieldname' => $field,
1033 'notification' => $notif,
1034 ];
1035 }
1036 }
1037 }
1038
1039 // Create a new (empty) record.
1040 $newentryid = 0;
1041 if ($processeddata->validated && $recordid = data_add_record($database, $groupid)) {
1042 $newentryid = $recordid;
1043 // Now populate the fields contents of the new record.
1044 data_add_fields_contents_to_new_record($database, $context, $recordid, $fields, $datarecord, $processeddata);
1045 }
1046
1047 $result = array(
1048 'newentryid' => $newentryid,
1049 'generalnotifications' => $processeddata->generalnotifications,
1050 'fieldnotifications' => $fieldnotifications,
1051 );
1052 return $result;
1053 }
1054
1055 /**
1056 * Returns description of method result value
1057 *
1058 * @return external_description
1059 * @since Moodle 3.3
1060 */
1061 public static function add_entry_returns() {
1062 return new external_single_structure(
1063 array(
1064 'newentryid' => new external_value(PARAM_INT, 'True new created entry id. 0 if the entry was not created.'),
1065 'generalnotifications' => new external_multiple_structure(
1066 new external_value(PARAM_RAW, 'General notifications')
1067 ),
1068 'fieldnotifications' => new external_multiple_structure(
1069 new external_single_structure(
1070 array(
1071 'fieldname' => new external_value(PARAM_TEXT, 'The field name.'),
1072 'notification' => new external_value(PARAM_RAW, 'The notification for the field.'),
1073 )
1074 )
1075 ),
1076 'warnings' => new external_warnings()
1077 )
1078 );
1079 }
4ca2890d
JL
1080
1081 /**
1082 * Returns description of method parameters
1083 *
1084 * @return external_function_parameters
1085 * @since Moodle 3.3
1086 */
1087 public static function update_entry_parameters() {
1088 return new external_function_parameters(
1089 array(
1090 'entryid' => new external_value(PARAM_INT, 'The entry record id.'),
1091 'data' => new external_multiple_structure(
1092 new external_single_structure(
1093 array(
1094 'fieldid' => new external_value(PARAM_INT, 'The field id.'),
1095 'subfield' => new external_value(PARAM_NOTAGS, 'The subfield name (if required).', VALUE_DEFAULT, null),
1096 'value' => new external_value(PARAM_RAW, 'The new contents for the field always JSON encoded.'),
1097 )
1098 ), 'The fields data to be updated'
1099 ),
1100 )
1101 );
1102 }
1103
1104 /**
1105 * Updates an existing entry.
1106 *
1107 * @param int $entryid the data instance id
1108 * @param array $data the fields data to be created
1109 * @return array of warnings and status result
1110 * @since Moodle 3.3
1111 * @throws moodle_exception
1112 */
1113 public static function update_entry($entryid, $data) {
1114 global $DB;
1115
1116 $params = array('entryid' => $entryid, 'data' => $data);
1117 $params = self::validate_parameters(self::update_entry_parameters(), $params);
1118 $warnings = array();
1119 $fieldnotifications = array();
1120 $updated = false;
1121
1122 $record = $DB->get_record('data_records', array('id' => $params['entryid']), '*', MUST_EXIST);
1123 list($database, $course, $cm, $context) = self::validate_database($record->dataid);
1124 // Check database is open in time.
1125 data_require_time_available($database, null, $context);
1126
1127 if (!data_user_can_manage_entry($record, $database, $context)) {
1128 throw new moodle_exception('noaccess', 'data');
1129 }
1130
1131 // Prepare the data as is expected by the API.
1132 $datarecord = new stdClass;
1133 foreach ($params['data'] as $data) {
1134 $subfield = ($data['subfield'] !== '') ? '_' . $data['subfield'] : '';
1135 // We ask for JSON encoded values because of multiple choice forms or checkboxes that use array parameters.
1136 $datarecord->{'field_' . $data['fieldid'] . $subfield} = json_decode($data['value']);
1137 }
1138 // Validate to ensure that enough data was submitted.
1139 $fields = $DB->get_records('data_fields', array('dataid' => $database->id));
1140 $processeddata = data_process_submission($database, $fields, $datarecord);
1141
1142 // Format notifications.
1143 if (!empty($processeddata->fieldnotifications)) {
1144 foreach ($processeddata->fieldnotifications as $field => $notififications) {
1145 foreach ($notififications as $notif) {
1146 $fieldnotifications[] = [
1147 'fieldname' => $field,
1148 'notification' => $notif,
1149 ];
1150 }
1151 }
1152 }
1153
1154 if ($processeddata->validated) {
1155 // Now update the fields contents.
1156 data_update_record_fields_contents($database, $record, $context, $datarecord, $processeddata);
1157 $updated = true;
1158 }
1159
1160 $result = array(
1161 'updated' => $updated,
1162 'generalnotifications' => $processeddata->generalnotifications,
1163 'fieldnotifications' => $fieldnotifications,
1164 'warnings' => $warnings,
1165 );
1166 return $result;
1167 }
1168
1169 /**
1170 * Returns description of method result value
1171 *
1172 * @return external_description
1173 * @since Moodle 3.3
1174 */
1175 public static function update_entry_returns() {
1176 return new external_single_structure(
1177 array(
1178 'updated' => new external_value(PARAM_BOOL, 'True if the entry was successfully updated, false other wise.'),
1179 'generalnotifications' => new external_multiple_structure(
1180 new external_value(PARAM_RAW, 'General notifications')
1181 ),
1182 'fieldnotifications' => new external_multiple_structure(
1183 new external_single_structure(
1184 array(
1185 'fieldname' => new external_value(PARAM_TEXT, 'The field name.'),
1186 'notification' => new external_value(PARAM_RAW, 'The notification for the field.'),
1187 )
1188 )
1189 ),
1190 'warnings' => new external_warnings()
1191 )
1192 );
1193 }
2ab34819 1194}