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