Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [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  namespace core_contentbank\form;
  18  
  19  /**
  20   * Upload files to content bank form
  21   *
  22   * @package    core_contentbank
  23   * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  class upload_files extends \core_form\dynamic_form {
  27  
  28      /**
  29       * Add elements to this form.
  30       */
  31      public function definition() {
  32          $mform = $this->_form;
  33  
  34          $mform->addElement('hidden', 'contextid');
  35          $mform->setType('contextid', PARAM_INT);
  36  
  37          $mform->addElement('hidden', 'id');
  38          $mform->setType('id', PARAM_INT);
  39  
  40          $mform->addElement('filepicker', 'file', get_string('file', 'core_contentbank'), null, $this->get_options());
  41          $mform->addHelpButton('file', 'file', 'core_contentbank');
  42          $mform->addRule('file', null, 'required');
  43      }
  44  
  45      /**
  46       * Validate incoming data.
  47       *
  48       * @param array $data
  49       * @param array $files
  50       * @return array
  51       */
  52      public function validation($data, $files) {
  53          $errors = array();
  54          $draftitemid = $data['file'];
  55          $options = $this->get_options();
  56          if (file_is_draft_area_limit_reached($draftitemid, $options['areamaxbytes'])) {
  57              $errors['file'] = get_string('userquotalimit', 'error');
  58          }
  59          return $errors;
  60      }
  61  
  62      /**
  63       * Check if current user has access to this form, otherwise throw exception
  64       *
  65       * Sometimes permission check may depend on the action and/or id of the entity.
  66       * If necessary, form data is available in $this->_ajaxformdata or
  67       * by calling $this->optional_param()
  68       */
  69      protected function check_access_for_dynamic_submission(): void {
  70          require_capability('moodle/contentbank:upload', $this->get_context_for_dynamic_submission());
  71  
  72          // Check the context used by the content bank is allowed.
  73          $cb = new \core_contentbank\contentbank();
  74          if (!$cb->is_context_allowed($this->get_context_for_dynamic_submission())) {
  75              throw new \moodle_exception('contextnotallowed', 'core_contentbank');
  76          }
  77  
  78          // If $id is defined, the file content will be replaced (instead of uploading a new one).
  79          // Check that the user has the right permissions to replace this content file.
  80          $id = $this->optional_param('id', null, PARAM_INT);
  81          if ($id) {
  82              $content = $cb->get_content_from_id($id);
  83              $contenttype = $content->get_content_type_instance();
  84              if (!$contenttype->can_manage($content) || !$contenttype->can_upload()) {
  85                  throw new \moodle_exception('nopermissions', 'error', '', null, get_string('replacecontent', 'contentbank'));
  86              }
  87          }
  88      }
  89  
  90      /**
  91       * Returns form context
  92       *
  93       * If context depends on the form data, it is available in $this->_ajaxformdata or
  94       * by calling $this->optional_param()
  95       *
  96       * @return \context
  97       */
  98      protected function get_context_for_dynamic_submission(): \context {
  99          $contextid = $this->optional_param('contextid', null, PARAM_INT);
 100          return \context::instance_by_id($contextid, MUST_EXIST);
 101      }
 102  
 103      /**
 104       * File upload options
 105       *
 106       * @return array
 107       * @throws \coding_exception
 108       */
 109      protected function get_options(): array {
 110          global $CFG;
 111  
 112          $maxbytes = $CFG->userquota;
 113          $maxareabytes = $CFG->userquota;
 114          if (has_capability('moodle/user:ignoreuserquota', $this->get_context_for_dynamic_submission())) {
 115              $maxbytes = USER_CAN_IGNORE_FILE_SIZE_LIMITS;
 116              $maxareabytes = FILE_AREA_MAX_BYTES_UNLIMITED;
 117          }
 118  
 119          $cb = new \core_contentbank\contentbank();
 120          $id = $this->optional_param('id', null, PARAM_INT);
 121          if ($id) {
 122              $content = $cb->get_content_from_id($id);
 123              $contenttype = $content->get_content_type_instance();
 124              $extensions = $contenttype->get_manageable_extensions();
 125              $acceptedtypes = implode(',', $extensions);
 126          } else {
 127              $acceptedtypes = $cb->get_supported_extensions_as_string($this->get_context_for_dynamic_submission());
 128          }
 129  
 130          return ['subdirs' => 1, 'maxbytes' => $maxbytes, 'maxfiles' => -1, 'accepted_types' => $acceptedtypes,
 131              'areamaxbytes' => $maxareabytes];
 132      }
 133  
 134      /**
 135       * Process the form submission, used if form was submitted via AJAX
 136       *
 137       * This method can return scalar values or arrays that can be json-encoded, they will be passed to the caller JS.
 138       *
 139       * Submission data can be accessed as: $this->get_data()
 140       *
 141       * @return mixed
 142       */
 143      public function process_dynamic_submission() {
 144          global $USER;
 145  
 146          // Get the file and create the content based on it.
 147          $usercontext = \context_user::instance($USER->id);
 148          $fs = get_file_storage();
 149          $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $this->get_data()->file, 'itemid, filepath,
 150              filename', false);
 151          if (!empty($files)) {
 152              $file = reset($files);
 153              $cb = new \core_contentbank\contentbank();
 154              try {
 155                  if ($this->get_data()->id) {
 156                      $content = $cb->get_content_from_id($this->get_data()->id);
 157                      $contenttype = $content->get_content_type_instance();
 158                      $content = $contenttype->replace_content($file, $content);
 159                  } else {
 160                      $content = $cb->create_content_from_file($this->get_context_for_dynamic_submission(), $USER->id, $file);
 161                  }
 162                  $params = ['id' => $content->get_id(), 'contextid' => $this->get_context_for_dynamic_submission()->id];
 163                  $url = new \moodle_url('/contentbank/view.php', $params);
 164              } catch (\Exception $e) {
 165                  // Redirect to the right page (depending on if content is new or existing) and display an error.
 166                  if ($this->get_data()->id) {
 167                      $content = $cb->get_content_from_id($this->get_data()->id);
 168                      $params = [
 169                          'id' => $content->get_id(),
 170                          'contextid' => $this->get_context_for_dynamic_submission()->id,
 171                          'errormsg' => 'notvalidpackage',
 172                      ];
 173                      $url = new \moodle_url('/contentbank/view.php', $params);
 174                  } else {
 175                      $url = new \moodle_url('/contentbank/index.php', [
 176                          'contextid' => $this->get_context_for_dynamic_submission()->id,
 177                          'errormsg' => 'notvalidpackage'],
 178                      );
 179                  }
 180              }
 181  
 182              return ['returnurl' => $url->out(false)];
 183          }
 184  
 185          return null;
 186      }
 187  
 188      /**
 189       * Load in existing data as form defaults
 190       *
 191       * Can be overridden to retrieve existing values from db by entity id and also
 192       * to preprocess editor and filemanager elements
 193       *
 194       * Example:
 195       *     $this->set_data(get_entity($this->_ajaxformdata['id']));
 196       */
 197      public function set_data_for_dynamic_submission(): void {
 198          $data = (object)[
 199              'contextid' => $this->optional_param('contextid', null, PARAM_INT),
 200              'id' => $this->optional_param('id', null, PARAM_INT),
 201          ];
 202          $this->set_data($data);
 203      }
 204  
 205      /**
 206       * Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX
 207       *
 208       * This is used in the form elements sensitive to the page url, such as Atto autosave in 'editor'
 209       *
 210       * If the form has arguments (such as 'id' of the element being edited), the URL should
 211       * also have respective argument.
 212       *
 213       * @return \moodle_url
 214       */
 215      protected function get_page_url_for_dynamic_submission(): \moodle_url {
 216          $params = ['contextid' => $this->get_context_for_dynamic_submission()->id];
 217  
 218          $id = $this->optional_param('id', null, PARAM_INT);
 219          if ($id) {
 220              $url = '/contentbank/view.php';
 221              $params['id'] = $id;
 222          } else {
 223              $url = '/contentbank/index.php';
 224          }
 225  
 226          return new \moodle_url($url, $params);
 227      }
 228  }