/** * The CSV file is parsed here so validation errors can be returned to the * user. The data from a successful parsing is stored in the <var>$CVSDATA</var> * array so it can be accessed by the submit function * * @param Pieform $form The form to validate * @param array $values The values submitted */ function uploadcsv_validate(Pieform $form, $values) { global $CSVDATA, $ALLOWEDKEYS, $MANDATORYFIELDS, $FORMAT, $USER, $UPDATES, $MEMBERS, $GROUPS; // Don't even start attempting to parse if there are previous errors if ($form->has_errors()) { return; } if ($values['file']['size'] == 0) { $form->set_error('file', $form->i18n('rule', 'required', 'required', array())); return; } $institution = $values['institution']; if (!$USER->can_edit_institution($institution)) { $form->set_error('institution', get_string('notadminforinstitution', 'admin')); return; } require_once 'csvfile.php'; $csvgroups = new CsvFile($values['file']['tmp_name']); $csvgroups->set('allowedkeys', $ALLOWEDKEYS); $csvgroups->set('mandatoryfields', $MANDATORYFIELDS); $csvdata = $csvgroups->get_data(); if (!empty($csvdata->errors['file'])) { $form->set_error('file', $csvdata->errors['file']); return; } $csverrors = new CSVErrors(); $formatkeylookup = array_flip($csvdata->format); $shortnames = array(); $hadadmin = array(); $num_lines = count($csvdata->data); foreach ($csvdata->data as $key => $line) { // If headers exists, increment i = key + 2 for actual line number $i = $csvgroups->get('headerExists') ? $key + 2 : $key + 1; // In adding 5000 groups, this part was approx 8% of the wall time. if (!($key % 25)) { set_progress_info('uploadgroupmemberscsv', $key, $num_lines * 10, get_string('validating', 'admin')); } // Trim non-breaking spaces -- they get left in place by File_CSV foreach ($line as &$field) { $field = preg_replace('/^(\\s|\\xc2\\xa0)*(.*?)(\\s|\\xc2\\xa0)*$/', '$2', $field); } $shortname = $line[$formatkeylookup['shortname']]; $username = $line[$formatkeylookup['username']]; $role = $line[$formatkeylookup['role']]; $gid = get_field('group', 'id', 'shortname', $shortname, 'institution', $institution); if (!$gid) { $csverrors->add($i, get_string('uploadgroupmemberscsverrornosuchshortname', 'admin', $i, $shortname, $institution)); continue; } $uid = get_field_sql('SELECT id FROM {usr} WHERE LOWER(username) = ?', array(strtolower($username))); if (!$uid) { $csverrors->add($i, get_string('uploadgroupmemberscsverrornosuchusername', 'admin', $i, $username)); continue; } if ($institution != 'mahara' && !record_exists('usr_institution', 'usr', $uid, 'institution', $institution)) { $csverrors->add($i, get_string('uploadgroupmemberscsverrorusernotininstitution', 'admin', $i, $username, $institution)); continue; } if (!in_array($role, array_keys(group_get_role_info($gid)))) { $csverrors->add($i, get_string('uploadgroupmemberscsverrorinvalidrole', 'admin', $i, $role)); continue; } if (!isset($MEMBERS[$gid])) { $MEMBERS[$gid] = array(); } if (isset($MEMBERS[$gid][$uid])) { $csverrors->add($i, get_string('uploadgroupmemberscsverrorduplicateusername', 'admin', $i, $shortname, $username)); continue; } $MEMBERS[$gid][$uid] = $role; $GROUPS[$gid] = $shortname; if ($role == 'admin') { $hasadmin[$shortname] = 1; } } foreach ($GROUPS as $shortname) { if (!isset($hasadmin[$shortname])) { $csverrors->add($i, get_string('uploadgroupmemberscsverrornoadminlisted', 'admin', $i, $shortname)); } } if ($errors = $csverrors->process()) { $form->set_error('file', clean_html($errors)); return; } $FORMAT = $csvdata->format; $CSVDATA = $csvdata->data; }
/** * Add the users to the system. */ function bulkimport_submit(Pieform $form, $values) { global $SESSION, $LEAP2AFILES; require_once 'file.php'; require_once get_config('docroot') . 'import/lib.php'; safe_require('import', 'leap'); $key = 0; $total = count($LEAP2AFILES); log_info('Attempting to import ' . $total . ' users from Leap2A files'); foreach ($LEAP2AFILES as $username => $filename) { if (!($key % 10)) { set_progress_info('bulkimport', $key, $total, get_string('importing', 'admin')); } $key++; import_next_user($filename, $username, $values['authinstance']); } finish_import(); }
/** * Add the users to the system. Make sure that they have to change their * password on next login also. */ function uploadcsv_submit(Pieform $form, $values) { global $USER, $SESSION, $CSVDATA, $FORMAT, $UPDATES; $formatkeylookup = array_flip($FORMAT); $authinstance = (int) $values['authinstance']; $authrecord = get_record('auth_instance', 'id', $authinstance); $authobj = AuthFactory::create($authinstance); $institution = new Institution($authobj->institution); $maxusers = $institution->maxuseraccounts; if (!empty($maxusers)) { $members = count_records_sql(' SELECT COUNT(*) FROM {usr} u INNER JOIN {usr_institution} i ON u.id = i.usr WHERE i.institution = ? AND u.deleted = 0', array($institution->name)); if ($members + count($CSVDATA) > $maxusers) { $SESSION->add_error_msg(get_string('uploadcsvfailedusersexceedmaxallowed', 'admin')); redirect('/admin/users/uploadcsv.php'); } } if ($values['updateusers']) { log_info('Updating users from the CSV file'); } else { log_info('Inserting users from the CSV file'); } db_begin(); $addedusers = array(); $cfgsendemail = get_config('sendemail'); if (empty($values['emailusers'])) { // Temporarily disable email sent during user creation, e.g. institution membership $GLOBALS['CFG']->sendemail = false; } $key = 0; $steps_total = $values['updateusers'] ? 5 : 4; $steps_done = $steps_total - 3; $num_lines = sizeof($CSVDATA); foreach ($CSVDATA as $record) { if (!($key % 25)) { // This part has three times the weight of the other two steps. set_progress_info('uploaduserscsv', $num_lines * $steps_done + $key * 3, $num_lines * $steps_total, get_string('committingchanges', 'admin')); } $key++; $user = new StdClass(); foreach ($FORMAT as $field) { if ($field == 'username' || $field == 'firstname' || $field == 'lastname' || $field == 'password' || $field == 'email' || $field == 'studentid' || $field == 'preferredname') { $user->{$field} = $record[$formatkeylookup[$field]]; } } $user->authinstance = $authinstance; if ($USER->get('admin') || get_config_plugin('artefact', 'file', 'institutionaloverride')) { $user->quota = $values['quota']; } $profilefields = new StdClass(); $remoteuser = null; foreach ($FORMAT as $field) { if ($field == 'username' || $field == 'password') { continue; } if ($field == 'remoteuser') { if (!empty($record[$formatkeylookup[$field]])) { $remoteuser = $record[$formatkeylookup[$field]]; } continue; } $profilefields->{$field} = $record[$formatkeylookup[$field]]; } if (!$values['updateusers'] || !isset($UPDATES[$user->username])) { $user->passwordchange = (int) $values['forcepasswordchange']; $user->id = create_user($user, $profilefields, $institution, $authrecord, $remoteuser, $values, true); $addedusers[] = $user; log_debug('added user ' . $user->username); } else { if (isset($UPDATES[$user->username])) { $updated = update_user($user, $profilefields, $remoteuser, $values, true, true); if (empty($updated)) { // Nothing changed for this user unset($UPDATES[$user->username]); } else { $UPDATES[$user->username] = $updated; log_debug('updated user ' . $user->username . ' (' . implode(', ', array_keys($updated)) . ')'); } } } set_time_limit(10); } db_commit(); // Reenable email set_config('sendemail', $cfgsendemail); // Only send e-mail to users after we're sure they have been inserted // successfully $straccountcreatedtext = $values['forcepasswordchange'] ? 'accountcreatedchangepasswordtext' : 'accountcreatedtext'; $straccountcreatedhtml = $values['forcepasswordchange'] ? 'accountcreatedchangepasswordhtml' : 'accountcreatedhtml'; if ($values['emailusers'] && $addedusers) { foreach ($addedusers as $user) { $failedusers = array(); try { email_user($user, null, get_string('accountcreated', 'mahara', get_config('sitename')), get_string($straccountcreatedtext, 'mahara', $user->firstname, get_config('sitename'), $user->username, $user->password, get_config('wwwroot'), get_config('sitename')), get_string($straccountcreatedhtml, 'mahara', $user->firstname, get_config('wwwroot'), get_config('sitename'), $user->username, $user->password, get_config('wwwroot'), get_config('wwwroot'), get_config('sitename'))); } catch (EmailException $e) { log_info($e->getMessage()); $failedusers[] = $user; } } if ($failedusers) { $message = get_string('uploadcsvsomeuserscouldnotbeemailed', 'admin') . "\n<ul>\n"; foreach ($failedusers as $user) { $message .= '<li>' . full_name($user) . ' <' . hsc($user->email) . "></li>\n"; } $message .= "</ul>\n"; $SESSION->add_info_msg($message, false); } } log_info('Added ' . count($addedusers) . ' users, updated ' . count($UPDATES) . ' users.'); $SESSION->add_ok_msg(get_string('csvfileprocessedsuccessfully', 'admin')); if ($UPDATES) { $updatemsg = smarty_core(); $updatemsg->assign('added', count($addedusers)); $updatemsg->assign('updates', $UPDATES); $SESSION->add_info_msg($updatemsg->fetch('admin/users/csvupdatemessage.tpl'), false); } else { $SESSION->add_ok_msg(get_string('numbernewusersadded', 'admin', count($addedusers))); } set_progress_done('uploaduserscsv'); redirect('/admin/users/uploadcsv.php'); }
/** * Completely update the membership of a group * * @param int $groupid ID of group * @param array $members list of members and roles, structured like this: * array( * userid => role, * userid => role, * ... * ) * @param lines_done Number of lines in the file that have been completed so far * @param num_lines Number of lines in the file (this and the previous values * are used to update the progress meter. */ function group_update_members($groupid, $members, $lines_done = 0, $num_lines = 0) { global $USER; $groupid = group_param_groupid($groupid); if (!($group = get_record('group', 'id', $groupid, 'deleted', 0))) { throw new NotFoundException("group_update_members: group not found: {$groupid}"); } if ($group->institution && !$USER->can_edit_institution($group->institution) || !$group->institution && !$USER->get('admin')) { throw new AccessDeniedException("group_update_members: access denied"); } if (!is_array($members)) { throw new SystemException("group_update_members: members must be an array"); } $badroles = array_unique(array_diff($members, array_keys(group_get_role_info($groupid)))); if (!empty($badroles)) { throw new UserException("group_update_members: invalid role(s) specified for group {$group->name} (id {$groupid}): " . join(', ', $badroles)); } if (!in_array('admin', $members)) { $groupname = get_field('group', 'name', 'id', $groupid); throw new UserException("group_update_members: no group admins listed for group {$group->name} (id {$groupid})"); } // Check the new members list for invalid users if (!empty($members)) { $userids = array_map('intval', array_keys($members)); if ($group->institution && $group->institution != 'mahara') { $gooduserids = get_column_sql(' SELECT usr FROM {usr_institution} WHERE usr IN (' . join(',', $userids) . ') AND institution = ?', array($group->institution)); if ($baduserids = array_diff($userids, $gooduserids)) { if (!(count($baduserids) == 1 && $baduserids[0] == $USER->id)) { throw new UserException("group_update_members: some members are not in the institution {$group->institution}: " . join(',', $baduserids)); } } } else { $gooduserids = get_column_sql(' SELECT id FROM {usr} WHERE id IN (' . join(',', $userids) . ') AND deleted = 0', array()); if ($baduserids = array_diff($userids, $gooduserids)) { throw new UserException("group_update_members: some new members do not exist: " . join(',', $baduserids)); } } } // Update group members $oldmembers = get_records_assoc('group_member', 'group', $groupid, '', 'member,role'); $added = 0; $removed = 0; $updated = 0; $to_add = count(array_diff_key($members, $oldmembers)); $to_remove = count(array_diff_key($oldmembers, $members)); $to_update = count($members) - $to_add; db_begin(); foreach ($members as $userid => $role) { if (!isset($oldmembers[$userid])) { group_add_user($groupid, $userid, $role); $added++; if (!(($lines_done + $added) % 25)) { set_progress_info('uploadgroupmemberscsv', $num_lines + 9 * ($lines_done + count($members) * $added / ($to_add + $to_remove)), $num_lines * 10, get_string('committingchanges', 'admin')); } } else { if ($oldmembers[$userid]->role != $role) { set_field('group_member', 'role', $role, 'group', $groupid, 'member', $userid); $updated++; } } } foreach (array_keys($oldmembers) as $userid) { if (!isset($members[$userid])) { group_remove_user($groupid, $userid, true); $removed++; if (!(($lines_done + $added + $removed) % 25)) { set_progress_info('uploadgroupmemberscsv', $num_lines + 9 * ($lines_done + count($members) * ($added + $removed) / ($to_add + $to_remove)), $num_lines * 10, get_string('committingchanges', 'admin')); } } } db_commit(); if ($added == 0 && $removed == 0 && $updated == 0) { return null; } return array('added' => $added, 'removed' => $removed, 'updated' => $updated); }
/** * Add the users to the system. Make sure that they have to change their * password on next login also. */ function uploadcsv_submit(Pieform $form, $values) { global $SESSION, $CSVDATA, $FORMAT, $UPDATES, $USER; $formatkeylookup = array_flip($FORMAT); $institution = $values['institution']; if ($values['updategroups']) { log_info('Updating groups from the CSV file'); } else { log_info('Inserting groups from the CSV file'); } db_begin(); $addedgroups = array(); $key = 0; $num_lines = count($CSVDATA); foreach ($CSVDATA as $record) { if (!($key % 25)) { set_progress_info('uploadgroupscsv', $num_lines + $key * 9, $num_lines * 10, get_string('committingchanges', 'admin')); } $key++; $group = new StdClass(); $group->name = $record[$formatkeylookup['displayname']]; $group->shortname = $record[$formatkeylookup['shortname']]; $group->institution = $institution; $group->grouptype = $record[$formatkeylookup['roles']]; foreach ($FORMAT as $field) { if ($field == 'displayname' || $field == 'shortname' || $field == 'roles') { continue; } if ($field == 'submitpages') { $group->submittableto = $record[$formatkeylookup[$field]]; continue; } $group->{$field} = $record[$formatkeylookup[$field]]; } if (!$values['updategroups'] || !isset($UPDATES[$group->shortname])) { $group->members = array($USER->id => 'admin'); $group->id = group_create((array) $group); $addedgroups[] = $group; log_debug('added group ' . $group->name); } else { if (isset($UPDATES[$group->shortname])) { $shortname = $group->shortname; $updates = group_update($group); if (empty($updates)) { unset($UPDATES[$shortname]); } else { if (isset($updates['name'])) { $updates['displayname'] = $updates['name']; unset($updates['name']); } $UPDATES[$shortname] = $updates; log_debug('updated group ' . $group->name . ' (' . implode(', ', array_keys((array) $updates)) . ')'); } } } } db_commit(); $SESSION->add_ok_msg(get_string('csvfileprocessedsuccessfully', 'admin')); if ($UPDATES) { $updatemsg = smarty_core(); $updatemsg->assign('added', count($addedgroups)); $updatemsg->assign('updates', $UPDATES); $SESSION->add_info_msg($updatemsg->fetch('admin/groups/csvupdatemessage.tpl'), false); } else { $SESSION->add_ok_msg(get_string('numbernewgroupsadded', 'admin', count($addedgroups))); } set_progress_done('uploadgroupscsv'); redirect('/admin/groups/uploadcsv.php'); }
function bulkexport_submit(Pieform $form, $values) { global $SESSION; $usernames = array(); // Read in the usernames explicitly specified foreach (explode("\n", $values['usernames']) as $username) { $username = trim($username); if (!empty($username)) { $usernames[] = $username; } } if (empty($usernames) and !empty($values['authinstance'])) { // Export all users from the selected institution $rs = get_recordset_select('usr', 'authinstance = ? AND deleted = 0', array($values['authinstance']), '', 'username'); while ($record = $rs->FetchRow()) { $usernames[] = $record['username']; } } safe_require('export', 'leap'); $listing = array(); $files = array(); $exportcount = 0; $exporterrors = array(); $num_users = count($usernames); foreach ($usernames as $username) { if (!($exportcount % 25)) { set_progress_info('bulkexport', $exportcount, $num_users, get_string('validating', 'admin')); } $user = new User(); try { $user->find_by_username($username); } catch (AuthUnknownUserException $e) { continue; // Skip non-existent users } $exporter = new PluginExportLeap($user, PluginExport::EXPORT_ALL_VIEWS_COLLECTIONS, PluginExport::EXPORT_ALL_ARTEFACTS); try { $zipfile = $exporter->export(); } catch (Exception $e) { $exporterrors[] = $username; continue; } $listing[] = array($username, $zipfile); $files[] = $exporter->get('exportdir') . $zipfile; $exportcount++; } if (!($zipfile = create_zipfile($listing, $files))) { export_iframe_die(get_string('bulkexportempty', 'admin')); } log_info("Exported {$exportcount} users to {$zipfile}"); if (!empty($exporterrors)) { $SESSION->add_error_msg(get_string('couldnotexportusers', 'admin', implode(', ', $exporterrors))); } // Store the filename in the session, and redirect the iframe to it to trigger // the download. Here it would be nice to trigger the download for everyone, // but alas this is not possible for people without javascript. $SESSION->set('exportfile', $zipfile); set_progress_done('bulkexport', array('redirect' => get_config('wwwroot') . 'admin/users/bulkexport.php')); // Download the export file once it has been generated require_once 'file.php'; serve_file($zipfile, basename($zipfile), 'application/x-zip', array('lifetime' => 0, 'forcedownload' => true)); // TODO: delete the zipfile (and temporary files) once it's been downloaded }