See Release Notes
Long Term Support Release
Differences Between: [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 submission plugin 19 * 20 * This class provides all the functionality for the new assign module. 21 * 22 * @package assignsubmission_file 23 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 // File areas for file submission assignment. 30 define('ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES', 5); 31 define('ASSIGNSUBMISSION_FILE_FILEAREA', 'submission_files'); 32 33 /** 34 * Library class for file submission plugin extending submission plugin base class 35 * 36 * @package assignsubmission_file 37 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class assign_submission_file extends assign_submission_plugin { 41 42 /** 43 * Get the name of the file submission plugin 44 * @return string 45 */ 46 public function get_name() { 47 return get_string('file', 'assignsubmission_file'); 48 } 49 50 /** 51 * Get file submission information from the database 52 * 53 * @param int $submissionid 54 * @return mixed 55 */ 56 private function get_file_submission($submissionid) { 57 global $DB; 58 return $DB->get_record('assignsubmission_file', array('submission'=>$submissionid)); 59 } 60 61 /** 62 * Get the default setting for file submission plugin 63 * 64 * @param MoodleQuickForm $mform The form to add elements to 65 * @return void 66 */ 67 public function get_settings(MoodleQuickForm $mform) { 68 global $CFG, $COURSE; 69 70 if ($this->assignment->has_instance()) { 71 $defaultmaxfilesubmissions = $this->get_config('maxfilesubmissions'); 72 $defaultmaxsubmissionsizebytes = $this->get_config('maxsubmissionsizebytes'); 73 $defaultfiletypes = $this->get_config('filetypeslist'); 74 } else { 75 $defaultmaxfilesubmissions = get_config('assignsubmission_file', 'maxfiles'); 76 $defaultmaxsubmissionsizebytes = get_config('assignsubmission_file', 'maxbytes'); 77 $defaultfiletypes = get_config('assignsubmission_file', 'filetypes'); 78 } 79 $defaultfiletypes = (string)$defaultfiletypes; 80 81 $settings = array(); 82 $options = array(); 83 for ($i = 1; $i <= get_config('assignsubmission_file', 'maxfiles'); $i++) { 84 $options[$i] = $i; 85 } 86 87 $name = get_string('maxfilessubmission', 'assignsubmission_file'); 88 $mform->addElement('select', 'assignsubmission_file_maxfiles', $name, $options); 89 $mform->addHelpButton('assignsubmission_file_maxfiles', 90 'maxfilessubmission', 91 'assignsubmission_file'); 92 $mform->setDefault('assignsubmission_file_maxfiles', $defaultmaxfilesubmissions); 93 $mform->hideIf('assignsubmission_file_maxfiles', 'assignsubmission_file_enabled', 'notchecked'); 94 95 $choices = get_max_upload_sizes($CFG->maxbytes, 96 $COURSE->maxbytes, 97 get_config('assignsubmission_file', 'maxbytes')); 98 99 $settings[] = array('type' => 'select', 100 'name' => 'maxsubmissionsizebytes', 101 'description' => get_string('maximumsubmissionsize', 'assignsubmission_file'), 102 'options'=> $choices, 103 'default'=> $defaultmaxsubmissionsizebytes); 104 105 $name = get_string('maximumsubmissionsize', 'assignsubmission_file'); 106 $mform->addElement('select', 'assignsubmission_file_maxsizebytes', $name, $choices); 107 $mform->addHelpButton('assignsubmission_file_maxsizebytes', 108 'maximumsubmissionsize', 109 'assignsubmission_file'); 110 $mform->setDefault('assignsubmission_file_maxsizebytes', $defaultmaxsubmissionsizebytes); 111 $mform->hideIf('assignsubmission_file_maxsizebytes', 112 'assignsubmission_file_enabled', 113 'notchecked'); 114 115 $name = get_string('acceptedfiletypes', 'assignsubmission_file'); 116 $mform->addElement('filetypes', 'assignsubmission_file_filetypes', $name); 117 $mform->addHelpButton('assignsubmission_file_filetypes', 'acceptedfiletypes', 'assignsubmission_file'); 118 $mform->setDefault('assignsubmission_file_filetypes', $defaultfiletypes); 119 $mform->hideIf('assignsubmission_file_filetypes', 'assignsubmission_file_enabled', 'notchecked'); 120 } 121 122 /** 123 * Save the settings for file submission plugin 124 * 125 * @param stdClass $data 126 * @return bool 127 */ 128 public function save_settings(stdClass $data) { 129 $this->set_config('maxfilesubmissions', $data->assignsubmission_file_maxfiles); 130 $this->set_config('maxsubmissionsizebytes', $data->assignsubmission_file_maxsizebytes); 131 132 if (!empty($data->assignsubmission_file_filetypes)) { 133 $this->set_config('filetypeslist', $data->assignsubmission_file_filetypes); 134 } else { 135 $this->set_config('filetypeslist', ''); 136 } 137 138 return true; 139 } 140 141 /** 142 * File format options 143 * 144 * @return array 145 */ 146 private function get_file_options() { 147 $fileoptions = array('subdirs' => 1, 148 'maxbytes' => $this->get_config('maxsubmissionsizebytes'), 149 'maxfiles' => $this->get_config('maxfilesubmissions'), 150 'accepted_types' => $this->get_configured_typesets(), 151 'return_types' => (FILE_INTERNAL | FILE_CONTROLLED_LINK)); 152 if ($fileoptions['maxbytes'] == 0) { 153 // Use module default. 154 $fileoptions['maxbytes'] = get_config('assignsubmission_file', 'maxbytes'); 155 } 156 return $fileoptions; 157 } 158 159 /** 160 * Add elements to submission form 161 * 162 * @param mixed $submission stdClass|null 163 * @param MoodleQuickForm $mform 164 * @param stdClass $data 165 * @return bool 166 */ 167 public function get_form_elements($submission, MoodleQuickForm $mform, stdClass $data) { 168 global $OUTPUT; 169 170 if ($this->get_config('maxfilesubmissions') <= 0) { 171 return false; 172 } 173 174 $fileoptions = $this->get_file_options(); 175 $submissionid = $submission ? $submission->id : 0; 176 177 $data = file_prepare_standard_filemanager($data, 178 'files', 179 $fileoptions, 180 $this->assignment->get_context(), 181 'assignsubmission_file', 182 ASSIGNSUBMISSION_FILE_FILEAREA, 183 $submissionid); 184 $mform->addElement('filemanager', 'files_filemanager', $this->get_name(), null, $fileoptions); 185 186 return true; 187 } 188 189 /** 190 * Count the number of files 191 * 192 * @param int $submissionid 193 * @param string $area 194 * @return int 195 */ 196 private function count_files($submissionid, $area) { 197 $fs = get_file_storage(); 198 $files = $fs->get_area_files($this->assignment->get_context()->id, 199 'assignsubmission_file', 200 $area, 201 $submissionid, 202 'id', 203 false); 204 205 return count($files); 206 } 207 208 /** 209 * Save the files and trigger plagiarism plugin, if enabled, 210 * to scan the uploaded files via events trigger 211 * 212 * @param stdClass $submission 213 * @param stdClass $data 214 * @return bool 215 */ 216 public function save(stdClass $submission, stdClass $data) { 217 global $USER, $DB; 218 219 $fileoptions = $this->get_file_options(); 220 221 $data = file_postupdate_standard_filemanager($data, 222 'files', 223 $fileoptions, 224 $this->assignment->get_context(), 225 'assignsubmission_file', 226 ASSIGNSUBMISSION_FILE_FILEAREA, 227 $submission->id); 228 229 $filesubmission = $this->get_file_submission($submission->id); 230 231 // Plagiarism code event trigger when files are uploaded. 232 233 $fs = get_file_storage(); 234 $files = $fs->get_area_files($this->assignment->get_context()->id, 235 'assignsubmission_file', 236 ASSIGNSUBMISSION_FILE_FILEAREA, 237 $submission->id, 238 'id', 239 false); 240 241 $count = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); 242 243 $params = array( 244 'context' => context_module::instance($this->assignment->get_course_module()->id), 245 'courseid' => $this->assignment->get_course()->id, 246 'objectid' => $submission->id, 247 'other' => array( 248 'content' => '', 249 'pathnamehashes' => array_keys($files) 250 ) 251 ); 252 if (!empty($submission->userid) && ($submission->userid != $USER->id)) { 253 $params['relateduserid'] = $submission->userid; 254 } 255 if ($this->assignment->is_blind_marking()) { 256 $params['anonymous'] = 1; 257 } 258 $event = \assignsubmission_file\event\assessable_uploaded::create($params); 259 $event->set_legacy_files($files); 260 $event->trigger(); 261 262 $groupname = null; 263 $groupid = 0; 264 // Get the group name as other fields are not transcribed in the logs and this information is important. 265 if (empty($submission->userid) && !empty($submission->groupid)) { 266 $groupname = $DB->get_field('groups', 'name', array('id' => $submission->groupid), MUST_EXIST); 267 $groupid = $submission->groupid; 268 } else { 269 $params['relateduserid'] = $submission->userid; 270 } 271 272 // Unset the objectid and other field from params for use in submission events. 273 unset($params['objectid']); 274 unset($params['other']); 275 $params['other'] = array( 276 'submissionid' => $submission->id, 277 'submissionattempt' => $submission->attemptnumber, 278 'submissionstatus' => $submission->status, 279 'filesubmissioncount' => $count, 280 'groupid' => $groupid, 281 'groupname' => $groupname 282 ); 283 284 if ($filesubmission) { 285 $filesubmission->numfiles = $this->count_files($submission->id, 286 ASSIGNSUBMISSION_FILE_FILEAREA); 287 $updatestatus = $DB->update_record('assignsubmission_file', $filesubmission); 288 $params['objectid'] = $filesubmission->id; 289 290 $event = \assignsubmission_file\event\submission_updated::create($params); 291 $event->set_assign($this->assignment); 292 $event->trigger(); 293 return $updatestatus; 294 } else { 295 $filesubmission = new stdClass(); 296 $filesubmission->numfiles = $this->count_files($submission->id, 297 ASSIGNSUBMISSION_FILE_FILEAREA); 298 $filesubmission->submission = $submission->id; 299 $filesubmission->assignment = $this->assignment->get_instance()->id; 300 $filesubmission->id = $DB->insert_record('assignsubmission_file', $filesubmission); 301 $params['objectid'] = $filesubmission->id; 302 303 $event = \assignsubmission_file\event\submission_created::create($params); 304 $event->set_assign($this->assignment); 305 $event->trigger(); 306 return $filesubmission->id > 0; 307 } 308 } 309 310 /** 311 * Remove files from this submission. 312 * 313 * @param stdClass $submission The submission 314 * @return boolean 315 */ 316 public function remove(stdClass $submission) { 317 global $DB; 318 $fs = get_file_storage(); 319 320 $fs->delete_area_files($this->assignment->get_context()->id, 321 'assignsubmission_file', 322 ASSIGNSUBMISSION_FILE_FILEAREA, 323 $submission->id); 324 325 $currentsubmission = $this->get_file_submission($submission->id); 326 if ($currentsubmission) { 327 $currentsubmission->numfiles = 0; 328 $DB->update_record('assignsubmission_file', $currentsubmission); 329 } 330 331 return true; 332 } 333 334 /** 335 * Produce a list of files suitable for export that represent this feedback or submission 336 * 337 * @param stdClass $submission The submission 338 * @param stdClass $user The user record - unused 339 * @return array - return an array of files indexed by filename 340 */ 341 public function get_files(stdClass $submission, stdClass $user) { 342 $result = array(); 343 $fs = get_file_storage(); 344 345 $files = $fs->get_area_files($this->assignment->get_context()->id, 346 'assignsubmission_file', 347 ASSIGNSUBMISSION_FILE_FILEAREA, 348 $submission->id, 349 'timemodified', 350 false); 351 352 foreach ($files as $file) { 353 // Do we return the full folder path or just the file name? 354 if (isset($submission->exportfullpath) && $submission->exportfullpath == false) { 355 $result[$file->get_filename()] = $file; 356 } else { 357 $result[$file->get_filepath().$file->get_filename()] = $file; 358 } 359 } 360 return $result; 361 } 362 363 /** 364 * Display the list of files in the submission status table 365 * 366 * @param stdClass $submission 367 * @param bool $showviewlink Set this to true if the list of files is long 368 * @return string 369 */ 370 public function view_summary(stdClass $submission, & $showviewlink) { 371 $count = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); 372 373 // Show we show a link to view all files for this plugin? 374 $showviewlink = $count > ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES; 375 if ($count <= ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES) { 376 return $this->assignment->render_area_files('assignsubmission_file', 377 ASSIGNSUBMISSION_FILE_FILEAREA, 378 $submission->id); 379 } else { 380 return get_string('countfiles', 'assignsubmission_file', $count); 381 } 382 } 383 384 /** 385 * No full submission view - the summary contains the list of files and that is the whole submission 386 * 387 * @param stdClass $submission 388 * @return string 389 */ 390 public function view(stdClass $submission) { 391 return $this->assignment->render_area_files('assignsubmission_file', 392 ASSIGNSUBMISSION_FILE_FILEAREA, 393 $submission->id); 394 } 395 396 397 398 /** 399 * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type 400 * and version. 401 * 402 * @param string $type 403 * @param int $version 404 * @return bool True if upgrade is possible 405 */ 406 public function can_upgrade($type, $version) { 407 408 $uploadsingletype ='uploadsingle'; 409 $uploadtype ='upload'; 410 411 if (($type == $uploadsingletype || $type == $uploadtype) && $version >= 2011112900) { 412 return true; 413 } 414 return false; 415 } 416 417 418 /** 419 * Upgrade the settings from the old assignment 420 * to the new plugin based one 421 * 422 * @param context $oldcontext - the old assignment context 423 * @param stdClass $oldassignment - the old assignment data record 424 * @param string $log record log events here 425 * @return bool Was it a success? (false will trigger rollback) 426 */ 427 public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) { 428 global $DB; 429 430 if ($oldassignment->assignmenttype == 'uploadsingle') { 431 $this->set_config('maxfilesubmissions', 1); 432 $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes); 433 return true; 434 } else if ($oldassignment->assignmenttype == 'upload') { 435 $this->set_config('maxfilesubmissions', $oldassignment->var1); 436 $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes); 437 438 // Advanced file upload uses a different setting to do the same thing. 439 $DB->set_field('assign', 440 'submissiondrafts', 441 $oldassignment->var4, 442 array('id'=>$this->assignment->get_instance()->id)); 443 444 // Convert advanced file upload "hide description before due date" setting. 445 $alwaysshow = 0; 446 if (!$oldassignment->var3) { 447 $alwaysshow = 1; 448 } 449 $DB->set_field('assign', 450 'alwaysshowdescription', 451 $alwaysshow, 452 array('id'=>$this->assignment->get_instance()->id)); 453 return true; 454 } 455 } 456 457 /** 458 * Upgrade the submission from the old assignment to the new one 459 * 460 * @param context $oldcontext The context of the old assignment 461 * @param stdClass $oldassignment The data record for the old oldassignment 462 * @param stdClass $oldsubmission The data record for the old submission 463 * @param stdClass $submission The data record for the new submission 464 * @param string $log Record upgrade messages in the log 465 * @return bool true or false - false will trigger a rollback 466 */ 467 public function upgrade(context $oldcontext, 468 stdClass $oldassignment, 469 stdClass $oldsubmission, 470 stdClass $submission, 471 & $log) { 472 global $DB; 473 474 $filesubmission = new stdClass(); 475 476 $filesubmission->numfiles = $oldsubmission->numfiles; 477 $filesubmission->submission = $submission->id; 478 $filesubmission->assignment = $this->assignment->get_instance()->id; 479 480 if (!$DB->insert_record('assignsubmission_file', $filesubmission) > 0) { 481 $log .= get_string('couldnotconvertsubmission', 'mod_assign', $submission->userid); 482 return false; 483 } 484 485 // Now copy the area files. 486 $this->assignment->copy_area_files_for_upgrade($oldcontext->id, 487 'mod_assignment', 488 'submission', 489 $oldsubmission->id, 490 $this->assignment->get_context()->id, 491 'assignsubmission_file', 492 ASSIGNSUBMISSION_FILE_FILEAREA, 493 $submission->id); 494 495 return true; 496 } 497 498 /** 499 * The assignment has been deleted - cleanup 500 * 501 * @return bool 502 */ 503 public function delete_instance() { 504 global $DB; 505 // Will throw exception on failure. 506 $DB->delete_records('assignsubmission_file', 507 array('assignment'=>$this->assignment->get_instance()->id)); 508 509 return true; 510 } 511 512 /** 513 * Formatting for log info 514 * 515 * @param stdClass $submission The submission 516 * @return string 517 */ 518 public function format_for_log(stdClass $submission) { 519 // Format the info for each submission plugin (will be added to log). 520 $filecount = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); 521 522 return get_string('numfilesforlog', 'assignsubmission_file', $filecount); 523 } 524 525 /** 526 * Return true if there are no submission files 527 * @param stdClass $submission 528 */ 529 public function is_empty(stdClass $submission) { 530 return $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA) == 0; 531 } 532 533 /** 534 * Determine if a submission is empty 535 * 536 * This is distinct from is_empty in that it is intended to be used to 537 * determine if a submission made before saving is empty. 538 * 539 * @param stdClass $data The submission data 540 * @return bool 541 */ 542 public function submission_is_empty(stdClass $data) { 543 global $USER; 544 $fs = get_file_storage(); 545 // Get a count of all the draft files, excluding any directories. 546 $files = $fs->get_area_files(context_user::instance($USER->id)->id, 547 'user', 548 'draft', 549 $data->files_filemanager, 550 'id', 551 false); 552 return count($files) == 0; 553 } 554 555 /** 556 * Get file areas returns a list of areas this plugin stores files 557 * @return array - An array of fileareas (keys) and descriptions (values) 558 */ 559 public function get_file_areas() { 560 return array(ASSIGNSUBMISSION_FILE_FILEAREA=>$this->get_name()); 561 } 562 563 /** 564 * Copy the student's submission from a previous submission. Used when a student opts to base their resubmission 565 * on the last submission. 566 * @param stdClass $sourcesubmission 567 * @param stdClass $destsubmission 568 */ 569 public function copy_submission(stdClass $sourcesubmission, stdClass $destsubmission) { 570 global $DB; 571 572 // Copy the files across. 573 $contextid = $this->assignment->get_context()->id; 574 $fs = get_file_storage(); 575 $files = $fs->get_area_files($contextid, 576 'assignsubmission_file', 577 ASSIGNSUBMISSION_FILE_FILEAREA, 578 $sourcesubmission->id, 579 'id', 580 false); 581 foreach ($files as $file) { 582 $fieldupdates = array('itemid' => $destsubmission->id); 583 $fs->create_file_from_storedfile($fieldupdates, $file); 584 } 585 586 // Copy the assignsubmission_file record. 587 if ($filesubmission = $this->get_file_submission($sourcesubmission->id)) { 588 unset($filesubmission->id); 589 $filesubmission->submission = $destsubmission->id; 590 $DB->insert_record('assignsubmission_file', $filesubmission); 591 } 592 return true; 593 } 594 595 /** 596 * Return a description of external params suitable for uploading a file submission from a webservice. 597 * 598 * @return external_description|null 599 */ 600 public function get_external_parameters() { 601 return array( 602 'files_filemanager' => new external_value( 603 PARAM_INT, 604 'The id of a draft area containing files for this submission.', 605 VALUE_OPTIONAL 606 ) 607 ); 608 } 609 610 /** 611 * Return the plugin configs for external functions. 612 * 613 * @return array the list of settings 614 * @since Moodle 3.2 615 */ 616 public function get_config_for_external() { 617 global $CFG; 618 619 $configs = $this->get_config(); 620 621 // Get a size in bytes. 622 if ($configs->maxsubmissionsizebytes == 0) { 623 $configs->maxsubmissionsizebytes = get_max_upload_file_size($CFG->maxbytes, $this->assignment->get_course()->maxbytes, 624 get_config('assignsubmission_file', 'maxbytes')); 625 } 626 return (array) $configs; 627 } 628 629 /** 630 * Get the type sets configured for this assignment. 631 * 632 * @return array('groupname', 'mime/type', ...) 633 */ 634 private function get_configured_typesets() { 635 $typeslist = (string)$this->get_config('filetypeslist'); 636 637 $util = new \core_form\filetypes_util(); 638 $sets = $util->normalize_file_types($typeslist); 639 640 return $sets; 641 } 642 643 /** 644 * Determine if the plugin allows image file conversion 645 * @return bool 646 */ 647 public function allow_image_conversion() { 648 return true; 649 } 650 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body