Merge branch 'MDL-48881_m30v5' of git://github.com/sbourget/moodle
This commit is contained in:
+147
-52
@@ -25,6 +25,7 @@
|
||||
|
||||
require_once('../../config.php');
|
||||
require_once($CFG->dirroot.'/mod/lesson/locallib.php');
|
||||
require_once($CFG->dirroot.'/mod/lesson/pagetypes/branchtable.php'); // Needed for constant.
|
||||
|
||||
$id = required_param('id', PARAM_INT); // Course Module ID
|
||||
$pageid = optional_param('pageid', null, PARAM_INT); // Lesson Page ID
|
||||
@@ -115,23 +116,30 @@ if ($action === 'delete') {
|
||||
this action is for default view and overview view
|
||||
**************************************************************************/
|
||||
|
||||
// Count the number of branch and question pages in this lesson.
|
||||
$branchcount = $DB->count_records('lesson_pages', array('lessonid' => $lesson->id, 'qtype' => LESSON_PAGE_BRANCHTABLE));
|
||||
$questioncount = ($DB->count_records('lesson_pages', array('lessonid' => $lesson->id)) - $branchcount);
|
||||
|
||||
// Only load students if there attempts for this lesson.
|
||||
if ($attempts = $DB->record_exists('lesson_attempts', array('lessonid' => $lesson->id))) {
|
||||
$attempts = $DB->record_exists('lesson_attempts', array('lessonid' => $lesson->id));
|
||||
$branches = $DB->record_exists('lesson_branch', array('lessonid' => $lesson->id));
|
||||
if ($attempts or $branches) {
|
||||
list($esql, $params) = get_enrolled_sql($context, '', $currentgroup, true);
|
||||
list($sort, $sortparams) = users_order_by_sql('u');
|
||||
|
||||
$params['lessonid'] = $lesson->id;
|
||||
$ufields = user_picture::fields('u');
|
||||
$sql = "SELECT DISTINCT $ufields
|
||||
FROM {user} u
|
||||
JOIN {lesson_attempts} a ON u.id = a.userid
|
||||
JOIN ($esql) ue ON ue.id = a.userid
|
||||
WHERE a.lessonid = :lessonid
|
||||
ORDER BY $sort";
|
||||
FROM {user} u
|
||||
JOIN (SELECT userid, lessonid FROM {lesson_attempts} a1 UNION
|
||||
SELECT userid, lessonid FROM {lesson_branch} b1) a ON u.id = a.userid
|
||||
JOIN ($esql) ue ON ue.id = a.userid
|
||||
WHERE a.lessonid = :lessonid
|
||||
ORDER BY $sort";
|
||||
|
||||
$students = $DB->get_recordset_sql($sql, $params);
|
||||
if (!$students->valid()) {
|
||||
$student->close();
|
||||
$students->close();
|
||||
$nothingtodisplay = true;
|
||||
}
|
||||
} else {
|
||||
@@ -153,6 +161,7 @@ if ($action === 'delete') {
|
||||
|
||||
// We have attempts and students, let's prepare all the information.
|
||||
$attempts = $DB->get_recordset('lesson_attempts', array('lessonid' => $lesson->id), 'timeseen');
|
||||
$branches = $DB->get_recordset('lesson_branch', array('lessonid' => $lesson->id), 'timeseen');
|
||||
|
||||
if (! $grades = $DB->get_records('lesson_grades', array('lessonid' => $lesson->id), 'completed')) {
|
||||
$grades = array();
|
||||
@@ -183,6 +192,7 @@ if ($action === 'delete') {
|
||||
$timestart = 0;
|
||||
$timeend = 0;
|
||||
$usergrade = null;
|
||||
$eol = false;
|
||||
|
||||
// search for the grade record for this try. if not there, the nulls defined above will be used.
|
||||
foreach($grades as $grade) {
|
||||
@@ -207,6 +217,7 @@ if ($action === 'delete') {
|
||||
// get grade info
|
||||
$timeend = $time->lessontime;
|
||||
$timestart = $time->starttime;
|
||||
$eol = $time->completed;
|
||||
break;
|
||||
}
|
||||
$n++; // if not equal, then increment n
|
||||
@@ -218,11 +229,57 @@ if ($action === 'delete') {
|
||||
$studentdata[$attempt->userid][$attempt->retry] = array( "timestart" => $timestart,
|
||||
"timeend" => $timeend,
|
||||
"grade" => $usergrade,
|
||||
"end" => $eol,
|
||||
"try" => $attempt->retry,
|
||||
"userid" => $attempt->userid);
|
||||
}
|
||||
}
|
||||
$attempts->close();
|
||||
foreach ($branches as $branch) {
|
||||
// If the user is not in the array or if the retry number is not in the sub array, add the data for that try.
|
||||
if (!array_key_exists($branch->userid, $studentdata) || !array_key_exists($branch->retry, $studentdata[$branch->userid])) {
|
||||
// Restore/setup defaults.
|
||||
$n = 0;
|
||||
$timestart = 0;
|
||||
$timeend = 0;
|
||||
$usergrade = null;
|
||||
$eol = false;
|
||||
// Search for the time record for this try. if not there, the nulls defined above will be used.
|
||||
foreach ($times as $time) {
|
||||
// Check to see if the grade matches the correct user.
|
||||
if ($time->userid == $branch->userid) {
|
||||
// See if n is = to the retry.
|
||||
if ($n == $branch->retry) {
|
||||
// Get grade info.
|
||||
$timeend = $time->lessontime;
|
||||
$timestart = $time->starttime;
|
||||
$eol = $time->completed;
|
||||
break;
|
||||
}
|
||||
$n++; // If not equal, then increment n.
|
||||
}
|
||||
}
|
||||
|
||||
// Build up the array.
|
||||
// This array represents each student and all of their tries at the lesson.
|
||||
$studentdata[$branch->userid][$branch->retry] = array( "timestart" => $timestart,
|
||||
"timeend" => $timeend,
|
||||
"grade" => $usergrade,
|
||||
"end" => $eol,
|
||||
"try" => $branch->retry,
|
||||
"userid" => $branch->userid);
|
||||
}
|
||||
}
|
||||
$branches->close();
|
||||
|
||||
// Determine if lesson should have a score.
|
||||
if ($branchcount > 0 AND $questioncount == 0) {
|
||||
// This lesson only contains content pages and is not graded.
|
||||
$lessonscored = false;
|
||||
} else {
|
||||
// This lesson is graded.
|
||||
$lessonscored = true;
|
||||
}
|
||||
// set all the stats variables
|
||||
$numofattempts = 0;
|
||||
$avescore = 0;
|
||||
@@ -234,8 +291,12 @@ if ($action === 'delete') {
|
||||
|
||||
$table = new html_table();
|
||||
|
||||
// set up the table object
|
||||
$table->head = array(get_string('name'), get_string('attempts', 'lesson'), get_string('highscore', 'lesson'));
|
||||
// Set up the table object.
|
||||
if ($lessonscored) {
|
||||
$table->head = array(get_string('name'), get_string('attempts', 'lesson'), get_string('highscore', 'lesson'));
|
||||
} else {
|
||||
$table->head = array(get_string('name'), get_string('attempts', 'lesson'));
|
||||
}
|
||||
$table->align = array('center', 'left', 'left');
|
||||
$table->wrap = array('nowrap', 'nowrap', 'nowrap');
|
||||
$table->attributes['class'] = 'standardtable generaltable';
|
||||
@@ -276,41 +337,64 @@ if ($action === 'delete') {
|
||||
$temp .= " ".userdate($try["timestart"]);
|
||||
$temp .= ", (".format_time($timetotake).")</a>";
|
||||
} else {
|
||||
// this is what the link does/looks like when the user has not completed the try
|
||||
$temp .= get_string("notcompleted", "lesson");
|
||||
$temp .= " ".userdate($try["timestart"])."</a>";
|
||||
$timetotake = null;
|
||||
if ($try["end"]) {
|
||||
// User finished the lesson but has no grade. (Happens when there are only content pages).
|
||||
$temp .= " ".userdate($try["timestart"]);
|
||||
$timetotake = $try["timeend"] - $try["timestart"];
|
||||
$temp .= ", (".format_time($timetotake).")</a>";
|
||||
} else {
|
||||
// This is what the link does/looks like when the user has not completed the attempt.
|
||||
$temp .= get_string("notcompleted", "lesson");
|
||||
if ($try['timestart'] !== 0) {
|
||||
// Teacher previews do not track time spent.
|
||||
$temp .= " ".userdate($try["timestart"]);
|
||||
}
|
||||
$temp .= "</a>";
|
||||
$timetotake = null;
|
||||
}
|
||||
}
|
||||
// build up the attempts array
|
||||
$attempts[] = $temp;
|
||||
|
||||
// run these lines for the stats only if the user finnished the lesson
|
||||
if ($try["grade"] !== null) {
|
||||
// Run these lines for the stats only if the user finnished the lesson.
|
||||
if ($try["end"]) {
|
||||
// User has completed the lesson.
|
||||
$numofattempts++;
|
||||
$avescore += $try["grade"];
|
||||
$avetime += $timetotake;
|
||||
if ($try["grade"] > $highscore || $highscore === null) {
|
||||
$highscore = $try["grade"];
|
||||
}
|
||||
if ($try["grade"] < $lowscore || $lowscore === null) {
|
||||
$lowscore = $try["grade"];
|
||||
}
|
||||
if ($timetotake > $hightime || $hightime == null) {
|
||||
$hightime = $timetotake;
|
||||
}
|
||||
if ($timetotake < $lowtime || $lowtime == null) {
|
||||
$lowtime = $timetotake;
|
||||
}
|
||||
if ($try["grade"] !== null) {
|
||||
// The lesson was scored.
|
||||
$avescore += $try["grade"];
|
||||
if ($try["grade"] > $highscore || $highscore === null) {
|
||||
$highscore = $try["grade"];
|
||||
}
|
||||
if ($try["grade"] < $lowscore || $lowscore === null) {
|
||||
$lowscore = $try["grade"];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// get line breaks in after each attempt
|
||||
$attempts = implode("<br />\n", $attempts);
|
||||
// add it to the table data[] object
|
||||
$table->data[] = array($studentname, $attempts, $bestgrade."%");
|
||||
|
||||
if ($lessonscored) {
|
||||
// Add the grade if the lesson is graded.
|
||||
$bestgrade = $bestgrade."%";
|
||||
$table->data[] = array($studentname, $attempts, $bestgrade);
|
||||
} else {
|
||||
// This lesson does not have a grade.
|
||||
$table->data[] = array($studentname, $attempts);
|
||||
}
|
||||
}
|
||||
}
|
||||
$students->close();
|
||||
// print it all out !
|
||||
// Print it all out!
|
||||
if (has_capability('mod/lesson:edit', $context)) {
|
||||
echo "<form id=\"theform\" method=\"post\" action=\"report.php\">\n
|
||||
<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n
|
||||
@@ -330,12 +414,7 @@ if ($action === 'delete') {
|
||||
echo '</form>';
|
||||
}
|
||||
|
||||
// some stat calculations
|
||||
if ($numofattempts == 0) {
|
||||
$avescore = get_string("notcompleted", "lesson");
|
||||
} else {
|
||||
$avescore = format_float($avescore/$numofattempts, 2);
|
||||
}
|
||||
// Calculate the Statistics.
|
||||
if ($avetime == null) {
|
||||
$avetime = get_string("notcompleted", "lesson");
|
||||
} else {
|
||||
@@ -352,30 +431,46 @@ if ($action === 'delete') {
|
||||
} else {
|
||||
$lowtime = format_time($lowtime);
|
||||
}
|
||||
if ($highscore === null) {
|
||||
$highscore = get_string("notcompleted", "lesson");
|
||||
}
|
||||
if ($lowscore === null) {
|
||||
$lowscore = get_string("notcompleted", "lesson");
|
||||
}
|
||||
|
||||
// output the stats
|
||||
echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
|
||||
$stattable = new html_table();
|
||||
$stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'),
|
||||
get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'),
|
||||
get_string('hightime', 'lesson'), get_string('lowtime', 'lesson'));
|
||||
$stattable->align = array('center', 'center', 'center', 'center', 'center', 'center');
|
||||
$stattable->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap');
|
||||
$stattable->attributes['class'] = 'standardtable generaltable';
|
||||
if ($lessonscored) {
|
||||
if ($numofattempts == 0) {
|
||||
$avescore = get_string("notcompleted", "lesson");
|
||||
} else {
|
||||
$avescore = format_float($avescore / $numofattempts, 2) . '%';
|
||||
}
|
||||
if ($highscore === null) {
|
||||
$highscore = get_string("notcompleted", "lesson");
|
||||
} else {
|
||||
$highscore .= '%';
|
||||
}
|
||||
if ($lowscore === null) {
|
||||
$lowscore = get_string("notcompleted", "lesson");
|
||||
} else {
|
||||
$lowscore .= '%';
|
||||
}
|
||||
|
||||
if (is_numeric($highscore)) {
|
||||
$highscore .= '%';
|
||||
// Display the full stats for the lesson.
|
||||
echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
|
||||
$stattable = new html_table();
|
||||
$stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'),
|
||||
get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'),
|
||||
get_string('hightime', 'lesson'), get_string('lowtime', 'lesson'));
|
||||
$stattable->align = array('center', 'center', 'center', 'center', 'center', 'center');
|
||||
$stattable->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap');
|
||||
$stattable->attributes['class'] = 'standardtable generaltable';
|
||||
$stattable->data[] = array($avescore, $avetime, $highscore, $lowscore, $hightime, $lowtime);
|
||||
|
||||
} else {
|
||||
// Display simple stats for the lesson.
|
||||
echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
|
||||
$stattable = new html_table();
|
||||
$stattable->head = array(get_string('averagetime', 'lesson'), get_string('hightime', 'lesson'),
|
||||
get_string('lowtime', 'lesson'));
|
||||
$stattable->align = array('center', 'center', 'center');
|
||||
$stattable->wrap = array('nowrap', 'nowrap', 'nowrap');
|
||||
$stattable->attributes['class'] = 'standardtable generaltable';
|
||||
$stattable->data[] = array($avetime, $hightime, $lowtime);
|
||||
}
|
||||
if (is_numeric($lowscore)) {
|
||||
$lowscore .= '%';
|
||||
}
|
||||
$stattable->data[] = array($avescore.'%', $avetime, $highscore, $lowscore, $hightime, $lowtime);
|
||||
|
||||
echo html_writer::table($stattable);
|
||||
} else if ($action === 'reportdetail') {
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
@mod @mod_lesson
|
||||
Feature: In a lesson activity, teachers can review student attempts
|
||||
To review student attempts in a lesson
|
||||
As a Teacher
|
||||
I need to view the reports.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Lesson" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson name |
|
||||
| Description | Test lesson description |
|
||||
| Re-takes allowed | Yes |
|
||||
And I press "Save and return to course"
|
||||
And I follow "Test lesson name"
|
||||
|
||||
@javascript
|
||||
Scenario: View student attempts in a lesson containing both content and question pages
|
||||
Given I follow "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | First page name |
|
||||
| Page contents | First page contents |
|
||||
| id_answer_editor_0 | Next page |
|
||||
| id_jumpto_0 | Next page |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Question"
|
||||
And I set the field "Select a question type" to "True/false"
|
||||
And I press "Add a question page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | True/false question 2 |
|
||||
| Page contents | Kermit is a frog |
|
||||
| id_answer_editor_0 | True |
|
||||
| id_response_editor_0 | Correct |
|
||||
| id_jumpto_0 | Next page |
|
||||
| id_answer_editor_1 | False |
|
||||
| id_response_editor_1 | Wrong |
|
||||
| id_jumpto_1 | This page |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Question"
|
||||
And I set the field "Select a question type" to "True/false"
|
||||
And I press "Add a question page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | True/false question 1 |
|
||||
| Page contents | Paper is made from trees. |
|
||||
| id_answer_editor_0 | True |
|
||||
| id_response_editor_0 | Correct |
|
||||
| id_jumpto_0 | Next page |
|
||||
| id_answer_editor_1 | False |
|
||||
| id_response_editor_1 | Wrong |
|
||||
| id_jumpto_1 | This page |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | Third page name |
|
||||
| Page contents | Third page contents |
|
||||
| id_answer_editor_0 | Previous page |
|
||||
| id_jumpto_0 | Previous page |
|
||||
| id_answer_editor_1 | Next page |
|
||||
| id_jumpto_1 | Next page |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | Second page name |
|
||||
| Page contents | Second page contents |
|
||||
| id_answer_editor_0 | Previous page |
|
||||
| id_jumpto_0 | Previous page |
|
||||
| id_answer_editor_1 | Next page |
|
||||
| id_jumpto_1 | Next page |
|
||||
And I press "Save page"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test lesson name"
|
||||
And I should see "First page contents"
|
||||
And I press "Next page"
|
||||
And I should see "Second page contents"
|
||||
And I press "Next page"
|
||||
And I should see "Third page contents"
|
||||
And I press "Next page"
|
||||
And I should see "Paper is made from trees."
|
||||
And I set the following fields to these values:
|
||||
| True | 1 |
|
||||
And I press "Submit"
|
||||
And I press "Continue"
|
||||
And I should see "Kermit is a frog"
|
||||
And I set the following fields to these values:
|
||||
| True | 1 |
|
||||
And I press "Submit"
|
||||
And I press "Continue"
|
||||
And I should see "Congratulations - end of lesson reached"
|
||||
And I log out
|
||||
Then I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test lesson name"
|
||||
And I follow "Reports"
|
||||
And I should see "Student 1"
|
||||
And I should see "100%"
|
||||
And I should see "High score"
|
||||
And I should see "Average score"
|
||||
And I should see "Low score"
|
||||
|
||||
@javascript
|
||||
Scenario: View student attempts in a lesson containing only content pages
|
||||
Given I follow "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | First page name |
|
||||
| Page contents | First page contents |
|
||||
| id_answer_editor_0 | Next page |
|
||||
| id_jumpto_0 | Next page |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | Fourth page name |
|
||||
| Page contents | Fourth page contents |
|
||||
| id_answer_editor_0 | Previous page |
|
||||
| id_jumpto_0 | Previous page |
|
||||
| id_answer_editor_1 | End of lesson |
|
||||
| id_jumpto_1 | End of lesson |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | Third page name |
|
||||
| Page contents | Third page contents |
|
||||
| id_answer_editor_0 | Previous page |
|
||||
| id_jumpto_0 | Previous page |
|
||||
| id_answer_editor_1 | Next page |
|
||||
| id_jumpto_1 | Next page |
|
||||
And I press "Save page"
|
||||
And I set the field "qtype" to "Add a content page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | Second page name |
|
||||
| Page contents | Second page contents |
|
||||
| id_answer_editor_0 | Previous page |
|
||||
| id_jumpto_0 | Previous page |
|
||||
| id_answer_editor_1 | Next page |
|
||||
| id_jumpto_1 | Next page |
|
||||
And I press "Save page"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test lesson name"
|
||||
And I should see "First page contents"
|
||||
And I press "Next page"
|
||||
And I should see "Second page contents"
|
||||
And I press "Next page"
|
||||
And I should see "Third page contents"
|
||||
And I press "Next page"
|
||||
And I should see "Fourth page contents"
|
||||
And I press "End of lesson"
|
||||
And I log out
|
||||
Then I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test lesson name"
|
||||
And I follow "Reports"
|
||||
And I should see "Student 1"
|
||||
And I should not see "High score"
|
||||
And I should not see "Average score"
|
||||
And I should not see "Low score"
|
||||
Reference in New Issue
Block a user