Пример #1
0
 /**
  * Test to ensure that event data is being stored correctly.
  */
 public function test_answer_deleted()
 {
     global $DB, $USER;
     // Generate user data.
     $user = $this->getDataGenerator()->create_user();
     $optionids = array_keys($DB->get_records('choice_options', array('choiceid' => $this->choice->id)));
     // Create the first answer.
     choice_user_submit_response($optionids[2], $this->choice, $user->id, $this->course, $this->cm);
     // Get the users response.
     $answer = $DB->get_record('choice_answers', array('userid' => $user->id, 'choiceid' => $this->choice->id), '*', $strictness = IGNORE_MULTIPLE);
     // Redirect event.
     $sink = $this->redirectEvents();
     // Now delete the answer.
     choice_delete_responses(array($answer->id), $this->choice, $this->cm, $this->course);
     // Get our event event.
     $events = $sink->get_events();
     $event = reset($events);
     // Data checking.
     $this->assertInstanceOf('\\mod_choice\\event\\answer_deleted', $event);
     $this->assertEquals($USER->id, $event->userid);
     $this->assertEquals($user->id, $event->relateduserid);
     $this->assertEquals(context_module::instance($this->choice->cmid), $event->get_context());
     $this->assertEquals($this->choice->id, $event->other['choiceid']);
     $this->assertEquals($answer->optionid, $event->other['optionid']);
     $this->assertEventContextNotUsed($event);
     $sink->close();
 }
Пример #2
0
        choice_delete_responses($attemptids, $choice, $cm, $course);
        //delete responses.
        redirect("view.php?id={$cm->id}");
    }
    // Redirection after all POSTs breaks block editing, we need to be more specific!
    if ($choice->allowmultiple) {
        $answer = optional_param_array('answer', array(), PARAM_INT);
    } else {
        $answer = optional_param('answer', '', PARAM_INT);
    }
    if (!$choiceavailable) {
        $reason = current(array_keys($warnings));
        throw new moodle_exception($reason, 'choice', '', $warnings[$reason]);
    }
    if ($answer) {
        choice_user_submit_response($answer, $choice, $USER->id, $course, $cm);
        redirect(new moodle_url('/mod/choice/view.php', array('id' => $cm->id, 'notify' => 'choicesaved', 'sesskey' => sesskey())));
    } else {
        if (empty($answer) and $action === 'makechoice') {
            // We cannot use the 'makechoice' alone because there might be some legacy renderers without it,
            // outdated renderers will not get the 'mustchoose' message - bad luck.
            redirect(new moodle_url('/mod/choice/view.php', array('id' => $cm->id, 'notify' => 'mustchooseone', 'sesskey' => sesskey())));
        }
    }
}
// Completion and trigger events.
choice_view($choice, $course, $cm, $context);
echo $OUTPUT->header();
echo $OUTPUT->heading(format_string($choice->name), 2, null);
if ($notify and confirm_sesskey()) {
    if ($notify === 'choicesaved') {
Пример #3
0
 /**
  * Submit choice responses
  *
  * @param int $choiceid the choice instance id
  * @param array $responses the response ids
  * @return array answers information and warnings
  * @since Moodle 3.0
  */
 public static function submit_choice_response($choiceid, $responses)
 {
     global $USER;
     $warnings = array();
     $params = self::validate_parameters(self::submit_choice_response_parameters(), array('choiceid' => $choiceid, 'responses' => $responses));
     if (!($choice = choice_get_choice($params['choiceid']))) {
         throw new moodle_exception("invalidcoursemodule", "error");
     }
     list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
     $context = context_module::instance($cm->id);
     self::validate_context($context);
     require_capability('mod/choice:choose', $context);
     $timenow = time();
     if ($choice->timeclose != 0) {
         if ($choice->timeopen > $timenow) {
             throw new moodle_exception("notopenyet", "choice", '', userdate($choice->timeopen));
         } else {
             if ($timenow > $choice->timeclose) {
                 throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose));
             }
         }
     }
     if (!choice_get_my_response($choice) or $choice->allowupdate) {
         // When a single response is given, we convert the array to a simple variable
         // in order to avoid choice_user_submit_response to check with allowmultiple even
         // for a single response.
         if (count($params['responses']) == 1) {
             $params['responses'] = reset($params['responses']);
         }
         choice_user_submit_response($params['responses'], $choice, $USER->id, $course, $cm);
     } else {
         throw new moodle_exception('missingrequiredcapability', 'webservice', '', 'allowupdate');
     }
     $answers = choice_get_my_response($choice);
     return array('answers' => $answers, 'warnings' => $warnings);
 }
Пример #4
0
 /**
  * Test delete_choice_responses
  */
 public function test_delete_choice_responses()
 {
     global $DB;
     $this->resetAfterTest(true);
     $course = self::getDataGenerator()->create_course();
     $params = new stdClass();
     $params->course = $course->id;
     $params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
     $params->name = 'First Choice Activity';
     $params->showresults = CHOICE_SHOWRESULTS_ALWAYS;
     $params->allowmultiple = 1;
     $params->showunanswered = 1;
     $choice = self::getDataGenerator()->create_module('choice', $params);
     $cm = get_coursemodule_from_id('choice', $choice->cmid);
     $choiceinstance = choice_get_choice($cm->instance);
     $options = array_keys($choiceinstance->option);
     $student = $this->getDataGenerator()->create_user();
     $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     // Enroll student in Course1.
     self::getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
     $this->setUser($student);
     $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
     $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
     $myresponses = array_keys(choice_get_my_response($choice));
     // Try to delete responses when allow update is false.
     try {
         mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[0]));
         $this->fail('Exception expected due to missing permissions.');
     } catch (required_capability_exception $e) {
         $this->assertEquals('nopermissions', $e->errorcode);
     }
     // Set allow update to true, and a passed time close.
     $DB->set_field('choice', 'allowupdate', 1, array('id' => $choice->id));
     $DB->set_field('choice', 'timeclose', time() - DAYSECS, array('id' => $choice->id));
     try {
         mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[1]));
         $this->fail('Exception expected due to expired choice.');
     } catch (moodle_exception $e) {
         $this->assertEquals('expired', $e->errorcode);
     }
     // Reset time close. We should be able now to delete all the responses.
     $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
     $results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[1]));
     $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
     $this->assertTrue($results['status']);
     $this->assertCount(0, $results['warnings']);
     // Now, in the DB 0 responses.
     $this->assertCount(0, choice_get_my_response($choice));
     // Submit again the responses.
     $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
     $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
     $myresponses = array_keys(choice_get_my_response($choice));
     // Delete only one response.
     $results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0]));
     $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
     $this->assertTrue($results['status']);
     $this->assertCount(0, $results['warnings']);
     // Now, in the DB 1 response still.
     $this->assertCount(1, choice_get_my_response($choice));
     // Delete the remaining response, passing 2 invalid responses ids.
     $results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[1], $myresponses[0] + 2, $myresponses[0] + 3));
     $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
     $this->assertTrue($results['status']);
     // 2 warnings, 2 invalid responses.
     $this->assertCount(2, $results['warnings']);
     // Now, in the DB 0 responses.
     $this->assertCount(0, choice_get_my_response($choice));
     // Now, as an admin we must be able to delete all the responses under any condition.
     // Submit again the responses.
     $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
     $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
     $studentresponses = array_keys(choice_get_my_response($choice));
     $this->setAdminUser();
     $DB->set_field('choice', 'allowupdate', 0, array('id' => $choice->id));
     $DB->set_field('choice', 'timeclose', time() - DAYSECS, array('id' => $choice->id));
     $results = mod_choice_external::delete_choice_responses($choice->id, array($studentresponses[0], $studentresponses[1]));
     $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
     $this->assertTrue($results['status']);
     $this->assertCount(0, $results['warnings']);
     // Submit again the responses.
     $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
     $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
     $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
     // With other user account too, so we can test all the responses are deleted.
     choice_user_submit_response(array($options[1], $options[2]), $choice, $student->id, $course, $cm);
     // Test deleting all (not passing the answers ids), event not only mine.
     $results = mod_choice_external::delete_choice_responses($choice->id);
     $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
     $this->assertTrue($results['status']);
     $this->assertCount(0, $results['warnings']);
     $this->assertCount(0, choice_get_all_responses($choice));
     // Now, in the DB 0 responses.
     $this->setUser($student);
     // Submit again respones.
     $DB->set_field('choice', 'allowupdate', 1, array('id' => $choice->id));
     $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
     $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
     $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
     // Delete all responses.
     $results = mod_choice_external::delete_choice_responses($choice->id);
     $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
     $this->assertTrue($results['status']);
     $this->assertCount(0, $results['warnings']);
     $this->assertCount(0, choice_get_my_response($choice));
 }
Пример #5
0
    /**
     * Test get_choice_options
     */
    public function test_get_choice_options() {
        global $DB;

        // Warningcodes.
        $notopenyet = 1;
        $previewonly = 2;
        $expired = 3;

        $this->resetAfterTest(true);
        $timenow = time();
        $timeopen = $timenow + (60 * 60 * 24 * 2);
        $timeclose = $timenow + (60 * 60 * 24 * 7);
        $course = self::getDataGenerator()->create_course();
        $possibleoptions = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
        $params = array();
        $params['course'] = $course->id;
        $params['option'] = $possibleoptions;
        $params['name'] = 'First Choice Activity';
        $params['showpreview'] = 0;

        $generator = $this->getDataGenerator()->get_plugin_generator('mod_choice');
        $choice = $generator->create_instance($params);

        $student1 = $this->getDataGenerator()->create_user();
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
        // Enroll Students in Course.
        self::getDataGenerator()->enrol_user($student1->id,  $course->id, $studentrole->id);
        $this->setUser($student1);

        $results = mod_choice_external::get_choice_options($choice->id);
        // We need to execute the return values cleaning process to simulate the web service server.
        $results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
        // We should retrieve all options.
        $this->assertCount(count($possibleoptions), $results['options']);

        // Here we force timeopen/close in the future.
        $choice->timeopen = $timeopen;
        $choice->timeclose = $timeclose;
        $DB->update_record('choice', $choice);

        $results = mod_choice_external::get_choice_options($choice->id);
        // We need to execute the return values cleaning process to simulate the web service server.
        $results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
        // We should retrieve no options.
        $this->assertCount(0, $results['options']);
        $this->assertEquals($notopenyet, $results['warnings'][0]['warningcode']);

        // Here we see the options because of preview!
        $choice->showpreview = 1;
        $DB->update_record('choice', $choice);
        $results = mod_choice_external::get_choice_options($choice->id);
        // We need to execute the return values cleaning process to simulate the web service server.
        $results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
        // We should retrieve all options.
        $this->assertCount(count($possibleoptions), $results['options']);

        foreach ($results['options'] as $option) {
            // Each option is disabled as this is only the preview!
            $this->assertEquals(1, $option['disabled']);
        }
        $warnings = array();
        foreach ($results['warnings'] as $warning) {
            $warnings[$warning['warningcode']] = $warning['message'];
        }
        $this->assertTrue(isset($warnings[$previewonly]));
        $this->assertTrue(isset($warnings[$notopenyet]));

        // Simulate activity as opened!
        $choice->timeopen = $timenow - (60 * 60 * 24 * 3);
        $choice->timeclose = $timenow + (60 * 60 * 24 * 2);
        $DB->update_record('choice', $choice);
        $cm = get_coursemodule_from_id('choice', $choice->cmid);
        $choiceinstance = choice_get_choice($cm->instance);
        $optionsids = array_keys($choiceinstance->option);
        $myanswerid = $optionsids[2];
        choice_user_submit_response($myanswerid, $choice, $student1->id, $course, $cm);

        $results = mod_choice_external::get_choice_options($choice->id);
        // We need to execute the return values cleaning process to simulate the web service server.
        $results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
        // We should retrieve all options.
        $this->assertCount(count($possibleoptions), $results['options']);
        foreach ($results['options'] as $option) {
            // When we answered and we cannot update our choice.
            if ($option['id'] == $myanswerid and !$choice->allowupdate) {
                $this->assertEquals(1, $option['disabled']);
                $this->assertEquals(1, $option['checked']);
            } else {
                $this->assertEquals(0, $option['disabled']);
            }
        }

        // Set timeopen and timeclose as older than today!
        // We simulate what happens when the activity is closed.
        $choice->timeopen = $timenow - (60 * 60 * 24 * 3);
        $choice->timeclose = $timenow - (60 * 60 * 24 * 2);
        $DB->update_record('choice', $choice);
        $results = mod_choice_external::get_choice_options($choice->id);
        // We need to execute the return values cleaning process to simulate the web service server.
        $results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
        // We should retrieve no options.
        $this->assertCount(0, $results['options']);
        $this->assertEquals($expired, $results['warnings'][0]['warningcode']);

    }
Пример #6
0
 /**
  * Test choice_get_availability_status
  * @return void
  */
 public function test_choice_get_availability_status()
 {
     global $USER;
     $this->resetAfterTest();
     $this->setAdminUser();
     // Setup test data.
     $course = $this->getDataGenerator()->create_course();
     $choice = $this->getDataGenerator()->create_module('choice', array('course' => $course->id));
     // No time restrictions and updates allowed.
     list($status, $warnings) = choice_get_availability_status($choice, false);
     $this->assertEquals(true, $status);
     $this->assertCount(0, $warnings);
     // No updates allowed, but haven't answered yet.
     $choice->allowupdate = false;
     list($status, $warnings) = choice_get_availability_status($choice, false);
     $this->assertEquals(true, $status);
     $this->assertCount(0, $warnings);
     // No updates allowed and have answered.
     $cm = get_coursemodule_from_instance('choice', $choice->id);
     $choicewithoptions = choice_get_choice($choice->id);
     $optionids = array_keys($choicewithoptions->option);
     choice_user_submit_response($optionids[0], $choice, $USER->id, $course, $cm);
     list($status, $warnings) = choice_get_availability_status($choice, false);
     $this->assertEquals(false, $status);
     $this->assertCount(1, $warnings);
     $this->assertEquals('choicesaved', array_keys($warnings)[0]);
     $choice->allowupdate = true;
     // With time restrictions, still open.
     $choice->timeopen = time() - DAYSECS;
     $choice->timeclose = time() + DAYSECS;
     list($status, $warnings) = choice_get_availability_status($choice, false);
     $this->assertEquals(true, $status);
     $this->assertCount(0, $warnings);
     // Choice not open yet.
     $choice->timeopen = time() + DAYSECS;
     $choice->timeclose = $choice->timeopen + DAYSECS;
     list($status, $warnings) = choice_get_availability_status($choice, false);
     $this->assertEquals(false, $status);
     $this->assertCount(1, $warnings);
     $this->assertEquals('notopenyet', array_keys($warnings)[0]);
     // Choice closed.
     $choice->timeopen = time() - DAYSECS;
     $choice->timeclose = time() - 1;
     list($status, $warnings) = choice_get_availability_status($choice, false);
     $this->assertEquals(false, $status);
     $this->assertCount(1, $warnings);
     $this->assertEquals('expired', array_keys($warnings)[0]);
 }
Пример #7
0
 /**
  * Test to ensure that event data is being stored correctly.
  */
 public function test_answer_updated()
 {
     // Generate user data.
     $user = $this->getDataGenerator()->create_user();
     // Create the first answer.
     choice_user_submit_response(2, $this->choice, $user->id, $this->course, $this->cm);
     // Redirect event.
     $sink = $this->redirectEvents();
     // Now choose a different answer.
     choice_user_submit_response(3, $this->choice, $user->id, $this->course, $this->cm);
     $events = $sink->get_events();
     // Data checking.
     $this->assertCount(1, $events);
     $this->assertInstanceOf('\\mod_choice\\event\\answer_updated', $events[0]);
     $this->assertEquals($user->id, $events[0]->userid);
     $this->assertEquals(context_module::instance($this->choice->cmid), $events[0]->get_context());
     $this->assertEquals($this->choice->id, $events[0]->other['choiceid']);
     $this->assertEquals(3, $events[0]->other['optionid']);
     $expected = array($this->course->id, "choice", "choose again", 'view.php?id=' . $this->cm->id, $this->choice->id, $this->cm->id);
     $this->assertEventLegacyLogData($expected, $events[0]);
     $this->assertEventContextNotUsed($events[0]);
     $sink->close();
 }
Пример #8
0
    /**
     * Test choice_get_my_response
     * @return void
     */
    public function test_choice_get_my_response() {
        global $USER;

        $this->resetAfterTest();

        $this->setAdminUser();
        // Setup test data.
        $course = $this->getDataGenerator()->create_course();
        $choice = $this->getDataGenerator()->create_module('choice', array('course' => $course->id));
        $context = context_module::instance($choice->cmid);
        $cm = get_coursemodule_from_instance('choice', $choice->id);

        $choicewithoptions = choice_get_choice($choice->id);
        $optionids = array_keys($choicewithoptions->option);

        choice_user_submit_response($optionids[0], $choice, $USER->id, $course, $cm);
        $responses = choice_get_my_response($choice, $course, $cm, $context);
        $this->assertCount(1, $responses);
        $response = array_shift($responses);
        $this->assertEquals($optionids[0], $response->optionid);

        // Multiple responses.
        $choice = $this->getDataGenerator()->create_module('choice', array('course' => $course->id, 'allowmultiple' => 1));
        $context = context_module::instance($choice->cmid);
        $cm = get_coursemodule_from_instance('choice', $choice->id);

        $choicewithoptions = choice_get_choice($choice->id);
        $optionids = array_keys($choicewithoptions->option);

        choice_user_submit_response($optionids, $choice, $USER->id, $course, $cm);
        $responses = choice_get_my_response($choice, $course, $cm, $context);
        $this->assertCount(count($optionids), $responses);
        foreach ($responses as $resp) {
            $this->assertContains($resp->optionid, $optionids);
        }
    }
Пример #9
0
/**
 * Modifies responses of other users adding the option $newoptionid to them
 *
 * @param array $userids list of users to add option to (must be users without any answers yet)
 * @param array $answerids list of existing attempt ids of users (will be either appended or
 *      substituted with the newoptionid, depending on $choice->allowmultiple)
 * @param int $newoptionid
 * @param stdClass $choice choice object, result of {@link choice_get_choice()}
 * @param stdClass $cm
 * @param stdClass $course
 */
function choice_modify_responses($userids, $answerids, $newoptionid, $choice, $cm, $course)
{
    // Get all existing responses and the list of non-respondents.
    $groupmode = groups_get_activity_groupmode($cm);
    $onlyactive = $choice->includeinactive ? false : true;
    $allresponses = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);
    // Check that the option value is valid.
    if (!$newoptionid || !isset($choice->option[$newoptionid])) {
        return;
    }
    // First add responses for users who did not make any choice yet.
    foreach ($userids as $userid) {
        if (isset($allresponses[0][$userid])) {
            choice_user_submit_response($newoptionid, $choice, $userid, $course, $cm);
        }
    }
    // Create the list of all options already selected by each user.
    $optionsbyuser = [];
    // Mapping userid=>array of chosen choice options.
    $usersbyanswer = [];
    // Mapping answerid=>userid (which answer belongs to each user).
    foreach ($allresponses as $optionid => $responses) {
        if ($optionid > 0) {
            foreach ($responses as $userid => $userresponse) {
                $optionsbyuser += [$userid => []];
                $optionsbyuser[$userid][] = $optionid;
                $usersbyanswer[$userresponse->answerid] = $userid;
            }
        }
    }
    // Go through the list of submitted attemptids and find which users answers need to be updated.
    foreach ($answerids as $answerid) {
        if (isset($usersbyanswer[$answerid])) {
            $userid = $usersbyanswer[$answerid];
            if (!in_array($newoptionid, $optionsbyuser[$userid])) {
                $options = $choice->allowmultiple ? array_merge($optionsbyuser[$userid], [$newoptionid]) : $newoptionid;
                choice_user_submit_response($options, $choice, $userid, $course, $cm);
            }
        }
    }
}