Merge branch 'MDL-59250-master' of git://github.com/jleyva/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 3 Oct 2017 16:34:56 +0000 (18:34 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 3 Oct 2017 16:34:56 +0000 (18:34 +0200)
mod/workshop/assessment.php
mod/workshop/classes/external.php
mod/workshop/db/services.php
mod/workshop/locallib.php
mod/workshop/tests/external_test.php
mod/workshop/version.php

index a4efdc7..23d2d27 100644 (file)
@@ -118,53 +118,8 @@ if (is_null($assessment->grade) and !$assessmenteditable) {
         redirect($workshop->view_url());
     } elseif ($assessmenteditable and ($data = $mform->get_data())) {
 
-        // Let the grading strategy subplugin save its data.
-        $rawgrade = $strategy->save_assessment($assessment, $data);
-
-        // Store the data managed by the workshop core.
-        $coredata = (object)array('id' => $assessment->id);
-        if (isset($data->feedbackauthor_editor)) {
-            $coredata->feedbackauthor_editor = $data->feedbackauthor_editor;
-            $coredata = file_postupdate_standard_editor($coredata, 'feedbackauthor', $workshop->overall_feedback_content_options(),
-                $workshop->context, 'mod_workshop', 'overallfeedback_content', $assessment->id);
-            unset($coredata->feedbackauthor_editor);
-        }
-        if (isset($data->feedbackauthorattachment_filemanager)) {
-            $coredata->feedbackauthorattachment_filemanager = $data->feedbackauthorattachment_filemanager;
-            $coredata = file_postupdate_standard_filemanager($coredata, 'feedbackauthorattachment',
-                $workshop->overall_feedback_attachment_options(), $workshop->context, 'mod_workshop', 'overallfeedback_attachment',
-                $assessment->id);
-            unset($coredata->feedbackauthorattachment_filemanager);
-            if (empty($coredata->feedbackauthorattachment)) {
-                $coredata->feedbackauthorattachment = 0;
-            }
-        }
-        if (isset($data->weight) and $cansetassessmentweight) {
-            $coredata->weight = $data->weight;
-        }
-        // Update the assessment data if there is something other than just the 'id'.
-        if (count((array)$coredata) > 1 ) {
-            $DB->update_record('workshop_assessments', $coredata);
-            $params = array(
-                'relateduserid' => $submission->authorid,
-                'objectid' => $assessment->id,
-                'context' => $workshop->context,
-                'other' => array(
-                    'workshopid' => $workshop->id,
-                    'submissionid' => $assessment->submissionid
-                )
-            );
-
-            if (is_null($assessment->grade)) {
-                // All workshop_assessments are created when allocations are made. The create event is of more use located here.
-                $event = \mod_workshop\event\submission_assessed::create($params);
-                $event->trigger();
-            } else {
-                $params['other']['grade'] = $assessment->grade;
-                $event = \mod_workshop\event\submission_reassessed::create($params);
-                $event->trigger();
-            }
-        }
+        // Add or update assessment.
+        $rawgrade = $workshop->edit_assessment($assessment, $submission, $data, $strategy);
 
         // And finally redirect the user's browser.
         if (!is_null($rawgrade) and isset($data->saveandclose)) {
index ae00327..220b216 100644 (file)
@@ -1412,4 +1412,132 @@ 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 update_assessment_parameters() {
+        return new external_function_parameters(
+            array(
+                'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'),
+                'data' => new external_multiple_structure (
+                    new external_single_structure(
+                        array(
+                            'name' => new external_value(PARAM_ALPHANUMEXT,
+                                'The assessment data (use WS get_assessment_form_definition for obtaining the data to sent).
+                                Apart from that data, you can optionally send:
+                                feedbackauthor (str); the feedback for the submission author
+                                feedbackauthorformat (int); the format of the feedbackauthor
+                                feedbackauthorinlineattachmentsid (int); the draft file area for the editor attachments
+                                feedbackauthorattachmentsid (int); the draft file area id for the feedback attachments'
+                            ),
+                            'value' => new external_value(PARAM_RAW, 'The value of the option.')
+                        )
+                    ), 'Assessment data'
+                )
+            )
+        );
+    }
+
+
+    /**
+     * Updates an assessment.
+     *
+     * @param int $assessmentid the assessment id
+     * @param array $data the assessment data
+     * @return array indicates if the assessment was updated, the new raw grade and possible warnings.
+     * @since Moodle 3.4
+     * @throws moodle_exception
+     */
+    public static function update_assessment($assessmentid, $data) {
+        global $DB, $USER;
+
+        $params = self::validate_parameters(
+            self::update_assessment_parameters(), array('assessmentid' => $assessmentid, 'data' => $data)
+        );
+        $warnings = array();
+
+        // 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.
+        $workshop->check_edit_assessment($assessment, $submission);
+
+        // Process data.
+        $data = new stdClass;
+        $data->feedbackauthor_editor = array();
+
+        foreach ($params['data'] as $wsdata) {
+            $name = trim($wsdata['name']);
+            switch ($name) {
+                case 'feedbackauthor':
+                    $data->feedbackauthor_editor['text'] = $wsdata['value'];
+                    break;
+                case 'feedbackauthorformat':
+                    $data->feedbackauthor_editor['format'] = clean_param($wsdata['value'], PARAM_FORMAT);
+                    break;
+                case 'feedbackauthorinlineattachmentsid':
+                    $data->feedbackauthor_editor['itemid'] = clean_param($wsdata['value'], PARAM_INT);
+                    break;
+                case 'feedbackauthorattachmentsid':
+                    $data->feedbackauthorattachment_filemanager = clean_param($wsdata['value'], PARAM_INT);
+                    break;
+                default:
+                    $data->{$wsdata['name']} = $wsdata['value'];    // Validation will be done in the form->validation.
+            }
+        }
+
+        $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();
+        $mform = $strategy->get_assessment_form(null, 'assessment', $assessment, true,
+            array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
+
+        $errors = $mform->validation((array) $data, array());
+        // We can get several errors, return them in warnings.
+        if (!empty($errors)) {
+            $status = false;
+            $rawgrade = null;
+            foreach ($errors as $itemname => $message) {
+                $warnings[] = array(
+                    'item' => $itemname,
+                    'itemid' => 0,
+                    'warningcode' => 'fielderror',
+                    'message' => s($message)
+                );
+            }
+        } else {
+            $rawgrade = $workshop->edit_assessment($assessment, $submission, $data, $strategy);
+            $status = true;
+        }
+
+        return array(
+            'status' => $status,
+            'rawgrade' => $rawgrade,
+            'warnings' => $warnings,
+        );
+    }
+
+    /**
+     * Returns description of method result value
+     *
+     * @return external_description
+     * @since Moodle 3.4
+     */
+    public static function update_assessment_returns() {
+        return new external_single_structure(
+            array(
+                'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was added or updated false otherwise.'),
+                'rawgrade' => new external_value(PARAM_FLOAT, 'Raw percentual grade (0.00000 to 100.00000) for submission.',
+                    VALUE_OPTIONAL),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
 }
index b97f3df..d262d15 100644 (file)
@@ -127,4 +127,11 @@ $functions = array(
         'type'          => 'read',
         'services'      => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
     ),
+    'mod_workshop_update_assessment' => array(
+        'classname'     => 'mod_workshop_external',
+        'methodname'    => 'update_assessment',
+        'description'   => 'Add information to an allocated assessment.',
+        'type'          => 'write',
+        'services'      => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
+    ),
 );
index ac243f2..c452c8b 100644 (file)
@@ -3025,6 +3025,71 @@ class workshop {
         }
     }
 
+    /**
+     * Adds information to an allocated assessment (function used the first time a review is done or when updating an existing one).
+     *
+     * @param  stdClass $assessment the assessment
+     * @param  stdClass $submission the submission
+     * @param  stdClass $data       the assessment data to be added or Updated
+     * @param  stdClass $strategy   the strategy instance
+     * @return float|null           Raw percentual grade (0.00000 to 100.00000) for submission
+     * @since  Moodle 3.4
+     */
+    public function edit_assessment($assessment, $submission, $data, $strategy) {
+        global $DB;
+
+        $cansetassessmentweight = has_capability('mod/workshop:allocate', $this->context);
+
+        // Let the grading strategy subplugin save its data.
+        $rawgrade = $strategy->save_assessment($assessment, $data);
+
+        // Store the data managed by the workshop core.
+        $coredata = (object)array('id' => $assessment->id);
+        if (isset($data->feedbackauthor_editor)) {
+            $coredata->feedbackauthor_editor = $data->feedbackauthor_editor;
+            $coredata = file_postupdate_standard_editor($coredata, 'feedbackauthor', $this->overall_feedback_content_options(),
+                $this->context, 'mod_workshop', 'overallfeedback_content', $assessment->id);
+            unset($coredata->feedbackauthor_editor);
+        }
+        if (isset($data->feedbackauthorattachment_filemanager)) {
+            $coredata->feedbackauthorattachment_filemanager = $data->feedbackauthorattachment_filemanager;
+            $coredata = file_postupdate_standard_filemanager($coredata, 'feedbackauthorattachment',
+                $this->overall_feedback_attachment_options(), $this->context, 'mod_workshop', 'overallfeedback_attachment',
+                $assessment->id);
+            unset($coredata->feedbackauthorattachment_filemanager);
+            if (empty($coredata->feedbackauthorattachment)) {
+                $coredata->feedbackauthorattachment = 0;
+            }
+        }
+        if (isset($data->weight) and $cansetassessmentweight) {
+            $coredata->weight = $data->weight;
+        }
+        // Update the assessment data if there is something other than just the 'id'.
+        if (count((array)$coredata) > 1 ) {
+            $DB->update_record('workshop_assessments', $coredata);
+            $params = array(
+                'relateduserid' => $submission->authorid,
+                'objectid' => $assessment->id,
+                'context' => $this->context,
+                'other' => array(
+                    'workshopid' => $this->id,
+                    'submissionid' => $assessment->submissionid
+                )
+            );
+
+            if (is_null($assessment->grade)) {
+                // All workshop_assessments are created when allocations are made. The create event is of more use located here.
+                $event = \mod_workshop\event\submission_assessed::create($params);
+                $event->trigger();
+            } else {
+                $params['other']['grade'] = $assessment->grade;
+                $event = \mod_workshop\event\submission_reassessed::create($params);
+                $event->trigger();
+            }
+        }
+        return $rawgrade;
+    }
+
     ////////////////////////////////////////////////////////////////////////////////
     // Internal methods (implementation details)                                  //
     ////////////////////////////////////////////////////////////////////////////////
index e64fd8c..860abd2 100644 (file)
@@ -75,7 +75,12 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase {
         $course->groupmode = SEPARATEGROUPS;
         $course->groupmodeforce = true;
         $this->course = $this->getDataGenerator()->create_course($course);
-        $this->workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $this->course->id));
+        $this->workshop = $this->getDataGenerator()->create_module('workshop',
+            array(
+                'course' => $this->course->id,
+                'overallfeedbackfiles' => 1,
+            )
+        );
         $this->context = context_module::instance($this->workshop->cmid);
         $this->cm = get_coursemodule_from_instance('workshop', $this->workshop->id);
 
@@ -1414,4 +1419,109 @@ class mod_workshop_external_testcase extends externallib_advanced_testcase {
         $this->setExpectedException('moodle_exception');
         mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
     }
+
+    /**
+     * Test update_assessment.
+     */
+    public function test_update_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);
+        // Get the form definition.
+        $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
+        $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
+
+        // Prepare the data to be sent.
+        $data = $result['fields'];
+        foreach ($data as $key => $param) {
+            if (strpos($param['name'], 'peercomment__idx_') === 0) {
+                $data[$key]['value'] = 'Some content';
+            } else if (strpos($param['name'], 'grade__idx_') === 0) {
+                $data[$key]['value'] = 25; // Set all to 25.
+            }
+        }
+
+        // Required data.
+        $data[] = array(
+            'name' => 'nodims',
+            'value' => $result['dimenssionscount'],
+        );
+
+        // General feedback.
+        $data[] = array(
+            'name' => 'feedbackauthor',
+            'value' => 'Feedback for the author',
+        );
+        $data[] = array(
+            'name' => 'feedbackauthorformat',
+            'value' => FORMAT_MOODLE,
+        );
+
+        // Create a file in a draft area for inline attachments.
+        $fs = get_file_storage();
+        $draftidinlineattach = file_get_unused_draft_itemid();
+        $usercontext = context_user::instance($this->student->id);
+        $filenameimg = 'shouldbeanimage.txt';
+        $filerecordinline = array(
+            'contextid' => $usercontext->id,
+            'component' => 'user',
+            'filearea'  => 'draft',
+            'itemid'    => $draftidinlineattach,
+            'filepath'  => '/',
+            'filename'  => $filenameimg,
+        );
+        $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
+
+        // Create a file in a draft area for regular attachments.
+        $draftidattach = file_get_unused_draft_itemid();
+        $filerecordattach = $filerecordinline;
+        $attachfilename = 'attachment.txt';
+        $filerecordattach['filename'] = $attachfilename;
+        $filerecordattach['itemid'] = $draftidattach;
+        $fs->create_file_from_string($filerecordattach, 'simple text attachment');
+
+        $data[] = array(
+            'name' => 'feedbackauthorinlineattachmentsid',
+            'value' => $draftidinlineattach,
+        );
+        $data[] = array(
+            'name' => 'feedbackauthorattachmentsid',
+            'value' => $draftidattach,
+        );
+
+        // Update the assessment.
+        $result = mod_workshop_external::update_assessment($assessmentid, $data);
+        $result = external_api::clean_returnvalue(mod_workshop_external::update_assessment_returns(), $result);
+        $this->assertEquals(100, $result['rawgrade']);
+        $this->assertTrue($result['status']);
+
+        // Get the assessment and check it was updated properly.
+        $result = mod_workshop_external::get_assessment($assessmentid);
+        $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
+        $this->assertEquals(100, $result['assessment']['grade']);
+        $this->assertEquals($this->student->id, $result['assessment']['reviewerid']);
+        $this->assertEquals('Feedback for the author', $result['assessment']['feedbackauthor']);
+        $this->assertCount(1, $result['assessment']['feedbackcontentfiles']);
+        $this->assertCount(1, $result['assessment']['feedbackattachmentfiles']);
+
+        // Now, get again the form and check we received the data we already sent.
+        $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
+        $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
+        foreach ($result['current'] as $currentdata) {
+            if (strpos($currentdata['name'], 'peercomment__idx_') === 0) {
+                $this->assertEquals('Some content', $currentdata['value']);
+            } else if (strpos($currentdata['name'], 'grade__idx_') === 0) {
+                $this->assertEquals(25, (int) $currentdata['value']);
+            }
+        }
+    }
 }
index db0082c..72263d9 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017051513;        // The current module version (YYYYMMDDXX)
+$plugin->version   = 2017051514;        // 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.