diff --git a/lib.php b/lib.php index 289100a..d1144b6 100644 --- a/lib.php +++ b/lib.php @@ -4,33 +4,35 @@ // debug switch defined in locallib.php define('WWASSIGNMENT_DEBUG',0); -//////////////////////////////////////////////////////////////// -// External grade triggers -// wwassignment_update_grades(wwassignment,userid=0) is called from -// grade_update_mod_grades in gradlib.php and also from wwassignment/upgrade.php file -// grade_update_mod_grades is called by $grade_item->refresh_grades -// -// wwassignment_grade_item_update(wwassignment) -// is called from grade_update_mod_grades (before update_grades(wwassignment,userid=0))) -// -// wwassignment_get_user_grades -// could be called from wwassignment/index.php pages (legacy??) -// -// High level grade calls in gradelib.php (see end of file) -// -// +/** ///////////////////////////////////////////////////////////// +* External grade triggers +* 1. wwassignment_update_grades(wwassignment,userid=0) is called from +* grade_update_mod_grades in gradlib.php and also from wwassignment/upgrade.php file +* grade_update_mod_grades is called by $grade_item->refresh_grades +* * handles updating the actual grades +* 2. wwassignment_grade_item_update(wwassignment) +* is called from grade_update_mod_grades (before update_grades(wwassignment,userid=0))) +* * updates the items (e.g. homework sets) that are graded +* +* High level grade calls are in gradelib.php (see end of file) +*/ // + // Internal grade calling structure // -// wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=true) -- updates grades for assignment instance or all instances -// wwassignment_get_user_grades($wwassignment,$userid=0) -- fetches homework grades from WeBWorK -// _wwassignment_get_course_students($courseid) -- collects users from moodle database -// $wwclient->grade_users_sets($webworkcourse,$webworkusers,$webworkset) -- fetches grades from a given course, set and user collection -// wwassignment_grade_item_update(wwassignment, grades) +// 1. wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=true) +// -- updates grades for assignment instance or all instances +// * wwassignment_get_user_grades($wwassignment,$userid=0) +// -- fetches homework grades from WeBWorK +// * _wwassignment_get_course_students($courseid) -- collects users from moodle database +// * $wwclient->grade_users_sets($webworkcourse,$webworkusers,$webworkset) +// -- fetches grades from a given course, set and user collection +// 2. wwassignment_grade_item_update(wwassignment, grades) // grade_update(...) -- fills record in grade_item table and possibly in grade_grades table as well // -// wwassignment_update_grade_item(wwassignment) -- just updates grade_item table -// wwassignment_update_grade_item(wwassignment, grades) updates grade_item table and grade_grades table +//////////////////////////////////////////////////////////////// +// This functino is defined in gradeslib.php -- I believe +// function grade_update($source, $courseid, $itemtype, $itemmodule, $iteminstance, $itemnumber, $grades=NULL, $itemdetails=NULL) { //////////////////////////////////////////////////////////////// @@ -52,8 +54,7 @@ function wwassignment_install() { */ function wwassignment_add_instance($wwassignment) { global $COURSE,$DB; - - debugLog("Begin wwassignment_add_instance"); + traceLog("-----------Begin wwassignment_add_instance-----------"); debugLog("input wwassignment "); //debugLog( print_r($wwassignment, true) ); @@ -78,7 +79,7 @@ function wwassignment_add_instance($wwassignment) { //notify gradebook wwassignment_grade_item_update($wwassignment); } - debugLog("End wwassignment_add_instance"); + traceLog("----------End wwassignment_add_instance------------"); return $returnid; } @@ -91,7 +92,7 @@ function wwassignment_add_instance($wwassignment) { function wwassignment_update_instance($wwassignment) { global $COURSE,$DB; require_once("locallib.php"); - debugLog("Begin wwassignment_update_instance"); + traceLog("---------Begin wwassignment_update_instance---------"); //checking mappings @@ -115,7 +116,7 @@ function wwassignment_update_instance($wwassignment) { //notify gradebook -- update grades for this wwassignment only wwassignment_grade_item_update($wwassignment); wwassignment_update_grades($wwassignment); - debugLog("End wwassignment_update_instance"); + traceLog("-------End wwassignment_update_instance---------"); return $returnid; } @@ -125,12 +126,10 @@ function wwassignment_update_instance($wwassignment) { * @param integer $wwassignmentid The id of the assignment to delete. * @return bool Delete was successful or not. */ -function wwassignment_delete_instance($wwassignmentid) { - +function wwassignment_delete_instance($wwassignmentid) { global $DB; - - debugLog("Begin wwassignment_delete_instance -- input wwassignmentid:"); - debugLog(print_r($wwassignmentid,true)); + traceLog("---------- Begin wwassignment_delete_instance -------------"); + debugLog("input wwassignmentid:".print_r($wwassignmentid,true)); $result = true; #delete DB record @@ -160,33 +159,32 @@ function wwassignment_delete_instance($wwassignmentid) { //notify gradebook wwassignment_grade_item_delete($wwassignment); - debugLog("End wwassignment_delete_instance -- input wwassignmentid:"); - + traceLog("------- End wwassignment_delete_instance --------"); return $result; } - /** gradebook upgrades +/** gradebook upgrades * add xxx_update_grades() function into mod/xxx/lib.php -� � * add xxx_grade_item_update() function into mod/xxx/lib.php -� � * patch xxx_update_instance(), xxx_insert_instance()? xxx_add_instance() and xxx_delete_instance() to call xxx_grade_item_update() -� � * patch all places of code that change grade values to call xxx_update_grades() -� � * patch code that displays grades to students to use final grades from the gradebook� - **/ + * add xxx_grade_item_update() function into mod/xxx/lib.php + * patch xxx_update_instance(), xxx_insert_instance()? xxx_add_instance() and xxx_delete_instance() to call xxx_grade_item_update() + * patch all places of code that change grade values to call xxx_update_grades() + * patch code that displays grades to students to use final grades from the gradebook� +**/ /** - * Return grade for given user or all users. + * Return, for a given homework assignment, the grade for a single user or for all users. * * @param int $assignmentid id of assignment * @param int $userid optional user id, 0 means all users - * @return array array of grades, false if none + * @return a hash of studentid=>grade values , false if none */ function wwassignment_get_user_grades($wwassignment,$userid=0) { - debugLog("Begin wwassignment_get_user_grades"); - //debugLog("inputs -- wwassignment" . print_r($wwassignment,true)); - //debugLog("userid = $userid"); + traceLog("------Begin wwassignment_get_user_grades -- fetch grades from WW -----"); + debugLog("inputs -- wwassignment" . print_r($wwassignment,true)); + debugLog("userid = $userid"); require_once("locallib.php"); @@ -209,19 +207,24 @@ function wwassignment_get_user_grades($wwassignment,$userid=0) { array_push($usernamearray,$student->username); } } + // get data from WeBWorK + debugLog("fetch grades from course: $wwcoursename set: $wwsetname"); + $gradearray = $wwclient->grade_users_sets($wwcoursename,$usernamearray,$wwsetname); - $gradearray = $wwclient->grade_users_sets($wwcoursename,$usernamearray,$wwsetname); // FIXME? return key/value pairs instead? // returns an array of grades -- the number of questions answered correctly? // debugLog("usernamearray " . print_r($usernamearray, true)); // debugLog("grades($wwcoursename,usernamearray,$wwsetname) = " . print_r($gradearray, true)); // model for output of grades + // FIXME? return key/value pairs instead? in grade_users_sets? + // this next segment matches students and their grades by dead reckoning + $i =0; foreach($students as $student) { $studentid = $student->id; $grade = new stdClass(); $grade->userid = $studentid; - $grade->rawgrade = (is_numeric($gradearray[$i])) ? $gradearray[$i] : ''; + $grade->rawgrade = (is_numeric($gradearray[$i])) ? $gradearray[$i] : ''; $grade->feedback = "some text"; $grade->feedbackformat = 0; $grade->usermodified = 0; @@ -235,20 +238,21 @@ function wwassignment_get_user_grades($wwassignment,$userid=0) { // end model - //debugLog("output student grades:" . print_r($studentgrades,true) ); - debugLog("End wwassignment_get_user_grades"); + debugLog("output student grades:" . print_r($studentgrades,true) ); + traceLog("---------End wwassignment_get_user_grades---------"); return $studentgrades; } /** + * This can be called from outside wwassignment * Update grades by firing grade_updated event * - * @param object $wwassignment object with extra cmidnumber ?? + * @param object $wwassignment object with extra cmidnumber ?? * @param object $wwassignment null means all wwassignments * @param int $userid specific user only, 0 mean all - */ +**/ function wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=true) { - debugLog("Begin wwassignment_update_grades"); + traceLog("------- Begin wwassignment_update_grades---------"); //debugLog("inputs wwassignment = " . print_r($wwassignment,true)); debugLog("userid = $userid"); global $CFG, $DB; @@ -265,6 +269,7 @@ function wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=t if ($grades = wwassignment_get_user_grades($wwassignment, $userid)) { # fetches all students if userid=0 foreach($grades as $k=>$v) { + // doctor grades with a negative one if ($v->rawgrade == -1) { $grades[$k]->rawgrade = null; } @@ -274,7 +279,7 @@ function wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=t wwassignment_grade_item_update($wwassignment); } - } else { // find all the assignments + } else { // find all the wwassignments in all courses and update all of them. debugLog("import grades for all wwassignments for all courses"); $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid FROM {wwassignment} a, {course_modules} cm, {modules} m @@ -302,7 +307,7 @@ function wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=t } } - debugLog("End wwassignment_update_grades"); + traceLog("--------End wwassignment_update_grades--------"); } /** @@ -310,9 +315,20 @@ function wwassignment_update_grades($wwassignment=null, $userid=0, $nullifnone=t * * @param object $wwassignment object with extra cmidnumber * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook + * side effect: uses contents of grades to change the values in the gradebook. + * grades contains gradeitem objects containing all of the necessary information + * $grade->userid = $studentid; + * $grade->rawgrade = (is_numeric($gradearray[$i])) ? $gradearray[$i] : ''; + * $grade->feedback = "some text"; + * $grade->feedbackformat = 0; + * $grade->usermodified = 0; + * $grade->dategraded = 0; + * $grade->datesubmitted = 0; + * $grade->id = $studentid; * @return int 0 if ok, error code otherwise - */ +**/ function wwassignment_grade_item_update ($wwassignment, $grades=NULL) { + traceLog("------- Begin wwassignment_grade_item_update ------- "); $msg = "Begin wwassignment_grade_item_update"; $msg = ($grades)? $msg . " with grades (updates grade_grades table)" :$msg; debugLog($msg); @@ -332,7 +348,7 @@ function wwassignment_grade_item_update ($wwassignment, $grades=NULL) { $wwsetname = _wwassignment_mapped_set($wwassignment->id,false); $wwassignment->grade = $wwclient->get_max_grade($wwcoursename,$wwsetname,false); } - // set grade in wwassignment + // set maximum grade in wwassignment record as "grade" for the homework set. $params = array('itemname'=>$wwassignment->name, 'idnumber'=>$wwassignment->cmidnumber); @@ -353,10 +369,14 @@ function wwassignment_grade_item_update ($wwassignment, $grades=NULL) { $params['reset'] = true; $grades = NULL; } - # grade_update() defined in gradelib.php - # $grades=NULL means update grade_item table only, otherwise post grades in grade_grades - // error_log("update grades for courseid: ". $wwassignment->courseid . " assignment id: ".$wwassignment->id." time modified ".$wwassignment->timemodified); - return grade_update('mod/wwassignment', $wwassignment->courseid, 'mod', 'wwassignment', $wwassignment->id, 0, $grades, $params); + // grade_update() defined in gradelib.php + // $grades=NULL means update grade_item table only, otherwise post grades in grade_grades + debugLog("wwassignment_grade_item_update: update grades for courseid: ". $wwassignment->courseid . + " assignment id: ".$wwassignment->id." time modified ". + $wwassignment->timemodified."grades".print_r($grades,true)); + traceLog("------- end wwassignment_grade_item_update ------- "); + return grade_update('mod/wwassignment', $wwassignment->courseid, 'mod', 'wwassignment', + $wwassignment->id, 0, $grades, $params); } /** * Delete grade item for given assignment @@ -365,7 +385,7 @@ function wwassignment_grade_item_update ($wwassignment, $grades=NULL) { * @return object wwassignment ???? */ function wwassignment_grade_item_delete($wwassignment) { - debugLog("Begin wwassignment_grade_item_delete"); + traceLog("-------Begin wwassignment_grade_item_delete------"); debugLog("inputs wwassignment " . print_r($wwassignment, true) ); global $CFG; @@ -374,7 +394,7 @@ function wwassignment_grade_item_delete($wwassignment) { if (!isset($wwassignment->courseid)) { $wwassignment->courseid = $wwassignment->course; } - debugLog("End wwassignment_grade_item_delete"); + traceLog("-------End wwassignment_grade_item_delete---------"); return grade_update('mod/wwassignment', $wwassignment->courseid, 'mod', 'wwassignment', $wwassignment->id, 0, NULL, array('deleted'=>1)); @@ -385,9 +405,9 @@ function wwassignment_grade_item_delete($wwassignment) { * This is done by calling the update_instance() method of the assignment type class */ function wwassignment_item_update($wwassignment) { - debugLog("Begin wwassignment_item_update -- not yet defined!!!!"); + traceLog("------Begin wwassignment_item_update -- not yet defined!!!!------"); debugLog("input wwassignment " . print_r($wwassignment,true) ); - debugLog("End wwassignment_item_update -- not yet defined!!!!"); + traceLog("-------End wwassignment_item_update -- not yet defined!!!!-------"); } /** * @desc Contacts webwork to find out the completion status of a problem set for all users in a course. @@ -395,7 +415,7 @@ function wwassignment_item_update($wwassignment) { * @return object The student grades indexed by student ID. */ function wwassignment_grades($wwassignmentid) { -// error_log("Begin wwassignment_grades -- legacy function?"); + traceLog("------ Begin wwassignment_grades -- legacy function?-------"); global $COURSE,$DB; $wwclient = new wwassignment_client(); $wwassignment = $DB->get_record('wwassignment', array( 'id'=>$wwassignmentid )); @@ -425,6 +445,7 @@ function wwassignment_grades($wwassignmentid) { } $studentgrades->maxgrade = $wwclient->get_max_grade($wwcoursename,$wwsetname); // error_log("End wwassignment_grades -- legacy function?"); + traceLog("------ End wwassignment_grades -- legacy function?-------"); return $studentgrades; } @@ -437,11 +458,13 @@ function wwassignment_grades($wwassignmentid) { * @return array Representing time, info pairing. */ function wwassignment_user_outline($course, $user, $mod, $wwassignment) { + traceLog("--------Begin wwassignment_user_outline-----------------"); $aLogs = get_logs("l.userid=$user AND l.course=$course AND l.cmid={$wwassignment->id}"); if( count($aLogs) > 0 ) { $return->time = $aLogs[0]->time; $return->info = $aLogs[0]->info; } + traceLog("--------End wwassignment_user_outline-----------------"); return $return; } @@ -479,7 +502,8 @@ function wwassignment_delete_userdata() { */ function wwassignment_print_recent_activity($course, $isteacher, $timestart) { global $CFG; -// error_log("Begin wwassignment_print_recent_activity --not used yet"); + traceLog("-------- Begin wwassignment_print_recent_activity --not used yet -------"); + traceLog("-------- End wwassignment_print_recent_activity --not used yet -------"); return false; // True if anything was printed, otherwise false } @@ -490,15 +514,15 @@ function wwassignment_print_recent_activity($course, $isteacher, $timestart) { * returns true if successful */ function wwassignment_cron() { - debugLog("Begin wwassignment_cron"); + traceLog("-------------Begin wwassignment_cron-------------------------"); //FIXME: Add a call that updates all events with dates (in case people forgot to push) //wwassignment_refresh_events(); //FIXME: Add a call that updates all grades in all courses //wwassignment_update_grades(null,0); //try { // try didn't work on some php systems -- leave it out. - wwassignment_update_dirty_sets(); - debugLog("End wwassignment_cron"); + _wwassignment_update_dirty_sets(); + traceLog("---------------------End wwassignment_cron------------------------"); return true; } @@ -517,71 +541,55 @@ function wwassignment_cron() { // // $modinfo = get_fast_modinfo($course); // - -function wwassignment_update_dirty_sets() { // update grades for all instances which have been modified since last cronjob - global $CFG,$DB; - $timenow = time(); - $lastcron = $DB->get_field("modules","lastcron",array( "name"=>"wwassignment" )); -// error_log ("lastcron is $lastcron and time now is $timenow"); - - //error_log ("sql string = $sql"); - // Could we speed this up by getting all of the log records pertaining to webwork in one go? - // Or perhaps just the log records which have occured after the lastcron date - // Then create a hash with wwassignment->id => timemodified - // means just one database lookup - $counter = 0; - $logRecords = get_logs("l.module LIKE \"wwassignment\" AND l.time >$lastcron ", null, "l.time ASC", $counter); - $wwmodtimes=array(); - foreach ($logRecords as $record) { - $wwmodtimes[$wwid =$record->info] = $record->time; - } - - // Create an array with the wwid values - $idValues= implode(",", array_keys($wwmodtimes) ); - list($usql,$params) = $DB->get_in_or_equal($idValues); - //error_log("values string $idValues"); - //error_log("last modification times".print_r($wwmodtimes,true)); - - - $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid, cm.id as wwinstanceid " . - "FROM {wwassignment} a, {course_modules} cm, {modules} m WHERE m.name = 'wwassignment' " . - "AND m.id=cm.module AND cm.instance=a.id AND a.id $usql"; - - $sql3 = "SELECT a.* FROM {wwassignment} a WHERE a.id $usql"; - - //error_log("last modification times".print_r($wwmodificationtime,true)); - - if ($rs = $DB->get_recordset_sql($sql,$params)) { - foreach ( $rs as $wwassignment ) { - if (!$wwassignment->cmidnumber) { // is this ever needed? - $wwassignment->cmidnumber =_wwassignment_cmid() ; - } - $wwassignment->timemodified = $wwmodtimes[$wwassignment->id]; - if ($wwassignment->timemodified > $lastcron) { -// error_log("instance needs update. timemodified ".$wwassignment->timemodified. -// ", lastcron $lastcron, course id ".$wwassignment->course.", wwassignment id ".$wwassignment->id. -// ", set name ".$wwassignment->name.", cm.id ".$wwassignment->wwinstanceid); - if ($wwassignment->grade != 0) { - wwassignment_update_grades($wwassignment); - } else { - wwassignment_grade_item_update($wwassignment); - } - // refresh events for this assignment - _wwassignment_refresh_event($wwassignment); - - } else { -// error_log("no update needed. timemodified ".$wwassignment->timemodified. -// ", lastcron $lastcron, course id ".$wwassignment->course.", wwassignment id ".$wwassignment->id. -// ", set name ".$wwassignment->name.", cm.id ".$wwassignment->wwinstanceid); - } - - } - $rs->close(); - } -// error_log("done with updating dirty sets"); - return(true); -} +// function report_log_userday($userid, $courseid, $daystart, $logreader = '') { +// global $DB; +// $logmanager = get_log_manager(); +// $readers = $logmanager->get_readers(); +// if (empty($logreader)) { +// $reader = reset($readers); +// } else { +// $reader = $readers[$logreader]; +// } +// +// // If reader is not a sql_internal_table_reader and not legacy store then return. +// if (!($reader instanceof \core\log\sql_internal_table_reader) && !($reader instanceof logstore_legacy\log\store)) { +// return array(); +// } +// +// $daystart = (int)$daystart; // Note: unfortunately pg complains if you use name parameter or column alias in GROUP BY. +// +// if ($reader instanceof logstore_legacy\log\store) { +// $logtable = 'log'; +// $timefield = 'time'; +// $coursefield = 'course'; +// // Anonymous actions are never logged in legacy log. +// $nonanonymous = ''; +// } else { +// $logtable = $reader->get_internal_log_table_name(); +// $timefield = 'timecreated'; +// $coursefield = 'courseid'; +// $nonanonymous = 'AND anonymous = 0'; +// } +// $params = array('userid' => $userid); +// +// $courseselect = ''; +// if ($courseid) { +// $courseselect = "AND $coursefield = :courseid"; +// $params['courseid'] = $courseid; +// } +// return $DB->get_records_sql("SELECT FLOOR(($timefield - $daystart)/" . HOURSECS . ") AS hour, COUNT(*) AS num +// FROM {" . $logtable . "} +// WHERE userid = :userid +// AND $timefield > $daystart $courseselect $nonanonymous +// GROUP BY FLOOR(($timefield - $daystart)/" . HOURSECS . ") ", $params); +// } +// +// target = course_module +// objecttable = wwassignment +// id = +// timecreated +// courseid /** @@ -599,81 +607,88 @@ function wwassignment_get_participants($wwassignmentid) { return _wwassignment_get_course_students( $wwassignment->course ); } - +//FIXME -- this should be restored function wwassignment_refresh_events($courseid = 0) { -// error_log('wwassignment_refresh_events called --not yet defined'); - global $DB; -// This standard function will check all instances of this module -// and make sure there are up-to-date events created for each of them. -// If courseid = 0, then every wwassignment event in the site is checked, else -// only wwassignment events belonging to the course specified are checked. -// This function is used, in its new format, by restore_refresh_events() and by the cron function -// - // find wwassignment instances associated with this course or all wwassignment modules - $courses = array(); # create array of courses - if ($courseid) { - if (! $wwassignments = $DB->get_records("wwassignment", array("course"=>$courseid) )) { - return true; - } else { - $courses[$courseid]= array(); // collect wwassignments for this course - array_push( $courses[$courseid], $wwassignments ); - } - } else { - if (! $wwassignments = $DB->get_records("wwassignment")) { - return true; - } else { - foreach ($wwassignments as $ww ) { - // collect wwassignments for each course -// error_log("course id ".$ww->course); - if (! ($courses[$ww->course] ) ) { - $courses[$ww->course] = array(); - } - array_push($courses[$ww->course], $ww) ; // push wwassignment onto an exisiting one - } - } - - } - - - // $courses now holds a list of courses with wwassignment modules - $moduleid = _wwassignment_cmid(); - $cids = array_keys($courses); # collect course ids -// error_log("cids".print_r($cids, true)); - $wwclient = new wwassignment_client(); - foreach ($cids as $cid) { - // connect to WeBWorK - $wwcoursename = _wwassignment_mapped_course($cid,false); - $wwassignment->webwork_course = $wwcoursename; - if ( $wwcoursename== -1) { -// error_log("Can't connect course $cid to webwork"); - break; - } - // retrieve wwassignments associated with this course - foreach($courses[$cid] as $wwassignment ) { - //checking mappings - $wwsetname = $wwassignment->webwork_set; -// error_log("updating events for $wwcoursename $wwsetname"); - //get data from WeBWorK - $wwsetdata = $wwclient->get_assignment_data($wwcoursename,$wwsetname,false); - $wwassignment->grade = $wwclient->get_max_grade($wwcoursename,$wwsetname,false); - $wwassignment->timemodified = time(); - $returnid = $DB->update_record('wwassignment',$wwassignment); - // update event - //this part won't work because these items implicitly require the course. - _wwassignment_delete_events($wwassignment->id); - _wwassignment_create_events($wwassignment, $wwsetdata); - } - - } - - - return true; + global $DB; + traceLog("----------------- Begin wwassignment_refresh_events ---------------"); + _wwassignment_refresh_events($courseid); + traceLog("----------------- End wwassignment_refresh_events ---------------"); } + +// +// // This standard function will check all instances of this module +// // and make sure there are up-to-date events created for each of them. +// // If courseid = 0, then every wwassignment event in the site is checked, else +// // only wwassignment events belonging to the course specified are checked. +// // This function is used, in its new format, by restore_refresh_events() and by the cron function +// // +// // find wwassignment instances associated with this course or all wwassignment modules +// $courses = array(); # create array of courses +// if ($courseid) { +// if (! $wwassignments = $DB->get_records("wwassignment", array("course"=>$courseid) )) { +// return true; +// } else { +// $courses[$courseid]= array(); // collect wwassignments for this course +// array_push( $courses[$courseid], $wwassignments ); +// } +// } else { +// if (! $wwassignments = $DB->get_records("wwassignment")) { +// return true; +// } else { +// foreach ($wwassignments as $ww ) { +// // collect wwassignments for each course +// // error_log("course id ".$ww->course); +// if (! ($courses[$ww->course] ) ) { +// $courses[$ww->course] = array(); +// } +// array_push($courses[$ww->course], $ww) ; // push wwassignment onto an exisiting one +// } +// } +// +// } +// +// +// // $courses now holds a list of courses with wwassignment modules +// $moduleid = _wwassignment_cmid(); +// $cids = array_keys($courses); # collect course ids +// // error_log("cids".print_r($cids, true)); +// $wwclient = new wwassignment_client(); +// foreach ($cids as $cid) { +// // connect to WeBWorK +// $wwcoursename = _wwassignment_mapped_course($cid,false); +// $wwassignment->webwork_course = $wwcoursename; +// if ( $wwcoursename== -1) { +// // error_log("Can't connect course $cid to webwork"); +// break; +// } +// // retrieve wwassignments associated with this course +// foreach($courses[$cid] as $wwassignment ) { +// //checking mappings +// $wwsetname = $wwassignment->webwork_set; +// // error_log("updating events for $wwcoursename $wwsetname"); +// //get data from WeBWorK +// $wwsetdata = $wwclient->get_assignment_data($wwcoursename,$wwsetname,false); +// $wwassignment->grade = $wwclient->get_max_grade($wwcoursename,$wwsetname,false); +// $wwassignment->timemodified = time(); +// $returnid = $DB->update_record('wwassignment',$wwassignment); +// // update event +// //this part won't work because these items implicitly require the course. +// _wwassignment_delete_events($wwassignment->id); +// _wwassignment_create_events($wwassignment, $wwsetdata); +// } +// +// } +// traceLog("----------------- End wwassignment_refresh_events ---------------"); +// +// return true; +// } +/////////////////////////////////////////////////////////////////////////////////////// // High level grade calls ins gradelib.php +/////////////////////////////////////////////////////////////////////////////////////// -/** +/** A. * Returns grading information for given activity - optionally with users grades * Manual, course or category items can not be queried. * @public @@ -685,10 +700,10 @@ function wwassignment_refresh_events($courseid = 0) { * @return array of grade information objects (scaleid, name, grade and locked status, etc.) indexed with itemnumbers */ -// function grade_get_grades($courseid, $itemtype, $itemmodule, $iteminstance, $userid_or_ids=null) { +// A. function grade_get_grades($courseid, $itemtype, $itemmodule, $iteminstance, $userid_or_ids=null) { - /** + /** B. * Submit new or update grade; update/create grade_item definition. Grade must have userid specified, * rawgrade and feedback with format are optional. rawgrade NULL means 'Not graded', missing property * or key means do not change existing. @@ -707,15 +722,19 @@ function wwassignment_refresh_events($courseid = 0) { * @param mixed $grades grade (object, array) or several grades (arrays of arrays or objects), NULL if updating grade_item definition only * @param mixed $itemdetails object or array describing the grading item, NULL if no change */ -// function grade_update($source, $courseid, $itemtype, $itemmodule, $iteminstance, $itemnumber, $grades=NULL, $itemdetails=NULL) { - -/** - * Refetches data from all course activities - * @param int $courseid - * @param string $modname - * @return success - */ -// function grade_grab_course_grades($courseid, $modname=null) { + +/** +* B. function grade_update($source, $courseid, $itemtype, $itemmodule, $iteminstance, +* $itemnumber, $grades=NULL, $itemdetails=NULL) {} + +/** C. +* Refetches data from all course activities +* @param int $courseid +* @param string $modname +* @return success +* C. function grade_grab_course_grades($courseid, $modname=null) {} +*/ +/////////////////////////////////////////////////////////////////////////////////////// function wwassignment_supports($feature) { switch($feature) { @@ -727,7 +746,7 @@ function wwassignment_supports($feature) { /** - * Given a coursemodule object, this function returns the extra + * Given a coursemodule object, `wwassignment_get_coursemodule_info` function returns the extra * information needed to print this activity in various places. * * If folder needs to be displayed inline we store additional information diff --git a/locallib.php b/locallib.php index d81d1be..98bbbdd 100644 --- a/locallib.php +++ b/locallib.php @@ -1,10 +1,12 @@ libdir/soap/nusoap.php"); require_once("$CFG->libdir/soaplib.php"); - +require_once("$CFG->dirroot/calendar/lib.php"); + define('WWASSIGNMENT_DEBUG',0); -// define('WWASSIGNMENT_DEBUG',1); +//define('WWASSIGNMENT_DEBUG',1); +define('WWASSIGNMENT_TRACE',0); +//define('WWASSIGNMENT_TRACE',1); ////////////////////////////////////////////////////////////////// @@ -23,6 +25,12 @@ function debugLog($message) { } } +function traceLog($message) { + if (WWASSIGNMENT_TRACE) { + error_log($message); + mtrace($message); + } +} /** (reference from accesslib.php ) * @desc gets all the users assigned this role in this context or higher * @param int roleid (can also be an array of ints!) @@ -43,27 +51,31 @@ function debugLog($message) { */ function _wwassignment_get_course_students($courseid) { - debugLog("Begin get_course_students($courseid )"); + traceLog("---------------Begin get_course_students($courseid )------------ "); + traceLog("which fetches all the students in the course"); debugLog("courseID is ". print_r($courseid, true)); $context = context_course::instance($courseid); debugLog("context is ". print_r($context, true)); $users = array(); $roles_used_in_context = get_roles_used_in_context($context); - //debugLog("roles used ". print_r($roles_used_in_context, true)); + debugLog("roles used ". print_r($roles_used_in_context, true)); foreach($roles_used_in_context as $role) { $roleid = $role->id; debugLog( "roleid should be 5 for a student $roleid"); - //debugLog(get_role_users($roleid, $context, true) ); + debugLog(get_role_users($roleid, $context, true) ); if ($new_users = get_role_users($roleid, $context, true) ) { - $users = array_merge($users, $new_users );//FIXME a user could be liseted twice + $users = array_merge($users, $new_users ); + //FIXME a user could be listed twice if they had two roles. } - debugLog("display users ".print_r($users,true)); + //debugLog("display users ".print_r($users,true)); + } + debugLog("getting logins of users in courseid $courseid"); + foreach($users as $item) { + debugLog("user: ".$item->lastname); } - debugLog("display users in course--on"); - debugLog("users again".print_r($users, true)); - debugLog("End get_course_students($courseid )"); + traceLog("---------------End get_course_students($courseid )------------ "); return $users; @@ -83,31 +95,35 @@ function _wwassignment_get_course_students($courseid) { */ function _wwassignment_create_events($wwassignment,$wwsetdata ) { -// error_log("enter create_events for set ".$wwassignment->name." id ".$wwassignment->id." date ".$wwsetdata['open_date']." ".$wwsetdata['due_date'] ); - global $COURSE; - //error_log("set data".print_r($wwsetdata,true)); + //global $COURSE; + global $CFG; + require_once("$CFG->dirroot/calendar/lib.php"); + traceLog("-----------------------Begin _wwassignment_create_events ---------------"); + traceLog(" create events for course: ". $wwassignment->name. + " assignment id ".$wwassignment->id." dates ". + $wwsetdata['open_date']." ".$wwsetdata['due_date'] ); + //$wwassignment->name is course name + //$wwassignment->id is name/id of set + debugLog("set data".print_r($wwsetdata,true)); if (! $opendate = $wwsetdata['open_date'] ) { -// error_log(" undefined open date "); + debugLog(" undefined open date "); } if (! $duedate = $wwsetdata["due_date"] ){ -// error_log(" undefined due date "); - } - if (! $wwassignmentid = $wwassignment->id ) { -// error_log(" undefined ww id "); - } - if (! $name = $wwassignment->name ) { -// error_log(" undefined set name "); - } - $courseid = $wwassignment->course; - - if (!$courseid) { - $courseid =$COURSE->id; - } - - - unset($event); - $event = new \stdClass(); - $event->name = $name; + debugLog(" undefined due date "); + } + if (! $wwassignmentid = $wwsetname = $wwassignment->id ) { + debugLog(" undefined set id/name "); + } + if (! $courseName = $wwassignment->name ) { + debugLog(" undefined course name "); + } + if (! $courseid = $wwassignment->course) { + debugLog(" undefined course id "); + } + +// unset($event); + $event = new stdClass(); + $event->name = "$courseName $wwassignmentid"; $event->description = 'WeBWorK Set Event'; $event->courseid = $courseid; $event->groupid = 0; @@ -118,19 +134,44 @@ function _wwassignment_create_events($wwassignment,$wwsetdata ) { $event->visible = 1; $event->eventtype = 'due'; $event->timestart = $duedate; - $event->timeduration = 1; - - // error_log("adding a due event"); + $event->timeduration = 0; + +// model +// $event = new stdClass; +// $event->name = get_string('stop', 'feedback').' '.$feedback->name; +// $event->description = format_module_intro('feedback', $feedback, $feedback->coursemodule); +// $event->courseid = $feedback->course; +// $event->groupid = 0; +// $event->userid = 0; +// $event->modulename = 'feedback'; +// $event->instance = $feedback->id; +// $event->eventtype = 'feedbackcloses'; // For activity module's events, this can be used to set the alternative text of the event icon. Set it to 'pluginname' unless you have a better string. +// $event->timestart = $feedback->timeclose; +// $event->visible = instance_is_visible('feedback', $feedback); +// $event->timeduration = 0; +// +// calendar_event::create($event); +// + traceLog("adding a due event"); $result = 0; - // $calendareventid = add_event($event); //calendar_event::create($event);// - global $CFG; + //global $CFG; require_once("$CFG->dirroot/calendar/lib.php"); + +// // $calendareventid = add_event($event); //calendar_event::create($event);// + +// FIXME -- this throws an error. ???? + + $calendareventid = calendar_event::create($event); -// error_log("calendareventid $calendareventid created"); + traceLog("due event added"); if(!$calendareventid) { -// error_log("can't create calendarevent for set $wwsetname wwid $wwassignmentid date $opendate $duedate course $courseid"); + debugLog("can't create calendarevent for set $wwsetname wwid $wwassignmentid date $opendate $duedate course $courseid"); $result = -1; + } else { + debugLog("created calendarevent for set $wwsetname wwid $wwassignmentid date $opendate $duedate course $courseid" + ); } + traceLog("-----------------------End _wwassignment_create_events ---------------"); return $result; } @@ -142,24 +183,279 @@ function _wwassignment_create_events($wwassignment,$wwsetdata ) { */ function _wwassignment_delete_events($wwassignmentid) { global $DB, $CFG; + traceLog("----------Begin _wwassignment_delete_events ---------------"); if ($events = $DB->get_records_select('event', "modulename = 'wwassignment' and instance = '$wwassignmentid'")) { foreach($events as $event) { - // error_log("deleting event ".$event->id); + debugLog("deleting event ".$event->id); require_once("$CFG->dirroot/calendar/lib.php"); $calEvent = new calendar_event($event); $calEvent->delete(true); - //delete_event($event->id); - + //delete_event($event->id); FIXME -- probably obsolete } } + traceLog("----------End _wwassignment_delete_events ---------------"); return 0; } +function _wwassignment_update_dirty_sets() { // update grades for all instances which have been modified since last cronjob + global $CFG,$DB; + global $CFG; + require_once($CFG->dirroot.'/course/lib.php'); + require_once($CFG->dirroot.'/report/log/locallib.php'); + require_once($CFG->libdir.'/adminlib.php'); + require_once($CFG->dirroot.'/lib/tablelib.php'); + traceLog("-----------------Begin _wwassignment_update_dirty_sets---------------"); + $timenow = time(); + ///////////////////////////////////////////////////////////////////// + // Obtain the last time that wwassignment cron processes were triggered. + ///////////////////////////////////////////////////////////////////// + $lastcron = $DB->get_field("modules","lastcron",array( "name"=>"wwassignment" )); + //FIXME make sure to readjust lastcron value + // $lastcron = 1488778000; # so we get some examples + + debugLog("_wwassignment_update_dirty_sets: lastcron is $lastcron and time now is $timenow"); + + $logreader=''; + $logmanager = get_log_manager(); + $readers = $logmanager->get_readers(); + if (empty($logreader)) { + $reader = reset($readers); //default is \core\log\sql_internal_table_reader + } else { + $reader = $readers[$logreader]; + } + + if ($reader instanceof \core\log\sql_internal_table_reader) { + debugLog("wwassignment_update_dirty_sets: reader is instance of \core\log\sql_internal_table_reader" ); + } + + // If reader is not a sql_internal_table_reader and not legacy store then return. + if (!($reader instanceof \core\log\sql_internal_table_reader) && + !($reader instanceof logstore_legacy\log\store)) { + mtrace("wwassignment_update_dirty_sets:don't have access to the right kind of logs"); + debugLog("wwassignment_update_dirty_sets:bad logs "); + return array(); + } + ///////////////////////////////////////////////////////////////////// + // This is the legacy code, it imitates reading from the old log file + ///////////////////////////////////////////////////////////////////// + // $logRecords = get_logs("l.module LIKE \"wwassignment\" AND l.time >$lastcron ", null, "l.time ASC", $counter); + //// The "log" file contains relevent fields + //// time -- of record entry + //// course -- number of course targeted + //// module -- module targeted (e.g. wwassignment) + //// info -- contains the number of wwassignment record (the homework set targeted) + + ////////////////////////////////////////////////////// + //// legacy action: return the record for events targeting wwassignment + //// after the last cron run sorted by time in ascending order + ///////////////////////////////////////////////////// + + // foreach ($logRecords as $record) { + // $wwmodtimes[$wwid =$record->info] = $record->time; + // } + //// legacy action: create a hash $wwmodtimes with key= homework set (wwid), + //// value= last access to that homework set + //// Notice that a given homework set is likely to have been accessed multiple times + //// and this collapses all of those touches into a single reference + + // $idValues= implode(",", array_keys($wwmodtimes) ); + //// legacy action: Create an string with the wwid values ?? wouldn't an array have worked? + + // list($usql,$params) = $DB->get_in_or_equal($idValues); + + ////////////////////////////////////////////////////////////////// + //// legacy action: result is a string $usql (sic) of the form + //// "IN (?,?,?)" and $params an array [23,12,45] + //// where the numbers are wwid's + ////////////////////////////////////////////////////////////////// + + +// $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid, cm.id as wwinstanceid " . +// "FROM {wwassignment} a, {course_modules} cm, {modules} m WHERE m.name = 'wwassignment' " . +// "AND m.id=cm.module AND cm.instance=a.id AND a.id $usql"; +// $rs = $DB->get_recordset_sql($sql,$params)) + + + ///////////////////////////////// ///////////////////////////////// + // Begin finding all of the wwassignment modules that have been touched since the last cron update + ///////////////////////////////// ///////////////////////////////// + + ////////////////////////////////////////////////////////////////// + //// legacy action: select records from wwassignment with id's in $insql (or $usql (sic)) + //// -- and which therefore have been touched since the last cron update + //// join each of these with the record in course_module which references (cm.instance) the record in wwassignmnent + //// and join each these also with the record in modules referenced from course_modules (cm.module). + //// Return the complete wwassignment record, augmented with the course_module idnumber (has inconsistent data) + //// the courseid (a number) and the course_module record id (cm.id) + ////////////////////////////////////////////////////////////////// + + + if ($reader instanceof logstore_legacy\log\store) { + debugLog("wwassignment_update_dirty_sets:Reading from the old style logs"); + $logtable = 'log'; + $timefield = 'time'; + $coursefield = 'course'; + // Anonymous actions are never logged in legacy log. + $nonanonymous = ''; + } else { + $logtable = $reader->get_internal_log_table_name(); + $timefield = 'timecreated'; + $coursefield = 'courseid'; + $nonanonymous = 'AND anonymous = 0'; + } + +// +// $courseselect = ''; +// if ($courseid) { +// $courseselect = "AND $coursefield = :courseid"; +// $params['courseid'] = $courseid; +// } + +#################### +# Look for activity involving wwassignment in the general log file +#################### + $params['module_type'] = 'course_module'; + $params['wwassignment'] = 'wwassignment'; + debugLog("using the log table $logtable"); + +// // Could we speed this up by getting all of the log records pertaining to webwork in one go? +// // Or perhaps just the log records which have occured after the lastcron date +// // Then create a hash with wwassignment->id => timemodified +// // means just one database lookup +// $counter = 0; +// // this is most likely what needs to be replaced +// +// +// // $logRecords = get_logs("l.module LIKE \"wwassignment\" AND l.time >$lastcron ", null, "l.time ASC", $counter,''); + +////////////////////////////////////////////////////////// +// reproducing legacy effect with the call to the "log" table +////////////////////////////////////////////////////////// +// Find all event records which have been created since the last cron update and which +// target a module +// AND the module table is labeled "wwassignment". +// return the time, the courseid, event id, +// the objecttable (named wwassign), and +// the target (module_type) +// !! the objectid (which wwassignment was touched) + + $logRecords = $DB->get_records_sql("SELECT $timefield AS time, COUNT(*) AS num, + $coursefield AS courseid, target AS target, + objecttable AS module, + objectid AS wwassignmentid, + id AS eventid + FROM {" . $logtable . "} + WHERE $timefield > $lastcron + AND target = :module_type + AND objecttable = :wwassignment + GROUP BY $timefield", $params); + $number_of_log_records = count($logRecords); + debugLog("wwassignment_update_dirty_sets:number of logRecords $number_of_log_records"); + //debugLog(print_r($logRecords,true)); + + + + $wwmodtimes=array(); + foreach ($logRecords as $record) { + $wwmodtimes[$record->wwassignmentid] = $record->time; + } + +// +// // Create an array with the wwid values +// $idValues= implode(",", array_keys($wwmodtimes) ); +// //list($insql,$inparams) = $DB->get_in_or_equal($idValues,SQL_PARAMS_NAMED); + $arraykeys = array_keys($wwmodtimes); +// //debugLog("array_keys ".print_r($arraykeys,true)); + if (count( $arraykeys)==0) { + traceLog("-----------------no grades to update -------------------------------"); + traceLog("-----------------End _wwassignment_update_dirty_sets---------------"); + return true; + } + traceLog("------ find arraykeys in SQL_PARAMs_NAMEd"); + list($insql,$inparams) = $DB->get_in_or_equal($arraykeys,SQL_PARAMS_NAMED); + +// //list($insql, $inparams) = $DB->get_in_or_equal($wwmodtimes,SQL_PARAMS_NAMED); +// debugLog("values string: $idValues"); +// debugLog("last modification times".print_r($wwmodtimes,true)); + //debugLog("insql ".print_r($insql,true)); + //debugLog("array values".print_r(array_values($arraykeys),true)); + debugLog("inparams ".print_r($inparams, true)); + + + ///////////////////////////////// ///////////////////////////////// + // End finding all of the wwassignment modules that have been touched since the last cron update + ///////////////////////////////// ///////////////////////////////// + // $insql looks like "IN(4,6,78)" where the numbers are ids (a.id) + // of records in the wwassignment table + // these are records of homework sets that have been touched. + // + + ////////////////////////////////////////////////////////////////// + // construct query for wwassignment table + ///////////////////////////////////////////////////////////////// + + // This should be the same query for both the legacy code + // and the new code + + $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid, + cm.id as wwinstanceid " . + "FROM {wwassignment} a, + {course_modules} cm, + {modules} m + WHERE a.id $insql + AND cm.instance=a.id + AND m.id=cm.module + AND m.name = 'wwassignment' + "; + debugLog("sql obtained from wwassignment is $sql"); + $rs = $DB->get_recordset_sql($sql,$inparams); + +///////////////////////////////// +// + if ($rs = $DB->get_recordset_sql($sql,$inparams)) { + foreach ( $rs as $wwassignment ) { + debugLog("record set ".print_r($wwassignment, true)); + if (!$wwassignment->cmidnumber) { // is this ever needed? + $wwassignment->cmidnumber =_wwassignment_cmid() ; + } + $wwassignment->timemodified = $wwmodtimes[$wwassignment->id]; + if ($wwassignment->timemodified > $lastcron) { + debugLog("instance needs update. timemodified ".$wwassignment->timemodified. + ", lastcron $lastcron, course id ".$wwassignment->course.",\n wwassignment id ".$wwassignment->id. + ", set name ".$wwassignment->name.", cm.id ".$wwassignment->wwinstanceid. + ", grade ".$wwassignment->grade); + if (1) { //FIXME this should check something + wwassignment_update_grades($wwassignment); + debugLog("update entire set ".print_r($wwassignment, true ) ); + + } else { + debugLog("do wwassignment_grade_item_update" ); + wwassignment_grade_item_update($wwassignment); + + } + +// // refresh events for this assignment + _wwassignment_refresh_event($wwassignment); +// + } else { // ?? shouldn't every record with id in $usql need an update? why the extra check. + debugLog("no update needed. timemodified ".$wwassignment->timemodified. + ", lastcron $lastcron, course id ".$wwassignment->course.", wwassignment id ".$wwassignment->id. + ", set name ".$wwassignment->name.", cm.id ".$wwassignment->wwinstanceid); + } + + } + $rs->close(); + } + traceLog("-----------------End _wwassignment_update_dirty_sets---------------"); + return(true); +} + function _wwassignment_refresh_event($wwassignment) { global $DB; + traceLog("----------------Begin _wwassignment_refresh_event-------------"); $cid = $wwassignment->course; $wwcoursename = _wwassignment_mapped_course($cid,false); if ( $wwcoursename== -1) { @@ -168,7 +464,7 @@ function _wwassignment_refresh_event($wwassignment) { } $wwclient = new wwassignment_client(); $wwsetname = $wwassignment->webwork_set; - error_log("updating events for $wwcoursename $wwsetname"); + traceLog("updating events for course: $wwcoursename assignment: $wwsetname"); //get data from WeBWorK $wwsetdata = $wwclient->get_assignment_data($wwcoursename,$wwsetname,false); $wwassignment->grade = $wwclient->get_max_grade($wwcoursename,$wwsetname,false); @@ -177,6 +473,7 @@ function _wwassignment_refresh_event($wwassignment) { // update event _wwassignment_delete_events($wwassignment->id); _wwassignment_create_events($wwassignment,$wwsetdata); + traceLog("----------------End _wwassignment_refresh_event-------------"); return true; } @@ -242,8 +539,8 @@ function _wwassignment_login_user($wwcoursename,$wwusername) { */ function _wwassignment_cmid() { global $DB; - $wwassignment = $DB->get_record('modules', array( 'name'=>'wwassignment' )); - return $wwassignment->id; + $wwassignment_module = $DB->get_record('modules', array( 'name'=>'wwassignment' )); + return $wwassignment_module->id; } /** @@ -408,18 +705,19 @@ function handler($functioncall,$params=array(),$override=false) { $params = array_merge($this->defaultparams,$params); } if(WWASSIGNMENT_DEBUG) { - echo "Called: $functioncall
"; + echo "Handler called: $functioncall
"; echo "Params: "; var_dump($params); echo "
"; } $result = $this->client->__soapCall($functioncall,$params); - - //$result = call_user_func_array(array(&$this->client,$functioncall),$params); -# if($err = $this->client->getError()) { -# //print_error(get_string("rpc_fault","wwassignment') . " " . $functioncall. " ". $err); -# print_error('rpc_error','wwassignment'); -# } + debugLog("result is ".print_r($result, true)); + // FIXME what does call_user_func array do?); +// $result = call_user_func_array(array(&$this->client,$functioncall),$params); +// if($err = $this->client->getError()) { +// //print_error(get_string("rpc_fault","wwassignment') . " " . $functioncall. " ". $err); +// print_error('rpc_error','wwassignment'); +// } return $result; } diff --git a/version.php b/version.php index 309cab1..c99f386 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ // 3.0+ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2015030916; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2015030918; // The current module version (Date: YYYYMMDDXX) $plugin->requires = 2014110400; // Requires this Moodle version $plugin->cron = 300; // Period for cron to check this module (secs) -- every 5 minutes $plugin->component = 'mod_wwassignment';