diff --git a/admin/uploaduser.php b/admin/uploaduser.php index 246951b318c..3be938c3a4d 100755 --- a/admin/uploaduser.php +++ b/admin/uploaduser.php @@ -3,23 +3,26 @@ /// Bulk user registration script from a comma separated file /// Returns list of users with their user ids -require_once('../config.php'); +require('../config.php'); require_once($CFG->libdir.'/adminlib.php'); +require_once($CFG->libdir.'/csvlib.class.php'); +require_once($CFG->dirroot.'/user/profile/lib.php'); require_once('uploaduser_form.php'); -$uplid = optional_param('uplid', '', PARAM_FILE); +$iid = optional_param('iid', '', PARAM_INT); $previewrows = optional_param('previewrows', 10, PARAM_INT); -$separator = optional_param('separator', 'comma', PARAM_ALPHA); +$readcount = optional_param('readcount', 0, PARAM_INT); -if (!defined('UP_LINE_MAX_SIZE')) { - define('UP_LINE_MAX_SIZE', 4096); -} +define('UU_ADDNEW', 0); +define('UU_ADDINC', 1); +define('UU_ADD_UPDATE', 2); +define('UU_UPDATE', 3); @set_time_limit(3600); // 1 hour should be enough @raise_memory_limit('256M'); if (function_exists('apache_child_terminate')) { - // if we are running from Apache, give httpd a hint that - // it can recycle the process after it's done. Apache's + // if we are running from Apache, give httpd a hint that + // it can recycle the process after it's done. Apache's // memory management is truly awful but we can help it. @apache_child_terminate(); } @@ -28,126 +31,72 @@ admin_externalpage_setup('uploadusers'); require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM)); $textlib = textlib_get_instance(); +$systemcontext = get_context_instance(CONTEXT_SYSTEM); -$struserrenamed = get_string('userrenamed', 'admin'); -$strusernotrenamedexists = get_string('usernotrenamedexists', 'error'); -$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error'); +$struserrenamed = get_string('userrenamed', 'admin'); +$strusernotrenamedexists = get_string('usernotrenamedexists', 'error'); +$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error'); +$strusernotrenamedoff = get_string('usernotrenamedoff', 'error'); +$strusernotrenamedadmin = get_string('usernotrenamedadmin', 'error'); -$struserupdated = get_string('useraccountupdated', 'admin'); -$strusernotupdated = get_string('usernotupdatederror', 'error'); +$struserupdated = get_string('useraccountupdated', 'admin'); +$strusernotupdated = get_string('usernotupdatederror', 'error'); +$strusernotupdatednotexists = get_string('usernotupdatednotexists', 'error'); +$strusernotupdatedadmin = get_string('usernotupdatedadmin', 'error'); -$struseradded = get_string('newuser'); -$strusernotadded = get_string('usernotaddedregistered', 'error'); -$strusernotaddederror = get_string('usernotaddederror', 'error'); +$struseradded = get_string('newuser'); +$strusernotadded = get_string('usernotaddedregistered', 'error'); +$strusernotaddederror = get_string('usernotaddederror', 'error'); -$struserdeleted = get_string('userdeleted', 'admin'); -$strusernotdeletederror = get_string('usernotdeletederror', 'error'); -$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error'); +$struserdeleted = get_string('userdeleted', 'admin'); +$strusernotdeletederror = get_string('usernotdeletederror', 'error'); +$strusernotdeletedmissing = get_string('usernotdeletedmissing', 'error'); +$strusernotdeletedoff = get_string('usernotdeletedoff', 'error'); +$strusernotdeletedadmin = get_string('usernotdeletedadmin', 'error'); -$strcannotassignrole = get_string('cannotassignrole', 'error'); -$strduplicateusername = get_string('duplicateusername', 'error'); -$strindent = '-->'; +$strcannotassignrole = get_string('cannotassignrole', 'error'); +$strduplicateusername = get_string('duplicateusername', 'error'); -$return = $CFG->wwwroot.'/'.$CFG->admin.'/uploaduser.php'; +$struserauthunsupported = get_string('userauthunsupported', 'error'); -// make arrays of valid fields for error checking -// the value associated to each field is: 0 = optional field, 1 = field required either in default values or in data file -$fields = array( - 'firstname' => 1, - 'lastname' => 1, - 'username' => 1, - 'email' => 1, - 'city' => 1, - 'country' => 1, - 'lang' => 1, - 'auth' => 1, - 'timezone' => 1, - 'mailformat' => 1, - 'maildisplay' => 1, - 'htmleditor' => 0, - 'ajax' => 0, - 'autosubscribe' => 1, - 'mnethostid' => 0, - 'institution' => 0, - 'department' => 0, - 'idnumber' => 0, - 'icq' => 0, - 'phone1' => 0, - 'phone2' => 0, - 'address' => 0, - 'url' => 0, - 'description' => 0, - 'icq' => 0, - 'oldusername' => 0, - 'emailstop' => 1, - 'deleted' => 0, - 'password' => 0, // changed later -); -if (empty($uplid)) { +$errorstr = get_string('error'); + +$returnurl = $CFG->wwwroot.'/'.$CFG->admin.'/uploaduser.php'; +$bulknurl = $CFG->wwwroot.'/'.$CFG->admin.'/user/user_bulk.php'; + +// array of all valid fields for validation +$STD_FIELDS = array('firstname', 'lastname', 'username', 'email', 'city', 'country', 'lang', 'auth', 'timezone', 'mailformat', 'maildisplay', 'htmleditor', + 'ajax', 'autosubscribe', 'mnethostid', 'institution', 'department', 'idnumber', 'icq', 'phone1', 'phone2', 'address', 'url', 'description', + 'icq', 'oldusername', 'emailstop', 'deleted', 'password'); + +$PRF_FIELDS = array(); + +if ($prof_fields = $fields = get_records_select('user_info_field')) { + foreach ($prof_fields as $prof_field) { + $PRF_FIELDS[] = 'profile_field_'.$prof_field->shortname; + } + unset($prof_fields); +} + +if (empty($iid)) { $mform = new admin_uploaduser_form1(); if ($formdata = $mform->get_data()) { - if (!$filename = make_upload_directory('temp/uploaduser/'.$USER->id, true)) { - error('Can not create temporary upload directory!', $return); - } - // use current (non-conflicting) time stamp - $uplid = time(); - while (file_exists($filename.'/'.$uplid)) { - $uplid--; - } - $filename = $filename.'/'.$uplid; + $iid = csv_import_reader::get_new_iid('uploaduser'); + $cir = new csv_import_reader($iid, 'uploaduser'); - $text = $mform->get_file_content('userfile'); - // convert to utf-8 encoding - $text = $textlib->convert($text, $formdata->encoding, 'utf-8'); - // remove Unicode BOM from first line - $text = $textlib->trim_utf8_bom($text); - // Fix mac/dos newlines - $text = preg_replace('!\r\n?!', "\n", $text); - //remove empty lines at the beginning and end - $text = trim($text); + $content = $mform->get_file_content('userfile'); - // verify each line has the same number of separators - this detects major breakage in files - $line = strtok($text, "\n"); - if ($line === false) { - error('Empty file', $return); //TODO: localize + $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name, 'validate_user_upload_columns'); + unset($content); + + if ($readcount === false) { + error($cir->get_error(), $returnurl); + } else if ($readcount == 0) { + error(get_string('csvemptyfile', 'error'), $returnurl); } - - // test headers - $csv_delimiter = get_upload_csv_delimiter($separator); - $col_count = substr_count($line, $csv_delimiter); - if ($col_count < 2) { - error('Not enough columns, please verify the separator setting!', $return); //TODO: localize - } - - $line = explode($csv_delimiter, $line); - foreach ($line as $key => $value) { - $value = trim($value); // remove whitespace - if (!array_key_exists($value, $fields) && // if not a standard field and not an enrolment field, then we have an error - !preg_match('/^course\d+$/', $value) && !preg_match('/^group\d+$/', $value) && - !preg_match('/^type\d+$/', $value) && !preg_match('/^role\d+$/', $value)) { - error(get_string('invalidfieldname', 'error', $value), $return); - } - } - - $line = strtok("\n"); - if ($line === false) { - error('Only one row present, can not continue!', $return); //TODO: localize - } - - while ($line !== false) { - if (substr_count($line, $csv_delimiter) !== $col_count) { - error('Incorrect file format - number of columns is not constant!', $return); //TODO: localize - } - $line = strtok("\n"); - } - - // store file - $fp = fopen($filename, "w"); - fwrite($fp,$text); - fclose($fp); - // continue to second form + // continue to form2 } else { admin_externalpage_print_header(); @@ -156,351 +105,566 @@ if (empty($uplid)) { admin_externalpage_print_footer(); die; } +} else { + $cir = new csv_import_reader($iid, 'uploaduser'); } -$mform = new admin_uploaduser_form2(); -// set initial date from form1 -$mform->set_data(array('separator'=>$separator, 'uplid'=>$uplid, 'previewrows'=>$previewrows)); +if (!$columns = $cir->get_columns()) { + error('Error reading temporary file', $returnurl); +} +$mform = new admin_uploaduser_form2(null, $columns); +// get initial date from form1 +$mform->set_data(array('iid'=>$iid, 'previewrows'=>$previewrows, 'readcount'=>$readcount)); // If a file has been uploaded, then process it if ($formdata = $mform->is_cancelled()) { - user_upload_cleanup($uplid); - redirect($return); + $cir->cleanup(true); + redirect($returnurl); -} else if ($formdata = $mform->get_data()) { +} else if ($formdata = $mform->get_data(false)) { // no magic quotes here!!! // Print the header admin_externalpage_print_header(); - print_heading(get_string('uploadusers')); + print_heading(get_string('uploadusersresult', 'admin')); - $createpassword = $formdata->createpassword; - $updateaccounts = $formdata->updateaccounts; - $allowrenames = $formdata->allowrenames; - $skipduplicates = $formdata->duplicatehandling; + $optype = $formdata->uutype; - $fields['password'] = !$createpassword; + $createpasswords = (!empty($formdata->uupasswordnew) and $optype != UU_UPDATE); + $updatepasswords = (!empty($formdata->uupasswordold) and $optype != UU_ADDNEW and $optype != UU_ADDINC); + $allowrenames = (!empty($formdata->uuallowrenames) and $optype != UU_ADDNEW and $optype != UU_ADDINC); + $allowdeletes = (!empty($formdata->uuallowdeletes) and $optype != UU_ADDNEW and $optype != UU_ADDINC); + $updatetype = isset($formdata->uuupdatetype) ? $formdata->uuupdatetype : 0; + $bulk = $formdata->uubulk; - $filename = $CFG->dataroot.'/temp/uploaduser/'.$USER->id.'/'.$uplid; - if (!file_exists($filename)) { - user_upload_cleanup($uplid); - error('Error reading temporary file!', $return); //TODO: localize - } - if (!$fp = fopen($filename, "r")) { - user_upload_cleanup($uplid); - error('Error reading temporary file!', $return); //TODO: localize - } - - $csv_delimiter = get_upload_csv_delimiter($separator); - $csv_encode = get_upload_csv_encode($csv_delimiter); + // verification moved to two places: after upload and into form2 + $usersnew = 0; + $usersupdated = 0; + $userserrors = 0; + $deletes = 0; + $deleteerrors = 0; + $renames = 0; + $renameerrors = 0; + $usersskipped = 0; - // find header row - $headers = array(); - $linenum = 1; - $line = explode($csv_delimiter, fgets($fp, UP_LINE_MAX_SIZE)); + // caches + $ccache = array(); // course cache - do not fetch all courses here, we will not probably use them all anyway! + $rolecache = array(); // roles lookup cache - // prepare headers - foreach ($line as $key => $value) { - $headers[$key] = trim($value); - } + $allowedauths = uu_allowed_auths(); + $allowedauths = array_keys($allowedauths); + $availableauths = get_list_of_plugins('auth'); - // check that required fields are present or a default value for them exists - $headersOk = true; - // disable the check if we also have deleting information (ie. deleted column) - if (!in_array('deleted', $headers)) { - foreach ($fields as $key => $required) { - if($required && !in_array($key, $headers) && (!isset($formdata->$key) || $formdata->$key==='')) { - notify(get_string('missingfield', 'error', $key)); - $headersOk = false; - } + $allowedroles = uu_allowed_roles(true); + foreach ($allowedroles as $rid=>$rname) { + $rolecache[$rid] = new object(); + $rolecache[$rid]->id = $rid; + $rolecache[$rid]->name = $rname; + if (!is_numeric($rname)) { // only non-numeric shornames are supported!!! + $rolecache[$rname] = new object(); + $rolecache[$rname]->id = $rid; + $rolecache[$rname]->name = $rname; } } - if ($headersOk) { - $usersnew = 0; - $usersupdated = 0; - $userserrors = 0; - $usersdeleted = 0; - $renames = 0; - $renameerrors = 0; - $deleteerrors = 0; - $newusernames = array(); - // We'll need courses a lot, so fetch it early and keep it in memory, indexed by their shortname - $tmp =& get_courses('all','','id,shortname,visible'); - $courses = array(); - foreach ($tmp as $c) { - $courses[$c->shortname] = $c; - } - unset($tmp); + unset($allowedroles); - echo '

'; - while (!feof($fp)) { - $linenum++; - $line = explode($csv_delimiter, fgets($fp, UP_LINE_MAX_SIZE)); - $errors = ''; - $user = new object(); - // by default, use the local mnet id (this may be changed in the file) - $user->mnethostid = $CFG->mnet_localhost_id; - // add fields to user object - foreach ($line as $key => $value) { - if($value !== '') { - $key = $headers[$key]; - //decode encoded commas - $value = str_replace($csv_encode,$csv_delimiter,trim($value)); - // special fields: password and username - if ($key == 'password' && !empty($value)) { - $user->$key = hash_internal_user_password($value); - } else if($key == 'username') { - $value = $textlib->strtolower(addslashes($value)); - if(empty($CFG->extendedusernamechars)) { - $value = eregi_replace('[^(-\.[:alnum:])]', '', $value); - } - @$newusernames[$value]++; - $user->$key = $value; - } else { - $user->$key = addslashes($value); - } - } - } + // clear bilk selection + if ($bulk) { + $SESSION->bulk_susers = array(); + } - // add default values for remaining fields - foreach ($fields as $key => $required) { - if(isset($user->$key)) { - continue; - } - if(!isset($formdata->$key) || $formdata->$key==='') { // no default value was submited - // if the field is required, give an error only if we are adding the user or deleting a user with unkown username - if($required && (empty($user->deleted) || $key == 'username')) { - $errors .= get_string('missingfield', 'error', $key) . ' '; - } - continue; - } - // process templates - $template = $formdata->$key; - $templatelen = strlen($template); - $value = ''; - for ($i = 0 ; $i < $templatelen; ++$i) { - if($template[$i] == '%') { - $case = 0; // 1=lowercase, 2=uppercase - $len = 0; // number of characters to keep - $info = null; // data to process - for($j = $i + 1; is_null($info) && $j < $templatelen; ++$j) { - $car = $template[$j]; - if ($car >= '0' && $car <= '9') { - $len = $len * 10 + (int)$car; - } else if($car == '-') { - $case = 1; - } else if($car == '+') { - $case = 2; - } else if($car == 'f') { // first name - $info = @$user->firstname; - } else if($car == 'l') { // last name - $info = @$user->lastname; - } else if($car == 'u') { // username - $info = @$user->username; - } else if($car == '%' && $j == $i+1) { - $info = '%'; - } else { // invalid character - $info = ''; - } - } - if($info==='' || is_null($info)) { // invalid template - continue; - } - $i = $j - 1; - // change case - if($case == 1) { - $info = $textlib->strtolower($info); - } else if($case == 2) { - $info = $textlib->strtoupper($info); - } - if($len) { // truncate data - $info = $textlib->substr($info, 0, $len); - } - $value .= $info; - } else { - $value .= $template[$i]; - } - } + // init csv import helper + $cir->init(); + $linenum = 1; //column header is first line - if($key == 'username') { - $value = $textlib->strtolower($value); - if(empty($CFG->extendedusernamechars)) { - $value = eregi_replace('[^(-\.[:alnum:])]', '', $value); - } - @$newusernames[$value]++; - // check for new username duplicates - if($newusernames[$value] > 1) { - if($skipduplicates) { - $errors .= $strduplicateusername . ' (' . stripslashes($value) . '). '; - continue; - } else { - $value .= $newusernames[$value]; - } - } - } - $user->$key = $value; - } - if($errors) { - notify(get_string('erroronline', 'error', $linenum). ': ' . $errors); - ++$userserrors; - continue; - } + // init upload progress tracker + $upt = new uu_progress_tracker(); + $upt->init(); // start table - // delete user - if(@$user->deleted) { - $info = ': ' . stripslashes($user->username) . '. '; - if($user =& get_record('user', 'username', $user->username, 'mnethostid', $user->mnethostid)) { - $user->timemodified = time(); - $user->username = addslashes($user->email . $user->timemodified); // Remember it just in case - $user->deleted = 1; - $user->email = ''; // Clear this field to free it up - $user->idnumber = ''; // Clear this field to free it up - if (update_record('user', $user)) { - // not sure if this is needed. unenrol_student($user->id); // From all courses - delete_records('role_assignments', 'userid', $user->id); // unassign all roles - // remove all context assigned on this user? - echo $struserdeleted . $info . '
'; - ++$usersdeleted; - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotdeletederror . $info); - ++$deleteerrors; + while ($line = $cir->next()) { + $upt->flush(); + $linenum++; + + $upt->track('line', $linenum); + + $user = new object(); + // by default, use the local mnet id (this may be changed in the file) + $user->mnethostid = $CFG->mnet_localhost_id; + // add fields to user object + foreach ($line as $key => $value) { + if ($value !== '') { + $key = $columns[$key]; + // password is special field + if ($key == 'password') { + if ($value !== '') { + $user->password = hash_internal_user_password($value); } } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotdeletedmissing . $info); - ++$deleteerrors; + $user->$key = $value; + if (in_array($key, $upt->columns)) { + $upt->track($key, $value); + } } + } + } + + // get username, first/last name now - we need them in templates!! + if ($optype == UU_UPDATE) { + // when updating only username is required + if (!isset($user->username)) { + $upt->track('status', get_string('missingfield', 'error', 'username'), 'error'); + $upt->track('username', $errorstr, 'error'); + $userserrors++; continue; } + } else { + $error = false; + // when all other ops need firstname and lastname + if (!isset($user->firstname) or $user->firstname === '') { + $upt->track('status', get_string('missingfield', 'error', 'firstname'), 'error'); + $upt->track('firstname', $errorstr, 'error'); + $error = true; + } + if (!isset($user->lastname) or $user->lastname === '') { + $upt->track('status', get_string('missingfield', 'error', 'lastname'), 'error'); + $upt->track('lastname', $errorstr, 'error'); + $error = true; + } + if ($error) { + $userserrors++; + continue; + } + // we require username too - we might use template for it though + if (!isset($user->username)) { + if (!isset($formdata->username) or $formdata->username === '') { + $upt->track('status', get_string('missingfield', 'error', 'username'), 'error'); + $upt->track('username', $errorstr, 'error'); + $userserrors++; + continue; + } else { + $user->username = process_template($formdata->username, $user); + $upt->track('username', $user->username); + } + } + } + + // normalize username + $user->username = $textlib->strtolower($user->username); + if (empty($CFG->extendedusernamechars)) { + $user->username = eregi_replace('[^(-\.[:alnum:])]', '', $user->username); + } + if (empty($user->username)) { + $upt->track('status', get_string('missingfield', 'error', 'username'), 'error'); + $upt->track('username', $errorstr, 'error'); + $userserrors++; + continue; + } + + if ($existinguser = get_record('user', 'username', addslashes($user->username), 'mnethostid', $user->mnethostid)) { + $upt->track('id', $existinguser->id, 'normal', false); + } + + // find out in username incrementing required + if ($existinguser and $optype == UU_ADDINC) { + $oldusername = $user->username; + $user->username = increment_username($user->username, $user->mnethostid); + $upt->track('username', '', 'normal', false); // clear previous + $upt->track('username', $oldusername.'-->'.$user->username, 'info'); + $existinguser = false; + } + + // add default values for remaining fields + foreach ($STD_FIELDS as $field) { + if (isset($user->$field)) { + continue; + } + // all validation moved to form2 + if (isset($formdata->$field)) { + // process templates + $user->$field = process_template($formdata->$field, $user); + } + } + foreach ($PRF_FIELDS as $field) { + if (isset($user->$field)) { + continue; + } + if (isset($formdata->$field)) { + // process templates + $user->$field = process_template($formdata->$field, $user); + } + } + + // delete user + if (!empty($user->deleted)) { + if (!$allowdeletes) { + $usersskipped++; + $upt->track('status', $strusernotdeletedoff, 'warning'); + continue; + } + if ($existinguser) { + if (has_capability('moodle/site:doanything', $systemcontext, $existinguser->id)) { + $upt->track('status', $strusernotdeletedadmin, 'error'); + $deleteerrors++; + continue; + } + if (delete_user($existinguser)) { + $upt->track('status', $struserdeleted); + $deletes++; + } else { + $upt->track('status', $strusernotdeletederror, 'error'); + $deleteerrors++; + } + } else { + $upt->track('status', $strusernotdeletedmissing, 'error'); + $deleteerrors++; + } + continue; + } + // we do not need the deleted flag anymore + unset($user->deleted); + + // renaming requested? + if (!empty($user->oldusername) ) { + $oldusername = $textlib->strtolower($user->oldusername); + if (!$allowrenames) { + $usersskipped++; + $upt->track('status', $strusernotrenamedoff, 'warning'); + continue; + } + + if ($existinguser) { + $upt->track('status', $strusernotrenamedexists, 'error'); + $renameerrors++; + continue; + } + + if ($olduser = get_record('user', 'username', addslashes($oldusername), 'mnethostid', $user->mnethostid)) { + $upt->track('id', $olduser->id, 'normal', false); + if (has_capability('moodle/site:doanything', $systemcontext, $olduser->id)) { + $upt->track('status', $strusernotrenamedadmin, 'error'); + $renameerrors++; + continue; + } + if (set_field('user', 'username', addslashes($user->username), 'id', $olduser->id)) { + $upt->track('username', '', 'normal', false); // clear previous + $upt->track('username', $oldusername.'-->'.$user->username, 'info'); + $upt->track('status', $struserrenamed); + $renames++; + } else { + $upt->track('status', $strusernotrenamedexists, 'error'); + $renameerrors++; + continue; + } + } else { + $upt->track('status', $strusernotrenamedmissing, 'error'); + $renameerrors++; + continue; + } + $existinguser = $olduser; + $existinguser->username = $user->username; + } + + // can we process with update or insert? + $skip = false; + switch ($optype) { + case UU_ADDNEW: + if ($existinguser) { + $usersskipped++; + $upt->track('status', $strusernotadded, 'warning'); + $skip = true;; + } + break; + + case UU_ADDINC: + if ($existinguser) { + //this should not happen! + $upt->track('status', $strusernotaddederror, 'error'); + $userserrors++; + continue; + } + break; + + case UU_ADD_UPDATE: + break; + + case UU_UPDATE: + if (!$existinguser) { + $usersskipped++; + $upt->track('status', $strusernotupdatednotexists, 'warning'); + $skip = true; + } + break; + } + + if ($skip) { + continue; + } + + if ($existinguser) { + $user->id = $existinguser->id; + + if (has_capability('moodle/site:doanything', $systemcontext, $user->id)) { + $upt->track('status', $strusernotupdatedadmin, 'error'); + $userserrors++; + continue; + } + + if (!$updatetype) { + // no updates of existing data at all + } else { + $existinguser->timemodified = time(); + //load existing profile data + profile_load_data($existinguser); + + $allowed = array(); + if ($updatetype == 1) { + $allowed = $columns; + } else if ($updatetype == 2 or $updatetype == 3) { + $allowed = array_merge($STD_FIELDS, $PRF_FIELDS); + } + foreach ($allowed as $column) { + if ($column == 'username') { + continue; + } + if ($column == 'password') { + if (!$updatepasswords or $updatetype == 3) { + continue; + } else if (!empty($user->password)) { + $upt->track('password', get_string('updated')); + } + } + if ((array_key_exists($column, $existinguser) and array_key_exists($column, $user)) or in_array($column, $PRF_FIELDS)) { + if ($updatetype == 3 and $existinguser->$column !== '') { + //missing == non-empty only + continue; + } + if ($existinguser->$column !== $user->$column) { + if ($column != 'password' and in_array($column, $upt->columns)) { + $upt->track($column, '', 'normal', false); // clear previous + $upt->track($column, $existinguser->$column.'-->'.$user->$column, 'info'); + } + $existinguser->$column = $user->$column; + } + } + } + + // do not update record if new auth plguin does not exist! + if (!in_array($existinguser->auth, $availableauths)) { + $upt->track('auth', get_string('userautherror', 'error', $existinguser->auth), 'error'); + $upt->track('status', $strusernotupdated, 'error'); + $userserrors++; + continue; + } else if (!in_array($existinguser->auth, $allowedauths)) { + $upt->track('auth', $struserauthunsupported, 'warning'); + } + + if (update_record('user', addslashes_recursive($existinguser))) { + $upt->track('status', $struserupdated); + $usersupdated++; + } else { + $upt->track('status', $strusernotupdated, 'error'); + $userserrors++; + continue; + } + // save custom profile fields data from csv file + profile_save_data(addslashes_recursive($existinguser)); + } + + if ($bulk == 2 or $bulk == 3) { + if (!in_array($user->id, $SESSION->bulk_susers)) { + $SESSION->bulk_susers[] = $user->id; + } + } + + } else { // save the user to the database $user->confirmed = 1; $user->timemodified = time(); - // before insert/update, check whether we should be updating an old record instead - if ($allowrenames && !empty($user->oldusername) ) { - $user->oldusername = $textlib->strtolower($user->oldusername); - $info = ': ' . stripslashes($user->oldusername) . '-->' . stripslashes($user->username) . '. '; - if ($olduser =& get_record('user', 'username', $user->oldusername, 'mnethostid', $user->mnethostid)) { - if (set_field('user', 'username', $user->username, 'id', $olduser->id)) { - echo $struserrenamed . $info; - $renames++; - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotrenamedexists . $info); - $renameerrors++; - continue; - } - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotrenamedmissing . $info); - $renameerrors++; + if (!$createpasswords and empty($user->password)) { + $upt->track('password', get_string('missingfield', 'error', 'password'), 'error'); + $upt->track('status', $strusernotaddederror, 'error'); + $userserrors++; + continue; + } + + // do not insert record if new auth plguin does not exist! + if (isset($user->auth)) { + if (!in_array($user->auth, $availableauths)) { + $upt->track('auth', get_string('userautherror', 'error', $user->auth), 'error'); + $upt->track('status', $strusernotaddederror, 'error'); + $userserrors++; continue; + } else if (!in_array($user->auth, $allowedauths)) { + $upt->track('auth', $struserauthunsupported, 'warning'); } } - // save the information - if ($olduser =& get_record('user', 'username', $user->username, 'mnethostid', $user->mnethostid)) { - $user->id = $olduser->id; - $info = ': ' . stripslashes($user->username) .' (ID = ' . $user->id . ')'; - if ($updateaccounts) { - // Record is being updated - if (update_record('user', $user)) { - echo $struserupdated . $info . '
'; - $usersupdated++; - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotupdated . $info); - $userserrors++; - continue; - } - } else { - //Record not added - user is already registered - //In this case, output userid from previous registration - //This can be used to obtain a list of userids for existing users - echo $strusernotadded . $info . '
'; - $userserrors++; + if ($user->id = insert_record('user', addslashes_recursive($user))) { + $info = ': ' . $user->username .' (ID = ' . $user->id . ')'; + $upt->track('status', $struseradded); + $upt->track('id', $user->id, 'normal', false); + $usersnew++; + if ($createpasswords and empty($user->password)) { + // passwords will be created and sent out on cron + set_user_preference('create_password', 1, $user->id); + set_user_preference('auth_forcepasswordchange', 1, $user->id); + $upt->track('password', get_string('new')); } - } else { // new user - if ($user->id = insert_record('user', $user)) { - $info = ': ' . stripslashes($user->username) .' (ID = ' . $user->id . ')'; - echo $struseradded . $info . '
'; - $usersnew++; - if (empty($user->password) && $createpassword) { - // passwords will be created and sent out on cron - set_user_preference('create_password', 1, $user->id); - set_user_preference('auth_forcepasswordchange', 1, $user->id); + } else { + // Record not added -- possibly some other error + $upt->track('status', $strusernotaddederror, 'error'); + $userserrors++; + continue; + } + // save custom profile fields data + profile_save_data($user); + + if ($bulk == 1 or $bulk == 3) { + if (!in_array($user->id, $SESSION->bulk_susers)) { + $SESSION->bulk_susers[] = $user->id; + } + } + } + + // find course enrolments, groups and roles/types + foreach ($columns as $column) { + if (!preg_match('/^course\d+$/', $column)) { + continue; + } + $i = substr($column, 6); + + $shortname = $user->{'course'.$i}; + if (!array_key_exists($shortname, $ccache)) { + if (!$course = get_record('course', 'shortname', $shortname, '', '', '', '', 'id, shortname, defaultrole')) { + $upt->track('enrolments', get_string('unknowncourse', 'error', $shortname), 'error'); + continue; + } + $ccache[$shortname] = $course; + $ccache[$shortname]->groups = null; + } + $courseid = $ccache[$shortname]->id; + $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid); + + // find role + $rid = false; + if (!empty($user->{'role'.$i})) { + $addrole = $user->{'role'.$i}; + if (array_key_exists($addrole, $rolecache)) { + $rid = $rolecache[$addrole]->id; + } else { + $upt->track('enrolments', get_string('unknownrole', 'error', $addrole), 'error'); + continue; + } + + } else if (!empty($user->{'type'.$i})) { + // if no role, then find "old" enrolment type + $addtype = $user->{'type'.$i}; + if ($addtype < 1 or $addtype > 3) { + $upt->track('enrolments', $strerror.': typeN = 1|2|3', 'error'); + continue; + } else if ($addtype == 1 and empty($formdata->uulegacy1)) { + if (empty($ccache[$shortname]->defaultrole)) { + $rid = $CFG->defaultcourseroleid; + } else { + $rid = $ccache[$shortname]->defaultrole; } } else { - // Record not added -- possibly some other error - notify(get_string('erroronline', 'error', $linenum). ': ' . $strusernotaddederror . ': ' . stripslashes($user->username)); - $userserrors++; - continue; + $rid = $formdata->{'uulegacy'.$addtype}; + } + + } else { + // no role specified, use the default + if (empty($ccache[$shortname]->defaultrole)) { + $rid = $CFG->defaultcourseroleid; + } else { + $rid = $ccache[$shortname]->defaultrole; + } + } + if ($rid) { + $a = new object(); + $a->course = $shortname; + $a->role = $rolecache[$rid]->name; + if (role_assign($rid, $user->id, 0, $coursecontext->id)) { + $upt->track('enrolments', get_string('enrolledincourserole', '', $a)); + } else { + $upt->track('enrolments', get_string('enrolledincoursenotrole', '', $a), 'error'); } } - // find course enrolments, groups and roles/types - for($ncourses = 1; $addcourse = @$user->{'course' . $ncourses}; ++$ncourses) { - // find course - if(!$course = @$courses[$addcourse]) { - notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('unknowncourse', 'error', $addcourse)); + // find group to add to + if (!empty($user->{'group'.$i})) { + // make sure user is enrolled into course before adding into groups + if (!has_capability('moodle/course:view', $coursecontext, $user->id, false)) { + $upt->track('enrolments', get_string('addedtogroupnotenrolled', '', $gname), 'error'); continue; } - // find role - if ($addrole = @$user->{'role' . $ncourses}) { - $coursecontext =& get_context_instance(CONTEXT_COURSE, $course->id); - if (!$ok = role_assign($addrole, $user->id, 0, $coursecontext->id)) { - echo $strindent . $strcannotassignrole . '
'; - } - } else { - // if no role, then find "old" enrolment type - switch ($addtype = @$user->{'type' . $ncourses}) { - case 2: // teacher - $ok = add_teacher($user->id, $course->id, 1); - break; - case 3: // non-editing teacher - $ok = add_teacher($user->id, $course->id, 0); - break; - case 1: // student - default: - $ok = enrol_student($user->id, $course->id); - break; - } - } - if ($ok) { // OK - echo $strindent . get_string('enrolledincourse', '', $addcourse) . '
'; - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('enrolledincoursenot', '', $addcourse)); - } - - // find group to add to - if ($addgroup = @$user->{'group' . $ncourses}) { - if ($gid =& groups_get_group_by_name($course->id, $addgroup)) { - $coursecontext =& get_context_instance(CONTEXT_COURSE, $course->id); - if (count(get_user_roles($coursecontext, $user->id))) { - if (groups_add_member($gid, $user->id)) { - echo $strindent . get_string('addedtogroup','',$addgroup) . '
'; - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('addedtogroupnot','',$addgroup)); + //build group cache + if (is_null($ccache[$shortname]->groups)) { + $ccache[$shortname]->groups = array(); + if ($groups = get_groups($courseid)) { + foreach ($groups as $gid=>$group) { + $ccache[$shortname]->groups[$gid] = new object(); + $ccache[$shortname]->groups[$gid]->id = $gid; + $ccache[$shortname]->groups[$gid]->name = $group->name; + if (!is_numeric($group->name)) { // only non-numeric names are supported!!! + $ccache[$shortname]->groups[$group->name] = new object(); + $ccache[$shortname]->groups[$group->name]->id = $gid; + $ccache[$shortname]->groups[$group->name]->name = $group->name; } - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('addedtogroupnotenrolled','',$addgroup)); } - } else { - notify(get_string('erroronline', 'error', $linenum). ': ' . get_string('groupunknown','error',$addgroup)); } } + // group exists? + $addgroup = $user->{'group'.$i}; + if (!array_key_exists($addgroup, $ccache[$shortname]->groups)) { + $upt->track('enrolments', get_string('unknowgroup', 'error', $addgroup), 'error'); + continue; + } + $gid = $ccache[$shortname]->groups[$addgroup]->id; + $gname = $ccache[$shortname]->groups[$addgroup]->name; + + if (groups_add_member($gid, $user->id)) { + $upt->track('enrolments', get_string('addedtogroup', '', $gname)); + } else { + $upt->track('enrolments', get_string('addedtogroupnot', '', $gname), 'error'); + continue; + } } } - echo '

'; - notify(get_string('userscreated', 'admin') . ': ' . $usersnew); - notify(get_string('usersupdated', 'admin') . ': ' . $usersupdated); - notify(get_string('usersdeleted', 'admin') . ': ' . $usersdeleted); - notify(get_string('deleteerrors', 'admin') . ': ' . $deleteerrors); - if ($allowrenames) { - notify(get_string('usersrenamed', 'admin') . ': ' . $renames); - notify(get_string('renameerrors', 'admin') . ': ' . $renameerrors); - } - notify(get_string('errors', 'admin') . ': ' . $userserrors); } - fclose($fp); - user_upload_cleanup($uplid); - echo '
'; - print_continue($return); + $upt->flush(); + $upt->close(); // close table + + $cir->close(); + $cir->cleanup(true); + + print_box_start('boxwidthnarrow boxaligncenter generalbox', 'uploadresults'); + echo '

'; + if ($optype != UU_UPDATE) { + echo get_string('userscreated', 'admin').': '.$usersnew.'
'; + } + if ($optype == UU_UPDATE or $optype == UU_ADD_UPDATE) { + echo get_string('usersupdated', 'admin').': '.$usersupdated.'
'; + } + if ($allowdeletes) { + echo get_string('usersdeleted', 'admin').': '.$deletes.'
'; + echo get_string('deleteerrors', 'admin').': '.$deleteerrors.'
'; + } + if ($allowrenames) { + echo get_string('usersrenamed', 'admin').': '.$renames.'
'; + echo get_string('renameerrors', 'admin').': '.$renameerrors.'
'; + } + if ($usersskipped) { + echo get_string('usersskipped', 'admin').': '.$usersskipped.'
'; + } + echo get_string('errors', 'admin').': '.$userserrors.'

'; + print_box_end(); + + if ($bulk) { + print_continue($bulknurl); + } else { + print_continue($returnurl); + } admin_externalpage_print_footer(); die; } @@ -509,107 +673,271 @@ if ($formdata = $mform->is_cancelled()) { admin_externalpage_print_header(); /// Print the form -print_heading_with_help(get_string('uploadusers'), 'uploadusers2'); +print_heading_with_help(get_string('uploaduserspreview', 'admin'), 'uploadusers2'); -/// Print csv file preview -$filename = $CFG->dataroot.'/temp/uploaduser/'.$USER->id.'/'.$uplid; -if (!file_exists($filename)) { - error('Error reading temporary file!', $return); //TODO: localize -} -if (!$fp = fopen($filename, "r")) { - error('Error reading temporary file!', $return); //TODO: localize -} +$ci = 0; +$ri = 0; -$csv_delimiter = get_upload_csv_delimiter($separator); -$csv_encode = get_upload_csv_encode($csv_delimiter); - -$header = explode($csv_delimiter, fgets($fp, UP_LINE_MAX_SIZE)); - -$width = count($header); -$columncount = 0; -$rowcount = 0; -echo ''; -echo ''; -foreach ($header as $h) { - echo ''; +echo '
'.trim($h).'
'; +echo ''; +foreach ($columns as $col) { + echo ''; } echo ''; -while (!feof($fp) and $rowcount <= $previewrows+1) { - $columncount = 0; - $fields = explode($csv_delimiter, fgets($fp, UP_LINE_MAX_SIZE)); - echo ''; +$cir->init(); +while ($fields = $cir->next()) { + if ($ri > $previewrows) { + echo ''; + foreach ($fields as $field) { + echo '';; + } + break; + } + $ci = 0; + echo ''; foreach ($fields as $field) { - echo '';; + echo '';; } echo ''; } -if ($rowcount > $previewrows+1) { - echo ''; - foreach ($fields as $field) { - echo '';; - } -} -echo '
'.s($col).'
...
'.trim(str_replace($csv_encode, $csv_delimiter, $field)).''.s($field).'
...
'; -fclose($fp); +$cir->close(); +echo ''; +echo '
'.get_string('uupreprocessedcount', 'admin', $readcount).'
'; $mform->display(); admin_externalpage_print_footer(); die; -///////////////////////// -/// Utility functions /// -///////////////////////// +///////////////////////////////////// +/// Utility functions and classes /// +///////////////////////////////////// -function user_upload_cleanup($uplid) { - global $USER, $CFG; - if (empty($uplid)) { - return; +class uu_progress_tracker { + var $_row; + var $columns = array('status', 'line', 'id', 'username', 'firstname', 'lastname', 'email', 'password', 'auth', 'enrolments', 'deleted'); + + function uu_progress_tracker() { } - $filename = $CFG->dataroot.'/temp/uploaduser/'.$USER->id.'/'.$uplid; - if (file_exists($filename)) { - @unlink($filename); + + function init() { + $ci = 0; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + $this->_row = null; + } + + function flush() { + if (empty($this->_row) or empty($this->_row['line']['normal'])) { + $this->_row = array(); + foreach ($this->columns as $col) { + $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>''); + } + return; + } + $ci = 0; + $ri = 1; + echo ''; + foreach ($this->_row as $field) { + foreach ($field as $type=>$content) { + if ($field[$type] !== '') { + $field[$type] = ''.$field[$type].''; + } else { + unset($field[$type]); + } + } + echo ''; + } + echo ''; + foreach ($this->columns as $col) { + $this->_row[$col] = array('normal'=>'', 'info'=>'', 'warning'=>'', 'error'=>''); + } + } + + function track($col, $msg, $level='normal', $merge=true) { + if (empty($this->_row)) { + $this->flush(); //init arrays + } + if (!in_array($col, $this->columns)) { + debugging('Incorrect column:'.$col); + return; + } + if ($merge) { + if ($this->_row[$col][$level] != '') { + $this->_row[$col][$level] .='
'; + } + $this->_row[$col][$level] .= s($msg); + } else { + $this->_row[$col][$level] = s($msg); + } + } + + function close() { + echo '
'.get_string('status').''.get_string('uucsvline', 'admin').'ID'.get_string('username').''.get_string('firstname').''.get_string('lastname').''.get_string('email').''.get_string('password').''.get_string('authentication').''.get_string('enrolments').''.get_string('delete').'
'; + if (!empty($field)) { + echo implode('
', $field); + } else { + echo ' '; + } + echo '
'; } } -function get_uf_headers($uplid, $separator) { - global $USER, $CFG; +/** + * Validation callback function - verified the column line of csv file. + * Converts column names to lowercase too. + */ +function validate_user_upload_columns(&$columns) { + global $STD_FIELDS, $PRF_FIELDS; - $filename = $CFG->dataroot.'/temp/uploaduser/'.$USER->id.'/'.$uplid; - if (!file_exists($filename)) { - return false; - } - $fp = fopen($filename, "r"); - $line = fgets($fp, 2048); - fclose($fp); - if ($line === false) { - return false; + if (count($columns) < 2) { + return get_string('csvfewcolumns', 'error'); } - $csv_delimiter = get_upload_csv_delimiter($separator); - $headers = explode($csv_delimiter, $line); - foreach($headers as $key=>$val) { - $headers[$key] = trim($val); + // test columns + $processed = array(); + foreach ($columns as $key=>$unused) { + $columns[$key] = strtolower($columns[$key]); // no unicode expected here, ignore case + $field = $columns[$key]; + 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 + !preg_match('/^course\d+$/', $field) && !preg_match('/^group\d+$/', $field) && + !preg_match('/^type\d+$/', $field) && !preg_match('/^role\d+$/', $field)) { + return get_string('invalidfieldname', 'error', $field); + } + if (in_array($field, $processed)) { + return get_string('csvcolumnduplicates', 'error'); + } + $processed[] = $field; } - return $headers; + return true; } -function get_upload_csv_delimiter($separator) { +/** + * Increments username - increments trailing number or adds it if not present. + * Varifies that the new username does not exist yet + * @param string $username + * @return incremented username which does not exist yet + */ +function increment_username($username, $mnethostid) { + if (!preg_match_all('/(.*?)([0-9]+)$/', $username, $matches)) { + $username = $username.'2'; + } else { + $username = $matches[1][0].($matches[2][0]+1); + } + + if (record_exists('user', 'username', addslashes($username), 'mnethostid', $mnethostid)) { + return increment_username($username, $mnethostid); + } else { + return $username; + } +} + +/** + * Check if default field contains templates and apply them. + * @param string template - potential tempalte string + * @param object user object- we need username, firstname and lastname + * @return string field value + */ +function process_template($template, $user) { + if (strpos($template, '%') === false) { + return $template; + } + + // very very ugly hack! + global $template_globals; + $template_globals = new object(); + $template_globals->username = isset($user->username) ? $user->username : ''; + $template_globals->firstname = isset($user->firstname) ? $user->firstname : ''; + $template_globals->lastname = isset($user->lastname) ? $user->lastname : ''; + + $result = preg_replace_callback('/(?username; break; + case 'f': $repl = $template_globals->firstname; break; + case 'l': $repl = $template_globals->lastname; break; + } + switch ($block[1]) { + case '+': $repl = $textlib->strtoupper($repl); break; + case '-': $repl = $textlib->strtolower($repl); break; + case '~': $repl = $textlib->strtotitle($repl); break; + } + if (!empty($block[2])) { + $repl = $textlib->substr($repl, 0 , $block[2]); + } + + return $repl; +} + +/** + * Returns list of auth plugins that are enabled and known to work. + */ +function uu_allowed_auths() { global $CFG; - switch ($separator) { - case 'semicolon' : return ';'; - case 'colon' : return ':'; - case 'tab' : return "\t"; - case 'cfg' : return isset($CFG->CSV_DELIMITER) ? $CFG->CSV_DELIMITER : ','; - default : return ','; + // only following plugins are guaranteed to work properly + // TODO: add support for more plguins in 2.0 + $whitelist = array('manual', 'nologin', 'none', 'email'); + $plugins = get_enabled_auth_plugins(); + $choices = array(); + foreach ($plugins as $plugin) { + $choices[$plugin] = get_string('auth_'.$plugin.'title', 'auth'); } + + return $choices; } -function get_upload_csv_encode($delimiter) { -//Note: commas within a field should be encoded as , (for comma separated csv files) -//Note: semicolon within a field should be encoded as ; (for semicolon separated csv files) +/** + * Returns list of non administrator roles + */ +function uu_allowed_roles($shortname=false) { global $CFG; - return '&#' . (isset($CFG->CSV_ENCODE) ? $CFG->CSV_ENCODE : ord($delimiter)); + + $roles = get_all_roles(); + $choices = array(); + foreach($roles as $role) { + if ($shortname) { + $choices[$role->id] = $role->shortname; + } else { + $choices[$role->id] = format_string($role->name); + } + } + // get rid of all admin roles + if ($adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW)) { + foreach($adminroles as $adminrole) { + unset($choices[$adminrole->id]); + } + } + + return $choices; } ?> diff --git a/admin/uploaduser_form.php b/admin/uploaduser_form.php index 140a17685b9..4eefd7bee43 100644 --- a/admin/uploaduser_form.php +++ b/admin/uploaduser_form.php @@ -5,26 +5,23 @@ class admin_uploaduser_form1 extends moodleform { function definition (){ global $CFG, $USER; - $this->set_upload_manager(new upload_manager('userfile', false, false, null, false, 0, true, true, false)); - $mform =& $this->_form; + $this->set_upload_manager(new upload_manager('userfile', false, false, null, false, 0, true, true, false)); + $mform->addElement('header', 'settingsheader', get_string('upload')); - $mform->addElement('file', 'userfile', get_string('file')); + $mform->addElement('file', 'userfile', get_string('file'), 'size="40"'); $mform->addRule('userfile', null, 'required'); - $choices = array('comma'=>',', 'semicolon'=>';', 'colon'=>':', 'tab'=>'\\t'); - if (isset($CFG->CSV_DELIMITER) and !in_array($CFG->CSV_DELIMITER, $choices)) { - $choices['cfg'] = $CFG->CSV_DELIMITER; - } - $mform->addElement('select', 'separator', get_string('csvseparator', 'admin'), $choices); + $choices = csv_import_reader::get_delimiter_list(); + $mform->addElement('select', 'delimiter_name', get_string('csvdelimiter', 'admin'), $choices); if (array_key_exists('cfg', $choices)) { - $mform->setDefault('separator', 'cfg'); + $mform->setDefault('delimiter_name', 'cfg'); } else if (get_string('listsep') == ';') { - $mform->setDefault('separator', 'semicolon'); + $mform->setDefault('delimiter_name', 'semicolon'); } else { - $mform->setDefault('separator', 'comma'); + $mform->setDefault('delimiter_name', 'comma'); } $textlib = textlib_get_instance(); @@ -44,35 +41,103 @@ class admin_uploaduser_form2 extends moodleform { function definition (){ global $CFG, $USER; - $mform =& $this->_form; + //no editors here - we need proper empty fields + $CFG->htmleditor = null; - // I am the tamplate user + $mform =& $this->_form; + $columns =& $this->_customdata; + + // I am the template user, why should it be the administrator? we have roles now, other ppl may use this script ;-) $templateuser = $USER; // upload settings and file $mform->addElement('header', 'settingsheader', get_string('settings')); + $choices = array(UU_ADDNEW => get_string('uuoptype_addnew', 'admin'), + UU_ADDINC => get_string('uuoptype_addinc', 'admin'), + UU_ADD_UPDATE => get_string('uuoptype_addupdate', 'admin'), + UU_UPDATE => get_string('uuoptype_update', 'admin')); + $mform->addElement('select', 'uutype', get_string('uuoptype', 'admin'), $choices); + $choices = array(0 => get_string('infilefield', 'auth'), 1 => get_string('createpasswordifneeded', 'auth')); - $mform->addElement('select', 'createpassword', get_string('passwordhandling', 'auth'), $choices); + $mform->addElement('select', 'uupasswordnew', get_string('uupasswordnew', 'admin'), $choices); + $mform->disabledIf('uupasswordnew', 'uutype', 'eq', UU_UPDATE); - $mform->addElement('selectyesno', 'updateaccounts', get_string('updateaccounts', 'admin')); - $mform->addElement('selectyesno', 'allowrenames', get_string('allowrenames', 'admin')); + $choices = array(0 => get_string('nochanges', 'admin'), + 1 => get_string('uuupdatefromfile', 'admin'), + 2 => get_string('uuupdateall', 'admin'), + 3 => get_string('uuupdatemissing', 'admin')); + $mform->addElement('select', 'uuupdatetype', get_string('uuupdatetype', 'admin'), $choices); + $mform->disabledIf('uuupdatetype', 'uutype', 'eq', UU_ADDNEW); + $mform->disabledIf('uuupdatetype', 'uutype', 'eq', UU_ADDINC); - $choices = array(0 => get_string('addcounter', 'admin'), 1 => get_string('skipuser', 'admin')); - $mform->addElement('select', 'duplicatehandling', get_string('newusernamehandling', 'admin'), $choices); - $mform->setDefault('duplicatehandling', 1); // better skip, bc and safer + $choices = array(0 => get_string('nochanges', 'admin'), 1 => get_string('update')); + $mform->addElement('select', 'uupasswordold', get_string('uupasswordold', 'admin'), $choices); + $mform->disabledIf('uupasswordold', 'uutype', 'eq', UU_ADDNEW); + $mform->disabledIf('uupasswordold', 'uutype', 'eq', UU_ADDINC); + $mform->disabledIf('uupasswordold', 'uuupdatetype', 'eq', 0); + $mform->disabledIf('uupasswordold', 'uuupdatetype', 'eq', 3); + + $mform->addElement('selectyesno', 'uuallowrenames', get_string('allowrenames', 'admin')); + $mform->disabledIf('uuallowrenames', 'uutype', 'eq', UU_ADDNEW); + $mform->disabledIf('uuallowrenames', 'uutype', 'eq', UU_ADDINC); + + $mform->addElement('selectyesno', 'uuallowdeletes', get_string('allowdeletes', 'admin')); + $mform->disabledIf('uuallowdeletes', 'uutype', 'eq', UU_ADDNEW); + $mform->disabledIf('uuallowdeletes', 'uutype', 'eq', UU_ADDINC); + + $choices = array(0 => get_string('no'), + 1 => get_string('uubulknew', 'admin'), + 2 => get_string('uubulkupdated', 'admin'), + 3 => get_string('uubulkall', 'admin')); + $mform->addElement('select', 'uubulk', get_string('uubulk', 'admin'), $choices); + +// roles selection + $showroles = false; + foreach ($columns as $column) { + if (preg_match('/^type\d+$/', $column)) { + $showroles = true; + break; + } + } + if ($showroles) { + $mform->addElement('header', 'rolesheader', get_string('roles')); + + $choices = uu_allowed_roles(true); + + $choices[0] = get_string('uucoursedefaultrole', 'admin'); + $mform->addElement('select', 'uulegacy1', get_string('uulegacy1role', 'admin'), $choices); + $mform->setDefault('uulegacy1', 0); + unset($choices[0]); + + $mform->addElement('select', 'uulegacy2', get_string('uulegacy2role', 'admin'), $choices); + if ($editteacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) { + $editteacherrole = array_shift($editteacherroles); /// Take the first one + $mform->setDefault('uulegacy2', $editteacherrole->id); + unset($editteacherroles); + } else { + $mform->setDefault('uulegacy2', $CFG->defaultcourseroleid); + } + + $mform->addElement('select', 'uulegacy3', get_string('uulegacy3role', 'admin'), $choices); + if ($teacherroles = get_roles_with_capability('moodle/legacy:teacher', CAP_ALLOW)) { + $teacherrole = array_shift($teacherroles); /// Take the first one + $mform->setDefault('uulegacy3', $teacherrole->id); + unset($teacherroles); + } else { + $mform->setDefault('uulegacy3', $CFG->defaultcourseroleid); + } + } // default values $mform->addElement('header', 'defaultheader', get_string('defaultvalues', 'admin')); - $mform->addElement('text', 'username', get_string('username'), 'size="20"'); - // only enabled plugins - $aplugins = get_enabled_auth_plugins(); - $auth_options = array(); - foreach ($aplugins as $module) { - $auth_options[$module] = get_string('auth_'.$module.'title', 'auth'); - } - $mform->addElement('select', 'auth', get_string('chooseauthmethod','auth'), $auth_options); + $mform->addElement('text', 'username', get_string('username'), 'size="20"'); + $mform->addRule('username', get_string('requiredtemplate', 'admin'), 'required', null, 'client'); + + // only enabled and known to work plugins + $choices = uu_allowed_auths(); + $mform->addElement('select', 'auth', get_string('chooseauthmethod','auth'), $choices); $mform->setDefault('auth', 'manual'); // manual is a sensible backwards compatible default $mform->setHelpButton('auth', array('authchange', get_string('chooseauthmethod','auth'))); $mform->setAdvanced('auth'); @@ -162,32 +227,100 @@ class admin_uploaduser_form2 extends moodleform { $mform->setType('address', PARAM_MULTILANG); $mform->setAdvanced('address'); -// hidden fields - $mform->addElement('hidden', 'uplid'); - $mform->setType('uplid', PARAM_FILE); + /// Next the profile defaults + profile_definition($mform); - $mform->addElement('hidden', 'separator'); - $mform->setType('separator', PARAM_ALPHA); +// hidden fields + $mform->addElement('hidden', 'iid'); + $mform->setType('iid', PARAM_INT); $mform->addElement('hidden', 'previewrows'); - $mform->setType('previewrows', PARAM_ALPHA); + $mform->setType('previewrows', PARAM_INT); + + $mform->addElement('hidden', 'readcount'); + $mform->setType('readcount', PARAM_INT); $this->add_action_buttons(true, get_string('uploadusers')); } + /** + * Form tweaks that depend on current data. + */ function definition_after_data() { - $mform =& $this->_form; + $mform =& $this->_form; + $columns =& $this->_customdata; - $separator = $mform->getElementValue('separator'); - $uplid = $mform->getElementValue('uplid'); - - if ($headers = get_uf_headers($uplid, $separator)) { - foreach ($headers as $header) { - if ($mform->elementExists($header)) { - $mform->removeElement($header); - } + foreach ($columns as $column) { + if ($mform->elementExists($column)) { + $mform->removeElement($column); } } } + + /** + * Server side validation. + */ + function validation($data) { + $errors = array(); + $columns =& $this->_customdata; + $optype = $data['uutype']; + + // detect if password column needed in file + if (!in_array('password', $columns)) { + switch ($optype) { + case UU_UPDATE: + if (!empty($data['uupasswordold'])) { + $errors['uupasswordold'] = get_string('missingfield', 'error', 'password'); + } + break; + + case UU_ADD_UPDATE: + if (empty($data['uupasswordnew'])) { + $errors['uupasswordnew'] = get_string('missingfield', 'error', 'password'); + } + if (!empty($data['uupasswordold'])) { + $errors['uupasswordold'] = get_string('missingfield', 'error', 'password'); + } + break; + + case UU_ADDNEW: + case UU_ADDINC: + if (empty($data['uupasswordnew'])) { + $errors['uupasswordnew'] = get_string('missingfield', 'error', 'password'); + } + break; + } + } + + // look for other required data + if ($optype != UU_UPDATE) { + if (!in_array('firstname', $columns)) { + $errors['uutype'] = get_string('missingfield', 'error', 'firstname'); + } + + if (!in_array('lastname', $columns)) { + if (isset($errors['uutype'])) { + $errors['uutype'] = ''; + } else { + $errors['uutype'] = ' '; + } + $errors['uutype'] .= get_string('missingfield', 'error', 'lastname'); + } + + if (!in_array('email', $columns) and empty($data['email'])) { + $errors['email'] = get_string('requiredtemplate', 'admin'); + } + + if (!in_array('city', $columns) and empty($data['city'])) { + $errors['city'] = get_string('required'); + } + } + + if (0 == count($errors)){ + return true; + } else { + return $errors; + } + } } ?> diff --git a/lang/en_utf8/admin.php b/lang/en_utf8/admin.php index 1635f73cf89..417e95d24ef 100644 --- a/lang/en_utf8/admin.php +++ b/lang/en_utf8/admin.php @@ -1,12 +1,12 @@ cron.php maintenance script has not been run for at least 24 hours.'; -$string['csvseparator'] = 'CSV separator'; +$string['csvdelimiter'] = 'CSV delimiter'; $string['curlrecommended'] = 'Installing the optional Curl library is highly recommended in order to enable Moodle Networking functionality.'; $string['customcheck'] = 'Other Checks'; $string['datarootsecuritywarning'] = 'Your site configuration might not be secure. Please make sure that your dataroot directory ($a) is not directly accessible via web.'; @@ -434,8 +434,8 @@ $string['mymoodle'] = 'My Moodle'; $string['mymoodleredirect'] = 'Force users to use My Moodle'; $string['mysql416bypassed'] = 'However, if your site is using iso-8859-1 (latin) languages ONLY, you may continue using your currently installed MySQL 4.1.12 (or higher).'; $string['mysql416required'] = 'MySQL 4.1.16 is the minimum version required for Moodle 1.6 in order to guarantee that all data can be converted to UTF-8 in the future.'; -$string['newusernamehandling'] = 'New username duplicate handling'; $string['nobookmarksforuser'] = 'You do not have any bookmarks.'; +$string['nochanges'] = 'No changes'; $string['nodefaultuserrolelists'] = 'Don\'t return all default role users'; $string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed'; $string['nomissingstrings'] = 'No missing strings'; @@ -536,6 +536,7 @@ $string['rcachettl'] = 'Record cache TTL'; $string['releasenoteslink'] = 'For information about this version of Moodle, please see the online Release Notes'; $string['remotelangnotavailable'] = 'Because Moodle can not connect to download.moodle.org, we are unable to do language pack installation automatically. Please download the appropriate zip file(s) from the list below, copy them to your $a directory and unzip them manually.'; $string['renameerrors'] = 'Rename errors'; +$string['requiredtemplate'] = 'Required. You may use template syntax here (%%l = lastname, %%f = firstname, %%u = username). See help for details and examples.'; $string['restrictbydefault'] = 'Restrict modules by default'; $string['restrictmodulesfor'] = 'Restrict modules for'; $string['riskconfig'] = 'Users could change site configuration and behaviour'; @@ -576,7 +577,6 @@ $string['sitemaintenancewarning'] = 'Your site is currently in maintenance mode $string['sitepolicies'] = 'Site policies'; $string['sitepolicy'] = 'Site policy URL'; $string['sitesectionhelp'] = 'If selected, a topic section will be displayed on the site\'s front page.'; -$string['skipuser'] = 'Skip user'; $string['slasharguments'] = 'Use slash arguments'; $string['smartpix'] ='Smart pix search'; $string['smtphosts'] = 'SMTP hosts'; @@ -633,6 +633,8 @@ Please note that this process can take a long time.

Are you sure you want to upgrade this server to this version?'; $string['upgradingdata'] = 'Upgrading data'; $string['upgradinglogs'] = 'Upgrading logs'; +$string['uploaduserspreview'] = 'Upload users preview'; +$string['uploadusersresult'] = 'Upload users results'; $string['upwards'] = 'upwards'; $string['usehtmleditor'] = 'Use HTML editor'; $string['useraccountupdated'] = 'User updated'; @@ -643,10 +645,32 @@ $string['userpolicies'] = 'User policies'; $string['userrenamed'] = 'User renamed'; $string['users'] = 'Users'; $string['userscreated'] = 'Users created'; -$string['usersrenamed'] = 'Users renamed'; $string['usersdeleted'] = 'Users deleted'; +$string['usersrenamed'] = 'Users renamed'; +$string['usersskipped'] = 'Users skipped'; $string['usersupdated'] = 'Users updated'; $string['usetags'] = 'Enable tags functionality'; +$string['uubulk'] = 'Select for bulk operations'; +$string['uubulkall'] = 'All users'; +$string['uubulknew'] = 'New users'; +$string['uubulkupdated'] = 'Updated users'; +$string['uucsvline'] = 'CSV line'; +$string['uucoursedefaultrole'] = 'Default course role'; +$string['uulegacy1role'] = '(Original Student) typeN=1'; +$string['uulegacy2role'] = '(Original Teacher) typeN=2'; +$string['uulegacy3role'] = '(Original Non-editing teacher) typeN=3'; +$string['uuoptype_addinc'] = 'Add all, append counter to usernames if needed'; +$string['uuoptype_addnew'] = 'Add new only, skip existing users'; +$string['uuoptype_addupdate'] = 'Add new and update existing users'; +$string['uuoptype_update'] = 'Update existing users only'; +$string['uuoptype'] = 'Upload type'; +$string['uupasswordnew'] = 'New user password'; +$string['uupasswordold'] = 'Existing user password'; +$string['uupreprocessedcount'] = 'Number of preprocessed records: $a'; +$string['uuupdateall'] = 'Override with file and defaults'; +$string['uuupdatefromfile'] = 'Override with file'; +$string['uuupdatemissing'] = 'Fill in missing from file and defaults'; +$string['uuupdatetype'] = 'Existing user details'; $string['validateerror'] = 'This value was not valid:'; $string['xmlstrictheaders'] = 'XML strict headers'; diff --git a/lang/en_utf8/error.php b/lang/en_utf8/error.php index 312cb4bbc41..fda552b9259 100644 --- a/lang/en_utf8/error.php +++ b/lang/en_utf8/error.php @@ -22,6 +22,10 @@ $string['componentisuptodate'] = 'Component is up to date.'; $string['confirmsesskeybad'] = 'Sorry, but your session key could not be confirmed to carry out this action. This security feature prevents against accidental or malicious execution of important functions in your name. Please make sure you really wanted to execute this function.'; $string['couldnotassignrole'] = 'A serious but unspecified error occurred while trying to assign a role to you'; $string['coursegroupunknown'] = 'Course corresponding to group $a not specified'; +$string['csvemptyfile'] = 'The CSV file is empty.'; +$string['csvcolumnduplicates'] = 'Duplicate columns detected.'; +$string['csvfewcolumns'] = 'Not enough columns, please verify the delimiter setting.'; +$string['csvweirdcolumns'] = 'Invalid CSV file format - number of columns is not constant!'; $string['downloadedfilecheckfailed'] = 'Downloaded file check failed.'; $string['duplicateusername'] = 'Duplicate username - skiping record'; $string['errorcleaningdirectory'] = 'Error cleaning directory \"$a\"'; @@ -88,15 +92,25 @@ $string['statscatchupmode'] = 'Statistics is currently in catchup mode. So far $ $string['unicodeupgradeerror'] = 'Sorry, but your database is not already in Unicode, and this version of Moodle is not able to migrate your database to Unicode. Please upgrade to Moodle 1.7.x first and perform the Unicode migration from the Admin page. After that is done you should be able to migrate to Moodle $a'; $string['unknowncourse'] = 'Unknown course named \"$a\"'; $string['unknowncourseidnumber'] = 'Unknown Course ID \"$a\"'; +$string['unknowngroup'] = 'Unknown group \"$a\"'; +$string['unknownrole'] = 'Unknown role \"$a\"'; $string['unknownuseraction'] = 'Sorry, I do not understand this user action.'; -$string['usernotaddederror'] = 'User not added - unknown error'; -$string['usernotaddedregistered'] = 'User not added - already registered'; -$string['usernotdeletederror'] = 'User not deleted - unknown error'; +$string['userautherror'] = 'Unknown auth plugin.'; +$string['userauthunsupported'] = 'Auth plugin not supported here.'; +$string['usernotaddedadmin'] = 'Can not delete admin accounts.'; +$string['usernotaddederror'] = 'User not added - error.'; +$string['usernotaddedregistered'] = 'User not added - already registered.'; +$string['usernotdeletederror'] = 'User not deleted - error.'; $string['usernotdeletedmissing'] = 'User not deleted - could not find the username.'; +$string['usernotdeletedoff'] = 'User not deleted - deleting not allowed.'; $string['usernotavailable'] = 'The details of this user are not available to you.'; -$string['usernotrenamedexists'] = 'User not renamed -- the new username is already in use.'; -$string['usernotrenamedmissing'] = 'User not renamed -- could not find the old username.'; -$string['usernotupdatederror'] = 'User not updated - unknown error'; +$string['usernotrenamedadmin'] = 'Can not rename admin accounts.'; +$string['usernotrenamedexists'] = 'User not renamed - the new username is already in use.'; +$string['usernotrenamedmissing'] = 'User not renamed - could not find the old username.'; +$string['usernotrenamedoff'] = 'User not renamed - renaming not allowed.'; +$string['usernotupdatedadmin'] = 'Can not update admin accounts.'; +$string['usernotupdatederror'] = 'User not updated - error.'; +$string['usernotupdatednotexists'] = 'User not updated - does not exist.'; $string['wrongdestpath'] = 'Wrong destination path.'; $string['wrongsourcebase'] = 'Wrong source URL base.'; $string['wrongzipfilename'] = 'Wrong ZIP filename.'; diff --git a/lang/en_utf8/moodle.php b/lang/en_utf8/moodle.php index dc9c29473cc..dc66d531d5d 100644 --- a/lang/en_utf8/moodle.php +++ b/lang/en_utf8/moodle.php @@ -23,9 +23,9 @@ $string['addcreator'] = 'Add course creator'; $string['added'] = 'Added $a'; $string['addedrecip'] = 'Added $a new recipient'; $string['addedrecips'] = 'Added $a new recipients'; -$string['addedtogroup'] = 'Added to group $a'; -$string['addedtogroupnot'] = 'Not added to group $a'; -$string['addedtogroupnotenrolled'] = 'Not added to group $a, because not enrolled in course'; +$string['addedtogroup'] = 'Added to group \"$a\"'; +$string['addedtogroupnot'] = 'Not added to group \"$a\"'; +$string['addedtogroupnotenrolled'] = 'Not added to group \"$a\", because not enrolled in course'; $string['addinganew'] = 'Adding a new $a'; $string['addinganewto'] = 'Adding a new $a->what to $a->to'; $string['addingdatatoexisting'] = 'Adding data to existing'; @@ -539,7 +539,9 @@ $string['enrolenddate'] = 'End date'; $string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date'; $string['enrollable'] = 'Course enrollable'; $string['enrolledincourse'] = 'Enrolled in course \"$a\"'; +$string['enrolledincourserole'] = 'Enrolled in \"$a->course\" as \"$a->role\"'; $string['enrolledincoursenot'] = 'Not enrolled in course \"$a\"'; +$string['enrolledincoursenotrole'] = 'Error enrolling into \"$a->course\" as \"$a->role\"'; $string['enrollfirst'] = 'You have to enrol in one of the courses before you can use the site activities'; $string['enrolme'] = 'Enrol me in this course'; $string['enrolmentconfirmation'] = 'You are about to enrol yourself as a member of this course.
Are you sure you wish to do this?'; diff --git a/lib/csvlib.class.php b/lib/csvlib.class.php new file mode 100644 index 00000000000..0cca4b83a24 --- /dev/null +++ b/lib/csvlib.class.php @@ -0,0 +1,268 @@ +_iid = $iid; + $this->_type = $type; + } + + /** + * Parse this content + * @param string &$content passed by ref for memory reasons, unset after return + * @param string $encoding content encoding + * @param string $delimiter_name separator (comma, semicolon, colon, cfg) + * @param string $column_validation name of function for columns validation, must have one param $columns + * @return false if error, count of data lines if ok; use get_error() to get error string + */ + function load_csv_content(&$content, $encoding, $delimiter_name, $column_validation=null) { + global $USER, $CFG; + + $this->close(); + $this->_error = null; + + $textlib = textlib_get_instance(); + + $content = $textlib->convert($content, $encoding, 'utf-8'); + // remove Unicode BOM from first line + $content = $textlib->trim_utf8_bom($content); + // Fix mac/dos newlines + $content = preg_replace('!\r\n?!', "\n", $content); + // is there anyting in file? + $columns = strtok($content, "\n"); + if ($columns === false) { + $this->_error = get_string('csvemptyfile', 'error'); + return false; + } + $csv_delimiter = csv_import_reader::get_delimiter($delimiter_name); + $csv_encode = csv_import_reader::get_encoded_delimiter($delimiter_name); + + // process header - list of columns + $columns = explode($csv_delimiter, $columns); + $col_count = count($columns); + if ($col_count === 0) { + $this->_error = get_string('csvemptyfile', 'error'); + return false; + } + + foreach ($columns as $key=>$value) { + $columns[$key] = str_replace($csv_encode, $csv_delimiter, trim($value)); + } + if ($column_validation) { + $result = $column_validation($columns); + if ($result !== true) { + $this->_error = $result; + return false; + } + } + $this->_columns = $columns; // cached columns + + // open file for writing + $filename = $CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid; + $fp = fopen($filename, "w"); + fwrite($fp, serialize($columns)."\n"); + + // again - do we have any data for processing? + $line = strtok("\n"); + $data_count = 0; + while ($line !== false) { + $line = explode($csv_delimiter, $line); + foreach ($line as $key=>$value) { + $line[$key] = str_replace($csv_encode, $csv_delimiter, trim($value)); + } + if (count($line) !== $col_count) { + // this is critical!! + $this->_error = get_string('csvweirdcolumns', 'error'); + fclose($fp); + $this->cleanup(); + return false; + } + fwrite($fp, serialize($line)."\n"); + $data_count++; + $line = strtok("\n"); + } + + fclose($fp); + return $data_count; + } + + /** + * Returns list of columns + * @return array + */ + function get_columns() { + if (isset($this->_columns)) { + return $this->_columns; + } + + global $USER, $CFG; + + $filename = $CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid; + if (!file_exists($filename)) { + return false; + } + $fp = fopen($filename, "r"); + $line = fgets($fp); + fclose($fp); + if ($line === false) { + return false; + } + $this->_columns = unserialize($line); + return $this->_columns; + } + + /** + * Init iterator. + */ + function init() { + global $CFG, $USER; + + if (!empty($this->_fp)) { + $this->close(); + } + $filename = $CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid; + if (!file_exists($filename)) { + return false; + } + if (!$this->_fp = fopen($filename, "r")) { + return false; + } + //skip header + return (fgets($this->_fp) !== false); + } + + /** + * Get next line + * @return array of values + */ + function next() { + if (empty($this->_fp) or feof($this->_fp)) { + return false; + } + if ($ser = fgets($this->_fp)) { + return unserialize($ser); + } else { + return false; + } + } + + /** + * Release iteration related resources + */ + function close() { + if (!empty($this->_fp)) { + fclose($this->_fp); + $this->_fp = null; + } + } + + /** + * Get last error + * @return string error text of null if none + */ + function get_error() { + return $this->_error; + } + + /** + * Cleanup temporary data + * @static if $full=true + * @param boolean true menasdo a full cleanup - all sessions for current user, false only the active iid + */ + function cleanup($full=false) { + global $USER, $CFG; + + if ($full) { + @remove_dir($CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id); + } else { + @unlink($CFG->dataroot.'/temp/csvimport/'.$this->_type.'/'.$USER->id.'/'.$this->_iid); + } + } + + /** + * Get list of cvs delimiters + * @static + * @return array suitable for selection box + */ + function get_delimiter_list() { + $delimiters = array('comma'=>',', 'semicolon'=>';', 'colon'=>':', 'tab'=>'\\t'); + if (isset($CFG->CSV_DELIMITER) and strlen($CFG->CSV_DELIMITER) === 1 and !in_array($CFG->CSV_DELIMITER, $delimiters)) { + $delimiters['cfg'] = $CFG->CSV_DELIMITER; + } + return $delimiters; + } + + /** + * Get delimiter character + * @static + * @param string separator name + * @return char delimiter char + */ + function get_delimiter($delimiter_name) { + switch ($delimiter_name) { + case 'colon': return ':'; + case 'semicolon': return ';'; + case 'tab': return "\t"; + case 'cfg': if (isset($CFG->CSV_DELIMITER)) { return $CFG->CSV_DELIMITER; } // no break; fall back to comma + case 'comma': return ','; + } + } + + /** + * Get encoded delimiter character + * @static + * @param string separator name + * @return char encoded delimiter char + */ + function get_encoded_delimiter($delimiter_name) { + global $CFG; + if ($delimiter_name == 'cfg' and isset($CFG->CSV_ENCODE)) { + return $CFG->CSV_ENCODE; + } + $delimiter = csv_import_reader::get_delimiter($delimiter_name); + return '&#'.ord($delimiter); + } + + /** + * Create new import id + * @static + * @param string who imports? + * @return int iid + */ + function get_new_iid($type) { + global $USER; + + if (!$filename = make_upload_directory('temp/csvimport/'.$type.'/'.$USER->id, false)) { + error('Can not create temporary upload directory - verify moodledata permissions!'); + } + + // use current (non-conflicting) time stamp + $iiid = time(); + while (file_exists($filename.'/'.$iiid)) { + $iiid--; + } + + return $iiid; + } +} +?> diff --git a/theme/standard/styles_color.css b/theme/standard/styles_color.css index 65bdfc7b306..ced7194d4a6 100644 --- a/theme/standard/styles_color.css +++ b/theme/standard/styles_color.css @@ -373,6 +373,18 @@ table.flexible .r1 { background-color : lime; } +#admin-uploaduser .uuinfo { + background-color: #8e8; +} + +#admin-uploaduser .uuwarning { + background-color: #ee8; +} + +#admin-uploaduser .uuerror { + background-color: #e99; +} + /*** *** Blocks ***/ diff --git a/theme/standard/styles_fonts.css b/theme/standard/styles_fonts.css index 14b03d202ea..c066026a79e 100644 --- a/theme/standard/styles_fonts.css +++ b/theme/standard/styles_fonts.css @@ -260,6 +260,12 @@ body#admin-index .copyright { font-size: 0.75em; } +#admin-uploaduser table#uupreview { + font-size: 0.8em; +} +#admin-uploaduser table#uuresults { + font-size: 0.9em; +} /*** *** Blocks diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css index db6e28e43db..e3f639271ca 100644 --- a/theme/standard/styles_layout.css +++ b/theme/standard/styles_layout.css @@ -1170,6 +1170,16 @@ body#admin-modules table.generaltable td.c0 display: block; } +#admin-uploaduser table#uuresults { + margin-bottom: 2em; +} + +#admin-uploaduser table#uupreview, +#admin-uploaduser table#uuresults td.cell { + padding-left: 3px; + padding-right: 3px; +} + /*** *** Blocks ***/