See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 401] [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 comment feedback plugin 19 * 20 * @package assignfeedback_comments 21 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 // File component for feedback comments. 28 define('ASSIGNFEEDBACK_COMMENTS_COMPONENT', 'assignfeedback_comments'); 29 30 // File area for feedback comments. 31 define('ASSIGNFEEDBACK_COMMENTS_FILEAREA', 'feedback'); 32 33 /** 34 * Library class for comment feedback plugin extending feedback plugin base class. 35 * 36 * @package assignfeedback_comments 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_feedback_comments extends assign_feedback_plugin { 41 42 /** 43 * Get the name of the online comment feedback plugin. 44 * @return string 45 */ 46 public function get_name() { 47 return get_string('pluginname', 'assignfeedback_comments'); 48 } 49 50 /** 51 * Get the feedback comment from the database. 52 * 53 * @param int $gradeid 54 * @return stdClass|false The feedback comments for the given grade if it exists. 55 * False if it doesn't. 56 */ 57 public function get_feedback_comments($gradeid) { 58 global $DB; 59 return $DB->get_record('assignfeedback_comments', array('grade'=>$gradeid)); 60 } 61 62 /** 63 * Get quickgrading form elements as html. 64 * 65 * @param int $userid The user id in the table this quickgrading element relates to 66 * @param mixed $grade - The grade data - may be null if there are no grades for this user (yet) 67 * @return mixed - A html string containing the html form elements required for quickgrading 68 */ 69 public function get_quickgrading_html($userid, $grade) { 70 $commenttext = ''; 71 if ($grade) { 72 $feedbackcomments = $this->get_feedback_comments($grade->id); 73 if ($feedbackcomments) { 74 $commenttext = $feedbackcomments->commenttext; 75 } 76 } 77 78 $pluginname = get_string('pluginname', 'assignfeedback_comments'); 79 $labeloptions = array('for'=>'quickgrade_comments_' . $userid, 80 'class'=>'accesshide'); 81 $textareaoptions = array('name'=>'quickgrade_comments_' . $userid, 82 'id'=>'quickgrade_comments_' . $userid, 83 'class'=>'quickgrade'); 84 return html_writer::tag('label', $pluginname, $labeloptions) . 85 html_writer::tag('textarea', $commenttext, $textareaoptions); 86 } 87 88 /** 89 * Has the plugin quickgrading form element been modified in the current form submission? 90 * 91 * @param int $userid The user id in the table this quickgrading element relates to 92 * @param stdClass $grade The grade 93 * @return boolean - true if the quickgrading form element has been modified 94 */ 95 public function is_quickgrading_modified($userid, $grade) { 96 $commenttext = ''; 97 if ($grade) { 98 $feedbackcomments = $this->get_feedback_comments($grade->id); 99 if ($feedbackcomments) { 100 $commenttext = $feedbackcomments->commenttext; 101 } 102 } 103 // Note that this handles the difference between empty and not in the quickgrading 104 // form at all (hidden column). 105 $newvalue = optional_param('quickgrade_comments_' . $userid, false, PARAM_RAW); 106 return ($newvalue !== false) && ($newvalue != $commenttext); 107 } 108 109 /** 110 * Has the comment feedback been modified? 111 * 112 * @param stdClass $grade The grade object. 113 * @param stdClass $data Data from the form submission. 114 * @return boolean True if the comment feedback has been modified, else false. 115 */ 116 public function is_feedback_modified(stdClass $grade, stdClass $data) { 117 $commenttext = ''; 118 if ($grade) { 119 $feedbackcomments = $this->get_feedback_comments($grade->id); 120 if ($feedbackcomments) { 121 $commenttext = $feedbackcomments->commenttext; 122 } 123 } 124 125 $formtext = $data->assignfeedbackcomments_editor['text']; 126 127 // Need to convert the form text to use @@PLUGINFILE@@ and format it so we can compare it with what is stored in the DB. 128 if (isset($data->assignfeedbackcomments_editor['itemid'])) { 129 $formtext = file_rewrite_urls_to_pluginfile($formtext, $data->assignfeedbackcomments_editor['itemid']); 130 $formtext = format_text($formtext, FORMAT_HTML); 131 } 132 133 if ($commenttext == $formtext) { 134 return false; 135 } else { 136 return true; 137 } 138 } 139 140 141 /** 142 * Override to indicate a plugin supports quickgrading. 143 * 144 * @return boolean - True if the plugin supports quickgrading 145 */ 146 public function supports_quickgrading() { 147 return true; 148 } 149 150 /** 151 * Return a list of the text fields that can be imported/exported by this plugin. 152 * 153 * @return array An array of field names and descriptions. (name=>description, ...) 154 */ 155 public function get_editor_fields() { 156 return array('comments' => get_string('pluginname', 'assignfeedback_comments')); 157 } 158 159 /** 160 * Get the saved text content from the editor. 161 * 162 * @param string $name 163 * @param int $gradeid 164 * @return string 165 */ 166 public function get_editor_text($name, $gradeid) { 167 if ($name == 'comments') { 168 $feedbackcomments = $this->get_feedback_comments($gradeid); 169 if ($feedbackcomments) { 170 return $feedbackcomments->commenttext; 171 } 172 } 173 174 return ''; 175 } 176 177 /** 178 * Get the saved text content from the editor. 179 * 180 * @param string $name 181 * @param string $value 182 * @param int $gradeid 183 * @return string 184 */ 185 public function set_editor_text($name, $value, $gradeid) { 186 global $DB; 187 188 if ($name == 'comments') { 189 $feedbackcomment = $this->get_feedback_comments($gradeid); 190 if ($feedbackcomment) { 191 $feedbackcomment->commenttext = $value; 192 return $DB->update_record('assignfeedback_comments', $feedbackcomment); 193 } else { 194 $feedbackcomment = new stdClass(); 195 $feedbackcomment->commenttext = $value; 196 $feedbackcomment->commentformat = FORMAT_HTML; 197 $feedbackcomment->grade = $gradeid; 198 $feedbackcomment->assignment = $this->assignment->get_instance()->id; 199 return $DB->insert_record('assignfeedback_comments', $feedbackcomment) > 0; 200 } 201 } 202 203 return false; 204 } 205 206 /** 207 * Save quickgrading changes. 208 * 209 * @param int $userid The user id in the table this quickgrading element relates to 210 * @param stdClass $grade The grade 211 * @return boolean - true if the grade changes were saved correctly 212 */ 213 public function save_quickgrading_changes($userid, $grade) { 214 global $DB; 215 $feedbackcomment = $this->get_feedback_comments($grade->id); 216 $quickgradecomments = optional_param('quickgrade_comments_' . $userid, null, PARAM_RAW); 217 if (!$quickgradecomments && $quickgradecomments !== '') { 218 return true; 219 } 220 if ($feedbackcomment) { 221 $feedbackcomment->commenttext = $quickgradecomments; 222 return $DB->update_record('assignfeedback_comments', $feedbackcomment); 223 } else { 224 $feedbackcomment = new stdClass(); 225 $feedbackcomment->commenttext = $quickgradecomments; 226 $feedbackcomment->commentformat = FORMAT_HTML; 227 $feedbackcomment->grade = $grade->id; 228 $feedbackcomment->assignment = $this->assignment->get_instance()->id; 229 return $DB->insert_record('assignfeedback_comments', $feedbackcomment) > 0; 230 } 231 } 232 233 /** 234 * Save the settings for feedback comments plugin 235 * 236 * @param stdClass $data 237 * @return bool 238 */ 239 public function save_settings(stdClass $data) { 240 $this->set_config('commentinline', !empty($data->assignfeedback_comments_commentinline)); 241 return true; 242 } 243 244 /** 245 * Get the default setting for feedback comments plugin 246 * 247 * @param MoodleQuickForm $mform The form to add elements to 248 * @return void 249 */ 250 public function get_settings(MoodleQuickForm $mform) { 251 $default = $this->get_config('commentinline'); 252 if ($default === false) { 253 // Apply the admin default if we don't have a value yet. 254 $default = get_config('assignfeedback_comments', 'inline'); 255 } 256 $mform->addElement('selectyesno', 257 'assignfeedback_comments_commentinline', 258 get_string('commentinline', 'assignfeedback_comments')); 259 $mform->addHelpButton('assignfeedback_comments_commentinline', 'commentinline', 'assignfeedback_comments'); 260 $mform->setDefault('assignfeedback_comments_commentinline', $default); 261 // Disable comment online if comment feedback plugin is disabled. 262 $mform->hideIf('assignfeedback_comments_commentinline', 'assignfeedback_comments_enabled', 'notchecked'); 263 } 264 265 /** 266 * Convert the text from any submission plugin that has an editor field to 267 * a format suitable for inserting in the feedback text field. 268 * 269 * @param stdClass $submission 270 * @param stdClass $data - Form data to be filled with the converted submission text and format. 271 * @param stdClass|null $grade 272 * @return boolean - True if feedback text was set. 273 */ 274 protected function convert_submission_text_to_feedback($submission, $data, $grade) { 275 global $DB; 276 277 $format = false; 278 $text = ''; 279 280 foreach ($this->assignment->get_submission_plugins() as $plugin) { 281 $fields = $plugin->get_editor_fields(); 282 if ($plugin->is_enabled() && $plugin->is_visible() && !$plugin->is_empty($submission) && !empty($fields)) { 283 $user = $DB->get_record('user', ['id' => $submission->userid]); 284 // Copy the files to the feedback area. 285 if ($files = $plugin->get_files($submission, $user)) { 286 $fs = get_file_storage(); 287 $component = 'assignfeedback_comments'; 288 $filearea = ASSIGNFEEDBACK_COMMENTS_FILEAREA; 289 $itemid = $grade->id; 290 $fieldupdates = [ 291 'component' => $component, 292 'filearea' => $filearea, 293 'itemid' => $itemid 294 ]; 295 foreach ($files as $file) { 296 if ($file instanceof stored_file) { 297 // Before we create it, check that it doesn't already exist. 298 if (!$fs->file_exists( 299 $file->get_contextid(), 300 $component, 301 $filearea, 302 $itemid, 303 $file->get_filepath(), 304 $file->get_filename())) { 305 $fs->create_file_from_storedfile($fieldupdates, $file); 306 } 307 } 308 } 309 } 310 foreach ($fields as $key => $description) { 311 $rawtext = clean_text($plugin->get_editor_text($key, $submission->id)); 312 $newformat = $plugin->get_editor_format($key, $submission->id); 313 314 if ($format !== false && $newformat != $format) { 315 // There are 2 or more editor fields using different formats, set to plain as a fallback. 316 $format = FORMAT_PLAIN; 317 } else { 318 $format = $newformat; 319 } 320 $text .= $rawtext; 321 } 322 } 323 } 324 325 if ($format === false) { 326 $format = FORMAT_HTML; 327 } 328 $data->assignfeedbackcomments = $text; 329 $data->assignfeedbackcommentsformat = $format; 330 331 return true; 332 } 333 334 /** 335 * Get form elements for the grading page 336 * 337 * @param stdClass|null $grade 338 * @param MoodleQuickForm $mform 339 * @param stdClass $data 340 * @return bool true if elements were added to the form 341 */ 342 public function get_form_elements_for_user($grade, MoodleQuickForm $mform, stdClass $data, $userid) { 343 $commentinlinenabled = $this->get_config('commentinline'); 344 $submission = $this->assignment->get_user_submission($userid, false); 345 $feedbackcomments = false; 346 347 if ($grade) { 348 $feedbackcomments = $this->get_feedback_comments($grade->id); 349 } 350 351 // Check first for data from last form submission in case grading validation failed. 352 if (!empty($data->assignfeedbackcomments_editor['text'])) { 353 $data->assignfeedbackcomments = $data->assignfeedbackcomments_editor['text']; 354 $data->assignfeedbackcommentsformat = $data->assignfeedbackcomments_editor['format']; 355 } else if ($feedbackcomments && !empty($feedbackcomments->commenttext)) { 356 $data->assignfeedbackcomments = $feedbackcomments->commenttext; 357 $data->assignfeedbackcommentsformat = $feedbackcomments->commentformat; 358 } else { 359 // No feedback given yet - maybe we need to copy the text from the submission? 360 if (!empty($commentinlinenabled) && $submission) { 361 $this->convert_submission_text_to_feedback($submission, $data, $grade); 362 } else { // Set it to empty. 363 $data->assignfeedbackcomments = ''; 364 $data->assignfeedbackcommentsformat = FORMAT_HTML; 365 } 366 } 367 368 file_prepare_standard_editor( 369 $data, 370 'assignfeedbackcomments', 371 $this->get_editor_options(), 372 $this->assignment->get_context(), 373 ASSIGNFEEDBACK_COMMENTS_COMPONENT, 374 ASSIGNFEEDBACK_COMMENTS_FILEAREA, 375 $grade->id 376 ); 377 378 $mform->addElement('editor', 'assignfeedbackcomments_editor', $this->get_name(), null, $this->get_editor_options()); 379 380 return true; 381 } 382 383 /** 384 * Saving the comment content into database. 385 * 386 * @param stdClass $grade 387 * @param stdClass $data 388 * @return bool 389 */ 390 public function save(stdClass $grade, stdClass $data) { 391 global $DB; 392 393 // Save the files. 394 $data = file_postupdate_standard_editor( 395 $data, 396 'assignfeedbackcomments', 397 $this->get_editor_options(), 398 $this->assignment->get_context(), 399 ASSIGNFEEDBACK_COMMENTS_COMPONENT, 400 ASSIGNFEEDBACK_COMMENTS_FILEAREA, 401 $grade->id 402 ); 403 404 $feedbackcomment = $this->get_feedback_comments($grade->id); 405 if ($feedbackcomment) { 406 $feedbackcomment->commenttext = $data->assignfeedbackcomments; 407 $feedbackcomment->commentformat = $data->assignfeedbackcommentsformat; 408 return $DB->update_record('assignfeedback_comments', $feedbackcomment); 409 } else { 410 $feedbackcomment = new stdClass(); 411 $feedbackcomment->commenttext = $data->assignfeedbackcomments; 412 $feedbackcomment->commentformat = $data->assignfeedbackcommentsformat; 413 $feedbackcomment->grade = $grade->id; 414 $feedbackcomment->assignment = $this->assignment->get_instance()->id; 415 return $DB->insert_record('assignfeedback_comments', $feedbackcomment) > 0; 416 } 417 } 418 419 /** 420 * Display the comment in the feedback table. 421 * 422 * @param stdClass $grade 423 * @param bool $showviewlink Set to true to show a link to view the full feedback 424 * @return string 425 */ 426 public function view_summary(stdClass $grade, & $showviewlink) { 427 $feedbackcomments = $this->get_feedback_comments($grade->id); 428 if ($feedbackcomments) { 429 $text = $this->rewrite_feedback_comments_urls($feedbackcomments->commenttext, $grade->id); 430 $text = format_text( 431 $text, 432 $feedbackcomments->commentformat, 433 [ 434 'context' => $this->assignment->get_context() 435 ] 436 ); 437 438 // Show the view all link if the text has been shortened. 439 $short = shorten_text($text, 140); 440 $showviewlink = $short != $text; 441 return $short; 442 } 443 return ''; 444 } 445 446 /** 447 * Display the comment in the feedback table. 448 * 449 * @param stdClass $grade 450 * @return string 451 */ 452 public function view(stdClass $grade) { 453 $feedbackcomments = $this->get_feedback_comments($grade->id); 454 if ($feedbackcomments) { 455 $text = $this->rewrite_feedback_comments_urls($feedbackcomments->commenttext, $grade->id); 456 $text = format_text( 457 $text, 458 $feedbackcomments->commentformat, 459 [ 460 'context' => $this->assignment->get_context() 461 ] 462 ); 463 464 return $text; 465 } 466 return ''; 467 } 468 469 /** 470 * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type 471 * and version. 472 * 473 * @param string $type old assignment subtype 474 * @param int $version old assignment version 475 * @return bool True if upgrade is possible 476 */ 477 public function can_upgrade($type, $version) { 478 479 if (($type == 'upload' || $type == 'uploadsingle' || 480 $type == 'online' || $type == 'offline') && $version >= 2011112900) { 481 return true; 482 } 483 return false; 484 } 485 486 /** 487 * Upgrade the settings from the old assignment to the new plugin based one 488 * 489 * @param context $oldcontext - the context for the old assignment 490 * @param stdClass $oldassignment - the data for the old assignment 491 * @param string $log - can be appended to by the upgrade 492 * @return bool was it a success? (false will trigger a rollback) 493 */ 494 public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) { 495 if ($oldassignment->assignmenttype == 'online') { 496 $this->set_config('commentinline', $oldassignment->var1); 497 return true; 498 } 499 return true; 500 } 501 502 /** 503 * Upgrade the feedback from the old assignment to the new one 504 * 505 * @param context $oldcontext - the database for the old assignment context 506 * @param stdClass $oldassignment The data record for the old assignment 507 * @param stdClass $oldsubmission The data record for the old submission 508 * @param stdClass $grade The data record for the new grade 509 * @param string $log Record upgrade messages in the log 510 * @return bool true or false - false will trigger a rollback 511 */ 512 public function upgrade(context $oldcontext, 513 stdClass $oldassignment, 514 stdClass $oldsubmission, 515 stdClass $grade, 516 & $log) { 517 global $DB; 518 519 $feedbackcomments = new stdClass(); 520 $feedbackcomments->commenttext = $oldsubmission->submissioncomment; 521 $feedbackcomments->commentformat = FORMAT_HTML; 522 523 $feedbackcomments->grade = $grade->id; 524 $feedbackcomments->assignment = $this->assignment->get_instance()->id; 525 if (!$DB->insert_record('assignfeedback_comments', $feedbackcomments) > 0) { 526 $log .= get_string('couldnotconvertgrade', 'mod_assign', $grade->userid); 527 return false; 528 } 529 530 return true; 531 } 532 533 /** 534 * If this plugin adds to the gradebook comments field, it must specify the format of the text 535 * of the comment 536 * 537 * Only one feedback plugin can push comments to the gradebook and that is chosen by the assignment 538 * settings page. 539 * 540 * @param stdClass $grade The grade 541 * @return int 542 */ 543 public function format_for_gradebook(stdClass $grade) { 544 $feedbackcomments = $this->get_feedback_comments($grade->id); 545 if ($feedbackcomments) { 546 return $feedbackcomments->commentformat; 547 } 548 return FORMAT_MOODLE; 549 } 550 551 /** 552 * If this plugin adds to the gradebook comments field, it must format the text 553 * of the comment 554 * 555 * Only one feedback plugin can push comments to the gradebook and that is chosen by the assignment 556 * settings page. 557 * 558 * @param stdClass $grade The grade 559 * @return string 560 */ 561 public function text_for_gradebook(stdClass $grade) { 562 $feedbackcomments = $this->get_feedback_comments($grade->id); 563 if ($feedbackcomments) { 564 return $feedbackcomments->commenttext; 565 } 566 return ''; 567 } 568 569 /** 570 * Return any files this plugin wishes to save to the gradebook. 571 * 572 * @param stdClass $grade The assign_grades object from the db 573 * @return array 574 */ 575 public function files_for_gradebook(stdClass $grade) : array { 576 return [ 577 'contextid' => $this->assignment->get_context()->id, 578 'component' => ASSIGNFEEDBACK_COMMENTS_COMPONENT, 579 'filearea' => ASSIGNFEEDBACK_COMMENTS_FILEAREA, 580 'itemid' => $grade->id 581 ]; 582 } 583 584 /** 585 * The assignment has been deleted - cleanup 586 * 587 * @return bool 588 */ 589 public function delete_instance() { 590 global $DB; 591 // Will throw exception on failure. 592 $DB->delete_records('assignfeedback_comments', 593 array('assignment'=>$this->assignment->get_instance()->id)); 594 return true; 595 } 596 597 /** 598 * Returns true if there are no feedback comments for the given grade. 599 * 600 * @param stdClass $grade 601 * @return bool 602 */ 603 public function is_empty(stdClass $grade) { 604 return $this->view($grade) == ''; 605 } 606 607 /** 608 * Get file areas returns a list of areas this plugin stores files 609 * @return array - An array of fileareas (keys) and descriptions (values) 610 */ 611 public function get_file_areas() { 612 return array(ASSIGNFEEDBACK_COMMENTS_FILEAREA => $this->get_name()); 613 } 614 615 /** 616 * Return a description of external params suitable for uploading an feedback comment from a webservice. 617 * 618 * @return external_description|null 619 */ 620 public function get_external_parameters() { 621 $editorparams = array('text' => new external_value(PARAM_RAW, 'The text for this feedback.'), 622 'format' => new external_value(PARAM_INT, 'The format for this feedback')); 623 $editorstructure = new external_single_structure($editorparams, 'Editor structure', VALUE_OPTIONAL); 624 return array('assignfeedbackcomments_editor' => $editorstructure); 625 } 626 627 /** 628 * Return the plugin configs for external functions. 629 * 630 * @return array the list of settings 631 * @since Moodle 3.2 632 */ 633 public function get_config_for_external() { 634 return (array) $this->get_config(); 635 } 636 637 /** 638 * Convert encoded URLs in $text from the @@PLUGINFILE@@/... form to an actual URL. 639 * 640 * @param string $text the Text to check 641 * @param int $gradeid The grade ID which refers to the id in the gradebook 642 */ 643 private function rewrite_feedback_comments_urls(string $text, int $gradeid) { 644 return file_rewrite_pluginfile_urls( 645 $text, 646 'pluginfile.php', 647 $this->assignment->get_context()->id, 648 ASSIGNFEEDBACK_COMMENTS_COMPONENT, 649 ASSIGNFEEDBACK_COMMENTS_FILEAREA, 650 $gradeid 651 ); 652 } 653 654 /** 655 * File format options. 656 * 657 * @return array 658 */ 659 private function get_editor_options() { 660 global $COURSE; 661 662 return [ 663 'subdirs' => 1, 664 'maxbytes' => $COURSE->maxbytes, 665 'accepted_types' => '*', 666 'context' => $this->assignment->get_context(), 667 'maxfiles' => EDITOR_UNLIMITED_FILES 668 ]; 669 } 670 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body