'mod_survey_get_surveys_by_courses',
'mod_survey_view_survey',
'mod_survey_get_questions',
+ 'mod_survey_submit_answers',
'mod_page_view_page',
'mod_resource_view_resource',
'mod_folder_view_folder',
);
}
+ /**
+ * Describes the parameters for submit_answers.
+ *
+ * @return external_function_parameters
+ * @since Moodle 3.0
+ */
+ public static function submit_answers_parameters() {
+ return new external_function_parameters(
+ array(
+ 'surveyid' => new external_value(PARAM_INT, 'Survey id'),
+ 'answers' => new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'key' => new external_value(PARAM_RAW, 'Answer key'),
+ 'value' => new external_value(PARAM_RAW, 'Answer value')
+ )
+ )
+ ),
+ )
+ );
+ }
+
+ /**
+ * Submit the answers for a given survey.
+ *
+ * @param int $surveyid the survey instance id
+ * @param array $answers the survey answers
+ * @return array of warnings and status result
+ * @since Moodle 3.0
+ * @throws moodle_exception
+ */
+ public static function submit_answers($surveyid, $answers) {
+ global $DB, $USER;
+
+ $params = self::validate_parameters(self::submit_answers_parameters(),
+ array(
+ 'surveyid' => $surveyid,
+ 'answers' => $answers
+ ));
+ $warnings = array();
+
+ // Request and permission validation.
+ $survey = $DB->get_record('survey', array('id' => $params['surveyid']), '*', MUST_EXIST);
+ list($course, $cm) = get_course_and_cm_from_instance($survey, 'survey');
+
+ $context = context_module::instance($cm->id);
+ self::validate_context($context);
+ require_capability('mod/survey:participate', $context);
+
+ if (survey_already_done($survey->id, $USER->id)) {
+ throw new moodle_exception("alreadysubmitted", "survey");
+ }
+
+ // Build the answers array. Data is cleaned inside the survey_save_answers function.
+ $answers = array();
+ foreach ($params['answers'] as $answer) {
+ $key = $answer['key'];
+ $answers[$key] = $answer['value'];
+ }
+
+ survey_save_answers($survey, $answers, $course, $context);
+
+ $result = array();
+ $result['status'] = true;
+ $result['warnings'] = $warnings;
+ return $result;
+ }
+
+ /**
+ * Returns description of method result value
+ *
+ * @return external_description
+ * @since Moodle 3.0
+ */
+ public static function submit_answers_returns() {
+ return new external_single_structure(
+ array(
+ 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
+ 'warnings' => new external_warnings()
+ )
+ );
+ }
+
}
'capabilities' => 'mod/survey:participate'
),
+ 'mod_survey_submit_answers' => array(
+ 'classname' => 'mod_survey_external',
+ 'methodname' => 'submit_answers',
+ 'description' => 'Submit the answers for a given survey.',
+ 'type' => 'write',
+ 'capabilities' => 'mod/survey:participate'
+ ),
+
);
return survey_order_questions($questions, $questionids);
}
+
+/**
+ * Save the answer for the given survey
+ *
+ * @param stdClass $survey a survey object
+ * @param array $answersrawdata the answers to be saved
+ * @param stdClass $course a course object (required for trigger the submitted event)
+ * @param stdClass $context a context object (required for trigger the submitted event)
+ * @since Moodle 3.0
+ */
+function survey_save_answers($survey, $answersrawdata, $course, $context) {
+ global $DB, $USER;
+
+ $answers = array();
+
+ // Sort through the data and arrange it.
+ // This is necessary because some of the questions may have two answers, eg Question 1 -> 1 and P1.
+ foreach ($answersrawdata as $key => $val) {
+ if ($key <> "userid" && $key <> "id") {
+ if (substr($key, 0, 1) == "q") {
+ $key = clean_param(substr($key, 1), PARAM_ALPHANUM); // Keep everything but the 'q', number or P number.
+ }
+ if (substr($key, 0, 1) == "P") {
+ $realkey = (int) substr($key, 1);
+ $answers[$realkey][1] = $val;
+ } else {
+ $answers[$key][0] = $val;
+ }
+ }
+ }
+
+ // Now store the data.
+ $timenow = time();
+ $answerstoinsert = array();
+ foreach ($answers as $key => $val) {
+ if ($key != 'sesskey') {
+ $newdata = new stdClass();
+ $newdata->time = $timenow;
+ $newdata->userid = $USER->id;
+ $newdata->survey = $survey->id;
+ $newdata->question = $key;
+ if (!empty($val[0])) {
+ $newdata->answer1 = $val[0];
+ } else {
+ $newdata->answer1 = "";
+ }
+ if (!empty($val[1])) {
+ $newdata->answer2 = $val[1];
+ } else {
+ $newdata->answer2 = "";
+ }
+
+ $answerstoinsert[] = $newdata;
+ }
+ }
+
+ if (!empty($answerstoinsert)) {
+ $DB->insert_records("survey_answers", $answerstoinsert);
+ }
+
+ $params = array(
+ 'context' => $context,
+ 'courseid' => $course->id,
+ 'other' => array('surveyid' => $survey->id)
+ );
+ $event = \mod_survey\event\response_submitted::create($params);
+ $event->trigger();
+}
exit;
}
-
-// Sort through the data and arrange it
-// This is necessary because some of the questions
-// may have two answers, eg Question 1 -> 1 and P1
-
- $answers = array();
-
- foreach ($formdata as $key => $val) {
- if ($key <> "userid" && $key <> "id") {
- if ( substr($key,0,1) == "q") {
- $key = clean_param(substr($key,1), PARAM_ALPHANUM); // keep everything but the 'q', number or Pnumber
- }
- if ( substr($key,0,1) == "P") {
- $realkey = (int) substr($key,1);
- $answers[$realkey][1] = $val;
- } else {
- $answers[$key][0] = $val;
- }
- }
- }
-
-
-// Now store the data.
-
- $timenow = time();
- foreach ($answers as $key => $val) {
- if ($key != 'sesskey') {
- $newdata = new stdClass();
- $newdata->time = $timenow;
- $newdata->userid = $USER->id;
- $newdata->survey = $survey->id;
- $newdata->question = $key;
- if (!empty($val[0])) {
- $newdata->answer1 = $val[0];
- } else {
- $newdata->answer1 = "";
- }
- if (!empty($val[1])) {
- $newdata->answer2 = $val[1];
- } else {
- $newdata->answer2 = "";
- }
-
- $DB->insert_record("survey_answers", $newdata);
- }
- }
+ survey_save_answers($survey, $formdata, $course, $context);
$params = array(
'context' => $context,
}
}
+ /**
+ * Test submit_answers
+ */
+ public function test_submit_answers() {
+ global $DB;
+
+ // Test user with full capabilities.
+ $this->setUser($this->student);
+
+ // Build our questions and responses array.
+ $realquestions = array();
+ $questions = survey_get_questions($this->survey);
+ $i = 5;
+ foreach ($questions as $q) {
+ if ($q->type >= 0) {
+ if ($q->multi) {
+ $subquestions = survey_get_subquestions($q);
+ foreach ($subquestions as $sq) {
+ $realquestions[] = array(
+ 'key' => 'q' . $sq->id,
+ 'value' => $i % 5 + 1 // Values between 1 and 5.
+ );
+ $i++;
+ }
+ } else {
+ $realquestions[] = array(
+ 'key' => 'q' . $q->id,
+ 'value' => $i % 5 + 1
+ );
+ $i++;
+ }
+ }
+ }
+
+ $result = mod_survey_external::submit_answers($this->survey->id, $realquestions);
+ $result = external_api::clean_returnvalue(mod_survey_external::submit_answers_returns(), $result);
+
+ $this->assertTrue($result['status']);
+ $this->assertCount(0, $result['warnings']);
+
+ $dbanswers = $DB->get_records_menu('survey_answers', array('survey' => $this->survey->id), '', 'question, answer1');
+ foreach ($realquestions as $q) {
+ $id = str_replace('q', '', $q['key']);
+ $this->assertEquals($q['value'], $dbanswers[$id]);
+ }
+
+ // Submit again, we expect an error here.
+ try {
+ mod_survey_external::submit_answers($this->survey->id, $realquestions);
+ $this->fail('Exception expected due to answers already submitted.');
+ } catch (moodle_exception $e) {
+ $this->assertEquals('alreadysubmitted', $e->errorcode);
+ }
+
+ // Test user with no capabilities.
+ // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
+ assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
+ accesslib_clear_all_caches_for_unit_testing();
+
+ try {
+ mod_survey_external::submit_answers($this->survey->id, $realquestions);
+ $this->fail('Exception expected due to missing capability.');
+ } catch (moodle_exception $e) {
+ $this->assertEquals('nopermissions', $e->errorcode);
+ }
+
+ // Test not-enrolled user.
+ $usernotenrolled = self::getDataGenerator()->create_user();
+ $this->setUser($usernotenrolled);
+ try {
+ mod_survey_external::submit_answers($this->survey->id, $realquestions);
+ $this->fail('Exception expected due to not enrolled user.');
+ } catch (moodle_exception $e) {
+ $this->assertEquals('requireloginerror', $e->errorcode);
+ }
+ }
+
}
}
}
+ /**
+ * Test survey_save_answers
+ */
+ public function test_survey_save_answers() {
+ global $DB;
+
+ $this->resetAfterTest();
+ $this->setAdminUser();
+
+ // Setup test data.
+ $course = $this->getDataGenerator()->create_course();
+ $survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
+ $context = context_module::instance($survey->cmid);
+
+ // Build our questions and responses array.
+ $realquestions = array();
+ $questions = survey_get_questions($survey);
+ $i = 5;
+ foreach ($questions as $q) {
+ if ($q->type > 0) {
+ if ($q->multi) {
+ $subquestions = survey_get_subquestions($q);
+ foreach ($subquestions as $sq) {
+ $key = 'q' . $sq->id;
+ $realquestions[$key] = $i % 5 + 1;
+ $i++;
+ }
+ } else {
+ $key = 'q' . $q->id;
+ $realquestions[$key] = $i % 5 + 1;
+ $i++;
+ }
+ }
+ }
+
+ $sink = $this->redirectEvents();
+ survey_save_answers($survey, $realquestions, $course, $context);
+
+ // Check the stored answers, they must match.
+ $dbanswers = $DB->get_records_menu('survey_answers', array('survey' => $survey->id), '', 'question, answer1');
+ foreach ($realquestions as $key => $value) {
+ $id = str_replace('q', '', $key);
+ $this->assertEquals($value, $dbanswers[$id]);
+ }
+
+ // Check events.
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = array_shift($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\mod_survey\event\response_submitted', $event);
+ $this->assertEquals($context, $event->get_context());
+ $this->assertEquals($survey->id, $event->other['surveyid']);
+ }
}