MDL-68819 core_contentbank: "Upload" button is not localized.
[moodle.git] / contentbank / classes / contenttype.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 /**
18  * Content type manager class
19  *
20  * @package    core_contentbank
21  * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core_contentbank;
27 use core\event\contentbank_content_created;
28 use core\event\contentbank_content_deleted;
29 use core\event\contentbank_content_viewed;
30 use moodle_url;
32 /**
33  * Content type manager class
34  *
35  * @package    core_contentbank
36  * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 abstract class contenttype {
41     /** Plugin implements uploading feature */
42     const CAN_UPLOAD = 'upload';
44     /** @var context This contenttype's context. **/
45     protected $context = null;
47     /**
48      * Content type constructor
49      *
50      * @param \context $context Optional context to check (default null)
51      */
52     public function __construct(\context $context = null) {
53         if (empty($context)) {
54             $context = \context_system::instance();
55         }
56         $this->context = $context;
57     }
59     /**
60      * Fills content_bank table with appropiate information.
61      *
62      * @param stdClass $record An optional content record compatible object (default null)
63      * @return content  Object with content bank information.
64      */
65     public function create_content(\stdClass $record = null): ?content {
66         global $USER, $DB;
68         $entry = new \stdClass();
69         $entry->contenttype = $this->get_contenttype_name();
70         $entry->contextid = $this->context->id;
71         $entry->name = $record->name ?? '';
72         $entry->usercreated = $record->usercreated ?? $USER->id;
73         $entry->timecreated = time();
74         $entry->usermodified = $entry->usercreated;
75         $entry->timemodified = $entry->timecreated;
76         $entry->configdata = $record->configdata ?? '';
77         $entry->instanceid = $record->instanceid ?? 0;
78         $entry->id = $DB->insert_record('contentbank_content', $entry);
79         if ($entry->id) {
80             $classname = '\\'.$entry->contenttype.'\\content';
81             $content = new $classname($entry);
82             // Trigger an event for creating the content.
83             $event = contentbank_content_created::create_from_record($content->get_content());
84             $event->trigger();
85             return $content;
86         }
87         return null;
88     }
90     /**
91      * Delete this content from the content_bank.
92      * This method can be overwritten by the plugins if they need to delete specific information.
93      *
94      * @param  content $content The content to delete.
95      * @return boolean true if the content has been deleted; false otherwise.
96      */
97     public function delete_content(content $content): bool {
98         global $DB;
100         // Delete the file if it exists.
101         if ($file = $content->get_file()) {
102             $file->delete();
103         }
105         // Delete the contentbank DB entry.
106         $result = $DB->delete_records('contentbank_content', ['id' => $content->get_id()]);
107         if ($result) {
108             // Trigger an event for deleting this content.
109             $record = $content->get_content();
110             $event = contentbank_content_deleted::create([
111                 'objectid' => $content->get_id(),
112                 'relateduserid' => $record->usercreated,
113                 'context' => \context::instance_by_id($record->contextid),
114                 'other' => [
115                     'contenttype' => $content->get_content_type(),
116                     'name' => $content->get_name()
117                 ]
118             ]);
119             $event->add_record_snapshot('contentbank_content', $record);
120             $event->trigger();
121         }
122         return $result;
123     }
125     /**
126      * Rename this content from the content_bank.
127      * This method can be overwritten by the plugins if they need to change some other specific information.
128      *
129      * @param  content $content The content to rename.
130      * @param string $name  The name of the content.
131      * @return boolean true if the content has been renamed; false otherwise.
132      */
133     public function rename_content(content $content, string $name): bool {
134         return $content->set_name($name);
135     }
137     /**
138      * Move content to another context.
139      * This method can be overwritten by the plugins if they need to change some other specific information.
140      *
141      * @param  content $content The content to rename.
142      * @param context $context  The new context.
143      * @return boolean true if the content has been renamed; false otherwise.
144      */
145     public function move_content(content $content, \context $context): bool {
146         return $content->set_contextid($context->id);
147     }
149     /**
150      * Returns the contenttype name of this content.
151      *
152      * @return string   Content type of the current instance
153      */
154     public function get_contenttype_name(): string {
155         $classname = get_class($this);
156         $contenttype = explode('\\', $classname);
157         return array_shift($contenttype);
158     }
160     /**
161      * Returns the plugin name of the current instance.
162      *
163      * @return string   Plugin name of the current instance
164      */
165     public function get_plugin_name(): string {
166         $contenttype = $this->get_contenttype_name();
167         $plugin = explode('_', $contenttype);
168         return array_pop($plugin);
169     }
171     /**
172      * Returns the URL where the content will be visualized.
173      *
174      * @param  content $content The content to be displayed.
175      * @return string           URL where to visualize the given content.
176      */
177     public function get_view_url(content $content): string {
178         return new moodle_url('/contentbank/view.php', ['id' => $content->get_id()]);
179     }
181     /**
182      * Returns the HTML content to add to view.php visualizer.
183      *
184      * @param  content $content The content to be displayed.
185      * @return string           HTML code to include in view.php.
186      */
187     public function get_view_content(content $content): string {
188         // Trigger an event for viewing this content.
189         $event = contentbank_content_viewed::create_from_record($content->get_content());
190         $event->trigger();
192         return '';
193     }
195     /**
196      * Returns the HTML code to render the icon for content bank contents.
197      *
198      * @param  content $content The content to be displayed.
199      * @return string               HTML code to render the icon
200      */
201     public function get_icon(content $content): string {
202         global $OUTPUT;
203         return $OUTPUT->image_url('f/unknown-64', 'moodle')->out(false);
204     }
206     /**
207      * Returns user has access capability for the main content bank and the content itself (base on is_access_allowed from plugin).
208      *
209      * @return bool     True if content could be accessed. False otherwise.
210      */
211     final public function can_access(): bool {
212         $classname = 'contenttype/'.$this->get_plugin_name();
213         $capability = $classname.":access";
214         $hascapabilities = has_capability('moodle/contentbank:access', $this->context)
215             && has_capability($capability, $this->context);
216         return $hascapabilities && $this->is_access_allowed();
217     }
219     /**
220      * Returns user has access capability for the content itself.
221      *
222      * @return bool     True if content could be accessed. False otherwise.
223      */
224     protected function is_access_allowed(): bool {
225         // Plugins can overwrite this function to add any check they need.
226         return true;
227     }
229     /**
230      * Returns the user has permission to upload new content.
231      *
232      * @return bool     True if content could be uploaded. False otherwise.
233      */
234     final public function can_upload(): bool {
235         if (!$this->is_feature_supported(self::CAN_UPLOAD)) {
236             return false;
237         }
238         if (!$this->can_access()) {
239             return false;
240         }
242         $classname = 'contenttype/'.$this->get_plugin_name();
243         $uploadcap = $classname.':upload';
244         $hascapabilities = has_capability('moodle/contentbank:upload', $this->context)
245             && has_capability($uploadcap, $this->context);
246         return $hascapabilities && $this->is_upload_allowed();
247     }
249     /**
250      * Returns plugin allows uploading.
251      *
252      * @return bool     True if plugin allows uploading. False otherwise.
253      */
254     protected function is_upload_allowed(): bool {
255         // Plugins can overwrite this function to add any check they need.
256         return true;
257     }
259     /**
260      * Check if the user can delete this content.
261      *
262      * @param  content $content The content to be deleted.
263      * @return bool True if content could be uploaded. False otherwise.
264      */
265     final public function can_delete(content $content): bool {
266         global $USER;
268         if ($this->context->id != $content->get_content()->contextid) {
269             // The content has to have exactly the same context as this contenttype.
270             return false;
271         }
273         $hascapability = has_capability('moodle/contentbank:deleteanycontent', $this->context);
274         if ($content->get_content()->usercreated == $USER->id) {
275             // This content has been created by the current user; check if she can delete her content.
276             $hascapability = $hascapability || has_capability('moodle/contentbank:deleteowncontent', $this->context);
277         }
279         return $hascapability && $this->is_delete_allowed($content);
280     }
282     /**
283      * Returns if content allows deleting.
284      *
285      * @param  content $content The content to be deleted.
286      * @return bool True if content allows uploading. False otherwise.
287      */
288     protected function is_delete_allowed(content $content): bool {
289         // Plugins can overwrite this function to add any check they need.
290         return true;
291     }
293     /**
294      * Check if the user can managed this content.
295      *
296      * @param  content $content The content to be managed.
297      * @return bool     True if content could be managed. False otherwise.
298      */
299     public final function can_manage(content $content): bool {
300         global $USER;
302         if ($this->context->id != $content->get_content()->contextid) {
303             // The content has to have exactly the same context as this contenttype.
304             return false;
305         }
307         // Check main contentbank management permission.
308         $hascapability = has_capability('moodle/contentbank:manageanycontent', $this->context);
309         if ($content->get_content()->usercreated == $USER->id) {
310             // This content has been created by the current user; check if they can manage their content.
311             $hascapability = $hascapability || has_capability('moodle/contentbank:manageowncontent', $this->context);
312         }
314         return $hascapability && $this->is_manage_allowed($content);
315     }
317     /**
318      * Returns if content allows managing.
319      *
320      * @param  content $content The content to be managed.
321      * @return bool True if content allows uploading. False otherwise.
322      */
323     protected function is_manage_allowed(content $content): bool {
324         // Plugins can overwrite this function to add any check they need.
325         return true;
326     }
328     /**
329      * Returns the plugin supports the feature.
330      *
331      * @param string $feature Feature code e.g CAN_UPLOAD
332      * @return bool     True if content could be uploaded. False otherwise.
333      */
334     final public function is_feature_supported(string $feature): bool {
335         return in_array($feature, $this->get_implemented_features());
336     }
338     /**
339      * Return an array of implemented features by the plugins.
340      *
341      * @return array
342      */
343     abstract protected function get_implemented_features(): array;
345     /**
346      * Return an array of extensions the plugins could manage.
347      *
348      * @return array
349      */
350     abstract public function get_manageable_extensions(): array;