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