Merge branch 'MDL-57724-master' of git://github.com/jleyva/moodle
This commit is contained in:
@@ -1537,4 +1537,117 @@ class mod_lesson_external extends external_api {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the parameters for finish_attempt.
|
||||
*
|
||||
* @return external_external_function_parameters
|
||||
* @since Moodle 3.3
|
||||
*/
|
||||
public static function finish_attempt_parameters() {
|
||||
return new external_function_parameters (
|
||||
array(
|
||||
'lessonid' => new external_value(PARAM_INT, 'Lesson instance id.'),
|
||||
'password' => new external_value(PARAM_RAW, 'Optional password (the lesson may be protected).', VALUE_DEFAULT, ''),
|
||||
'outoftime' => new external_value(PARAM_BOOL, 'If the user run out of time.', VALUE_DEFAULT, false),
|
||||
'review' => new external_value(PARAM_BOOL, 'If we want to review just after finishing (1 hour margin).',
|
||||
VALUE_DEFAULT, false),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the current attempt.
|
||||
*
|
||||
* @param int $lessonid lesson instance id
|
||||
* @param str $password optional password (the lesson may be protected)
|
||||
* @param bool $outoftime optional if the user run out of time
|
||||
* @param bool $review if we want to review just after finishing (1 hour margin)
|
||||
* @return array of warnings and information about the finished attempt
|
||||
* @since Moodle 3.3
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public static function finish_attempt($lessonid, $password = '', $outoftime = false, $review = false) {
|
||||
|
||||
$params = array('lessonid' => $lessonid, 'password' => $password, 'outoftime' => $outoftime, 'review' => $review);
|
||||
$params = self::validate_parameters(self::finish_attempt_parameters(), $params);
|
||||
|
||||
$warnings = array();
|
||||
|
||||
list($lesson, $course, $cm, $context) = self::validate_lesson($params['lessonid']);
|
||||
|
||||
// Update timer so the validation can check the time restrictions.
|
||||
$timer = $lesson->update_timer();
|
||||
|
||||
// Return the validation to avoid exceptions in case the user is out of time.
|
||||
$params['pageid'] = LESSON_EOL;
|
||||
$validation = self::validate_attempt($lesson, $params, true);
|
||||
|
||||
if (array_key_exists('eolstudentoutoftime', $validation)) {
|
||||
// Maybe we run out of time just now.
|
||||
$params['outoftime'] = true;
|
||||
unset($validation['eolstudentoutoftime']);
|
||||
}
|
||||
// Check if there are more errors.
|
||||
if (!empty($validation)) {
|
||||
reset($validation);
|
||||
throw new moodle_exception(key($validation), 'lesson', '', current($validation)); // Throw first error.
|
||||
}
|
||||
|
||||
$result = $lesson->process_eol_page($params['outoftime']);
|
||||
|
||||
// Return the data.
|
||||
$validmessages = array(
|
||||
'notenoughtimespent', 'numberofpagesviewed', 'youshouldview', 'numberofcorrectanswers',
|
||||
'displayscorewithessays', 'displayscorewithoutessays', 'yourcurrentgradeisoutof', 'eolstudentoutoftimenoanswers',
|
||||
'welldone', 'displayofgrade', 'reviewlesson', 'modattemptsnoteacher', 'progresscompleted');
|
||||
|
||||
$data = array();
|
||||
foreach ($result as $el => $value) {
|
||||
if ($value !== false) {
|
||||
$message = '';
|
||||
if (in_array($el, $validmessages)) { // Check if the data comes with an informative message.
|
||||
$a = (is_bool($value)) ? null : $value;
|
||||
$message = get_string($el, 'lesson', $a);
|
||||
}
|
||||
// Return the data.
|
||||
$data[] = array(
|
||||
'name' => $el,
|
||||
'value' => (is_bool($value)) ? 1 : json_encode($value), // The data can be a php object.
|
||||
'message' => $message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'data' => $data,
|
||||
'messages' => self::format_lesson_messages($lesson),
|
||||
'warnings' => $warnings,
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the finish_attempt return value.
|
||||
*
|
||||
* @return external_single_structure
|
||||
* @since Moodle 3.3
|
||||
*/
|
||||
public static function finish_attempt_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'data' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'name' => new external_value(PARAM_ALPHANUMEXT, 'Data name.'),
|
||||
'value' => new external_value(PARAM_RAW, 'Data value.'),
|
||||
'message' => new external_value(PARAM_RAW, 'Data message (translated string).'),
|
||||
)
|
||||
), 'The EOL page information data.'
|
||||
),
|
||||
'messages' => self::external_messages(),
|
||||
'warnings' => new external_warnings(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,4 +124,12 @@ $functions = array(
|
||||
'capabilities' => 'mod/lesson:view',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
'mod_lesson_finish_attempt' => array(
|
||||
'classname' => 'mod_lesson_external',
|
||||
'methodname' => 'finish_attempt',
|
||||
'description' => 'Finishes the current attempt.',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'mod/lesson:view',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2790,6 +2790,198 @@ class lesson extends lesson_base {
|
||||
$this->add_message(get_string('attemptsremaining', 'lesson', $result->attemptsremaining));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process and return all the information for the end of lesson page.
|
||||
*
|
||||
* @param string $outoftime used to check to see if the student ran out of time
|
||||
* @return stdclass an object with all the page data ready for rendering
|
||||
* @since Moodle 3.3
|
||||
*/
|
||||
public function process_eol_page($outoftime) {
|
||||
global $DB, $USER;
|
||||
|
||||
$course = $this->get_courserecord();
|
||||
$cm = $this->get_cm();
|
||||
$canmanage = $this->can_manage();
|
||||
|
||||
// Init all the possible fields and values.
|
||||
$data = (object) array(
|
||||
'gradelesson' => true,
|
||||
'notenoughtimespent' => false,
|
||||
'numberofpagesviewed' => false,
|
||||
'youshouldview' => false,
|
||||
'numberofcorrectanswers' => false,
|
||||
'displayscorewithessays' => false,
|
||||
'displayscorewithoutessays' => false,
|
||||
'yourcurrentgradeisoutof' => false,
|
||||
'eolstudentoutoftimenoanswers' => false,
|
||||
'welldone' => false,
|
||||
'progressbar' => false,
|
||||
'displayofgrade' => false,
|
||||
'reviewlesson' => false,
|
||||
'modattemptsnoteacher' => false,
|
||||
'activitylink' => false,
|
||||
);
|
||||
|
||||
$ntries = $DB->count_records("lesson_grades", array("lessonid" => $this->properties->id, "userid" => $USER->id));
|
||||
if (isset($USER->modattempts[$this->properties->id])) {
|
||||
$ntries--; // Need to look at the old attempts :).
|
||||
}
|
||||
|
||||
$gradeinfo = lesson_grade($this, $ntries);
|
||||
$data->gradeinfo = $gradeinfo;
|
||||
if ($this->properties->custom && !$canmanage) {
|
||||
// Before we calculate the custom score make sure they answered the minimum
|
||||
// number of questions. We only need to do this for custom scoring as we can
|
||||
// not get the miniumum score the user should achieve. If we are not using
|
||||
// custom scoring (so all questions are valued as 1) then we simply check if
|
||||
// they answered more than the minimum questions, if not, we mark it out of the
|
||||
// number specified in the minimum questions setting - which is done in lesson_grade().
|
||||
// Get the number of answers given.
|
||||
if ($gradeinfo->nquestions < $this->properties->minquestions) {
|
||||
$data->gradelesson = false;
|
||||
$a = new stdClass;
|
||||
$a->nquestions = $gradeinfo->nquestions;
|
||||
$a->minquestions = $this->properties->minquestions;
|
||||
$this->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$canmanage) {
|
||||
if ($data->gradelesson) {
|
||||
// Store this now before any modifications to pages viewed.
|
||||
$progresscompleted = $this->calculate_progress();
|
||||
|
||||
// Update the clock / get time information for this user.
|
||||
$this->stop_timer();
|
||||
|
||||
// Update completion state.
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled($cm) && $this->properties->completionendreached) {
|
||||
$completion->update_state($cm, COMPLETION_COMPLETE);
|
||||
}
|
||||
|
||||
if ($this->properties->completiontimespent > 0) {
|
||||
$duration = $DB->get_field_sql(
|
||||
"SELECT SUM(lessontime - starttime)
|
||||
FROM {lesson_timer}
|
||||
WHERE lessonid = :lessonid
|
||||
AND userid = :userid",
|
||||
array('userid' => $USER->id, 'lessonid' => $this->properties->id));
|
||||
if (!$duration) {
|
||||
$duration = 0;
|
||||
}
|
||||
|
||||
// If student has not spend enough time in the lesson, display a message.
|
||||
if ($duration < $this->properties->completiontimespent) {
|
||||
$a = new stdClass;
|
||||
$a->timespentraw = $duration;
|
||||
$a->timespent = format_time($duration);
|
||||
$a->timerequiredraw = $this->properties->completiontimespent;
|
||||
$a->timerequired = format_time($this->properties->completiontimespent);
|
||||
$data->notenoughtimespent = $a;
|
||||
}
|
||||
}
|
||||
|
||||
if ($gradeinfo->attempts) {
|
||||
if (!$this->properties->custom) {
|
||||
$data->numberofpagesviewed = $gradeinfo->nquestions;
|
||||
if ($this->properties->minquestions) {
|
||||
if ($gradeinfo->nquestions < $this->properties->minquestions) {
|
||||
$data->youshouldview = $this->properties->minquestions;
|
||||
}
|
||||
}
|
||||
$data->numberofcorrectanswers = $gradeinfo->earned;
|
||||
}
|
||||
$a = new stdClass;
|
||||
$a->score = $gradeinfo->earned;
|
||||
$a->grade = $gradeinfo->total;
|
||||
if ($gradeinfo->nmanual) {
|
||||
$a->tempmaxgrade = $gradeinfo->total - $gradeinfo->manualpoints;
|
||||
$a->essayquestions = $gradeinfo->nmanual;
|
||||
$data->displayscorewithessays = $a;
|
||||
} else {
|
||||
$data->displayscorewithoutessays = $a;
|
||||
}
|
||||
if ($this->properties->grade != GRADE_TYPE_NONE) {
|
||||
$a = new stdClass;
|
||||
$a->grade = number_format($gradeinfo->grade * $this->properties->grade / 100, 1);
|
||||
$a->total = $this->properties->grade;
|
||||
$data->yourcurrentgradeisoutof = $a;
|
||||
}
|
||||
|
||||
$grade = new stdClass();
|
||||
$grade->lessonid = $this->properties->id;
|
||||
$grade->userid = $USER->id;
|
||||
$grade->grade = $gradeinfo->grade;
|
||||
$grade->completed = time();
|
||||
if (isset($USER->modattempts[$this->properties->id])) { // If reviewing, make sure update old grade record.
|
||||
if (!$grades = $DB->get_records("lesson_grades",
|
||||
array("lessonid" => $this->properties->id, "userid" => $USER->id), "completed DESC", '*', 0, 1)) {
|
||||
throw new moodle_exception('cannotfindgrade', 'lesson');
|
||||
}
|
||||
$oldgrade = array_shift($grades);
|
||||
$grade->id = $oldgrade->id;
|
||||
$DB->update_record("lesson_grades", $grade);
|
||||
} else {
|
||||
$newgradeid = $DB->insert_record("lesson_grades", $grade);
|
||||
}
|
||||
} else {
|
||||
if ($this->properties->timelimit) {
|
||||
if ($outoftime == 'normal') {
|
||||
$grade = new stdClass();
|
||||
$grade->lessonid = $this->properties->id;
|
||||
$grade->userid = $USER->id;
|
||||
$grade->grade = 0;
|
||||
$grade->completed = time();
|
||||
$newgradeid = $DB->insert_record("lesson_grades", $grade);
|
||||
$data->eolstudentoutoftimenoanswers = true;
|
||||
}
|
||||
} else {
|
||||
$data->welldone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update central gradebook.
|
||||
lesson_update_grades($this, $USER->id);
|
||||
$data->progresscompleted = $progresscompleted;
|
||||
}
|
||||
} else {
|
||||
// Display for teacher.
|
||||
if ($this->properties->grade != GRADE_TYPE_NONE) {
|
||||
$data->displayofgrade = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->properties->modattempts && !$canmanage) {
|
||||
// Make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
|
||||
// look at the attempt records to find the first QUESTION page that the user answered, then use that page id
|
||||
// to pass to view again. This is slick cause it wont call the empty($pageid) code
|
||||
// $ntries is decremented above.
|
||||
if (!$attempts = $this->get_attempts($ntries)) {
|
||||
$attempts = array();
|
||||
$url = new moodle_url('/mod/lesson/view.php', array('id' => $cm->id));
|
||||
} else {
|
||||
$firstattempt = current($attempts);
|
||||
$pageid = $firstattempt->pageid;
|
||||
// If the student wishes to review, need to know the last question page that the student answered.
|
||||
// This will help to make sure that the student can leave the lesson via pushing the continue button.
|
||||
$lastattempt = end($attempts);
|
||||
$USER->modattempts[$this->properties->id] = $lastattempt->pageid;
|
||||
|
||||
$url = new moodle_url('/mod/lesson/view.php', array('id' => $cm->id, 'pageid' => $pageid));
|
||||
}
|
||||
$data->reviewlesson = $url;
|
||||
} else if ($this->properties->modattempts && $canmanage) {
|
||||
$data->modattemptsnoteacher = true;
|
||||
}
|
||||
|
||||
if ($this->properties->activitylink) {
|
||||
$data->activitylink = $this->link_for_activitylink();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+92
-3
@@ -484,9 +484,10 @@ class mod_lesson_renderer extends plugin_renderer_base {
|
||||
* Returns HTML to display a progress bar of progression through a lesson
|
||||
*
|
||||
* @param lesson $lesson
|
||||
* @param int $progress optional, if empty it will be calculated
|
||||
* @return string
|
||||
*/
|
||||
public function progress_bar(lesson $lesson) {
|
||||
public function progress_bar(lesson $lesson, $progress = null) {
|
||||
$context = context_module::instance($this->page->cm->id);
|
||||
|
||||
// lesson setting to turn progress bar on or off
|
||||
@@ -499,8 +500,9 @@ class mod_lesson_renderer extends plugin_renderer_base {
|
||||
return $this->output->notification(get_string('progressbarteacherwarning2', 'lesson'));
|
||||
}
|
||||
|
||||
// Check if the user is reviewing the attempt.
|
||||
$progress = $lesson->calculate_progress();
|
||||
if ($progress === null) {
|
||||
$progress = $lesson->calculate_progress();
|
||||
}
|
||||
|
||||
// print out the Progress Bar. Attempted to put as much as possible in the style sheets.
|
||||
$content = '<br />' . html_writer::tag('div', $progress . '%', array('class' => 'progress_bar_completed', 'style' => 'width: '. $progress . '%;'));
|
||||
@@ -541,4 +543,91 @@ class mod_lesson_renderer extends plugin_renderer_base {
|
||||
$output = html_writer::tag('p', $contents, $attributes);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML for displaying the end of lesson page.
|
||||
*
|
||||
* @param lesson $lesson lesson instance
|
||||
* @param stdclass $data lesson data to be rendered
|
||||
* @return string HTML contents
|
||||
*/
|
||||
public function display_eol_page(lesson $lesson, $data) {
|
||||
|
||||
$output = '';
|
||||
$canmanage = $lesson->can_manage();
|
||||
$course = $lesson->courserecord;
|
||||
|
||||
if ($lesson->custom && !$canmanage && (($data->gradeinfo->nquestions < $lesson->minquestions))) {
|
||||
$output .= $this->box_start('generalbox boxaligncenter');
|
||||
}
|
||||
|
||||
if ($data->gradelesson) {
|
||||
// We are using level 3 header because the page title is a sub-heading of lesson title (MDL-30911).
|
||||
$output .= $this->heading(get_string("congratulations", "lesson"), 3);
|
||||
$output .= $this->box_start('generalbox boxaligncenter');
|
||||
}
|
||||
|
||||
if ($data->notenoughtimespent !== false) {
|
||||
$output .= $this->paragraph(get_string("notenoughtimespent", "lesson", $data->notenoughtimespent), 'center');
|
||||
}
|
||||
|
||||
if ($data->numberofpagesviewed !== false) {
|
||||
$output .= $this->paragraph(get_string("numberofpagesviewed", "lesson", $data->numberofpagesviewed), 'center');
|
||||
}
|
||||
if ($data->youshouldview !== false) {
|
||||
$output .= $this->paragraph(get_string("youshouldview", "lesson", $data->youshouldview), 'center');
|
||||
}
|
||||
if ($data->numberofcorrectanswers !== false) {
|
||||
$output .= $this->paragraph(get_string("numberofcorrectanswers", "lesson", $data->numberofcorrectanswers), 'center');
|
||||
}
|
||||
|
||||
if ($data->displayscorewithessays !== false) {
|
||||
$output .= $this->box(get_string("displayscorewithessays", "lesson", $data->displayscorewithessays), 'center');
|
||||
} else if ($data->displayscorewithoutessays !== false) {
|
||||
$output .= $this->box(get_string("displayscorewithoutessays", "lesson", $data->displayscorewithoutessays), 'center');
|
||||
}
|
||||
|
||||
if ($data->yourcurrentgradeisoutof !== false) {
|
||||
$output .= $this->paragraph(get_string("yourcurrentgradeisoutof", "lesson", $data->yourcurrentgradeisoutof), 'center');
|
||||
}
|
||||
if ($data->eolstudentoutoftimenoanswers !== false) {
|
||||
$output .= $this->paragraph(get_string("eolstudentoutoftimenoanswers", "lesson"));
|
||||
}
|
||||
if ($data->welldone !== false) {
|
||||
$output .= $this->paragraph(get_string("welldone", "lesson"));
|
||||
}
|
||||
|
||||
if ($data->progresscompleted !== false) {
|
||||
$output .= $this->progress_bar($lesson, $data->progresscompleted);
|
||||
}
|
||||
|
||||
if ($data->displayofgrade !== false) {
|
||||
$output .= $this->paragraph(get_string("displayofgrade", "lesson"), 'center');
|
||||
}
|
||||
|
||||
$output .= $this->box_end(); // End of Lesson button to Continue.
|
||||
|
||||
if ($data->reviewlesson !== false) {
|
||||
$output .= html_writer::link($data->reviewlesson, get_string('reviewlesson', 'lesson'), array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
|
||||
}
|
||||
if ($data->modattemptsnoteacher !== false) {
|
||||
$output .= $this->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
|
||||
}
|
||||
|
||||
if ($data->activitylink !== false) {
|
||||
$output .= $data->activitylink;
|
||||
}
|
||||
|
||||
$url = new moodle_url('/course/view.php', array('id' => $course->id));
|
||||
$output .= html_writer::link($url, get_string('returnto', 'lesson', format_string($course->fullname, true)),
|
||||
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
|
||||
|
||||
if (has_capability('gradereport/user:view', context_course::instance($course->id))
|
||||
&& $course->showgrades && $lesson->grade != 0 && !$lesson->practice) {
|
||||
$url = new moodle_url('/grade/index.php', array('id' => $course->id));
|
||||
$output .= html_writer::link($url, get_string('viewgrades', 'lesson'),
|
||||
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,4 +1042,93 @@ class mod_lesson_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertFalse($result['maxattemptsreached']); // Still one attempt.
|
||||
$this->assertEquals(50, $result['progress']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test finish attempt not doing anything.
|
||||
*/
|
||||
public function test_finish_attempt_not_doing_anything() {
|
||||
|
||||
$this->setUser($this->student);
|
||||
// First we need to launch the lesson so the timer is on.
|
||||
mod_lesson_external::launch_attempt($this->lesson->id);
|
||||
|
||||
$result = mod_lesson_external::finish_attempt($this->lesson->id);
|
||||
$result = external_api::clean_returnvalue(mod_lesson_external::finish_attempt_returns(), $result);
|
||||
|
||||
$this->assertCount(0, $result['warnings']);
|
||||
$returneddata = [];
|
||||
foreach ($result['data'] as $data) {
|
||||
$returneddata[$data['name']] = $data['value'];
|
||||
}
|
||||
$this->assertEquals(1, $returneddata['gradelesson']); // Graded lesson.
|
||||
$this->assertEquals(1, $returneddata['welldone']); // Finished correctly (even without grades).
|
||||
$gradeinfo = json_decode($returneddata['gradeinfo']);
|
||||
$expectedgradeinfo = (object) [
|
||||
'nquestions' => 0,
|
||||
'attempts' => 0,
|
||||
'total' => 0,
|
||||
'earned' => 0,
|
||||
'grade' => 0,
|
||||
'nmanual' => 0,
|
||||
'manualpoints' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test finish attempt with correct answer.
|
||||
*/
|
||||
public function test_finish_attempt_with_correct_answer() {
|
||||
global $DB;
|
||||
|
||||
$this->setUser($this->student);
|
||||
// First we need to launch the lesson so the timer is on.
|
||||
mod_lesson_external::launch_attempt($this->lesson->id);
|
||||
|
||||
// Attempt a question, correct answer.
|
||||
$DB->set_field('lesson', 'custom', 0, array('id' => $this->lesson->id));
|
||||
$DB->set_field('lesson', 'progressbar', 1, array('id' => $this->lesson->id));
|
||||
|
||||
$answercorrect = 0;
|
||||
$p2answers = $DB->get_records('lesson_answers', array('lessonid' => $this->lesson->id, 'pageid' => $this->page2->id), 'id');
|
||||
foreach ($p2answers as $answer) {
|
||||
if ($answer->jumpto != 0) {
|
||||
$answercorrect = $answer->id;
|
||||
}
|
||||
}
|
||||
|
||||
$data = array(
|
||||
array(
|
||||
'name' => 'answerid',
|
||||
'value' => $answercorrect,
|
||||
),
|
||||
array(
|
||||
'name' => '_qf__lesson_display_answer_form_truefalse',
|
||||
'value' => 1,
|
||||
)
|
||||
);
|
||||
$result = mod_lesson_external::process_page($this->lesson->id, $this->page2->id, $data);
|
||||
$result = external_api::clean_returnvalue(mod_lesson_external::process_page_returns(), $result);
|
||||
|
||||
$result = mod_lesson_external::finish_attempt($this->lesson->id);
|
||||
$result = external_api::clean_returnvalue(mod_lesson_external::finish_attempt_returns(), $result);
|
||||
|
||||
$this->assertCount(0, $result['warnings']);
|
||||
$returneddata = [];
|
||||
foreach ($result['data'] as $data) {
|
||||
$returneddata[$data['name']] = $data['value'];
|
||||
}
|
||||
$this->assertEquals(1, $returneddata['gradelesson']); // Graded lesson.
|
||||
$this->assertEquals(1, $returneddata['numberofpagesviewed']);
|
||||
$this->assertEquals(1, $returneddata['numberofcorrectanswers']);
|
||||
$gradeinfo = json_decode($returneddata['gradeinfo']);
|
||||
$expectedgradeinfo = (object) [
|
||||
'nquestions' => 1,
|
||||
'attempts' => 1,
|
||||
'total' => 1,
|
||||
'earned' => 1,
|
||||
'grade' => 100,
|
||||
'nmanual' => 0,
|
||||
'manualpoints' => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2016120511; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2016120512; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2016112900; // Requires this Moodle version
|
||||
$plugin->component = 'mod_lesson'; // Full name of the plugin (used for diagnostics)
|
||||
$plugin->cron = 0;
|
||||
|
||||
+2
-173
@@ -233,183 +233,12 @@ if ($pageid != LESSON_EOL) {
|
||||
|
||||
} else {
|
||||
|
||||
$lessoncontent = '';
|
||||
// End of lesson reached work out grade.
|
||||
// Used to check to see if the student ran out of time.
|
||||
$outoftime = optional_param('outoftime', '', PARAM_ALPHA);
|
||||
|
||||
$ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
|
||||
if (isset($USER->modattempts[$lesson->id])) {
|
||||
$ntries--; // need to look at the old attempts :)
|
||||
}
|
||||
$gradelesson = true;
|
||||
$gradeinfo = lesson_grade($lesson, $ntries);
|
||||
if ($lesson->custom && !$canmanage) {
|
||||
// Before we calculate the custom score make sure they answered the minimum
|
||||
// number of questions. We only need to do this for custom scoring as we can
|
||||
// not get the miniumum score the user should achieve. If we are not using
|
||||
// custom scoring (so all questions are valued as 1) then we simply check if
|
||||
// they answered more than the minimum questions, if not, we mark it out of the
|
||||
// number specified in the minimum questions setting - which is done in lesson_grade().
|
||||
// Get the number of answers given.
|
||||
if ($gradeinfo->nquestions < $lesson->minquestions) {
|
||||
$gradelesson = false;
|
||||
$a = new stdClass;
|
||||
$a->nquestions = $gradeinfo->nquestions;
|
||||
$a->minquestions = $lesson->minquestions;
|
||||
$lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
|
||||
$lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
|
||||
}
|
||||
}
|
||||
if ($gradelesson) {
|
||||
// We are using level 3 header because the page title is a sub-heading of lesson title (MDL-30911).
|
||||
$lessoncontent .= $OUTPUT->heading(get_string("congratulations", "lesson"), 3);
|
||||
$lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
|
||||
}
|
||||
if (!$canmanage) {
|
||||
if ($gradelesson) {
|
||||
// Store this now before any modifications to pages viewed.
|
||||
$progressbar = $lessonoutput->progress_bar($lesson);
|
||||
// Update the clock / get time information for this user.
|
||||
$lesson->stop_timer();
|
||||
|
||||
// Update completion state.
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled($cm) && $lesson->completionendreached) {
|
||||
$completion->update_state($cm, COMPLETION_COMPLETE);
|
||||
}
|
||||
|
||||
if ($lesson->completiontimespent > 0) {
|
||||
$duration = $DB->get_field_sql(
|
||||
"SELECT SUM(lessontime - starttime)
|
||||
FROM {lesson_timer}
|
||||
WHERE lessonid = :lessonid
|
||||
AND userid = :userid",
|
||||
array('userid' => $USER->id, 'lessonid' => $lesson->id));
|
||||
if (!$duration) {
|
||||
$duration = 0;
|
||||
}
|
||||
|
||||
// If student has not spend enough time in the lesson, display a message.
|
||||
if ($duration < $lesson->completiontimespent) {
|
||||
$a = new stdClass;
|
||||
$a->timespent = format_time($duration);
|
||||
$a->timerequired = format_time($lesson->completiontimespent);
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("notenoughtimespent", "lesson", $a), 'center');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($gradeinfo->attempts) {
|
||||
if (!$lesson->custom) {
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions), 'center');
|
||||
if ($lesson->minquestions) {
|
||||
if ($gradeinfo->nquestions < $lesson->minquestions) {
|
||||
// print a warning and set nviewed to minquestions
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("youshouldview", "lesson", $lesson->minquestions), 'center');
|
||||
}
|
||||
}
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'center');
|
||||
}
|
||||
$a = new stdClass;
|
||||
$a->score = $gradeinfo->earned;
|
||||
$a->grade = $gradeinfo->total;
|
||||
if ($gradeinfo->nmanual) {
|
||||
$a->tempmaxgrade = $gradeinfo->total - $gradeinfo->manualpoints;
|
||||
$a->essayquestions = $gradeinfo->nmanual;
|
||||
$lessoncontent .= $OUTPUT->box(get_string("displayscorewithessays", "lesson", $a), 'center');
|
||||
} else {
|
||||
$lessoncontent .= $OUTPUT->box(get_string("displayscorewithoutessays", "lesson", $a), 'center');
|
||||
}
|
||||
if ($lesson->grade != GRADE_TYPE_NONE) {
|
||||
$a = new stdClass;
|
||||
$a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
|
||||
$a->total = $lesson->grade;
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("yourcurrentgradeisoutof", "lesson", $a), 'center');
|
||||
}
|
||||
|
||||
$grade = new stdClass();
|
||||
$grade->lessonid = $lesson->id;
|
||||
$grade->userid = $USER->id;
|
||||
$grade->grade = $gradeinfo->grade;
|
||||
$grade->completed = time();
|
||||
if (isset($USER->modattempts[$lesson->id])) { // If reviewing, make sure update old grade record.
|
||||
if (!$grades = $DB->get_records("lesson_grades",
|
||||
array("lessonid" => $lesson->id, "userid" => $USER->id), "completed DESC", '*', 0, 1)) {
|
||||
print_error('cannotfindgrade', 'lesson');
|
||||
}
|
||||
$oldgrade = array_shift($grades);
|
||||
$grade->id = $oldgrade->id;
|
||||
$DB->update_record("lesson_grades", $grade);
|
||||
} else {
|
||||
$newgradeid = $DB->insert_record("lesson_grades", $grade);
|
||||
}
|
||||
} else {
|
||||
if ($lesson->timelimit) {
|
||||
if ($outoftime == 'normal') {
|
||||
$grade = new stdClass();
|
||||
$grade->lessonid = $lesson->id;
|
||||
$grade->userid = $USER->id;
|
||||
$grade->grade = 0;
|
||||
$grade->completed = time();
|
||||
$newgradeid = $DB->insert_record("lesson_grades", $grade);
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("eolstudentoutoftimenoanswers", "lesson"));
|
||||
}
|
||||
} else {
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("welldone", "lesson"));
|
||||
}
|
||||
}
|
||||
|
||||
// update central gradebook
|
||||
lesson_update_grades($lesson, $USER->id);
|
||||
$lessoncontent .= $progressbar;
|
||||
}
|
||||
} else {
|
||||
// display for teacher
|
||||
if ($lesson->grade != GRADE_TYPE_NONE) {
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("displayofgrade", "lesson"), 'center');
|
||||
}
|
||||
}
|
||||
$lessoncontent .= $OUTPUT->box_end(); //End of Lesson button to Continue.
|
||||
|
||||
if ($lesson->modattempts && !$canmanage) {
|
||||
// make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
|
||||
// look at the attempt records to find the first QUESTION page that the user answered, then use that page id
|
||||
// to pass to view again. This is slick cause it wont call the empty($pageid) code
|
||||
// $ntries is decremented above
|
||||
if (!$attempts = $lesson->get_attempts($ntries)) {
|
||||
$attempts = array();
|
||||
$url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
|
||||
} else {
|
||||
$firstattempt = current($attempts);
|
||||
$pageid = $firstattempt->pageid;
|
||||
// IF the student wishes to review, need to know the last question page that the student answered. This will help to make
|
||||
// sure that the student can leave the lesson via pushing the continue button.
|
||||
$lastattempt = end($attempts);
|
||||
$USER->modattempts[$lesson->id] = $lastattempt->pageid;
|
||||
|
||||
$url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
|
||||
}
|
||||
$lessoncontent .= html_writer::link($url, get_string('reviewlesson', 'lesson'),
|
||||
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
|
||||
} elseif ($lesson->modattempts && $canmanage) {
|
||||
$lessoncontent .= $lessonoutput->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
|
||||
}
|
||||
|
||||
if ($lesson->activitylink) {
|
||||
$lessoncontent .= $lesson->link_for_activitylink();
|
||||
}
|
||||
|
||||
$url = new moodle_url('/course/view.php', array('id'=>$course->id));
|
||||
$lessoncontent .= html_writer::link($url, get_string('returnto', 'lesson', format_string($course->fullname, true)),
|
||||
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
|
||||
|
||||
if (has_capability('gradereport/user:view', context_course::instance($course->id))
|
||||
&& $course->showgrades && $lesson->grade != 0 && !$lesson->practice) {
|
||||
$url = new moodle_url('/grade/index.php', array('id' => $course->id));
|
||||
$lessoncontent .= html_writer::link($url, get_string('viewgrades', 'lesson'),
|
||||
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
|
||||
}
|
||||
$data = $lesson->process_eol_page($outoftime);
|
||||
$lessoncontent = $lessonoutput->display_eol_page($lesson, $data);
|
||||
|
||||
lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
|
||||
echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, get_string("congratulations", "lesson"));
|
||||
|
||||
Reference in New Issue
Block a user