From f2a9bb6edb37eb88c3e50d98e1a761908cbc1eee Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Mon, 11 May 2020 18:53:30 +0200 Subject: [PATCH] MDL-68526 core_contentbank: Delete content when a course is deleted Or when a course category is moved/deleted --- contentbank/classes/content.php | 33 +++++++++++++++ contentbank/classes/contentbank.php | 64 ++++++++++++++++++++++++++--- contentbank/classes/contenttype.php | 12 ++++++ course/classes/category.php | 17 ++++++++ lang/en/contentbank.php | 3 ++ lib/moodlelib.php | 7 ++++ 6 files changed, 130 insertions(+), 6 deletions(-) diff --git a/contentbank/classes/content.php b/contentbank/classes/content.php index 25bc2ddab86..5e8c7bc37b6 100644 --- a/contentbank/classes/content.php +++ b/contentbank/classes/content.php @@ -146,6 +146,39 @@ abstract class content { return $this->content->name; } + /** + * Set a new contextid to the content. + * + * @param int $contextid The new contextid of the content. + * @return bool True if the content has been succesfully updated. False otherwise. + */ + public function set_contextid(int $contextid): bool { + if ($this->content->contextid == $contextid) { + return true; + } + + $oldcontextid = $this->content->contextid; + $this->content->contextid = $contextid; + $updated = $this->update_content(); + if ($updated) { + // Move files to new context + $fs = get_file_storage(); + $fs->move_area_files_to_new_context($oldcontextid, $contextid, 'contentbank', 'public', $this->content->id); + } else { + $this->content->contextid = $oldcontextid; + } + return $updated; + } + + /** + * Returns the contextid of the content. + * + * @return int The id of the content context. + */ + public function get_contextid(): string { + return $this->content->contextid; + } + /** * Returns the content ID. * diff --git a/contentbank/classes/contentbank.php b/contentbank/classes/contentbank.php index 197a36c79cb..8393f6a184a 100644 --- a/contentbank/classes/contentbank.php +++ b/contentbank/classes/contentbank.php @@ -25,6 +25,7 @@ namespace core_contentbank; use stored_file; +use context; /** * Content bank class @@ -88,10 +89,10 @@ class contentbank { /** * Obtains an array of supported extensions in the given context. * - * @param \context $context Optional context to check (default null) + * @param context $context Optional context to check (default null) * @return array The array with all the extensions supported and the supporting plugin names. */ - public function load_context_supported_extensions(\context $context = null): array { + public function load_context_supported_extensions(context $context = null): array { $extensionscache = \cache::make('core', 'contentbank_context_extensions'); $contextextensions = $extensionscache->get($context->id); @@ -117,10 +118,10 @@ class contentbank { * Obtains a string with all supported extensions by active plugins. * Mainly to use as filepicker options parameter. * - * @param \context $context Optional context to check (default null) + * @param context $context Optional context to check (default null) * @return string A string with all the extensions supported. */ - public function get_supported_extensions_as_string(\context $context = null) { + public function get_supported_extensions_as_string(context $context = null) { $supported = $this->load_context_supported_extensions($context); $extensions = array_keys($supported); return implode(',', $extensions); @@ -144,10 +145,10 @@ class contentbank { * Get the first content bank plugin supports a file extension. * * @param string $extension Content file extension - * @param \context $context $context Optional context to check (default null) + * @param context $context $context Optional context to check (default null) * @return string contenttype name supports the file extension or null if the extension is not supported by any allowed plugin. */ - public function get_extension_supporter(string $extension, \context $context = null): ?string { + public function get_extension_supporter(string $extension, context $context = null): ?string { $supporters = $this->load_context_supported_extensions($context); if (array_key_exists($extension, $supporters)) { return $supporters[$extension]; @@ -240,4 +241,55 @@ class contentbank { $event->trigger(); return $content; } + + /** + * Delete content bank content by context. + * + * @param context $context The context to delete content from. + * @return bool + */ + public function delete_contents(context $context): bool { + global $DB; + + $result = true; + $records = $DB->get_records('contentbank_content', ['contextid' => $context->id]); + foreach ($records as $record) { + $contenttypeclass = "\\$record->contenttype\\contenttype"; + if (class_exists($contenttypeclass)) { + $contenttype = new $contenttypeclass($context); + $contentclass = "\\$record->contenttype\\content"; + $content = new $contentclass($record); + if (!$contenttype->delete_content($content)) { + $result = false; + } + } + } + return $result; + } + + /** + * Move content bank content from a context to another. + * + * @param context $from The context to get content from. + * @param context $to The context to move content to. + * @return bool + */ + public function move_contents(context $from, context $to): bool { + global $DB; + + $result = true; + $records = $DB->get_records('contentbank_content', ['contextid' => $from->id]); + foreach ($records as $record) { + $contenttypeclass = "\\$record->contenttype\\contenttype"; + if (class_exists($contenttypeclass)) { + $contenttype = new $contenttypeclass($from); + $contentclass = "\\$record->contenttype\\content"; + $content = new $contentclass($record); + if (!$contenttype->move_content($content, $to)) { + $result = false; + } + } + } + return $result; + } } diff --git a/contentbank/classes/contenttype.php b/contentbank/classes/contenttype.php index 7f7fbf59694..e86ce450f22 100644 --- a/contentbank/classes/contenttype.php +++ b/contentbank/classes/contenttype.php @@ -134,6 +134,18 @@ abstract class contenttype { 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. * diff --git a/course/classes/category.php b/course/classes/category.php index aea6ed0df83..5812abdf133 100644 --- a/course/classes/category.php +++ b/course/classes/category.php @@ -1993,6 +1993,10 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr // Now delete anything that may depend on course category context. grade_course_category_delete($this->id, 0, $showfeedback); + $cb = new \core_contentbank\contentbank(); + if (!$cb->delete_contents($this->get_context())) { + throw new moodle_exception('errordeletingcontentfromcategory', 'contentbank', '', $this->get_formatted_name()); + } if (!question_delete_course_category($this, 0, $showfeedback)) { throw new moodle_exception('cannotdeletecategoryquestions', '', '', $this->get_formatted_name()); } @@ -2153,6 +2157,19 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr // Now delete anything that may depend on course category context. grade_course_category_delete($this->id, $newparentid, $showfeedback); + $cb = new \core_contentbank\contentbank(); + $newparentcontext = context_coursecat::instance($newparentid); + $result = $cb->move_contents($context, $newparentcontext); + if ($showfeedback) { + if ($result) { + echo $OUTPUT->notification(get_string('contentsmoved', 'contentbank', $catname), 'notifysuccess'); + } else { + echo $OUTPUT->notification( + get_string('errordeletingcontentbankfromcategory', 'contentbank', $catname), + 'notifysuccess' + ); + } + } if (!question_delete_course_category($this, $newparentcat, $showfeedback)) { if ($showfeedback) { echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $catname), 'notifysuccess'); diff --git a/lang/en/contentbank.php b/lang/en/contentbank.php index e111a7c6d5f..14b1c98a239 100644 --- a/lang/en/contentbank.php +++ b/lang/en/contentbank.php @@ -23,16 +23,19 @@ */ $string['author'] = 'Author'; +$string['contentbank'] = 'Content bank'; $string['contentdeleted'] = 'The content has been deleted.'; $string['contentname'] = 'Content name'; $string['contentnotdeleted'] = 'An error was encountered while trying to delete the content.'; $string['contentnotrenamed'] = 'An error was encountered while trying to rename the content.'; $string['contentrenamed'] = 'The content has been renamed.'; +$string['contentsmoved'] = 'Content bank contents moved to {$a}.'; $string['eventcontentcreated'] = 'Content created'; $string['eventcontentdeleted'] = 'Content deleted'; $string['eventcontentupdated'] = 'Content updated'; $string['eventcontentuploaded'] = 'Content uploaded'; $string['eventcontentviewed'] = 'Content viewed'; +$string['errordeletingcontentfromcategory'] = 'Error deleting content from category {$a}.'; $string['deletecontent'] = 'Delete content'; $string['deletecontentconfirm'] = 'Are you sure you want to delete the content \'{$a->name}\' and all associated files? This action cannot be undone.'; $string['file'] = 'Upload content'; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index f1c9a30e560..d5d2735ef58 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -5335,6 +5335,13 @@ function remove_course_contents($courseid, $showfeedback = true, array $options echo $OUTPUT->notification($strdeleted.get_string('questions', 'question'), 'notifysuccess'); } + // Delete content bank contents. + $cb = new \core_contentbank\contentbank(); + $cbdeleted = $cb->delete_contents($coursecontext); + if ($showfeedback && $cbdeleted) { + echo $OUTPUT->notification($strdeleted.get_string('contentbank', 'contentbank'), 'notifysuccess'); + } + // Make sure there are no subcontexts left - all valid blocks and modules should be already gone. $childcontexts = $coursecontext->get_child_contexts(); // Returns all subcontexts since 2.2. foreach ($childcontexts as $childcontext) {