Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 functions 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 defined('MOODLE_INTERNAL') || die(); 27 28 define('UU_USER_ADDNEW', 0); 29 define('UU_USER_ADDINC', 1); 30 define('UU_USER_ADD_UPDATE', 2); 31 define('UU_USER_UPDATE', 3); 32 33 define('UU_UPDATE_NOCHANGES', 0); 34 define('UU_UPDATE_FILEOVERRIDE', 1); 35 define('UU_UPDATE_ALLOVERRIDE', 2); 36 define('UU_UPDATE_MISSING', 3); 37 38 define('UU_BULK_NONE', 0); 39 define('UU_BULK_NEW', 1); 40 define('UU_BULK_UPDATED', 2); 41 define('UU_BULK_ALL', 3); 42 43 define('UU_PWRESET_NONE', 0); 44 define('UU_PWRESET_WEAK', 1); 45 define('UU_PWRESET_ALL', 2); 46 47 /** 48 * Tracking of processed users. 49 * 50 * This class prints user information into a html table. 51 * 52 * @package core 53 * @subpackage admin 54 * @copyright 2007 Petr Skoda {@link http://skodak.org} 55 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 56 */ 57 class uu_progress_tracker { 58 /** @var array */ 59 protected $_row; 60 61 /** 62 * The columns shown on the table. 63 * @var array 64 */ 65 public $columns = []; 66 /** @var array column headers */ 67 protected $headers = []; 68 69 /** 70 * uu_progress_tracker constructor. 71 */ 72 public function __construct() { 73 $this->headers = [ 74 'status' => get_string('status'), 75 'line' => get_string('uucsvline', 'tool_uploaduser'), 76 'id' => 'ID', 77 'username' => get_string('username'), 78 'firstname' => get_string('firstname'), 79 'lastname' => get_string('lastname'), 80 'email' => get_string('email'), 81 'password' => get_string('password'), 82 'auth' => get_string('authentication'), 83 'enrolments' => get_string('enrolments', 'enrol'), 84 'suspended' => get_string('suspended', 'auth'), 85 'theme' => get_string('theme'), 86 'deleted' => get_string('delete'), 87 ]; 88 $this->columns = array_keys($this->headers); 89 } 90 91 /** 92 * Print table header. 93 * @return void 94 */ 95 public function start() { 96 $ci = 0; 97 echo '<table id="uuresults" class="generaltable boxaligncenter flexible-wrap" summary="'.get_string('uploadusersresult', 'tool_uploaduser').'">'; 98 echo '<tr class="heading r0">'; 99 foreach ($this->headers as $key => $header) { 100 echo '<th class="header c'.$ci++.'" scope="col">'.$header.'</th>'; 101 } 102 echo '</tr>'; 103 $this->_row = null; 104 } 105 106 /** 107 * Flush previous line and start a new one. 108 * @return void 109 */ 110 public function flush() { 111 if (empty($this->_row) or empty($this->_row['line']['normal'])) { 112 // Nothing to print - each line has to have at least number 113 $this->_row = array(); 114 foreach ($this->columns as $col) { 115 $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>''); 116 } 117 return; 118 } 119 $ci = 0; 120 $ri = 1; 121 echo '<tr class="r'.$ri.'">'; 122 foreach ($this->_row as $key=>$field) { 123 foreach ($field as $type=>$content) { 124 if ($field[$type] !== '') { 125 $field[$type] = '<span class="uu'.$type.'">'.$field[$type].'</span>'; 126 } else { 127 unset($field[$type]); 128 } 129 } 130 echo '<td class="cell c'.$ci++.'">'; 131 if (!empty($field)) { 132 echo implode('<br />', $field); 133 } else { 134 echo ' '; 135 } 136 echo '</td>'; 137 } 138 echo '</tr>'; 139 foreach ($this->columns as $col) { 140 $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>''); 141 } 142 } 143 144 /** 145 * Add tracking info 146 * @param string $col name of column 147 * @param string $msg message 148 * @param string $level 'normal', 'warning' or 'error' 149 * @param bool $merge true means add as new line, false means override all previous text of the same type 150 * @return void 151 */ 152 public function track($col, $msg, $level = 'normal', $merge = true) { 153 if (empty($this->_row)) { 154 $this->flush(); //init arrays 155 } 156 if (!in_array($col, $this->columns)) { 157 debugging('Incorrect column:'.$col); 158 return; 159 } 160 if ($merge) { 161 if ($this->_row[$col][$level] != '') { 162 $this->_row[$col][$level] .='<br />'; 163 } 164 $this->_row[$col][$level] .= $msg; 165 } else { 166 $this->_row[$col][$level] = $msg; 167 } 168 } 169 170 /** 171 * Print the table end 172 * @return void 173 */ 174 public function close() { 175 $this->flush(); 176 echo '</table>'; 177 } 178 } 179 180 /** 181 * Validation callback function - verified the column line of csv file. 182 * Converts standard column names to lowercase. 183 * @param csv_import_reader $cir 184 * @param array $stdfields standard user fields 185 * @param array $profilefields custom profile fields 186 * @param moodle_url $returnurl return url in case of any error 187 * @return array list of fields 188 */ 189 function uu_validate_user_upload_columns(csv_import_reader $cir, $stdfields, $profilefields, moodle_url $returnurl) { 190 $columns = $cir->get_columns(); 191 192 if (empty($columns)) { 193 $cir->close(); 194 $cir->cleanup(); 195 print_error('cannotreadtmpfile', 'error', $returnurl); 196 } 197 if (count($columns) < 2) { 198 $cir->close(); 199 $cir->cleanup(); 200 print_error('csvfewcolumns', 'error', $returnurl); 201 } 202 203 // test columns 204 $processed = array(); 205 foreach ($columns as $key=>$unused) { 206 $field = $columns[$key]; 207 $field = trim($field); 208 $lcfield = core_text::strtolower($field); 209 if (in_array($field, $stdfields) or in_array($lcfield, $stdfields)) { 210 // standard fields are only lowercase 211 $newfield = $lcfield; 212 213 } else if (in_array($field, $profilefields)) { 214 // exact profile field name match - these are case sensitive 215 $newfield = $field; 216 217 } else if (in_array($lcfield, $profilefields)) { 218 // hack: somebody wrote uppercase in csv file, but the system knows only lowercase profile field 219 $newfield = $lcfield; 220 221 } else if (preg_match('/^(sysrole|cohort|course|group|type|role|enrolperiod|enrolstatus|enroltimestart)\d+$/', $lcfield)) { 222 // special fields for enrolments 223 $newfield = $lcfield; 224 225 } else { 226 $cir->close(); 227 $cir->cleanup(); 228 print_error('invalidfieldname', 'error', $returnurl, $field); 229 } 230 if (in_array($newfield, $processed)) { 231 $cir->close(); 232 $cir->cleanup(); 233 print_error('duplicatefieldname', 'error', $returnurl, $newfield); 234 } 235 $processed[$key] = $newfield; 236 } 237 238 return $processed; 239 } 240 241 /** 242 * Increments username - increments trailing number or adds it if not present. 243 * Varifies that the new username does not exist yet 244 * @param string $username 245 * @return incremented username which does not exist yet 246 */ 247 function uu_increment_username($username) { 248 global $DB, $CFG; 249 250 if (!preg_match_all('/(.*?)([0-9]+)$/', $username, $matches)) { 251 $username = $username.'2'; 252 } else { 253 $username = $matches[1][0].($matches[2][0]+1); 254 } 255 256 if ($DB->record_exists('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id))) { 257 return uu_increment_username($username); 258 } else { 259 return $username; 260 } 261 } 262 263 /** 264 * Check if default field contains templates and apply them. 265 * @param string template - potential tempalte string 266 * @param object user object- we need username, firstname and lastname 267 * @return string field value 268 */ 269 function uu_process_template($template, $user) { 270 if (is_array($template)) { 271 // hack for for support of text editors with format 272 $t = $template['text']; 273 } else { 274 $t = $template; 275 } 276 if (strpos($t, '%') === false) { 277 return $template; 278 } 279 280 $username = isset($user->username) ? $user->username : ''; 281 $firstname = isset($user->firstname) ? $user->firstname : ''; 282 $lastname = isset($user->lastname) ? $user->lastname : ''; 283 284 $callback = partial('uu_process_template_callback', $username, $firstname, $lastname); 285 286 $result = preg_replace_callback('/(?<!%)%([+-~])?(\d)*([flu])/', $callback, $t); 287 288 if (is_null($result)) { 289 return $template; //error during regex processing?? 290 } 291 292 if (is_array($template)) { 293 $template['text'] = $result; 294 return $t; 295 } else { 296 return $result; 297 } 298 } 299 300 /** 301 * Internal callback function. 302 */ 303 function uu_process_template_callback($username, $firstname, $lastname, $block) { 304 switch ($block[3]) { 305 case 'u': 306 $repl = $username; 307 break; 308 case 'f': 309 $repl = $firstname; 310 break; 311 case 'l': 312 $repl = $lastname; 313 break; 314 default: 315 return $block[0]; 316 } 317 318 switch ($block[1]) { 319 case '+': 320 $repl = core_text::strtoupper($repl); 321 break; 322 case '-': 323 $repl = core_text::strtolower($repl); 324 break; 325 case '~': 326 $repl = core_text::strtotitle($repl); 327 break; 328 } 329 330 if (!empty($block[2])) { 331 $repl = core_text::substr($repl, 0 , $block[2]); 332 } 333 334 return $repl; 335 } 336 337 /** 338 * Returns list of auth plugins that are enabled and known to work. 339 * 340 * If ppl want to use some other auth type they have to include it 341 * in the CSV file next on each line. 342 * 343 * @return array type=>name 344 */ 345 function uu_supported_auths() { 346 // Get all the enabled plugins. 347 $plugins = get_enabled_auth_plugins(); 348 $choices = array(); 349 foreach ($plugins as $plugin) { 350 $objplugin = get_auth_plugin($plugin); 351 // If the plugin can not be manually set skip it. 352 if (!$objplugin->can_be_manually_set()) { 353 continue; 354 } 355 $choices[$plugin] = get_string('pluginname', "auth_{$plugin}"); 356 } 357 358 return $choices; 359 } 360 361 /** 362 * Returns list of roles that are assignable in courses 363 * @return array 364 */ 365 function uu_allowed_roles() { 366 // let's cheat a bit, frontpage is guaranteed to exist and has the same list of roles ;-) 367 $roles = get_assignable_roles(context_course::instance(SITEID), ROLENAME_ORIGINALANDSHORT); 368 return array_reverse($roles, true); 369 } 370 371 /** 372 * Returns mapping of all roles using short role name as index. 373 * @return array 374 */ 375 function uu_allowed_roles_cache() { 376 $allowedroles = get_assignable_roles(context_course::instance(SITEID), ROLENAME_SHORT); 377 $rolecache = []; 378 foreach ($allowedroles as $rid=>$rname) { 379 $rolecache[$rid] = new stdClass(); 380 $rolecache[$rid]->id = $rid; 381 $rolecache[$rid]->name = $rname; 382 if (!is_numeric($rname)) { // only non-numeric shortnames are supported!!! 383 $rolecache[$rname] = new stdClass(); 384 $rolecache[$rname]->id = $rid; 385 $rolecache[$rname]->name = $rname; 386 } 387 } 388 return $rolecache; 389 } 390 391 /** 392 * Returns mapping of all system roles using short role name as index. 393 * @return array 394 */ 395 function uu_allowed_sysroles_cache() { 396 $allowedroles = get_assignable_roles(context_system::instance(), ROLENAME_SHORT); 397 $rolecache = []; 398 foreach ($allowedroles as $rid => $rname) { 399 $rolecache[$rid] = new stdClass(); 400 $rolecache[$rid]->id = $rid; 401 $rolecache[$rid]->name = $rname; 402 if (!is_numeric($rname)) { // Only non-numeric shortnames are supported! 403 $rolecache[$rname] = new stdClass(); 404 $rolecache[$rname]->id = $rid; 405 $rolecache[$rname]->name = $rname; 406 } 407 } 408 return $rolecache; 409 } 410 411 /** 412 * Pre process custom profile data, and update it with corrected value 413 * 414 * @param stdClass $data user profile data 415 * @return stdClass pre-processed custom profile data 416 */ 417 function uu_pre_process_custom_profile_data($data) { 418 global $CFG; 419 require_once($CFG->dirroot . '/user/profile/lib.php'); 420 $fields = profile_get_user_fields_with_data(0); 421 422 // find custom profile fields and check if data needs to converted. 423 foreach ($data as $key => $value) { 424 if (preg_match('/^profile_field_/', $key)) { 425 $shortname = str_replace('profile_field_', '', $key); 426 if ($fields) { 427 foreach ($fields as $formfield) { 428 if ($formfield->get_shortname() === $shortname && method_exists($formfield, 'convert_external_data')) { 429 $data->$key = $formfield->convert_external_data($value); 430 } 431 } 432 } 433 } 434 } 435 return $data; 436 } 437 438 /** 439 * Checks if data provided for custom fields is correct 440 * Currently checking for custom profile field or type menu 441 * 442 * @param array $data user profile data 443 * @param array $profilefieldvalues Used to track previous profile field values to ensure uniqueness is observed 444 * @return bool true if no error else false 445 */ 446 function uu_check_custom_profile_data(&$data, array &$profilefieldvalues = []) { 447 global $CFG; 448 require_once($CFG->dirroot.'/user/profile/lib.php'); 449 450 $noerror = true; 451 $testuserid = null; 452 453 if (!empty($data['username'])) { 454 if (preg_match('/id=(.*)"/i', $data['username'], $result)) { 455 $testuserid = $result[1]; 456 } 457 } 458 $profilefields = profile_get_user_fields_with_data(0); 459 // Find custom profile fields and check if data needs to converted. 460 foreach ($data as $key => $value) { 461 if (preg_match('/^profile_field_/', $key)) { 462 $shortname = str_replace('profile_field_', '', $key); 463 foreach ($profilefields as $formfield) { 464 if ($formfield->get_shortname() === $shortname) { 465 if (method_exists($formfield, 'convert_external_data') && 466 is_null($formfield->convert_external_data($value))) { 467 $data['status'][] = get_string('invaliduserfield', 'error', $shortname); 468 $noerror = false; 469 } 470 471 // Ensure unique field value doesn't already exist in supplied data. 472 $formfieldunique = $formfield->is_unique() && ($value !== '' || $formfield->is_required()); 473 if ($formfieldunique && array_key_exists($shortname, $profilefieldvalues) && 474 (array_search($value, $profilefieldvalues[$shortname]) !== false)) { 475 476 $data['status'][] = get_string('valuealreadyused') . " ({$key})"; 477 $noerror = false; 478 } 479 480 // Check for duplicate value. 481 if (method_exists($formfield, 'edit_validate_field') ) { 482 $testuser = new stdClass(); 483 $testuser->{$key} = $value; 484 $testuser->id = $testuserid; 485 $err = $formfield->edit_validate_field($testuser); 486 if (!empty($err[$key])) { 487 $data['status'][] = $err[$key].' ('.$key.')'; 488 $noerror = false; 489 } 490 } 491 492 // Record value of unique field, so it can be compared for duplicates. 493 if ($formfieldunique) { 494 $profilefieldvalues[$shortname][] = $value; 495 } 496 } 497 } 498 } 499 } 500 return $noerror; 501 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body