2023-05-17 21:19:14 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace local_treestudyplan;
|
|
|
|
require_once($CFG->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){
|
2023-06-16 23:12:17 +02:00
|
|
|
$this->courseid = $gi->courseid;
|
2023-05-17 21:19:14 +02:00
|
|
|
$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'),
|
2023-06-16 23:12:17 +02:00
|
|
|
"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'),
|
2023-05-17 21:19:14 +02:00
|
|
|
"students" => new \external_value(PARAM_INT, 'number of students that should submit'),
|
2023-06-16 23:12:17 +02:00
|
|
|
],"details about gradable submissions",$value);
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function model(){
|
2023-06-16 23:12:17 +02:00
|
|
|
// 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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
return [
|
2023-06-16 23:12:17 +02:00
|
|
|
'ungraded' => $ungraded,
|
|
|
|
'completed' => $completed,
|
|
|
|
'completed_pass' => $completed_pass,
|
|
|
|
'completed_fail' => $completed_fail,
|
|
|
|
'students' => count($students),
|
2023-05-17 21:19:14 +02:00
|
|
|
];
|
2023-06-16 23:12:17 +02:00
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
|
2023-06-16 23:12:17 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|