on-demand release 4.0dev+
[moodle.git] / contentbank / classes / form / upload_files.php
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/>.
17 namespace core_contentbank\form;
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 {
28     /**
29      * Add elements to this form.
30      */
31     public function definition() {
32         $mform = $this->_form;
34         $mform->addElement('hidden', 'contextid');
35         $mform->setType('contextid', PARAM_INT);
37         $mform->addElement('hidden', 'id');
38         $mform->setType('id', PARAM_INT);
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     }
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     }
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());
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         }
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     }
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     }
103     /**
104      * File upload options
105      *
106      * @return array
107      * @throws \coding_exception
108      */
109     protected function get_options(): array {
110         global $CFG;
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         }
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         }
130         return ['subdirs' => 1, 'maxbytes' => $maxbytes, 'maxfiles' => -1, 'accepted_types' => $acceptedtypes,
131             'areamaxbytes' => $maxareabytes];
132     }
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;
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             }
182             return ['returnurl' => $url->out(false)];
183         }
185         return null;
186     }
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     }
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];
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         }
226         return new \moodle_url($url, $params);
227     }