Skip to content

Commit

Permalink
MDL-78388 course: Copy permissions when duplicating module
Browse files Browse the repository at this point in the history
  • Loading branch information
djarran committed Jul 3, 2024
1 parent dc6dda1 commit 92564ac
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 0 deletions.
17 changes: 17 additions & 0 deletions course/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -3605,6 +3605,23 @@ function duplicate_module($course, $cm, int $sectionid = null, bool $changename
// The following line is to be removed in MDL-58906.
course_module_update_calendar_events($newcm->modname, null, $newcm);

// Copy permission overrides to new course module.
$newcmcontext = context_module::instance($newcm->id);
$overrides = $DB->get_records('role_capabilities', ['contextid' => $cmcontext->id]);
foreach ($overrides as $override) {
$override->contextid = $newcmcontext->id;
unset($override->id);
$DB->insert_record('role_capabilities', $override);
}

// Copy locally assigned roles to new course module.
$overrides = $DB->get_records('role_assignments', ['contextid' => $cmcontext->id]);
foreach ($overrides as $override) {
$override->contextid = $newcmcontext->id;
unset($override->id);
$DB->insert_record('role_assignments', $override);
}

// Trigger course module created event. We can trigger the event only if we know the newcmid.
$newcm = get_fast_modinfo($cm->course)->get_cm($newcmid);
$event = \core\event\course_module_created::create_from_cm($newcm);
Expand Down
75 changes: 75 additions & 0 deletions course/tests/courselib_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -3046,6 +3046,81 @@ public function test_duplicate_module() {
}
}

/**
* Test that permissions are duplicated correctly after duplicate_module().
* @covers ::duplicate_module
* @return void
*/
public function test_duplicate_module_permissions(): void {
global $DB;
$this->setAdminUser();
$this->resetAfterTest();

// Create course and course module.
$course = self::getDataGenerator()->create_course();
$res = self::getDataGenerator()->create_module('assign', ['course' => $course]);
$cm = get_coursemodule_from_id('assign', $res->cmid, 0, false, MUST_EXIST);
$cmcontext = \context_module::instance($cm->id);

// Enrol student user.
$user = self::getDataGenerator()->create_user();
$roleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST);
self::getDataGenerator()->enrol_user($user->id, $course->id, $roleid);

// Add capability to original course module.
assign_capability('gradereport/grader:view', CAP_ALLOW, $roleid, $cmcontext->id);

// Duplicate module.
$newcm = duplicate_module($course, $cm);
$newcmcontext = \context_module::instance($newcm->id);

// Assert that user still has capability.
$this->assertTrue(has_capability('gradereport/grader:view', $newcmcontext, $user));

// Assert that both modules contain the same count of overrides.
$overrides = $DB->get_records('role_capabilities', ['contextid' => $cmcontext->id]);
$newoverrides = $DB->get_records('role_capabilities', ['contextid' => $newcmcontext->id]);
$this->assertEquals(count($overrides), count($newoverrides));
}

/**
* Test that locally assigned roles are duplicated correctly after duplicate_module().
* @covers ::duplicate_module
* @return void
*/
public function test_duplicate_module_role_assignments(): void {
global $DB;
$this->setAdminUser();
$this->resetAfterTest();

// Create course and course module.
$course = self::getDataGenerator()->create_course();
$res = self::getDataGenerator()->create_module('assign', ['course' => $course]);
$cm = get_coursemodule_from_id('assign', $res->cmid, 0, false, MUST_EXIST);
$cmcontext = \context_module::instance($cm->id);

// Enrol student user.
$user = self::getDataGenerator()->create_user();
$roleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST);
self::getDataGenerator()->enrol_user($user->id, $course->id, $roleid);

// Assign user a new local role.
$newroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST);
role_assign($newroleid, $user->id, $cmcontext->id);

// Duplicate module.
$newcm = duplicate_module($course, $cm);
$newcmcontext = \context_module::instance($newcm->id);

// Assert that user still has role assigned.
$this->assertTrue(user_has_role_assignment($user->id, $newroleid, $newcmcontext->id));

// Assert that both modules contain the same count of overrides.
$overrides = $DB->get_records('role_assignments', ['contextid' => $cmcontext->id]);
$newoverrides = $DB->get_records('role_assignments', ['contextid' => $newcmcontext->id]);
$this->assertEquals(count($overrides), count($newoverrides));
}

/**
* Tests that when creating or updating a module, if the availability settings
* are present but set to an empty tree, availability is set to null in
Expand Down
62 changes: 62 additions & 0 deletions mod/assign/tests/behat/duplicate_permissions.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@mod @mod_assign
Feature: Duplicate assign activity module with permissions
In order to ensure that locally assigned roles and permissions are correctly duplicated
As a teacher
I need to add the roles and permissions and ensure they are correctly duplicated

Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student10@example.com |
| student2 | Student | 2 | student20@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activity" exists:
| activity | assign |
| course | C1 |
| name | Test assignment name |
| intro | Test assignment description |
| markingworkflow | 1 |
| submissiondrafts | 0 |

@javascript
Scenario: Add a locally assigned role and duplicate activity
Given I log in as "teacher 1"
And I am on "Course 1" course homepage with editing mode on

When I open "Test assignment name" actions menu
And I click on "Assign roles" "link" in the "Test assignment name" activity
And I click on "Non-editing teacher" "link"
And I click on "Student 2" "option"
And I click on "Add" "button"
And I am on "Course 1" course homepage with editing mode on
And I duplicate "Test assignment name" activity
Then I should see "Test assignment name (copy)"

And I open "Test assignment name (copy)" actions menu
And I click on "Assign roles" "link" in the "Test assignment name (copy)" activity
Then "Non-editing teacher" row "Users with role" column of "generaltable" table should contain "1"

@javascript
Scenario: Add a permission override to activity and duplicate
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| mod/assign:grade | Allow | student | 70 | Test assignment name |
And I log in as "admin"

When I am on "Course 1" course homepage with editing mode on
And I duplicate "Test assignment name" activity
Then I should see "Test assignment name (copy)"

And I open "Test assignment name (copy)" actions menu
And I click on "Edit settings" "link" in the "Test assignment name (copy)" activity
And I navigate to "Permissions" in current page administration
And I set the field "permissionscapabilitysearch" to "mod/assign:grade"
Then "Grade assignmentmod/assign:grade" row "Roles with permission" column of "permissions" table should contain "Student"

0 comments on commit 92564ac

Please sign in to comment.