MDL-40669 tool_uploaduser: allow emailstop to be set during upload.
[moodle.git] / admin / tool / uploaduser / index.php
CommitLineData
9e492db0 1<?php
8bdb31ed
PS
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
0a6150ca 16
8bdb31ed
PS
17/**
18 * Bulk user registration script from a comma separated file
19 *
ce15d56d
PS
20 * @package tool
21 * @subpackage uploaduser
8bdb31ed
PS
22 * @copyright 2004 onwards Martin Dougiamas (http://dougiamas.com)
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
0a6150ca 25
ce15d56d 26require('../../../config.php');
cc891abe 27require_once($CFG->libdir.'/adminlib.php');
e4e38544 28require_once($CFG->libdir.'/csvlib.class.php');
29require_once($CFG->dirroot.'/user/profile/lib.php');
bb78e249 30require_once($CFG->dirroot.'/user/lib.php');
59186c92 31require_once($CFG->dirroot.'/group/lib.php');
92b59a56 32require_once($CFG->dirroot.'/cohort/lib.php');
ce15d56d
PS
33require_once('locallib.php');
34require_once('user_form.php');
e6ce167b
MM
35require_once('classes/local/field_value_validators.php');
36use tool_uploaduser\local\field_value_validators;
1ae083e4 37
e4e38544 38$iid = optional_param('iid', '', PARAM_INT);
df7ecfe4 39$previewrows = optional_param('previewrows', 10, PARAM_INT);
066bfbfe 40
3ef7279f 41core_php_time_limit::raise(60*60); // 1 hour should be enough
8bdb31ed 42raise_memory_limit(MEMORY_HUGE);
0a6150ca 43
ce15d56d 44admin_externalpage_setup('tooluploaduser');
bf006d2c 45require_capability('moodle/site:uploadusers', context_system::instance());
0a6150ca 46
ce15d56d 47$struserrenamed = get_string('userrenamed', 'tool_uploaduser');
e4e38544 48$strusernotrenamedexists = get_string('usernotrenamedexists', 'error');
49$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error');
50$strusernotrenamedoff = get_string('usernotrenamedoff', 'error');
51$strusernotrenamedadmin = get_string('usernotrenamedadmin', 'error');
52
ce15d56d 53$struserupdated = get_string('useraccountupdated', 'tool_uploaduser');
e4e38544 54$strusernotupdated = get_string('usernotupdatederror', 'error');
55$strusernotupdatednotexists = get_string('usernotupdatednotexists', 'error');
56$strusernotupdatedadmin = get_string('usernotupdatedadmin', 'error');
57
ce15d56d 58$struseruptodate = get_string('useraccountuptodate', 'tool_uploaduser');
8bdb31ed 59
e4e38544 60$struseradded = get_string('newuser');
61$strusernotadded = get_string('usernotaddedregistered', 'error');
62$strusernotaddederror = get_string('usernotaddederror', 'error');
63
ce15d56d 64$struserdeleted = get_string('userdeleted', 'tool_uploaduser');
e4e38544 65$strusernotdeletederror = get_string('usernotdeletederror', 'error');
66$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error');
67$strusernotdeletedoff = get_string('usernotdeletedoff', 'error');
68$strusernotdeletedadmin = get_string('usernotdeletedadmin', 'error');
69
70$strcannotassignrole = get_string('cannotassignrole', 'error');
e4e38544 71
72$struserauthunsupported = get_string('userauthunsupported', 'error');
3fe2cfb5 73$stremailduplicate = get_string('useremailduplicate', 'error');
e4e38544 74
3f12c146 75$strinvalidpasswordpolicy = get_string('invalidpasswordpolicy', 'error');
e4e38544 76$errorstr = get_string('error');
ca23a9c9 77
08157bfe
PS
78$stryes = get_string('yes');
79$strno = get_string('no');
80$stryesnooptions = array(0=>$strno, 1=>$stryes);
81
ce15d56d 82$returnurl = new moodle_url('/admin/tool/uploaduser/index.php');
8bdb31ed 83$bulknurl = new moodle_url('/admin/user/user_bulk.php');
e4e38544 84
2a6dcb72
PS
85$today = time();
86$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
87
e4e38544 88// array of all valid fields for validation
c4e79fc6 89$STD_FIELDS = array('id', 'username', 'email', 'emailstop',
8bdb31ed 90 'city', 'country', 'lang', 'timezone', 'mailformat',
a80b5a0c 91 'maildisplay', 'maildigest', 'htmleditor', 'autosubscribe',
8bdb31ed 92 'institution', 'department', 'idnumber', 'skype',
6dbcacee 93 'msn', 'aim', 'yahoo', 'icq', 'phone1', 'phone2', 'address',
8bdb31ed
PS
94 'url', 'description', 'descriptionformat', 'password',
95 'auth', // watch out when changing auth type or using external auth plugins!
96 'oldusername', // use when renaming users - this is the original username
08157bfe 97 'suspended', // 1 means suspend user account, 0 means activate user account, nothing means keep as is for existing users
09df5975 98 'theme', // Define a theme for user when 'allowuserthemes' is enabled.
8bdb31ed 99 'deleted', // 1 means delete user
9dcae46d 100 'mnethostid', // Can not be used for adding, updating or deleting of users - only for enrolments, groups, cohorts and suspending.
3da0c3cb 101 'interests',
8bdb31ed 102 );
c00252fb 103// Include all name fields.
6f4ece9f 104$STD_FIELDS = array_merge($STD_FIELDS, get_all_user_name_fields());
e4e38544 105
106$PRF_FIELDS = array();
b650fe6a
RT
107if ($proffields = $DB->get_records('user_info_field')) {
108 foreach ($proffields as $key => $proffield) {
109 $profilefieldname = 'profile_field_'.$proffield->shortname;
110 $PRF_FIELDS[] = $profilefieldname;
111 // Re-index $proffields with key as shortname. This will be
112 // used while checking if profile data is key and needs to be converted (eg. menu profile field)
113 $proffields[$profilefieldname] = $proffield;
114 unset($proffields[$key]);
e4e38544 115 }
e4e38544 116}
117
118if (empty($iid)) {
8bdb31ed 119 $mform1 = new admin_uploaduser_form1();
0a6150ca 120
8bdb31ed 121 if ($formdata = $mform1->get_data()) {
e4e38544 122 $iid = csv_import_reader::get_new_iid('uploaduser');
123 $cir = new csv_import_reader($iid, 'uploaduser');
df7ecfe4 124
8bdb31ed
PS
125 $content = $mform1->get_file_content('userfile');
126
127 $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name);
a2071fbf 128 $csvloaderror = $cir->get_error();
e4e38544 129 unset($content);
df7ecfe4 130
a2071fbf
AG
131 if (!is_null($csvloaderror)) {
132 print_error('csvloaderror', '', $returnurl, $csvloaderror);
ed22a01b 133 }
8bdb31ed
PS
134 // test if columns ok
135 $filecolumns = uu_validate_user_upload_columns($cir, $STD_FIELDS, $PRF_FIELDS, $returnurl);
e4e38544 136 // continue to form2
df7ecfe4 137
138 } else {
61ef8f9f 139 echo $OUTPUT->header();
9e492db0 140
ce15d56d 141 echo $OUTPUT->heading_with_help(get_string('uploadusers', 'tool_uploaduser'), 'uploadusers', 'tool_uploaduser');
9e492db0 142
8bdb31ed 143 $mform1->display();
73d6f52f 144 echo $OUTPUT->footer();
df7ecfe4 145 die;
146 }
e4e38544 147} else {
148 $cir = new csv_import_reader($iid, 'uploaduser');
8bdb31ed 149 $filecolumns = uu_validate_user_upload_columns($cir, $STD_FIELDS, $PRF_FIELDS, $returnurl);
df7ecfe4 150}
151
8bdb31ed 152$mform2 = new admin_uploaduser_form2(null, array('columns'=>$filecolumns, 'data'=>array('iid'=>$iid, 'previewrows'=>$previewrows)));
df7ecfe4 153
154// If a file has been uploaded, then process it
8bdb31ed 155if ($formdata = $mform2->is_cancelled()) {
e4e38544 156 $cir->cleanup(true);
157 redirect($returnurl);
df7ecfe4 158
8bdb31ed 159} else if ($formdata = $mform2->get_data()) {
df7ecfe4 160 // Print the header
61ef8f9f 161 echo $OUTPUT->header();
ce15d56d 162 echo $OUTPUT->heading(get_string('uploadusersresult', 'tool_uploaduser'));
e4e38544 163
164 $optype = $formdata->uutype;
165
0c4807ab 166 $updatetype = isset($formdata->uuupdatetype) ? $formdata->uuupdatetype : 0;
8bdb31ed
PS
167 $createpasswords = (!empty($formdata->uupasswordnew) and $optype != UU_USER_UPDATE);
168 $updatepasswords = (!empty($formdata->uupasswordold) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC and ($updatetype == UU_UPDATE_FILEOVERRIDE or $updatetype == UU_UPDATE_ALLOVERRIDE));
169 $allowrenames = (!empty($formdata->uuallowrenames) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC);
170 $allowdeletes = (!empty($formdata->uuallowdeletes) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC);
08157bfe 171 $allowsuspends = (!empty($formdata->uuallowsuspends));
0c4807ab 172 $bulk = $formdata->uubulk;
95020832 173 $noemailduplicates = empty($CFG->allowaccountssameemail) ? 1 : $formdata->uunoemailduplicates;
8bdb31ed
PS
174 $standardusernames = $formdata->uustandardusernames;
175 $resetpasswords = isset($formdata->uuforcepasswordchange) ? $formdata->uuforcepasswordchange : UU_PWRESET_NONE;
e4e38544 176
177 // verification moved to two places: after upload and into form2
8bdb31ed
PS
178 $usersnew = 0;
179 $usersupdated = 0;
180 $usersuptodate = 0; //not printed yet anywhere
181 $userserrors = 0;
182 $deletes = 0;
183 $deleteerrors = 0;
184 $renames = 0;
185 $renameerrors = 0;
186 $usersskipped = 0;
d6bb2d2f 187 $weakpasswords = 0;
feecd4d6 188
e4e38544 189 // caches
8bdb31ed 190 $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway!
92b59a56 191 $cohorts = array();
2a34360e
SP
192 $rolecache = uu_allowed_roles_cache(); // Course roles lookup cache.
193 $sysrolecache = uu_allowed_sysroles_cache(); // System roles lookup cache.
8bdb31ed
PS
194 $manualcache = array(); // cache of used manual enrol plugins in each course
195 $supportedauths = uu_supported_auths(); // officially supported plugins that are enabled
e4e38544 196
df997f84
PS
197 // we use only manual enrol plugin here, if it is disabled no enrol is done
198 if (enrol_is_enabled('manual')) {
199 $manual = enrol_get_plugin('manual');
200 } else {
201 $manual = NULL;
e4e38544 202 }
df7ecfe4 203
b4bd91ce 204 // clear bulk selection
e4e38544 205 if ($bulk) {
cd1edf9e 206 $SESSION->bulk_users = array();
e4e38544 207 }
df7ecfe4 208
e4e38544 209 // init csv import helper
210 $cir->init();
211 $linenum = 1; //column header is first line
df7ecfe4 212
e4e38544 213 // init upload progress tracker
214 $upt = new uu_progress_tracker();
8bdb31ed 215 $upt->start(); // start table
94a578af 216 $validation = array();
e4e38544 217 while ($line = $cir->next()) {
218 $upt->flush();
219 $linenum++;
220
221 $upt->track('line', $linenum);
222
a226a972 223 $user = new stdClass();
8bdb31ed 224
e4e38544 225 // add fields to user object
8bdb31ed
PS
226 foreach ($line as $keynum => $value) {
227 if (!isset($filecolumns[$keynum])) {
228 // this should not happen
229 continue;
230 }
231 $key = $filecolumns[$keynum];
232 if (strpos($key, 'profile_field_') === 0) {
233 //NOTE: bloody mega hack alert!!
234 if (isset($USER->$key) and is_array($USER->$key)) {
235 // this must be some hacky field that is abusing arrays to store content and format
236 $user->$key = array();
83bef8da
MG
237 $user->{$key['text']} = $value;
238 $user->{$key['format']} = FORMAT_MOODLE;
8bdb31ed 239 } else {
7ca44a49 240 $user->$key = trim($value);
e4e38544 241 }
c3231d1d 242 } else {
7ca44a49 243 $user->$key = trim($value);
a7db355a 244 }
e4e38544 245
8bdb31ed
PS
246 if (in_array($key, $upt->columns)) {
247 // default value in progress tracking table, can be changed later
248 $upt->track($key, s($value), 'normal');
e4e38544 249 }
8bdb31ed
PS
250 }
251 if (!isset($user->username)) {
ce8df92d 252 // prevent warnings below
8bdb31ed
PS
253 $user->username = '';
254 }
e4e38544 255
8bdb31ed
PS
256 if ($optype == UU_USER_ADDNEW or $optype == UU_USER_ADDINC) {
257 // user creation is a special case - the username may be constructed from templates using firstname and lastname
258 // better never try this in mixed update types
e4e38544 259 $error = false;
e4e38544 260 if (!isset($user->firstname) or $user->firstname === '') {
261 $upt->track('status', get_string('missingfield', 'error', 'firstname'), 'error');
262 $upt->track('firstname', $errorstr, 'error');
263 $error = true;
264 }
265 if (!isset($user->lastname) or $user->lastname === '') {
266 $upt->track('status', get_string('missingfield', 'error', 'lastname'), 'error');
267 $upt->track('lastname', $errorstr, 'error');
268 $error = true;
269 }
270 if ($error) {
271 $userserrors++;
272 continue;
273 }
274 // we require username too - we might use template for it though
8bdb31ed
PS
275 if (empty($user->username) and !empty($formdata->username)) {
276 $user->username = uu_process_template($formdata->username, $user);
277 $upt->track('username', s($user->username));
e4e38544 278 }
a7db355a 279 }
e4e38544 280
281 // normalize username
8bdb31ed
PS
282 $originalusername = $user->username;
283 if ($standardusernames) {
ac9768fc 284 $user->username = core_user::clean_field($user->username, 'username');
8bdb31ed 285 }
07ed083e 286
8bdb31ed 287 // make sure we really have username
e4e38544 288 if (empty($user->username)) {
289 $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
290 $upt->track('username', $errorstr, 'error');
291 $userserrors++;
292 continue;
8bdb31ed
PS
293 } else if ($user->username === 'guest') {
294 $upt->track('status', get_string('guestnoeditprofileother', 'error'), 'error');
295 $userserrors++;
296 continue;
e4e38544 297 }
9dcae46d 298
ac9768fc 299 if ($user->username !== core_user::clean_field($user->username, 'username')) {
7bf99ee5
AA
300 $upt->track('status', get_string('invalidusername', 'error', 'username'), 'error');
301 $upt->track('username', $errorstr, 'error');
302 $userserrors++;
303 }
397ccf13 304
9dcae46d
PS
305 if (empty($user->mnethostid)) {
306 $user->mnethostid = $CFG->mnet_localhost_id;
307 }
308
309 if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$user->mnethostid))) {
e4e38544 310 $upt->track('id', $existinguser->id, 'normal', false);
311 }
312
9dcae46d
PS
313 if ($user->mnethostid == $CFG->mnet_localhost_id) {
314 $remoteuser = false;
315
316 // Find out if username incrementing required.
317 if ($existinguser and $optype == UU_USER_ADDINC) {
318 $user->username = uu_increment_username($user->username);
319 $existinguser = false;
320 }
321
322 } else {
323 if (!$existinguser or $optype == UU_USER_ADDINC) {
324 $upt->track('status', get_string('errormnetadd', 'tool_uploaduser'), 'error');
325 $userserrors++;
326 continue;
327 }
328
329 $remoteuser = true;
330
331 // Make sure there are no changes of existing fields except the suspended status.
332 foreach ((array)$existinguser as $k => $v) {
333 if ($k === 'suspended') {
334 continue;
335 }
336 if (property_exists($user, $k)) {
337 $user->$k = $v;
338 }
339 if (in_array($k, $upt->columns)) {
340 if ($k === 'password' or $k === 'oldusername' or $k === 'deleted') {
341 $upt->track($k, '', 'normal', false);
342 } else {
343 $upt->track($k, s($v), 'normal', false);
344 }
345 }
346 }
347 unset($user->oldusername);
348 unset($user->password);
349 $user->auth = $existinguser->auth;
e4e38544 350 }
351
8bdb31ed
PS
352 // notify about nay username changes
353 if ($originalusername !== $user->username) {
354 $upt->track('username', '', 'normal', false); // clear previous
355 $upt->track('username', s($originalusername).'-->'.s($user->username), 'info');
356 } else {
357 $upt->track('username', s($user->username), 'normal', false);
358 }
359
e6ce167b 360 // Verify if the theme is valid and allowed to be set.
09df5975 361 if (isset($user->theme)) {
e6ce167b
MM
362 list($status, $message) = field_value_validators::validate_theme($user->theme);
363 if ($status !== 'normal' && !empty($message)) {
364 $upt->track('status', $message, $status);
365 // Unset the theme when validation fails.
366 unset($user->theme);
09df5975
DNA
367 }
368 }
369
e4e38544 370 // add default values for remaining fields
8bdb31ed 371 $formdefaults = array();
1744570b 372 if (!$existinguser || ($updatetype != UU_UPDATE_FILEOVERRIDE && $updatetype != UU_UPDATE_NOCHANGES)) {
f85800f3
MN
373 foreach ($STD_FIELDS as $field) {
374 if (isset($user->$field)) {
375 continue;
376 }
377 // all validation moved to form2
378 if (isset($formdata->$field)) {
379 // process templates
380 $user->$field = uu_process_template($formdata->$field, $user);
381 $formdefaults[$field] = true;
382 if (in_array($field, $upt->columns)) {
383 $upt->track($field, s($user->$field), 'normal');
384 }
43070e61 385 }
e4e38544 386 }
f85800f3
MN
387 foreach ($PRF_FIELDS as $field) {
388 if (isset($user->$field)) {
389 continue;
b650fe6a 390 }
f85800f3
MN
391 if (isset($formdata->$field)) {
392 // process templates
393 $user->$field = uu_process_template($formdata->$field, $user);
394
395 // Form contains key and later code expects value.
396 // Convert key to value for required profile fields.
397 require_once($CFG->dirroot.'/user/profile/field/'.$proffields[$field]->datatype.'/field.class.php');
398 $profilefieldclass = 'profile_field_'.$proffields[$field]->datatype;
399 $profilefield = new $profilefieldclass($proffields[$field]->id);
400 if (method_exists($profilefield, 'convert_external_data')) {
401 $user->$field = $profilefield->edit_save_data_preprocess($user->$field, null);
402 }
b650fe6a 403
f85800f3
MN
404 $formdefaults[$field] = true;
405 }
e4e38544 406 }
407 }
408
409 // delete user
410 if (!empty($user->deleted)) {
9dcae46d 411 if (!$allowdeletes or $remoteuser) {
e4e38544 412 $usersskipped++;
413 $upt->track('status', $strusernotdeletedoff, 'warning');
414 continue;
415 }
416 if ($existinguser) {
4f0c2d00 417 if (is_siteadmin($existinguser->id)) {
e4e38544 418 $upt->track('status', $strusernotdeletedadmin, 'error');
419 $deleteerrors++;
420 continue;
421 }
422 if (delete_user($existinguser)) {
423 $upt->track('status', $struserdeleted);
424 $deletes++;
425 } else {
426 $upt->track('status', $strusernotdeletederror, 'error');
427 $deleteerrors++;
6b09974b 428 }
e4e38544 429 } else {
430 $upt->track('status', $strusernotdeletedmissing, 'error');
431 $deleteerrors++;
432 }
433 continue;
434 }
435 // we do not need the deleted flag anymore
436 unset($user->deleted);
437
438 // renaming requested?
439 if (!empty($user->oldusername) ) {
e4e38544 440 if (!$allowrenames) {
441 $usersskipped++;
442 $upt->track('status', $strusernotrenamedoff, 'warning');
443 continue;
444 }
445
446 if ($existinguser) {
447 $upt->track('status', $strusernotrenamedexists, 'error');
448 $renameerrors++;
449 continue;
16a1fed4 450 }
ed22a01b 451
8bdb31ed
PS
452 if ($user->username === 'guest') {
453 $upt->track('status', get_string('guestnoeditprofileother', 'error'), 'error');
454 $renameerrors++;
455 continue;
456 }
457
458 if ($standardusernames) {
ac9768fc 459 $oldusername = core_user::clean_field($user->oldusername, 'username');
8bdb31ed
PS
460 } else {
461 $oldusername = $user->oldusername;
462 }
463
464 // no guessing when looking for old username, it must be exact match
465 if ($olduser = $DB->get_record('user', array('username'=>$oldusername, 'mnethostid'=>$CFG->mnet_localhost_id))) {
e4e38544 466 $upt->track('id', $olduser->id, 'normal', false);
4f0c2d00 467 if (is_siteadmin($olduser->id)) {
e4e38544 468 $upt->track('status', $strusernotrenamedadmin, 'error');
469 $renameerrors++;
a7db355a 470 continue;
0063abee 471 }
df997f84
PS
472 $DB->set_field('user', 'username', $user->username, array('id'=>$olduser->id));
473 $upt->track('username', '', 'normal', false); // clear previous
8bdb31ed 474 $upt->track('username', s($oldusername).'-->'.s($user->username), 'info');
df997f84
PS
475 $upt->track('status', $struserrenamed);
476 $renames++;
e4e38544 477 } else {
478 $upt->track('status', $strusernotrenamedmissing, 'error');
479 $renameerrors++;
480 continue;
481 }
482 $existinguser = $olduser;
483 $existinguser->username = $user->username;
484 }
485
486 // can we process with update or insert?
487 $skip = false;
488 switch ($optype) {
8bdb31ed 489 case UU_USER_ADDNEW:
e4e38544 490 if ($existinguser) {
491 $usersskipped++;
492 $upt->track('status', $strusernotadded, 'warning');
3fe2cfb5 493 $skip = true;
e4e38544 494 }
495 break;
496
8bdb31ed 497 case UU_USER_ADDINC:
e4e38544 498 if ($existinguser) {
499 //this should not happen!
500 $upt->track('status', $strusernotaddederror, 'error');
501 $userserrors++;
8bdb31ed 502 $skip = true;
e4e38544 503 }
504 break;
505
8bdb31ed 506 case UU_USER_ADD_UPDATE:
e4e38544 507 break;
508
8bdb31ed 509 case UU_USER_UPDATE:
e4e38544 510 if (!$existinguser) {
511 $usersskipped++;
512 $upt->track('status', $strusernotupdatednotexists, 'warning');
513 $skip = true;
514 }
515 break;
8bdb31ed
PS
516
517 default:
518 // unknown type
519 $skip = true;
e4e38544 520 }
521
522 if ($skip) {
523 continue;
524 }
525
526 if ($existinguser) {
527 $user->id = $existinguser->id;
528
8bdb31ed 529 $upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$existinguser->id)), s($existinguser->username)), 'normal', false);
08157bfe 530 $upt->track('suspended', $stryesnooptions[$existinguser->suspended] , 'normal', false);
628e9b20 531 $upt->track('auth', $existinguser->auth, 'normal', false);
8bdb31ed 532
4f0c2d00 533 if (is_siteadmin($user->id)) {
e4e38544 534 $upt->track('status', $strusernotupdatedadmin, 'error');
535 $userserrors++;
536 continue;
537 }
538
8bdb31ed
PS
539 $existinguser->timemodified = time();
540 // do NOT mess with timecreated or firstaccess here!
541
542 //load existing profile data
543 profile_load_data($existinguser);
3fe2cfb5 544
8bdb31ed 545 $doupdate = false;
08157bfe 546 $dologout = false;
8bdb31ed 547
9dcae46d 548 if ($updatetype != UU_UPDATE_NOCHANGES and !$remoteuser) {
8bdb31ed
PS
549 if (!empty($user->auth) and $user->auth !== $existinguser->auth) {
550 $upt->track('auth', s($existinguser->auth).'-->'.s($user->auth), 'info', false);
551 $existinguser->auth = $user->auth;
552 if (!isset($supportedauths[$user->auth])) {
553 $upt->track('auth', $struserauthunsupported, 'warning');
554 }
df833016 555 $doupdate = true;
08157bfe
PS
556 if ($existinguser->auth === 'nologin') {
557 $dologout = true;
558 }
e4e38544 559 }
8bdb31ed
PS
560 $allcolumns = array_merge($STD_FIELDS, $PRF_FIELDS);
561 foreach ($allcolumns as $column) {
08157bfe 562 if ($column === 'username' or $column === 'password' or $column === 'auth' or $column === 'suspended') {
8bdb31ed 563 // these can not be changed here
e4e38544 564 continue;
565 }
8bdb31ed 566 if (!property_exists($user, $column) or !property_exists($existinguser, $column)) {
8bdb31ed
PS
567 continue;
568 }
569 if ($updatetype == UU_UPDATE_MISSING) {
570 if (!is_null($existinguser->$column) and $existinguser->$column !== '') {
e4e38544 571 continue;
a7db355a 572 }
8bdb31ed
PS
573 } else if ($updatetype == UU_UPDATE_ALLOVERRIDE) {
574 // we override everything
3f12c146 575
8bdb31ed
PS
576 } else if ($updatetype == UU_UPDATE_FILEOVERRIDE) {
577 if (!empty($formdefaults[$column])) {
578 // do not override with form defaults
579 continue;
580 }
581 }
582 if ($existinguser->$column !== $user->$column) {
583 if ($column === 'email') {
92cec53b 584 $select = $DB->sql_like('email', ':email', false, true, false, '|');
585 $params = array('email' => $DB->sql_like_escape($user->email, '|'));
586 if ($DB->record_exists_select('user', $select , $params)) {
587
588 $changeincase = core_text::strtolower($existinguser->$column) === core_text::strtolower(
589 $user->$column);
590
591 if ($changeincase) {
592 // If only case is different then switch to lower case and carry on.
593 $user->$column = core_text::strtolower($user->$column);
594 continue;
595 } else if ($noemailduplicates) {
8bdb31ed
PS
596 $upt->track('email', $stremailduplicate, 'error');
597 $upt->track('status', $strusernotupdated, 'error');
598 $userserrors++;
599 continue 2;
600 } else {
601 $upt->track('email', $stremailduplicate, 'warning');
3f12c146
RW
602 }
603 }
8bdb31ed
PS
604 if (!validate_email($user->email)) {
605 $upt->track('email', get_string('invalidemail'), 'warning');
e4e38544 606 }
8bdb31ed 607 }
3f12c146 608
4d3cd148
PS
609 if ($column === 'lang') {
610 if (empty($user->lang)) {
611 // Do not change to not-set value.
612 continue;
ac9768fc 613 } else if (core_user::clean_field($user->lang, 'lang') === '') {
4d3cd148
PS
614 $upt->track('status', get_string('cannotfindlang', 'error', $user->lang), 'warning');
615 continue;
616 }
617 }
618
8bdb31ed
PS
619 if (in_array($column, $upt->columns)) {
620 $upt->track($column, s($existinguser->$column).'-->'.s($user->$column), 'info', false);
a7db355a 621 }
8bdb31ed
PS
622 $existinguser->$column = $user->$column;
623 $doupdate = true;
6b09974b 624 }
a7db355a 625 }
8bdb31ed 626 }
ed22a01b 627
8bdb31ed 628 try {
3f12c146 629 $auth = get_auth_plugin($existinguser->auth);
8bdb31ed
PS
630 } catch (Exception $e) {
631 $upt->track('auth', get_string('userautherror', 'error', s($existinguser->auth)), 'error');
632 $upt->track('status', $strusernotupdated, 'error');
633 $userserrors++;
634 continue;
635 }
636 $isinternalauth = $auth->is_internal();
3f12c146 637
08157bfe
PS
638 // deal with suspending and activating of accounts
639 if ($allowsuspends and isset($user->suspended) and $user->suspended !== '') {
640 $user->suspended = $user->suspended ? 1 : 0;
641 if ($existinguser->suspended != $user->suspended) {
642 $upt->track('suspended', '', 'normal', false);
643 $upt->track('suspended', $stryesnooptions[$existinguser->suspended].'-->'.$stryesnooptions[$user->suspended], 'info', false);
644 $existinguser->suspended = $user->suspended;
645 $doupdate = true;
646 if ($existinguser->suspended) {
647 $dologout = true;
648 }
649 }
650 }
651
8bdb31ed
PS
652 // changing of passwords is a special case
653 // do not force password changes for external auth plugins!
654 $oldpw = $existinguser->password;
9dcae46d
PS
655
656 if ($remoteuser) {
657 // Do not mess with passwords of remote users.
658
659 } else if (!$isinternalauth) {
ec2d8ceb 660 $existinguser->password = AUTH_PASSWORD_NOT_CACHED;
8bdb31ed
PS
661 $upt->track('password', '-', 'normal', false);
662 // clean up prefs
663 unset_user_preference('create_password', $existinguser);
664 unset_user_preference('auth_forcepasswordchange', $existinguser);
665
666 } else if (!empty($user->password)) {
667 if ($updatepasswords) {
ec2d8ceb
SC
668 // Check for passwords that we want to force users to reset next
669 // time they log in.
8bdb31ed 670 $errmsg = null;
ad9c96e5 671 $weak = !check_password_policy($user->password, $errmsg, $user);
8bdb31ed
PS
672 if ($resetpasswords == UU_PWRESET_ALL or ($resetpasswords == UU_PWRESET_WEAK and $weak)) {
673 if ($weak) {
674 $weakpasswords++;
675 $upt->track('password', $strinvalidpasswordpolicy, 'warning');
676 }
677 set_user_preference('auth_forcepasswordchange', 1, $existinguser);
678 } else {
679 unset_user_preference('auth_forcepasswordchange', $existinguser);
680 }
681 unset_user_preference('create_password', $existinguser); // no need to create password any more
ec2d8ceb
SC
682
683 // Use a low cost factor when generating bcrypt hash otherwise
684 // hashing would be slow when uploading lots of users. Hashes
685 // will be automatically updated to a higher cost factor the first
686 // time the user logs in.
687 $existinguser->password = hash_internal_user_password($user->password, true);
2197b642 688 $upt->track('password', $user->password, 'normal', false);
3f12c146 689 } else {
8bdb31ed
PS
690 // do not print password when not changed
691 $upt->track('password', '', 'normal', false);
3f12c146 692 }
8bdb31ed 693 }
3f12c146 694
8bdb31ed 695 if ($doupdate or $existinguser->password !== $oldpw) {
bb78e249 696 // We want only users that were really updated.
9363073b 697 user_update_user($existinguser, false, false);
3f12c146 698
df997f84
PS
699 $upt->track('status', $struserupdated);
700 $usersupdated++;
9dcae46d
PS
701
702 if (!$remoteuser) {
703 // pre-process custom profile menu fields data from csv file
704 $existinguser = uu_pre_process_custom_profile_data($existinguser);
705 // save custom profile fields data from csv file
706 profile_save_data($existinguser);
707 }
e6f74ba3 708
8bdb31ed
PS
709 if ($bulk == UU_BULK_UPDATED or $bulk == UU_BULK_ALL) {
710 if (!in_array($user->id, $SESSION->bulk_users)) {
711 $SESSION->bulk_users[] = $user->id;
712 }
713 }
714
9363073b
RT
715 // Trigger event.
716 \core\event\user_updated::create_from_userid($existinguser->id)->trigger();
717
8bdb31ed
PS
718 } else {
719 // no user information changed
720 $upt->track('status', $struseruptodate);
721 $usersuptodate++;
722
723 if ($bulk == UU_BULK_ALL) {
724 if (!in_array($user->id, $SESSION->bulk_users)) {
725 $SESSION->bulk_users[] = $user->id;
726 }
ed22a01b 727 }
066bfbfe 728 }
ed22a01b 729
08157bfe 730 if ($dologout) {
d79d5ac2 731 \core\session\manager::kill_user_sessions($existinguser->id);
08157bfe
PS
732 }
733
e4e38544 734 } else {
8bdb31ed
PS
735 // save the new user to the database
736 $user->confirmed = 1;
a7db355a 737 $user->timemodified = time();
8bdb31ed
PS
738 $user->timecreated = time();
739 $user->mnethostid = $CFG->mnet_localhost_id; // we support ONLY local accounts here, sorry
066bfbfe 740
08157bfe
PS
741 if (!isset($user->suspended) or $user->suspended === '') {
742 $user->suspended = 0;
743 } else {
744 $user->suspended = $user->suspended ? 1 : 0;
745 }
746 $upt->track('suspended', $stryesnooptions[$user->suspended], 'normal', false);
747
8bdb31ed 748 if (empty($user->auth)) {
3f12c146
RW
749 $user->auth = 'manual';
750 }
8bdb31ed 751 $upt->track('auth', $user->auth, 'normal', false);
3f12c146 752
8bdb31ed
PS
753 // do not insert record if new auth plugin does not exist!
754 try {
755 $auth = get_auth_plugin($user->auth);
756 } catch (Exception $e) {
757 $upt->track('auth', get_string('userautherror', 'error', s($user->auth)), 'error');
758 $upt->track('status', $strusernotaddederror, 'error');
759 $userserrors++;
760 continue;
e4e38544 761 }
8bdb31ed
PS
762 if (!isset($supportedauths[$user->auth])) {
763 $upt->track('auth', $struserauthunsupported, 'warning');
066bfbfe 764 }
a2ce7344 765
8bdb31ed
PS
766 $isinternalauth = $auth->is_internal();
767
43070e61
PS
768 if (empty($user->email)) {
769 $upt->track('email', get_string('invalidemail'), 'error');
770 $upt->track('status', $strusernotaddederror, 'error');
771 $userserrors++;
772 continue;
773
774 } else if ($DB->record_exists('user', array('email'=>$user->email))) {
0c4807ab 775 if ($noemailduplicates) {
776 $upt->track('email', $stremailduplicate, 'error');
777 $upt->track('status', $strusernotaddederror, 'error');
778 $userserrors++;
779 continue;
780 } else {
781 $upt->track('email', $stremailduplicate, 'warning');
782 }
783 }
8bdb31ed
PS
784 if (!validate_email($user->email)) {
785 $upt->track('email', get_string('invalidemail'), 'warning');
3f12c146 786 }
0c4807ab 787
4d3cd148
PS
788 if (empty($user->lang)) {
789 $user->lang = '';
ac9768fc 790 } else if (core_user::clean_field($user->lang, 'lang') === '') {
4d3cd148
PS
791 $upt->track('status', get_string('cannotfindlang', 'error', $user->lang), 'warning');
792 $user->lang = '';
793 }
794
8bdb31ed
PS
795 $forcechangepassword = false;
796
797 if ($isinternalauth) {
798 if (empty($user->password)) {
799 if ($createpasswords) {
800 $user->password = 'to be generated';
801 $upt->track('password', '', 'normal', false);
ce15d56d 802 $upt->track('password', get_string('uupasswordcron', 'tool_uploaduser'), 'warning', false);
8bdb31ed
PS
803 } else {
804 $upt->track('password', '', 'normal', false);
805 $upt->track('password', get_string('missingfield', 'error', 'password'), 'error');
806 $upt->track('status', $strusernotaddederror, 'error');
807 $userserrors++;
808 continue;
809 }
3f12c146 810 } else {
8bdb31ed 811 $errmsg = null;
ad9c96e5 812 $weak = !check_password_policy($user->password, $errmsg, $user);
8bdb31ed
PS
813 if ($resetpasswords == UU_PWRESET_ALL or ($resetpasswords == UU_PWRESET_WEAK and $weak)) {
814 if ($weak) {
815 $weakpasswords++;
816 $upt->track('password', $strinvalidpasswordpolicy, 'warning');
817 }
818 $forcechangepassword = true;
819 }
ec2d8ceb
SC
820 // Use a low cost factor when generating bcrypt hash otherwise
821 // hashing would be slow when uploading lots of users. Hashes
822 // will be automatically updated to a higher cost factor the first
823 // time the user logs in.
824 $user->password = hash_internal_user_password($user->password, true);
3f12c146 825 }
8bdb31ed 826 } else {
ec2d8ceb 827 $user->password = AUTH_PASSWORD_NOT_CACHED;
8bdb31ed 828 $upt->track('password', '-', 'normal', false);
df997f84
PS
829 }
830
9363073b 831 $user->id = user_create_user($user, false, false);
8bdb31ed
PS
832 $upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$user->id)), s($user->username)), 'normal', false);
833
d6aea4cc 834 // pre-process custom profile menu fields data from csv file
bd8dc9ba 835 $user = uu_pre_process_custom_profile_data($user);
e4e38544 836 // save custom profile fields data
837 profile_save_data($user);
838
8bdb31ed
PS
839 if ($forcechangepassword) {
840 set_user_preference('auth_forcepasswordchange', 1, $user);
841 }
842 if ($user->password === 'to be generated') {
843 set_user_preference('create_password', 1, $user);
844 }
845
9363073b
RT
846 // Trigger event.
847 \core\event\user_created::create_from_userid($user->id)->trigger();
848
8bdb31ed
PS
849 $upt->track('status', $struseradded);
850 $upt->track('id', $user->id, 'normal', false);
851 $usersnew++;
852
2304f629 853 // make sure user context exists
bf006d2c 854 context_user::instance($user->id);
2304f629 855
8bdb31ed 856 if ($bulk == UU_BULK_NEW or $bulk == UU_BULK_ALL) {
cd1edf9e 857 if (!in_array($user->id, $SESSION->bulk_users)) {
858 $SESSION->bulk_users[] = $user->id;
066bfbfe 859 }
066bfbfe 860 }
e4e38544 861 }
862
3da0c3cb
MG
863 // Update user interests.
864 if (isset($user->interests) && strval($user->interests) !== '') {
865 useredit_update_interests($user, preg_split('/\s*,\s*/', $user->interests, -1, PREG_SPLIT_NO_EMPTY));
866 }
92b59a56
PS
867
868 // add to cohort first, it might trigger enrolments indirectly - do NOT create cohorts here!
869 foreach ($filecolumns as $column) {
870 if (!preg_match('/^cohort\d+$/', $column)) {
871 continue;
872 }
873
874 if (!empty($user->$column)) {
875 $addcohort = $user->$column;
876 if (!isset($cohorts[$addcohort])) {
877 if (is_number($addcohort)) {
878 // only non-numeric idnumbers!
879 $cohort = $DB->get_record('cohort', array('id'=>$addcohort));
880 } else {
881 $cohort = $DB->get_record('cohort', array('idnumber'=>$addcohort));
e7bc9157
MG
882 if (empty($cohort) && has_capability('moodle/cohort:manage', context_system::instance())) {
883 // Cohort was not found. Create a new one.
884 $cohortid = cohort_add_cohort((object)array(
885 'idnumber' => $addcohort,
886 'name' => $addcohort,
887 'contextid' => context_system::instance()->id
888 ));
889 $cohort = $DB->get_record('cohort', array('id'=>$cohortid));
890 }
92b59a56
PS
891 }
892
893 if (empty($cohort)) {
894 $cohorts[$addcohort] = get_string('unknowncohort', 'core_cohort', s($addcohort));
895 } else if (!empty($cohort->component)) {
896 // cohorts synchronised with external sources must not be modified!
897 $cohorts[$addcohort] = get_string('external', 'core_cohort');
898 } else {
899 $cohorts[$addcohort] = $cohort;
900 }
901 }
902
903 if (is_object($cohorts[$addcohort])) {
904 $cohort = $cohorts[$addcohort];
905 if (!$DB->record_exists('cohort_members', array('cohortid'=>$cohort->id, 'userid'=>$user->id))) {
906 cohort_add_member($cohort->id, $user->id);
907 // we might add special column later, for now let's abuse enrolments
908 $upt->track('enrolments', get_string('useradded', 'core_cohort', s($cohort->name)));
909 }
910 } else {
911 // error message
912 $upt->track('enrolments', $cohorts[$addcohort], 'error');
913 }
914 }
915 }
916
917
2686b6c3 918 // find course enrolments, groups, roles/types and enrol periods
8bdb31ed
PS
919 // this is again a special case, we always do this for any updated or created users
920 foreach ($filecolumns as $column) {
2a34360e
SP
921 if (preg_match('/^sysrole\d+$/', $column)) {
922
923 if (!empty($user->$column)) {
924 $sysrolename = $user->$column;
925 if ($sysrolename[0] == '-') {
926 $removing = true;
927 $sysrolename = substr($sysrolename, 1);
928 } else {
929 $removing = false;
930 }
931
932 if (array_key_exists($sysrolename, $sysrolecache)) {
933 $sysroleid = $sysrolecache[$sysrolename]->id;
934 } else {
935 $upt->track('enrolments', get_string('unknownrole', 'error', s($sysrolename)), 'error');
936 continue;
937 }
938
939 if ($removing) {
940 if (user_has_role_assignment($user->id, $sysroleid, SYSCONTEXTID)) {
941 role_unassign($sysroleid, $user->id, SYSCONTEXTID);
942 $upt->track('enrolments', get_string('unassignedsysrole',
943 'tool_uploaduser', $sysrolecache[$sysroleid]->name));
944 }
945 } else {
946 if (!user_has_role_assignment($user->id, $sysroleid, SYSCONTEXTID)) {
947 role_assign($sysroleid, $user->id, SYSCONTEXTID);
948 $upt->track('enrolments', get_string('assignedsysrole',
949 'tool_uploaduser', $sysrolecache[$sysroleid]->name));
950 }
951 }
952 }
953
954 continue;
955 }
e4e38544 956 if (!preg_match('/^course\d+$/', $column)) {
957 continue;
958 }
959 $i = substr($column, 6);
6b09974b 960
df997f84
PS
961 if (empty($user->{'course'.$i})) {
962 continue;
963 }
e4e38544 964 $shortname = $user->{'course'.$i};
965 if (!array_key_exists($shortname, $ccache)) {
df997f84 966 if (!$course = $DB->get_record('course', array('shortname'=>$shortname), 'id, shortname')) {
8bdb31ed 967 $upt->track('enrolments', get_string('unknowncourse', 'error', s($shortname)), 'error');
a7db355a 968 continue;
066bfbfe 969 }
e4e38544 970 $ccache[$shortname] = $course;
971 $ccache[$shortname]->groups = null;
972 }
973 $courseid = $ccache[$shortname]->id;
bf006d2c 974 $coursecontext = context_course::instance($courseid);
df997f84 975 if (!isset($manualcache[$courseid])) {
4cb02426
PS
976 $manualcache[$courseid] = false;
977 if ($manual) {
978 if ($instances = enrol_get_instances($courseid, false)) {
979 foreach ($instances as $instance) {
980 if ($instance->enrol === 'manual') {
981 $manualcache[$courseid] = $instance;
982 break;
983 }
984 }
985 }
e4e38544 986 }
df997f84 987 }
e4e38544 988
968083cd
PS
989 if ($courseid == SITEID) {
990 // Technically frontpage does not have enrolments, but only role assignments,
991 // let's not invent new lang strings here for this rarely used feature.
992
993 if (!empty($user->{'role'.$i})) {
2a34360e
SP
994 $rolename = $user->{'role'.$i};
995 if (array_key_exists($rolename, $rolecache)) {
996 $roleid = $rolecache[$rolename]->id;
968083cd 997 } else {
2a34360e 998 $upt->track('enrolments', get_string('unknownrole', 'error', s($rolename)), 'error');
968083cd
PS
999 continue;
1000 }
1001
2a34360e 1002 role_assign($roleid, $user->id, context_course::instance($courseid));
968083cd
PS
1003
1004 $a = new stdClass();
1005 $a->course = $shortname;
2a34360e 1006 $a->role = $rolecache[$roleid]->name;
968083cd
PS
1007 $upt->track('enrolments', get_string('enrolledincourserole', 'enrol_manual', $a));
1008 }
1009
1010 } else if ($manual and $manualcache[$courseid]) {
df997f84
PS
1011
1012 // find role
2a34360e 1013 $roleid = false;
df997f84 1014 if (!empty($user->{'role'.$i})) {
2a34360e
SP
1015 $rolename = $user->{'role'.$i};
1016 if (array_key_exists($rolename, $rolecache)) {
1017 $roleid = $rolecache[$rolename]->id;
e4e38544 1018 } else {
2a34360e 1019 $upt->track('enrolments', get_string('unknownrole', 'error', s($rolename)), 'error');
df997f84 1020 continue;
a7db355a 1021 }
e4e38544 1022
df997f84
PS
1023 } else if (!empty($user->{'type'.$i})) {
1024 // if no role, then find "old" enrolment type
1025 $addtype = $user->{'type'.$i};
1026 if ($addtype < 1 or $addtype > 3) {
1027 $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error');
1028 continue;
1029 } else if (empty($formdata->{'uulegacy'.$addtype})) {
1030 continue;
1031 } else {
2a34360e 1032 $roleid = $formdata->{'uulegacy'.$addtype};
df997f84 1033 }
e4e38544 1034 } else {
df997f84 1035 // no role specified, use the default from manual enrol plugin
2a34360e 1036 $roleid = $manualcache[$courseid]->roleid;
a7db355a 1037 }
2686b6c3 1038
2a34360e 1039 if ($roleid) {
6afe875e
JH
1040 // Find duration and/or enrol status.
1041 $timeend = 0;
6ab44bdb 1042 $timestart = $today;
6afe875e
JH
1043 $status = null;
1044
1045 if (isset($user->{'enrolstatus'.$i})) {
7ca44a49 1046 $enrolstatus = $user->{'enrolstatus'.$i};
6afe875e
JH
1047 if ($enrolstatus == '') {
1048 $status = null;
1049 } else if ($enrolstatus === (string)ENROL_USER_ACTIVE) {
1050 $status = ENROL_USER_ACTIVE;
1051 } else if ($enrolstatus === (string)ENROL_USER_SUSPENDED) {
1052 $status = ENROL_USER_SUSPENDED;
1053 } else {
1054 debugging('Unknown enrolment status.');
1055 }
1056 }
1057
6ab44bdb
FM
1058 if (!empty($user->{'enroltimestart'.$i})) {
1059 $parsedtimestart = strtotime($user->{'enroltimestart'.$i});
1060 if ($parsedtimestart !== false) {
1061 $timestart = $parsedtimestart;
1062 }
1063 }
1064
df997f84 1065 if (!empty($user->{'enrolperiod'.$i})) {
8bdb31ed 1066 $duration = (int)$user->{'enrolperiod'.$i} * 60*60*24; // convert days to seconds
df997f84 1067 if ($duration > 0) { // sanity check
6ab44bdb 1068 $timeend = $timestart + $duration;
df997f84 1069 }
b1d76077 1070 } else if ($manualcache[$courseid]->enrolperiod > 0) {
6ab44bdb 1071 $timeend = $timestart + $manualcache[$courseid]->enrolperiod;
df997f84 1072 }
2686b6c3 1073
6ab44bdb 1074 $manual->enrol_user($manualcache[$courseid], $user->id, $roleid, $timestart, $timeend, $status);
df997f84 1075
a226a972 1076 $a = new stdClass();
df997f84 1077 $a->course = $shortname;
2a34360e 1078 $a->role = $rolecache[$roleid]->name;
df997f84 1079 $upt->track('enrolments', get_string('enrolledincourserole', 'enrol_manual', $a));
066bfbfe 1080 }
e4e38544 1081 }
6b09974b 1082
e4e38544 1083 // find group to add to
1084 if (!empty($user->{'group'.$i})) {
1085 // make sure user is enrolled into course before adding into groups
4f0c2d00 1086 if (!is_enrolled($coursecontext, $user->id)) {
d85f2634 1087 $upt->track('enrolments', get_string('addedtogroupnotenrolled', '', $user->{'group'.$i}), 'error');
e4e38544 1088 continue;
1089 }
1090 //build group cache
1091 if (is_null($ccache[$shortname]->groups)) {
1092 $ccache[$shortname]->groups = array();
35987665 1093 if ($groups = groups_get_all_groups($courseid)) {
e4e38544 1094 foreach ($groups as $gid=>$group) {
a226a972 1095 $ccache[$shortname]->groups[$gid] = new stdClass();
e4e38544 1096 $ccache[$shortname]->groups[$gid]->id = $gid;
1097 $ccache[$shortname]->groups[$gid]->name = $group->name;
1098 if (!is_numeric($group->name)) { // only non-numeric names are supported!!!
8bdb31ed
PS
1099 $ccache[$shortname]->groups[$group->name] = new stdClass();
1100 $ccache[$shortname]->groups[$group->name]->id = $gid;
1101 $ccache[$shortname]->groups[$group->name]->name = $group->name;
a7db355a 1102 }
a5702569 1103 }
0063abee 1104 }
6b09974b 1105 }
e4e38544 1106 // group exists?
1107 $addgroup = $user->{'group'.$i};
1108 if (!array_key_exists($addgroup, $ccache[$shortname]->groups)) {
b225cf36 1109 // if group doesn't exist, create it
a226a972 1110 $newgroupdata = new stdClass();
b225cf36 1111 $newgroupdata->name = $addgroup;
1112 $newgroupdata->courseid = $ccache[$shortname]->id;
e95bf5b5
PS
1113 $newgroupdata->description = '';
1114 $gid = groups_create_group($newgroupdata);
1115 if ($gid){
1116 $ccache[$shortname]->groups[$addgroup] = new stdClass();
1117 $ccache[$shortname]->groups[$addgroup]->id = $gid;
b225cf36 1118 $ccache[$shortname]->groups[$addgroup]->name = $newgroupdata->name;
1119 } else {
8bdb31ed 1120 $upt->track('enrolments', get_string('unknowngroup', 'error', s($addgroup)), 'error');
b225cf36 1121 continue;
1122 }
e4e38544 1123 }
1124 $gid = $ccache[$shortname]->groups[$addgroup]->id;
1125 $gname = $ccache[$shortname]->groups[$addgroup]->name;
1126
9c000a99 1127 try {
1128 if (groups_add_member($gid, $user->id)) {
8bdb31ed 1129 $upt->track('enrolments', get_string('addedtogroup', '', s($gname)));
df997f84 1130 } else {
8bdb31ed 1131 $upt->track('enrolments', get_string('addedtogroupnot', '', s($gname)), 'error');
9c000a99 1132 }
1133 } catch (moodle_exception $e) {
8bdb31ed 1134 $upt->track('enrolments', get_string('addedtogroupnot', '', s($gname)), 'error');
e4e38544 1135 continue;
1136 }
a5702569 1137 }
066bfbfe 1138 }
94a578af 1139 $validation[$user->username] = core_user::validate($user);
066bfbfe 1140 }
e4e38544 1141 $upt->close(); // close table
94a578af 1142 if (!empty($validation)) {
0de3caf6
SL
1143 foreach ($validation as $username => $result) {
1144 if ($result !== true) {
1145 \core\notification::warning(get_string('invaliduserdata', 'tool_uploaduser', s($username)));
1146 }
94a578af
SL
1147 }
1148 }
e4e38544 1149 $cir->close();
1150 $cir->cleanup(true);
1151
20486a5a 1152 echo $OUTPUT->box_start('boxwidthnarrow boxaligncenter generalbox', 'uploadresults');
e4e38544 1153 echo '<p>';
8bdb31ed 1154 if ($optype != UU_USER_UPDATE) {
ce15d56d 1155 echo get_string('userscreated', 'tool_uploaduser').': '.$usersnew.'<br />';
e4e38544 1156 }
8bdb31ed 1157 if ($optype == UU_USER_UPDATE or $optype == UU_USER_ADD_UPDATE) {
ce15d56d 1158 echo get_string('usersupdated', 'tool_uploaduser').': '.$usersupdated.'<br />';
e4e38544 1159 }
1160 if ($allowdeletes) {
ce15d56d
PS
1161 echo get_string('usersdeleted', 'tool_uploaduser').': '.$deletes.'<br />';
1162 echo get_string('deleteerrors', 'tool_uploaduser').': '.$deleteerrors.'<br />';
e4e38544 1163 }
1164 if ($allowrenames) {
ce15d56d
PS
1165 echo get_string('usersrenamed', 'tool_uploaduser').': '.$renames.'<br />';
1166 echo get_string('renameerrors', 'tool_uploaduser').': '.$renameerrors.'<br />';
e4e38544 1167 }
1168 if ($usersskipped) {
ce15d56d 1169 echo get_string('usersskipped', 'tool_uploaduser').': '.$usersskipped.'<br />';
e4e38544 1170 }
ce15d56d
PS
1171 echo get_string('usersweakpassword', 'tool_uploaduser').': '.$weakpasswords.'<br />';
1172 echo get_string('errors', 'tool_uploaduser').': '.$userserrors.'</p>';
20486a5a 1173 echo $OUTPUT->box_end();
e4e38544 1174
1175 if ($bulk) {
8fbce1c8 1176 echo $OUTPUT->continue_button($bulknurl);
e4e38544 1177 } else {
8fbce1c8 1178 echo $OUTPUT->continue_button($returnurl);
e4e38544 1179 }
73d6f52f 1180 echo $OUTPUT->footer();
df7ecfe4 1181 die;
6b09974b 1182}
0a6150ca 1183
df7ecfe4 1184// Print the header
61ef8f9f 1185echo $OUTPUT->header();
df7ecfe4 1186
ce15d56d 1187echo $OUTPUT->heading(get_string('uploaduserspreview', 'tool_uploaduser'));
df7ecfe4 1188
8bdb31ed
PS
1189// NOTE: this is JUST csv processing preview, we must not prevent import from here if there is something in the file!!
1190// this was intended for validation of csv formatting and encoding, not filtering the data!!!!
1191// we definitely must not process the whole file!
1192
1193// preview table data
1194$data = array();
e4e38544 1195$cir->init();
8bdb31ed 1196$linenum = 1; //column header is first line
1b4d2d56 1197$noerror = true; // Keep status of any error.
8bdb31ed
PS
1198while ($linenum <= $previewrows and $fields = $cir->next()) {
1199 $linenum++;
3fe2cfb5 1200 $rowcols = array();
8bdb31ed
PS
1201 $rowcols['line'] = $linenum;
1202 foreach($fields as $key => $field) {
7ca44a49 1203 $rowcols[$filecolumns[$key]] = s(trim($field));
3fe2cfb5 1204 }
8bdb31ed 1205 $rowcols['status'] = array();
3fe2cfb5 1206
8bdb31ed 1207 if (isset($rowcols['username'])) {
ac9768fc 1208 $stdusername = core_user::clean_field($rowcols['username'], 'username');
8bdb31ed
PS
1209 if ($rowcols['username'] !== $stdusername) {
1210 $rowcols['status'][] = get_string('invalidusernameupload');
3fe2cfb5 1211 }
8bdb31ed
PS
1212 if ($userid = $DB->get_field('user', 'id', array('username'=>$stdusername, 'mnethostid'=>$CFG->mnet_localhost_id))) {
1213 $rowcols['username'] = html_writer::link(new moodle_url('/user/profile.php', array('id'=>$userid)), $rowcols['username']);
e4e38544 1214 }
8bdb31ed
PS
1215 } else {
1216 $rowcols['status'][] = get_string('missingusername');
df7ecfe4 1217 }
07ed083e 1218
43070e61
PS
1219 if (isset($rowcols['email'])) {
1220 if (!validate_email($rowcols['email'])) {
1221 $rowcols['status'][] = get_string('invalidemail');
1222 }
92cec53b 1223
1224 $select = $DB->sql_like('email', ':email', false, true, false, '|');
1225 $params = array('email' => $DB->sql_like_escape($rowcols['email'], '|'));
1226 if ($DB->record_exists_select('user', $select , $params)) {
43070e61
PS
1227 $rowcols['status'][] = $stremailduplicate;
1228 }
07ed083e 1229 }
fd9672ac
RW
1230
1231 if (isset($rowcols['city'])) {
7ca44a49 1232 $rowcols['city'] = $rowcols['city'];
fd9672ac 1233 }
e6ce167b
MM
1234
1235 if (isset($rowcols['theme'])) {
1236 list($status, $message) = field_value_validators::validate_theme($rowcols['theme']);
1237 if ($status !== 'normal' && !empty($message)) {
1238 $rowcols['status'][] = $message;
1239 }
1240 }
1241
1b4d2d56
RT
1242 // Check if rowcols have custom profile field with correct data and update error state.
1243 $noerror = uu_check_custom_profile_data($rowcols) && $noerror;
8bdb31ed
PS
1244 $rowcols['status'] = implode('<br />', $rowcols['status']);
1245 $data[] = $rowcols;
07ed083e 1246}
8bdb31ed
PS
1247if ($fields = $cir->next()) {
1248 $data[] = array_fill(0, count($fields) + 2, '...');
07ed083e 1249}
8bdb31ed 1250$cir->close();
3fe2cfb5
RW
1251
1252$table = new html_table();
1253$table->id = "uupreview";
16be8974 1254$table->attributes['class'] = 'generaltable';
3fe2cfb5 1255$table->tablealign = 'center';
ce15d56d 1256$table->summary = get_string('uploaduserspreview', 'tool_uploaduser');
3fe2cfb5 1257$table->head = array();
8bdb31ed 1258$table->data = $data;
3fe2cfb5 1259
ce15d56d 1260$table->head[] = get_string('uucsvline', 'tool_uploaduser');
8bdb31ed
PS
1261foreach ($filecolumns as $column) {
1262 $table->head[] = $column;
07ed083e 1263}
8bdb31ed 1264$table->head[] = get_string('status');
07ed083e 1265
3f12c146 1266echo html_writer::tag('div', html_writer::table($table), array('class'=>'flexible-wrap'));
3fe2cfb5 1267
1b4d2d56
RT
1268// Print the form if valid values are available
1269if ($noerror) {
1270 $mform2->display();
1271}
73d6f52f 1272echo $OUTPUT->footer();
df7ecfe4 1273die;