From b435527321c8fae082f283260e64aeaee6c130f4 Mon Sep 17 00:00:00 2001 From: toyomoyo Date: Fri, 13 Jul 2007 08:06:30 +0000 Subject: [PATCH] MDL-9363, some fixes for grade import, not finished! --- grade/import/csv/index.php | 139 +++++++++++++++++++++-------- grade/import/grade_import_form.php | 44 +++++---- grade/import/lib.php | 84 ++++++++--------- 3 files changed, 168 insertions(+), 99 deletions(-) diff --git a/grade/import/csv/index.php b/grade/import/csv/index.php index 1ed05acc52e..146b9556ddb 100755 --- a/grade/import/csv/index.php +++ b/grade/import/csv/index.php @@ -1,10 +1,13 @@ libdir.'/gradelib.php'); + $id = required_param('id', PARAM_INT); // course id $course = get_record('course', 'id', $id); // actual course // capability check +require_login($id); require_capability('moodle/course:managegrades', get_context_instance(CONTEXT_COURSE, $course->id)); require_once('../grade_import_form.php'); @@ -29,25 +32,34 @@ $action = 'importcsv'; print_header($course->shortname.': '.get_string('grades'), $course->fullname, grade_nav($course, $action)); $mform = new grade_import_form(); - +//$mform2 = new grade_import_mapping_form(); //if ($formdata = $mform2->get_data() ) { // i am not able to get the mapping[] and map[] array using the following line // they are somehow not returned with get_data() -// if ($formdata = $mform2->get_data()) { if (($formdata = data_submitted()) && !empty($formdata->map)) { + + // temporary file name supplied by form + $filename = $CFG->dataroot.'/temp/'.clean_param($formdata->filename, PARAM_FILE); - // if mapping informatioin is supplied - - foreach ($formdata->maps as $i=>$header) { - // either "new" or existing ids, clean using alphanum - $map[clean_param($header, PARAM_RAW)] = clean_param($formdata->mapping[clean_param($i, PARAM_INT)], PARAM_ALPHANUM); + if ($fp = fopen($filename, "r")) { + // --- get header (field names) --- + $header = split($csv_delimiter, clean_param(fgets($fp,1024), PARAM_RAW)); + + foreach ($header as $i => $h) { + $h = trim($h); $header[$i] = $h; // remove whitespace + } + } else { + error ('could not open file '.$filename); + } + + // loops mapping_0, mapping_1 .. mapping_n and construct $map array + foreach ($header as $i=>$head) { + $map[$i] = $formdata->{'mapping_'.$i}; } + // if mapping informatioin is supplied $map[clean_param($formdata->mapfrom, PARAM_RAW)] = clean_param($formdata->mapto, PARAM_RAW); - // temporary file name supplied by form - $filename = $CFG->dataroot.'/temp/'.clean_param($formdata->filename, PARAM_FILE); - // 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. @@ -59,15 +71,14 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { // we only operate if file is readable if ($fp = fopen($filename, "r")) { - - // use current time stamp - $importcode = time(); - - // --- get header (field names) --- + + // read the first line makes sure this doesn't get read again $header = split($csv_delimiter, clean_param(fgets($fp,1024), PARAM_RAW)); - foreach ($header as $i => $h) { - $h = trim($h); $header[$i] = $h; // remove whitespace + // use current (non-conflicting) time stamp + $importcode = time(); + while (get_record('grade_import_values', 'import_code', $importcode)) { + $importcode = time(); } $newgradeitems = array(); // temporary array to keep track of what new headers are processed @@ -79,14 +90,31 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { // array to hold all grades to be inserted $newgrades = array(); - + // array to hold all feedback + $newfeedbacks = array(); // each line is a student record foreach ($line as $key => $value) { //decode encoded commas $value = clean_param($value, PARAM_RAW); $value = preg_replace($csv_encode,$csv_delimiter2,trim($value)); - switch ($map[$header[$key]]) { + /* + * the options are + * 1) userid, useridnumber, usermail, username - used to identify user row + * 2) new - new grade item + * 3) id - id of the old grade item to map onto + * 3) feedback_id - feedback for grade item id + */ + + $t = explode("_", $map[$key]); + $t0 = $t[0]; + if (isset($t[1])) { + $t1 = $t[1]; + } else { + $t1 = ''; + } + + switch ($t0) { case 'userid': // if (!$user = get_record('user','id', $value)) { // user not found, abort whold import @@ -145,45 +173,54 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { } unset($newgrade); $newgrade -> newgradeitem = $newgradeitems[$key]; - $newgrade -> rawgrade = $value; + $newgrade -> finalgrade = $value; $newgrades[] = $newgrade; // if not, put it in // else, insert grade into the table break; + case 'feeback': + if ($t1) { + // t1 is the id of the grade item + $feedback -> itemid = $t1; + $feedback -> feedback = $value; + $newfeedback[] = $feedback; + } + break; default: // existing grade items - if (!empty($map[$header[$key]])) { + if (!empty($map[$key]) && $value!=="") { // non numeric grade value supplied, possibly mapped wrong column - if (!is_numeric($value)) { - $status = false; + if (!is_numeric($value)) { + $status = false; import_cleanup($importcode); notify(get_string('badgrade', 'grades')); break 3; } - // case of an id, only maps idnumber of a grade_item + // case of an id, only maps id of a grade_item + // this was idnumber include_once($CFG->libdir.'/grade/grade_item.php'); - if (!$gradeitem = new grade_item(array('idnumber'=>$map[$header[$key]]))) { + if (!$gradeitem = new grade_item(array('id'=>$map[$key]))) { // supplied bad mapping, should not be possible since user // had to pick mapping $status = false; import_cleanup($importcode); notify(get_string('importfailed', 'grades')); break 3; - } - + } + unset($newgrade); $newgrade -> itemid = $gradeitem->id; - $newgrade -> rawgrade = $value; + $newgrade -> finalgrade = $value; $newgrades[] = $newgrade; } // otherwise, we ignore this column altogether // because user has chosen to ignore them (e.g. institution, address etc) break; } } - + // no user mapping supplied at all, or user mapping failed if (empty($studentid) || !is_numeric($studentid)) { // user not found, abort whold import @@ -192,9 +229,10 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { notify('user mapping error, could not find user!'); break; } - + // insert results of this students into buffer if (!empty($newgrades)) { + foreach ($newgrades as $newgrade) { $newgrade->import_code = $importcode; $newgrade->userid = $studentid; @@ -207,8 +245,24 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { } } } + + // updating/inserting all comments here + if (!empty($newfeedbacks)) { + foreach ($newfeedbacks as $newfeedback) { + if ($feedback = get_record('grade_import_values', 'importcode', $importcode, 'userid', $studentid, 'itemid', $newfeedback->itemid)) { + $newfeedback ->id = $feedback ->id; + update_record('grade_import_values', $newfeedback); + } else { + // the grade item for this is not updated + $newfeedback->import_code = $importcode; + $newfeedback->userid = $studentid; + insert_record('grade_import_values', $newfeedback); + } + } + } + } - + /// at this stage if things are all ok, we commit the changes from temp table if ($status) { grade_import_commit($course->id, $importcode); @@ -224,7 +278,6 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { $filename = $mform->get_userfile_name(); - // 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. @@ -266,20 +319,36 @@ if (($formdata = data_submitted()) && !empty($formdata->map)) { $lines = split($csv_delimiter, fgets($fp,1024)); echo ''; foreach ($lines as $line) { - echo ''.clean_param($line, PARAM_RAW).'';; + echo ''.$line.'';; } $numlines ++; echo ''; } echo ''; - + /// feeding gradeitems into the grade_import_mapping_form + include_once($CFG->libdir.'/grade/grade_item.php'); + $gradeitems = array(); + if ($id) { + if ($grade_items = grade_item::fetch_all(array('courseid'=>$id))) { + foreach ($grade_items as $grade_item) { + // skip course type and category type + if ($grade_item->itemtype == 'course' || $grade_item->itemtype == 'category') { + continue; + } + + // this was idnumber + $gradeitems[$grade_item->id] = $grade_item->itemname; + } + } + } // display the mapping form with header info processed - $mform2 = new grade_import_mapping_form(qualified_me(), array('id'=>$id, 'header'=>$header, 'filename'=>$filename)); + $mform2 = new grade_import_mapping_form(qualified_me(), array('gradeitems'=>$gradeitems, 'header'=>$header, 'filename'=>$filename)); $mform2->display(); } else { // display the standard upload file form $mform->display(); } + print_footer(); ?> \ No newline at end of file diff --git a/grade/import/grade_import_form.php b/grade/import/grade_import_form.php index 13314be619e..4ab0777e91d 100755 --- a/grade/import/grade_import_form.php +++ b/grade/import/grade_import_form.php @@ -45,14 +45,13 @@ class grade_import_mapping_form extends moodleform { // temporary filename $filename = $this->_customdata['filename']; // course id - $id = $this->_customdata['id']; $mform->addElement('header', 'general', get_string('identifier', 'grades')); $mapfromoptions = array(); if ($header) { - foreach ($header as $h) { - $mapfromoptions[$h] = $h; + foreach ($header as $i=>$h) { + $mapfromoptions[$i] = $h; } } $mform->addElement('select', 'mapfrom', get_string('mapfrom', 'grades'), $mapfromoptions); @@ -64,34 +63,33 @@ class grade_import_mapping_form extends moodleform { $mform->addElement('header', 'general', get_string('mappings', 'grades')); - $gradeitems = array(); - - include_once($CFG->libdir.'/gradelib.php'); - - if ($id) { - if ($grade_items = grade_item::fetch_all(array('courseid'=>$id))) { - foreach ($grade_items as $grade_item) { - $gradeitems[$grade_item->idnumber] = $grade_item->itemname; - } - } - } + $gradeitems = $this->_customdata['gradeitems']; - if ($header) { + include_once($CFG->libdir.'/gradelib.php'); + + if ($header) { + $i = 0; // index foreach ($header as $h) { - + $h = trim($h); // this is the order of the headers - $mform->addElement('hidden', 'maps[]', $h); - //echo ''; - // this is what they map to - - $mapfromoptions = array_merge(array('0'=>'ignore', 'new'=>'new gradeitem'), $gradeitems); - $mform->addElement('select', 'mapping[]', $h, $mapfromoptions); - //choose_from_menu($mapfromoptions, 'mapping[]', $h); + // $mform->addElement('hidden', 'maps[]', $h); + + // this is what they map to + $mapfromoptions = array('0'=>'ignore', 'new'=>'new gradeitem') + $gradeitems; + $mform->addElement('select', 'mapping_'.$i, s($h), $mapfromoptions); + $i++; } } + + // find a non-conflicting file name based on time stamp $newfilename = 'cvstemp_'.time(); + while (file_exists($CFG->dataroot.'/temp/'.$newfilename)) { + $newfilename = 'cvstemp_'.time(); + } + + // move the uploaded file move_uploaded_file($filename, $CFG->dataroot.'/temp/'.$newfilename); // course id needs to be passed for auth purposes diff --git a/grade/import/lib.php b/grade/import/lib.php index 50db97f2344..93ae6459cf0 100755 --- a/grade/import/lib.php +++ b/grade/import/lib.php @@ -12,7 +12,7 @@ function grade_import_commit($courseid, $importcode) { global $CFG; include_once($CFG->libdir.'/gradelib.php'); - + include_once($CFG->libdir.'/grade/grade_item.php'); $commitstart = time(); // start time in case we need to roll back $newitemids = array(); // array to hold new grade_item ids from grade_import_newitem table, mapping array @@ -28,20 +28,10 @@ function grade_import_commit($courseid, $importcode) { foreach ($newitems as $newitem) { // get all grades with this item - if ($grades = get_records('grade_import_values', 'newgradeitem', $newitem->id)) { - - $studentgrades = array(); + if ($grades = get_records('grade_import_values', 'newgradeitem', $newitem->id)) { + // make the grardes array for update_grade - foreach ($grades as $grade) { - - $g = new object(); - $g -> userid = $grade->userid; - $g -> rawgrade = $grade->rawgrade; - $studentgrades[] = $g ; - - } - $itemdetails -> itemname = $newitem->itemname; - + // find the max instance number of 'manual' grade item // and increment that number by 1 by hand // I can not find other ways to make 'manual' type work, @@ -60,18 +50,29 @@ function grade_import_commit($courseid, $importcode) { $instances[] = $instance; // if fails, deletes all the created grade_items and grades - - if (!grade_update('import', $courseid, 'manual', NULL, $instance, NULL, $studentgrades, $itemdetails) == GRADE_UPDATE_OK) { - // undo existings ones - include_once($CFG->libdir.'/grade/grade_item.php'); + + /// create a new grade item for this + $gradeitem = new grade_item(array('courseid'=>$courseid, 'itemtype'=>'manual', 'iteminstance'=>$instance, 'itemname'=>$newitem->itemname)); + $gradeitem->insert(); + + // insert each individual grade to this new grade item + $failed = 0; + foreach ($grades as $grade) { + if (!$gradeitem->update_final_grade($grade->userid, $grade->finalgrade, NULL, NULL, $grade->feedback)) { + $failed = 1; + break; + } + } + if ($failed) { foreach ($instances as $instance) { $gradeitem = new grade_item(array('courseid'=>$courseid, 'itemtype'=>'manual', 'iteminstance'=>$instance)); // this method does not seem to delete all the raw grades and the item itself // which I think should be deleted in this case, can I use sql directly here? $gradeitem->delete(); } - import_cleanup($importcode); - } + import_cleanup($importcode); + return false; + } } } } @@ -80,36 +81,37 @@ function grade_import_commit($courseid, $importcode) { if ($gradeitems = get_records_sql("SELECT DISTINCT (itemid) FROM {$CFG->prefix}grade_import_values - WHERE import_code = $importcode")) { + WHERE import_code = $importcode + AND itemid > 0")) { + $modifieditems = array(); - foreach ($gradeitems as $itemid) { + + foreach ($gradeitems as $itemid=>$iteminfo) { - if (!$gradeitem = get_record('grade_items', 'id', $itemid->itemid)) { - continue; // new items which are already processed + if (!$gradeitem = new grade_item(array('id'=>$itemid))) { + // not supposed to happen, but just in case + import_cleanup($importcode); + return false; } // get all grades with this item - if ($grades = get_records('grade_import_values', 'itemid', $itemid->itemid)) { + if ($grades = get_records('grade_import_values', 'itemid', $itemid)) { - $studentgrades = array(); // make the grardes array for update_grade foreach ($grades as $grade) { - - $g = new object(); - $g -> userid = $grade->userid; - $g -> rawgrade = $grade->rawgrade; - $studentgrades[] = $g ; + if (!$gradeitem->update_final_grade($grade->userid, $grade->finalgrade, NULL, NULL, $grade->feedback)) { + $failed = 1; + break 2; + } + } + //$itemdetails -> idnumber = $gradeitem->idnumber; + $modifieditems[] = $itemid; - } - //$itemdetails -> idnumber = $gradeitem->idnumber; + } - $modifieditems[] = $itemid; - - if (!grade_update('import', $courseid, $gradeitem->itemtype, $gradeitem->itemmodule, $gradeitem->iteminstance, $gradeitem->itemnumber, $studentgrades) == GRADE_UPDATE_OK) { - // here we could possibly roll back by using grade_history - // to compare timestamps? - import_cleanup($importcode); - } - } + if (!empty($failed)) { + import_cleanup($importcode); + return false; + } } }