Edit User Accounts page)
// N.B. Using user account search strings instead of IDs gives a performance hit with a large number of teachers
// I did not add Student enrolment, though this would be relatively trivial, as this is already
// handled by the far more elegant enrolment plugin system.
// Teachers are a sort of "course property", but Students are not.
// Rory Allford (rory@allford.net)
// 22nd June 2007 Mark Pearson (markp@earlham.edu)
// minor tweaks to increase size of category (from 30 - 50) and shortname (from 15 to 20)
// line 210 from (Category name "'.$item.'" length > 30) to (Category name "'.$item.'" length > 50)
// line 629 from 'shortname' => array(1,15,1) to 'shortname' => array(1,20,1)
// line 910 modify help to read shortname string(20)
// -----------------------------------------------------------------------------------------------------
// UPDATED BY: Austin Gooding & Cole Spicer
// UPDATE: Added compatability for newer versions of moodle as well as made future updates easier
// Just add new mdl_course column names to $optional and $validate arrays.
// DATE: 3/27/07
// -----------------------------------------------------------------------------------------------------
//error_reporting(E_ALL | E_STRICT );
// Some Regex constants
define('TOPIC_FIELD','/^(topic)([0-9]|[1-4][0-9]|5[0-2])$/');
define('TEACHER_FIELD','/^(teacher)([1-9]+\d*)(_account|_role)$/');
require_once('../config.php');
require_once("../course/lib.php");
require_once("$CFG->libdir/blocklib.php");
$courseid=-1;
function csverror($message, $link='') {
global $CFG, $SESSION;
print_header(get_string('error'));
echo '
';
$message = clean_text($message);
print_simple_box(''.$message.'', 'center', '', '#FFBBBB', 5, 'errorbox');
if (!$link) {
if ( !empty($SESSION->fromurl) ) {
$link = $SESSION->fromurl;
unset($SESSION->fromurl);
} else {
$link = $CFG->wwwroot .'/';
}
}
print_continue($link);
print_footer();
die;
}
function getdefaultcategory() {
static $mysqlresource1;
static $cat;
global $CFG;
global $USER;
($mysqlresource1=mysql_query('SELECT MIN(`id`) FROM `'.$CFG->prefix.'course_categories`')) or csverror('You have no category table!','uploadcourse.php?sesskey='.$USER->sesskey);
if (mysql_num_rows($mysqlresource1)) {
$cat = mysql_fetch_row($mysqlresource1);
return $cat[0];
} else {
return 1; // *SHOULD* be the Misc category?
}
}
function checkisint($supposedint) {
return ((string)intval($supposedint) == $supposedint) ? true : false;
}
function checkisstring($supposedstring) {
$supposedstring = trim($supposedstring); // Is it just spaces?
return (strlen($supposedstring) == 0) ? false : true;
}
function validateas($value, $validatename, $lineno, $fieldname = '') {
// Validates each field based on information in the $validate array
global $USER;
global $validate;
($fieldname=='') and ($fieldname=$validatename);
(isset($validate[$validatename])) or csverror('Coding Error: Unvalidated field type: "'.$validatename.'"','uploadcourse.php?sesskey='.$USER->sesskey);
$format = $validate[$validatename];
switch($format[0]) {
case 1: // String
if (($maxlen = $format[1])!=0) // Max length?
(strlen($value) <=$format[1]) or csverror('Invalid value for field '.$fieldname.' (length > '.$format[1].'). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
if ($format[2] == 1) // Not null?
checkisstring($value) or csverror('Invalid value for field '.$fieldname.' (only spaces or missing). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
break;
case 2: // Integer
checkisint($value) or csverror('Invalid value for field '.$fieldname.' (not an integer). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
if (($max = $format[1])!=0) // Max value?
($value <= $max) or csverror('Invalid value for field '.$fieldname.' (> '.$max.'). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
$min = $format[2]; // Min value
($value >= $min) or csverror('Invalid value for field '.$fieldname.' (< '.$min.'). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
break;
case 3: // Timestamp - validates and converts to Unix Time
if (($value = strtotime($value)) < 1)
csverror('Invalid value for field '.$fieldname.' (Bad Timestamp). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
break;
case 4: // Domain
$validvalues = explode(',',$format[1]);
if (array_search($value,$validvalues)===false)
csverror('Invalid value for field '.$fieldname.' (Must be one of {'.$format[1].'}). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
break;
case 5: // Category
if (checkisint($value)) {
// It's a Category ID Number
categoryexists_ex($value) or csverror('Invalid value for field '.$fieldname.' (No Category with ID '.$value.'). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
} elseif(checkisstring($value)) {
// It's a Category Path string
$value=trim(str_replace('\\','/',$value)," \t\n\r\0\x0B/");
// Clean path, ensuring all slashes are forward ones
(strlen($value)>0) or csverror('Invalid value for field '.$fieldname.' (Path string not set). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
unset ($cats);
$cats=explode('/',$value); // Break up path into array
(count($cats)>0) or csverror('Invalid value for field '.$fieldname.' (Path string "'.$value.'" invalid - not delimited correctly). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
foreach ($cats as $n => $item) { // Validate the path
$item=trim($item); // Remove whitespace
(strlen($item) <= 50) or csverror('Invalid value for field '.$fieldname.' (Category name "'.$item.'" length > 50). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
checkisstring($item) or csverror('Invalid value for field '.$fieldname.' (Path string "'.$value.'" invalid - category name at position '.($n+1).' as shown is invalid). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
}
$value=$cats; // Return the array
unset ($cats);
} else {
csverror('Invalid value for field '.$fieldname.' (not an integer or string). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
}
break;
case 6: // User ID or Name (Search String)
$value=trim($value);
if (checkisint($value)) { // User ID
userexists_ex($value) or csverror('Invalid value for field '.$fieldname.' (No User with ID '.$value.'). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
} elseif (checkisstring($value)) { // User Search String
// Only PHP5 supports named arguments
$usersearch=get_users_listing('lastaccess','ASC',0,99999,mysql_real_escape_string($value),'','');
if (isset($usersearch) and ($usersearch!==false) and is_array($usersearch) and (($ucount=count($usersearch))>0)) {
($ucount==1) or csverror('Invalid value for field '.$fieldname.' (Search string ambiguous; returned multiple ['.$ucount.'] results). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
reset($usersearch);
$uid=key($usersearch);
(checkisint($uid) && userexists_ex($uid)) or csverror('Invalid value for field '.$fieldname.' (Search string returned a nonexistent user ?!). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
$value=$uid; // Return found user id
} else {
csverror('Invalid value for field '.$fieldname.' (Search string returned no results). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
}
} else {
if ($format[2] == 1) // Not null?
csverror('Invalid value for field '.$fieldname.' (only spaces or missing). '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
}
break;
default:
csverror('Coding Error: Bad field validation type: "'.$fieldname.'"','uploadcourse.php?sesskey='.$USER->sesskey);
break;
}
return $value;
}
function categoryexists_ex($categoryid) {
// Does category with given id exist?
global $CFG;
static $mysqlresource1;
if ($mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'course_categories` WHERE `id`='.mysql_real_escape_string($categoryid))){
return mysql_num_rows($mysqlresource1) ? true : false;
} else {
return false;
}
}
function userexists_ex($userid) {
// Does category with given id exist?
global $CFG;
static $mysqlresource1;
if ($mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'user` WHERE `deleted` = 0 AND `id`='.mysql_real_escape_string($userid))){
return mysql_num_rows($mysqlresource1) ? true : false;
} else {
return false;
}
}
function microtime_float()
{
// In case we don't have php5
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function mystr($value)
{
// Prepare $value for inclusion in SQL Query
return '\''.mysql_real_escape_string($value).'\'';;
}
function fast_get_category_ex($hname, &$hstatus, $hparent=0)
{
// Find category with the given name and parentID, or create it, in both cases returning a category ID
/* $hstatus:
-1 : Failed to create category
1 : Existing category found
2 : Created new category successfully
*/
static $mysqlresource1;
static $mysqlresource2;
static $cat;
static $cname;
global $CFG;
global $USER;
$cname = mystr($hname);
// Check if a category with the same name and parent ID already exists
$mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'course_categories` WHERE `name` = '.$cname.' AND `parent` = '.$hparent);
if (mysql_num_rows($mysqlresource1)) {
$cat = mysql_fetch_row($mysqlresource1);
$hstatus=1;
return $cat[0];
} else {
// Create it - moodle does set sortorder to 999, and doesn't use the description field
if (!($mysqlresource2=mysql_query('INSERT INTO `'.$CFG->prefix.'course_categories` (`name`,`description`,`parent`,`sortorder`,`coursecount`,`visible`,`timemodified`) VALUES ('.$cname.',\'\','.$hparent.',999,0,1,0);'))) {
// Failed!
$hstatus=-1;
return -1;
} else {
$hstatus=2;
return mysql_insert_id();
}
}
}
function fast_is_course($hshortname) {
// Does a course with the given shortname exist?
global $CFG;
static $mysqlresource1;
static $cshortname;
$cshortname = mystr($hshortname);
if ($mysqlresource1=mysql_query('SELECT `id` FROM `'.$CFG->prefix.'course` WHERE `ShortName`='.$cshortname)) { // Check shortname is unique before inserting
if (mysql_num_rows($mysqlresource1)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
// Edited by Austin Gooding & Cole Spicer to fix problems with 1.7.1 and make easier to dynamically add new columns
function fastcreatecourse_ex($hcategory, $course, $header, $validate) {
if(!is_array($course) || !is_array($header) || !is_array($validate)) {
return -2;
}
global $CFG;
// declaring as static prevents object pointers being continually created and destroyed, saving time in theory
static $courseid;
static $mysqlresource1;
static $mysqlresource2;
static $mysqlresource3;
static $mysqlresource4;
static $dcomma; // Creating SQL for composite fields
static $dtopics;
static $dtopicno;
static $dtopicname;
static $dteachers;
static $dteacherno;
static $dteacherdata;
// Dynamically Create Query Based on number of headings excluding Teacher[1,2,...] and Topic[1,2,...]
// Added for increased functionality with newer versions of moodle
// Author: Austin Gooding & Cole Spicer
static $tempstring;
$query = 'INSERT INTO `'.$CFG->prefix.'course` (`category`,';
foreach ($header as $i => $col) {
$col = strtolower($col);
if(preg_match(TOPIC_FIELD, $col) || preg_match(TEACHER_FIELD, $col) || $col == 'category') {
continue;
}
$query = $query.'`'.$col.'`,';
}
$query = $query.'`modinfo`) VALUES ('.$hcategory.',';
foreach ($header as $i => $col) {
$col = strtolower($col);
if(preg_match(TOPIC_FIELD, $col) || preg_match(TEACHER_FIELD, $col) || $col == 'category') {
continue;
}
if($col == 'expirythreshold') {
$course[$col] = $course[$col]*86400;
}
$temparray = explode(',',$validate[$col][1]);
if($validate[$col][0] == 1 || ($validate[$col][0] == 4 && !checkisint($temparray[0]) ) ) { //String or Domain with strings
$query = $query.''.mystr($course[$col]).', ';
}
else {
$query = $query.''.$course[$col].', ';
}
}
$query = $query.' \'\');';
// End Dynamic Query
if (!($mysqlresource2=mysql_query($query))) {
return -2;
}
$courseid=mysql_insert_id();
$page = page_create_object(PAGE_COURSE_VIEW, $courseid);
blocks_repopulate_page($page); // Setup blocks
$dtopics=''; // String concatenation for topic INSERT
$dcomma=false; // Should we add a comma before the next item?
if (isset($course['topics'])) { // Any topic headings specified ?
foreach($course['topics'] as $dtopicno => $dtopicname)
if ($dtopicno <= $course['numsections']) { // Avoid overflowing topic headings
if ($dcomma==true) {
$dtopics.=',';
} else {
$dcomma=true;
}
$dtopics.='('.$courseid.','.mystr($dtopicno).','.mystr($dtopicname).',\'\',\'1\')';
}
}
if (!isset($course['topics'][0])) {
// Ensure at least default topic section exists
if ($dcomma==true) {
$dtopics.=',';
} else {
$dcomma=true;
}
$dtopics.='(\''.$courseid.'\',\'0\',\'\',\'\',\'1\');';
} else {
$dtopics.=';';
}
if (!($mysqlresource3=mysql_query('INSERT INTO `'.$CFG->prefix.'course_sections` (`course`,`section`,`summary`,`sequence`,`visible`) VALUES '.$dtopics)))
return -3;
$dteachers=''; // String concatenation for topic INSERT
$dcomma=false; // Should we add a comma before the next item?
// SELECT id FROM mdl_role WHERE name = blah
// use that id and change insert to:
// mdl_role_assignments
// roleid contextid userid timemodified modifierid enrol
// courseshit 0 'manual'
// If SELECT id... doesnt work (returns false or contians no items) then throw error
$roleid;
if (!$context = get_context_instance(CONTEXT_COURSE, $courseid)) {
return -6;
}
if (isset($course['teachers_enrol']) && (count($course['teachers_enrol'])>0)) { // Any teachers specified?
foreach($course['teachers_enrol'] as $dteacherno => $dteacherdata) {
if (isset($dteacherdata['_account'])) {
if ($dcomma==true) {
$dteachers.=',';
} else {
$dcomma=true;
}
if(!($mysqlresource5 = mysql_query('SELECT `id` FROM `'.$CFG->prefix.'role` WHERE `shortname`=\''.$dteacherdata['_role'].'\';')) ) {
return -5;
}
if(!mysql_num_rows($mysqlresource5)) {
return -5;
}
$row = mysql_fetch_row($mysqlresource5);
$dteachers.='('.$row[0].','.$context->id.','.$dteacherdata['_account'].','.$course['timecreated'].',0,\'manual\');';
}
}
if ($dteachers!='') {
if (!($mysqlresource4=mysql_query('INSERT INTO `'.$CFG->prefix.'role_assignments` (`roleid`,`contextid`,`userid`,`timemodified`,`modifierid`,`enrol`) VALUES '.$dteachers)))
return -4;
}
}
return 1;
}
require_login();
if (!isadmin()) {
csverror('You must be an administrator to edit courses in this way.');
}
/* if (!confirm_sesskey()) {
csverror(get_string('confirmsesskeybad', 'error'));
} */
if (! $site = get_site()) {
csverror('Could not find site-level course');
}
if (!$adminuser = get_admin()) {
csverror('Could not find site admin');
}
set_time_limit(300); // Up the php timeout
$time_start = microtime_float(); // Just for timing
$stradministration = get_string('administration');
$strchoose = get_string('choose');
$struploadcourses = 'Upload Courses';
$csv_encode = '/\&\#44/';
if (isset($CFG->CSV_DELIMITER)) {
$csv_delimiter = '\\' . $CFG->CSV_DELIMITER;
$csv_delimiter2 = $CFG->CSV_DELIMITER;
if (isset($CFG->CSV_ENCODE)) {
$csv_encode = '/\&\#' . $CFG->CSV_ENCODE . '/';
}
} else {
$csv_delimiter = '\,';
$csv_delimiter2 = ',';
}
/// Print the header
print_header("$site->shortname: $struploadcourses", $site->fullname,
"$stradministration -> $struploadcourses");
/// If a file has been uploaded, then process it
require_once($CFG->dirroot.'/lib/uploadlib.php');
$um = new upload_manager('coursefile',false,false,null,false,0);
if ($um->preprocess_files()) {
if (!isset($um->files['coursefile']))
csverror('Upload Error!', 'uploadcourse.php?sesskey='.$USER->sesskey);
$filename = $um->files['coursefile']['tmp_name'];
// Everything to Unix Line Endings
$text = my_file_get_contents($filename);
$text = preg_replace('!\r\n?!',"\n",$text);
if ($fp = fopen($filename, "w")) {
fwrite($fp,$text);
unset($text); // Memory!
fclose($fp);
} else {
csverror('File I/O Error! (1)', 'uploadcourse.php?sesskey='.$USER->sesskey);
}
if (!$fp = fopen($filename, "r")) {
csverror('File I/O Error! (2)', 'uploadcourse.php?sesskey='.$USER->sesskey);
}
// make arrays of fields for error checking
$defaultcategory = getdefaultcategory();
$defaultmtime = time();
$required = array( 'fullname' => false, // Mandatory fields
'shortname' => false);
$optional = array( 'category' => $defaultcategory, // Default values for optional fields
'sortorder' => 0,
'summary' => 'Write a concise and interesting paragraph here that explains what this course is about',
'format' => 'weeks',
'showgrades' => 0,
'newsitems' => 5,
'teacher' => 'Teacher',
'teachers' => 'Teachers',
'student' => 'Student',
'students' => 'Students',
'startdate' => $defaultmtime,
'numsections' => 16,
'maxbytes' => 2097152,
'visible' => 1,
'groupmode' => 0,
'timecreated' => $defaultmtime,
'timemodified' => $defaultmtime,
'idnumber' => '',
'password' => '',
'enrolperiod' => 0,
'groupmodeforce' => 0,
'metacourse' => 0,
'lang' => '',
'theme' => '',
'cost' => '',
'showreports' => 0,
'guest' => 0,
'enrollable' => 1,
'enrolstartdate' => $defaultmtime,
'enrolenddate' => $defaultmtime,
'notifystudents' => 0,
'expirynotify' => 0,
'expirythreshold' => 10);
$validate = array( 'fullname' => array(1,254,1), // Validation information - see validateas function
'shortname' => array(1,20,1),
'category' => array(5),
'sortorder' => array(2,4294967295,0),
'summary' => array(1,0,0),
'format' => array(4,'social,topics,weeks'),
'showgrades' => array(4,'0,1'),
'newsitems' => array(2,10,0),
'teacher' => array(1,100,1),
'teachers' => array(1,100,1),
'student' => array(1,100,1),
'students' => array(1,100,1),
'startdate' => array(3),
'numsections' => array(2,52,0),
'maxbytes' => array(2,$CFG->maxbytes,0),
'visible' => array(4,'0,1'),
'groupmode' => array(4,NOGROUPS.','.SEPARATEGROUPS.','.VISIBLEGROUPS),
'timecreated' => array(3),
'timemodified' => array(3),
'idnumber' => array(1,100,0),
'password' => array(1,50,0),
'enrolperiod' => array(2,4294967295,0),
'groupmodeforce' => array(4,'0,1'),
'metacourse' => array(4,'0,1'),
'lang' => array(1,50,0),
'theme' => array(1,50,0),
'cost' => array(1,10,0),
'showreports' => array(4,'0,1'),
'guest' => array(4,'0,1,2'),
'enrollable' => array(4,'0,1'),
'enrolstartdate' => array(3),
'enrolenddate' => array(3),
'notifystudents' => array(4,'0,1'),
'expirynotify' => array(4,'0,1'),
'expirythreshold' => array(2,30,1), // Following ones cater for [something]N
'topic' => array(1,0,0),
'teacher_account' => array(6,0),
'teacher_role' => array(1,40,0));
$header = fgetcsv($fp, 1024);
// check for valid field names
if (($header[0]==null)&&(count($line)<1)) // Blank Line?
csverror('First line must be the CSV header', 'uploadcourse.php?sesskey='.$USER->sesskey);
foreach ($header as $i => $h) {
if ($h==null)
csverror('Null CSV columns are not permitted in header', 'uploadcourse.php?sesskey='.$USER->sesskey);
if (preg_match(TOPIC_FIELD,$h)) { // Regex defined header names
} elseif (preg_match(TEACHER_FIELD,$h)) {
} else {
if (!(isset($required[$h]) || isset($optional[$h])))
csverror(get_string('invalidfieldname', 'error', $h), 'uploadcourse.php?sesskey='.$USER->sesskey);
if (isset($required[$h])) $required[$h] = true; // Mark Field as present
}
}
// check for required fields
foreach ($required as $key => $value) {
if ($value != true)
csverror(get_string('fieldrequired', 'error', $key), 'uploadcourse.php?sesskey='.$USER->sesskey);
}
$fieldcount = count($header);
$lineno=2;
unset($bulkcourses);
while (($line = fgetcsv($fp, 1024)) !== false) {
if (($line[0]!=null)||(count($line)>1)) { // Blank Line?
if (count($line) > $fieldcount)
csverror('Too many actual values. '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
foreach ($header as $i => $h) {
// Is line complete?
if (!isset($line[$i])) {
csverror(get_string('missingfield', 'error', $h). ". ".
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
}
}
unset($coursetocreate);
unset($coursetopics);
unset($courseteachers);
foreach ($optional as $key => $value) { // Set course array to defaults
$coursetocreate[$key] = $value;
}
foreach ($line as $key => $value) { // Validate each value
$cf = $header[$key];
if (preg_match(TOPIC_FIELD,$cf,$matches)) {
$coursetopics[$matches[2]] = validateas($value,$matches[1], $lineno, $cf);
} elseif (preg_match(TEACHER_FIELD,$cf,$matches)) {
$tmp=validateas($value,$matches[1].$matches[3], $lineno, $cf);
(isset($tmp)&&($tmp!='')) and
($courseteachers[$matches[2]][$matches[3]] = $tmp);
} else {
$coursetocreate[$cf] = validateas($value, $cf, $lineno); // Accept value if it passed validation
}
}
$coursetocreate['topics'] = $coursetopics;
if (isset($courseteachers))
foreach ($courseteachers as $key => $value) // Deep validate course teacher info on second pass
{
if (isset($value) && (count($value) > 0)){
if (!(isset($value['_account'])&&checkisint($value['_account'])))
csverror('Invalid value for field teacher'.$key.' - other fields were specified but required teacher'.$key.'_account was null. '.
get_string('erroronline', 'error', $lineno) .". ".
get_string('processingstops', 'error'),
'uploadcourse.php?sesskey='.$USER->sesskey);
// Hardcoded default values (that are as close to moodle's UI as possible)
// and we can't assume PHP5 so no pointers!
if (!isset($value['_role']))
$courseteachers[$key]['_role'] = '';
}
}
$coursetocreate['teachers_enrol'] = $courseteachers;
$bulkcourses[] = $coursetocreate; // Merge into array
}
$lineno++;
}
fclose($fp);
if ((!isset($bulkcourses)) or (count($bulkcourses)==0))
csverror('No courses were parsed from CSV', 'uploadcourse.php?sesskey='.$USER->sesskey);
else
notify('Parsed '.count($bulkcourses).' course(s) from CSV','notifysuccess');
// Running Status Totals
$t = 0; // Read courses
$s = 0; // Skipped courses
$n = 0; // Created courses
$p = 0; // Broken courses (failed halfway through
$cat_e = 0; // Errored categories
$cat_c = 0; // Created categories
foreach ($bulkcourses as $bulkcourse) {
// Try to create the course
if (!fast_is_course($bulkcourse['shortname'])) {
$coursetocategory = 0; // Category ID
if (is_array($bulkcourse['category'])) {
// Course Category creation routine as a category path was given
$curparent=0;
$curstatus=0;
foreach ($bulkcourse['category'] as $catindex => $catname) {
$curparent = fast_get_category_ex($catname,$curstatus,$curparent);
switch ($curstatus) {
case 1: // Skipped the category, already exists
break;
case 2: // Created a category
$cat_c++;
break;
default:
$cat_e+=count($bulkcourse['category']) - $catindex;
$coursetocategory=-1;
notify('An error occured creating category with name '.$catname.', meaning a total '.(count($bulkcourse['category']) - $catindex).' category(ies) failed','notifyproblem');
break 2;
}
}
($coursetocategory==-1) or $coursetocategory = $curparent;
// Last category created will contain the actual course
} else {
// It's just a straight category ID
$coursetocategory=$bulkcourse['category'];
}
if ($coursetocategory==-1) {
notify('Course with ShortName '.$bulkcourse['shortname'].' could not be created because parent category(ies) failed','notifyproblem');
} else {
//switch (fastcreatecourse_ex($coursetocategory, $bulkcourse['sortorder'], $bulkcourse['fullname'], $bulkcourse['shortname'], $bulkcourse['summary'], $bulkcourse['format'], $bulkcourse['showgrades'], $bulkcourse['newsitems'], $bulkcourse['teacher'], $bulkcourse['teachers'], $bulkcourse['student'], $bulkcourse['students'], $bulkcourse['startdate'], $bulkcourse['numsections'], $bulkcourse['maxbytes'], $bulkcourse['visible'], $bulkcourse['groupmode'], $bulkcourse['timecreated'], $bulkcourse['timemodified'], $bulkcourse['idnumber'], $bulkcourse['password'], $bulkcourse['enrolperiod'], $bulkcourse['groupmodeforce'], $bulkcourse['metacourse'], $bulkcourse['lang'], $bulkcourse['theme'], $bulkcourse['cost'], $bulkcourse['showreports'], $bulkcourse['guest'], $bulkcourse['enrollable'], $bulkcourse['enrolstartdate'], $bulkcourse['enrolenddate'], $bulkcourse['notifystudents'], $bulkcourse['expirynotify'], $bulkcourse['expirythreshold'], $bulkcourse, $header, $validate, $bulkcourse['topics'], $bulkcourse['teachers_enrol'])) {
switch (fastcreatecourse_ex($coursetocategory, $bulkcourse, $header, $validate)) {
case 1:
$n++; // Succeeded
break;
case -3:
notify('Could not create topic sections for course with ShortName '.$bulkcourse['shortname'],'notifyproblem');
$p++;
break;
case -4:
notify('Could not enrol teachers for course with ShortName '.$bulkcourse['shortname'],'notifyproblem');
$p++;
break;
case -5:
notify('Could not find teacher role for course with ShortName '.$bulkcourse['shortname'],'notifyproblem');
$p++;
break;
case -6:
notify('Could not enrol teacher for course due to course misconfiguration. Course ShortName: '.$bulkcourse['shortname'],'notifyproblem');
$p++;
break;
default:
notify('An Error occured creating course with ShortName '.$bulkcourse['shortname'],'notifyproblem');
break;
}
}
} else {
// Skip course, already exists
$s++;
}
$t++;
}
notify('Created '.$n.' course(s) out of '.$t,'notifysuccess');
if ($s > 0)
notify ($s.' course(s) were skipped (duplicate ShortName)','notifysuccess');
if ($p > 0)
notify ($p.' course(s) could not be fully created, due to errors. Though they make work, it is advisable to delete them and try again.','notifyproblem');
if (($e = $t - $n - $s - $p) > 0)
notify ($e.' course(s) failed due to errors','notifyproblem');
if ($cat_e > 0)
notify ($cat_e.' new category(ies) failed due to errors','notifyproblem');
if ($cat_c > 0) {
notify ($cat_c.' new category(ies) were created','notifysuccess');
notify ('You may wish to manually Re-Sort the categories','notifysuccess');
// We don't automatically sort alphabetically, as the somewhat clunky category sorting
// method used by moodle could annoy the user
}
fix_course_sortorder(); // Re-sort courses
notify('Re-Sorted courses','notifysuccess');
// We potentially did a lot to the Database: avoid tempting fate
if (mysql_query('ANALYZE TABLE `'.$CFG->prefix.'course`') && mysql_query('ANALYZE TABLE `'.$CFG->prefix.'course_categories`') && mysql_query('ANALYZE TABLE `'.$CFG->prefix.'course_sections`') && mysql_query('ANALYZE TABLE `'.$CFG->prefix.'user_teachers`'))
notify('ANALYZE Database Tables OK','notifysuccess');
else
notify('Could not ANALYZE Database Tables (`'.$CFG->prefix.'course`, `'.$CFG->prefix.'course_categories`, `'.$CFG->prefix.'course_sections` and `'.$CFG->prefix.'user_teachers`) - You should do this manually','notifyproblem');
if (mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'course`') && mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'course_categories`') && mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'course_sections`') && mysql_query('OPTIMIZE TABLE `'.$CFG->prefix.'user_teachers`'))
notify('OPTIMIZE Database Tables OK','notifysuccess');
else
notify('Could not OPTIMIZE Database Tables (`'.$CFG->prefix.'course`, `'.$CFG->prefix.'course_categories`, `'.$CFG->prefix.'course_sections` and `'.$CFG->prefix.'user_teachers`) - You should do this manually','notifyproblem');
$time_end = microtime_float();
notify('Total Execution Time: '.round(($time_end - $time_start),2).' s','notifysuccess');
echo '
Upload an RFC4180-Compliant CSV file.
Valid fields for each course are:
| Field | Value |
|---|---|
| category | [Forward]Slash-Delimited Category "Path" String (new categories are created as necessary) OR Integer Database Category ID |
| cost | String(10) |
| enrolperiod | Integer/Seconds |
| enrollable | 0=FALSE,1=TRUE |
| enrolstartdate | String Date Literal |
| enrolenddate | String Date Literal |
| expirynotify | 0=FALSE,1=TRUE |
| expirythreshold | Integer Value Between 1-30 |
| format | String('social','topics','weeks') |
| fullname | String(254) |
| groupmode | 0=NOGROUPS,1=SEPARATEGROUPS,2=VISIBLEGROUPS |
| groupmodeforce | 0=FALSE,1=TRUE |
| guest | 0=NO,1=YES,2=WITHKEY |
| idnumber | String(100) |
| lang | String(10) |
| maxbytes | Integer(Site Max) |
| metacourse | 0=FALSE,1=TRUE |
| newsitems | Integer(10) |
| notifystudents | 0=FALSE,1=TRUE |
| numsections | Integer(52) |
| password | String(50) |
| shortname | String(20) |
| showgrades | 0=FALSE,1=TRUE |
| showreports | 0=FALSE,1=TRUE |
| sortorder | Integer |
| startdate | String Date Literal |
| student | String(100) |
| students | String(100) |
| summary | Text |
| teacher | String(100) |
| teachers | String(100) |
| teacher[1,2,...]_account | Search String that returns only one User Account (as used in Administration » Edit user accounts OR Integer Database User ID |
| teacher[1,2,...]_role | String(40) |
| theme | String(50) |
| timecreated | String Date Literal |
| timemodified | String Date Literal |
| topic0 [main heading], topic1 ... topic52 [topic/week headings] | Text |
| visible | 0=FALSE,1=TRUE |