From b78adea3c328ee2d92b1c7b78375c4678ba1b3bf Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Thu, 16 Oct 2025 17:03:59 +0200 Subject: [PATCH] MDL-84866 core_courseformat: Add duplicate option to subsections --- .../local/content/cm/delegatedcontrolmenu.php | 31 +++++++++++++++++++ .../tests/behat/subsection_actionmenu.feature | 22 +++++++++---- .../behat/subsection_disabled_plugin.feature | 2 +- .../courseformat/sectiondelegate_test.php | 1 + 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/public/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php b/public/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php index ab11f47d13f..8cf78de1bd8 100644 --- a/public/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php +++ b/public/course/format/classes/output/local/content/cm/delegatedcontrolmenu.php @@ -84,6 +84,7 @@ class delegatedcontrolmenu extends basecontrolmenu { $controls = []; $controls['view'] = $this->get_section_view_item(); $controls['edit'] = $this->get_section_edit_item(); + $controls['duplicate'] = $this->get_section_duplicate_item(); $controls['visibility'] = $this->get_section_visibility_item(); $controls['movesection'] = $this->get_cm_move_item(); $controls['permalink'] = $this->get_section_permalink_item(); @@ -173,6 +174,36 @@ class delegatedcontrolmenu extends basecontrolmenu { ); } + /** + * Retrieves the duplicate item for the section control menu. + * + * @return link|null The menu item if applicable, otherwise null. + */ + protected function get_section_duplicate_item(): ?link { + $capabilities = ['moodle/course:update', 'moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport']; + if (!has_all_capabilities($capabilities, $this->coursecontext)) { + return null; + } + if (!plugin_supports('mod', $this->mod->modname, FEATURE_BACKUP_MOODLE2)) { + return null; + } + if (!course_allowed_module($this->mod->get_course(), $this->mod->modname)) { + return null; + } + + $url = $this->format->get_update_url( + action: 'cm_duplicate', + ids: [$this->mod->id], + returnurl: $this->baseurl, + ); + + return new link_secondary( + url: $url, + icon: new pix_icon('t/copy', ''), + text: get_string('duplicate'), + ); + } + /** * Retrieves the get_section_visibility_menu_item item for the section control menu. * diff --git a/public/mod/subsection/tests/behat/subsection_actionmenu.feature b/public/mod/subsection/tests/behat/subsection_actionmenu.feature index 867301e77ae..95eeb77b1b6 100644 --- a/public/mod/subsection/tests/behat/subsection_actionmenu.feature +++ b/public/mod/subsection/tests/behat/subsection_actionmenu.feature @@ -33,8 +33,7 @@ Feature: The module menu replaces the delegated section menu And I should not see "Highlight" And I should see "Edit settings" And I should not see "Move" - # Duplicate is not implemented yet. - And I should not see "Duplicate" + And I should see "Duplicate" And I should see "Hide" And I should see "Delete" And I should see "Permalink" @@ -49,8 +48,7 @@ Feature: The module menu replaces the delegated section menu And I should see "View" And I should see "Edit settings" And I should see "Move" - # Duplicate is not implemented yet. - And I should not see "Duplicate" + And I should see "Duplicate" And I should see "Hide" And I should see "Delete" @@ -65,8 +63,7 @@ Feature: The module menu replaces the delegated section menu And I should see "View" And I should see "Edit settings" And I should see "Move" - # Duplicate is not implemented yet. - And I should not see "Duplicate" + And I should see "Duplicate" And I should see "Hide" And I should see "Delete" And I should see "Permalink" @@ -237,3 +234,16 @@ Feature: The module menu replaces the delegated section menu And I am on the "C1 > Subsection1" "course > section" page And I click on "Edit" "button" in the "[data-region='header-actions-container']" "css_element" And "Move" "link" should not exist in the "[data-region='header-actions-container']" "css_element" + + @javascript + Scenario: Duplicate a subsection and its content + Given the following "activities" exist: + | activity | name | intro | course | idnumber | section | + | assign | Activity sample | Test assignment description | C1 | sample | 3 | + Given I am on "Course 1" course homepage with editing mode on + When I open section "Subsection1" edit menu + And I choose "Duplicate" in the open action menu + # The duplicated section has section number "Subsection1 (copy)". + Then I should see "Subsection1 (copy)" in the "Section 1" "section" + And I should see "Activity sample" in the "Subsection1" "section" + And I should see "Activity sample" in the "Subsection1 (copy)" "section" diff --git a/public/mod/subsection/tests/behat/subsection_disabled_plugin.feature b/public/mod/subsection/tests/behat/subsection_disabled_plugin.feature index a533e624434..010e79c1486 100644 --- a/public/mod/subsection/tests/behat/subsection_disabled_plugin.feature +++ b/public/mod/subsection/tests/behat/subsection_disabled_plugin.feature @@ -63,7 +63,7 @@ Feature: Courses should not lose subsection contents when mod_subsection is disa And I should see "Subactivity" in the "Subsection1" "section" And "Subsection1" "section" should appear before "Section 2" "section" And "Edit settings" "link" should exist in the "Subsection1" "core_courseformat > Section actions menu" - And "Duplicate" "link" should not exist in the "Subsection1" "core_courseformat > Section actions menu" + And "Duplicate" "link" should exist in the "Subsection1" "core_courseformat > Section actions menu" And "Hide" "link" should exist in the "Subsection1" "core_courseformat > Section actions menu" And "Move" "link" should exist in the "Subsection1" "core_courseformat > Section actions menu" And "View" "link" should exist in the "Subsection1" "core_courseformat > Section actions menu" diff --git a/public/mod/subsection/tests/courseformat/sectiondelegate_test.php b/public/mod/subsection/tests/courseformat/sectiondelegate_test.php index b47d5fb4b22..8cc693494a3 100644 --- a/public/mod/subsection/tests/courseformat/sectiondelegate_test.php +++ b/public/mod/subsection/tests/courseformat/sectiondelegate_test.php @@ -74,6 +74,7 @@ final class sectiondelegate_test extends \advanced_testcase { get_string('move'), get_string('delete'), get_string('sectionlink', 'course'), + get_string('duplicate'), ]; // The default section menu should be different for the delegated section menu.