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