MDL-68483 contentbank: improve search API
[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
fb302d38
AA
27use core\event\contentbank_content_created;
28use core\event\contentbank_content_deleted;
29use core\event\contentbank_content_viewed;
33b8ca26
AA
30use moodle_url;
31
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 */
39abstract class contenttype {
40
41 /** Plugin implements uploading feature */
42 const CAN_UPLOAD = 'upload';
43
448012c6 44 /** @var context This contenttype's context. **/
33b8ca26
AA
45 protected $context = null;
46
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 }
58
59 /**
60 * Fills content_bank table with appropiate information.
61 *
de322e3d
SA
62 * @param stdClass $record An optional content record compatible object (default null)
63 * @return content Object with content bank information.
33b8ca26 64 */
de322e3d 65 public function create_content(\stdClass $record = null): ?content {
33b8ca26
AA
66 global $USER, $DB;
67
de322e3d
SA
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 ?? '';
fb302d38 77 $entry->instanceid = $record->instanceid ?? 0;
de322e3d
SA
78 $entry->id = $DB->insert_record('contentbank_content', $entry);
79 if ($entry->id) {
80 $classname = '\\'.$entry->contenttype.'\\content';
fb302d38
AA
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;
33b8ca26
AA
86 }
87 return null;
88 }
89
c0d615e8
SA
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;
99
100 // Delete the file if it exists.
101 if ($file = $content->get_file()) {
102 $file->delete();
103 }
104
105 // Delete the contentbank DB entry.
fb302d38
AA
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;
c0d615e8
SA
123 }
124
448012c6
AA
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 }
136
33b8ca26
AA
137 /**
138 * Returns the contenttype name of this content.
139 *
140 * @return string Content type of the current instance
141 */
142 public function get_contenttype_name(): string {
143 $classname = get_class($this);
144 $contenttype = explode('\\', $classname);
145 return array_shift($contenttype);
146 }
147
148 /**
149 * Returns the plugin name of the current instance.
150 *
151 * @return string Plugin name of the current instance
152 */
153 public function get_plugin_name(): string {
154 $contenttype = $this->get_contenttype_name();
155 $plugin = explode('_', $contenttype);
156 return array_pop($plugin);
157 }
158
159 /**
160 * Returns the URL where the content will be visualized.
161 *
de322e3d
SA
162 * @param stdClass $record The content to be displayed.
163 * @return string URL where to visualize the given content.
33b8ca26
AA
164 */
165 public function get_view_url(\stdClass $record): string {
166 return new moodle_url('/contentbank/view.php', ['id' => $record->id]);
167 }
168
169 /**
170 * Returns the HTML content to add to view.php visualizer.
171 *
de322e3d
SA
172 * @param stdClass $record The content to be displayed.
173 * @return string HTML code to include in view.php.
33b8ca26
AA
174 */
175 public function get_view_content(\stdClass $record): string {
fb302d38
AA
176 // Trigger an event for viewing this content.
177 $event = contentbank_content_viewed::create_from_record($record);
178 $event->trigger();
179
33b8ca26
AA
180 // Main contenttype class can visualize the content, but plugins could overwrite visualization.
181 return '';
182 }
183
184 /**
185 * Returns the HTML code to render the icon for content bank contents.
186 *
187 * @param string $contentname The contentname to add as alt value to the icon.
188 * @return string HTML code to render the icon
189 */
190 public function get_icon(string $contentname): string {
191 global $OUTPUT;
192 return $OUTPUT->pix_icon('f/unknown-64', $contentname, 'moodle', ['class' => 'iconsize-big']);
193 }
194
195 /**
196 * Returns user has access capability for the main content bank and the content itself (base on is_access_allowed from plugin).
197 *
198 * @return bool True if content could be accessed. False otherwise.
199 */
200 final public function can_access(): bool {
201 $classname = 'contenttype/'.$this->get_plugin_name();
202 $capability = $classname.":access";
203 $hascapabilities = has_capability('moodle/contentbank:access', $this->context)
204 && has_capability($capability, $this->context);
205 return $hascapabilities && $this->is_access_allowed();
206 }
207
208 /**
209 * Returns user has access capability for the content itself.
210 *
211 * @return bool True if content could be accessed. False otherwise.
212 */
213 protected function is_access_allowed(): bool {
214 // Plugins can overwrite this function to add any check they need.
215 return true;
216 }
217
218 /**
219 * Returns the user has permission to upload new content.
220 *
221 * @return bool True if content could be uploaded. False otherwise.
222 */
223 final public function can_upload(): bool {
224 if (!$this->is_feature_supported(self::CAN_UPLOAD)) {
225 return false;
226 }
227 if (!$this->can_access()) {
228 return false;
229 }
230
231 $classname = 'contenttype/'.$this->get_plugin_name();
232 $uploadcap = $classname.':upload';
233 $hascapabilities = has_capability('moodle/contentbank:upload', $this->context)
234 && has_capability($uploadcap, $this->context);
235 return $hascapabilities && $this->is_upload_allowed();
236 }
237
238 /**
239 * Returns plugin allows uploading.
240 *
241 * @return bool True if plugin allows uploading. False otherwise.
242 */
243 protected function is_upload_allowed(): bool {
244 // Plugins can overwrite this function to add any check they need.
245 return true;
246 }
247
c0d615e8
SA
248 /**
249 * Check if the user can delete this content.
250 *
251 * @param content $content The content to be deleted.
252 * @return bool True if content could be uploaded. False otherwise.
253 */
254 final public function can_delete(content $content): bool {
255 global $USER;
256
257 if ($this->context->id != $content->get_content()->contextid) {
258 // The content has to have exactly the same context as this contenttype.
259 return false;
260 }
261
262 $hascapability = has_capability('moodle/contentbank:deleteanycontent', $this->context);
263 if ($content->get_content()->usercreated == $USER->id) {
264 // This content has been created by the current user; check if she can delete her content.
265 $hascapability = $hascapability || has_capability('moodle/contentbank:deleteowncontent', $this->context);
266 }
267
268 return $hascapability && $this->is_delete_allowed($content);
269 }
270
271 /**
272 * Returns if content allows deleting.
273 *
274 * @param content $content The content to be deleted.
275 * @return bool True if content allows uploading. False otherwise.
276 */
277 protected function is_delete_allowed(content $content): bool {
278 // Plugins can overwrite this function to add any check they need.
279 return true;
280 }
281
448012c6
AA
282 /**
283 * Check if the user can managed this content.
284 *
285 * @param content $content The content to be managed.
286 * @return bool True if content could be managed. False otherwise.
287 */
288 public final function can_manage(content $content): bool {
289 global $USER;
290
291 if ($this->context->id != $content->get_content()->contextid) {
292 // The content has to have exactly the same context as this contenttype.
293 return false;
294 }
295
296 // Check main contentbank management permission.
297 $hascapability = has_capability('moodle/contentbank:manageanycontent', $this->context);
298 if ($content->get_content()->usercreated == $USER->id) {
299 // This content has been created by the current user; check if they can manage their content.
300 $hascapability = $hascapability || has_capability('moodle/contentbank:manageowncontent', $this->context);
301 }
302
303 return $hascapability && $this->is_manage_allowed($content);
304 }
305
306 /**
307 * Returns if content allows managing.
308 *
309 * @param content $content The content to be managed.
310 * @return bool True if content allows uploading. False otherwise.
311 */
312 protected function is_manage_allowed(content $content): bool {
313 // Plugins can overwrite this function to add any check they need.
314 return true;
315 }
316
33b8ca26
AA
317 /**
318 * Returns the plugin supports the feature.
319 *
320 * @param string $feature Feature code e.g CAN_UPLOAD
321 * @return bool True if content could be uploaded. False otherwise.
322 */
323 final public function is_feature_supported(string $feature): bool {
324 return in_array($feature, $this->get_implemented_features());
325 }
326
327 /**
328 * Return an array of implemented features by the plugins.
329 *
330 * @return array
331 */
332 abstract protected function get_implemented_features(): array;
333
334 /**
335 * Return an array of extensions the plugins could manage.
336 *
337 * @return array
338 */
339 abstract public function get_manageable_extensions(): array;
340}