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