Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** This file contains the definition for the library class for file feedback plugin*** @package assignfeedback_file* @copyright 2012 NetSpot {@link http://www.netspot.com.au}* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/defined('MOODLE_INTERNAL') || die();use mod_assign\output\assign_header;use core_external\external_value;// File areas for file feedback assignment.define('ASSIGNFEEDBACK_FILE_FILEAREA', 'feedback_files');define('ASSIGNFEEDBACK_FILE_BATCH_FILEAREA', 'feedback_files_batch');define('ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA', 'feedback_files_import');define('ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES', 5);define('ASSIGNFEEDBACK_FILE_MAXSUMMARYUSERS', 5);define('ASSIGNFEEDBACK_FILE_MAXFILEUNZIPTIME', 120);/*** Library class for file feedback plugin extending feedback plugin base class.** @package assignfeedback_file* @copyright 2012 NetSpot {@link http://www.netspot.com.au}* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class assign_feedback_file extends assign_feedback_plugin {/*** Get the name of the file feedback plugin.** @return string*/public function get_name() {return get_string('file', 'assignfeedback_file');}/*** Get file feedback information from the database.** @param int $gradeid* @return mixed*/public function get_file_feedback($gradeid) {global $DB;return $DB->get_record('assignfeedback_file', array('grade'=>$gradeid));}/*** File format options.** @return array*/private function get_file_options() {global $COURSE;$fileoptions = array('subdirs'=>1,'maxbytes'=>$COURSE->maxbytes,'accepted_types'=>'*','return_types'=>FILE_INTERNAL);return $fileoptions;}/*** Has the feedback file been modified?** @param stdClass $grade Grade object.* @param stdClass $data Form data.* @return boolean True if the file area has been modified, else false.*/public function is_feedback_modified(stdClass $grade, stdClass $data) {global $USER;$filekey = null;$draftareainfo = null;foreach ($data as $key => $value) {if (strpos($key, 'files_') === 0 && strpos($key, '_filemanager')) {$filekey = $key;}}if (isset($filekey)) {$draftareainfo = file_get_draft_area_info($data->$filekey);$filecount = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA);if ($filecount != $draftareainfo['filecount']) {return true;} else {// We need to check that the files in the draft area are the same as in the file area.$usercontext = context_user::instance($USER->id);$fs = get_file_storage();$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $data->$filekey, 'id', true);$files = $fs->get_area_files($this->assignment->get_context()->id,'assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$grade->id,'id',false);foreach ($files as $key => $file) {// Flag for recording if we have a matching file.$matchflag = false;foreach ($draftfiles as $draftkey => $draftfile) {if (!$file->is_directory()) {// File name is the same, but it could be a different file with the same name.if ($draftfile->get_filename() == $file->get_filename()) {// If the file name is the same but the content hash is different, or// The file path for the file has changed, then we have a modification.if ($draftfile->get_contenthash() != $file->get_contenthash() ||$draftfile->get_filepath() != $file->get_filepath()) {return true;}// These files match. Check the next file.$matchflag = true;// We have a match on the file name so we can move to the next file and not// proceed through the other draftfiles.break;}}}// If the file does not match then there has been a modification.if (!$matchflag) {return true;}}}}return false;}/*** Copy all the files from one file area to another.** @param file_storage $fs - The source context id* @param int $fromcontextid - The source context id* @param string $fromcomponent - The source component* @param string $fromfilearea - The source filearea* @param int $fromitemid - The source item id* @param int $tocontextid - The destination context id* @param string $tocomponent - The destination component* @param string $tofilearea - The destination filearea* @param int $toitemid - The destination item id* @return boolean*/private function copy_area_files(file_storage $fs,$fromcontextid,$fromcomponent,$fromfilearea,$fromitemid,$tocontextid,$tocomponent,$tofilearea,$toitemid) {$newfilerecord = new stdClass();$newfilerecord->contextid = $tocontextid;$newfilerecord->component = $tocomponent;$newfilerecord->filearea = $tofilearea;$newfilerecord->itemid = $toitemid;if ($files = $fs->get_area_files($fromcontextid, $fromcomponent, $fromfilearea, $fromitemid)) {foreach ($files as $file) {if ($file->is_directory() and $file->get_filepath() === '/') {// We need a way to mark the age of each draft area.// By not copying the root dir we force it to be created// automatically with current timestamp.continue;}$existingfile = $fs->get_file($newfilerecord->contextid,$newfilerecord->component,$newfilerecord->filearea,$newfilerecord->itemid,$file->get_filepath(),$file->get_filename());if ($existingfile) {// If the file already exists, remove it so it can be updated.$existingfile->delete();}$newfile = $fs->create_file_from_storedfile($newfilerecord, $file);}}return true;}/*** Get form elements for grading form.** @param stdClass $grade* @param MoodleQuickForm $mform* @param stdClass $data* @param int $userid The userid we are currently grading* @return bool true if elements were added to the form*/public function get_form_elements_for_user($grade, MoodleQuickForm $mform, stdClass $data, $userid) {$fileoptions = $this->get_file_options();$gradeid = $grade ? $grade->id : 0;$elementname = 'files_' . $userid;$data = file_prepare_standard_filemanager($data,$elementname,$fileoptions,$this->assignment->get_context(),'assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$gradeid);$mform->addElement('filemanager', $elementname . '_filemanager', $this->get_name(), null, $fileoptions);return true;}/*** Count the number of files.** @param int $gradeid* @param string $area* @return int*/private function count_files($gradeid, $area) {$fs = get_file_storage();$files = $fs->get_area_files($this->assignment->get_context()->id,'assignfeedback_file',$area,$gradeid,'id',false);return count($files);}/*** Update the number of files in the file area.** @param stdClass $grade The grade record* @return bool - true if the value was saved*/public function update_file_count($grade) {global $DB;$filefeedback = $this->get_file_feedback($grade->id);if ($filefeedback) {$filefeedback->numfiles = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA);return $DB->update_record('assignfeedback_file', $filefeedback);} else {$filefeedback = new stdClass();$filefeedback->numfiles = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA);$filefeedback->grade = $grade->id;$filefeedback->assignment = $this->assignment->get_instance()->id;return $DB->insert_record('assignfeedback_file', $filefeedback) > 0;}}/*** Save the feedback files.** @param stdClass $grade* @param stdClass $data* @return bool*/public function save(stdClass $grade, stdClass $data) {$fileoptions = $this->get_file_options();// The element name may have been for a different user.foreach ($data as $key => $value) {if (strpos($key, 'files_') === 0 && strpos($key, '_filemanager')) {$elementname = substr($key, 0, strpos($key, '_filemanager'));}}$data = file_postupdate_standard_filemanager($data,$elementname,$fileoptions,$this->assignment->get_context(),'assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$grade->id);return $this->update_file_count($grade);}/*** Display the list of files in the feedback status table.** @param stdClass $grade* @param bool $showviewlink - Set to true to show a link to see the full list of files* @return string*/public function view_summary(stdClass $grade, & $showviewlink) {$count = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA);// Show a view all link if the number of files is over this limit.$showviewlink = $count > ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES;if ($count <= ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES) {return $this->assignment->render_area_files('assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$grade->id);} else {return get_string('countfiles', 'assignfeedback_file', $count);}}/*** Display the list of files in the feedback status table.** @param stdClass $grade* @return string*/public function view(stdClass $grade) {return $this->assignment->render_area_files('assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$grade->id);}/*** The assignment has been deleted - cleanup.** @return bool*/public function delete_instance() {global $DB;// Will throw exception on failure.$DB->delete_records('assignfeedback_file',array('assignment'=>$this->assignment->get_instance()->id));return true;}/*** Return true if there are no feedback files.** @param stdClass $grade*/public function is_empty(stdClass $grade) {return $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA) == 0;}/*** Get file areas returns a list of areas this plugin stores files.** @return array - An array of fileareas (keys) and descriptions (values)*/public function get_file_areas() {return array(ASSIGNFEEDBACK_FILE_FILEAREA=>$this->get_name());}/*** Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type* and version.** @param string $type old assignment subtype* @param int $version old assignment version* @return bool True if upgrade is possible*/public function can_upgrade($type, $version) {if (($type == 'upload' || $type == 'uploadsingle') && $version >= 2011112900) {return true;}return false;}/*** Upgrade the settings from the old assignment to the new plugin based one.** @param context $oldcontext - the context for the old assignment* @param stdClass $oldassignment - the data for the old assignment* @param string $log - can be appended to by the upgrade* @return bool was it a success? (false will trigger a rollback)*/public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) {// First upgrade settings (nothing to do).return true;}/*** Upgrade the feedback from the old assignment to the new one.** @param context $oldcontext - the database for the old assignment context* @param stdClass $oldassignment The data record for the old assignment* @param stdClass $oldsubmission The data record for the old submission* @param stdClass $grade The data record for the new grade* @param string $log Record upgrade messages in the log* @return bool true or false - false will trigger a rollback*/public function upgrade(context $oldcontext,stdClass $oldassignment,stdClass $oldsubmission,stdClass $grade,& $log) {global $DB;// Now copy the area files.$this->assignment->copy_area_files_for_upgrade($oldcontext->id,'mod_assignment','response',$oldsubmission->id,$this->assignment->get_context()->id,'assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$grade->id);// Now count them!$filefeedback = new stdClass();$filefeedback->numfiles = $this->count_files($grade->id, ASSIGNFEEDBACK_FILE_FILEAREA);$filefeedback->grade = $grade->id;$filefeedback->assignment = $this->assignment->get_instance()->id;if (!$DB->insert_record('assignfeedback_file', $filefeedback) > 0) {$log .= get_string('couldnotconvertgrade', 'mod_assign', $grade->userid);return false;}return true;}/*** Return a list of the batch grading operations performed by this plugin.* This plugin supports batch upload files and upload zip.** @return array The list of batch grading operations*/public function get_grading_batch_operations() {return array('uploadfiles'=>get_string('uploadfiles', 'assignfeedback_file'));}/*** Upload files and send them to multiple users.** @param array $users - An array of user ids* @return string - The response html*/public function view_batch_upload_files($users) {global $CFG, $DB, $USER;require_capability('mod/assign:grade', $this->assignment->get_context());require_once($CFG->dirroot . '/mod/assign/feedback/file/batchuploadfilesform.php');require_once($CFG->dirroot . '/mod/assign/renderable.php');$formparams = array('cm'=>$this->assignment->get_course_module()->id,'users'=>$users,'context'=>$this->assignment->get_context());$usershtml = '';$usercount = 0;foreach ($users as $userid) {if ($usercount >= ASSIGNFEEDBACK_FILE_MAXSUMMARYUSERS) {$moreuserscount = count($users) - ASSIGNFEEDBACK_FILE_MAXSUMMARYUSERS;$usershtml .= get_string('moreusers', 'assignfeedback_file', $moreuserscount);break;}$user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);$usersummary = new assign_user_summary($user,$this->assignment->get_course()->id,has_capability('moodle/site:viewfullnames',$this->assignment->get_course_context()),$this->assignment->is_blind_marking(),$this->assignment->get_uniqueid_for_user($user->id),// TODO Does not support custom user profile fields (MDL-70456).\core_user\fields::get_identity_fields($this->assignment->get_context(), false));$usershtml .= $this->assignment->get_renderer()->render($usersummary);$usercount += 1;}$formparams['usershtml'] = $usershtml;$mform = new assignfeedback_file_batch_upload_files_form(null, $formparams);if ($mform->is_cancelled()) {redirect(new moodle_url('view.php',array('id'=>$this->assignment->get_course_module()->id,'action'=>'grading')));return;} else if ($data = $mform->get_data()) {// Copy the files from the draft area to a temporary import area.$data = file_postupdate_standard_filemanager($data,'files',$this->get_file_options(),$this->assignment->get_context(),'assignfeedback_file',ASSIGNFEEDBACK_FILE_BATCH_FILEAREA,$USER->id);$fs = get_file_storage();// Now copy each of these files to the users feedback file area.foreach ($users as $userid) {$grade = $this->assignment->get_user_grade($userid, true);$this->assignment->notify_grade_modified($grade);$this->copy_area_files($fs,$this->assignment->get_context()->id,'assignfeedback_file',ASSIGNFEEDBACK_FILE_BATCH_FILEAREA,$USER->id,$this->assignment->get_context()->id,'assignfeedback_file',ASSIGNFEEDBACK_FILE_FILEAREA,$grade->id);$filefeedback = $this->get_file_feedback($grade->id);if ($filefeedback) {$filefeedback->numfiles = $this->count_files($grade->id,ASSIGNFEEDBACK_FILE_FILEAREA);$DB->update_record('assignfeedback_file', $filefeedback);} else {$filefeedback = new stdClass();$filefeedback->numfiles = $this->count_files($grade->id,ASSIGNFEEDBACK_FILE_FILEAREA);$filefeedback->grade = $grade->id;$filefeedback->assignment = $this->assignment->get_instance()->id;$DB->insert_record('assignfeedback_file', $filefeedback);}}// Now delete the temporary import area.$fs->delete_area_files($this->assignment->get_context()->id,'assignfeedback_file',ASSIGNFEEDBACK_FILE_BATCH_FILEAREA,$USER->id);redirect(new moodle_url('view.php',array('id'=>$this->assignment->get_course_module()->id,'action'=>'grading')));return;} else {$header = new assign_header($this->assignment->get_instance(),$this->assignment->get_context(),false,$this->assignment->get_course_module()->id,get_string('batchuploadfiles', 'assignfeedback_file'));$o = '';$o .= $this->assignment->get_renderer()->render($header);$o .= $this->assignment->get_renderer()->render(new assign_form('batchuploadfiles', $mform));$o .= $this->assignment->get_renderer()->render_footer();}return $o;}/*** User has chosen a custom grading batch operation and selected some users.** @param string $action - The chosen action* @param array $users - An array of user ids* @return string - The response html*/public function grading_batch_operation($action, $users) {if ($action == 'uploadfiles') {return $this->view_batch_upload_files($users);}return '';}/*** View the upload zip form.** @return string - The html response*/public function view_upload_zip() {global $CFG, $USER;require_capability('mod/assign:grade', $this->assignment->get_context());require_once($CFG->dirroot . '/mod/assign/feedback/file/uploadzipform.php');require_once($CFG->dirroot . '/mod/assign/feedback/file/importziplib.php');require_once($CFG->dirroot . '/mod/assign/feedback/file/importzipform.php');$formparams = array('context'=>$this->assignment->get_context(),'cm'=>$this->assignment->get_course_module()->id);$mform = new assignfeedback_file_upload_zip_form(null, $formparams);$o = '';$confirm = optional_param('confirm', 0, PARAM_BOOL);$renderer = $this->assignment->get_renderer();// Delete any existing files.$importer = new assignfeedback_file_zip_importer();$contextid = $this->assignment->get_context()->id;if ($mform->is_cancelled()) {$importer->delete_import_files($contextid);$urlparams = array('id'=>$this->assignment->get_course_module()->id,'action'=>'grading');$url = new moodle_url('view.php', $urlparams);redirect($url);return;} else if ($confirm) {$params = array('assignment'=>$this->assignment, 'importer'=>$importer);$mform = new assignfeedback_file_import_zip_form(null, $params);if ($mform->is_cancelled()) {$importer->delete_import_files($contextid);$urlparams = array('id'=>$this->assignment->get_course_module()->id,'action'=>'grading');$url = new moodle_url('view.php', $urlparams);redirect($url);return;}$o .= $importer->import_zip_files($this->assignment, $this);$importer->delete_import_files($contextid);} else if (($data = $mform->get_data()) &&($zipfile = $mform->save_stored_file('feedbackzip',$contextid,'assignfeedback_file',ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA,$USER->id,'/','import.zip',true))) {$importer->extract_files_from_zip($zipfile, $contextid);$params = array('assignment'=>$this->assignment, 'importer'=>$importer);$mform = new assignfeedback_file_import_zip_form(null, $params);$header = new assign_header($this->assignment->get_instance(),$this->assignment->get_context(),false,$this->assignment->get_course_module()->id,get_string('confirmuploadzip', 'assignfeedback_file'));$o .= $renderer->render($header);$o .= $renderer->render(new assign_form('confirmimportzip', $mform));$o .= $renderer->render_footer();} else {$header = new assign_header($this->assignment->get_instance(),$this->assignment->get_context(),false,$this->assignment->get_course_module()->id,get_string('uploadzip', 'assignfeedback_file'));$o .= $renderer->render($header);$o .= $renderer->render(new assign_form('uploadfeedbackzip', $mform));$o .= $renderer->render_footer();}return $o;}/*** Called by the assignment module when someone chooses something from the* grading navigation or batch operations list.** @param string $action - The page to view* @return string - The html response*/public function view_page($action) {if ($action == 'uploadfiles') {$users = required_param('selectedusers', PARAM_SEQUENCE);return $this->view_batch_upload_files(explode(',', $users));}if ($action == 'uploadzip') {return $this->view_upload_zip();}return '';}/*** Return a list of the grading actions performed by this plugin.* This plugin supports upload zip.** @return array The list of grading actions*/public function get_grading_actions() {return array('uploadzip'=>get_string('uploadzip', 'assignfeedback_file'));}/*** Return a description of external params suitable for uploading a feedback file from a webservice.** @return \core_external\external_description|null*/public function get_external_parameters() {return array('files_filemanager' => new external_value(PARAM_INT,'The id of a draft area containing files for this feedback.',VALUE_OPTIONAL));}/*** Return the plugin configs for external functions.** @return array the list of settings* @since Moodle 3.2*/public function get_config_for_external() {return (array) $this->get_config();}}