mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 00:16:46 +02:00

This has been generated running the following Sniff, part of the Moodle's CodeSniffer standard: - PSR2.Methods.MethodDeclaration It just ensures all the function declarations have the correct order for: - abstract and final. - visibility (public, protected, private). - static. So, all the lines modified by this commit are function declarations and the only changes are in the positions of those keywords.
554 lines
19 KiB
PHP
554 lines
19 KiB
PHP
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
namespace core_contentbank;
|
|
|
|
use core\event\contentbank_content_created;
|
|
use core\event\contentbank_content_deleted;
|
|
use core\event\contentbank_content_viewed;
|
|
use stored_file;
|
|
use moodle_url;
|
|
|
|
/**
|
|
* Content type manager class
|
|
*
|
|
* @package core_contentbank
|
|
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
abstract class contenttype {
|
|
|
|
/** @var string Constant representing whether the plugin implements uploading feature */
|
|
const CAN_UPLOAD = 'upload';
|
|
|
|
/** @var string Constant representing whether the plugin implements edition feature */
|
|
const CAN_EDIT = 'edit';
|
|
|
|
/**
|
|
* @var string Constant representing whether the plugin implements download feature
|
|
* @since Moodle 3.10
|
|
*/
|
|
const CAN_DOWNLOAD = 'download';
|
|
|
|
/**
|
|
* @var string Constant representing whether the plugin implements copy feature
|
|
* @since Moodle 4.3
|
|
*/
|
|
const CAN_COPY = 'copy';
|
|
|
|
/** @var \context This contenttype's context. **/
|
|
protected $context = null;
|
|
|
|
/**
|
|
* Content type constructor
|
|
*
|
|
* @param \context $context Optional context to check (default null)
|
|
*/
|
|
public function __construct(\context $context = null) {
|
|
if (empty($context)) {
|
|
$context = \context_system::instance();
|
|
}
|
|
$this->context = $context;
|
|
}
|
|
|
|
/**
|
|
* Fills content_bank table with appropiate information.
|
|
*
|
|
* @throws dml_exception A DML specific exception is thrown for any creation error.
|
|
* @param \stdClass $record An optional content record compatible object (default null)
|
|
* @return content Object with content bank information.
|
|
*/
|
|
public function create_content(\stdClass $record = null): content {
|
|
global $USER, $DB, $CFG;
|
|
|
|
$entry = new \stdClass();
|
|
if (isset($record->visibility)) {
|
|
$entry->visibility = $record->visibility;
|
|
} else {
|
|
$usercreated = $record->usercreated ?? $USER->id;
|
|
$entry->visibility = get_user_preferences('core_contentbank_visibility',
|
|
$CFG->defaultpreference_core_contentbank_visibility, $usercreated);
|
|
}
|
|
$entry->contenttype = $this->get_contenttype_name();
|
|
$entry->contextid = $this->context->id;
|
|
$entry->name = $record->name ?? '';
|
|
$entry->usercreated = $record->usercreated ?? $USER->id;
|
|
$entry->timecreated = time();
|
|
$entry->usermodified = $entry->usercreated;
|
|
$entry->timemodified = $entry->timecreated;
|
|
$entry->configdata = $record->configdata ?? '';
|
|
$entry->instanceid = $record->instanceid ?? 0;
|
|
$entry->id = $DB->insert_record('contentbank_content', $entry);
|
|
$classname = '\\'.$entry->contenttype.'\\content';
|
|
$content = new $classname($entry);
|
|
// Trigger an event for creating the content.
|
|
$event = contentbank_content_created::create_from_record($content->get_content());
|
|
$event->trigger();
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Create a new content from an uploaded file.
|
|
*
|
|
* @throws file_exception If file operations fail
|
|
* @throws dml_exception if the content creation fails
|
|
* @param stored_file $file the uploaded file
|
|
* @param \stdClass|null $record an optional content record
|
|
* @return content Object with content bank information.
|
|
*/
|
|
public function upload_content(stored_file $file, \stdClass $record = null): content {
|
|
if (empty($record)) {
|
|
$record = new \stdClass();
|
|
$record->name = $file->get_filename();
|
|
}
|
|
$content = $this->create_content($record);
|
|
try {
|
|
$content->import_file($file);
|
|
} catch (\moodle_exception $e) {
|
|
$this->delete_content($content);
|
|
throw new \moodle_exception($e->errorcode);
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Replace a content using an uploaded file.
|
|
*
|
|
* @throws file_exception If file operations fail
|
|
* @throws dml_exception if the content creation fails
|
|
* @param stored_file $file the uploaded file
|
|
* @param content $content the original content record
|
|
* @return content Object with the updated content bank information.
|
|
*/
|
|
public function replace_content(stored_file $file, content $content): content {
|
|
$content->import_file($file);
|
|
$content->update_content();
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Delete this content from the content_bank.
|
|
* This method can be overwritten by the plugins if they need to delete specific information.
|
|
*
|
|
* @param content $content The content to delete.
|
|
* @return boolean true if the content has been deleted; false otherwise.
|
|
*/
|
|
public function delete_content(content $content): bool {
|
|
global $DB;
|
|
|
|
// Delete the file if it exists.
|
|
if ($file = $content->get_file()) {
|
|
$file->delete();
|
|
}
|
|
|
|
// Delete the contentbank DB entry.
|
|
$result = $DB->delete_records('contentbank_content', ['id' => $content->get_id()]);
|
|
if ($result) {
|
|
// Trigger an event for deleting this content.
|
|
$record = $content->get_content();
|
|
$event = contentbank_content_deleted::create([
|
|
'objectid' => $content->get_id(),
|
|
'relateduserid' => $record->usercreated,
|
|
'context' => \context::instance_by_id($record->contextid),
|
|
'other' => [
|
|
'contenttype' => $content->get_content_type(),
|
|
'name' => $content->get_name()
|
|
]
|
|
]);
|
|
$event->add_record_snapshot('contentbank_content', $record);
|
|
$event->trigger();
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Rename this content from the content_bank.
|
|
* This method can be overwritten by the plugins if they need to change some other specific information.
|
|
*
|
|
* @param content $content The content to rename.
|
|
* @param string $name The name of the content.
|
|
* @return boolean true if the content has been renamed; false otherwise.
|
|
*/
|
|
public function rename_content(content $content, string $name): bool {
|
|
return $content->set_name($name);
|
|
}
|
|
|
|
/**
|
|
* Move content to another context.
|
|
* This method can be overwritten by the plugins if they need to change some other specific information.
|
|
*
|
|
* @param content $content The content to rename.
|
|
* @param \context $context The new context.
|
|
* @return boolean true if the content has been renamed; false otherwise.
|
|
*/
|
|
public function move_content(content $content, \context $context): bool {
|
|
return $content->set_contextid($context->id);
|
|
}
|
|
|
|
/**
|
|
* Returns the contenttype name of this content.
|
|
*
|
|
* @return string Content type of the current instance
|
|
*/
|
|
public function get_contenttype_name(): string {
|
|
$classname = get_class($this);
|
|
$contenttype = explode('\\', $classname);
|
|
return array_shift($contenttype);
|
|
}
|
|
|
|
/**
|
|
* Returns the plugin name of the current instance.
|
|
*
|
|
* @return string Plugin name of the current instance
|
|
*/
|
|
public function get_plugin_name(): string {
|
|
$contenttype = $this->get_contenttype_name();
|
|
$plugin = explode('_', $contenttype);
|
|
return array_pop($plugin);
|
|
}
|
|
|
|
/**
|
|
* Returns the URL where the content will be visualized.
|
|
*
|
|
* @param content $content The content to be displayed.
|
|
* @return string URL where to visualize the given content.
|
|
*/
|
|
public function get_view_url(content $content): string {
|
|
return new moodle_url('/contentbank/view.php', ['id' => $content->get_id()]);
|
|
}
|
|
|
|
/**
|
|
* Returns the HTML content to add to view.php visualizer.
|
|
*
|
|
* @param content $content The content to be displayed.
|
|
* @return string HTML code to include in view.php.
|
|
*/
|
|
public function get_view_content(content $content): string {
|
|
// Trigger an event for viewing this content.
|
|
$event = contentbank_content_viewed::create_from_record($content->get_content());
|
|
$event->trigger();
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Returns the URL to download the content.
|
|
*
|
|
* @since Moodle 3.10
|
|
* @param content $content The content to be downloaded.
|
|
* @return string URL with the content to download.
|
|
*/
|
|
public function get_download_url(content $content): string {
|
|
$downloadurl = '';
|
|
$file = $content->get_file();
|
|
if (!empty($file)) {
|
|
$url = \moodle_url::make_pluginfile_url(
|
|
$file->get_contextid(),
|
|
$file->get_component(),
|
|
$file->get_filearea(),
|
|
$file->get_itemid(),
|
|
$file->get_filepath(),
|
|
$file->get_filename()
|
|
);
|
|
$downloadurl = $url->out(false);
|
|
}
|
|
|
|
return $downloadurl;
|
|
}
|
|
|
|
/**
|
|
* Returns the HTML code to render the icon for content bank contents.
|
|
*
|
|
* @param content $content The content to be displayed.
|
|
* @return string HTML code to render the icon
|
|
*/
|
|
public function get_icon(content $content): string {
|
|
global $OUTPUT;
|
|
return $OUTPUT->image_url('f/unknown')->out(false);
|
|
}
|
|
|
|
/**
|
|
* Returns user has access capability for the main content bank and the content itself (base on is_access_allowed from plugin).
|
|
*
|
|
* @return bool True if content could be accessed. False otherwise.
|
|
*/
|
|
final public function can_access(): bool {
|
|
$classname = 'contenttype/'.$this->get_plugin_name();
|
|
$capability = $classname.":access";
|
|
$hascapabilities = has_capability('moodle/contentbank:access', $this->context)
|
|
&& has_capability($capability, $this->context);
|
|
return $hascapabilities && $this->is_access_allowed();
|
|
}
|
|
|
|
/**
|
|
* Returns user has access capability for the content itself.
|
|
*
|
|
* @return bool True if content could be accessed. False otherwise.
|
|
*/
|
|
protected function is_access_allowed(): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns the user has permission to upload new content.
|
|
*
|
|
* @return bool True if content could be uploaded. False otherwise.
|
|
*/
|
|
final public function can_upload(): bool {
|
|
if (!$this->is_feature_supported(self::CAN_UPLOAD)) {
|
|
return false;
|
|
}
|
|
if (!$this->can_access()) {
|
|
return false;
|
|
}
|
|
|
|
$classname = 'contenttype/'.$this->get_plugin_name();
|
|
$uploadcap = $classname.':upload';
|
|
$hascapabilities = has_capability('moodle/contentbank:upload', $this->context)
|
|
&& has_capability($uploadcap, $this->context);
|
|
return $hascapabilities && $this->is_upload_allowed();
|
|
}
|
|
|
|
/**
|
|
* Returns plugin allows uploading.
|
|
*
|
|
* @return bool True if plugin allows uploading. False otherwise.
|
|
*/
|
|
protected function is_upload_allowed(): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if the user can delete this content.
|
|
*
|
|
* @param content $content The content to be deleted.
|
|
* @return bool True if content could be uploaded. False otherwise.
|
|
*/
|
|
final public function can_delete(content $content): bool {
|
|
global $USER;
|
|
|
|
if ($this->context->id != $content->get_content()->contextid) {
|
|
// The content has to have exactly the same context as this contenttype.
|
|
return false;
|
|
}
|
|
|
|
$hascapability = has_capability('moodle/contentbank:deleteanycontent', $this->context);
|
|
if ($content->get_content()->usercreated == $USER->id) {
|
|
// This content has been created by the current user; check if she can delete her content.
|
|
$hascapability = $hascapability || has_capability('moodle/contentbank:deleteowncontent', $this->context);
|
|
}
|
|
|
|
return $hascapability && $this->is_delete_allowed($content);
|
|
}
|
|
|
|
/**
|
|
* Returns if content allows deleting.
|
|
*
|
|
* @param content $content The content to be deleted.
|
|
* @return bool True if content allows uploading. False otherwise.
|
|
*/
|
|
protected function is_delete_allowed(content $content): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if the user can managed this content.
|
|
*
|
|
* @param content $content The content to be managed.
|
|
* @return bool True if content could be managed. False otherwise.
|
|
*/
|
|
final public function can_manage(content $content): bool {
|
|
global $USER;
|
|
|
|
if ($this->context->id != $content->get_content()->contextid) {
|
|
// The content has to have exactly the same context as this contenttype.
|
|
return false;
|
|
}
|
|
|
|
// Check main contentbank management permission.
|
|
$hascapability = has_capability('moodle/contentbank:manageanycontent', $this->context);
|
|
if ($content->get_content()->usercreated == $USER->id) {
|
|
// This content has been created by the current user; check if they can manage their content.
|
|
$hascapability = $hascapability || has_capability('moodle/contentbank:manageowncontent', $this->context);
|
|
}
|
|
|
|
return $hascapability && $this->is_manage_allowed($content);
|
|
}
|
|
|
|
/**
|
|
* Returns if content allows managing.
|
|
*
|
|
* @param content $content The content to be managed.
|
|
* @return bool True if content allows uploading. False otherwise.
|
|
*/
|
|
protected function is_manage_allowed(content $content): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns whether or not the user has permission to use the editor.
|
|
* This function will be called with the content to be edited as parameter,
|
|
* or null when is checking permission to create a new content using the editor.
|
|
*
|
|
* @param content $content The content to be edited or null when creating a new content.
|
|
* @return bool True if the user can edit content. False otherwise.
|
|
*/
|
|
final public function can_edit(?content $content = null): bool {
|
|
if (!$this->is_feature_supported(self::CAN_EDIT)) {
|
|
return false;
|
|
}
|
|
|
|
if (!$this->can_access()) {
|
|
return false;
|
|
}
|
|
|
|
if (!is_null($content) && !$this->can_manage($content)) {
|
|
return false;
|
|
}
|
|
|
|
$classname = 'contenttype/'.$this->get_plugin_name();
|
|
|
|
$editioncap = $classname.':useeditor';
|
|
$hascapabilities = has_all_capabilities(['moodle/contentbank:useeditor', $editioncap], $this->context);
|
|
return $hascapabilities && $this->is_edit_allowed($content);
|
|
}
|
|
|
|
/**
|
|
* Returns plugin allows edition.
|
|
*
|
|
* @param content $content The content to be edited.
|
|
* @return bool True if plugin allows edition. False otherwise.
|
|
*/
|
|
protected function is_edit_allowed(?content $content): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns whether or not the user has permission to download the content.
|
|
*
|
|
* @since Moodle 3.10
|
|
* @param content $content The content to be downloaded.
|
|
* @return bool True if the user can download the content. False otherwise.
|
|
*/
|
|
final public function can_download(content $content): bool {
|
|
if (!$this->is_feature_supported(self::CAN_DOWNLOAD)) {
|
|
return false;
|
|
}
|
|
|
|
if (!$this->can_access()) {
|
|
return false;
|
|
}
|
|
|
|
$hascapability = has_capability('moodle/contentbank:downloadcontent', $this->context);
|
|
return $hascapability && $this->is_download_allowed($content);
|
|
}
|
|
|
|
/**
|
|
* Returns whether or not the user has permission to copy the content.
|
|
*
|
|
* @since Moodle 4.3
|
|
* @param content $content The content to be copied.
|
|
* @return bool True if the user can copy the content. False otherwise.
|
|
*/
|
|
final public function can_copy(content $content): bool {
|
|
global $USER;
|
|
|
|
if (!$this->is_feature_supported(self::CAN_COPY)) {
|
|
return false;
|
|
}
|
|
|
|
if (!$this->can_access()) {
|
|
return false;
|
|
}
|
|
|
|
if (!$this->is_copy_allowed($content)) {
|
|
return false;
|
|
}
|
|
|
|
$hascapability = has_capability('moodle/contentbank:copyanycontent', $this->context);
|
|
if (!$hascapability && ($content->get_content()->usercreated == $USER->id)) {
|
|
$hascapability = has_capability('moodle/contentbank:copycontent', $this->context);
|
|
}
|
|
return $hascapability;
|
|
}
|
|
|
|
/**
|
|
* Returns plugin allows downloading.
|
|
*
|
|
* @since Moodle 3.10
|
|
* @param content $content The content to be downloaed.
|
|
* @return bool True if plugin allows downloading. False otherwise.
|
|
*/
|
|
protected function is_download_allowed(content $content): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns plugin allows copying.
|
|
*
|
|
* @since Moodle 4.3
|
|
* @param content $content The content to be copied.
|
|
* @return bool True if plugin allows copying. False otherwise.
|
|
*/
|
|
protected function is_copy_allowed(content $content): bool {
|
|
// Plugins can overwrite this function to add any check they need.
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns the plugin supports the feature.
|
|
*
|
|
* @param string $feature Feature code e.g CAN_UPLOAD
|
|
* @return bool True if content could be uploaded. False otherwise.
|
|
*/
|
|
final public function is_feature_supported(string $feature): bool {
|
|
return in_array($feature, $this->get_implemented_features());
|
|
}
|
|
|
|
/**
|
|
* Return an array of implemented features by the plugins.
|
|
*
|
|
* @return array
|
|
*/
|
|
abstract protected function get_implemented_features(): array;
|
|
|
|
/**
|
|
* Return an array of extensions the plugins could manage.
|
|
*
|
|
* @return array
|
|
*/
|
|
abstract public function get_manageable_extensions(): array;
|
|
|
|
/**
|
|
* Returns the list of different types of the given content type.
|
|
*
|
|
* A content type can have one or more options for creating content. This method will report all of them or only the content
|
|
* type itself if it has no other options.
|
|
*
|
|
* @return array An object for each type:
|
|
* - string typename: descriptive name of the type.
|
|
* - string typeeditorparams: params required by this content type editor.
|
|
* - url typeicon: this type icon.
|
|
*/
|
|
abstract public function get_contenttype_types(): array;
|
|
}
|