From 4d201b824db0cea32e8f8e2d931240d51a0919f5 Mon Sep 17 00:00:00 2001 From: Juan Leyva Date: Fri, 30 Jun 2017 16:08:18 +0100 Subject: [PATCH] MDL-59253 mod_workshop: New WS mod_workshop_get_grades_report --- mod/workshop/classes/external.php | 171 +++++++++++++++++++++++++++ mod/workshop/db/services.php | 7 ++ mod/workshop/locallib.php | 48 ++++++++ mod/workshop/tests/external_test.php | 70 +++++++++++ mod/workshop/version.php | 2 +- 5 files changed, 297 insertions(+), 1 deletion(-) diff --git a/mod/workshop/classes/external.php b/mod/workshop/classes/external.php index 0d5404d8587..2f0145da9f5 100644 --- a/mod/workshop/classes/external.php +++ b/mod/workshop/classes/external.php @@ -1747,4 +1747,175 @@ class mod_workshop_external extends external_api { ) ); } + + /** + * Returns description of method parameters + * + * @return external_function_parameters + * @since Moodle 3.4 + */ + public static function get_grades_report_parameters() { + return new external_function_parameters( + array( + 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), + 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.', + VALUE_DEFAULT, 0), + 'sortby' => new external_value(PARAM_ALPHA, 'sort by this element: lastname, firstname, submissiontitle, + submissionmodified, submissiongrade, gradinggrade.', VALUE_DEFAULT, 'lastname'), + 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'ASC'), + 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0), + 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0), + ) + ); + } + + /** + * Retrieves the assessment grades report. + * + * @param int $workshopid the workshop instance id + * @param int $groupid (optional) group id, 0 means that the function will determine the user group + * @param string $sortby sort by this element + * @param string $sortdirection sort direction: ASC or DESC + * @param int $page page of records to return + * @param int $perpage number of records to return per page + * @return array of warnings and the report data + * @since Moodle 3.4 + * @throws moodle_exception + */ + public static function get_grades_report($workshopid, $groupid = 0, $sortby = 'lastname', $sortdirection = 'ASC', + $page = 0, $perpage = 0) { + global $USER; + + $params = array('workshopid' => $workshopid, 'groupid' => $groupid, 'sortby' => $sortby, 'sortdirection' => $sortdirection, + 'page' => $page, 'perpage' => $perpage); + $params = self::validate_parameters(self::get_grades_report_parameters(), $params); + $submissions = $warnings = array(); + + $sortallowedvalues = array('lastname', 'firstname', 'submissiontitle', 'submissionmodified', 'submissiongrade', + 'gradinggrade'); + if (!in_array($params['sortby'], $sortallowedvalues)) { + throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' . + 'allowed values are: ' . implode(',', $sortallowedvalues)); + } + + $sortdirection = strtoupper($params['sortdirection']); + $directionallowedvalues = array('ASC', 'DESC'); + if (!in_array($sortdirection, $directionallowedvalues)) { + throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . + 'allowed values are: ' . implode(',', $directionallowedvalues)); + } + + list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); + require_capability('mod/workshop:viewallassessments', $context); + + if (!empty($params['groupid'])) { + $groupid = $params['groupid']; + // Determine is the group is visible to user. + if (!groups_group_visible($groupid, $course, $cm)) { + throw new moodle_exception('notingroup'); + } + } else { + // Check to see if groups are being used here. + if ($groupmode = groups_get_activity_groupmode($cm)) { + $groupid = groups_get_activity_group($cm); + // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). + if (!groups_group_visible($groupid, $course, $cm)) { + throw new moodle_exception('notingroup'); + } + } else { + $groupid = 0; + } + } + + if ($workshop->phase >= workshop::PHASE_SUBMISSION) { + $showauthornames = has_capability('mod/workshop:viewauthornames', $context); + $showreviewernames = has_capability('mod/workshop:viewreviewernames', $context); + + if ($workshop->phase >= workshop::PHASE_EVALUATION) { + $showsubmissiongrade = true; + $showgradinggrade = true; + } else { + $showsubmissiongrade = false; + $showgradinggrade = false; + } + + $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $params['page'], $params['perpage'], + $params['sortby'], $sortdirection); + + if (!empty($data)) { + // Populate the display options for the submissions report. + $reportopts = new stdclass(); + $reportopts->showauthornames = $showauthornames; + $reportopts->showreviewernames = $showreviewernames; + $reportopts->sortby = $params['sortby']; + $reportopts->sorthow = $sortdirection; + $reportopts->showsubmissiongrade = $showsubmissiongrade; + $reportopts->showgradinggrade = $showgradinggrade; + $reportopts->workshopphase = $workshop->phase; + + $report = new workshop_grading_report($data, $reportopts); + return array( + 'report' => $report->export_data_for_external(), + 'warnings' => array(), + ); + } + } + throw new moodle_exception('nothingfound', 'workshop'); + } + + /** + * Returns description of method result value + * + * @return external_description + * @since Moodle 3.4 + */ + public static function get_grades_report_returns() { + + $reviewstructure = new external_single_structure( + array( + 'userid' => new external_value(PARAM_INT, 'The id of the user (0 when is configured to do not display names).'), + 'assessmentid' => new external_value(PARAM_INT, 'The id of the assessment.'), + 'submissionid' => new external_value(PARAM_INT, 'The id of the submission assessed.'), + 'grade' => new external_value(PARAM_FLOAT, 'The grade for submission.'), + 'gradinggrade' => new external_value(PARAM_FLOAT, 'The grade for assessment.'), + 'gradinggradeover' => new external_value(PARAM_FLOAT, 'The aggregated grade overrided.'), + 'weight' => new external_value(PARAM_INT, 'The weight of the assessment for aggregation.'), + ) + ); + + return new external_single_structure( + array( + 'report' => new external_single_structure( + array( + 'grades' => new external_multiple_structure( + new external_single_structure( + array( + 'userid' => new external_value(PARAM_INT, 'The id of the user being displayed in the report.'), + 'submissionid' => new external_value(PARAM_INT, 'Submission id.'), + 'submissiontitle' => new external_value(PARAM_RAW, 'Submission title.'), + 'submissionmodified' => new external_value(PARAM_INT, 'Timestamp submission was updated.'), + 'submissiongrade' => new external_value(PARAM_FLOAT, 'Aggregated grade for the submission.', + VALUE_OPTIONAL), + 'gradinggrade' => new external_value(PARAM_FLOAT, 'Computed grade for the assessment.', + VALUE_OPTIONAL), + 'submissiongradeover' => new external_value(PARAM_FLOAT, 'Grade for the assessment overrided + by the teacher.', VALUE_OPTIONAL), + 'submissiongradeoverby' => new external_value(PARAM_INT, 'The id of the user who overrided + the grade.', VALUE_OPTIONAL), + 'submissionpublished' => new external_value(PARAM_INT, 'Whether is a submission published.', + VALUE_OPTIONAL), + 'reviewedby' => new external_multiple_structure($reviewstructure, 'The users who reviewed the + user submission.', VALUE_OPTIONAL), + 'reviewerof' => new external_multiple_structure($reviewstructure, 'The assessments the user + reviewed.', VALUE_OPTIONAL), + ) + ) + ), + 'totalcount' => new external_value(PARAM_INT, 'Number of total submissions.'), + ) + ), + 'warnings' => new external_warnings() + ) + ); + } } diff --git a/mod/workshop/db/services.php b/mod/workshop/db/services.php index 0e766832b49..e9bf3669c5c 100644 --- a/mod/workshop/db/services.php +++ b/mod/workshop/db/services.php @@ -148,4 +148,11 @@ $functions = array( 'type' => 'write', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) ), + 'mod_workshop_get_grades_report' => array( + 'classname' => 'mod_workshop_external', + 'methodname' => 'get_grades_report', + 'description' => 'Retrieves the assessment grades report.', + 'type' => 'read', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) + ), ); diff --git a/mod/workshop/locallib.php b/mod/workshop/locallib.php index 966e2680b63..926ef7d713b 100644 --- a/mod/workshop/locallib.php +++ b/mod/workshop/locallib.php @@ -4504,6 +4504,54 @@ class workshop_grading_report implements renderable { public function get_options() { return $this->options; } + + /** + * Prepare the data to be exported to a external system via Web Services. + * + * This function applies extra capabilities checks. + * @return stdClass the data ready for external systems + */ + public function export_data_for_external() { + $data = $this->get_data(); + $options = $this->get_options(); + + foreach ($data->grades as $reportdata) { + // If we are in submission phase ignore the following data. + if ($options->workshopphase == workshop::PHASE_SUBMISSION) { + unset($reportdata->submissiongrade); + unset($reportdata->gradinggrade); + unset($reportdata->submissiongradeover); + unset($reportdata->submissiongradeoverby); + unset($reportdata->submissionpublished); + unset($reportdata->reviewedby); + unset($reportdata->reviewerof); + continue; + } + + if (!$options->showsubmissiongrade) { + unset($reportdata->submissiongrade); + unset($reportdata->submissiongradeover); + } + + if (!$options->showgradinggrade and $tr == 0) { + unset($reportdata->gradinggrade); + } + + if (!$options->showreviewernames) { + foreach ($reportdata->reviewedby as $reviewedby) { + $reviewedby->userid = 0; + } + } + + if (!$options->showauthornames) { + foreach ($reportdata->reviewerof as $reviewerof) { + $reviewerof->userid = 0; + } + } + } + + return $data; + } } diff --git a/mod/workshop/tests/external_test.php b/mod/workshop/tests/external_test.php index dbe229c911e..2657a966d0c 100644 --- a/mod/workshop/tests/external_test.php +++ b/mod/workshop/tests/external_test.php @@ -1668,4 +1668,74 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase { $this->expectException('moodle_exception'); mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight, $gradinggradeover); } + + /** + * Test get_grades_report. + */ + public function test_get_grades_report() { + global $DB; + + $workshop = new workshop($this->workshop, $this->cm, $this->course); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id); + $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id); + + $assessmentid1 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array( + 'weight' => 100, + 'grade' => 50, + )); + $assessmentid2 = $workshopgenerator->create_assessment($submissionid1, $this->anotherstudentg1->id, array( + 'weight' => 100, + 'grade' => 55, + )); + + $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id)); + $this->setUser($this->teacher); + $result = mod_workshop_external::get_grades_report($this->workshop->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result); + $this->assertEquals(3, $result['report']['totalcount']); // Expect 3 potential submissions. + + foreach ($result['report']['grades'] as $grade) { + if ($grade['userid'] == $this->student->id) { + $this->assertEquals($this->anotherstudentg1->id, $grade['reviewedby'][0]['userid']); // Check reviewer. + $this->assertEquals($this->anotherstudentg1->id, $grade['reviewerof'][0]['userid']); // Check reviewer. + $this->assertEquals($workshop->real_grade(50), $grade['reviewerof'][0]['grade']); // Check grade (converted). + $this->assertEquals($workshop->real_grade(55), $grade['reviewedby'][0]['grade']); // Check grade (converted). + } else if ($grade['userid'] == $this->anotherstudentg1->id) { + $this->assertEquals($this->student->id, $grade['reviewedby'][0]['userid']); // Check reviewer. + $this->assertEquals($this->student->id, $grade['reviewerof'][0]['userid']); // Check reviewer. + $this->assertEquals($workshop->real_grade(55), $grade['reviewerof'][0]['grade']); // Check grade (converted). + $this->assertEquals($workshop->real_grade(50), $grade['reviewedby'][0]['grade']); // Check grade (converted). + } + } + // Now check pagination. + $result = mod_workshop_external::get_grades_report($this->workshop->id, 0, 'lastname', 'ASC', 0, 1); + $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result); + $this->assertEquals(3, $result['report']['totalcount']); // Expect the total count. + $this->assertCount(1, $result['report']['grades']); + + // Groups filtering. + $result = mod_workshop_external::get_grades_report($this->workshop->id, $this->group1->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result); + $this->assertEquals(2, $result['report']['totalcount']); // Expect the group count. + } + + /** + * Test get_grades_report_invalid_phase. + */ + public function test_get_grades_report_invalid_phase() { + $this->setUser($this->teacher); + $this->expectException('moodle_exception'); + $this->expectExceptionMessage(get_string('nothingfound', 'workshop')); + mod_workshop_external::get_grades_report($this->workshop->id); + } + + /** + * Test get_grades_report_missing_permissions. + */ + public function test_get_grades_report_missing_permissions() { + $this->setUser($this->student); + $this->expectException('required_capability_exception'); + mod_workshop_external::get_grades_report($this->workshop->id); + } } diff --git a/mod/workshop/version.php b/mod/workshop/version.php index 001cf8a44d4..bb1bc3a7b6e 100644 --- a/mod/workshop/version.php +++ b/mod/workshop/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2017051516; // The current module version (YYYYMMDDXX) +$plugin->version = 2017051517; // The current module version (YYYYMMDDXX) $plugin->requires = 2017050500; // Requires this Moodle version. $plugin->component = 'mod_workshop'; $plugin->cron = 60; // Give as a chance every minute. -- 2.43.0