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