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