diff --git a/admin/tool/uploaduser/classes/process.php b/admin/tool/uploaduser/classes/process.php index 70913f91cd9..45a7ba9fe0f 100644 --- a/admin/tool/uploaduser/classes/process.php +++ b/admin/tool/uploaduser/classes/process.php @@ -27,6 +27,9 @@ namespace tool_uploaduser; defined('MOODLE_INTERNAL') || die(); use context_system; +use context_coursecat; +use core_course_category; + use tool_uploaduser\local\field_value_validators; require_once($CFG->dirroot.'/user/profile/lib.php'); @@ -1107,6 +1110,48 @@ class process { continue; } + + if (preg_match('/^categoryrole(?\d+)$/', $column, $rolematches)) { + $categoryrolecache = []; + $categorycache = []; // Category cache - do not fetch all categories here, we will not probably use them all. + + $categoryfield = "category{$rolematches['roleid']}"; + $categoryrolefield = "categoryrole{$rolematches['roleid']}"; + + if (empty($user->{$categoryfield})) { + continue; + } + + $categoryidnumber = $user->{$categoryfield}; + + if (!array_key_exists($categoryidnumber, $categorycache)) { + $category = $DB->get_record('course_categories', ['idnumber' => $categoryidnumber], 'id, idnumber'); + if (empty($category)) { + $this->upt->track('enrolments', get_string('unknowncategory', 'error', s($categoryidnumber)), 'error'); + continue; + } + $categoryrolecache[$categoryidnumber] = uu_allowed_roles_cache($category->id); + $categoryobj = core_course_category::get($category->id); + $context = context_coursecat::instance($categoryobj->id); + $categorycache[$categoryidnumber] = $context; + } + // Check the user's category role. + if (!empty($user->{$categoryrolefield})) { + $rolename = $user->{$categoryrolefield}; + if (array_key_exists($rolename, $categoryrolecache[$categoryidnumber])) { + $roleid = $categoryrolecache[$categoryidnumber][$rolename]->id; + // Assign a role to user with category context. + role_assign($roleid, $user->id, $categorycache[$categoryidnumber]->id); + } else { + $this->upt->track('enrolments', get_string('unknownrole', 'error', s($rolename)), 'error'); + continue; + } + } else { + $this->upt->track('enrolments', get_string('missingcategoryrole', 'error', s($categoryidnumber)), 'error'); + continue; + } + } + if (!preg_match('/^course\d+$/', $column)) { continue; } diff --git a/admin/tool/uploaduser/locallib.php b/admin/tool/uploaduser/locallib.php index d79960b32b5..607f64bd004 100644 --- a/admin/tool/uploaduser/locallib.php +++ b/admin/tool/uploaduser/locallib.php @@ -202,6 +202,21 @@ function uu_validate_user_upload_columns(csv_import_reader $cir, $stdfields, $pr // test columns $processed = array(); + $acceptedfields = [ + 'category', + 'categoryrole', + 'cohort', + 'course', + 'enrolperiod', + 'enrolstatus', + 'enroltimestart', + 'group', + 'role', + 'sysrole', + 'type', + ]; + $specialfieldsregex = "/^(" . implode('|', $acceptedfields) . ")\d+$/"; + foreach ($columns as $key=>$unused) { $field = $columns[$key]; $field = trim($field); @@ -218,7 +233,7 @@ function uu_validate_user_upload_columns(csv_import_reader $cir, $stdfields, $pr // hack: somebody wrote uppercase in csv file, but the system knows only lowercase profile field $newfield = $lcfield; - } else if (preg_match('/^(sysrole|cohort|course|group|type|role|enrolperiod|enrolstatus|enroltimestart)\d+$/', $lcfield)) { + } else if (preg_match($specialfieldsregex, $lcfield)) { // special fields for enrolments $newfield = $lcfield; @@ -369,11 +384,17 @@ function uu_allowed_roles() { } /** - * Returns mapping of all roles using short role name as index. + * Returns mapping of roles using short role name as index. + * + * @param int|null $categoryid Id of the category to get roles for. Null means all roles. * @return array */ -function uu_allowed_roles_cache() { - $allowedroles = get_assignable_roles(context_course::instance(SITEID), ROLENAME_SHORT); +function uu_allowed_roles_cache(?int $categoryid = null): array { + if (is_null($categoryid)) { + $allowedroles = get_assignable_roles(context_course::instance(SITEID), ROLENAME_SHORT); + } else { + $allowedroles = get_assignable_roles(context_coursecat::instance($categoryid), ROLENAME_SHORT); + } $rolecache = []; foreach ($allowedroles as $rid=>$rname) { $rolecache[$rid] = new stdClass(); diff --git a/admin/tool/uploaduser/tests/behat/upload_users.feature b/admin/tool/uploaduser/tests/behat/upload_users.feature index ffe2e48b435..1253e5abe29 100644 --- a/admin/tool/uploaduser/tests/behat/upload_users.feature +++ b/admin/tool/uploaduser/tests/behat/upload_users.feature @@ -14,7 +14,7 @@ Feature: Upload users | Section 1 | math102 | S1 | | Section 3 | math102 | S3 | And I log in as "admin" - And I navigate to "Users > Accounts >Upload users" in site administration + And I navigate to "Users > Accounts > Upload users" in site administration When I upload "lib/tests/fixtures/upload_users.csv" file to "File" filemanager And I press "Upload users" Then I should see "Upload users preview" @@ -186,3 +186,77 @@ Feature: Upload users And I should see "12 January 2020" in the "Enrolment ends" "table_row" And I click on "Close" "button" in the "Enrolment details" "dialogue" And I log out + + @javascript + Scenario: Upload users enrolling them on courses and assign category roles + Given the following "courses" exist: + | fullname | shortname | + | management1 | management1 | + | film1 | film1 | + And the following "categories" exist: + | name | idnumber | + | MGMT | MGMT | + | Film | Film | + And I log in as "admin" + And I navigate to "Users > Accounts > Upload users" in site administration + When I upload "lib/tests/fixtures/upload_users_category.csv" file to "File" filemanager + And I press "Upload users" + Then I should see "Upload users preview" + And I should see "Tom" + And I should see "Jones" + And I should see "Trent" + And I should see "Reznor" + And I should see "Aurora" + And I should see "Jiang" + And I should see "Federico" + And I should see "Fellini" + And I should see "Ivan" + And I should see "Ivanov" + And I should see "John" + And I should see "Smith" + And I should see "Warm" + And I should see "Cool" + And I should see "James" + And I should see "Bond" + And I should see "MGMT" + And I should see "Film" + And I should see "manager" + And I should see "student" + And I should see "coursecreator" + And I should see "management1" + And I should see "film1" + And I press "Upload users" + And I should see "Unknown category with category ID number \"Movie\"" + And I should see "Unknown course named \"movie1\"" + And I should see "Unknown role \"notcoursecreator\"" + And I should see "Could not assign role to user: missing role for category" + And I press "Continue" + And I navigate to "Users > Accounts > Browse list of users" in site administration + And I should see "Tom Jones" + And I should see "Trent Reznor" + And I should see "reznor@example.com" + And I am on "management1" course homepage + And I should see "Participants" + And I follow "Participants" + And I should see "Tom Jones" + And I should see "Trent Reznor" + And I should see "Aurora Jiang" + And I should see "Student" + And I am on "film1" course homepage + And I should see "Participants" + And I follow "Participants" + And I should see "Federico Fellini" + And I should see "Student" + And I navigate to "Courses > Manage courses and categories" in site administration + And I click on "permissions" action for "MGMT" in management category listing + And I select "Assign roles" from the "jump" singleselect + And I should see "Manager" + And I should see "Tom Jones" + And I should see "Trent Reznor" + And I should see "Course creator" + And I should see "Aurora Jiang" + And I navigate to "Courses > Manage courses and categories" in site administration + And I click on "permissions" action for "Film" in management category listing + And I select "Assign roles" from the "jump" singleselect + And I should see "Course creator" + And I should see "Federico Fellini" diff --git a/lang/en/error.php b/lang/en/error.php index 3649ebc8aed..da5e7b2e221 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -404,6 +404,7 @@ $string['messageundeliveredbynotificationsettings'] = 'The message could not be $string['messagingdisable'] = 'Messaging is disabled on this site'; $string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to obtain the C source from https://www.forkosh.com/mimetex.zip, compile it and put the executable into your moodle/filter/tex/ directory.'; $string['mimetexnotexecutable'] = 'Custom mimetex is not executable!'; +$string['missingcategoryrole'] = 'Could not assign role to user: missing role for category.'; $string['missingfield'] = 'Field "{$a}" is missing'; $string['missingkeyinsql'] = 'ERROR: missing param "{$a}" in query'; $string['missingparam'] = 'A required parameter ({$a}) was missing'; @@ -566,6 +567,7 @@ $string['unknowcontext'] = 'This is an unknown context ({$a}) in get_child_conte $string['unknowformat'] = 'Format not known ({$a})'; $string['unknownbackupexporterror'] = 'Unknown error preparing information for import'; $string['unknownblockregion'] = 'The block region \'{$a}\' is not recognised on this page.'; +$string['unknowncategory'] = 'Unknown category with category ID number "{$a}"'; $string['unknowncontext'] = 'This is an unknown context.'; $string['unknowncourse'] = 'Unknown course named "{$a}"'; $string['unknowncourseidnumber'] = 'Unknown course ID "{$a}"'; diff --git a/lib/tests/fixtures/upload_users_category.csv b/lib/tests/fixtures/upload_users_category.csv new file mode 100644 index 00000000000..4ee63e5c697 --- /dev/null +++ b/lib/tests/fixtures/upload_users_category.csv @@ -0,0 +1,9 @@ +username,password,firstname,lastname,email,category1,categoryrole1,course1,role1 +jonest,verysecret,Tom,Jones,jonest@example.com,MGMT,manager,management1,student +reznor,somesecret,Trent,Reznor,reznor@example.com,MGMT,manager,management1,student +aurora,topsecret,Aurora,Jiang,aurora@example.com,MGMT,coursecreator,management1,student +fellini,mysecret,Federico,Fellini,fellini@example.com,Film,coursecreator,film1,student +ivanov,secret,Ivan,Ivanov,ivanov@example.com,Film,notcoursecreator,film1,student +smith,notsecret,John,Smith,smith@example.com,Movie,coursecreator,movie1,student +cool,simplepass,Warm,Cool,cool@example.com,MGMT,,management1,student +bond,secret007,James,Bond,bond@example.com,,manager,management1,student \ No newline at end of file