Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 PDF feedback plugin
  19   *
  20   *
  21   * @package   assignfeedback_editpdf
  22   * @copyright 2012 Davo Smith
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  use \assignfeedback_editpdf\document_services;
  29  use \assignfeedback_editpdf\page_editor;
  30  
  31  /**
  32   * library class for editpdf feedback plugin extending feedback plugin base class
  33   *
  34   * @package   assignfeedback_editpdf
  35   * @copyright 2012 Davo Smith
  36   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class assign_feedback_editpdf extends assign_feedback_plugin {
  39  
  40      /** @var boolean|null $enabledcache Cached lookup of the is_enabled function */
  41      private $enabledcache = null;
  42  
  43      /**
  44       * Get the name of the file feedback plugin
  45       * @return string
  46       */
  47      public function get_name() {
  48          return get_string('pluginname', 'assignfeedback_editpdf');
  49      }
  50  
  51      /**
  52       * Create a widget for rendering the editor.
  53       *
  54       * @param int $userid
  55       * @param stdClass $grade
  56       * @param bool $readonly
  57       * @return assignfeedback_editpdf_widget
  58       */
  59      public function get_widget($userid, $grade, $readonly) {
  60          $attempt = -1;
  61          if ($grade && isset($grade->attemptnumber)) {
  62              $attempt = $grade->attemptnumber;
  63          } else {
  64              $grade = $this->assignment->get_user_grade($userid, true);
  65          }
  66  
  67          $feedbackfile = document_services::get_feedback_document($this->assignment->get_instance()->id,
  68                                                                   $userid,
  69                                                                   $attempt);
  70  
  71          $stampfiles = array();
  72          $fs = get_file_storage();
  73          $syscontext = context_system::instance();
  74  
  75          // Copy any new stamps to this instance.
  76          if ($files = $fs->get_area_files($syscontext->id,
  77                                           'assignfeedback_editpdf',
  78                                           'stamps',
  79                                           0,
  80                                           "filename",
  81                                           false)) {
  82              foreach ($files as $file) {
  83                  $filename = $file->get_filename();
  84                  if ($filename !== '.') {
  85  
  86                      $existingfile = $fs->get_file($this->assignment->get_context()->id,
  87                                                    'assignfeedback_editpdf',
  88                                                    'stamps',
  89                                                    $grade->id,
  90                                                    '/',
  91                                                    $file->get_filename());
  92                      if (!$existingfile) {
  93                          $newrecord = new stdClass();
  94                          $newrecord->contextid = $this->assignment->get_context()->id;
  95                          $newrecord->itemid = $grade->id;
  96                          $fs->create_file_from_storedfile($newrecord, $file);
  97                      }
  98                  }
  99              }
 100          }
 101  
 102          // Now get the full list of stamp files for this instance.
 103          if ($files = $fs->get_area_files($this->assignment->get_context()->id,
 104                                           'assignfeedback_editpdf',
 105                                           'stamps',
 106                                           $grade->id,
 107                                           "filename",
 108                                           false)) {
 109              foreach ($files as $file) {
 110                  $filename = $file->get_filename();
 111                  if ($filename !== '.') {
 112                      $url = moodle_url::make_pluginfile_url($this->assignment->get_context()->id,
 113                                                     'assignfeedback_editpdf',
 114                                                     'stamps',
 115                                                     $grade->id,
 116                                                     '/',
 117                                                     $file->get_filename(),
 118                                                     false);
 119                      array_push($stampfiles, $url->out());
 120                  }
 121              }
 122          }
 123  
 124          $url = false;
 125          $filename = '';
 126          if ($feedbackfile) {
 127              $url = moodle_url::make_pluginfile_url($this->assignment->get_context()->id,
 128                                                     'assignfeedback_editpdf',
 129                                                     document_services::FINAL_PDF_FILEAREA,
 130                                                     $grade->id,
 131                                                     '/',
 132                                                     $feedbackfile->get_filename(),
 133                                                     false);
 134             $filename = $feedbackfile->get_filename();
 135          }
 136  
 137          $widget = new assignfeedback_editpdf_widget($this->assignment->get_instance()->id,
 138                                                      $userid,
 139                                                      $attempt,
 140                                                      $url,
 141                                                      $filename,
 142                                                      $stampfiles,
 143                                                      $readonly
 144                                                  );
 145          return $widget;
 146      }
 147  
 148      /**
 149       * Get form elements for grading form
 150       *
 151       * @param stdClass $grade
 152       * @param MoodleQuickForm $mform
 153       * @param stdClass $data
 154       * @param int $userid
 155       * @return bool true if elements were added to the form
 156       */
 157      public function get_form_elements_for_user($grade, MoodleQuickForm $mform, stdClass $data, $userid) {
 158          global $PAGE;
 159  
 160          $attempt = -1;
 161          if ($grade) {
 162              $attempt = $grade->attemptnumber;
 163          }
 164  
 165          $renderer = $PAGE->get_renderer('assignfeedback_editpdf');
 166  
 167          // Links to download the generated pdf...
 168          if ($attempt > -1 && page_editor::has_annotations_or_comments($grade->id, false)) {
 169              $html = $this->assignment->render_area_files('assignfeedback_editpdf',
 170                                                           document_services::FINAL_PDF_FILEAREA,
 171                                                           $grade->id);
 172              $mform->addElement('static', 'editpdf_files', get_string('downloadfeedback', 'assignfeedback_editpdf'), $html);
 173          }
 174  
 175          $widget = $this->get_widget($userid, $grade, false);
 176  
 177          $html = $renderer->render($widget);
 178          $mform->addElement('static', 'editpdf', get_string('editpdf', 'assignfeedback_editpdf'), $html);
 179          $mform->addHelpButton('editpdf', 'editpdf', 'assignfeedback_editpdf');
 180          $mform->addElement('hidden', 'editpdf_source_userid', $userid);
 181          $mform->setType('editpdf_source_userid', PARAM_INT);
 182          $mform->setConstant('editpdf_source_userid', $userid);
 183      }
 184  
 185      /**
 186       * Check to see if the grade feedback for the pdf has been modified.
 187       *
 188       * @param stdClass $grade Grade object.
 189       * @param stdClass $data Data from the form submission (not used).
 190       * @return boolean True if the pdf has been modified, else false.
 191       */
 192      public function is_feedback_modified(stdClass $grade, stdClass $data) {
 193          // We only need to know if the source user's PDF has changed. If so then all
 194          // following users will have the same status. If it's only an individual annotation
 195          // then only one user will come through this method.
 196          // Source user id is only added to the form if there was a pdf.
 197          if (!empty($data->editpdf_source_userid)) {
 198              $sourceuserid = $data->editpdf_source_userid;
 199              // Retrieve the grade information for the source user.
 200              $sourcegrade = $this->assignment->get_user_grade($sourceuserid, true, $grade->attemptnumber);
 201              $pagenumbercount = document_services::page_number_for_attempt($this->assignment, $sourceuserid, $sourcegrade->attemptnumber);
 202              for ($i = 0; $i < $pagenumbercount; $i++) {
 203                  // Select all annotations.
 204                  $draftannotations = page_editor::get_annotations($sourcegrade->id, $i, true);
 205                  $nondraftannotations = page_editor::get_annotations($grade->id, $i, false);
 206                  // Check to see if the count is the same.
 207                  if (count($draftannotations) != count($nondraftannotations)) {
 208                      // The count is different so we have a modification.
 209                      return true;
 210                  } else {
 211                      $matches = 0;
 212                      // Have a closer look and see if the draft files match all the non draft files.
 213                      foreach ($nondraftannotations as $ndannotation) {
 214                          foreach ($draftannotations as $dannotation) {
 215                              foreach ($ndannotation as $key => $value) {
 216                                  if ($key != 'id' && $value != $dannotation->{$key}) {
 217                                      continue 2;
 218                                  }
 219                              }
 220                              $matches++;
 221                          }
 222                      }
 223                      if ($matches !== count($nondraftannotations)) {
 224                          return true;
 225                      }
 226                  }
 227                  // Select all comments.
 228                  $draftcomments = page_editor::get_comments($sourcegrade->id, $i, true);
 229                  $nondraftcomments = page_editor::get_comments($grade->id, $i, false);
 230                  if (count($draftcomments) != count($nondraftcomments)) {
 231                      return true;
 232                  } else {
 233                      // Go for a closer inspection.
 234                      $matches = 0;
 235                      foreach ($nondraftcomments as $ndcomment) {
 236                          foreach ($draftcomments as $dcomment) {
 237                              foreach ($ndcomment as $key => $value) {
 238                                  if ($key != 'id' && $value != $dcomment->{$key}) {
 239                                      continue 2;
 240                                  }
 241                              }
 242                              $matches++;
 243                          }
 244                      }
 245                      if ($matches !== count($nondraftcomments)) {
 246                          return true;
 247                      }
 248                  }
 249              }
 250          }
 251          return false;
 252      }
 253  
 254      /**
 255       * Generate the pdf.
 256       *
 257       * @param stdClass $grade
 258       * @param stdClass $data
 259       * @return bool
 260       */
 261      public function save(stdClass $grade, stdClass $data) {
 262          // Source user id is only added to the form if there was a pdf.
 263          if (!empty($data->editpdf_source_userid)) {
 264              $sourceuserid = $data->editpdf_source_userid;
 265              // Copy drafts annotations and comments if current user is different to sourceuserid.
 266              if ($sourceuserid != $grade->userid) {
 267                  page_editor::copy_drafts_from_to($this->assignment, $grade, $sourceuserid);
 268              }
 269          }
 270          if (page_editor::has_annotations_or_comments($grade->id, true)) {
 271              document_services::generate_feedback_document($this->assignment, $grade->userid, $grade->attemptnumber);
 272          }
 273  
 274          return true;
 275      }
 276  
 277      /**
 278       * Display the list of files in the feedback status table.
 279       *
 280       * @param stdClass $grade
 281       * @param bool $showviewlink (Always set to false).
 282       * @return string
 283       */
 284      public function view_summary(stdClass $grade, & $showviewlink) {
 285          $showviewlink = false;
 286          return $this->view($grade);
 287      }
 288  
 289      /**
 290       * Display the list of files in the feedback status table.
 291       *
 292       * @param stdClass $grade
 293       * @return string
 294       */
 295      public function view(stdClass $grade) {
 296          global $PAGE;
 297          $html = '';
 298          // Show a link to download the pdf.
 299          if (page_editor::has_annotations_or_comments($grade->id, false)) {
 300              $html = $this->assignment->render_area_files('assignfeedback_editpdf',
 301                                                           document_services::FINAL_PDF_FILEAREA,
 302                                                           $grade->id);
 303  
 304              // Also show the link to the read-only interface.
 305              $renderer = $PAGE->get_renderer('assignfeedback_editpdf');
 306              $widget = $this->get_widget($grade->userid, $grade, true);
 307  
 308              $html .= $renderer->render($widget);
 309          }
 310          return $html;
 311      }
 312  
 313      /**
 314       * Return true if there are no released comments/annotations.
 315       *
 316       * @param stdClass $grade
 317       */
 318      public function is_empty(stdClass $grade) {
 319          global $DB;
 320  
 321          $comments = $DB->count_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$grade->id, 'draft'=>0));
 322          $annotations = $DB->count_records('assignfeedback_editpdf_annot', array('gradeid'=>$grade->id, 'draft'=>0));
 323          return $comments == 0 && $annotations == 0;
 324      }
 325  
 326      /**
 327       * The assignment has been deleted - remove the plugin specific data
 328       *
 329       * @return bool
 330       */
 331      public function delete_instance() {
 332          global $DB;
 333          $grades = $DB->get_records('assign_grades', array('assignment'=>$this->assignment->get_instance()->id), '', 'id');
 334          if ($grades) {
 335              list($gradeids, $params) = $DB->get_in_or_equal(array_keys($grades), SQL_PARAMS_NAMED);
 336              $DB->delete_records_select('assignfeedback_editpdf_annot', 'gradeid ' . $gradeids, $params);
 337              $DB->delete_records_select('assignfeedback_editpdf_cmnt', 'gradeid ' . $gradeids, $params);
 338          }
 339          return true;
 340      }
 341  
 342      /**
 343       * Determine if ghostscript is available and working.
 344       *
 345       * @return bool
 346       */
 347      public function is_available() {
 348          if ($this->enabledcache === null) {
 349              $testpath = assignfeedback_editpdf\pdf::test_gs_path(false);
 350              $this->enabledcache = ($testpath->status == assignfeedback_editpdf\pdf::GSPATH_OK);
 351          }
 352          return $this->enabledcache;
 353      }
 354      /**
 355       * Prevent enabling this plugin if ghostscript is not available.
 356       *
 357       * @return bool false
 358       */
 359      public function is_configurable() {
 360          return $this->is_available();
 361      }
 362  
 363      /**
 364       * Get file areas returns a list of areas this plugin stores files.
 365       *
 366       * @return array - An array of fileareas (keys) and descriptions (values)
 367       */
 368      public function get_file_areas() {
 369          return array(document_services::FINAL_PDF_FILEAREA => $this->get_name());
 370      }
 371  
 372      /**
 373       * This plugin will inject content into the review panel with javascript.
 374       * @return bool true
 375       */
 376      public function supports_review_panel() {
 377          return true;
 378      }
 379  
 380      /**
 381       * Return the plugin configs for external functions.
 382       *
 383       * @return array the list of settings
 384       * @since Moodle 3.2
 385       */
 386      public function get_config_for_external() {
 387          return (array) $this->get_config();
 388      }
 389  }