libdir.'/externallib.php'); use \grade_item; // $gi->courseid, // $gi->itemmodule, // $gi->iteminstance class gradingscanner { private static $mod_supported = []; private static $course_students = []; private $scanner = null; private $gi = null; private $pending_cache = []; public static function supported($mod){ if(!array_key_exists($mod,self::$mod_supported)){ self::$mod_supported[$mod] = class_exists("\local_treestudyplan\\local\\ungradedscanners\\{$mod}_scanner"); } return self::$mod_supported[$mod]; } public static function get_course_students($courseid){ global $CFG; if(!array_key_exists($courseid,self::$course_students)){ $students = []; $context = \context_course::instance($courseid); foreach (explode(',', $CFG->gradebookroles) as $roleid) { $roleid = trim($roleid); $students = array_keys(get_role_users($roleid, $context, false, 'u.id', 'u.id ASC')); } self::$course_students[$courseid] = $students; } return self::$course_students[$courseid]; } public function __construct(grade_item $gi){ $this->courseid = $gi->courseid; $this->gi = $gi; if(self::supported($gi->itemmodule)) { $scannerclass = "\local_treestudyplan\\local\ungradedscanners\\{$gi->itemmodule}_scanner"; $this->scanner = new $scannerclass($gi); } } public function is_available(){ return $this->scanner !== null; } public function pending($userid){ if(!array_key_exists($userid, $this->pending_cache)){ if($this->scanner === null) { $this->pending_cache[$userid] = false; } else { $this->pending_cache[$userid] = $this->scanner->has_ungraded_submission($userid);; } } return $this->pending_cache[$userid]; } public static function structure($value=VALUE_OPTIONAL){ return new \external_single_structure([ "ungraded" => new \external_value(PARAM_INT, 'number of ungraded submissions'), "completed" => new \external_value(PARAM_INT, 'number of completed students'), "completed_pass" => new \external_value(PARAM_INT, 'number of completed-pass students'), "completed_fail" => new \external_value(PARAM_INT, 'number of completed-fail students'), "students" => new \external_value(PARAM_INT, 'number of students that should submit'), ],"details about gradable submissions",$value); } public function model(){ // Upda $students = self::get_course_students($this->courseid); $completed = 0; $ungraded = 0; $completed_pass = 0; $completed_fail = 0; foreach($students as $userid){ if($this->pending($userid)){ // First check if the completion needs grading $ungraded++; } else { $grade = $this->gi->get_final($userid); if(!is_numeric($grade->finalgrade) && empty($grade->finalgrade)){ //skip } else { //compare grade to minimum grade if($this->grade_passed($grade)){ $completed_pass++; } else { $completed_fail++; } } } } return [ 'ungraded' => $ungraded, 'completed' => $completed, 'completed_pass' => $completed_pass, 'completed_fail' => $completed_fail, 'students' => count($students), ]; } // Function copied from bistate aggregator to avoid reference mazes private function grade_passed($grade){ global $DB; $table = "local_treestudyplan_gradecfg"; // first determine if we have a grade_config for this scale or this maximum grade $finalgrade = $grade->finalgrade; $scale = $this->gi->load_scale(); if( isset($scale)){ $gradecfg = $DB->get_record($table,["scale_id"=>$scale->id]); } else if($this->gi->grademin == 0) { $gradecfg = $DB->get_record($table,["grade_points"=>$this->gi->grademax]); } else { $gradecfg = null; } // for point grades, a provided grade pass overrides the defaults in the gradeconfig // for scales, the configuration in the gradeconfig is leading if($gradecfg && (isset($scale) || $this->gi->gradepass == 0)) { // if so, we need to know if the grade is if($finalgrade >= $gradecfg->min_completed){ return true; } else { return false; } } else if($this->gi->gradepass > 0) { $range = floatval($this->gi->grademax - $this->gi->grademin); // if no gradeconfig and gradepass is set, use that one to determine config. if($finalgrade >= $this->gi->gradepass){ return true; } else { return false; } } else { // Blind assumptions if nothing is provided // over 55% of range is completed // if range >= 3 and failed is enabled, assume that this means failed $g = floatval($finalgrade - $this->gi->grademin); $range = floatval($this->gi->grademax - $this->gi->grademin); $score = $g / $range; if($score > 0.55){ return true; } else { return false; } } } }