From 7b95d06c4f2607d79befb34bc93f240aa8e18770 Mon Sep 17 00:00:00 2001 From: PMKuipers Date: Fri, 16 Jun 2023 13:49:47 +0200 Subject: [PATCH] Added service functions for grade/badge/completion progress --- classes/badgeinfo.php | 11 +++ classes/completionscanner.php | 4 +- classes/corecompletioninfo.php | 3 +- classes/courseservice.php | 135 +++++++++++++++++++++++++++++++-- classes/studyplan.php | 36 +++++++++ version.php | 2 +- 6 files changed, 180 insertions(+), 11 deletions(-) diff --git a/classes/badgeinfo.php b/classes/badgeinfo.php index bc2db63..68d06e9 100644 --- a/classes/badgeinfo.php +++ b/classes/badgeinfo.php @@ -127,4 +127,15 @@ class badgeinfo { return $badge; } + function count_issued(array $student_ids){ + $issuecount = 0; + + foreach($student_ids as $uid){ + if($this->badge->is_issued($userid)){ + $issuecount++; + } + } + return $issuecount; + } + } \ No newline at end of file diff --git a/classes/completionscanner.php b/classes/completionscanner.php index 84596e9..9721d95 100644 --- a/classes/completionscanner.php +++ b/classes/completionscanner.php @@ -39,8 +39,8 @@ class completionscanner return self::$course_students[$courseid]; } - public function __construct($course,\completion_criteria $crit){ - $this->course = $course; + public function __construct(\completion_criteria $crit){ + $this->course = $crit->course; $this->crit = $crit; // Find a related scanner if the type is an activity type diff --git a/classes/corecompletioninfo.php b/classes/corecompletioninfo.php index 28a9345..5333945 100644 --- a/classes/corecompletioninfo.php +++ b/classes/corecompletioninfo.php @@ -53,6 +53,7 @@ class corecompletioninfo { public static function completion_item_editor_structure($value=VALUE_REQUIRED){ return new \external_single_structure([ + "id" => new \external_value(PARAM_INT,'criteria id',VALUE_OPTIONAL), "title" => new \external_value(PARAM_TEXT,'name of subitem',VALUE_OPTIONAL), "link" => new \external_value(PARAM_TEXT, 'optional link to more details',VALUE_OPTIONAL), "details" => new \external_single_structure([ @@ -85,7 +86,7 @@ class corecompletioninfo { public static function completion_item_user_structure($value=VALUE_REQUIRED){ return new \external_single_structure([ - "id" => new \external_value(PARAM_INT,'id of subitem',VALUE_OPTIONAL), + "id" => new \external_value(PARAM_INT,'id of completion',VALUE_OPTIONAL), "title" => new \external_value(PARAM_TEXT,'name of subitem',VALUE_OPTIONAL), "details" => new \external_single_structure([ "type" => new \external_value(PARAM_RAW, 'type',VALUE_OPTIONAL), diff --git a/classes/courseservice.php b/classes/courseservice.php index 6ec793b..ac473f9 100644 --- a/classes/courseservice.php +++ b/classes/courseservice.php @@ -3,10 +3,15 @@ namespace local_treestudyplan; require_once($CFG->libdir.'/externallib.php'); use \local_treestudyplan\courseinfo; +use \local_treestudyplan\associationservice; use \local_treestudyplan\local\helpers\webservicehelper; +use \local_treestudyplan\completionscanner; +use \local_treestudyplan\gradingscanner; class courseservice extends \external_api { + const CAP_EDIT = "local/treestudyplan:editstudyplan"; + const CAP_VIEW = "local/treestudyplan:viewuserreports"; /************************ * * @@ -50,7 +55,7 @@ class courseservice extends \external_api $root = \core_course_category::get($root_id); $context = $root->get_context(); // Make sure the user has access to the context for editing purposes - webservicehelper::require_capabilities("local/treestudyplan:editstudyplan",$context); + webservicehelper::require_capabilities(self::CAP_EDIT,$context); // Determine top categories from provided context @@ -135,9 +140,9 @@ class courseservice extends \external_api public static function list_accessible_categories($operation="edit") { if($operation == "edit"){ - $capability = "local/treestudyplan:editstudyplan"; + $capability = self::CAP_EDIT; } else { // $operation == "view" || default - $capability = "local/treestudyplan:viewuserreports"; + $capability = self::CAP_VIEW; } $cats = static::categories_by_capability($capability); @@ -208,9 +213,9 @@ class courseservice extends \external_api { global $DB; if($operation == "edit"){ - $capability = "local/treestudyplan:editstudyplan"; + $capability = self::CAP_EDIT; } else { // $operation == "view" || default - $capability = "local/treestudyplan:viewuserreports"; + $capability = self::CAP_VIEW; } $context_ids = []; $rs = $DB->get_recordset_sql("SELECT DISTINCT context_id, COUNT(*) as num FROM {local_treestudyplan} @@ -243,9 +248,9 @@ class courseservice extends \external_api public static function list_accessible_categories_with_usage($operation='edit'){ global $DB; if($operation == "edit"){ - $capability = "local/treestudyplan:editstudyplan"; + $capability = self::CAP_EDIT; } else { // $operation == "view" || default - $capability = "local/treestudyplan:viewuserreports"; + $capability = self::CAP_VIEW; } // retrieve context ids used $context_ids = []; @@ -269,6 +274,7 @@ class courseservice extends \external_api } $o = new \stdClass(); $o->cat = $cat; + $o->ctxid = $ctxid; $o->count = $count; $list[] = $o; } @@ -276,4 +282,119 @@ class courseservice extends \external_api } + /************************************** + * + * Progress scanners for teacherview + * + **************************************/ + + public static function scan_grade_progress_parameters() + { + return new \external_function_parameters( [ + "gradeitemid" => new \external_value(PARAM_INT, 'Grade item ID to scan progress for',VALUE_DEFAULT), + "studyplanid" => new \external_value(PARAM_INT, 'Study plan id to check progress in',VALUE_DEFAULT), + + ]); + } + + public static function scan_grade_progress_returns() + { + return gradingscanner::structure(VALUE_REQUIRED); + } + + public static function scan_grade_progress($gradeitemid, $studyplanid) + { + global $DB; + // Verify access to the study plan + $o = studyplan::findById($studyplanid); + webservicehelper::require_capabilities(self::CAP_VIEW,$o->context()); + + // Retrieve grade item + $gi = \grade_item::fetch(["id" => $gradeitemid]); + + // Validate course is linked to studyplan + $courseid = $gi->courseid; + if(!$o->course_linked($courseid)){ + throw new \webservice_access_exception("Course {$courseid} linked to grade item {$gradeitemid} is not linked to studyplan {$o->id()}"); + } + + $scanner = new gradingscanner($gi); + return $scanner->model(); + } + + + public static function scan_completion_progress_parameters() + { + return new \external_function_parameters( [ + "criteriaid" => new \external_value(PARAM_INT, 'CriteriaID to scan progress for',VALUE_DEFAULT), + "studyplanid" => new \external_value(PARAM_INT, 'Study plan id to check progress in',VALUE_DEFAULT), + ]); + } + + public static function scan_completion_progress_returns() + { + return completionscanner::structure(VALUE_REQUIRED); + } + + public static function scan_completion_progress($criteriaid, $studyplanid) + { + global $DB; + // Verify access to the study plan + $o = studyplan::findById($studyplanid); + webservicehelper::require_capabilities(self::CAP_VIEW,$o->context()); + + $crit = \completion_criteria::fetch(["id" => $criteriaid]); + $courseid = $crit->course; + if(!$o->course_linked($courseid)){ + throw new \webservice_access_exception("Course {$courseid} linked to criteria {$criteriaid} is not linked to studyplan {$o->id()}"); + } + $scanner = new completionscanner($crit); + return $scanner->model(); + } + + public static function scan_badge_progress_parameters() + { + return new \external_function_parameters( [ + "badgeid" => new \external_value(PARAM_INT, 'Badge to scan progress for',VALUE_DEFAULT), + "studyplanid" => new \external_value(PARAM_INT, 'Study plan id to limit progress search to (to determine which students to scan)',VALUE_DEFAULT), + ]); + } + + public static function scan_badge_progress_returns() + { + return new \external_single_structure([ + "total" => new \external_value(PARAM_INT, 'Total number of students scanned'), + "issued" => new \external_value(PARAM_INT, 'Number of issued badges'), + ]); + } + + public static function scan_badge_progress($badgeid,$studyplanid) + { + global $DB; + // Check access to the study plan + $o = studyplan::findById($studyplanid); + webservicehelper::require_capabilities(self::CAP_VIEW,$o->context()); + + // Validate that badge is linked to studyplan + if(!$o->badge_linked($badgeid)){ + throw new \webservice_access_exception("Badge {$badgeid} is not linked to studyplan {$o->id()}"); + } + + // Get badge info + $badge = new \core_badges\badge($badgeid); + $badgeinfo = new badgeinfo($badge); + + // get the connected users + $students = associationservice::all_associated($studyplanid); + // Just get the user ids + $studentids = array_map(function ($a){ return $a["id"];},$students); + + return [ + "total" => count($studentids), + "issued" => $badgeinfo->count_issued($studentids), + ]; + + } + + } \ No newline at end of file diff --git a/classes/studyplan.php b/classes/studyplan.php index ba397ed..5a6408a 100644 --- a/classes/studyplan.php +++ b/classes/studyplan.php @@ -721,5 +721,41 @@ class studyplan { return true; } + /** + * See if the specified course id is linked in this studyplan + */ + public function course_linked($courseid){ + global $DB; + + $sql = "SELECT COUNT(i.id) + FROM {local_treestudyplan} + INNER JOIN {local_treestudyplan_line} l ON p.id = l.studyplan_id + INNER JOIN {local_treestudyplan_item} i ON l.id = i.line_id + WHERE p.id = :planid + AND i.course_id = :courseid"; + $count = $DB->get_field_sql($sql,["courseid" => $courseid, "planid" => $this->id]); + + return ($count > 0)?true:false; + } + + /** + * See if the specified course id is linked in this studyplan + */ + public function badge_linked($badgeid){ + global $DB; + + $sql = "SELECT COUNT(i.id) + FROM {local_treestudyplan} + INNER JOIN {local_treestudyplan_line} l ON p.id = l.studyplan_id + INNER JOIN {local_treestudyplan_item} i ON l.id = i.line_id + WHERE p.id = :planid + AND i.badge_id = :badgeid"; + $count = $DB->get_field_sql($sql,["badgeid" => $badgeid, "planid" => $this->id]); + + return ($count > 0)?true:false; + } + + + } \ No newline at end of file diff --git a/version.php b/version.php index 2a6b158..ca92318 100644 --- a/version.php +++ b/version.php @@ -1,6 +1,6 @@ component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494) -$plugin->version = 2023051700; // YYYYMMDDHH (year, month, day, iteration) +$plugin->version = 2023061600; // YYYYMMDDHH (year, month, day, iteration) $plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11) $plugin->dependencies = [