Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

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