See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]
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 * This file contains the definition for the library class for file feedback plugin 19 * 20 * 21 * @package assignfeedback_file 22 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 use \mod_assign\output\assign_header; 29 30 // File areas for file feedback assignment. 31 define('ASSIGNFEEDBACK_FILE_FILEAREA', 'feedback_files'); 32 define('ASSIGNFEEDBACK_FILE_BATCH_FILEAREA', 'feedback_files_batch'); 33 define('ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA', 'feedback_files_import'); 34 define('ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES', 5); 35 define('ASSIGNFEEDBACK_FILE_MAXSUMMARYUSERS', 5); 36 define('ASSIGNFEEDBACK_FILE_MAXFILEUNZIPTIME', 120); 37 38 /** 39 * Library class for file feedback plugin extending feedback plugin base class. 40 * 41 * @package assignfeedback_file 42 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class assign_feedback_file extends assign_feedback_plugin { 46 47 /** 48 * Get the name of the file feedback plugin. 49 * 50 * @return string 51 */ 52 public function get_name() { 53 return get_string('file', 'assignfeedback_file'); 54 } 55 56 /** 57 * Get file feedback information from the database. 58 * 59 * @param int $gradeid 60 * @return mixed 61 */ 62 public function get_file_feedback($gradeid) { 63 global $DB; 64 return $DB->get_record('assignfeedback_file', array('grade'=>$gradeid)); 65 } 66 67 /** 68 * File format options. 69 * 70 * @return array 71 */ 72 private function get_file_options() { 73 global $COURSE; 74 75 $fileoptions = array('subdirs'=>1, 76 'maxbytes'=>$COURSE->maxbytes, 77 'accepted_types'=>'*', 78 'return_types'=>FILE_INTERNAL); 79 return $fileoptions; 80 } 81 82 /** 83 * Has the feedback file been modified? 84 * 85 * @param stdClass $grade Grade object. 86 * @param stdClass $data Form data. 87 * @return boolean True if the file area has been modified, else false. 88 */ 89 public function is_feedback_modified(stdClass $grade, stdClass $data) { 90 global $USER; 91 92 $filekey = null; 93 $draftareainfo = null; 94 foreach ($data as $key => $value) { 95 if (strpos($key, 'files_') === 0 && strpos($key, '_filemanager')) { 96 $filekey = $key; 97 } 98 } 99 if (isset($filekey)) { 100 $draftareainfo = file_get_draft_area_info($data->$filekey); 101 $filecount = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA); 102 if ($filecount != $draftareainfo['filecount']) { 103 return true; 104 } else { 105 // We need to check that the files in the draft area are the same as in the file area. 106 $usercontext = context_user::instance($USER->id); 107 $fs = get_file_storage(); 108 $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $data->$filekey, 'id', true); 109 $files = $fs->get_area_files($this->assignment->get_context()->id, 110 'assignfeedback_file', 111 ASSIGNFEEDBACK_FILE_FILEAREA, 112 $grade->id, 113 'id', 114 false); 115 foreach ($files as $key => $file) { 116 // Flag for recording if we have a matching file. 117 $matchflag = false; 118 foreach ($draftfiles as $draftkey => $draftfile) { 119 if (!$file->is_directory()) { 120 // File name is the same, but it could be a different file with the same name. 121 if ($draftfile->get_filename() == $file->get_filename()) { 122 // If the file name is the same but the content hash is different, or 123 // The file path for the file has changed, then we have a modification. 124 if ($draftfile->get_contenthash() != $file->get_contenthash() || 125 $draftfile->get_filepath() != $file->get_filepath()) { 126 return true; 127 } 128 // These files match. Check the next file. 129 $matchflag = true; 130 // We have a match on the file name so we can move to the next file and not 131 // proceed through the other draftfiles. 132 break; 133 } 134 } 135 } 136 // If the file does not match then there has been a modification. 137 if (!$matchflag) { 138 return true; 139 } 140 } 141 } 142 } 143 return false; 144 } 145 146 /** 147 * Copy all the files from one file area to another. 148 * 149 * @param file_storage $fs - The source context id 150 * @param int $fromcontextid - The source context id 151 * @param string $fromcomponent - The source component 152 * @param string $fromfilearea - The source filearea 153 * @param int $fromitemid - The source item id 154 * @param int $tocontextid - The destination context id 155 * @param string $tocomponent - The destination component 156 * @param string $tofilearea - The destination filearea 157 * @param int $toitemid - The destination item id 158 * @return boolean 159 */ 160 private function copy_area_files(file_storage $fs, 161 $fromcontextid, 162 $fromcomponent, 163 $fromfilearea, 164 $fromitemid, 165 $tocontextid, 166 $tocomponent, 167 $tofilearea, 168 $toitemid) { 169 170 $newfilerecord = new stdClass(); 171 $newfilerecord->contextid = $tocontextid; 172 $newfilerecord->component = $tocomponent; 173 $newfilerecord->filearea = $tofilearea; 174 $newfilerecord->itemid = $toitemid; 175 176 if ($files = $fs->get_area_files($fromcontextid, $fromcomponent, $fromfilearea, $fromitemid)) { 177 foreach ($files as $file) { 178 if ($file->is_directory() and $file->get_filepath() === '/') { 179 // We need a way to mark the age of each draft area. 180 // By not copying the root dir we force it to be created 181 // automatically with current timestamp. 182 continue; 183 } 184 185 $existingfile = $fs->get_file( 186 $newfilerecord->contextid, 187 $newfilerecord->component, 188 $newfilerecord->filearea, 189 $newfilerecord->itemid, 190 $file->get_filepath(), 191 $file->get_filename() 192 ); 193 if ($existingfile) { 194 // If the file already exists, remove it so it can be updated. 195 $existingfile->delete(); 196 } 197 198 $newfile = $fs->create_file_from_storedfile($newfilerecord, $file); 199 } 200 } 201 return true; 202 } 203 204 /** 205 * Get form elements for grading form. 206 * 207 * @param stdClass $grade 208 * @param MoodleQuickForm $mform 209 * @param stdClass $data 210 * @param int $userid The userid we are currently grading 211 * @return bool true if elements were added to the form 212 */ 213 public function get_form_elements_for_user($grade, MoodleQuickForm $mform, stdClass $data, $userid) { 214 215 $fileoptions = $this->get_file_options(); 216 $gradeid = $grade ? $grade->id : 0; 217 $elementname = 'files_' . $userid; 218 219 $data = file_prepare_standard_filemanager($data, 220 $elementname, 221 $fileoptions, 222 $this->assignment->get_context(), 223 'assignfeedback_file', 224 ASSIGNFEEDBACK_FILE_FILEAREA, 225 $gradeid); 226 $mform->addElement('filemanager', $elementname . '_filemanager', $this->get_name(), null, $fileoptions); 227 228 return true; 229 } 230 231 /** 232 * Count the number of files. 233 * 234 * @param int $gradeid 235 * @param string $area 236 * @return int 237 */ 238 private function count_files($gradeid, $area) { 239 240 $fs = get_file_storage(); 241 $files = $fs->get_area_files($this->assignment->get_context()->id, 242 'assignfeedback_file', 243 $area, 244 $gradeid, 245 'id', 246 false); 247 248 return count($files); 249 } 250 251 /** 252 * Update the number of files in the file area. 253 * 254 * @param stdClass $grade The grade record 255 * @return bool - true if the value was saved 256 */ 257 public function update_file_count($grade) { 258 global $DB; 259 260 $filefeedback = $this->get_file_feedback($grade->id); 261 if ($filefeedback) { 262 $filefeedback->numfiles = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA); 263 return $DB->update_record('assignfeedback_file', $filefeedback); 264 } else { 265 $filefeedback = new stdClass(); 266 $filefeedback->numfiles = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA); 267 $filefeedback->grade = $grade->id; 268 $filefeedback->assignment = $this->assignment->get_instance()->id; 269 return $DB->insert_record('assignfeedback_file', $filefeedback) > 0; 270 } 271 } 272 273 /** 274 * Save the feedback files. 275 * 276 * @param stdClass $grade 277 * @param stdClass $data 278 * @return bool 279 */ 280 public function save(stdClass $grade, stdClass $data) { 281 $fileoptions = $this->get_file_options(); 282 283 // The element name may have been for a different user. 284 foreach ($data as $key => $value) { 285 if (strpos($key, 'files_') === 0 && strpos($key, '_filemanager')) { 286 $elementname = substr($key, 0, strpos($key, '_filemanager')); 287 } 288 } 289 290 $data = file_postupdate_standard_filemanager($data, 291 $elementname, 292 $fileoptions, 293 $this->assignment->get_context(), 294 'assignfeedback_file', 295 ASSIGNFEEDBACK_FILE_FILEAREA, 296 $grade->id); 297 298 return $this->update_file_count($grade); 299 } 300 301 /** 302 * Display the list of files in the feedback status table. 303 * 304 * @param stdClass $grade 305 * @param bool $showviewlink - Set to true to show a link to see the full list of files 306 * @return string 307 */ 308 public function view_summary(stdClass $grade, & $showviewlink) { 309 310 $count = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA); 311 312 // Show a view all link if the number of files is over this limit. 313 $showviewlink = $count > ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES; 314 315 if ($count <= ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES) { 316 return $this->assignment->render_area_files('assignfeedback_file', 317 ASSIGNFEEDBACK_FILE_FILEAREA, 318 $grade->id); 319 } else { 320 return get_string('countfiles', 'assignfeedback_file', $count); 321 } 322 } 323 324 /** 325 * Display the list of files in the feedback status table. 326 * 327 * @param stdClass $grade 328 * @return string 329 */ 330 public function view(stdClass $grade) { 331 return $this->assignment->render_area_files('assignfeedback_file', 332 ASSIGNFEEDBACK_FILE_FILEAREA, 333 $grade->id); 334 } 335 336 /** 337 * The assignment has been deleted - cleanup. 338 * 339 * @return bool 340 */ 341 public function delete_instance() { 342 global $DB; 343 // Will throw exception on failure. 344 $DB->delete_records('assignfeedback_file', 345 array('assignment'=>$this->assignment->get_instance()->id)); 346 347 return true; 348 } 349 350 /** 351 * Return true if there are no feedback files. 352 * 353 * @param stdClass $grade 354 */ 355 public function is_empty(stdClass $grade) { 356 return $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA) == 0; 357 } 358 359 /** 360 * Get file areas returns a list of areas this plugin stores files. 361 * 362 * @return array - An array of fileareas (keys) and descriptions (values) 363 */ 364 public function get_file_areas() { 365 return array(ASSIGNFEEDBACK_FILE_FILEAREA=>$this->get_name()); 366 } 367 368 /** 369 * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type 370 * and version. 371 * 372 * @param string $type old assignment subtype 373 * @param int $version old assignment version 374 * @return bool True if upgrade is possible 375 */ 376 public function can_upgrade($type, $version) { 377 if (($type == 'upload' || $type == 'uploadsingle') && $version >= 2011112900) { 378 return true; 379 } 380 return false; 381 } 382 383 /** 384 * Upgrade the settings from the old assignment to the new plugin based one. 385 * 386 * @param context $oldcontext - the context for the old assignment 387 * @param stdClass $oldassignment - the data for the old assignment 388 * @param string $log - can be appended to by the upgrade 389 * @return bool was it a success? (false will trigger a rollback) 390 */ 391 public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) { 392 // First upgrade settings (nothing to do). 393 return true; 394 } 395 396 /** 397 * Upgrade the feedback from the old assignment to the new one. 398 * 399 * @param context $oldcontext - the database for the old assignment context 400 * @param stdClass $oldassignment The data record for the old assignment 401 * @param stdClass $oldsubmission The data record for the old submission 402 * @param stdClass $grade The data record for the new grade 403 * @param string $log Record upgrade messages in the log 404 * @return bool true or false - false will trigger a rollback 405 */ 406 public function upgrade(context $oldcontext, 407 stdClass $oldassignment, 408 stdClass $oldsubmission, 409 stdClass $grade, 410 & $log) { 411 global $DB; 412 413 // Now copy the area files. 414 $this->assignment->copy_area_files_for_upgrade($oldcontext->id, 415 'mod_assignment', 416 'response', 417 $oldsubmission->id, 418 $this->assignment->get_context()->id, 419 'assignfeedback_file', 420 ASSIGNFEEDBACK_FILE_FILEAREA, 421 $grade->id); 422 423 // Now count them! 424 $filefeedback = new stdClass(); 425 $filefeedback->numfiles = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA); 426 $filefeedback->grade = $grade->id; 427 $filefeedback->assignment = $this->assignment->get_instance()->id; 428 if (!$DB->insert_record('assignfeedback_file', $filefeedback) > 0) { 429 $log .= get_string('couldnotconvertgrade', 'mod_assign', $grade->userid); 430 return false; 431 } 432 return true; 433 } 434 435 /** 436 * Return a list of the batch grading operations performed by this plugin. 437 * This plugin supports batch upload files and upload zip. 438 * 439 * @return array The list of batch grading operations 440 */ 441 public function get_grading_batch_operations() { 442 return array('uploadfiles'=>get_string('uploadfiles', 'assignfeedback_file')); 443 } 444 445 /** 446 * Upload files and send them to multiple users. 447 * 448 * @param array $users - An array of user ids 449 * @return string - The response html 450 */ 451 public function view_batch_upload_files($users) { 452 global $CFG, $DB, $USER; 453 454 require_capability('mod/assign:grade', $this->assignment->get_context()); 455 require_once($CFG->dirroot . '/mod/assign/feedback/file/batchuploadfilesform.php'); 456 require_once($CFG->dirroot . '/mod/assign/renderable.php'); 457 458 $formparams = array('cm'=>$this->assignment->get_course_module()->id, 459 'users'=>$users, 460 'context'=>$this->assignment->get_context()); 461 462 $usershtml = ''; 463 464 $usercount = 0; 465 foreach ($users as $userid) { 466 if ($usercount >= ASSIGNFEEDBACK_FILE_MAXSUMMARYUSERS) { 467 $moreuserscount = count($users) - ASSIGNFEEDBACK_FILE_MAXSUMMARYUSERS; 468 $usershtml .= get_string('moreusers', 'assignfeedback_file', $moreuserscount); 469 break; 470 } 471 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); 472 473 $usersummary = new assign_user_summary($user, 474 $this->assignment->get_course()->id, 475 has_capability('moodle/site:viewfullnames', 476 $this->assignment->get_course_context()), 477 $this->assignment->is_blind_marking(), 478 $this->assignment->get_uniqueid_for_user($user->id), 479 // TODO Does not support custom user profile fields (MDL-70456). 480 \core_user\fields::get_identity_fields($this->assignment->get_context(), false)); 481 $usershtml .= $this->assignment->get_renderer()->render($usersummary); 482 $usercount += 1; 483 } 484 485 $formparams['usershtml'] = $usershtml; 486 487 $mform = new assignfeedback_file_batch_upload_files_form(null, $formparams); 488 489 if ($mform->is_cancelled()) { 490 redirect(new moodle_url('view.php', 491 array('id'=>$this->assignment->get_course_module()->id, 492 'action'=>'grading'))); 493 return; 494 } else if ($data = $mform->get_data()) { 495 // Copy the files from the draft area to a temporary import area. 496 $data = file_postupdate_standard_filemanager($data, 497 'files', 498 $this->get_file_options(), 499 $this->assignment->get_context(), 500 'assignfeedback_file', 501 ASSIGNFEEDBACK_FILE_BATCH_FILEAREA, 502 $USER->id); 503 $fs = get_file_storage(); 504 505 // Now copy each of these files to the users feedback file area. 506 foreach ($users as $userid) { 507 $grade = $this->assignment->get_user_grade($userid, true); 508 $this->assignment->notify_grade_modified($grade); 509 510 $this->copy_area_files($fs, 511 $this->assignment->get_context()->id, 512 'assignfeedback_file', 513 ASSIGNFEEDBACK_FILE_BATCH_FILEAREA, 514 $USER->id, 515 $this->assignment->get_context()->id, 516 'assignfeedback_file', 517 ASSIGNFEEDBACK_FILE_FILEAREA, 518 $grade->id); 519 520 $filefeedback = $this->get_file_feedback($grade->id); 521 if ($filefeedback) { 522 $filefeedback->numfiles = $this->count_files($grade->id, 523 ASSIGNFEEDBACK_FILE_FILEAREA); 524 $DB->update_record('assignfeedback_file', $filefeedback); 525 } else { 526 $filefeedback = new stdClass(); 527 $filefeedback->numfiles = $this->count_files($grade->id, 528 ASSIGNFEEDBACK_FILE_FILEAREA); 529 $filefeedback->grade = $grade->id; 530 $filefeedback->assignment = $this->assignment->get_instance()->id; 531 $DB->insert_record('assignfeedback_file', $filefeedback); 532 } 533 } 534 535 // Now delete the temporary import area. 536 $fs->delete_area_files($this->assignment->get_context()->id, 537 'assignfeedback_file', 538 ASSIGNFEEDBACK_FILE_BATCH_FILEAREA, 539 $USER->id); 540 541 redirect(new moodle_url('view.php', 542 array('id'=>$this->assignment->get_course_module()->id, 543 'action'=>'grading'))); 544 return; 545 } else { 546 547 $header = new assign_header($this->assignment->get_instance(), 548 $this->assignment->get_context(), 549 false, 550 $this->assignment->get_course_module()->id, 551 get_string('batchuploadfiles', 'assignfeedback_file')); 552 $o = ''; 553 $o .= $this->assignment->get_renderer()->render($header); 554 $o .= $this->assignment->get_renderer()->render(new assign_form('batchuploadfiles', $mform)); 555 $o .= $this->assignment->get_renderer()->render_footer(); 556 } 557 558 return $o; 559 } 560 561 /** 562 * User has chosen a custom grading batch operation and selected some users. 563 * 564 * @param string $action - The chosen action 565 * @param array $users - An array of user ids 566 * @return string - The response html 567 */ 568 public function grading_batch_operation($action, $users) { 569 570 if ($action == 'uploadfiles') { 571 return $this->view_batch_upload_files($users); 572 } 573 return ''; 574 } 575 576 /** 577 * View the upload zip form. 578 * 579 * @return string - The html response 580 */ 581 public function view_upload_zip() { 582 global $CFG, $USER; 583 584 require_capability('mod/assign:grade', $this->assignment->get_context()); 585 require_once($CFG->dirroot . '/mod/assign/feedback/file/uploadzipform.php'); 586 require_once($CFG->dirroot . '/mod/assign/feedback/file/importziplib.php'); 587 require_once($CFG->dirroot . '/mod/assign/feedback/file/importzipform.php'); 588 589 $formparams = array('context'=>$this->assignment->get_context(), 590 'cm'=>$this->assignment->get_course_module()->id); 591 $mform = new assignfeedback_file_upload_zip_form(null, $formparams); 592 593 $o = ''; 594 595 $confirm = optional_param('confirm', 0, PARAM_BOOL); 596 $renderer = $this->assignment->get_renderer(); 597 598 // Delete any existing files. 599 $importer = new assignfeedback_file_zip_importer(); 600 $contextid = $this->assignment->get_context()->id; 601 602 if ($mform->is_cancelled()) { 603 $importer->delete_import_files($contextid); 604 $urlparams = array('id'=>$this->assignment->get_course_module()->id, 605 'action'=>'grading'); 606 $url = new moodle_url('view.php', $urlparams); 607 redirect($url); 608 return; 609 } else if ($confirm) { 610 $params = array('assignment'=>$this->assignment, 'importer'=>$importer); 611 612 $mform = new assignfeedback_file_import_zip_form(null, $params); 613 if ($mform->is_cancelled()) { 614 $importer->delete_import_files($contextid); 615 $urlparams = array('id'=>$this->assignment->get_course_module()->id, 616 'action'=>'grading'); 617 $url = new moodle_url('view.php', $urlparams); 618 redirect($url); 619 return; 620 } 621 622 $o .= $importer->import_zip_files($this->assignment, $this); 623 $importer->delete_import_files($contextid); 624 } else if (($data = $mform->get_data()) && 625 ($zipfile = $mform->save_stored_file('feedbackzip', 626 $contextid, 627 'assignfeedback_file', 628 ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA, 629 $USER->id, 630 '/', 631 'import.zip', 632 true))) { 633 634 $importer->extract_files_from_zip($zipfile, $contextid); 635 636 $params = array('assignment'=>$this->assignment, 'importer'=>$importer); 637 638 $mform = new assignfeedback_file_import_zip_form(null, $params); 639 640 $header = new assign_header($this->assignment->get_instance(), 641 $this->assignment->get_context(), 642 false, 643 $this->assignment->get_course_module()->id, 644 get_string('confirmuploadzip', 'assignfeedback_file')); 645 $o .= $renderer->render($header); 646 $o .= $renderer->render(new assign_form('confirmimportzip', $mform)); 647 $o .= $renderer->render_footer(); 648 649 } else { 650 651 $header = new assign_header($this->assignment->get_instance(), 652 $this->assignment->get_context(), 653 false, 654 $this->assignment->get_course_module()->id, 655 get_string('uploadzip', 'assignfeedback_file')); 656 $o .= $renderer->render($header); 657 $o .= $renderer->render(new assign_form('uploadfeedbackzip', $mform)); 658 $o .= $renderer->render_footer(); 659 } 660 661 return $o; 662 } 663 664 /** 665 * Called by the assignment module when someone chooses something from the 666 * grading navigation or batch operations list. 667 * 668 * @param string $action - The page to view 669 * @return string - The html response 670 */ 671 public function view_page($action) { 672 if ($action == 'uploadfiles') { 673 $users = required_param('selectedusers', PARAM_SEQUENCE); 674 return $this->view_batch_upload_files(explode(',', $users)); 675 } 676 if ($action == 'uploadzip') { 677 return $this->view_upload_zip(); 678 } 679 680 return ''; 681 } 682 683 /** 684 * Return a list of the grading actions performed by this plugin. 685 * This plugin supports upload zip. 686 * 687 * @return array The list of grading actions 688 */ 689 public function get_grading_actions() { 690 return array('uploadzip'=>get_string('uploadzip', 'assignfeedback_file')); 691 } 692 693 /** 694 * Return a description of external params suitable for uploading a feedback file from a webservice. 695 * 696 * @return external_description|null 697 */ 698 public function get_external_parameters() { 699 return array( 700 'files_filemanager' => new external_value( 701 PARAM_INT, 702 'The id of a draft area containing files for this feedback.', 703 VALUE_OPTIONAL 704 ) 705 ); 706 } 707 708 /** 709 * Return the plugin configs for external functions. 710 * 711 * @return array the list of settings 712 * @since Moodle 3.2 713 */ 714 public function get_config_for_external() { 715 return (array) $this->get_config(); 716 } 717 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body