diff --git a/mod/assign/db/services.php b/mod/assign/db/services.php index 4d8ab30f1e4..1fe8cd2c9c4 100644 --- a/mod/assign/db/services.php +++ b/mod/assign/db/services.php @@ -47,5 +47,21 @@ $functions = array( 'classpath' => 'mod/assign/externallib.php', 'description' => 'Returns the submissions for assignments', 'type' => 'read' + ), + + 'mod_assign_get_user_flags' => array( + 'classname' => 'mod_assign_external', + 'methodname' => 'get_user_flags', + 'classpath' => 'mod/assign/externallib.php', + 'description' => 'Returns the user flags for assignments', + 'type' => 'read' + ), + + 'mod_assign_get_user_mappings' => array( + 'classname' => 'mod_assign_external', + 'methodname' => 'get_user_mappings', + 'classpath' => 'mod/assign/externallib.php', + 'description' => 'Returns the blind marking mappings for assignments', + 'type' => 'read' ) ); diff --git a/mod/assign/externallib.php b/mod/assign/externallib.php index 7c29a61b0d3..2b03f0737e0 100644 --- a/mod/assign/externallib.php +++ b/mod/assign/externallib.php @@ -697,4 +697,302 @@ class mod_assign_external extends external_api { ) ); } + + /** + * Describes the parameters for get_user_flags + * @return external_function_parameters + * @since Moodle 2.6 + */ + public static function get_user_flags_parameters() { + return new external_function_parameters( + array( + 'assignmentids' => new external_multiple_structure( + new external_value(PARAM_INT, 'assignment id'), + '1 or more assignment ids', + VALUE_REQUIRED) + ) + ); + } + + /** + * Returns user flag information from assign_user_flags for the requested assignment ids + * @param array of ints $assignmentids + * @return array of user flag records for each requested assignment + * @since Moodle 2.6 + */ + public static function get_user_flags($assignmentids) { + global $DB; + $params = self::validate_parameters(self::get_user_flags_parameters(), + array('assignmentids' => $assignmentids)); + + $assignments = array(); + $warnings = array(); + $requestedassignmentids = $params['assignmentids']; + + // Check the user is allowed to get the user flags for the assignments requested. + $placeholders = array(); + list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED); + $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ". + "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids; + $placeholders['modname'] = 'assign'; + $cms = $DB->get_records_sql($sql, $placeholders); + foreach ($cms as $cm) { + try { + $context = context_module::instance($cm->id); + self::validate_context($context); + require_capability('mod/assign:grade', $context); + } catch (Exception $e) { + $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance)); + $warning = array(); + $warning['item'] = 'assignment'; + $warning['itemid'] = $cm->instance; + $warning['warningcode'] = '1'; + $warning['message'] = 'No access rights in module context'; + $warnings[] = $warning; + } + } + + // Create the query and populate an array of assign_user_flags records from the recordset results. + if (count ($requestedassignmentids) > 0) { + $placeholders = array(); + list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED); + + $sql = "SELECT auf.id,auf.assignment,auf.userid,auf.locked,auf.mailed,". + "auf.extensionduedate,auf.workflowstate,auf.allocatedmarker ". + "FROM {assign_user_flags} auf ". + "WHERE auf.assignment ".$inorequalsql. + " ORDER BY auf.assignment, auf.id"; + + $rs = $DB->get_recordset_sql($sql, $placeholders); + $currentassignmentid = null; + $assignment = null; + foreach ($rs as $rd) { + $userflag = array(); + $userflag['id'] = $rd->id; + $userflag['userid'] = $rd->userid; + $userflag['locked'] = $rd->locked; + $userflag['mailed'] = $rd->mailed; + $userflag['extensionduedate'] = $rd->extensionduedate; + $userflag['workflowstate'] = $rd->workflowstate; + $userflag['allocatedmarker'] = $rd->allocatedmarker; + + if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) { + if (!is_null($assignment)) { + $assignments[] = $assignment; + } + $assignment = array(); + $assignment['assignmentid'] = $rd->assignment; + $assignment['userflags'] = array(); + $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment)); + } + $assignment['userflags'][] = $userflag; + + $currentassignmentid = $rd->assignment; + } + if (!is_null($assignment)) { + $assignments[] = $assignment; + } + $rs->close(); + + } + + foreach ($requestedassignmentids as $assignmentid) { + $warning = array(); + $warning['item'] = 'assignment'; + $warning['itemid'] = $assignmentid; + $warning['warningcode'] = '3'; + $warning['message'] = 'No user flags found'; + $warnings[] = $warning; + } + + $result = array(); + $result['assignments'] = $assignments; + $result['warnings'] = $warnings; + return $result; + } + + /** + * Creates an assign_user_flags external_single_structure + * @return external_single_structure + * @since Moodle 2.6 + */ + private static function assign_user_flags() { + return new external_single_structure( + array ( + 'assignmentid' => new external_value(PARAM_INT, 'assignment id'), + 'userflags' => new external_multiple_structure(new external_single_structure( + array( + 'id' => new external_value(PARAM_INT, 'user flag id'), + 'userid' => new external_value(PARAM_INT, 'student id'), + 'locked' => new external_value(PARAM_INT, 'locked'), + 'mailed' => new external_value(PARAM_INT, 'mailed'), + 'extensionduedate' => new external_value(PARAM_INT, 'extension due date'), + 'workflowstate' => new external_value(PARAM_TEXT, 'marking workflow state', VALUE_OPTIONAL), + 'allocatedmarker' => new external_value(PARAM_INT, 'allocated marker') + ) + ) + ) + ) + ); + } + + /** + * Describes the get_user_flags return value + * @return external_single_structure + * @since Moodle 2.6 + */ + public static function get_user_flags_returns() { + return new external_single_structure( + array( + 'assignments' => new external_multiple_structure(self::assign_user_flags(), 'list of assign user flag information'), + 'warnings' => new external_warnings('item is always \'assignment\'', + 'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id', + 'errorcode can be 3 (no user flags found) or 1 (no permission to get user flags)') + ) + ); + } + + /** + * Describes the parameters for get_user_mappings + * @return external_function_parameters + * @since Moodle 2.6 + */ + public static function get_user_mappings_parameters() { + return new external_function_parameters( + array( + 'assignmentids' => new external_multiple_structure( + new external_value(PARAM_INT, 'assignment id'), + '1 or more assignment ids', + VALUE_REQUIRED) + ) + ); + } + + /** + * Returns user mapping information from assign_user_mapping for the requested assignment ids + * @param array of ints $assignmentids + * @return array of user mapping records for each requested assignment + * @since Moodle 2.6 + */ + public static function get_user_mappings($assignmentids) { + global $DB; + $params = self::validate_parameters(self::get_user_mappings_parameters(), + array('assignmentids' => $assignmentids)); + + $assignments = array(); + $warnings = array(); + $requestedassignmentids = $params['assignmentids']; + + // Check the user is allowed to get the mappings for the assignments requested. + $placeholders = array(); + list($sqlassignmentids, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED); + $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ". + "WHERE md.name = :modname AND cm.instance ".$sqlassignmentids; + $placeholders['modname'] = 'assign'; + $cms = $DB->get_records_sql($sql, $placeholders); + foreach ($cms as $cm) { + try { + $context = context_module::instance($cm->id); + self::validate_context($context); + require_capability('mod/assign:revealidentities', $context); + } catch (Exception $e) { + $requestedassignmentids = array_diff($requestedassignmentids, array($cm->instance)); + $warning = array(); + $warning['item'] = 'assignment'; + $warning['itemid'] = $cm->instance; + $warning['warningcode'] = '1'; + $warning['message'] = 'No access rights in module context'; + $warnings[] = $warning; + } + } + + // Create the query and populate an array of assign_user_mapping records from the recordset results. + if (count ($requestedassignmentids) > 0) { + $placeholders = array(); + list($inorequalsql, $placeholders) = $DB->get_in_or_equal($requestedassignmentids, SQL_PARAMS_NAMED); + + $sql = "SELECT aum.id,aum.assignment,aum.userid ". + "FROM {assign_user_mapping} aum ". + "WHERE aum.assignment ".$inorequalsql. + " ORDER BY aum.assignment, aum.id"; + + $rs = $DB->get_recordset_sql($sql, $placeholders); + $currentassignmentid = null; + $assignment = null; + foreach ($rs as $rd) { + $mapping = array(); + $mapping['id'] = $rd->id; + $mapping['userid'] = $rd->userid; + + if (is_null($currentassignmentid) || ($rd->assignment != $currentassignmentid )) { + if (!is_null($assignment)) { + $assignments[] = $assignment; + } + $assignment = array(); + $assignment['assignmentid'] = $rd->assignment; + $assignment['mappings'] = array(); + $requestedassignmentids = array_diff($requestedassignmentids, array($rd->assignment)); + } + $assignment['mappings'][] = $mapping; + + $currentassignmentid = $rd->assignment; + } + if (!is_null($assignment)) { + $assignments[] = $assignment; + } + $rs->close(); + + } + + foreach ($requestedassignmentids as $assignmentid) { + $warning = array(); + $warning['item'] = 'assignment'; + $warning['itemid'] = $assignmentid; + $warning['warningcode'] = '3'; + $warning['message'] = 'No mappings found'; + $warnings[] = $warning; + } + + $result = array(); + $result['assignments'] = $assignments; + $result['warnings'] = $warnings; + return $result; + } + + /** + * Creates an assign_user_mappings external_single_structure + * @return external_single_structure + * @since Moodle 2.6 + */ + private static function assign_user_mappings() { + return new external_single_structure( + array ( + 'assignmentid' => new external_value(PARAM_INT, 'assignment id'), + 'mappings' => new external_multiple_structure(new external_single_structure( + array( + 'id' => new external_value(PARAM_INT, 'user mapping id'), + 'userid' => new external_value(PARAM_INT, 'student id') + ) + ) + ) + ) + ); + } + + /** + * Describes the get_user_mappings return value + * @return external_single_structure + * @since Moodle 2.6 + */ + public static function get_user_mappings_returns() { + return new external_single_structure( + array( + 'assignments' => new external_multiple_structure(self::assign_user_mappings(), 'list of assign user mapping data'), + 'warnings' => new external_warnings('item is always \'assignment\'', + 'when errorcode is 3 then itemid is an assignment id. When errorcode is 1, itemid is a course module id', + 'errorcode can be 3 (no user mappings found) or 1 (no permission to get user mappings)') + ) + ); + } + } diff --git a/mod/assign/tests/externallib_test.php b/mod/assign/tests/externallib_test.php index df21515a6c5..45823ff24f0 100644 --- a/mod/assign/tests/externallib_test.php +++ b/mod/assign/tests/externallib_test.php @@ -58,10 +58,10 @@ class mod_assign_external_testcase extends externallib_advanced_testcase { $assign = self::getDataGenerator()->create_module('assign', $assigndata); // Create a manual enrolment record. - $manual_enrol_data['enrol'] = 'manual'; - $manual_enrol_data['status'] = 0; - $manual_enrol_data['courseid'] = $course->id; - $enrolid = $DB->insert_record('enrol', $manual_enrol_data); + $manualenroldata['enrol'] = 'manual'; + $manualenroldata['status'] = 0; + $manualenroldata['courseid'] = $course->id; + $enrolid = $DB->insert_record('enrol', $manualenroldata); // Create a teacher and give them capabilities. $context = context_course::instance($course->id); @@ -70,10 +70,10 @@ class mod_assign_external_testcase extends externallib_advanced_testcase { $this->assignUserCapability('mod/assign:grade', $context->id, $roleid); // Create the teacher's enrolment record. - $user_enrolment_data['status'] = 0; - $user_enrolment_data['enrolid'] = $enrolid; - $user_enrolment_data['userid'] = $USER->id; - $DB->insert_record('user_enrolments', $user_enrolment_data); + $userenrolmentdata['status'] = 0; + $userenrolmentdata['enrolid'] = $enrolid; + $userenrolmentdata['userid'] = $USER->id; + $DB->insert_record('user_enrolments', $userenrolmentdata); // Create a student and give them 2 grades (for 2 attempts). $student = self::getDataGenerator()->create_user(); @@ -259,10 +259,10 @@ class mod_assign_external_testcase extends externallib_advanced_testcase { $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission); // Create manual enrolment record. - $manual_enrol_data['enrol'] = 'manual'; - $manual_enrol_data['status'] = 0; - $manual_enrol_data['courseid'] = $course1->id; - $enrolid = $DB->insert_record('enrol', $manual_enrol_data); + $manualenroldata['enrol'] = 'manual'; + $manualenroldata['status'] = 0; + $manualenroldata['courseid'] = $course1->id; + $enrolid = $DB->insert_record('enrol', $manualenroldata); // Create a teacher and give them capabilities. $context = context_course::instance($course1->id); @@ -271,10 +271,10 @@ class mod_assign_external_testcase extends externallib_advanced_testcase { $this->assignUserCapability('mod/assign:grade', $context->id, $roleid); // Create the teacher's enrolment record. - $user_enrolment_data['status'] = 0; - $user_enrolment_data['enrolid'] = $enrolid; - $user_enrolment_data['userid'] = $USER->id; - $DB->insert_record('user_enrolments', $user_enrolment_data); + $userenrolmentdata['status'] = 0; + $userenrolmentdata['enrolid'] = $enrolid; + $userenrolmentdata['userid'] = $USER->id; + $DB->insert_record('user_enrolments', $userenrolmentdata); $assignmentids[] = $assign1->id; $result = mod_assign_external::get_submissions($assignmentids); @@ -297,4 +297,137 @@ class mod_assign_external_testcase extends externallib_advanced_testcase { } $this->assertTrue($foundonlinetext); } + + /** + * Test get_user_flags + */ + public function test_get_user_flags () { + global $DB, $USER; + + $this->resetAfterTest(true); + // Create a course and assignment. + $coursedata['idnumber'] = 'idnumbercourse'; + $coursedata['fullname'] = 'Lightwork Course'; + $coursedata['summary'] = 'Lightwork Course description'; + $coursedata['summaryformat'] = FORMAT_MOODLE; + $course = self::getDataGenerator()->create_course($coursedata); + + $assigndata['course'] = $course->id; + $assigndata['name'] = 'lightwork assignment'; + + $assign = self::getDataGenerator()->create_module('assign', $assigndata); + + // Create a manual enrolment record. + $manualenroldata['enrol'] = 'manual'; + $manualenroldata['status'] = 0; + $manualenroldata['courseid'] = $course->id; + $enrolid = $DB->insert_record('enrol', $manualenroldata); + + // Create a teacher and give them capabilities. + $context = context_course::instance($course->id); + $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3); + $context = context_module::instance($assign->id); + $this->assignUserCapability('mod/assign:grade', $context->id, $roleid); + + // Create the teacher's enrolment record. + $userenrolmentdata['status'] = 0; + $userenrolmentdata['enrolid'] = $enrolid; + $userenrolmentdata['userid'] = $USER->id; + $DB->insert_record('user_enrolments', $userenrolmentdata); + + // Create a student and give them a user flag record. + $student = self::getDataGenerator()->create_user(); + $userflag = new stdClass(); + $userflag->assignment = $assign->id; + $userflag->userid = $student->id; + $userflag->locked = 0; + $userflag->mailed = 0; + $userflag->extensionduedate = 0; + $userflag->workflowstate = 'inmarking'; + $userflag->allocatedmarker = $USER->id; + + $DB->insert_record('assign_user_flags', $userflag); + + $assignmentids[] = $assign->id; + $result = mod_assign_external::get_user_flags($assignmentids); + + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(mod_assign_external::get_user_flags_returns(), $result); + + // Check that the correct user flag information for the student is returned. + $this->assertEquals(1, count($result['assignments'])); + $assignment = $result['assignments'][0]; + $this->assertEquals($assign->id, $assignment['assignmentid']); + // Should be one user flag record. + $this->assertEquals(1, count($assignment['userflags'])); + $userflag = $assignment['userflags'][0]; + $this->assertEquals($student->id, $userflag['userid']); + $this->assertEquals(0, $userflag['locked']); + $this->assertEquals(0, $userflag['mailed']); + $this->assertEquals(0, $userflag['extensionduedate']); + $this->assertEquals('inmarking', $userflag['workflowstate']); + $this->assertEquals($USER->id, $userflag['allocatedmarker']); + } + + /** + * Test get_user_mappings + */ + public function test_get_user_mappings () { + global $DB, $USER; + + $this->resetAfterTest(true); + // Create a course and assignment. + $coursedata['idnumber'] = 'idnumbercourse'; + $coursedata['fullname'] = 'Lightwork Course'; + $coursedata['summary'] = 'Lightwork Course description'; + $coursedata['summaryformat'] = FORMAT_MOODLE; + $course = self::getDataGenerator()->create_course($coursedata); + + $assigndata['course'] = $course->id; + $assigndata['name'] = 'lightwork assignment'; + + $assign = self::getDataGenerator()->create_module('assign', $assigndata); + + // Create a manual enrolment record. + $manualenroldata['enrol'] = 'manual'; + $manualenroldata['status'] = 0; + $manualenroldata['courseid'] = $course->id; + $enrolid = $DB->insert_record('enrol', $manualenroldata); + + // Create a teacher and give them capabilities. + $context = context_course::instance($course->id); + $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3); + $context = context_module::instance($assign->id); + $this->assignUserCapability('mod/assign:revealidentities', $context->id, $roleid); + + // Create the teacher's enrolment record. + $userenrolmentdata['status'] = 0; + $userenrolmentdata['enrolid'] = $enrolid; + $userenrolmentdata['userid'] = $USER->id; + $DB->insert_record('user_enrolments', $userenrolmentdata); + + // Create a student and give them a user mapping record. + $student = self::getDataGenerator()->create_user(); + $mapping = new stdClass(); + $mapping->assignment = $assign->id; + $mapping->userid = $student->id; + + $DB->insert_record('assign_user_mapping', $mapping); + + $assignmentids[] = $assign->id; + $result = mod_assign_external::get_user_mappings($assignmentids); + + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(mod_assign_external::get_user_mappings_returns(), $result); + + // Check that the correct user mapping information for the student is returned. + $this->assertEquals(1, count($result['assignments'])); + $assignment = $result['assignments'][0]; + $this->assertEquals($assign->id, $assignment['assignmentid']); + // Should be one user mapping record. + $this->assertEquals(1, count($assignment['mappings'])); + $mapping = $assignment['mappings'][0]; + $this->assertEquals($student->id, $mapping['userid']); + } + } diff --git a/mod/assign/version.php b/mod/assign/version.php index d98fd51c010..7b06f0d62b4 100644 --- a/mod/assign/version.php +++ b/mod/assign/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); $module->component = 'mod_assign'; // Full name of the plugin (used for diagnostics). -$module->version = 2013070901; // The current module version (Date: YYYYMMDDXX). +$module->version = 2013070902; // The current module version (Date: YYYYMMDDXX). $module->requires = 2013050100; // Requires this Moodle version. $module->cron = 60;