MDL-59248 mod_workshop: New WS get_assessment_form_definition
authorJuan Leyva <juanleyvadelgado@gmail.com>
Tue, 27 Jun 2017 12:18:24 +0000 (13:18 +0100)
committerJuan Leyva <juanleyvadelgado@gmail.com>
Tue, 3 Oct 2017 06:51:30 +0000 (08:51 +0200)
mod/workshop/classes/external.php
mod/workshop/db/services.php
mod/workshop/form/assessment_form.php
mod/workshop/locallib.php
mod/workshop/tests/external_test.php
mod/workshop/version.php

index 78955bd..6a94cf1 100644 (file)
@@ -1187,4 +1187,137 @@ class mod_workshop_external extends external_api {
             )
         );
     }
+
+    /**
+     * Returns the description of the external function parameters.
+     *
+     * @return external_function_parameters
+     * @since Moodle 3.4
+     */
+    public static function get_assessment_form_definition_parameters() {
+        return new external_function_parameters(
+            array(
+                'assessmentid' => new external_value(PARAM_INT, 'Assessment id'),
+                'mode' => new external_value(PARAM_ALPHA, 'The form mode (assessment or preview)', VALUE_DEFAULT, 'assessment'),
+            )
+        );
+    }
+
+
+    /**
+     * Retrieves the assessment form definition (data required to be able to display the assessment form).
+     *
+     * @param int $assessmentid the assessment id
+     * @param string $mode the form mode (assessment or preview)
+     * @return array containing the assessment and warnings.
+     * @since Moodle 3.4
+     * @throws moodle_exception
+     */
+    public static function get_assessment_form_definition($assessmentid, $mode = 'assessment') {
+        global $DB, $USER;
+
+        $params = self::validate_parameters(
+            self::get_assessment_form_definition_parameters(), array('assessmentid' => $assessmentid, 'mode' => $mode)
+        );
+        $warnings = $pending = array();
+
+        if ($params['mode'] != 'assessment' && $params['mode'] != 'preview') {
+            throw new invalid_parameter_exception('Invalid value for mode parameter (value: ' . $params['mode'] . ')');
+        }
+
+        // Get and validate the assessment, submission and workshop.
+        $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
+        $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
+        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
+
+        // Check we can edit the assessment (so we can get the form data).
+        $workshop->check_edit_assessment($assessment, $submission);
+
+        $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
+        $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
+
+        // Retrieve the data from the strategy plugin.
+        $strategy = $workshop->grading_strategy_instance();
+        $strategyname = str_replace('_strategy', '', get_class($strategy)); // Get strategy name.
+        $mform = $strategy->get_assessment_form(null, $params['mode'], $assessment, true,
+            array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
+        $formdata = $mform->get_customdata();
+
+        $result = array(
+            'dimenssionscount' => $formdata['nodims'],
+            'descriptionfiles' => external_util::get_area_files($context->id, $strategyname, 'description'),
+            'warnings' => $warnings
+        );
+        // Include missing dimension fields.
+        for ($i = 0; $i < $formdata['nodims']; $i++) {
+            $formdata['fields']->{'gradeid__idx_' . $i} = 0;
+            $formdata['fields']->{'peercomment__idx_' . $i} = '';
+        }
+
+        // Convert all the form data for external.
+        foreach (array('options', 'fields', 'current') as $typeofdata) {
+            $result[$typeofdata] = array();
+
+            if (!empty($formdata[$typeofdata])) {
+                $alldata = (array) $formdata[$typeofdata];
+                foreach ($alldata as $key => $val) {
+                    if (strpos($key, 'peercomment__idx_') === 0) {
+                        // Format reviewer comment.
+                        list($val, $format) = external_format_text($val, FORMAT_MOODLE, $context->id);
+                    } else if (strpos($key, 'description__idx_')) {
+                        // Format dimension description.
+                        $id = str_replace('description__idx_', '', $key);
+                        list($val, $format) = external_format_text($val, $alldata['dimensionid__idx_' . $id . 'format'],
+                            $context->id, $strategyname, 'description', $alldata['dimensionid__idx_' . $id]);
+                    }
+                    $result[$typeofdata][] = array(
+                        'name' => $key,
+                        'value' => $val
+                    );
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns description of method result value
+     *
+     * @return external_description
+     * @since Moodle 3.4
+     */
+    public static function get_assessment_form_definition_returns() {
+        return new external_single_structure(
+            array(
+                'dimenssionscount' => new external_value(PARAM_INT, 'The number of dimenssions used by the form.'),
+                'descriptionfiles' => new external_files('Files in the description text'),
+                'options' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'name' => new external_value(PARAM_ALPHANUMEXT, 'Option name.'),
+                            'value' => new external_value(PARAM_NOTAGS, 'Option value.')
+                        )
+                    ), 'The form options.'
+                ),
+                'fields' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
+                            'value' => new external_value(PARAM_RAW, 'Field default value.')
+                        )
+                    ), 'The form fields.'
+                ),
+                'current' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
+                            'value' => new external_value(PARAM_RAW, 'Current field value.')
+                        )
+                    ), 'The current field values.'
+                ),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
 }
index 341e017..94b4c19 100644 (file)
@@ -113,4 +113,11 @@ $functions = array(
         'type'          => 'read',
         'services'      => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
     ),
+    'mod_workshop_get_assessment_form_definition' => array(
+        'classname'     => 'mod_workshop_external',
+        'methodname'    => 'get_assessment_form_definition',
+        'description'   => 'Retrieves the assessment form definition.',
+        'type'          => 'read',
+        'services'      => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
+    ),
 );
index 56128dc..4f7ba99 100644 (file)
@@ -120,4 +120,14 @@ class workshop_assessment_form extends moodleform {
     public function is_editable() {
         return !$this->_form->isFrozen();
     }
+
+    /**
+     * Return the form custom data.
+     *
+     * @return array an array containing the custom data
+     * @since  Moodle 3.4
+     */
+    public function get_customdata() {
+        return $this->_customdata;
+    }
 }
index 383ce61..ac243f2 100644 (file)
@@ -2998,6 +2998,33 @@ class workshop {
         }
     }
 
+    /**
+     * Helper method for validating if the current user can edit the given assessment.
+     *
+     * @param  stdClass   $assessment assessment object
+     * @param  stdClass   $submission submission object
+     * @return void
+     * @throws moodle_exception
+     * @since  Moodle 3.4
+     */
+    public function check_edit_assessment($assessment, $submission) {
+        global $USER;
+
+        $this->check_view_assessment($assessment, $submission);
+        // Further checks.
+        $isreviewer = ($USER->id == $assessment->reviewerid);
+
+        $assessmenteditable = $isreviewer && $this->assessing_allowed($USER->id);
+        if (!$assessmenteditable) {
+            throw new moodle_exception('nopermissions', 'error', '', 'edit assessments');
+        }
+
+        list($assessed, $notice) = $this->check_examples_assessed_before_assessment($assessment->reviewerid);
+        if (!$assessed) {
+            throw new moodle_exception($notice, 'mod_workshop');
+        }
+    }
+
     ////////////////////////////////////////////////////////////////////////////////
     // Internal methods (implementation details)                                  //
     ////////////////////////////////////////////////////////////////////////////////
index 5992fe5..c319b0a 100644 (file)
@@ -79,6 +79,20 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase {
         $this->context = context_module::instance($this->workshop->cmid);
         $this->cm = get_coursemodule_from_instance('workshop', $this->workshop->id);
 
+        // Add grading strategy data (accumulative is the default).
+        $workshop = new workshop($this->workshop, $this->cm, $this->course);
+        $strategy = $workshop->grading_strategy_instance();
+        $data = array();
+        for ($i = 0; $i < 4; $i++) {
+            $data['dimensionid__idx_'.$i] = 0;
+            $data['description__idx_'.$i.'_editor'] = array('text' => "Content $i", 'format' => FORMAT_MOODLE);
+            $data['grade__idx_'.$i] = 25;
+            $data['weight__idx_'.$i] = 25;
+        }
+        $data['workshopid'] = $workshop->id;
+        $data['norepeats'] = 4;
+        $strategy->save_edit_strategy_form((object) $data);
+
         // Create users.
         $this->student = self::getDataGenerator()->create_user();
         $this->anotherstudentg1 = self::getDataGenerator()->create_user();
@@ -343,7 +357,7 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase {
         $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') {
+            if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform') {
                 $this->assertEquals(1, $task['completed']);
             } else {
                 $this->assertEmpty($task['completed']);
@@ -357,7 +371,8 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase {
         $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') {
+            if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform' ||
+                    $task['code'] == 'switchtonextphase') {
                 $this->assertEquals(1, $task['completed']);
             } else {
                 $this->assertEmpty($task['completed']);
@@ -1266,4 +1281,69 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase {
         $this->setExpectedException('moodle_exception');
         mod_workshop_external::get_assessment($assessmentid);
     }
+
+    /**
+     * Test get_assessment_form_definition_reviewer_new_assessment.
+     */
+    public function test_get_assessment_form_definition_reviewer_new_assessment() {
+        global $DB;
+
+        // Create the submission.
+        $submissionid = $this->create_test_submission($this->anotherstudentg1);
+
+        $workshop = new workshop($this->workshop, $this->cm, $this->course);
+        $submission = $workshop->get_submission_by_id($submissionid);
+        $assessmentid = $workshop->add_allocation($submission, $this->student->id);
+
+        // Switch to assessment phase.
+        $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
+        $this->setUser($this->student);
+        $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
+        $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
+        $this->assertEquals(4, $result['dimenssionscount']);    // We receive the expected 4 dimensions.
+        $this->assertEmpty($result['current']); // Assessment not yet done.
+        foreach ($result['fields'] as $field) {
+            if (strpos($field['name'], 'grade__idx_') === 0) {
+                $this->assertEquals(25, $field['value']); // Check one of the dimension fields attributes.
+            }
+        }
+    }
+
+    /**
+     * Test get_assessment_form_definition_teacher_new_assessment.
+     */
+    public function test_get_assessment_form_definition_teacher_new_assessment() {
+        global $DB;
+
+        // Create the submission.
+        $submissionid = $this->create_test_submission($this->anotherstudentg1);
+
+        $workshop = new workshop($this->workshop, $this->cm, $this->course);
+        $submission = $workshop->get_submission_by_id($submissionid);
+        $assessmentid = $workshop->add_allocation($submission, $this->student->id);
+
+        // Switch to assessment phase.
+        $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
+        $this->setUser($this->teacher);
+        $this->setExpectedException('moodle_exception');
+        mod_workshop_external::get_assessment_form_definition($assessmentid);   // Teachers can't add/edit assessments.
+    }
+
+    /**
+     * Test get_assessment_form_definition_invalid_phase.
+     */
+    public function test_get_assessment_form_definition_invalid_phase() {
+        global $DB;
+
+        // Create the submission.
+        $submissionid = $this->create_test_submission($this->anotherstudentg1);
+
+        $workshop = new workshop($this->workshop, $this->cm, $this->course);
+        $submission = $workshop->get_submission_by_id($submissionid);
+        $assessmentid = $workshop->add_allocation($submission, $this->student->id);
+
+        $this->setUser($this->student);
+        $this->setExpectedException('moodle_exception');
+        mod_workshop_external::get_assessment_form_definition($assessmentid);
+    }
 }
index 487445b..6bb09d7 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017051511;        // The current module version (YYYYMMDDXX)
+$plugin->version   = 2017051512;        // 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.