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