See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
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_offline 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 require_once($CFG->dirroot.'/grade/grading/lib.php'); 31 32 /** 33 * library class for file feedback plugin extending feedback plugin base class 34 * 35 * @package assignfeedback_offline 36 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class assign_feedback_offline extends assign_feedback_plugin { 40 41 /** @var boolean|null $enabledcache Cached lookup of the is_enabled function */ 42 private $enabledcache = null; 43 44 /** 45 * Get the name of the file feedback plugin 46 * @return string 47 */ 48 public function get_name() { 49 return get_string('pluginname', 'assignfeedback_offline'); 50 } 51 52 /** 53 * Get form elements for grading form 54 * 55 * @param stdClass $grade 56 * @param MoodleQuickForm $mform 57 * @param stdClass $data 58 * @return bool true if elements were added to the form 59 */ 60 public function get_form_elements($grade, MoodleQuickForm $mform, stdClass $data) { 61 return false; 62 } 63 64 /** 65 * Return true if there are no feedback files 66 * @param stdClass $grade 67 */ 68 public function is_empty(stdClass $grade) { 69 return true; 70 } 71 72 /** 73 * This plugin does not save through the normal interface so this returns false. 74 * 75 * @param stdClass $grade The grade. 76 * @param stdClass $data Form data from the feedback form. 77 * @return boolean - False 78 */ 79 public function is_feedback_modified(stdClass $grade, stdClass $data) { 80 return false; 81 } 82 83 /** 84 * Loop through uploaded grades and update the grades for this assignment 85 * 86 * @param int $draftid - The unique draft item id for this import 87 * @param int $importid - The unique import ID for this csv import operation 88 * @param bool $ignoremodified - Ignore the last modified date when checking fields 89 * @param string $encoding - Encoding of the file being processed. 90 * @param string $separator - The character used to separate the information. 91 * @return string - The html response 92 */ 93 public function process_import_grades($draftid, $importid, $ignoremodified, $encoding = 'utf-8', $separator = 'comma') { 94 global $USER, $DB; 95 96 require_sesskey(); 97 require_capability('mod/assign:grade', $this->assignment->get_context()); 98 99 $gradeimporter = new assignfeedback_offline_grade_importer($importid, $this->assignment, $encoding, $separator); 100 101 $context = context_user::instance($USER->id); 102 $fs = get_file_storage(); 103 if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) { 104 redirect(new moodle_url('view.php', 105 array('id'=>$this->assignment->get_course_module()->id, 106 'action'=>'grading'))); 107 return; 108 } 109 $file = reset($files); 110 111 $csvdata = $file->get_content(); 112 113 if ($csvdata) { 114 $gradeimporter->parsecsv($csvdata); 115 } 116 if (!$gradeimporter->init()) { 117 $thisurl = new moodle_url('/mod/assign/view.php', array('action'=>'viewpluginpage', 118 'pluginsubtype'=>'assignfeedback', 119 'plugin'=>'offline', 120 'pluginaction'=>'uploadgrades', 121 'id' => $this->assignment->get_course_module()->id)); 122 throw new \moodle_exception('invalidgradeimport', 'assignfeedback_offline', $thisurl); 123 return; 124 } 125 // Does this assignment use a scale? 126 $scaleoptions = null; 127 if ($this->assignment->get_instance()->grade < 0) { 128 if ($scale = $DB->get_record('scale', array('id'=>-($this->assignment->get_instance()->grade)))) { 129 $scaleoptions = make_menu_from_list($scale->scale); 130 } 131 } 132 // We may need to upgrade the gradebook comments after this update. 133 $adminconfig = $this->assignment->get_admin_config(); 134 $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook; 135 136 $updategradecount = 0; 137 $updatefeedbackcount = 0; 138 while ($record = $gradeimporter->next()) { 139 $user = $record->user; 140 $modified = $record->modified; 141 $userdesc = fullname($user); 142 $usergrade = $this->assignment->get_user_grade($user->id, false); 143 144 if (!empty($scaleoptions)) { 145 // This is a scale - we need to convert any grades to indexes in the scale. 146 $scaleindex = array_search($record->grade, $scaleoptions); 147 if ($scaleindex !== false) { 148 $record->grade = $scaleindex; 149 } else { 150 $record->grade = ''; 151 } 152 } else { 153 $record->grade = unformat_float($record->grade); 154 } 155 156 // Note: Do not count the seconds when comparing modified dates. 157 $skip = false; 158 $stalemodificationdate = ($usergrade && $usergrade->timemodified > ($modified + 60)); 159 160 if ($usergrade && $usergrade->grade == $record->grade) { 161 // Skip - grade not modified. 162 $skip = true; 163 } else if (!isset($record->grade) || $record->grade === '' || $record->grade < 0) { 164 // Skip - grade has no value. 165 $skip = true; 166 } else if (!$ignoremodified && $stalemodificationdate) { 167 // Skip - grade has been modified. 168 $skip = true; 169 } else if ($this->assignment->grading_disabled($record->user->id)) { 170 // Skip grade is locked. 171 $skip = true; 172 } else if (($this->assignment->get_instance()->grade > -1) && 173 (($record->grade < 0) || ($record->grade > $this->assignment->get_instance()->grade))) { 174 // Out of range. 175 $skip = true; 176 } 177 178 if (!$skip) { 179 $grade = $this->assignment->get_user_grade($record->user->id, true); 180 181 $grade->grade = $record->grade; 182 $grade->grader = $USER->id; 183 if ($this->assignment->update_grade($grade)) { 184 $this->assignment->notify_grade_modified($grade); 185 $updategradecount += 1; 186 } 187 } 188 189 if ($ignoremodified || !$stalemodificationdate) { 190 foreach ($record->feedback as $feedback) { 191 $plugin = $feedback['plugin']; 192 $field = $feedback['field']; 193 $newvalue = $feedback['value']; 194 $description = $feedback['description']; 195 $oldvalue = ''; 196 if ($usergrade) { 197 $oldvalue = $plugin->get_editor_text($field, $usergrade->id); 198 if (empty($oldvalue)) { 199 $oldvalue = ''; 200 } 201 } 202 if ($newvalue != $oldvalue) { 203 $updatefeedbackcount += 1; 204 $grade = $this->assignment->get_user_grade($record->user->id, true); 205 $this->assignment->notify_grade_modified($grade); 206 $plugin->set_editor_text($field, $newvalue, $grade->id); 207 208 // If this is the gradebook comments plugin - post an update to the gradebook. 209 if (($plugin->get_subtype() . '_' . $plugin->get_type()) == $gradebookplugin) { 210 $grade->feedbacktext = $plugin->text_for_gradebook($grade); 211 $grade->feedbackformat = $plugin->format_for_gradebook($grade); 212 $this->assignment->update_grade($grade); 213 } 214 } 215 } 216 } 217 } 218 $gradeimporter->close(true); 219 220 $renderer = $this->assignment->get_renderer(); 221 $o = ''; 222 223 $o .= $renderer->render(new assign_header($this->assignment->get_instance(), 224 $this->assignment->get_context(), 225 false, 226 $this->assignment->get_course_module()->id, 227 get_string('importgrades', 'assignfeedback_offline'))); 228 $strparams = [ 229 'gradeupdatescount' => $updategradecount, 230 'feedbackupdatescount' => $updatefeedbackcount, 231 ]; 232 $o .= $renderer->box(get_string('updatedgrades', 'assignfeedback_offline', $strparams)); 233 $url = new moodle_url('view.php', 234 array('id'=>$this->assignment->get_course_module()->id, 235 'action'=>'grading')); 236 $o .= $renderer->continue_button($url); 237 $o .= $renderer->render_footer(); 238 return $o; 239 } 240 241 /** 242 * Display upload grades form 243 * 244 * @return string The response html 245 */ 246 public function upload_grades() { 247 global $CFG, $USER; 248 249 require_capability('mod/assign:grade', $this->assignment->get_context()); 250 require_once($CFG->dirroot . '/mod/assign/feedback/offline/uploadgradesform.php'); 251 require_once($CFG->dirroot . '/mod/assign/feedback/offline/importgradesform.php'); 252 require_once($CFG->dirroot . '/mod/assign/feedback/offline/importgradeslib.php'); 253 require_once($CFG->libdir . '/csvlib.class.php'); 254 255 $mform = new assignfeedback_offline_upload_grades_form(null, 256 array('context'=>$this->assignment->get_context(), 257 'cm'=>$this->assignment->get_course_module()->id)); 258 259 $o = ''; 260 261 $confirm = optional_param('confirm', 0, PARAM_BOOL); 262 $renderer = $this->assignment->get_renderer(); 263 264 if ($mform->is_cancelled()) { 265 redirect(new moodle_url('view.php', 266 array('id'=>$this->assignment->get_course_module()->id, 267 'action'=>'grading'))); 268 return; 269 } else if (($data = $mform->get_data()) && 270 ($csvdata = $mform->get_file_content('gradesfile'))) { 271 272 $importid = csv_import_reader::get_new_iid('assignfeedback_offline'); 273 $gradeimporter = new assignfeedback_offline_grade_importer($importid, $this->assignment, 274 $data->encoding, $data->separator); 275 // File exists and was valid. 276 $ignoremodified = !empty($data->ignoremodified); 277 278 $draftid = $data->gradesfile; 279 280 // Preview import. 281 282 $mform = new assignfeedback_offline_import_grades_form(null, array('assignment'=>$this->assignment, 283 'csvdata'=>$csvdata, 284 'ignoremodified'=>$ignoremodified, 285 'gradeimporter'=>$gradeimporter, 286 'draftid'=>$draftid)); 287 288 $o .= $renderer->render(new assign_header($this->assignment->get_instance(), 289 $this->assignment->get_context(), 290 false, 291 $this->assignment->get_course_module()->id, 292 get_string('confirmimport', 'assignfeedback_offline'))); 293 $o .= $renderer->render(new assign_form('confirmimport', $mform)); 294 $o .= $renderer->render_footer(); 295 } else if ($confirm) { 296 $importid = optional_param('importid', 0, PARAM_INT); 297 $draftid = optional_param('draftid', 0, PARAM_INT); 298 $encoding = optional_param('encoding', 'utf-8', PARAM_ALPHANUMEXT); 299 $separator = optional_param('separator', 'comma', PARAM_ALPHA); 300 $ignoremodified = optional_param('ignoremodified', 0, PARAM_BOOL); 301 $gradeimporter = new assignfeedback_offline_grade_importer($importid, $this->assignment, $encoding, $separator); 302 $mform = new assignfeedback_offline_import_grades_form(null, array('assignment'=>$this->assignment, 303 'csvdata'=>'', 304 'ignoremodified'=>$ignoremodified, 305 'gradeimporter'=>$gradeimporter, 306 'draftid'=>$draftid)); 307 if ($mform->is_cancelled()) { 308 redirect(new moodle_url('view.php', 309 array('id'=>$this->assignment->get_course_module()->id, 310 'action'=>'grading'))); 311 return; 312 } 313 314 $o .= $this->process_import_grades($draftid, $importid, $ignoremodified, $encoding, $separator); 315 } else { 316 317 $o .= $renderer->render(new assign_header($this->assignment->get_instance(), 318 $this->assignment->get_context(), 319 false, 320 $this->assignment->get_course_module()->id, 321 get_string('uploadgrades', 'assignfeedback_offline'))); 322 $o .= $renderer->render(new assign_form('batchuploadfiles', $mform)); 323 $o .= $renderer->render_footer(); 324 } 325 326 return $o; 327 } 328 329 /** 330 * Download a marking worksheet 331 * 332 * @return string The response html 333 */ 334 public function download_grades() { 335 global $CFG; 336 337 require_capability('mod/assign:grade', $this->assignment->get_context()); 338 require_once($CFG->dirroot . '/mod/assign/gradingtable.php'); 339 340 $groupmode = groups_get_activity_groupmode($this->assignment->get_course_module()); 341 // All users. 342 $groupid = 0; 343 $groupname = ''; 344 if ($groupmode) { 345 $groupid = groups_get_activity_group($this->assignment->get_course_module(), true); 346 $groupname = groups_get_group_name($groupid) . '-'; 347 } 348 $filename = clean_filename(get_string('offlinegradingworksheet', 'assignfeedback_offline') . '-' . 349 $this->assignment->get_course()->shortname . '-' . 350 $this->assignment->get_instance()->name . '-' . 351 $groupname . 352 $this->assignment->get_course_module()->id); 353 354 $table = new assign_grading_table($this->assignment, 0, '', 0, false, $filename); 355 356 $table->out(0, false); 357 return; 358 } 359 360 /** 361 * Print a sub page in this plugin 362 * 363 * @param string $action - The plugin action 364 * @return string The response html 365 */ 366 public function view_page($action) { 367 if ($action == 'downloadgrades') { 368 return $this->download_grades(); 369 } else if ($action == 'uploadgrades') { 370 return $this->upload_grades(); 371 } 372 373 return ''; 374 } 375 376 /** 377 * Return a list of the grading actions performed by this plugin 378 * This plugin supports upload zip 379 * 380 * @return array The list of grading actions 381 */ 382 public function get_grading_actions() { 383 return array('uploadgrades'=>get_string('uploadgrades', 'assignfeedback_offline'), 384 'downloadgrades'=>get_string('downloadgrades', 'assignfeedback_offline')); 385 } 386 387 /** 388 * Override the default is_enabled to disable this plugin if advanced grading is active 389 * 390 * @return bool 391 */ 392 public function is_enabled() { 393 if ($this->enabledcache === null) { 394 $gradingmanager = get_grading_manager($this->assignment->get_context(), 'mod_assign', 'submissions'); 395 $controller = $gradingmanager->get_active_controller(); 396 $active = !empty($controller); 397 398 if ($active) { 399 $this->enabledcache = false; 400 } else { 401 $this->enabledcache = parent::is_enabled(); 402 } 403 } 404 return $this->enabledcache; 405 } 406 407 /** 408 * Do not show this plugin in the grading table or on the front page 409 * 410 * @return bool 411 */ 412 public function has_user_summary() { 413 return false; 414 } 415 416 /** 417 * Return the plugin configs for external functions. 418 * 419 * @return array the list of settings 420 * @since Moodle 3.2 421 */ 422 public function get_config_for_external() { 423 return (array) $this->get_config(); 424 } 425 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body