gradebook MDL-21218 course and category totals behaviour when they contain hidden...
[moodle.git] / admin / uploaduser.php
CommitLineData
9e492db0 1<?php
0a6150ca 2
3/// Bulk user registration script from a comma separated file
4/// Returns list of users with their user ids
5
e4e38544 6require('../config.php');
cc891abe 7require_once($CFG->libdir.'/adminlib.php');
e4e38544 8require_once($CFG->libdir.'/csvlib.class.php');
9require_once($CFG->dirroot.'/user/profile/lib.php');
0a5dffcc 10require_once('uploaduser_form.php');
1ae083e4 11
e4e38544 12$iid = optional_param('iid', '', PARAM_INT);
df7ecfe4 13$previewrows = optional_param('previewrows', 10, PARAM_INT);
e4e38544 14$readcount = optional_param('readcount', 0, PARAM_INT);
df7ecfe4 15
e4e38544 16define('UU_ADDNEW', 0);
17define('UU_ADDINC', 1);
18define('UU_ADD_UPDATE', 2);
19define('UU_UPDATE', 3);
066bfbfe 20
df7ecfe4 21@set_time_limit(3600); // 1 hour should be enough
22@raise_memory_limit('256M');
23if (function_exists('apache_child_terminate')) {
e4e38544 24 // if we are running from Apache, give httpd a hint that
25 // it can recycle the process after it's done. Apache's
df7ecfe4 26 // memory management is truly awful but we can help it.
27 @apache_child_terminate();
28}
0a6150ca 29
ebff4779 30require_login();
066bfbfe 31admin_externalpage_setup('uploadusers');
1ae083e4 32require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM));
0a6150ca 33
1c0ccfd6 34$textlib = textlib_get_instance();
e4e38544 35$systemcontext = get_context_instance(CONTEXT_SYSTEM);
36
37$struserrenamed = get_string('userrenamed', 'admin');
38$strusernotrenamedexists = get_string('usernotrenamedexists', 'error');
39$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error');
40$strusernotrenamedoff = get_string('usernotrenamedoff', 'error');
41$strusernotrenamedadmin = get_string('usernotrenamedadmin', 'error');
42
43$struserupdated = get_string('useraccountupdated', 'admin');
44$strusernotupdated = get_string('usernotupdatederror', 'error');
45$strusernotupdatednotexists = get_string('usernotupdatednotexists', 'error');
46$strusernotupdatedadmin = get_string('usernotupdatedadmin', 'error');
47
48$struseradded = get_string('newuser');
49$strusernotadded = get_string('usernotaddedregistered', 'error');
50$strusernotaddederror = get_string('usernotaddederror', 'error');
51
52$struserdeleted = get_string('userdeleted', 'admin');
53$strusernotdeletederror = get_string('usernotdeletederror', 'error');
54$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error');
55$strusernotdeletedoff = get_string('usernotdeletedoff', 'error');
56$strusernotdeletedadmin = get_string('usernotdeletedadmin', 'error');
57
58$strcannotassignrole = get_string('cannotassignrole', 'error');
59$strduplicateusername = get_string('duplicateusername', 'error');
60
61$struserauthunsupported = get_string('userauthunsupported', 'error');
0c4807ab 62$stremailduplicate = get_string('useremailduplicate', 'error');;
e4e38544 63
64$errorstr = get_string('error');
ca23a9c9 65
e4e38544 66$returnurl = $CFG->wwwroot.'/'.$CFG->admin.'/uploaduser.php';
67$bulknurl = $CFG->wwwroot.'/'.$CFG->admin.'/user/user_bulk.php';
68
69// array of all valid fields for validation
6dbcacee 70$STD_FIELDS = array('id', 'firstname', 'lastname', 'username', 'email',
71 'city', 'country', 'lang', 'auth', 'timezone', 'mailformat',
72 'maildisplay', 'maildigest', 'htmleditor', 'ajax', 'autosubscribe',
73 'mnethostid', 'institution', 'department', 'idnumber', 'skype',
74 'msn', 'aim', 'yahoo', 'icq', 'phone1', 'phone2', 'address',
8bdc9cac 75 'url', 'description', 'descriptionformat', 'oldusername', 'emailstop', 'deleted',
c79106c4 76 'password');
e4e38544 77
78$PRF_FIELDS = array();
79
1d8bf5f0 80if ($prof_fields = $DB->get_records('user_info_field')) {
e4e38544 81 foreach ($prof_fields as $prof_field) {
82 $PRF_FIELDS[] = 'profile_field_'.$prof_field->shortname;
83 }
84 unset($prof_fields);
85}
86
87if (empty($iid)) {
df7ecfe4 88 $mform = new admin_uploaduser_form1();
0a6150ca 89
df7ecfe4 90 if ($formdata = $mform->get_data()) {
e4e38544 91 $iid = csv_import_reader::get_new_iid('uploaduser');
92 $cir = new csv_import_reader($iid, 'uploaduser');
df7ecfe4 93
e4e38544 94 $content = $mform->get_file_content('userfile');
df7ecfe4 95
e4e38544 96 $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name, 'validate_user_upload_columns');
97 unset($content);
df7ecfe4 98
e4e38544 99 if ($readcount === false) {
bd8ee7c1 100 //TODO: need more detailed error info
101 print_error('csvloaderror', '', $returnurl);
e4e38544 102 } else if ($readcount == 0) {
5a2a5331 103 print_error('csvemptyfile', 'error', $returnurl);
ed22a01b 104 }
e4e38544 105 // continue to form2
df7ecfe4 106
107 } else {
108 admin_externalpage_print_header();
9e492db0 109
4bcc5118 110 echo $OUTPUT->heading_with_help(get_string('uploadusers'), 'uploadusers3');
9e492db0 111
df7ecfe4 112 $mform->display();
73d6f52f 113 echo $OUTPUT->footer();
df7ecfe4 114 die;
115 }
e4e38544 116} else {
117 $cir = new csv_import_reader($iid, 'uploaduser');
df7ecfe4 118}
119
e4e38544 120if (!$columns = $cir->get_columns()) {
8e9d88f2 121 print_error('cannotreadtmpfile', 'error', $returnurl);
e4e38544 122}
123$mform = new admin_uploaduser_form2(null, $columns);
124// get initial date from form1
125$mform->set_data(array('iid'=>$iid, 'previewrows'=>$previewrows, 'readcount'=>$readcount));
df7ecfe4 126
127// If a file has been uploaded, then process it
128if ($formdata = $mform->is_cancelled()) {
e4e38544 129 $cir->cleanup(true);
130 redirect($returnurl);
df7ecfe4 131
294ce987 132} else if ($formdata = $mform->get_data()) {
df7ecfe4 133 // Print the header
134 admin_externalpage_print_header();
2fff8846 135 echo $OUTPUT->heading(get_string('uploadusersresult', 'admin'));
e4e38544 136
137 $optype = $formdata->uutype;
138
0c4807ab 139 $createpasswords = (!empty($formdata->uupasswordnew) and $optype != UU_UPDATE);
140 $updatepasswords = (!empty($formdata->uupasswordold) and $optype != UU_ADDNEW and $optype != UU_ADDINC);
141 $allowrenames = (!empty($formdata->uuallowrenames) and $optype != UU_ADDNEW and $optype != UU_ADDINC);
142 $allowdeletes = (!empty($formdata->uuallowdeletes) and $optype != UU_ADDNEW and $optype != UU_ADDINC);
143 $updatetype = isset($formdata->uuupdatetype) ? $formdata->uuupdatetype : 0;
144 $bulk = $formdata->uubulk;
145 $noemailduplicates = $formdata->uunoemailduplicates;
e4e38544 146
147 // verification moved to two places: after upload and into form2
148 $usersnew = 0;
149 $usersupdated = 0;
150 $userserrors = 0;
151 $deletes = 0;
152 $deleteerrors = 0;
153 $renames = 0;
154 $renameerrors = 0;
155 $usersskipped = 0;
d6bb2d2f 156 $weakpasswords = 0;
feecd4d6 157
e4e38544 158 // caches
159 $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway!
160 $rolecache = array(); // roles lookup cache
161
162 $allowedauths = uu_allowed_auths();
163 $allowedauths = array_keys($allowedauths);
17da2e6f 164 $availableauths = get_plugin_list('auth');
165 $availableauths = array_keys($availableauths);
e4e38544 166
167 $allowedroles = uu_allowed_roles(true);
168 foreach ($allowedroles as $rid=>$rname) {
169 $rolecache[$rid] = new object();
170 $rolecache[$rid]->id = $rid;
171 $rolecache[$rid]->name = $rname;
172 if (!is_numeric($rname)) { // only non-numeric shornames are supported!!!
173 $rolecache[$rname] = new object();
174 $rolecache[$rname]->id = $rid;
175 $rolecache[$rname]->name = $rname;
176 }
177 }
178 unset($allowedroles);
df7ecfe4 179
b4bd91ce 180 // clear bulk selection
e4e38544 181 if ($bulk) {
cd1edf9e 182 $SESSION->bulk_users = array();
e4e38544 183 }
df7ecfe4 184
e4e38544 185 // init csv import helper
186 $cir->init();
187 $linenum = 1; //column header is first line
df7ecfe4 188
e4e38544 189 // init upload progress tracker
190 $upt = new uu_progress_tracker();
191 $upt->init(); // start table
a2ce7344 192
e4e38544 193 while ($line = $cir->next()) {
194 $upt->flush();
195 $linenum++;
196
197 $upt->track('line', $linenum);
198
d6bb2d2f
PS
199 $forcechangepassword = false;
200
e4e38544 201 $user = new object();
202 // by default, use the local mnet id (this may be changed in the file)
203 $user->mnethostid = $CFG->mnet_localhost_id;
204 // add fields to user object
205 foreach ($line as $key => $value) {
206 if ($value !== '') {
207 $key = $columns[$key];
d3d393ab 208 $user->timecreated = time();
e4e38544 209 // password is special field
210 if ($key == 'password') {
211 if ($value !== '') {
212 $user->password = hash_internal_user_password($value);
feecd4d6 213 if (!empty($CFG->passwordpolicy) and !check_password_policy($value, $errmsg)) {
d6bb2d2f
PS
214 $forcechangepassword = true;
215 $weakpasswords++;
feecd4d6 216 }
e4e38544 217 }
218 } else {
219 $user->$key = $value;
220 if (in_array($key, $upt->columns)) {
221 $upt->track($key, $value);
222 }
223 }
a7db355a 224 }
225 }
e4e38544 226
227 // get username, first/last name now - we need them in templates!!
228 if ($optype == UU_UPDATE) {
229 // when updating only username is required
230 if (!isset($user->username)) {
231 $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
232 $upt->track('username', $errorstr, 'error');
233 $userserrors++;
234 continue;
235 }
236
237 } else {
238 $error = false;
239 // when all other ops need firstname and lastname
240 if (!isset($user->firstname) or $user->firstname === '') {
241 $upt->track('status', get_string('missingfield', 'error', 'firstname'), 'error');
242 $upt->track('firstname', $errorstr, 'error');
243 $error = true;
244 }
245 if (!isset($user->lastname) or $user->lastname === '') {
246 $upt->track('status', get_string('missingfield', 'error', 'lastname'), 'error');
247 $upt->track('lastname', $errorstr, 'error');
248 $error = true;
249 }
250 if ($error) {
251 $userserrors++;
252 continue;
253 }
254 // we require username too - we might use template for it though
255 if (!isset($user->username)) {
256 if (!isset($formdata->username) or $formdata->username === '') {
257 $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
258 $upt->track('username', $errorstr, 'error');
259 $userserrors++;
260 continue;
261 } else {
262 $user->username = process_template($formdata->username, $user);
263 $upt->track('username', $user->username);
264 }
265 }
a7db355a 266 }
e4e38544 267
268 // normalize username
07ed083e
RW
269 $user->username = clean_param($user->username, PARAM_USERNAME);
270
e4e38544 271 if (empty($user->username)) {
272 $upt->track('status', get_string('missingfield', 'error', 'username'), 'error');
273 $upt->track('username', $errorstr, 'error');
274 $userserrors++;
275 continue;
276 }
277
1d8bf5f0 278 if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$user->mnethostid))) {
e4e38544 279 $upt->track('id', $existinguser->id, 'normal', false);
280 }
281
282 // find out in username incrementing required
283 if ($existinguser and $optype == UU_ADDINC) {
284 $oldusername = $user->username;
285 $user->username = increment_username($user->username, $user->mnethostid);
286 $upt->track('username', '', 'normal', false); // clear previous
287 $upt->track('username', $oldusername.'-->'.$user->username, 'info');
288 $existinguser = false;
289 }
290
291 // add default values for remaining fields
292 foreach ($STD_FIELDS as $field) {
293 if (isset($user->$field)) {
294 continue;
295 }
296 // all validation moved to form2
297 if (isset($formdata->$field)) {
298 // process templates
299 $user->$field = process_template($formdata->$field, $user);
300 }
301 }
302 foreach ($PRF_FIELDS as $field) {
303 if (isset($user->$field)) {
304 continue;
305 }
306 if (isset($formdata->$field)) {
307 // process templates
308 $user->$field = process_template($formdata->$field, $user);
309 }
310 }
311
312 // delete user
313 if (!empty($user->deleted)) {
314 if (!$allowdeletes) {
315 $usersskipped++;
316 $upt->track('status', $strusernotdeletedoff, 'warning');
317 continue;
318 }
319 if ($existinguser) {
320 if (has_capability('moodle/site:doanything', $systemcontext, $existinguser->id)) {
321 $upt->track('status', $strusernotdeletedadmin, 'error');
322 $deleteerrors++;
323 continue;
324 }
325 if (delete_user($existinguser)) {
326 $upt->track('status', $struserdeleted);
327 $deletes++;
328 } else {
329 $upt->track('status', $strusernotdeletederror, 'error');
330 $deleteerrors++;
6b09974b 331 }
e4e38544 332 } else {
333 $upt->track('status', $strusernotdeletedmissing, 'error');
334 $deleteerrors++;
335 }
336 continue;
337 }
338 // we do not need the deleted flag anymore
339 unset($user->deleted);
340
341 // renaming requested?
342 if (!empty($user->oldusername) ) {
343 $oldusername = $textlib->strtolower($user->oldusername);
344 if (!$allowrenames) {
345 $usersskipped++;
346 $upt->track('status', $strusernotrenamedoff, 'warning');
347 continue;
348 }
349
350 if ($existinguser) {
351 $upt->track('status', $strusernotrenamedexists, 'error');
352 $renameerrors++;
353 continue;
16a1fed4 354 }
ed22a01b 355
1d8bf5f0 356 if ($olduser = $DB->get_record('user', array('username'=>$oldusername, 'mnethostid'=>$user->mnethostid))) {
e4e38544 357 $upt->track('id', $olduser->id, 'normal', false);
358 if (has_capability('moodle/site:doanything', $systemcontext, $olduser->id)) {
359 $upt->track('status', $strusernotrenamedadmin, 'error');
360 $renameerrors++;
a7db355a 361 continue;
0063abee 362 }
1d8bf5f0 363 if ($DB->set_field('user', 'username', $user->username, array('id'=>$olduser->id))) {
e4e38544 364 $upt->track('username', '', 'normal', false); // clear previous
365 $upt->track('username', $oldusername.'-->'.$user->username, 'info');
366 $upt->track('status', $struserrenamed);
367 $renames++;
368 } else {
369 $upt->track('status', $strusernotrenamedexists, 'error');
370 $renameerrors++;
a7db355a 371 continue;
372 }
e4e38544 373 } else {
374 $upt->track('status', $strusernotrenamedmissing, 'error');
375 $renameerrors++;
376 continue;
377 }
378 $existinguser = $olduser;
379 $existinguser->username = $user->username;
380 }
381
382 // can we process with update or insert?
383 $skip = false;
384 switch ($optype) {
385 case UU_ADDNEW:
386 if ($existinguser) {
387 $usersskipped++;
388 $upt->track('status', $strusernotadded, 'warning');
389 $skip = true;;
390 }
391 break;
392
393 case UU_ADDINC:
394 if ($existinguser) {
395 //this should not happen!
396 $upt->track('status', $strusernotaddederror, 'error');
397 $userserrors++;
398 continue;
399 }
400 break;
401
402 case UU_ADD_UPDATE:
403 break;
404
405 case UU_UPDATE:
406 if (!$existinguser) {
407 $usersskipped++;
408 $upt->track('status', $strusernotupdatednotexists, 'warning');
409 $skip = true;
410 }
411 break;
412 }
413
414 if ($skip) {
415 continue;
416 }
417
418 if ($existinguser) {
419 $user->id = $existinguser->id;
420
421 if (has_capability('moodle/site:doanything', $systemcontext, $user->id)) {
422 $upt->track('status', $strusernotupdatedadmin, 'error');
423 $userserrors++;
424 continue;
425 }
426
427 if (!$updatetype) {
428 // no updates of existing data at all
429 } else {
430 $existinguser->timemodified = time();
431 //load existing profile data
432 profile_load_data($existinguser);
433
434 $allowed = array();
435 if ($updatetype == 1) {
436 $allowed = $columns;
437 } else if ($updatetype == 2 or $updatetype == 3) {
438 $allowed = array_merge($STD_FIELDS, $PRF_FIELDS);
439 }
440 foreach ($allowed as $column) {
441 if ($column == 'username') {
442 continue;
443 }
444 if ($column == 'password') {
445 if (!$updatepasswords or $updatetype == 3) {
a7db355a 446 continue;
e4e38544 447 } else if (!empty($user->password)) {
448 $upt->track('password', get_string('updated'));
feecd4d6 449 if ($forcechangepassword) {
450 set_user_preference('auth_forcepasswordchange', 1, $existinguser->id);
451 }
a7db355a 452 }
e4e38544 453 }
454 if ((array_key_exists($column, $existinguser) and array_key_exists($column, $user)) or in_array($column, $PRF_FIELDS)) {
455 if ($updatetype == 3 and $existinguser->$column !== '') {
456 //missing == non-empty only
457 continue;
a7db355a 458 }
e4e38544 459 if ($existinguser->$column !== $user->$column) {
0c4807ab 460 if ($column == 'email') {
1d8bf5f0 461 if ($DB->record_exists('user', array('email'=>$user->email))) {
0c4807ab 462 if ($noemailduplicates) {
463 $upt->track('email', $stremailduplicate, 'error');
464 $upt->track('status', $strusernotupdated, 'error');
465 $userserrors++;
466 continue 2;
467 } else {
468 $upt->track('email', $stremailduplicate, 'warning');
469 }
470 }
471 }
e4e38544 472 if ($column != 'password' and in_array($column, $upt->columns)) {
473 $upt->track($column, '', 'normal', false); // clear previous
474 $upt->track($column, $existinguser->$column.'-->'.$user->$column, 'info');
475 }
476 $existinguser->$column = $user->$column;
a7db355a 477 }
6b09974b 478 }
a7db355a 479 }
ed22a01b 480
e4e38544 481 // do not update record if new auth plguin does not exist!
482 if (!in_array($existinguser->auth, $availableauths)) {
483 $upt->track('auth', get_string('userautherror', 'error', $existinguser->auth), 'error');
484 $upt->track('status', $strusernotupdated, 'error');
485 $userserrors++;
486 continue;
487 } else if (!in_array($existinguser->auth, $allowedauths)) {
488 $upt->track('auth', $struserauthunsupported, 'warning');
066bfbfe 489 }
a7db355a 490
1d8bf5f0 491 if ($DB->update_record('user', $existinguser)) {
e4e38544 492 $upt->track('status', $struserupdated);
493 $usersupdated++;
a7db355a 494 } else {
e4e38544 495 $upt->track('status', $strusernotupdated, 'error');
496 $userserrors++;
497 continue;
498 }
499 // save custom profile fields data from csv file
5d910388 500 profile_save_data($existinguser);
e4e38544 501 }
502
503 if ($bulk == 2 or $bulk == 3) {
cd1edf9e 504 if (!in_array($user->id, $SESSION->bulk_users)) {
505 $SESSION->bulk_users[] = $user->id;
ed22a01b 506 }
066bfbfe 507 }
ed22a01b 508
e4e38544 509 } else {
a7db355a 510 // save the user to the database
511 $user->confirmed = 1;
512 $user->timemodified = time();
066bfbfe 513
e4e38544 514 if (!$createpasswords and empty($user->password)) {
515 $upt->track('password', get_string('missingfield', 'error', 'password'), 'error');
516 $upt->track('status', $strusernotaddederror, 'error');
517 $userserrors++;
518 continue;
519 }
520
521 // do not insert record if new auth plguin does not exist!
522 if (isset($user->auth)) {
523 if (!in_array($user->auth, $availableauths)) {
524 $upt->track('auth', get_string('userautherror', 'error', $user->auth), 'error');
525 $upt->track('status', $strusernotaddederror, 'error');
526 $userserrors++;
066bfbfe 527 continue;
e4e38544 528 } else if (!in_array($user->auth, $allowedauths)) {
529 $upt->track('auth', $struserauthunsupported, 'warning');
066bfbfe 530 }
066bfbfe 531 }
a2ce7344 532
1d8bf5f0 533 if ($DB->record_exists('user', array('email'=>$user->email))) {
0c4807ab 534 if ($noemailduplicates) {
535 $upt->track('email', $stremailduplicate, 'error');
536 $upt->track('status', $strusernotaddederror, 'error');
537 $userserrors++;
538 continue;
539 } else {
540 $upt->track('email', $stremailduplicate, 'warning');
541 }
542 }
543
1d8bf5f0 544 if ($user->id = $DB->insert_record('user', $user)) {
e4e38544 545 $info = ': ' . $user->username .' (ID = ' . $user->id . ')';
546 $upt->track('status', $struseradded);
547 $upt->track('id', $user->id, 'normal', false);
548 $usersnew++;
549 if ($createpasswords and empty($user->password)) {
550 // passwords will be created and sent out on cron
551 set_user_preference('create_password', 1, $user->id);
552 set_user_preference('auth_forcepasswordchange', 1, $user->id);
553 $upt->track('password', get_string('new'));
066bfbfe 554 }
feecd4d6 555 if ($forcechangepassword) {
556 set_user_preference('auth_forcepasswordchange', 1, $user->id);
557 }
e4e38544 558 } else {
559 // Record not added -- possibly some other error
560 $upt->track('status', $strusernotaddederror, 'error');
561 $userserrors++;
562 continue;
563 }
564 // save custom profile fields data
565 profile_save_data($user);
566
2304f629 567 // make sure user context exists
a5feb176 568 get_context_instance(CONTEXT_USER, $user->id);
2304f629 569
e4e38544 570 if ($bulk == 1 or $bulk == 3) {
cd1edf9e 571 if (!in_array($user->id, $SESSION->bulk_users)) {
572 $SESSION->bulk_users[] = $user->id;
066bfbfe 573 }
066bfbfe 574 }
e4e38544 575 }
576
2686b6c3 577 // find course enrolments, groups, roles/types and enrol periods
e4e38544 578 foreach ($columns as $column) {
579 if (!preg_match('/^course\d+$/', $column)) {
580 continue;
581 }
582 $i = substr($column, 6);
6b09974b 583
e4e38544 584 $shortname = $user->{'course'.$i};
585 if (!array_key_exists($shortname, $ccache)) {
1d8bf5f0 586 if (!$course = $DB->get_record('course', array('shortname'=>$shortname), 'id, shortname, defaultrole')) {
e4e38544 587 $upt->track('enrolments', get_string('unknowncourse', 'error', $shortname), 'error');
a7db355a 588 continue;
066bfbfe 589 }
e4e38544 590 $ccache[$shortname] = $course;
591 $ccache[$shortname]->groups = null;
592 }
593 $courseid = $ccache[$shortname]->id;
594 $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
595
596 // find role
597 $rid = false;
598 if (!empty($user->{'role'.$i})) {
599 $addrole = $user->{'role'.$i};
600 if (array_key_exists($addrole, $rolecache)) {
601 $rid = $rolecache[$addrole]->id;
a7db355a 602 } else {
e4e38544 603 $upt->track('enrolments', get_string('unknownrole', 'error', $addrole), 'error');
604 continue;
605 }
606
607 } else if (!empty($user->{'type'.$i})) {
608 // if no role, then find "old" enrolment type
609 $addtype = $user->{'type'.$i};
610 if ($addtype < 1 or $addtype > 3) {
611 $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error');
612 continue;
613 } else if ($addtype == 1 and empty($formdata->uulegacy1)) {
614 if (empty($ccache[$shortname]->defaultrole)) {
615 $rid = $CFG->defaultcourseroleid;
616 } else {
617 $rid = $ccache[$shortname]->defaultrole;
a7db355a 618 }
e4e38544 619 } else {
620 $rid = $formdata->{'uulegacy'.$addtype};
621 }
622
623 } else {
624 // no role specified, use the default
625 if (empty($ccache[$shortname]->defaultrole)) {
626 $rid = $CFG->defaultcourseroleid;
627 } else {
628 $rid = $ccache[$shortname]->defaultrole;
a7db355a 629 }
e4e38544 630 }
2686b6c3 631
632 // find duration
633 $timestart = 0;
634 $timeend = 0;
635 if (!empty($user->{'enrolperiod'.$i})) {
636 $duration = (int)$user->{'enrolperiod'.$i} * 86400; // convert days to seconds
637 if ($duration > 0) { // sanity check
638 $timestart = time();
639 $timeend = $timestart + $duration;
640 }
641 }
642
e4e38544 643 if ($rid) {
644 $a = new object();
645 $a->course = $shortname;
646 $a->role = $rolecache[$rid]->name;
2686b6c3 647 if (role_assign($rid, $user->id, 0, $coursecontext->id, $timestart, $timeend)) {
e4e38544 648 $upt->track('enrolments', get_string('enrolledincourserole', '', $a));
a7db355a 649 } else {
e4e38544 650 $upt->track('enrolments', get_string('enrolledincoursenotrole', '', $a), 'error');
066bfbfe 651 }
e4e38544 652 }
6b09974b 653
e4e38544 654 // find group to add to
655 if (!empty($user->{'group'.$i})) {
656 // make sure user is enrolled into course before adding into groups
657 if (!has_capability('moodle/course:view', $coursecontext, $user->id, false)) {
658 $upt->track('enrolments', get_string('addedtogroupnotenrolled', '', $gname), 'error');
659 continue;
660 }
661 //build group cache
662 if (is_null($ccache[$shortname]->groups)) {
663 $ccache[$shortname]->groups = array();
35987665 664 if ($groups = groups_get_all_groups($courseid)) {
e4e38544 665 foreach ($groups as $gid=>$group) {
666 $ccache[$shortname]->groups[$gid] = new object();
667 $ccache[$shortname]->groups[$gid]->id = $gid;
668 $ccache[$shortname]->groups[$gid]->name = $group->name;
669 if (!is_numeric($group->name)) { // only non-numeric names are supported!!!
670 $ccache[$shortname]->groups[$group->name] = new object();
671 $ccache[$shortname]->groups[$group->name]->id = $gid;
672 $ccache[$shortname]->groups[$group->name]->name = $group->name;
a7db355a 673 }
a5702569 674 }
0063abee 675 }
6b09974b 676 }
e4e38544 677 // group exists?
678 $addgroup = $user->{'group'.$i};
679 if (!array_key_exists($addgroup, $ccache[$shortname]->groups)) {
b225cf36 680 // if group doesn't exist, create it
681 $newgroupdata = new object();
682 $newgroupdata->name = $addgroup;
683 $newgroupdata->courseid = $ccache[$shortname]->id;
684 if ($ccache[$shortname]->groups[$addgroup]->id = groups_create_group($newgroupdata)){
685 $ccache[$shortname]->groups[$addgroup]->name = $newgroupdata->name;
686 } else {
687 $upt->track('enrolments', get_string('unknowngroup', 'error', $addgroup), 'error');
688 continue;
689 }
e4e38544 690 }
691 $gid = $ccache[$shortname]->groups[$addgroup]->id;
692 $gname = $ccache[$shortname]->groups[$addgroup]->name;
693
9c000a99 694 try {
695 if (groups_add_member($gid, $user->id)) {
696 $upt->track('enrolments', get_string('addedtogroup', '', $gname));
697 }
698 } catch (moodle_exception $e) {
e4e38544 699 $upt->track('enrolments', get_string('addedtogroupnot', '', $gname), 'error');
700 continue;
701 }
a5702569 702 }
066bfbfe 703 }
704 }
e4e38544 705 $upt->flush();
706 $upt->close(); // close table
707
708 $cir->close();
709 $cir->cleanup(true);
710
20486a5a 711 echo $OUTPUT->box_start('boxwidthnarrow boxaligncenter generalbox', 'uploadresults');
e4e38544 712 echo '<p>';
713 if ($optype != UU_UPDATE) {
714 echo get_string('userscreated', 'admin').': '.$usersnew.'<br />';
715 }
716 if ($optype == UU_UPDATE or $optype == UU_ADD_UPDATE) {
717 echo get_string('usersupdated', 'admin').': '.$usersupdated.'<br />';
718 }
719 if ($allowdeletes) {
720 echo get_string('usersdeleted', 'admin').': '.$deletes.'<br />';
721 echo get_string('deleteerrors', 'admin').': '.$deleteerrors.'<br />';
722 }
723 if ($allowrenames) {
724 echo get_string('usersrenamed', 'admin').': '.$renames.'<br />';
725 echo get_string('renameerrors', 'admin').': '.$renameerrors.'<br />';
726 }
727 if ($usersskipped) {
728 echo get_string('usersskipped', 'admin').': '.$usersskipped.'<br />';
729 }
d6bb2d2f 730 echo get_string('usersweakpassword', 'admin').': '.$weakpasswords.'<br />';
e4e38544 731 echo get_string('errors', 'admin').': '.$userserrors.'</p>';
20486a5a 732 echo $OUTPUT->box_end();
e4e38544 733
734 if ($bulk) {
8fbce1c8 735 echo $OUTPUT->continue_button($bulknurl);
e4e38544 736 } else {
8fbce1c8 737 echo $OUTPUT->continue_button($returnurl);
e4e38544 738 }
73d6f52f 739 echo $OUTPUT->footer();
df7ecfe4 740 die;
6b09974b 741}
0a6150ca 742
df7ecfe4 743// Print the header
744admin_externalpage_print_header();
745
a5702569 746/// Print the form
9e492db0 747
4bcc5118 748echo $OUTPUT->heading_with_help(get_string('uploaduserspreview', 'admin'), 'uploadusers2');
df7ecfe4 749
e4e38544 750$ri = 0;
e4e38544 751$cir->init();
07ed083e
RW
752
753$filerows = array();
e4e38544 754while ($fields = $cir->next()) {
07ed083e 755 $ci = 0;
e4e38544 756 if ($ri > $previewrows) {
07ed083e 757 $arow .= '<tr class="r'.$ri++.'">';
e4e38544 758 foreach ($fields as $field) {
07ed083e 759 $arow .= '<td class="cell c'.$ci++.'">...</td>';
e4e38544 760 }
07ed083e 761 $arow .= '</tr>';
e4e38544 762 break;
df7ecfe4 763 }
07ed083e
RW
764
765 $arow = '';
766 $errormsg = array();
767 $filerows[$ri] = array();
768 $arow .= '<tr class="r'.$ri.'">';
769 foreach ($fields as $key => $field) {
770 $errorclass = '';
771 if ($ci == 0) { //username field
772 $newusername = clean_param($field, PARAM_USERNAME);
773 if (strcmp($field, $newusername) != 0){
774 $errorclass = 'uuerror';
775 $errormsg[] = get_string('invalidusernameupload');
776 } else if ($DB->record_exists('user', array('username'=>$field)) || $DB->record_exists('user', array('username'=>$field)) ) {
777 $errorclass = 'uuerror';
778 $errormsg[] = get_string('usernameexists');
779 }
780 } else {
781 if ($ci == 4) { //email field
782 if ($DB->record_exists('user', array('email'=>$field))) {
783 $errorclass = 'uuerror';
784 $errormsg[] = get_string('emailexists');
785
786 } else if (!validate_email($field)) {
787 $errorclass = 'uuerror';
788 $errormsg[] = get_string('invalidemail');
789 }
790 }
791 }
792 $arow .= '<td class="cell c'.$ci++.'">';
793 $arow .= '<div class="'.$errorclass.'">'.s($field). '</div>';
794 $arow .= '</td>';
795
796 if ($key == (count($fields) - 1) && !empty($errormsg)) {
797 $errormsg = implode('<br />', $errormsg);
798 $arow .= '<td>' . $errormsg . '</td>';
799 $filerows[$ri]['error'] = $errormsg;
800 }
df7ecfe4 801 }
07ed083e
RW
802 $arow .= '</tr>';
803 $filerows[$ri]['content'] = $arow;
804 $ri++;
805}
e4e38544 806$cir->close();
df7ecfe4 807
07ed083e
RW
808$validcontent = array();
809$invalidcontent = array();
810foreach ($filerows as $arow) {
811 if (array_key_exists('error', $arow)){
812 $invalidcontent[] = $arow['content'];
813 $mform = new admin_uploaduser_form3();
814 } else {
815 $validcontent[] = $arow['content'];
816 }
817}
818
819$ri = 0;
820$ci = 0;
821echo '<table id="uupreview" class="generaltable boxaligncenter" summary="'.get_string('uploaduserspreview', 'admin').'">';
822echo '<tr class="heading r'.$ri++.'">';
823foreach ($columns as $col) {
824 echo '<th class="header c'.$ci++.'" scope="col">'.s($col).'</th>';
825}
826if (!empty($invalidcontent)) {
827 echo '<th class="header c'.$ci++.'" scope="col">'.moodle_strtolower(get_string('error', 'moodle')).'</th>';
828}
829echo '</tr>';
830
831$countcontent = 0;
832if (empty($invalidcontent)) {
833 $countcontent = count($validcontent);
834 echo implode('', $validcontent);
835} else {
836 $countcontent = count($invalidcontent);
837 echo implode('', $invalidcontent);
838}
e4e38544 839echo '</table>';
07ed083e
RW
840
841if (!empty($invalidcontent)) {
842 echo '<div class="centerpara">'.get_string('uploadinvalidpreprocessedcount', 'moodle', $countcontent).'</div>';
843 echo '<div class="">'.get_string('invalidusername', 'moodle').'</div>';
844 echo '<div class="">'.get_string('uploadfilecontainerror', 'moodle').'</div>';
845} else {
846 echo '<div class="">'.get_string('uupreprocessedcount', 'admin', $countcontent).'</div>';
847}
848
849//echo '<div class="centerpara">'.get_string('uupreprocessedcount', 'admin', $readcount).'</div>';
0a5dffcc 850$mform->display();
73d6f52f 851echo $OUTPUT->footer();
df7ecfe4 852die;
853
e4e38544 854/////////////////////////////////////
855/// Utility functions and classes ///
856/////////////////////////////////////
857
858class uu_progress_tracker {
859 var $_row;
860 var $columns = array('status', 'line', 'id', 'username', 'firstname', 'lastname', 'email', 'password', 'auth', 'enrolments', 'deleted');
861
862 function uu_progress_tracker() {
863 }
864
865 function init() {
866 $ci = 0;
867 echo '<table id="uuresults" class="generaltable boxaligncenter" summary="'.get_string('uploadusersresult', 'admin').'">';
868 echo '<tr class="heading r0">';
869 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('status').'</th>';
870 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('uucsvline', 'admin').'</th>';
871 echo '<th class="header c'.$ci++.'" scope="col">ID</th>';
872 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('username').'</th>';
873 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('firstname').'</th>';
874 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('lastname').'</th>';
875 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('email').'</th>';
876 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('password').'</th>';
877 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('authentication').'</th>';
878 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('enrolments').'</th>';
879 echo '<th class="header c'.$ci++.'" scope="col">'.get_string('delete').'</th>';
880 echo '</tr>';
881 $this->_row = null;
882 }
883
884 function flush() {
885 if (empty($this->_row) or empty($this->_row['line']['normal'])) {
886 $this->_row = array();
887 foreach ($this->columns as $col) {
888 $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>'');
889 }
890 return;
891 }
892 $ci = 0;
893 $ri = 1;
07ed083e
RW
894 echo '<tr class="r'.$ri.'">';
895 foreach ($this->_row as $key=>$field) {
e4e38544 896 foreach ($field as $type=>$content) {
897 if ($field[$type] !== '') {
07ed083e
RW
898 if ($key == 'username' && $type == 'normal') {
899 $field[$type] = clean_param($field[$type], PARAM_USERNAME);
900 }
e4e38544 901 $field[$type] = '<span class="uu'.$type.'">'.$field[$type].'</span>';
902 } else {
903 unset($field[$type]);
904 }
905 }
906 echo '<td class="cell c'.$ci++.'">';
907 if (!empty($field)) {
908 echo implode('<br />', $field);
909 } else {
910 echo '&nbsp;';
911 }
912 echo '</td>';
913 }
914 echo '</tr>';
915 foreach ($this->columns as $col) {
916 $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>'');
917 }
918 }
919
920 function track($col, $msg, $level='normal', $merge=true) {
921 if (empty($this->_row)) {
922 $this->flush(); //init arrays
923 }
924 if (!in_array($col, $this->columns)) {
925 debugging('Incorrect column:'.$col);
926 return;
927 }
928 if ($merge) {
929 if ($this->_row[$col][$level] != '') {
930 $this->_row[$col][$level] .='<br />';
931 }
932 $this->_row[$col][$level] .= s($msg);
933 } else {
934 $this->_row[$col][$level] = s($msg);
935 }
936 }
937
938 function close() {
939 echo '</table>';
940 }
941}
df7ecfe4 942
e4e38544 943/**
944 * Validation callback function - verified the column line of csv file.
945 * Converts column names to lowercase too.
946 */
947function validate_user_upload_columns(&$columns) {
948 global $STD_FIELDS, $PRF_FIELDS;
949
950 if (count($columns) < 2) {
951 return get_string('csvfewcolumns', 'error');
df7ecfe4 952 }
e4e38544 953
954 // test columns
955 $processed = array();
956 foreach ($columns as $key=>$unused) {
957 $columns[$key] = strtolower($columns[$key]); // no unicode expected here, ignore case
958 $field = $columns[$key];
959 if (!in_array($field, $STD_FIELDS) && !in_array($field, $PRF_FIELDS) &&// if not a standard field and not an enrolment field, then we have an error
960 !preg_match('/^course\d+$/', $field) && !preg_match('/^group\d+$/', $field) &&
2686b6c3 961 !preg_match('/^type\d+$/', $field) && !preg_match('/^role\d+$/', $field) &&
962 !preg_match('/^enrolperiod\d+$/', $field)) {
e4e38544 963 return get_string('invalidfieldname', 'error', $field);
964 }
965 if (in_array($field, $processed)) {
966 return get_string('csvcolumnduplicates', 'error');
967 }
968 $processed[] = $field;
df7ecfe4 969 }
e4e38544 970 return true;
df7ecfe4 971}
972
e4e38544 973/**
974 * Increments username - increments trailing number or adds it if not present.
975 * Varifies that the new username does not exist yet
976 * @param string $username
977 * @return incremented username which does not exist yet
978 */
979function increment_username($username, $mnethostid) {
1d8bf5f0 980 global $DB;
981
e4e38544 982 if (!preg_match_all('/(.*?)([0-9]+)$/', $username, $matches)) {
983 $username = $username.'2';
984 } else {
985 $username = $matches[1][0].($matches[2][0]+1);
986 }
987
1d8bf5f0 988 if ($DB->record_exists('user', array('username'=>$username, 'mnethostid'=>$mnethostid))) {
e4e38544 989 return increment_username($username, $mnethostid);
990 } else {
991 return $username;
992 }
993}
df7ecfe4 994
e4e38544 995/**
996 * Check if default field contains templates and apply them.
997 * @param string template - potential tempalte string
998 * @param object user object- we need username, firstname and lastname
999 * @return string field value
1000 */
1001function process_template($template, $user) {
1002 if (strpos($template, '%') === false) {
1003 return $template;
df7ecfe4 1004 }
e4e38544 1005
1006 // very very ugly hack!
1007 global $template_globals;
1008 $template_globals = new object();
1009 $template_globals->username = isset($user->username) ? $user->username : '';
1010 $template_globals->firstname = isset($user->firstname) ? $user->firstname : '';
1011 $template_globals->lastname = isset($user->lastname) ? $user->lastname : '';
1012
1013 $result = preg_replace_callback('/(?<!%)%([+-~])?(\d)*([flu])/', 'process_template_callback', $template);
1014
1015 $template_globals = null;
1016
1017 if (is_null($result)) {
1018 return $template; //error during regex processing??
1019 } else {
1020 return $result;
df7ecfe4 1021 }
e4e38544 1022}
df7ecfe4 1023
e4e38544 1024/**
1025 * Internal callback function.
1026 */
1027function process_template_callback($block) {
1028 global $template_globals;
1029 $textlib = textlib_get_instance();
1030 $repl = $block[0];
1031
1032 switch ($block[3]) {
1033 case 'u': $repl = $template_globals->username; break;
1034 case 'f': $repl = $template_globals->firstname; break;
1035 case 'l': $repl = $template_globals->lastname; break;
1036 }
1037 switch ($block[1]) {
1038 case '+': $repl = $textlib->strtoupper($repl); break;
1039 case '-': $repl = $textlib->strtolower($repl); break;
1040 case '~': $repl = $textlib->strtotitle($repl); break;
1041 }
1042 if (!empty($block[2])) {
1043 $repl = $textlib->substr($repl, 0 , $block[2]);
df7ecfe4 1044 }
e4e38544 1045
1046 return $repl;
df7ecfe4 1047}
1048
e4e38544 1049/**
1050 * Returns list of auth plugins that are enabled and known to work.
1051 */
1052function uu_allowed_auths() {
df7ecfe4 1053 global $CFG;
1054
e4e38544 1055 // only following plugins are guaranteed to work properly
1056 // TODO: add support for more plguins in 2.0
1057 $whitelist = array('manual', 'nologin', 'none', 'email');
1058 $plugins = get_enabled_auth_plugins();
1059 $choices = array();
1060 foreach ($plugins as $plugin) {
2a274f2a 1061 $choices[$plugin] = auth_get_plugin_title ($plugin);
df7ecfe4 1062 }
e4e38544 1063
1064 return $choices;
df7ecfe4 1065}
1066
e4e38544 1067/**
1068 * Returns list of non administrator roles
1069 */
1070function uu_allowed_roles($shortname=false) {
df7ecfe4 1071 global $CFG;
e4e38544 1072
1073 $roles = get_all_roles();
1074 $choices = array();
1075 foreach($roles as $role) {
1076 if ($shortname) {
1077 $choices[$role->id] = $role->shortname;
1078 } else {
1079 $choices[$role->id] = format_string($role->name);
1080 }
1081 }
1082 // get rid of all admin roles
1083 if ($adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW)) {
1084 foreach($adminroles as $adminrole) {
1085 unset($choices[$adminrole->id]);
1086 }
1087 }
1088
1089 return $choices;
df7ecfe4 1090}
20207b82 1091