diff --git a/public/mod/subsection/cleandescriptions.php b/public/mod/subsection/cleandescriptions.php new file mode 100644 index 00000000000..f5170e0323a --- /dev/null +++ b/public/mod/subsection/cleandescriptions.php @@ -0,0 +1,52 @@ +. + +/** + * Remove or migrate subsection descriptions + * + * @copyright 2026 Sara Arjona + * @package mod_subsection + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once('../../config.php'); + +require_admin(); + +$action = required_param('action', PARAM_ALPHA); +$count = optional_param('count', 0, PARAM_INT); +$return = new moodle_url('/admin/settings.php', ['section' => 'mod_subsection_settings']); + +$PAGE->set_url('/mod/subsection/cleandescriptions.php'); +$PAGE->set_context(context_system::instance()); + +require_sesskey(); +if ($action === 'delete') { + // Remove all existing subsection descriptions. + $DB->set_field('course_sections', 'summary', '', ['component' => 'mod_subsection']); + redirect( + $return, + get_string('descriptionsdeletedsuccess', 'mod_subsection', $count), + null, + \core\output\notification::NOTIFY_SUCCESS + ); +} else if ($action === 'migrate') { + // Schedule the ad-hoc task to migrate subsection descriptions. + \core\task\manager::queue_adhoc_task(new \mod_subsection\task\migrate_subsection_descriptions_task(), true); + redirect($return); +} else { + throw new moodle_exception('invalidaction', 'mod_subsection'); +} diff --git a/public/mod/subsection/lang/en/subsection.php b/public/mod/subsection/lang/en/subsection.php index 3893fbe662a..b82aff3bd7a 100644 --- a/public/mod/subsection/lang/en/subsection.php +++ b/public/mod/subsection/lang/en/subsection.php @@ -23,6 +23,28 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['cleandescriptionsdetail'] = 'Subsection pages and descriptions are no longer supported in Moodle 5.2. +

This site has {$a->count} subsection descriptions that are no longer visible to users.

+

You can choose to: +

+

'; +$string['deleteconfirmbutton'] = 'Delete all descriptions'; +$string['deleteconfirmtext'] = 'This will permanently delete {$a} subsection descriptions from the database.

You can\'t undo this. Are you sure you want to delete all descriptions?'; +$string['deleteconfirmtitle'] = 'Delete all subsection descriptions?'; +$string['deletelinktext'] = 'Delete descriptions'; +$string['descriptionsdeletedsuccess'] = '{$a} subsection descriptions deleted.'; +$string['descriptionsmigratedpending'] = 'Subsection descriptions waiting to be migrated: {$a}'; +$string['descriptionsmigratedsuccess'] = 'The migration task for all subsection descriptions has been created. This task will run in the background and may take a few minutes.'; +$string['invalidaction'] = 'Invalid action specified.'; +$string['migrateconfirmbutton'] = 'Migrate all descriptions'; +$string['migrateconfirmtext'] = 'This will migrate {$a} subsection descriptions to Text and Media areas.

You can\'t undo this. Are you sure you want to migrate all descriptions?'; +$string['migrateconfirmtitle'] = 'Migrate all subsection descriptions?'; +$string['migratelinktext'] = 'Migrate descriptions'; $string['modulename'] = 'Subsection'; $string['modulenameplural'] = 'Subsections'; $string['pluginadministration'] = 'Subsection administration'; diff --git a/public/mod/subsection/settings.php b/public/mod/subsection/settings.php index 9025c8122d6..41ef83e9d16 100644 --- a/public/mod/subsection/settings.php +++ b/public/mod/subsection/settings.php @@ -28,7 +28,78 @@ defined('MOODLE_INTERNAL') || die(); if ($hassiteconfig) { $settings = new admin_settingpage('mod_subsection_settings', new lang_string('pluginname', 'mod_subsection')); - // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedIf if ($ADMIN->fulltree) { + // Add description cleanup and migration links. + $count = $DB->count_records_select( + table: 'course_sections', + select: 'component = :component AND summary != :empty', + params: ['component' => 'mod_subsection', 'empty' => ''], + ); + $task = \core\task\manager::get_queued_adhoc_task_record(new \mod_subsection\task\migrate_subsection_descriptions_task()); + if ($task) { + // There is a pending migration task, show notification and pending count. + $notification = $OUTPUT->notification( + get_string('descriptionsmigratedsuccess', 'mod_subsection'), + \core\output\notification::NOTIFY_SUCCESS, + ); + $settings->add(new admin_setting_heading( + 'migratedescriptionsnotification', + '', + $notification, + )); + $settings->add(new admin_setting_heading( + 'pendingcleandescriptions', + '', + new lang_string('descriptionsmigratedpending', 'mod_subsection', $count), + )); + } else if ($count > 0) { + // Show migration and deletion links. + $migrateaction = new \confirm_action( + message: get_string('migrateconfirmtext', 'mod_subsection', $count), + continuelabel: get_string('migrateconfirmbutton', 'mod_subsection'), + title: get_string('migrateconfirmtitle', 'mod_subsection'), + ); + $migrateurl = new moodle_url( + '/mod/subsection/cleandescriptions.php', + ['action' => 'migrate', 'count' => $count, 'sesskey' => sesskey()], + ); + $migratelink = $OUTPUT->action_link( + url: $migrateurl, + text: get_string('migratelinktext', 'mod_subsection'), + action: $migrateaction, + attributes: ['class' => 'btn btn-secondary'], + ); + + $deleteaction = new \confirm_action( + message: get_string('deleteconfirmtext', 'mod_subsection', $count), + continuelabel: get_string('deleteconfirmbutton', 'mod_subsection'), + title: get_string('deleteconfirmtitle', 'mod_subsection'), + dialogtype: 'delete', + ); + $deleteurl = new moodle_url( + '/mod/subsection/cleandescriptions.php', + ['action' => 'delete', 'count' => $count, 'sesskey' => sesskey()], + ); + $deletelink = $OUTPUT->action_link( + url: $deleteurl, + text: get_string('deletelinktext', 'mod_subsection'), + action: $deleteaction, + attributes: ['class' => 'btn btn-secondary'], + ); + + $settings->add(new admin_setting_heading( + 'cleandescriptions', + '', + new lang_string( + 'cleandescriptionsdetail', + 'mod_subsection', + [ + 'count' => $count, + 'migratelink' => $migratelink, + 'deletelink' => $deletelink, + ], + ), + )); + } } } diff --git a/public/mod/subsection/tests/behat/subsection_clean_descriptions.feature b/public/mod/subsection/tests/behat/subsection_clean_descriptions.feature new file mode 100644 index 00000000000..7aa8f8ad2c8 --- /dev/null +++ b/public/mod/subsection/tests/behat/subsection_clean_descriptions.feature @@ -0,0 +1,46 @@ +@mod @mod_subsection @_file_upload +Feature: Subsection clean descriptions + In order to manage subsection descriptions + As an administrator + I want to be able to delete or migrate subsection descriptions + + Background: + Given the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following config values are set as admin: + | enableasyncbackup | 0 | + And I am on the "Course 1" "restore" page logged in as "admin" + And I press "Manage course backups" + And I upload "mod/subsection/tests/fixtures/subsections_with_descriptions.mbz" file to "Files" filemanager + And I press "Save changes" + And I restore "subsections_with_descriptions.mbz" backup into a new course using this options: + | Schema | Course name | Course 2 | + | Schema | Course short name | C2 | + + @javascript + Scenario: Migrate subsection descriptions + Given I navigate to "Plugins > Activity modules > Subsection" in site administration + And I should see "This site has 2 subsection descriptions that are no longer visible to users." + When I click on "Migrate descriptions" "link" in the "region-main" "region" + And I should see "This will migrate 2 subsection descriptions to Text and Media areas." in the "Migrate all subsection descriptions?" "dialogue" + And I click on "Migrate all descriptions" "button" in the "Migrate all subsection descriptions?" "dialogue" + Then I should see "The migration task for all subsection descriptions has been created." in the "region-main" "region" + And I should see "Subsection descriptions waiting to be migrated: 2" in the "region-main" "region" + And I reload the page + And I should see "The migration task for all subsection descriptions has been created." in the "region-main" "region" + And I should see "Subsection descriptions waiting to be migrated: 2" in the "region-main" "region" + And I run all adhoc tasks + And I reload the page + And I should not see "Subsection descriptions waiting to be migrated:" in the "region-main" "region" + + @javascript + Scenario: Delete subsection descriptions + Given I navigate to "Plugins > Activity modules > Subsection" in site administration + And I should see "This site has 2 subsection descriptions that are no longer visible to users." + When I click on "Delete descriptions" "link" in the "region-main" "region" + And I should see "This will permanently delete 2 subsection descriptions from the database." in the "Delete all subsection descriptions?" "dialogue" + And I click on "Delete all descriptions" "button" in the "Delete all subsection descriptions?" "dialogue" + Then I should see "2 subsection descriptions deleted." in the "region-main" "region" + And I reload the page + And I should not see "Subsection pages and descriptions are no longer supported in Moodle 5.2" diff --git a/public/mod/subsection/tests/fixtures/subsections_with_descriptions.mbz b/public/mod/subsection/tests/fixtures/subsections_with_descriptions.mbz new file mode 100644 index 00000000000..2550090994f Binary files /dev/null and b/public/mod/subsection/tests/fixtures/subsections_with_descriptions.mbz differ