MDL-29029 move multilang upgrade to admin tools
[moodle.git] / admin / uploaduser.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 *
20 * @package core
21 * @subpackage admin
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
e4e38544 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');
59186c92 30require_once($CFG->dirroot.'/group/lib.php');
92b59a56 31require_once($CFG->dirroot.'/cohort/lib.php');
8bdb31ed 32require_once('uploaduserlib.php');
0a5dffcc 33require_once('uploaduser_form.php');
1ae083e4 34
e4e38544 35$iid = optional_param('iid', '', PARAM_INT);
df7ecfe4 36$previewrows = optional_param('previewrows', 10, PARAM_INT);
066bfbfe 37
8bdb31ed
PS
38@set_time_limit(60*60); // 1 hour should be enough
39raise_memory_limit(MEMORY_HUGE);
0a6150ca 40
ebff4779 41require_login();
066bfbfe 42admin_externalpage_setup('uploadusers');
1ae083e4 43require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM));
0a6150ca 44
e4e38544 45$struserrenamed = get_string('userrenamed', 'admin');
46$strusernotrenamedexists = get_string('usernotrenamedexists', 'error');
47$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error');
48$strusernotrenamedoff = get_string('usernotrenamedoff', 'error');
49$strusernotrenamedadmin = get_string('usernotrenamedadmin', 'error');
50
51$struserupdated = get_string('useraccountupdated', 'admin');
52$strusernotupdated = get_string('usernotupdatederror', 'error');
53$strusernotupdatednotexists = get_string('usernotupdatednotexists', 'error');
54$strusernotupdatedadmin = get_string('usernotupdatedadmin', 'error');
55
8bdb31ed
PS
56$struseruptodate = get_string('useraccountuptodate', 'admin');
57
e4e38544 58$struseradded = get_string('newuser');
59$strusernotadded = get_string('usernotaddedregistered', 'error');
60$strusernotaddederror = get_string('usernotaddederror', 'error');
61
62$struserdeleted = get_string('userdeleted', 'admin');
63$strusernotdeletederror = get_string('usernotdeletederror', 'error');
64$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error');
65$strusernotdeletedoff = get_string('usernotdeletedoff', 'error');
66$strusernotdeletedadmin = get_string('usernotdeletedadmin', 'error');
67
68$strcannotassignrole = get_string('cannotassignrole', 'error');
e4e38544 69
70$struserauthunsupported = get_string('userauthunsupported', 'error');
3fe2cfb5 71$stremailduplicate = get_string('useremailduplicate', 'error');
e4e38544 72
3f12c146 73$strinvalidpasswordpolicy = get_string('invalidpasswordpolicy', 'error');
e4e38544 74$errorstr = get_string('error');
ca23a9c9 75
8bdb31ed
PS
76$returnurl = new moodle_url('/admin/uploaduser.php');
77$bulknurl = new moodle_url('/admin/user/user_bulk.php');
e4e38544 78
2a6dcb72
PS
79$today = time();
80$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
81
e4e38544 82// array of all valid fields for validation
6dbcacee 83$STD_FIELDS = array('id', 'firstname', 'lastname', 'username', 'email',
8bdb31ed 84 'city', 'country', 'lang', 'timezone', 'mailformat',
6dbcacee 85 'maildisplay', 'maildigest', 'htmleditor', 'ajax', 'autosubscribe',
8bdb31ed 86 'institution', 'department', 'idnumber', 'skype',
6dbcacee 87 'msn', 'aim', 'yahoo', 'icq', 'phone1', 'phone2', 'address',
8bdb31ed
PS
88 'url', 'description', 'descriptionformat', 'password',
89 'auth', // watch out when changing auth type or using external auth plugins!
90 'oldusername', // use when renaming users - this is the original username
91 'deleted', // 1 means delete user
92 );
e4e38544 93
94$PRF_FIELDS = array();
95
1d8bf5f0 96if ($prof_fields = $DB->get_records('user_info_field')) {
e4e38544 97 foreach ($prof_fields as $prof_field) {
98 $PRF_FIELDS[] = 'profile_field_'.$prof_field->shortname;
99 }
e4e38544 100}
8bdb31ed 101unset($prof_fields);
e4e38544 102
103if (empty($iid)) {
8bdb31ed 104 $mform1 = new admin_uploaduser_form1();
0a6150ca 105
8bdb31ed 106 if ($formdata = $mform1->get_data()) {
e4e38544 107 $iid = csv_import_reader::get_new_iid('uploaduser');
108 $cir = new csv_import_reader($iid, 'uploaduser');
df7ecfe4 109
8bdb31ed
PS
110 $content = $mform1->get_file_content('userfile');
111
112 $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name);
e4e38544 113 unset($content);
df7ecfe4 114
e4e38544 115 if ($readcount === false) {
bd8ee7c1 116 print_error('csvloaderror', '', $returnurl);
e4e38544 117 } else if ($readcount == 0) {
5a2a5331 118 print_error('csvemptyfile', 'error', $returnurl);
ed22a01b 119 }
8bdb31ed
PS
120 // test if columns ok
121 $filecolumns = uu_validate_user_upload_columns($cir, $STD_FIELDS, $PRF_FIELDS, $returnurl);
e4e38544 122 // continue to form2
df7ecfe4 123
124 } else {
61ef8f9f 125 echo $OUTPUT->header();
9e492db0 126
6c7a5df7 127 echo $OUTPUT->heading_with_help(get_string('uploadusers', 'admin'), 'uploadusers', 'admin');
9e492db0 128
8bdb31ed 129 $mform1->display();
73d6f52f 130 echo $OUTPUT->footer();
df7ecfe4 131 die;
132 }
e4e38544 133} else {
134 $cir = new csv_import_reader($iid, 'uploaduser');
8bdb31ed 135 $filecolumns = uu_validate_user_upload_columns($cir, $STD_FIELDS, $PRF_FIELDS, $returnurl);
df7ecfe4 136}
137
8bdb31ed 138$mform2 = new admin_uploaduser_form2(null, array('columns'=>$filecolumns, 'data'=>array('iid'=>$iid, 'previewrows'=>$previewrows)));
df7ecfe4 139
140// If a file has been uploaded, then process it
8bdb31ed 141if ($formdata = $mform2->is_cancelled()) {
e4e38544 142 $cir->cleanup(true);
143 redirect($returnurl);
df7ecfe4 144
8bdb31ed 145} else if ($formdata = $mform2->get_data()) {
df7ecfe4 146 // Print the header
61ef8f9f 147 echo $OUTPUT->header();
2fff8846 148 echo $OUTPUT->heading(get_string('uploadusersresult', 'admin'));
e4e38544 149
150 $optype = $formdata->uutype;
151
0c4807ab 152 $updatetype = isset($formdata->uuupdatetype) ? $formdata->uuupdatetype : 0;
8bdb31ed
PS
153 $createpasswords = (!empty($formdata->uupasswordnew) and $optype != UU_USER_UPDATE);
154 $updatepasswords = (!empty($formdata->uupasswordold) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC and ($updatetype == UU_UPDATE_FILEOVERRIDE or $updatetype == UU_UPDATE_ALLOVERRIDE));
155 $allowrenames = (!empty($formdata->uuallowrenames) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC);
156 $allowdeletes = (!empty($formdata->uuallowdeletes) and $optype != UU_USER_ADDNEW and $optype != UU_USER_ADDINC);
0c4807ab 157 $bulk = $formdata->uubulk;
158 $noemailduplicates = $formdata->uunoemailduplicates;
8bdb31ed
PS
159 $standardusernames = $formdata->uustandardusernames;
160 $resetpasswords = isset($formdata->uuforcepasswordchange) ? $formdata->uuforcepasswordchange : UU_PWRESET_NONE;
e4e38544 161
162 // verification moved to two places: after upload and into form2
8bdb31ed
PS
163 $usersnew = 0;
164 $usersupdated = 0;
165 $usersuptodate = 0; //not printed yet anywhere
166 $userserrors = 0;
167 $deletes = 0;
168 $deleteerrors = 0;
169 $renames = 0;
170 $renameerrors = 0;
171 $usersskipped = 0;
d6bb2d2f 172 $weakpasswords = 0;
feecd4d6 173
e4e38544 174 // caches
8bdb31ed 175 $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway!
92b59a56 176 $cohorts = array();
8bdb31ed
PS
177 $rolecache = uu_allowed_roles_cache(); // roles lookup cache
178 $manualcache = array(); // cache of used manual enrol plugins in each course
179 $supportedauths = uu_supported_auths(); // officially supported plugins that are enabled
e4e38544 180
df997f84
PS
181 // we use only manual enrol plugin here, if it is disabled no enrol is done
182 if (enrol_is_enabled('manual')) {
183 $manual = enrol_get_plugin('manual');
184 } else {
185 $manual = NULL;
e4e38544 186 }
df7ecfe4 187
b4bd91ce 188 // clear bulk selection
e4e38544 189 if ($bulk) {
cd1edf9e 190 $SESSION->bulk_users = array();
e4e38544 191 }
df7ecfe4 192
e4e38544 193 // init csv import helper
194 $cir->init();
195 $linenum = 1; //column header is first line
df7ecfe4 196
e4e38544 197 // init upload progress tracker
198 $upt = new uu_progress_tracker();
8bdb31ed 199 $upt->start(); // start table
a2ce7344 200
e4e38544 201 while ($line = $cir->next()) {
202 $upt->flush();
203 $linenum++;
204
205 $upt->track('line', $linenum);
206
a226a972 207 $user = new stdClass();
8bdb31ed 208
e4e38544 209 // add fields to user object
8bdb31ed
PS
210 foreach ($line as $keynum => $value) {
211 if (!isset($filecolumns[$keynum])) {
212 // this should not happen
213 continue;
214 }
215 $key = $filecolumns[$keynum];
216 if (strpos($key, 'profile_field_') === 0) {
217 //NOTE: bloody mega hack alert!!
218 if (isset($USER->$key) and is_array($USER->$key)) {
219 // this must be some hacky field that is abusing arrays to store content and format
220 $user->$key = array();
221 $user->$key['text'] = $value;
222 $user->$key['format'] = FORMAT_MOODLE;
223 } else {
224 $user->$key = $value;
e4e38544 225 }
c3231d1d 226 } else {
8bdb31ed 227 $user->$key = $value;
a7db355a 228 }
e4e38544 229
8bdb31ed
PS
230 if (in_array($key, $upt->columns)) {
231 // default value in progress tracking table, can be changed later
232 $upt->track($key, s($value), 'normal');
e4e38544 233 }
8bdb31ed
PS
234 }
235 if (!isset($user->username)) {
236 // prevent warnings bellow
237 $user->username = '';
238 }
e4e38544 239
8bdb31ed
PS
240 if ($optype == UU_USER_ADDNEW or $optype == UU_USER_ADDINC) {
241 // user creation is a special case - the username may be constructed from templates using firstname and lastname
242 // better never try this in mixed update types
e4e38544 243 $error = false;
e4e38544 244 if (!isset($user->firstname) or $user->firstname === '') {
245 $upt->track('status', get_string('missingfield', 'error', 'firstname'), 'error');
246 $upt->track('firstname', $errorstr, 'error');
247 $error = true;
248 }
249 if (!isset($user->lastname) or $user->lastname === '') {
250 $upt->track('status', get_string('missingfield', 'error', 'lastname'), 'error');
251 $upt->track('lastname', $errorstr, 'error');
252 $error = true;
253 }
254 if ($error) {
255 $userserrors++;
256 continue;
257 }
258 // we require username too - we might use template for it though
8bdb31ed
PS
259 if (empty($user->username) and !empty($formdata->username)) {
260 $user->username = uu_process_template($formdata->username, $user);
261 $upt->track('username', s($user->username));
e4e38544 262 }
a7db355a 263 }
e4e38544 264
265 // normalize username
8bdb31ed
PS
266 $originalusername = $user->username;
267 if ($standardusernames) {
268 $user->username = clean_param($user->username, PARAM_USERNAME);
269 }
07ed083e 270
8bdb31ed 271 // make sure we really have username
e4e38544 272 if (empty($user->username)) {
273 $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
274 $upt->track('username', $errorstr, 'error');
275 $userserrors++;
276 continue;
8bdb31ed
PS
277 } else if ($user->username === 'guest') {
278 $upt->track('status', get_string('guestnoeditprofileother', 'error'), 'error');
279 $userserrors++;
280 continue;
e4e38544 281 }
282
8bdb31ed 283 if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
e4e38544 284 $upt->track('id', $existinguser->id, 'normal', false);
285 }
286
287 // find out in username incrementing required
8bdb31ed
PS
288 if ($existinguser and $optype == UU_USER_ADDINC) {
289 $user->username = uu_increment_username($user->username);
e4e38544 290 $existinguser = false;
291 }
292
8bdb31ed
PS
293 // notify about nay username changes
294 if ($originalusername !== $user->username) {
295 $upt->track('username', '', 'normal', false); // clear previous
296 $upt->track('username', s($originalusername).'-->'.s($user->username), 'info');
297 } else {
298 $upt->track('username', s($user->username), 'normal', false);
299 }
300
e4e38544 301 // add default values for remaining fields
8bdb31ed 302 $formdefaults = array();
e4e38544 303 foreach ($STD_FIELDS as $field) {
304 if (isset($user->$field)) {
305 continue;
306 }
307 // all validation moved to form2
308 if (isset($formdata->$field)) {
309 // process templates
8bdb31ed
PS
310 $user->$field = uu_process_template($formdata->$field, $user);
311 $formdefaults[$field] = true;
43070e61
PS
312 if (in_array($field, $upt->columns)) {
313 $upt->track($field, s($user->$field), 'normal');
314 }
e4e38544 315 }
316 }
317 foreach ($PRF_FIELDS as $field) {
318 if (isset($user->$field)) {
319 continue;
320 }
321 if (isset($formdata->$field)) {
322 // process templates
8bdb31ed
PS
323 $user->$field = uu_process_template($formdata->$field, $user);
324 $formdefaults[$field] = true;
e4e38544 325 }
326 }
327
328 // delete user
329 if (!empty($user->deleted)) {
330 if (!$allowdeletes) {
331 $usersskipped++;
332 $upt->track('status', $strusernotdeletedoff, 'warning');
333 continue;
334 }
335 if ($existinguser) {
4f0c2d00 336 if (is_siteadmin($existinguser->id)) {
e4e38544 337 $upt->track('status', $strusernotdeletedadmin, 'error');
338 $deleteerrors++;
339 continue;
340 }
341 if (delete_user($existinguser)) {
342 $upt->track('status', $struserdeleted);
343 $deletes++;
344 } else {
345 $upt->track('status', $strusernotdeletederror, 'error');
346 $deleteerrors++;
6b09974b 347 }
e4e38544 348 } else {
349 $upt->track('status', $strusernotdeletedmissing, 'error');
350 $deleteerrors++;
351 }
352 continue;
353 }
354 // we do not need the deleted flag anymore
355 unset($user->deleted);
356
357 // renaming requested?
358 if (!empty($user->oldusername) ) {
e4e38544 359 if (!$allowrenames) {
360 $usersskipped++;
361 $upt->track('status', $strusernotrenamedoff, 'warning');
362 continue;
363 }
364
365 if ($existinguser) {
366 $upt->track('status', $strusernotrenamedexists, 'error');
367 $renameerrors++;
368 continue;
16a1fed4 369 }
ed22a01b 370
8bdb31ed
PS
371 if ($user->username === 'guest') {
372 $upt->track('status', get_string('guestnoeditprofileother', 'error'), 'error');
373 $renameerrors++;
374 continue;
375 }
376
377 if ($standardusernames) {
378 $oldusername = clean_param($user->oldusername, PARAM_USERNAME);
379 } else {
380 $oldusername = $user->oldusername;
381 }
382
383 // no guessing when looking for old username, it must be exact match
384 if ($olduser = $DB->get_record('user', array('username'=>$oldusername, 'mnethostid'=>$CFG->mnet_localhost_id))) {
e4e38544 385 $upt->track('id', $olduser->id, 'normal', false);
4f0c2d00 386 if (is_siteadmin($olduser->id)) {
e4e38544 387 $upt->track('status', $strusernotrenamedadmin, 'error');
388 $renameerrors++;
a7db355a 389 continue;
0063abee 390 }
df997f84
PS
391 $DB->set_field('user', 'username', $user->username, array('id'=>$olduser->id));
392 $upt->track('username', '', 'normal', false); // clear previous
8bdb31ed 393 $upt->track('username', s($oldusername).'-->'.s($user->username), 'info');
df997f84
PS
394 $upt->track('status', $struserrenamed);
395 $renames++;
e4e38544 396 } else {
397 $upt->track('status', $strusernotrenamedmissing, 'error');
398 $renameerrors++;
399 continue;
400 }
401 $existinguser = $olduser;
402 $existinguser->username = $user->username;
403 }
404
405 // can we process with update or insert?
406 $skip = false;
407 switch ($optype) {
8bdb31ed 408 case UU_USER_ADDNEW:
e4e38544 409 if ($existinguser) {
410 $usersskipped++;
411 $upt->track('status', $strusernotadded, 'warning');
3fe2cfb5 412 $skip = true;
e4e38544 413 }
414 break;
415
8bdb31ed 416 case UU_USER_ADDINC:
e4e38544 417 if ($existinguser) {
418 //this should not happen!
419 $upt->track('status', $strusernotaddederror, 'error');
420 $userserrors++;
8bdb31ed 421 $skip = true;
e4e38544 422 }
423 break;
424
8bdb31ed 425 case UU_USER_ADD_UPDATE:
e4e38544 426 break;
427
8bdb31ed 428 case UU_USER_UPDATE:
e4e38544 429 if (!$existinguser) {
430 $usersskipped++;
431 $upt->track('status', $strusernotupdatednotexists, 'warning');
432 $skip = true;
433 }
434 break;
8bdb31ed
PS
435
436 default:
437 // unknown type
438 $skip = true;
e4e38544 439 }
440
441 if ($skip) {
442 continue;
443 }
444
445 if ($existinguser) {
446 $user->id = $existinguser->id;
447
8bdb31ed
PS
448 $upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$existinguser->id)), s($existinguser->username)), 'normal', false);
449
4f0c2d00 450 if (is_siteadmin($user->id)) {
e4e38544 451 $upt->track('status', $strusernotupdatedadmin, 'error');
452 $userserrors++;
453 continue;
454 }
455
8bdb31ed
PS
456 $existinguser->timemodified = time();
457 // do NOT mess with timecreated or firstaccess here!
458
459 //load existing profile data
460 profile_load_data($existinguser);
3fe2cfb5 461
8bdb31ed 462 $upt->track('auth', $existinguser->auth, 'normal', false);
e4e38544 463
8bdb31ed
PS
464 $doupdate = false;
465
466 if ($updatetype != UU_UPDATE_NOCHANGES) {
467 if (!empty($user->auth) and $user->auth !== $existinguser->auth) {
468 $upt->track('auth', s($existinguser->auth).'-->'.s($user->auth), 'info', false);
469 $existinguser->auth = $user->auth;
470 if (!isset($supportedauths[$user->auth])) {
471 $upt->track('auth', $struserauthunsupported, 'warning');
472 }
df833016 473 $doupdate = true;
e4e38544 474 }
8bdb31ed
PS
475 $allcolumns = array_merge($STD_FIELDS, $PRF_FIELDS);
476 foreach ($allcolumns as $column) {
477 if ($column === 'username' or $column === 'password' or $column === 'auth') {
478 // these can not be changed here
e4e38544 479 continue;
480 }
8bdb31ed
PS
481 if (!property_exists($user, $column) or !property_exists($existinguser, $column)) {
482 // this should never happen
483 continue;
484 }
485 if ($updatetype == UU_UPDATE_MISSING) {
486 if (!is_null($existinguser->$column) and $existinguser->$column !== '') {
e4e38544 487 continue;
a7db355a 488 }
8bdb31ed
PS
489 } else if ($updatetype == UU_UPDATE_ALLOVERRIDE) {
490 // we override everything
3f12c146 491
8bdb31ed
PS
492 } else if ($updatetype == UU_UPDATE_FILEOVERRIDE) {
493 if (!empty($formdefaults[$column])) {
494 // do not override with form defaults
495 continue;
496 }
497 }
498 if ($existinguser->$column !== $user->$column) {
499 if ($column === 'email') {
500 if ($DB->record_exists('user', array('email'=>$user->email))) {
501 if ($noemailduplicates) {
502 $upt->track('email', $stremailduplicate, 'error');
503 $upt->track('status', $strusernotupdated, 'error');
504 $userserrors++;
505 continue 2;
506 } else {
507 $upt->track('email', $stremailduplicate, 'warning');
3f12c146
RW
508 }
509 }
8bdb31ed
PS
510 if (!validate_email($user->email)) {
511 $upt->track('email', get_string('invalidemail'), 'warning');
e4e38544 512 }
8bdb31ed 513 }
3f12c146 514
8bdb31ed
PS
515 if (in_array($column, $upt->columns)) {
516 $upt->track($column, s($existinguser->$column).'-->'.s($user->$column), 'info', false);
a7db355a 517 }
8bdb31ed
PS
518 $existinguser->$column = $user->$column;
519 $doupdate = true;
6b09974b 520 }
a7db355a 521 }
8bdb31ed 522 }
ed22a01b 523
8bdb31ed 524 try {
3f12c146 525 $auth = get_auth_plugin($existinguser->auth);
8bdb31ed
PS
526 } catch (Exception $e) {
527 $upt->track('auth', get_string('userautherror', 'error', s($existinguser->auth)), 'error');
528 $upt->track('status', $strusernotupdated, 'error');
529 $userserrors++;
530 continue;
531 }
532 $isinternalauth = $auth->is_internal();
3f12c146 533
8bdb31ed
PS
534 // changing of passwords is a special case
535 // do not force password changes for external auth plugins!
536 $oldpw = $existinguser->password;
537 if (!$isinternalauth) {
538 $existinguser->password = 'not cached';
539 $upt->track('password', '-', 'normal', false);
540 // clean up prefs
541 unset_user_preference('create_password', $existinguser);
542 unset_user_preference('auth_forcepasswordchange', $existinguser);
543
544 } else if (!empty($user->password)) {
545 if ($updatepasswords) {
546 $errmsg = null;
faceca91 547 $weak = !check_password_policy($user->password, $errmsg);
8bdb31ed
PS
548 if ($resetpasswords == UU_PWRESET_ALL or ($resetpasswords == UU_PWRESET_WEAK and $weak)) {
549 if ($weak) {
550 $weakpasswords++;
551 $upt->track('password', $strinvalidpasswordpolicy, 'warning');
552 }
553 set_user_preference('auth_forcepasswordchange', 1, $existinguser);
554 } else {
555 unset_user_preference('auth_forcepasswordchange', $existinguser);
556 }
557 unset_user_preference('create_password', $existinguser); // no need to create password any more
558 $existinguser->password = hash_internal_user_password($user->password);
2197b642 559 $upt->track('password', $user->password, 'normal', false);
3f12c146 560 } else {
8bdb31ed
PS
561 // do not print password when not changed
562 $upt->track('password', '', 'normal', false);
3f12c146 563 }
8bdb31ed 564 }
3f12c146 565
8bdb31ed
PS
566 if ($doupdate or $existinguser->password !== $oldpw) {
567 // we want only users that were really updated
3f12c146 568
df997f84 569 $DB->update_record('user', $existinguser);
3f12c146 570
df997f84
PS
571 $upt->track('status', $struserupdated);
572 $usersupdated++;
e4e38544 573 // save custom profile fields data from csv file
5d910388 574 profile_save_data($existinguser);
e6f74ba3
PS
575
576 events_trigger('user_updated', $existinguser);
e4e38544 577
8bdb31ed
PS
578 if ($bulk == UU_BULK_UPDATED or $bulk == UU_BULK_ALL) {
579 if (!in_array($user->id, $SESSION->bulk_users)) {
580 $SESSION->bulk_users[] = $user->id;
581 }
582 }
583
584 } else {
585 // no user information changed
586 $upt->track('status', $struseruptodate);
587 $usersuptodate++;
588
589 if ($bulk == UU_BULK_ALL) {
590 if (!in_array($user->id, $SESSION->bulk_users)) {
591 $SESSION->bulk_users[] = $user->id;
592 }
ed22a01b 593 }
066bfbfe 594 }
ed22a01b 595
e4e38544 596 } else {
8bdb31ed
PS
597 // save the new user to the database
598 $user->confirmed = 1;
a7db355a 599 $user->timemodified = time();
8bdb31ed
PS
600 $user->timecreated = time();
601 $user->mnethostid = $CFG->mnet_localhost_id; // we support ONLY local accounts here, sorry
066bfbfe 602
8bdb31ed 603 if (empty($user->auth)) {
3f12c146
RW
604 $user->auth = 'manual';
605 }
8bdb31ed 606 $upt->track('auth', $user->auth, 'normal', false);
3f12c146 607
8bdb31ed
PS
608 // do not insert record if new auth plugin does not exist!
609 try {
610 $auth = get_auth_plugin($user->auth);
611 } catch (Exception $e) {
612 $upt->track('auth', get_string('userautherror', 'error', s($user->auth)), 'error');
613 $upt->track('status', $strusernotaddederror, 'error');
614 $userserrors++;
615 continue;
e4e38544 616 }
8bdb31ed
PS
617 if (!isset($supportedauths[$user->auth])) {
618 $upt->track('auth', $struserauthunsupported, 'warning');
066bfbfe 619 }
a2ce7344 620
8bdb31ed
PS
621 $isinternalauth = $auth->is_internal();
622
43070e61
PS
623 if (empty($user->email)) {
624 $upt->track('email', get_string('invalidemail'), 'error');
625 $upt->track('status', $strusernotaddederror, 'error');
626 $userserrors++;
627 continue;
628
629 } else if ($DB->record_exists('user', array('email'=>$user->email))) {
0c4807ab 630 if ($noemailduplicates) {
631 $upt->track('email', $stremailduplicate, 'error');
632 $upt->track('status', $strusernotaddederror, 'error');
633 $userserrors++;
634 continue;
635 } else {
636 $upt->track('email', $stremailduplicate, 'warning');
637 }
638 }
8bdb31ed
PS
639 if (!validate_email($user->email)) {
640 $upt->track('email', get_string('invalidemail'), 'warning');
3f12c146 641 }
0c4807ab 642
8bdb31ed
PS
643 $forcechangepassword = false;
644
645 if ($isinternalauth) {
646 if (empty($user->password)) {
647 if ($createpasswords) {
648 $user->password = 'to be generated';
649 $upt->track('password', '', 'normal', false);
650 $upt->track('password', get_string('uupasswordcron', 'admin'), 'warning', false);
651 } else {
652 $upt->track('password', '', 'normal', false);
653 $upt->track('password', get_string('missingfield', 'error', 'password'), 'error');
654 $upt->track('status', $strusernotaddederror, 'error');
655 $userserrors++;
656 continue;
657 }
3f12c146 658 } else {
8bdb31ed 659 $errmsg = null;
faceca91 660 $weak = !check_password_policy($user->password, $errmsg);
8bdb31ed
PS
661 if ($resetpasswords == UU_PWRESET_ALL or ($resetpasswords == UU_PWRESET_WEAK and $weak)) {
662 if ($weak) {
663 $weakpasswords++;
664 $upt->track('password', $strinvalidpasswordpolicy, 'warning');
665 }
666 $forcechangepassword = true;
667 }
668 $user->password = hash_internal_user_password($user->password);
3f12c146 669 }
8bdb31ed
PS
670 } else {
671 $user->password = 'not cached';
672 $upt->track('password', '-', 'normal', false);
df997f84
PS
673 }
674
8bdb31ed
PS
675 // create user - insert_record ignores any extra properties
676 $user->id = $DB->insert_record('user', $user);
677 $upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$user->id)), s($user->username)), 'normal', false);
678
e4e38544 679 // save custom profile fields data
680 profile_save_data($user);
681
8bdb31ed
PS
682 if ($forcechangepassword) {
683 set_user_preference('auth_forcepasswordchange', 1, $user);
684 }
685 if ($user->password === 'to be generated') {
686 set_user_preference('create_password', 1, $user);
687 }
688
689 $upt->track('status', $struseradded);
690 $upt->track('id', $user->id, 'normal', false);
691 $usersnew++;
692
2304f629 693 // make sure user context exists
a5feb176 694 get_context_instance(CONTEXT_USER, $user->id);
2304f629 695
e6f74ba3
PS
696 events_trigger('user_created', $user);
697
8bdb31ed 698 if ($bulk == UU_BULK_NEW or $bulk == UU_BULK_ALL) {
cd1edf9e 699 if (!in_array($user->id, $SESSION->bulk_users)) {
700 $SESSION->bulk_users[] = $user->id;
066bfbfe 701 }
066bfbfe 702 }
e4e38544 703 }
704
92b59a56
PS
705
706 // add to cohort first, it might trigger enrolments indirectly - do NOT create cohorts here!
707 foreach ($filecolumns as $column) {
708 if (!preg_match('/^cohort\d+$/', $column)) {
709 continue;
710 }
711
712 if (!empty($user->$column)) {
713 $addcohort = $user->$column;
714 if (!isset($cohorts[$addcohort])) {
715 if (is_number($addcohort)) {
716 // only non-numeric idnumbers!
717 $cohort = $DB->get_record('cohort', array('id'=>$addcohort));
718 } else {
719 $cohort = $DB->get_record('cohort', array('idnumber'=>$addcohort));
720 }
721
722 if (empty($cohort)) {
723 $cohorts[$addcohort] = get_string('unknowncohort', 'core_cohort', s($addcohort));
724 } else if (!empty($cohort->component)) {
725 // cohorts synchronised with external sources must not be modified!
726 $cohorts[$addcohort] = get_string('external', 'core_cohort');
727 } else {
728 $cohorts[$addcohort] = $cohort;
729 }
730 }
731
732 if (is_object($cohorts[$addcohort])) {
733 $cohort = $cohorts[$addcohort];
734 if (!$DB->record_exists('cohort_members', array('cohortid'=>$cohort->id, 'userid'=>$user->id))) {
735 cohort_add_member($cohort->id, $user->id);
736 // we might add special column later, for now let's abuse enrolments
737 $upt->track('enrolments', get_string('useradded', 'core_cohort', s($cohort->name)));
738 }
739 } else {
740 // error message
741 $upt->track('enrolments', $cohorts[$addcohort], 'error');
742 }
743 }
744 }
745
746
2686b6c3 747 // find course enrolments, groups, roles/types and enrol periods
8bdb31ed
PS
748 // this is again a special case, we always do this for any updated or created users
749 foreach ($filecolumns as $column) {
e4e38544 750 if (!preg_match('/^course\d+$/', $column)) {
751 continue;
752 }
753 $i = substr($column, 6);
6b09974b 754
df997f84
PS
755 if (empty($user->{'course'.$i})) {
756 continue;
757 }
e4e38544 758 $shortname = $user->{'course'.$i};
759 if (!array_key_exists($shortname, $ccache)) {
df997f84 760 if (!$course = $DB->get_record('course', array('shortname'=>$shortname), 'id, shortname')) {
8bdb31ed 761 $upt->track('enrolments', get_string('unknowncourse', 'error', s($shortname)), 'error');
a7db355a 762 continue;
066bfbfe 763 }
e4e38544 764 $ccache[$shortname] = $course;
765 $ccache[$shortname]->groups = null;
766 }
767 $courseid = $ccache[$shortname]->id;
768 $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
df997f84 769 if (!isset($manualcache[$courseid])) {
4cb02426
PS
770 $manualcache[$courseid] = false;
771 if ($manual) {
772 if ($instances = enrol_get_instances($courseid, false)) {
773 foreach ($instances as $instance) {
774 if ($instance->enrol === 'manual') {
775 $manualcache[$courseid] = $instance;
776 break;
777 }
778 }
779 }
e4e38544 780 }
df997f84 781 }
e4e38544 782
df997f84
PS
783 if ($manual and $manualcache[$courseid]) {
784
785 // find role
786 $rid = false;
787 if (!empty($user->{'role'.$i})) {
788 $addrole = $user->{'role'.$i};
789 if (array_key_exists($addrole, $rolecache)) {
790 $rid = $rolecache[$addrole]->id;
e4e38544 791 } else {
8bdb31ed 792 $upt->track('enrolments', get_string('unknownrole', 'error', s($addrole)), 'error');
df997f84 793 continue;
a7db355a 794 }
e4e38544 795
df997f84
PS
796 } else if (!empty($user->{'type'.$i})) {
797 // if no role, then find "old" enrolment type
798 $addtype = $user->{'type'.$i};
799 if ($addtype < 1 or $addtype > 3) {
800 $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error');
801 continue;
802 } else if (empty($formdata->{'uulegacy'.$addtype})) {
803 continue;
804 } else {
805 $rid = $formdata->{'uulegacy'.$addtype};
806 }
e4e38544 807 } else {
df997f84
PS
808 // no role specified, use the default from manual enrol plugin
809 $rid = $manualcache[$courseid]->roleid;
a7db355a 810 }
2686b6c3 811
df997f84
PS
812 if ($rid) {
813 // find duration
df997f84
PS
814 $timeend = 0;
815 if (!empty($user->{'enrolperiod'.$i})) {
8bdb31ed 816 $duration = (int)$user->{'enrolperiod'.$i} * 60*60*24; // convert days to seconds
df997f84 817 if ($duration > 0) { // sanity check
8bdb31ed 818 $timeend = $today + $duration;
df997f84
PS
819 }
820 }
2686b6c3 821
02c97e65 822 $manual->enrol_user($manualcache[$courseid], $user->id, $rid, $today, $timeend);
df997f84 823
a226a972 824 $a = new stdClass();
df997f84
PS
825 $a->course = $shortname;
826 $a->role = $rolecache[$rid]->name;
827 $upt->track('enrolments', get_string('enrolledincourserole', 'enrol_manual', $a));
066bfbfe 828 }
e4e38544 829 }
6b09974b 830
e4e38544 831 // find group to add to
832 if (!empty($user->{'group'.$i})) {
833 // make sure user is enrolled into course before adding into groups
4f0c2d00 834 if (!is_enrolled($coursecontext, $user->id)) {
d85f2634 835 $upt->track('enrolments', get_string('addedtogroupnotenrolled', '', $user->{'group'.$i}), 'error');
e4e38544 836 continue;
837 }
838 //build group cache
839 if (is_null($ccache[$shortname]->groups)) {
840 $ccache[$shortname]->groups = array();
35987665 841 if ($groups = groups_get_all_groups($courseid)) {
e4e38544 842 foreach ($groups as $gid=>$group) {
a226a972 843 $ccache[$shortname]->groups[$gid] = new stdClass();
e4e38544 844 $ccache[$shortname]->groups[$gid]->id = $gid;
845 $ccache[$shortname]->groups[$gid]->name = $group->name;
846 if (!is_numeric($group->name)) { // only non-numeric names are supported!!!
8bdb31ed
PS
847 $ccache[$shortname]->groups[$group->name] = new stdClass();
848 $ccache[$shortname]->groups[$group->name]->id = $gid;
849 $ccache[$shortname]->groups[$group->name]->name = $group->name;
a7db355a 850 }
a5702569 851 }
0063abee 852 }
6b09974b 853 }
e4e38544 854 // group exists?
855 $addgroup = $user->{'group'.$i};
856 if (!array_key_exists($addgroup, $ccache[$shortname]->groups)) {
b225cf36 857 // if group doesn't exist, create it
a226a972 858 $newgroupdata = new stdClass();
b225cf36 859 $newgroupdata->name = $addgroup;
860 $newgroupdata->courseid = $ccache[$shortname]->id;
861 if ($ccache[$shortname]->groups[$addgroup]->id = groups_create_group($newgroupdata)){
862 $ccache[$shortname]->groups[$addgroup]->name = $newgroupdata->name;
863 } else {
8bdb31ed 864 $upt->track('enrolments', get_string('unknowngroup', 'error', s($addgroup)), 'error');
b225cf36 865 continue;
866 }
e4e38544 867 }
868 $gid = $ccache[$shortname]->groups[$addgroup]->id;
869 $gname = $ccache[$shortname]->groups[$addgroup]->name;
870
9c000a99 871 try {
872 if (groups_add_member($gid, $user->id)) {
8bdb31ed 873 $upt->track('enrolments', get_string('addedtogroup', '', s($gname)));
df997f84 874 } else {
8bdb31ed 875 $upt->track('enrolments', get_string('addedtogroupnot', '', s($gname)), 'error');
9c000a99 876 }
877 } catch (moodle_exception $e) {
8bdb31ed 878 $upt->track('enrolments', get_string('addedtogroupnot', '', s($gname)), 'error');
e4e38544 879 continue;
880 }
a5702569 881 }
066bfbfe 882 }
883 }
e4e38544 884 $upt->close(); // close table
885
886 $cir->close();
887 $cir->cleanup(true);
888
20486a5a 889 echo $OUTPUT->box_start('boxwidthnarrow boxaligncenter generalbox', 'uploadresults');
e4e38544 890 echo '<p>';
8bdb31ed 891 if ($optype != UU_USER_UPDATE) {
e4e38544 892 echo get_string('userscreated', 'admin').': '.$usersnew.'<br />';
893 }
8bdb31ed 894 if ($optype == UU_USER_UPDATE or $optype == UU_USER_ADD_UPDATE) {
e4e38544 895 echo get_string('usersupdated', 'admin').': '.$usersupdated.'<br />';
896 }
897 if ($allowdeletes) {
898 echo get_string('usersdeleted', 'admin').': '.$deletes.'<br />';
899 echo get_string('deleteerrors', 'admin').': '.$deleteerrors.'<br />';
900 }
901 if ($allowrenames) {
902 echo get_string('usersrenamed', 'admin').': '.$renames.'<br />';
903 echo get_string('renameerrors', 'admin').': '.$renameerrors.'<br />';
904 }
905 if ($usersskipped) {
906 echo get_string('usersskipped', 'admin').': '.$usersskipped.'<br />';
907 }
d6bb2d2f 908 echo get_string('usersweakpassword', 'admin').': '.$weakpasswords.'<br />';
e4e38544 909 echo get_string('errors', 'admin').': '.$userserrors.'</p>';
20486a5a 910 echo $OUTPUT->box_end();
e4e38544 911
912 if ($bulk) {
8fbce1c8 913 echo $OUTPUT->continue_button($bulknurl);
e4e38544 914 } else {
8fbce1c8 915 echo $OUTPUT->continue_button($returnurl);
e4e38544 916 }
73d6f52f 917 echo $OUTPUT->footer();
df7ecfe4 918 die;
6b09974b 919}
0a6150ca 920
df7ecfe4 921// Print the header
61ef8f9f 922echo $OUTPUT->header();
df7ecfe4 923
6c7a5df7 924echo $OUTPUT->heading(get_string('uploaduserspreview', 'admin'));
df7ecfe4 925
8bdb31ed
PS
926// NOTE: this is JUST csv processing preview, we must not prevent import from here if there is something in the file!!
927// this was intended for validation of csv formatting and encoding, not filtering the data!!!!
928// we definitely must not process the whole file!
929
930// preview table data
931$data = array();
e4e38544 932$cir->init();
8bdb31ed
PS
933$linenum = 1; //column header is first line
934while ($linenum <= $previewrows and $fields = $cir->next()) {
935 $linenum++;
3fe2cfb5 936 $rowcols = array();
8bdb31ed
PS
937 $rowcols['line'] = $linenum;
938 foreach($fields as $key => $field) {
939 $rowcols[$filecolumns[$key]] = s($field);
3fe2cfb5 940 }
8bdb31ed 941 $rowcols['status'] = array();
3fe2cfb5 942
8bdb31ed
PS
943 if (isset($rowcols['username'])) {
944 $stdusername = clean_param($rowcols['username'], PARAM_USERNAME);
945 if ($rowcols['username'] !== $stdusername) {
946 $rowcols['status'][] = get_string('invalidusernameupload');
3fe2cfb5 947 }
8bdb31ed
PS
948 if ($userid = $DB->get_field('user', 'id', array('username'=>$stdusername, 'mnethostid'=>$CFG->mnet_localhost_id))) {
949 $rowcols['username'] = html_writer::link(new moodle_url('/user/profile.php', array('id'=>$userid)), $rowcols['username']);
e4e38544 950 }
8bdb31ed
PS
951 } else {
952 $rowcols['status'][] = get_string('missingusername');
df7ecfe4 953 }
07ed083e 954
43070e61
PS
955 if (isset($rowcols['email'])) {
956 if (!validate_email($rowcols['email'])) {
957 $rowcols['status'][] = get_string('invalidemail');
958 }
959 if ($DB->record_exists('user', array('email'=>$rowcols['email']))) {
960 $rowcols['status'][] = $stremailduplicate;
961 }
07ed083e 962 }
fd9672ac
RW
963
964 if (isset($rowcols['city'])) {
965 $rowcols['city'] = trim($rowcols['city']);
966 if (empty($rowcols['city'])) {
967 $rowcols['status'][] = get_string('fieldrequired', 'error', 'city');
968 }
969 }
970
8bdb31ed
PS
971 $rowcols['status'] = implode('<br />', $rowcols['status']);
972 $data[] = $rowcols;
07ed083e 973}
8bdb31ed
PS
974if ($fields = $cir->next()) {
975 $data[] = array_fill(0, count($fields) + 2, '...');
07ed083e 976}
8bdb31ed 977$cir->close();
3fe2cfb5
RW
978
979$table = new html_table();
980$table->id = "uupreview";
16be8974 981$table->attributes['class'] = 'generaltable';
3fe2cfb5
RW
982$table->tablealign = 'center';
983$table->summary = get_string('uploaduserspreview', 'admin');
984$table->head = array();
8bdb31ed 985$table->data = $data;
3fe2cfb5 986
8bdb31ed
PS
987$table->head[] = get_string('uucsvline', 'admin');
988foreach ($filecolumns as $column) {
989 $table->head[] = $column;
07ed083e 990}
8bdb31ed 991$table->head[] = get_string('status');
07ed083e 992
3f12c146 993echo html_writer::tag('div', html_writer::table($table), array('class'=>'flexible-wrap'));
3fe2cfb5 994
8bdb31ed 995/// Print the form
07ed083e 996
8bdb31ed 997$mform2->display();
73d6f52f 998echo $OUTPUT->footer();
df7ecfe4 999die;
1000