Search moodle.org's
Developer Documentation

See Release Notes

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

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