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