158 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
// This file is part of the Studyplan plugin for Moodle
 | 
						|
//
 | 
						|
// Moodle is free software: you can redistribute it and/or modify
 | 
						|
// it under the terms of the GNU General Public License as published by
 | 
						|
// the Free Software Foundation, either version 3 of the License, or
 | 
						|
// (at your option) any later version.
 | 
						|
//
 | 
						|
// Moodle is distributed in the hope that it will be useful,
 | 
						|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
// GNU General Public License for more details.
 | 
						|
//
 | 
						|
// You should have received a copy of the GNU General Public License
 | 
						|
// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
/**
 | 
						|
 *
 | 
						|
 * @package    local_treestudyplan
 | 
						|
 * @copyright  2023 P.M. Kuipers
 | 
						|
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
						|
 */
 | 
						|
 | 
						|
namespace local_treestudyplan;
 | 
						|
defined('MOODLE_INTERNAL') || die();
 | 
						|
 | 
						|
require_once($CFG->libdir.'/externallib.php');
 | 
						|
 | 
						|
use \grade_item;
 | 
						|
 | 
						|
class completionscanner {
 | 
						|
    private static $modsupported = [];
 | 
						|
    private static $coursestudents = [];
 | 
						|
    private $scanner = null;
 | 
						|
    private $course = null;
 | 
						|
    private $cm = null;
 | 
						|
    private $gi = null;
 | 
						|
    private $pendingcache = [];
 | 
						|
 | 
						|
    public static function supported($mod) {
 | 
						|
        if (!array_key_exists($mod, self::$modsupported)) {
 | 
						|
            self::$modsupported[$mod] = class_exists("\local_treestudyplan\\local\\ungradedscanners\\{$mod}_scanner");
 | 
						|
        }
 | 
						|
        return self::$modsupported[$mod];
 | 
						|
    }
 | 
						|
 | 
						|
    public static function get_course_students($courseid) {
 | 
						|
        global $CFG;
 | 
						|
        if (!array_key_exists($courseid, self::$coursestudents)) {
 | 
						|
            $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::$coursestudents[$courseid] = $students;
 | 
						|
        }
 | 
						|
        return self::$coursestudents[$courseid];
 | 
						|
    }
 | 
						|
 | 
						|
    public function __construct(\completion_criteria $crit, $course) {
 | 
						|
        $this->courseid = $course->id;
 | 
						|
        $this->course = $course;
 | 
						|
        $this->modinfo = get_fast_modinfo($course);
 | 
						|
        $this->crit = $crit;
 | 
						|
 | 
						|
        $this->completioninfo = new \completion_info($course);
 | 
						|
 | 
						|
        // Find a related scanner if the type is an activity type.
 | 
						|
        if ($crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
 | 
						|
            // First find the course module.
 | 
						|
            $this->cm = $this->modinfo->get_cm($crit->moduleinstance);
 | 
						|
            $gi = grade_item::fetch( ['itemtype' => 'mod',
 | 
						|
                                      'itemmodule' => $this->cm->modname,
 | 
						|
                                      'iteminstance' => $this->cm->instance,
 | 
						|
                                      'courseid' => $this->courseid]);
 | 
						|
            if ($gi !== false) {
 | 
						|
                /* Grade none items should not be relevant.
 | 
						|
                   Note that the grade status is probably only relevant if the item
 | 
						|
                   has not yet received a completion, but has been submitted.
 | 
						|
                */
 | 
						|
                if (($gi->gradetype == GRADE_TYPE_VALUE || $gi->gradetype == GRADE_TYPE_SCALE)) {
 | 
						|
                    // If it's a relevant grade type, initialize a scanner if possible.
 | 
						|
                    $this->gi = $gi;
 | 
						|
                    if (self::supported($gi->itemmodule)) {
 | 
						|
                        $scannerclass = "\local_treestudyplan\\local\ungradedscanners\\{$gi->itemmodule}_scanner";
 | 
						|
                        $this->scanner = new $scannerclass($gi);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    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() {
 | 
						|
 | 
						|
        // Get completion info.
 | 
						|
        $students = self::get_course_students($this->courseid);
 | 
						|
        $completed = 0;
 | 
						|
        $ungraded = 0;
 | 
						|
        $completedpass = 0;
 | 
						|
        $completedfail = 0;
 | 
						|
        foreach ($students as $userid) {
 | 
						|
            if ($this->pending($userid)) {
 | 
						|
                // First check if the completion needs grading.
 | 
						|
                $ungraded++;
 | 
						|
            } else {
 | 
						|
                $completion = $this->completioninfo->get_user_completion($userid, $this->crit);
 | 
						|
 | 
						|
                if ($this->crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
 | 
						|
                    // If it's an activity completion, add all the relevant activities as sub-items.
 | 
						|
                    $completionstatus = $this->completioninfo->get_grade_completion($this->cm, $userid);
 | 
						|
 | 
						|
                    if ($completionstatus == COMPLETION_COMPLETE_PASS) {
 | 
						|
                        $completedpass++;
 | 
						|
                    } else if ($completionstatus == COMPLETION_COMPLETE_FAIL) {
 | 
						|
                        $completedfail++;
 | 
						|
                    } else if ($completionstatus == COMPLETION_COMPLETE) {
 | 
						|
                        $completed++;
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    if ($completion->is_complete()) {
 | 
						|
                        $completed++;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return [
 | 
						|
            'ungraded' => $ungraded,
 | 
						|
            'completed' => $completed,
 | 
						|
            'completed_pass' => $completedpass,
 | 
						|
            'completed_fail' => $completedfail,
 | 
						|
            'students' => count($students),
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
}
 |