diff --git a/admin/tool/uploaduser/classes/process.php b/admin/tool/uploaduser/classes/process.php index 45a7ba9fe0fd3..6ef4f854f97c8 100644 --- a/admin/tool/uploaduser/classes/process.php +++ b/admin/tool/uploaduser/classes/process.php @@ -228,6 +228,15 @@ protected function get_allow_deletes(): bool { return (!empty($this->formdata->uuallowdeletes) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC); } + /** + * Setting to allow matching user accounts on email + * @return bool + */ + protected function get_match_on_email(): bool { + $optype = $this->get_operation_type(); + return (!empty($this->formdata->uumatchemail) && $optype != UU_USER_ADDNEW && $optype != UU_USER_ADDINC); + } + /** * Setting to allow deletes * @return bool @@ -414,7 +423,7 @@ protected function prepare_user_record(array $line): ?\stdClass { } // Make sure we really have username. - if (empty($user->username)) { + if (empty($user->username) && !$this->get_match_on_email()) { $this->upt->track('status', get_string('missingfield', 'error', 'username'), 'error'); $this->upt->track('username', get_string('error'), 'error'); $this->userserrors++; @@ -453,7 +462,16 @@ public function process_line(array $line) { return; } - if ($existinguser = $DB->get_record('user', ['username' => $user->username, 'mnethostid' => $user->mnethostid])) { + $matchparam = $this->get_match_on_email() ? ['email' => $user->email] : ['username' => $user->username]; + if ($existinguser = $DB->get_records('user', $matchparam + ['mnethostid' => $user->mnethostid])) { + if (is_array($existinguser) && count($existinguser) !== 1) { + $this->upt->track('status', get_string('duplicateemail', 'tool_uploaduser', $user->email), 'warning'); + $this->userserrors++; + return; + + } + + $existinguser = is_array($existinguser) ? array_values($existinguser)[0] : $existinguser; $this->upt->track('id', $existinguser->id, 'normal', false); } @@ -582,6 +600,12 @@ public function process_line(array $line) { // We do not need the deleted flag anymore. unset($user->deleted); + $matchonemailallowrename = $this->get_match_on_email() && $this->get_allow_renames(); + if ($matchonemailallowrename && $user->username && ($user->username !== $existinguser->username)) { + $user->oldusername = $existinguser->username; + $existinguser = false; + } + // Renaming requested? if (!empty($user->oldusername) ) { if (!$this->get_allow_renames()) { diff --git a/admin/tool/uploaduser/lang/en/tool_uploaduser.php b/admin/tool/uploaduser/lang/en/tool_uploaduser.php index eb8cc3df6dafb..7c480398eb1f8 100644 --- a/admin/tool/uploaduser/lang/en/tool_uploaduser.php +++ b/admin/tool/uploaduser/lang/en/tool_uploaduser.php @@ -38,6 +38,7 @@ $string['csvdelimiter'] = 'CSV separator'; $string['defaultvalues'] = 'Default values'; $string['deleteerrors'] = 'Delete errors'; +$string['duplicateemail'] = 'Multiple users with email {$a} detected'; $string['encoding'] = 'Encoding'; $string['errormnetadd'] = 'Can not add remote users'; $string['errorprefix'] = 'Error:'; @@ -51,6 +52,7 @@ $string['invaliduserdata'] = 'Invalid data detected for user {$a} and it has been automatically cleaned.'; $string['invalidtheme'] = 'Theme "{$a}" is not installed and will be ignored.'; $string['linex'] = 'Line {$a}'; +$string['matchemail'] = 'Match on email address'; $string['nochanges'] = 'No changes'; $string['notheme'] = 'No theme is defined for this user.'; $string['pluginname'] = 'User upload'; diff --git a/admin/tool/uploaduser/tests/behat/upload_users.feature b/admin/tool/uploaduser/tests/behat/upload_users.feature index a7af0df214d98..065638994a985 100644 --- a/admin/tool/uploaduser/tests/behat/upload_users.feature +++ b/admin/tool/uploaduser/tests/behat/upload_users.feature @@ -258,3 +258,47 @@ Feature: Upload users And I select "Assign roles" from the "jump" singleselect And I should see "Course creator" And I should see "Federico Fellini" + + @javascript + Scenario: Update existing users matching them on email + Given the following "users" exist: + | username | firstname | lastname | email | + | bilbob | Blasbo | Blabbins | bilbo@example.com | + | frodob | Frodeo | Baspins | frodo@example.com | + 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_email_matching.csv" file to "File" filemanager + And I press "Upload users" + Then I should see "Upload users preview" + And I set the following fields to these values: + | Upload type | Update existing users only | + | Existing user details | Override with file | + | Match on email address | Yes | + And I press "Upload users" + And I press "Continue" + And I navigate to "Users > Accounts > Browse list of users" in site administration + And I should see "Bilbo Baggins" + And I should see "Frodo Baggins" + + @javascript + Scenario: Update existing users matching them on email where one email address is associated with multiple users + Given the following "users" exist: + | username | firstname | lastname | email | + | bilbob | Blasbo | Blabbins | bilbo@example.com | + | frodob | Frodeo | Baspins | frodo@example.com | + | fredob | Fredoo | Baspins | frodo@example.com | + 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_email_matching.csv" file to "File" filemanager + And I press "Upload users" + Then I should see "Upload users preview" + And I set the following fields to these values: + | Upload type | Update existing users only | + | Existing user details | Override with file | + | Match on email address | Yes | + And I press "Upload users" + And I should see "Multiple users with email frodo@example.com detected" + And I press "Continue" + And I navigate to "Users > Accounts > Browse list of users" in site administration + And I should see "Bilbo Baggins" + And I should not see "Frodo Baggins" diff --git a/admin/tool/uploaduser/user_form.php b/admin/tool/uploaduser/user_form.php index 66e2e819d166a..e6239094b95f2 100644 --- a/admin/tool/uploaduser/user_form.php +++ b/admin/tool/uploaduser/user_form.php @@ -139,6 +139,10 @@ function definition () { } $mform->addElement('select', 'uuforcepasswordchange', get_string('forcepasswordchange', 'core'), $choices); + $mform->addElement('selectyesno', 'uumatchemail', get_string('matchemail', 'tool_uploaduser')); + $mform->setDefault('uumatchemail', 0); + $mform->hideIf('uumatchemail', 'uutype', 'eq', UU_USER_ADDNEW); + $mform->hideIf('uumatchemail', 'uutype', 'eq', UU_USER_ADDINC); $mform->addElement('selectyesno', 'uuallowrenames', get_string('allowrenames', 'tool_uploaduser')); $mform->setDefault('uuallowrenames', 0); @@ -230,7 +234,6 @@ function definition () { $mform->addElement('text', 'username', get_string('uuusernametemplate', 'tool_uploaduser'), 'size="20"'); $mform->setType('username', PARAM_RAW); // No cleaning here. The process verifies it later. - $mform->addRule('username', get_string('requiredtemplate', 'tool_uploaduser'), 'required', null, 'client'); $mform->hideIf('username', 'uutype', 'eq', UU_USER_ADD_UPDATE); $mform->hideIf('username', 'uutype', 'eq', UU_USER_UPDATE); $mform->setForceLtr('username'); diff --git a/lib/tests/fixtures/upload_users_email_matching.csv b/lib/tests/fixtures/upload_users_email_matching.csv new file mode 100644 index 0000000000000..2fadab7408ce6 --- /dev/null +++ b/lib/tests/fixtures/upload_users_email_matching.csv @@ -0,0 +1,3 @@ +username,password,firstname,lastname,email,course1,group1 +bilbob,verysecret,Bilbo,Baggins,bilbo@example.com,math102,Section 1 +frodob,somesecret,Frodo,Baggins,frodo@example.com,math102,Section 3