diff --git a/mod/workshop/classes/external.php b/mod/workshop/classes/external.php index 52fe32af5c1..788fb37ff3f 100644 --- a/mod/workshop/classes/external.php +++ b/mod/workshop/classes/external.php @@ -231,4 +231,138 @@ class mod_workshop_external extends external_api { return new external_single_structure($structure); } + + /** + * Describes the parameters for get_user_plan. + * + * @return external_external_function_parameters + * @since Moodle 3.4 + */ + public static function get_user_plan_parameters() { + return new external_function_parameters ( + array( + 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'), + 'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0), + ) + ); + } + + /** + * Return the planner information for the given user. + * + * @param int $workshopid workshop instance id + * @param int $userid user id + * @return array of warnings and the user plan + * @since Moodle 3.4 + * @throws moodle_exception + */ + public static function get_user_plan($workshopid, $userid = 0) { + global $USER; + + $params = array( + 'workshopid' => $workshopid, + 'userid' => $userid, + ); + $params = self::validate_parameters(self::get_user_plan_parameters(), $params); + + list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']); + + // Extra checks so only users with permissions can view other users plans. + if (empty($params['userid']) || $params['userid'] == $USER->id) { + $userid = $USER->id; + } else { + require_capability('moodle/course:manageactivities', $context); + $user = core_user::get_user($params['userid'], '*', MUST_EXIST); + core_user::require_active_user($user); + if (!$workshop->check_group_membership($user->id)) { + throw new moodle_exception('notingroup'); + } + $userid = $user->id; + } + + // Get the user plan information ready for external functions. + $userplan = new workshop_user_plan($workshop, $userid); + $userplan = array('phases' => $userplan->phases, 'examples' => $userplan->get_examples()); + foreach ($userplan['phases'] as $phasecode => $phase) { + $phase->code = $phasecode; + $userplan['phases'][$phasecode] = (array) $phase; + foreach ($userplan['phases'][$phasecode]['tasks'] as $taskcode => $task) { + $task->code = $taskcode; + if ($task->link instanceof moodle_url) { + $task->link = $task->link->out(false); + } + $userplan['phases'][$phasecode]['tasks'][$taskcode] = (array) $task; + } + foreach ($userplan['phases'][$phasecode]['actions'] as $actioncode => $action) { + if ($action->url instanceof moodle_url) { + $action->url = $action->url->out(false); + } + $userplan['phases'][$phasecode]['actions'][$actioncode] = (array) $action; + } + } + + $result['userplan'] = $userplan; + $result['warnings'] = array(); + return $result; + } + + /** + * Describes the get_user_plan return value. + * + * @return external_single_structure + * @since Moodle 3.4 + */ + public static function get_user_plan_returns() { + return new external_single_structure( + array( + 'userplan' => new external_single_structure( + array( + 'phases' => new external_multiple_structure( + new external_single_structure( + array( + 'code' => new external_value(PARAM_INT, 'Phase code.'), + 'title' => new external_value(PARAM_NOTAGS, 'Phase title.'), + 'active' => new external_value(PARAM_BOOL, 'Whether is the active task.'), + 'tasks' => new external_multiple_structure( + new external_single_structure( + array( + 'code' => new external_value(PARAM_ALPHA, 'Task code.'), + 'title' => new external_value(PARAM_RAW, 'Task title.'), + 'link' => new external_value(PARAM_URL, 'Link to task.'), + 'details' => new external_value(PARAM_RAW, 'Task details.', VALUE_OPTIONAL), + 'completed' => new external_value(PARAM_NOTAGS, + 'Completion information (maybe empty, maybe a boolean or generic info.'), + ) + ) + ), + 'actions' => new external_multiple_structure( + new external_single_structure( + array( + 'type' => new external_value(PARAM_ALPHA, 'Action type.', VALUE_OPTIONAL), + 'label' => new external_value(PARAM_RAW, 'Action label.', VALUE_OPTIONAL), + 'url' => new external_value(PARAM_URL, 'Link to action.'), + 'method' => new external_value(PARAM_ALPHA, 'Get or post.', VALUE_OPTIONAL), + ) + ) + ), + ) + ) + ), + 'examples' => new external_multiple_structure( + new external_single_structure( + array( + 'id' => new external_value(PARAM_INT, 'Example submission id.'), + 'title' => new external_value(PARAM_RAW, 'Example submission title.'), + 'assessmentid' => new external_value(PARAM_INT, 'Example submission assessment id.'), + 'grade' => new external_value(PARAM_FLOAT, 'The submission grade.'), + 'gradinggrade' => new external_value(PARAM_FLOAT, 'The assessment grade.'), + ) + ) + ), + ) + ), + 'warnings' => new external_warnings(), + ) + ); + } } diff --git a/mod/workshop/db/services.php b/mod/workshop/db/services.php index 0da25d271be..f86b53fbe51 100644 --- a/mod/workshop/db/services.php +++ b/mod/workshop/db/services.php @@ -45,4 +45,12 @@ $functions = array( 'capabilities' => 'mod/workshop:view', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), + 'mod_workshop_get_user_plan' => array( + 'classname' => 'mod_workshop_external', + 'methodname' => 'get_user_plan', + 'description' => 'Return the planner information for the given user.', + 'type' => 'read', + 'capabilities' => 'mod/workshop:view', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + ), ); diff --git a/mod/workshop/tests/external_test.php b/mod/workshop/tests/external_test.php index 0156a3e0b7d..8d7f4071b9a 100644 --- a/mod/workshop/tests/external_test.php +++ b/mod/workshop/tests/external_test.php @@ -280,4 +280,74 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase { $this->assertFalse($result['assessingallowed']); $this->assertFalse($result['assessingexamplesallowed']); } + + /** + * Test mod_workshop_get_user_plan for students. + */ + public function test_mod_workshop_get_user_plan_student() { + + self::setUser($this->student); + $result = mod_workshop_external::get_user_plan($this->workshop->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result); + + $this->assertCount(0, $result['userplan']['examples']); // No examples given. + $this->assertCount(5, $result['userplan']['phases']); // Always 5 phases. + $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']); // First phase always setup. + $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops. + + // Switch phase. + $workshop = new workshop($this->workshop, $this->cm, $this->course); + $workshop->switch_phase(workshop::PHASE_SUBMISSION); + + $result = mod_workshop_external::get_user_plan($this->workshop->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result); + + $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']); + $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase. + } + + /** + * Test mod_workshop_get_user_plan for teachers. + */ + public function test_mod_workshop_get_user_plan_teacher() { + global $DB; + + self::setUser($this->teacher); + $result = mod_workshop_external::get_user_plan($this->workshop->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result); + + $this->assertCount(0, $result['userplan']['examples']); // No examples given. + $this->assertCount(5, $result['userplan']['phases']); // Always 5 phases. + $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']); // First phase always setup. + $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops. + $this->assertCount(4, $result['userplan']['phases'][0]['tasks']); // For new empty workshops, always 4 tasks. + + foreach ($result['userplan']['phases'][0]['tasks'] as $task) { + if ($task['code'] == 'intro' || $task['code'] == 'instructauthors') { + $this->assertEquals(1, $task['completed']); + } else { + $this->assertEmpty($task['completed']); + } + } + + // Do some of the tasks asked - switch phase. + $workshop = new workshop($this->workshop, $this->cm, $this->course); + $workshop->switch_phase(workshop::PHASE_SUBMISSION); + + $result = mod_workshop_external::get_user_plan($this->workshop->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result); + foreach ($result['userplan']['phases'][0]['tasks'] as $task) { + if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'switchtonextphase') { + $this->assertEquals(1, $task['completed']); + } else { + $this->assertEmpty($task['completed']); + } + } + + $result = mod_workshop_external::get_user_plan($this->workshop->id); + $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result); + + $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']); + $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase. + } } diff --git a/mod/workshop/version.php b/mod/workshop/version.php index 1de474ef1d2..68fff480ef7 100644 --- a/mod/workshop/version.php +++ b/mod/workshop/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2017051502; // The current module version (YYYYMMDDXX) +$plugin->version = 2017051503; // 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.