]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-10181, user management improvements, adding improvements to bulk user upload...
authortoyomoyo <toyomoyo>
Mon, 20 Aug 2007 08:51:35 +0000 (08:51 +0000)
committertoyomoyo <toyomoyo>
Mon, 20 Aug 2007 08:51:35 +0000 (08:51 +0000)
admin/uploaduser.php
admin/uploaduser_form.php
admin/user/user_bulk.php
admin/user/user_bulk_confirm.php
admin/user/user_bulk_delete.php
admin/user/user_bulk_display.php [new file with mode: 0755]
admin/user/user_bulk_form.php
lang/en_utf8/admin.php
lang/en_utf8/bulkusers.php
lang/en_utf8/error.php
lang/en_utf8/help/uploadusers.html

index 4f357a84d22b5adc6f1e527dc522463dbbc28904..6a4d5811b345dad5fd69aa9549e4d6174eb70ef7 100755 (executable)
-<?php // $Id$
+<?php
 
 /// Bulk user registration script from a comma separated file
 /// Returns list of users with their user ids
 
 require_once('../config.php');
 require_once($CFG->libdir.'/adminlib.php');
-require_once($CFG->dirroot.'/group/lib.php');
+require_once($CFG->libdir.'/textlib.class.php');
 require_once('uploaduser_form.php');
+define('LINE_MAX_SIZE', 1024);
 
-admin_externalpage_setup('uploadusers');
+//Note: commas within a field should be encoded as &#44 (for comma separated csv files)
+//Note: semicolon within a field should be encoded as &#59 (for semicolon separated csv files)
+$csv_delimiter = isset($CFG->CSV_DELIMITER) ? $CFG->CSV_DELIMITER : ',';
+$csv_encode = '&#' . (isset($CFG->CSV_ENCODE) ? $CFG->CSV_ENCODE : ord($csv_delimiter));
+
+@set_time_limit(0);
+@raise_memory_limit('192M');
 
+admin_externalpage_setup('uploadusers');
 require_capability('moodle/site:uploadusers', get_context_instance(CONTEXT_SYSTEM));
 
 if (! $site = get_site()) {
-    error("Could not find site-level course");
+    error('Could not find site-level course');
 }
 
-if (!$adminuser = get_admin()) {
-    error("Could not find site admin");
-}
+$textlib =& textlib_get_instance();
 
-$struser = get_string('user');
-$strusersnew = get_string('usersnew');
+$struserrenamed = get_string('userrenamed', 'admin');
+$strusernotrenamedexists = get_string('usernotrenamedexists', 'error');
+$strusernotrenamedmissing = get_string('usernotrenamedmissing', 'error');
 
-$csv_encode = '/\&\#44/';
-if (isset($CFG->CSV_DELIMITER)) {
-    $csv_delimiter = '\\' . $CFG->CSV_DELIMITER;
-    $csv_delimiter2 = $CFG->CSV_DELIMITER;
+$struserupdated = get_string('useraccountupdated', 'admin');
+$strusernotupdated = get_string('usernotupdatederror', 'error');
+$strusernotadded = get_string('usernotaddedregistered', 'error');
 
-    if (isset($CFG->CSV_ENCODE)) {
-        $csv_encode = '/\&\#' . $CFG->CSV_ENCODE . '/';
-    }
-} else {
-    $csv_delimiter = "\,";
-    $csv_delimiter2 = ",";
-}
-
-/// Print the header
-
-admin_externalpage_print_header();
+$struseradded = get_string('newuser');
+$strusernotaddederror = get_string('usernotaddederror', 'error');
+$strcannotassignrole = get_string('cannotassignrole', 'error');
+$strduplicateusername = get_string('duplicateusername', 'error');
+$strindent = '-->';
 
 $mform = new admin_uploaduser_form();
 
-/// If a file has been uploaded, then process it
+// Print the header
 
-if ( $formdata = $mform->get_data() ) {
+admin_externalpage_print_header();
 
+// If a file has been uploaded, then process it
+if ( $formdata = $mform->get_data() ) {
     $createpassword = $formdata->createpassword;
     $updateaccounts = $formdata->updateaccounts;
     $allowrenames   = $formdata->allowrenames;
-
-    $filename = $mform->get_userfile_name();
+    $skipduplicates = $formdata->duplicatehandling;
     
-    // Large files are likely to take their time and memory. Let PHP know
-    // that we'll take longer, and that the process should be recycled soon
-    // to free up memory.
-    @set_time_limit(0);
-    @raise_memory_limit("192M");
-    if (function_exists('apache_child_terminate')) {
-        @apache_child_terminate();
+    // 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' => 1,
+        'autosubscribe' => 1,
+        'mnethostid' => 1, 
+        'institution' => 0,
+        'department' => 0,
+        'idnumber' => 0,
+        'icq' => 0,
+        'phone1' => 0,
+        'phone2' => 0,
+        'address' => 0,
+        'url' => 0,
+        'description' => 0,
+        'icq' => 0,
+        'oldusername' => 0,
+        'emailstop' => 1,
+        'password' => !$createpassword,
+    );
+
+    $fp = fopen($mform->get_userfile_name(), 'r');
+    $linenum = 1; // since header is line 1
+    // get header (field names) and remove Unicode BOM from first line, if any
+    $line = explode($csv_delimiter, $textlib->trim_utf8_bom(fgets($fp,LINE_MAX_SIZE)));
+    // check for valid field names
+    $headers = array();
+    foreach ($line as $key => $value) {
+        $value = trim($value); // remove whitespace
+        if (!in_array($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), 'uploaduser.php?sesskey='.$USER->sesskey);
+        }
+        $headers[$key] = $value; 
     }
 
-    $text = my_file_get_contents($filename);
-    //trim utf-8 bom
-    $textlib = new textlib();
-    $text = $textlib->trim_utf8_bom($text);
-    //Fix mac/dos newlines
-    $text = preg_replace('!\r\n?!',"\n",$text);
-    $fp = fopen($filename, "w");
-    fwrite($fp,$text);
-    fclose($fp);
-
-    $fp = fopen($filename, "r");
-
-    // make arrays of valid fields for error checking
-    $required = array("username" => 1,
-            "password" => !$createpassword,
-            "firstname" => 1,
-            "lastname" => 1,
-            "email" => 1);
-    $optionalDefaults = array("mnethostid" => 1,
-            "institution" => 1,
-            "department" => 1,
-            "city" => 1,
-            "country" => 1,
-            "lang" => 1,
-            "auth" => 1,
-            "timezone" => 1);
-    $optional = array("idnumber" => 1,
-            "icq" => 1,
-            "phone1" => 1,
-            "phone2" => 1,
-            "address" => 1,
-            "url" => 1,
-            "description" => 1,
-            "mailformat" => 1,
-            "maildisplay" => 1,
-            "htmleditor" => 1,
-            "autosubscribe" => 1,
-            "idnumber" => 1,
-            "icq" => 1,
-            "course1" => 1,
-            "course2" => 1,
-            "course3" => 1,
-            "course4" => 1,
-            "course5" => 1,
-            "group1" => 1,
-            "group2" => 1,
-            "group3" => 1,
-            "group4" => 1,
-            "group5" => 1,
-            "type1" => 1,
-            "type2" => 1,
-            "type3" => 1,
-            "type4" => 1,
-            "type5" => 1,
-            "role1" => 1,
-            "role2" => 1,
-            "role3" => 1,
-            "role4" => 1,
-            "role5" => 1,
-            "password" => $createpassword,
-            "oldusername" => $allowrenames,
-            "emailstop" => 1);
-
-            // --- get header (field names) ---
-            $header = split($csv_delimiter, fgets($fp,1024));
-            // check for valid field names
-            foreach ($header as $i => $h) {
-                $h = trim($h); $header[$i] = $h; // remove whitespace
-                if (!(isset($required[$h]) or isset($optionalDefaults[$h]) or isset($optional[$h]))) {
-                    error(get_string('invalidfieldname', 'error', $h), 'uploaduser.php?sesskey='.$USER->sesskey);
-                }
-                if (isset($required[$h])) {
-                    $required[$h] = 0;
+    $usersnew     = 0;
+    $usersupdated = 0;
+    $userserrors  = 0;
+    $renames      = 0;
+    $renameerrors = 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);
+
+    echo '<p id="results">';
+    while (!feof ($fp)) {
+        $user = new object();
+        // by default, use the local mnet id (this may be changed in the file)
+        $user->mnethostid = $CFG->mnet_localhost_id;
+        $line = explode($csv_delimiter, fgets($fp,LINE_MAX_SIZE));
+        ++$linenum;
+        $ok = true;
+        // 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') {
+                    $user->$key = addslashes($textlib->strtolower($value));
+                } else {
+                    $user->$key = addslashes($value);
                 }
             }
-            // check for required fields
-            foreach ($required as $key => $value) {
-                if ($value) { //required field missing
-                    error(get_string('fieldrequired', 'error', $key), 'uploaduser.php?sesskey='.$USER->sesskey);
-                }
+        }
+        // add default values for remaining fields
+        foreach ($fields as $key => $value) {
+            if(isset($user->$key)) {
+                continue;
             }
-            $linenum = 2; // since header is line 1
-
-            $usersnew     = 0;
-            $usersupdated = 0;
-            $userserrors  = 0;
-            $renames      = 0;
-            $renameerrors = 0;
-
-            // Will use this course array a lot
-            // so fetch it early and keep it in memory
-            $courses = get_courses('all','c.sortorder','c.id,c.shortname,c.fullname,c.sortorder,c.teacher,c.visible');
-
-            while (!feof ($fp)) {
-                foreach ($optionalDefaults as $key => $value) {
-                    $user->$key = addslashes($adminuser->$key);
+            if(!isset($formdata->$key) || $formdata->$key==='') { // no default value was submited
+                if($value) { // the field is required
+                    notify(get_string('erroronline', 'error', $linenum). ': ' .get_string('missingfield', 'error', $key));
+                    $ok = false;
                 }
-                //Note: commas within a field should be encoded as &#44 (for comma separated csv files)
-                //Note: semicolon within a field should be encoded as &#59 (for semicolon separated csv files)
-                $line = split($csv_delimiter, fgets($fp,1024));
-                foreach ($line as $key => $value) {
-                    //decode encoded commas
-                    $record[$header[$key]] = preg_replace($csv_encode,$csv_delimiter2,trim($value));
-                }
-                if ($record[$header[0]]) {
-                    // add a new user to the database
-
-                    // add fields to object $user
-                    foreach ($record as $name => $value) {
-                        // check for required values
-                        if (isset($required[$name]) and !$value) {
-                            error(get_string('missingfield', 'error', $name). " ".
-                                    get_string('erroronline', 'error', $linenum) .". ".
-                                    get_string('processingstops', 'error'),
-                                    'uploaduser.php?sesskey='.$USER->sesskey);
-                        }
-                        // password needs to be encrypted
-                        else if ($name == "password" && !empty($value)) {
-                            $user->password = hash_internal_user_password($value);
-                        }
-                        else if ($name == "username") {
-                            $user->username = addslashes(moodle_strtolower($value));
-                        }
-                        // normal entry
-                        else {
-                            $user->{$name} = addslashes($value);
+                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 = '';
                         }
                     }
-                    $user->confirmed = 1;
-                    $user->timemodified = time();
-                    $linenum++;
-                    $username = $user->username;
-                    $addcourse[0] = isset($user->course1) ? $user->course1 : NULL;
-                    $addcourse[1] = isset($user->course2) ? $user->course2 : NULL;
-                    $addcourse[2] = isset($user->course3) ? $user->course3 : NULL;
-                    $addcourse[3] = isset($user->course4) ? $user->course4 : NULL;
-                    $addcourse[4] = isset($user->course5) ? $user->course5 : NULL;
-                    $addgroup[0] = isset($user->group1) ? $user->group1 : NULL;
-                    $addgroup[1] = isset($user->group2) ? $user->group2 : NULL;
-                    $addgroup[2] = isset($user->group3) ? $user->group3 : NULL;
-                    $addgroup[3] = isset($user->group4) ? $user->group4 : NULL;
-                    $addgroup[4] = isset($user->group5) ? $user->group5 : NULL;
-                    $addtype[0] = isset($user->type1) ? $user->type1 : NULL;
-                    $addtype[1] = isset($user->type2) ? $user->type2 : NULL;
-                    $addtype[2] = isset($user->type3) ? $user->type3 : NULL;
-                    $addtype[3] = isset($user->type4) ? $user->type4 : NULL;
-                    $addtype[4] = isset($user->type5) ? $user->type5 : NULL;
-                    $addrole[0] = isset($user->role1) ? $user->role1 : NULL;
-                    $addrole[1] = isset($user->role2) ? $user->role2 : NULL;
-                    $addrole[2] = isset($user->role3) ? $user->role3 : NULL;
-                    $addrole[3] = isset($user->role4) ? $user->role4 : NULL;
-                    $addrole[4] = isset($user->role5) ? $user->role5 : NULL;
-
-                    for ($i=0; $i<5; $i++) {
-                        $course[$i]=NULL;
+                    if($info==='' || is_null($info)) { // invalid template
+                        continue;
                     }
-                    foreach ($courses as $eachcourse) {
-                        for ($i=0; $i<5; $i++) {
-                            if ($eachcourse->shortname == $addcourse[$i]) {
-                                $course[$i] = $eachcourse;
-                            }
-                        }
+                    $i = $j - 1;
+                    // change case
+                    if($case == 1) { 
+                        $info = $textlib->strtolower($info);
+                    } else if($case == 2) {
+                        $info = $textlib->strtoupper($info);
                     }
-
-                    // before insert/update, check whether we should be updating
-                    // an old record instead
-                    if ($allowrenames && !empty($user->oldusername) ) {
-                        $user->oldusername = moodle_strtolower($user->oldusername);
-                        if ($olduser = get_record('user', 'username', $user->oldusername, 'mnethostid', $user->mnethostid)) {
-                            if (set_field('user', 'username', $user->username, 'username', $user->oldusername)) {
-                                notify(get_string('userrenamed', 'admin') . " : $user->oldusername $user->username");
-                                $renames++;
-                            } else {
-                                notify(get_string('usernotrenamedexists', 'error') . " : $user->oldusername $user->username");
-                                $renameerrors++;
-                                continue;
-                            }
-                        } else {
-                            notify(get_string('usernotrenamedmissing', 'error') . " : $user->oldusername $user->username");
-                            $renameerrors++;
-                            continue;
-                        }
+                    if($len) { // truncate data
+                        $info = $textlib->substr($info, 0, $len);
+                    }
+                    $value .= $info;
+                } else {
+                    $value .= $template[$i];
+                }
+            }
+            
+            if($key == 'username') {
+                $value = $textlib->strtolower($value);
+                if(empty($CFG->extendedusernamechars)) {
+                    $value = eregi_replace('[^(-\.[:alnum:])]', '', $value);
+                }
+                // check for new username duplicates
+                if(empty($newusernames[$value])) {
+                    $newusernames[$value] = 1;
+                } else {
+                    if($skipduplicates) {
+                        notify($strduplicateusername . ': ' . $value);
+                        $ok = false;
+                        continue;
+                    } else {
+                        ++$newusernames[$value];
+                        $value .= $newusernames[$value];
                     }
+                }
+            }
+            $user->$key = $value;
+        }
+        if(!$ok) {
+            ++$userserrors;
+            continue;
+        }
 
-                    if ($olduser = get_record("user", "username", $username, "mnethostid", $user->mnethostid)) {
-                        if ($updateaccounts) {
-                            // Record is being updated
-                            $user->id = $olduser->id;
-                            if (update_record('user', $user)) {
-                                notify("$user->id , $user->username ".get_string('useraccountupdated', 'admin'));
-                                $usersupdated++;
-                            } else {
-                                notify(get_string('usernotupdatederror', 'error', $username));
-                                $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
-                            notify("$olduser->id ".get_string('usernotaddedregistered', 'error', $username));
-                            $userserrors++;
-                        }
+        $user->confirmed = 1;
+        $user->timemodified = time();
+
+        // save the user to the database
+        $username = $user->username;
+
+        // 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 = ': ' . $user->oldusername . '-->' . $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($strusernotrenamedexists . $info);
+                    $renameerrors++;
+                    continue;
+                }
+            } else {
+                notify($strusernotrenamedmissing . $info);
+                $renameerrors++;
+                continue;
+            }
+        }
 
-                    } else { // new user
-                        if ($user->id = insert_record("user", $user)) {
-                            notify("$struser: $user->id = $user->username");
-                            $usersnew++;
-                            if (empty($user->password) && $createpassword) {
-                                // passwords will be created and sent out on cron
-                                insert_record('user_preferences', array( 'userid' => $user->id,
-                                            'name'   => 'create_password',
-                                            'value'  => 1));
-                                insert_record('user_preferences', array( 'userid' => $user->id,
-                                            'name'   => 'auth_forcepasswordchange',
-                                            'value'  => 1));
-                            }
-                        } else {
-                            // Record not added -- possibly some other error
-                            notify(get_string('usernotaddederror', 'error', $username));
-                            $userserrors++;
-                            continue;
-                        }
-                    }
-                    for ($i=0; $i<5; $i++) {
-                        if ($addcourse[$i] && !$course[$i]) {
-                            notify(get_string('unknowncourse', 'error', $addcourse[$i]));
-                        }
-                    }
-                    for ($i=0; $i<5; $i++) {
-                        $groupid[$i] = 0;
-                        if ($addgroup[$i]) {
-                            if (!$course[$i]) {
-                                notify(get_string('coursegroupunknown','error',$addgroup[$i]));
-                            } else {
-                                if ($gid = groups_get_group_by_name($course[$i]->id, $addgroup[$i])) {
-                                    $groupid[$i] = $gid;
-                                } else {
-                                    notify(get_string('groupunknown','error',$addgroup[$i]));
-                                }
-                            }
-                        }
-                    }
-                    for ($i=0; $i<5; $i++) {   /// Enrol into courses if necessary
-                        if ($course[$i]) {
-                            if (isset($addrole[$i])) {
-                                $coursecontext = get_context_instance(CONTEXT_COURSE, $course[$i]->id);
-                                if (!user_can_assign($coursecontext, $addrole[$i])) {
-                                    notify('--> Can not assign role in course'); //TODO: localize
-                                }
-                                $ret = role_assign($addrole[$i], $user->id, 0, $coursecontext->id);
-                            } else if (isset($addtype[$i])) {
-                                switch ($addtype[$i]) {
-                                    case 2:   // teacher
-                                        $ret = add_teacher($user->id, $course[$i]->id, 1);
-                                        break;
+        // save the information
+        if ($olduser = get_record('user', 'username', $username, 'mnethostid', $user->mnethostid)) {
+            $user->id = $olduser->id;
+            $info = ': ' . $username .' (ID = ' . $user->id . ')';
+            if ($updateaccounts) {
+                // Record is being updated
+                if (update_record('user', $user)) {
+                    echo $struserupdated . $info . '<br />';
+                    $usersupdated++;
+                } else {
+                    notify($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 . '<br />';
+                $userserrors++;
+            }
+        } else { // new user
+            if ($user->id = insert_record('user', $user)) {
+                $info = ': ' . $username .' (ID = ' . $user->id . ')';
+                echo $struseradded . $info . '<br />';
+                $usersnew++;
+                if (empty($user->password) && $createpassword) {
+                    // passwords will be created and sent out on cron
+                    insert_record('user_preferences', array( 'userid' => $user->id, 'name'   => 'create_password', 'value'  => 1));
+                    insert_record('user_preferences', array( 'userid' => $user->id, 'name'   => 'auth_forcepasswordchange', 'value'  => 1));
+                }
+            } else {
+                // Record not added -- possibly some other error
+                notify($strusernotaddederror . ': ' . $username);
+                $userserrors++;
+                continue;
+            }
+        }
 
-                                    case 3:   // non-editing teacher
-                                        $ret = add_teacher($user->id, $course[$i]->id, 0);
-                                        break;
+        // find course enrolments, groups and roles/types
+        for($ncourses = 1; $addcourse = @$user->{'course' . $ncourses}; ++$ncourses) {
+            // find course
+            if(!$course = @$courses[$addcourse]) {
+                notify(get_string('unknowncourse', 'error', $addcourse));
+                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 . '<br >';
+                }
+            } 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) . '<br />';
+            } else {
+                notify(get_string('enrolledincoursenot', '', $addcourse));
+            }
 
-                                    default:  // student
-                                        $ret = enrol_student($user->id, $course[$i]->id);
-                                        break;
-                                }
-                            } else {
-                                $ret = enrol_student($user->id, $course[$i]->id);
-                            }
-                            if ($ret) {   // OK
-                                notify('-->'. get_string('enrolledincourse', '', $addcourse[$i]));
-                            } else {
-                                notify('-->'.get_string('enrolledincoursenot', '', $addcourse[$i]));
-                            }
-                        }
-                    }
-                    for ($i=0; $i<5; $i++) {   // Add user to groups if necessary
-                        if ($course[$i] && $groupid[$i]) {
-                            $coursecontext = get_context_instance(CONTEXT_COURSE, $course[$i]->id);
-                            if (count(get_user_roles($coursecontext, $user->id))) {
-                                if (groups_add_member($groupid[$i], $user->id)) {
-                                    notify('-->' . get_string('addedtogroup','',$addgroup[$i]));
-                                } else {
-                                    notify('-->' . get_string('addedtogroupnot','',$addgroup[$i]));
-                                }
-                            } else {
-                                notify('-->' . get_string('addedtogroupnotenrolled','',$addgroup[$i]));
-                            }
+            // 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) . '<br />';
+                        } else {
+                            notify(get_string('addedtogroupnot','',$addgroup));
                         }
+                    } else {
+                        notify(get_string('addedtogroupnotenrolled','',$addgroup));
                     }
-
-                    unset ($user);
+                } else {
+                    notify(get_string('groupunknown','error',$addgroup));
                 }
             }
-            fclose($fp);
-            notify("$strusersnew: $usersnew");
-            notify(get_string('usersupdated', 'admin') . ": $usersupdated");
-            notify(get_string('errors', 'admin') . ": $userserrors");
-            if ($allowrenames) {
-                notify(get_string('usersrenamed', 'admin') . ": $renames");
-                notify(get_string('renameerrors', 'admin') . ": $renameerrors");
-            }
-            echo '<hr />';
+        }
+    }
+    echo '</p>';
+    
+    fclose($fp);
+    notify(get_string('userscreated', 'admin') . ': ' . $usersnew);
+    notify(get_string('usersupdated', 'admin') . ': ' . $usersupdated);
+    notify(get_string('errors', 'admin') . ': ' . $userserrors);
+    if ($allowrenames) {
+        notify(get_string('usersrenamed', 'admin') . ': ' . $renames);
+        notify(get_string('renameerrors', 'admin') . ': ' . $renameerrors);
+    }
+    echo '<hr />';
 }
 
 /// Print the form
 print_heading_with_help(get_string('uploadusers'), 'uploadusers');
-
 $mform->display();
-
 admin_externalpage_print_footer();
-
-
-
-function my_file_get_contents($filename, $use_include_path = 0) {
-    /// Returns the file as one big long string
-
-    $data = "";
-    $file = @fopen($filename, "rb", $use_include_path);
-    if ($file) {
-        while (!feof($file)) {
-            $data .= fread($file, 1024);
-        }
-        fclose($file);
-    }
-    return $data;
-}
-
 ?>
index 075baf4ddb2a0c3c8ec3371d4a28249fa30279b5..13d7d95229b1020a68c6aaa0b8ec0a7054adec7e 100644 (file)
@@ -3,22 +3,124 @@ require_once $CFG->libdir.'/formslib.php';
 
 class admin_uploaduser_form extends moodleform {
     function definition (){
+        global $CFG;
+        $templateuser = $this->_customdata;
+        if(empty($templateuser)) {
+            if (!$templateuser = get_admin()) {
+                error('Could not find site admin');
+            }
+        }
+        
         $mform =& $this->_form;
 
         $mform->addElement('file', 'userfile', get_string('file'));
         $mform->addRule('userfile', null, 'required');
 
-        $mform->addElement('header', 'settingsheader', get_string('settings'));
+        $mform->addElement('header', 'defaultheader', get_string('defaultvalues', 'admin'));
+        $mform->addElement('text', 'username', get_string('username'), 'size="20"');
+
+        $modules = get_list_of_plugins('auth');
+        $auth_options = array();
+        foreach ($modules as $module) {
+            $auth_options[$module] = get_string("auth_$module"."title", "auth");
+        }
+        $mform->addElement('select', 'auth', get_string('chooseauthmethod','auth'), $auth_options);
+        $mform->setDefault('auth', $templateuser->auth);
+        $mform->setHelpButton('auth', array('authchange', get_string('chooseauthmethod','auth')));
 
-        $passwordopts = array( 0 => get_string('infilefield', 'auth'),
-            1 => get_string('createpasswordifneeded', 'auth'),
+        $mform->addElement('text', 'email', get_string('email'), 'maxlength="100" size="30"');
+        $choices = array(
+            get_string('emaildisplayno'),
+            get_string('emaildisplayyes'),
+            get_string('emaildisplaycourse'),
         );
+        $mform->addElement('select', 'maildisplay', get_string('emaildisplay'), $choices);
+        $mform->setDefault('maildisplay', 2);
+
+        $choices = array(
+            get_string('emailenable'),
+            get_string('emaildisable'),
+        );
+        $mform->addElement('select', 'emailstop', get_string('emailactive'), $choices);
+
+        $choices = array(
+            get_string('textformat'),
+            get_string('htmlformat'),
+        );
+        $mform->addElement('select', 'mailformat', get_string('emailformat'), $choices);
+        $mform->setDefault('mailformat', 1);
+
+        $choices = array(
+            get_string('autosubscribeyes'),
+            get_string('autosubscribeno'),
+        );
+        $mform->addElement('select', 'autosubscribe', get_string('autosubscribe'), $choices);
+        $mform->setDefault('autosubscribe', 1);
+
+        if ($CFG->htmleditor) {
+            $choices = array(
+                get_string('texteditor'),
+                get_string('htmleditor'),
+            );
+            $mform->addElement('select', 'htmleditor', get_string('textediting'), $choices);
+            $mform->setDefault('htmleditor', 1);
+        }
+
+        $mform->addElement('text', 'city', get_string('city'), 'maxlength="100" size="25"');
+        $mform->setType('city', PARAM_MULTILANG);
+        $mform->setDefault('city', $templateuser->city);
+        
+        $mform->addElement('select', 'country', get_string('selectacountry'), get_list_of_countries());
+        $mform->setDefault('country', $templateuser->country);
 
-        $mform->addElement('select', 'createpassword', get_string('passwordhandling', 'auth'), $passwordopts);
+        $choices = get_list_of_timezones();
+        $choices['99'] = get_string('serverlocaltime');
+        $mform->addElement('select', 'timezone', get_string('timezone'), $choices);
+        $mform->setDefault('timezone', $templateuser->timezone);
+
+        $mform->addElement('select', 'lang', get_string('preferredlanguage'), get_list_of_languages());
+        $mform->setDefault('lang', $templateuser->lang);
+        
+        $mform->addElement('htmleditor', 'description', get_string('userdescription'));
+        $mform->setType('description', PARAM_CLEAN);
+        $mform->setHelpButton('description', array('text', get_string('helptext')));
+
+        $mform->addElement('text', 'url', get_string('webpage'), 'maxlength="255" size="50"');
+
+        $mform->addElement('text', 'institution', get_string('institution'), 'maxlength="40" size="25"');
+        $mform->setType('institution', PARAM_MULTILANG);
+        $mform->setDefault('institution', $templateuser->institution);
+
+        $mform->addElement('text', 'department', get_string('department'), 'maxlength="30" size="25"');
+        $mform->setType('department', PARAM_MULTILANG);
+        $mform->setDefault('department', $templateuser->department);
+
+        $mform->addElement('text', 'phone1', get_string('phone'), 'maxlength="20" size="25"');
+        $mform->setType('phone1', PARAM_CLEAN);
+
+        $mform->addElement('text', 'phone2', get_string('phone'), 'maxlength="20" size="25"');
+        $mform->setType('phone2', PARAM_CLEAN);
+
+        $mform->addElement('text', 'address', get_string('address'), 'maxlength="70" size="25"');
+        $mform->setType('address', PARAM_MULTILANG);
+        
+        $mform->addElement('header', 'settingsheader', get_string('settings'));
+
+        $choices = array(
+            get_string('infilefield', 'auth'),
+            get_string('createpasswordifneeded', 'auth'),
+        );
+        $mform->addElement('select', 'createpassword', get_string('passwordhandling', 'auth'), $choices);
 
         $mform->addElement('selectyesno', 'updateaccounts', get_string('updateaccounts', 'admin'));
         $mform->addElement('selectyesno', 'allowrenames', get_string('allowrenames', 'admin'));
 
+        $choices = array(
+            get_string('addcounter', 'admin'),
+            get_string('skipuser', 'admin'),
+        );
+        $mform->addElement('select', 'duplicatehandling', get_string('newusernamehandling', 'admin'), $choices);
+
         $this->add_action_buttons(false, get_string('uploadusers'));
     }
 
index 7f1f4680abec0dfeecedda8ac92ca9a56c93e561..3cad89c4fa2291c815add6394095887de6a750b5 100755 (executable)
         $actions[2] = get_string('messageselectadd');
     }
     $actions[3] = get_string('delete');
-
+    $actions[4] = get_string('displayonpage');
     // create the bulk operations form
     $user_bulk_form =& new user_bulk_form(null, $actions);
     // check if an action should be performed and do so
     switch ($user_bulk_form->getAction()) {
     case 1:
-        include($CFG->dirroot . '/admin/user/user_bulk_confirm.php');
-        return;
+        redirect($CFG->wwwroot . '/admin/user/user_bulk_confirm.php');
     case 2:
-        include($CFG->dirroot . '/admin/user/user_bulk_message.php');
-        return;
+        redirect($CFG->wwwroot . '/admin/user/user_bulk_message.php');
     case 3:
-        include($CFG->dirroot . '/admin/user/user_bulk_delete.php');
-        return;
+        redirect($CFG->wwwroot . '/admin/user/user_bulk_delete.php');
+    case 4:
+        redirect($CFG->wwwroot . '/admin/user/user_bulk_display.php');
     }
 
     // prepare user filter types
index 4fcc36dc3eb29a8c60cd6a47baa1b46693c89178..2e062b23e23b88af9389087bf6684ebcbc910edf 100755 (executable)
@@ -21,7 +21,7 @@ foreach ($SESSION->bulk_susers as $k => $v) {
 }
 
 if (empty($userlist)) {
-    redirect($CFG->wwwroot . '/admin/user_bulk.php');
+    redirect($CFG->wwwroot . '/admin/user/user_bulk.php');
 }
 
 admin_externalpage_setup('userbulk');
index 753e7c7768375f0695fefc25575a6123464b2db3..42c18c79e6261f1172670541214a3741eac852fc 100755 (executable)
@@ -22,7 +22,7 @@ foreach ($SESSION->bulk_susers as $k => $v) {
 }
 
 if (empty($userlist)) {
-    redirect($CFG->wwwroot . '/admin/user_bulk.php');
+    redirect($CFG->wwwroot . '/admin/user/user_bulk.php');
 }
 
 admin_externalpage_setup('userbulk');
diff --git a/admin/user/user_bulk_display.php b/admin/user/user_bulk_display.php
new file mode 100755 (executable)
index 0000000..7504ba9
--- /dev/null
@@ -0,0 +1,76 @@
+<?php // $Id$
+
+    require_once('../../config.php');
+    require_once($CFG->libdir.'/adminlib.php');
+
+    if(empty($SESSION->bulk_susers)) {
+        redirect($CFG->wwwroot . '/admin/user/user_bulk.php');
+    }
+    $users = $SESSION->bulk_susers;
+    $usertotal = get_users(false);
+    $usercount = count($users);
+
+    $sort         = optional_param('sort', 'fullname', PARAM_ALPHA);
+    $dir          = optional_param('dir', 'asc', PARAM_ALPHA);
+    
+    $strnever = get_string('never');
+    $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
+    $site = get_site();
+
+    admin_externalpage_setup('userbulk');
+    admin_externalpage_print_header();
+
+    $countries =& get_list_of_countries();
+    foreach ($users as $key => $id) {
+        $user =& get_record('user', 'id', $id, null, null, null, null, 'id,firstname,lastname,username,email,country,lastaccess,city');
+        $user->fullname = fullname($user, true);
+        $user->country = @$countries[$user->country];
+        unset($user->firstname);
+        unset($user->lastname);
+        $users[$key] = $user;
+    }
+    unset($countries);
+    
+    // Need to sort by data
+    function sort_compare($a, $b) {
+        global $sort, $dir;
+        if($sort == 'lastaccess') {
+            $rez = $b->lastaccess - $a->lastaccess;
+        } else {
+            $rez = strcasecmp(@$a->$sort, @$b->$sort);
+        }
+        return $dir == 'desc' ? -$rez : $rez;
+    }
+    usort($users, 'sort_compare');
+    
+    $table->width = "95%";
+    $columns = array('fullname', 'username', 'email', 'city', 'country', 'lastaccess');
+    foreach ($columns as $column) {
+        $strtitle = get_string($column);
+        if ($sort != $column) {
+            $columnicon = '';
+            $columndir = 'asc';
+        } else {
+            $columndir = $dir == 'asc' ? 'desc' : 'asc';
+            $columnicon = ' <img src="' . $CFG->pixpath . '/t/' . ($dir == 'asc' ? 'down' : 'up' ). '.gif" alt="" />';
+        }
+        $table->head[] = '<a href="user_bulk_display.php?sort=' . $column . '&amp;dir=' . $columndir .'">' .$strtitle . '</a>' . $columnicon;
+        $table->align[] = 'left';
+    }
+
+    foreach($users as $user) {
+        $table->data[] = array (
+            '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $user->id . '&amp;course=' . $site->id .'">' . $user->fullname .'</a>',
+            $user->username,
+            $user->email,
+            $user->city,
+            $user->country,
+            $user->lastaccess ? format_time(time() - $user->lastaccess) : $strnever
+        );
+    }
+
+    print_heading("$usercount / $usertotal ".get_string('users'));
+    print_table($table);
+
+    admin_externalpage_print_footer();
+?>
\ No newline at end of file
index fbe812ec902ba33eb3822a9e372e4318abfaf558..d4b403836894348d3d2fb12cecf125c049201fbf 100644 (file)
@@ -53,7 +53,7 @@ class user_bulk_form extends moodleform {
         }
         $obj =& $this->_form->getElement('comment');
         $obj->setLabel($comment);
-        $obj->setText(get_string('usersfound', 'bulkusers', $count));
+        $obj->setText(get_string('usersfound', 'bulkusers', $count) . ' ' .get_string('usersselected', 'bulkusers', count($SESSION->bulk_susers)));
     }
     
     function definition_after_data() {
index 47b71cc41beefc687795e11dac458d872bc9def1..f4a0707b8d0845573cec4b9aedd29775fe3da521 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 $string['accessdenied'] = 'Access denied';
 $string['accounts'] = 'Accounts';
+$string['addcounter'] = 'Append counter';
 $string['adminseesall'] = 'Admins See All';
 $string['adminseesallevents'] = 'Administrators see all events';
 $string['adminseesownevents'] = 'Administrators are just like other users';
@@ -252,6 +253,7 @@ $string['defaultallowedmodules'] = 'Default allowed modules';
 $string['defaultcourseroleid'] = 'Default role for users in a course';
 $string['defaultrequestcategory'] = 'Default category for course requests';
 $string['defaultuserroleid'] = 'Default role for all users';
+$string['defaultvalues'] = 'Default values';
 $string['deleteunconfirmed'] = 'Delete unconfirmed users after';
 $string['deleteuser'] = 'Delete user';
 $string['density'] = 'Density';
@@ -423,6 +425,7 @@ $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['nodefaultuserrolelists'] = 'Don\'t return all default role users';
 $string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed';
@@ -561,6 +564,7 @@ $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';
index 13fd50dd886a370aa477c4fff8aacd2e550cf296..3f56497cdbe3c08a83f230a638e53f96cbe1c17f 100644 (file)
@@ -6,4 +6,5 @@ $string['removeall'] = 'Clear selection';
 $string['removesel'] = 'Remove from selection';
 $string['available'] = 'Available';
 $string['selected'] = 'Selected';
-$string['usersfound'] = '$a user(s) found';
+$string['usersfound'] = '$a user(s) found.';
+$string['usersselected'] = '$a user(s) selected.';
\ No newline at end of file
index e36a9adf9992ceaa234d979f5e07c44d741ed607..cd1a8d2ed934f3b31cadf4af3f4776784b6c19d7 100644 (file)
@@ -3,6 +3,7 @@
 
 
 $string['adminprimarynoedit'] = 'The primary admin cannot be edited by others';
+$string['cannotassignrole'] = 'Cannot assign role in course';
 $string['cannotcreatelangdir'] = 'Cannot create lang dir.';
 $string['cannotcreatetempdir'] = 'Cannot create temp dir.';
 $string['cannotcustomizelocallang'] = 'You do not have permission to customize the strings translation.  This permission is controlled by the capability "moodle/site:langeditlocal". Set this capability to allow you to edit local language packages in case you want to modify translations for your site.';
@@ -21,6 +22,7 @@ $string['confirmsesskeybad'] = 'Sorry, but your session key could not be confirm
 $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['downloadedfilecheckfailed'] = 'Downloaded file check failed.';
+$string['duplicateusername'] = 'Duplicate username - skiping record';
 $string['errorcleaningdirectory'] = 'Error cleaning directory \"$a\"';
 $string['errorcopyingfiles'] = 'Error copying files';
 $string['errorcreatingdirectory'] = 'Error creating directory \"$a\"';
@@ -85,11 +87,12 @@ $string['unicodeupgradeerror'] = 'Sorry, but your database is not already in Uni
 $string['unknowncourse'] = 'Unknown course named \"$a\"';
 $string['unknowncourseidnumber'] = 'Unknown Course ID \"$a\"';
 $string['unknownuseraction'] = 'Sorry, I do not understand this user action.';
-$string['usernotaddederror'] = 'User \"$a\" not added - unknown error';
-$string['usernotaddedregistered'] = 'User \"$a\" not added - already registered';
+$string['usernotaddederror'] = 'User not added - unknown error';
+$string['usernotaddedregistered'] = 'User not added - already registered';
 $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['wrongdestpath'] = 'Wrong destination path.';
 $string['wrongsourcebase'] = 'Wrong source URL base.';
 $string['wrongzipfilename'] = 'Wrong ZIP filename.';
index 7c58cdf372d825c08b96aaa4c47967eff2265c1f..63f020d6d31eff7fa4092faad8cfa56d452c84c5 100644 (file)
@@ -9,30 +9,56 @@
   <li>The first record of the file is special, and contains a list of fieldnames. This defines the format of the rest of the file.
     <blockquote>
       <p><strong>Required fieldnames:</strong> these fields must be included in the first record, and defined for each user</p>
-      <p><code class="example1">username, password, firstname, lastname, email</code></p>
-
-      <p><strong>Default fieldnames:</strong> these are optional - if they are not included then the values are taken from the primary admin</p>
-      <p><code class="example1">institution, department, city, country, lang, auth, timezone</code> </p>
-      <p><strong>Optional fieldnames: </strong>all of these are completely optional. The  course names are the &quot;shortnames&quot; of the courses - if present then the user  will be enrolled as students in those courses. Group names must be associated to the corresponding courses, i.e. group1 to course1, etc.</p>
-      <p> <code class="example1">idnumber, icq, phone1, phone2, address, url, description, mailformat, maildisplay, htmleditor, autosubscribe, course1, course2, course3, course4, course5, group1, group2, group3, group4, group5, type1, type2, type3, type4, type5, role1, role2, role3, role4, role5, emailstop</code></p>
+      <p><code class="example1">firstname, lastname</code></p>
+      <p><strong>Optional fieldnames: </strong>all of these are completely optional. If a values is present for the field in the file, then that value is used; else, the default value for that field is used.</p>
+      <p> <code class="example1">institution, department, city, country, lang, auth, timezone, idnumber, icq, phone1, phone2, address, url, description, mailformat, maildisplay, htmleditor, autosubscribe, emailstop</code></p>
+      <p><strong>Enrolment fieldnames (optional): </strong>The  course names are the &quot;shortnames&quot; of the courses - if present then the user will be enrolled in those courses. For groups use group name; for roles use id. Group names must be associated to the corresponding courses, i.e. group1 to course1, etc.</p>
+      <p><code class="example1">course1, group1, type1, role1, course2, group2, type2, role2, etc.</code></p>
     </blockquote>
     </li>
   <li>Commas within the data should be encoded as &amp;#44 - the script will automatically decode these back to commas. </li>
   <li>For Boolean fields, use 0 for false and 1 for true. </li>
   <li>Types are used to tell Moodle whether the user is a student or a teacher if a corresponding course exists (e.g. type2 corresponds to course2). 1 = Student, 2 = Editing Teacher, and 3 = Non-editing Teacher. If type is left blank, or if no course is specified, the user is default to student. </li>
-  <li>For courses use the short name; for groups use group name; for roles use id.</li>
   <li>Note: If a user is already registered in the Moodle user database, this script will return the 
       userid number (database index) for that user, and will enrol the user as a student in any of the
       specified courses WITHOUT updating the other specified data.</li>
 </ul>
-  
-  
 <p>Here is an example of a valid import file:</p>
 <p><code>username, password, firstname, lastname, email, lang, idnumber, maildisplay, course1, group1, type1<br />
 jonest, verysecret, Tom, Jones, jonest@someplace.edu, en, 3663737, 1, Intro101, Section 1, 1<br />
 reznort, somesecret, Trent, Reznor, reznort@someplace.edu, en_us, 6736733, 0, Advanced202, Section 3, 3
 </code></p>
 
+<h2>Templates</h2>
+<p>The default values are processed as templates in which the following codes are allowed:</p>
+<ul>
+<li><code>%l</code> - will be replaced by the lastname</li>
+<li><code>%f</code> - will be replaced by the firstname</li>
+<li><code>%u</code> - will be replaced by the username</li>
+<li><code>%%</code> - will be replaced by the %</li>
+</ul>
+<p>Between the percent sign (%) and any code letter (l, f or u) the following modifiers are allowed:</p>
+<ul>
+<li>minus sign (-) - the information specified by the code letter will be converted to lowercase</li>
+<li>plus sign (+) - the information specified by the code letter will be converted to uppercase</li>
+<li>a decimal number - the information specified by the code letter will be truncated to that many characters</li>
+</ul>
+
+<p>For example, if the firstname is John and the lastname is Doe, the following values will be obtained with the specified templates:</p>
+<ul>
+<li>%l%f = DoeJohn</li>
+<li>%l%1f = DoeJ</li>
+<li>%-l%+f = doeJOHN</li>
+<li>%-f_%-l = john_doe</li>
+<li>http://www.example.com/~%u/ = http://www.example.com/~jdoe/ (if the username is jdoe or %-1f%-l)</li>
+</ul>
+<p>Template processing is done only on default values, and not on the values retrieved from the CSV file.</p>
+<p>In order to create corect Moodle usernames, the username is always converted to lowercase. Moreover, if the &quot;Allow extended characters in usernames&quot; option in the Site policies page is off, characters different to letters, digits, dash (-) and dot (.) are removed. 
+For example if the firstname is John Jr. and the lastname is Doe, the username %-f%-l will produce john jr.doe when Allow extended characters in usernames is on, and johnjr.doe when off (notice the extra space).</p>
+<p>When the &quot;New username duplicate handling&quot; setting is set to Append counter, an auto-increment counter will be append to duplicate usernames produced by the template.
+For example, if the CSV file contains the users named John Doe, Jane Doe and Jenny Doe without explicit usernames, the default username is %-1f%-l and New username duplicate handling is set to Append counter, then the usernames produced will be jdoe, jdoe2 and jdoe3.
+</p>
+
 <h2>Updating existing accounts</h2>
 
 <p>By default Moodle assumes that you will be creating new user accounts, and skips records where the username matches an existing account. However, if you set "Update existing accounts" to <b>Yes</b>, the existing user account will be updated. </p>