diff --git a/mod/lesson/backup/moodle2/backup_lesson_stepslib.php b/mod/lesson/backup/moodle2/backup_lesson_stepslib.php
index 2ff5ef6f5ce..cfb746d0b05 100644
--- a/mod/lesson/backup/moodle2/backup_lesson_stepslib.php
+++ b/mod/lesson/backup/moodle2/backup_lesson_stepslib.php
@@ -69,13 +69,14 @@ class backup_lesson_activity_structure_step extends backup_activity_structure_st
// alot goes into it but nothing relational other than course when will
// need to be corrected upon restore
$lesson = new backup_nested_element('lesson', array('id'), array(
- 'course','name','practice','modattempts','usepassword','password',
- 'dependency','conditions','grade','custom','ongoing','usemaxgrade',
- 'maxanswers','maxattempts','review','nextpagedefault','feedback',
- 'minquestions','maxpages','timed','maxtime','retake','activitylink',
- 'mediafile','mediaheight','mediawidth','mediaclose','slideshow',
- 'width','height','bgcolor','displayleft','displayleftif','progressbar',
- 'showhighscores','maxhighscores','available','deadline','timemodified'
+ 'course', 'name', 'practice', 'modattempts', 'usepassword', 'password',
+ 'dependency', 'conditions', 'grade', 'custom', 'ongoing', 'usemaxgrade',
+ 'maxanswers', 'maxattempts', 'review', 'nextpagedefault', 'feedback',
+ 'minquestions', 'maxpages', 'timed', 'maxtime', 'retake', 'activitylink',
+ 'mediafile', 'mediaheight', 'mediawidth', 'mediaclose', 'slideshow',
+ 'width', 'height', 'bgcolor', 'displayleft', 'displayleftif', 'progressbar',
+ 'showhighscores', 'maxhighscores', 'available', 'deadline', 'timemodified',
+ 'completionendreached'
));
// Tell the lesson element about the showhighscores elements mapping to the highscores
// database field.
@@ -140,7 +141,7 @@ class backup_lesson_activity_structure_step extends backup_activity_structure_st
// Grouped by a `timers` element this is relational to the lesson and user.
$timers = new backup_nested_element('timers');
$timer = new backup_nested_element('timer', array('id'), array(
- 'userid','starttime','lessontime'
+ 'userid', 'starttime', 'lessontime', 'completed'
));
// Now that we have all of the elements created we've got to put them
diff --git a/mod/lesson/backup/moodle2/restore_lesson_stepslib.php b/mod/lesson/backup/moodle2/restore_lesson_stepslib.php
index 34e8371370c..8be645e9bf0 100644
--- a/mod/lesson/backup/moodle2/restore_lesson_stepslib.php
+++ b/mod/lesson/backup/moodle2/restore_lesson_stepslib.php
@@ -72,6 +72,11 @@ class restore_lesson_activity_structure_step extends restore_activity_structure_
unset($data->showhighscores);
}
+ // Supply item that maybe missing from previous versions.
+ if (!isset($data->completionendreached)) {
+ $data->completionendreached = 0;
+ }
+
// insert the lesson record
$newitemid = $DB->insert_record('lesson', $data);
// immediately after inserting "activity" record, call this
@@ -175,7 +180,10 @@ class restore_lesson_activity_structure_step extends restore_activity_structure_
$data->userid = $this->get_mappingid('user', $data->userid);
$data->starttime = $this->apply_date_offset($data->starttime);
$data->lessontime = $this->apply_date_offset($data->lessontime);
-
+ // Supply item that maybe missing from previous versions.
+ if (!isset($data->completed)) {
+ $data->completed = 0;
+ }
$newitemid = $DB->insert_record('lesson_timer', $data);
}
diff --git a/mod/lesson/db/install.xml b/mod/lesson/db/install.xml
index dc77a6daf9d..470a172d5ae 100644
--- a/mod/lesson/db/install.xml
+++ b/mod/lesson/db/install.xml
@@ -48,6 +48,7 @@
+
@@ -145,6 +146,7 @@
+
diff --git a/mod/lesson/db/upgrade.php b/mod/lesson/db/upgrade.php
index 6531a2299e7..3d78bf107dd 100644
--- a/mod/lesson/db/upgrade.php
+++ b/mod/lesson/db/upgrade.php
@@ -102,5 +102,27 @@ function xmldb_lesson_upgrade($oldversion) {
// Moodle v2.8.0 release upgrade line.
// Put any upgrade step following this.
+ if ($oldversion < 2014112300) {
+
+ // Define field completionendreached to be added to lesson.
+ $table = new xmldb_table('lesson');
+ $field = new xmldb_field('completionendreached', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'timemodified');
+
+ // Conditionally launch add field completionendreached.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Define field completed to be added to lesson_timer.
+ $table = new xmldb_table('lesson_timer');
+ $field = new xmldb_field('completed', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'lessontime');
+
+ // Conditionally launch add field completed.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+ // Lesson savepoint reached.
+ upgrade_mod_savepoint(true, 2014112300, 'lesson');
+ }
return true;
}
diff --git a/mod/lesson/lang/en/lesson.php b/mod/lesson/lang/en/lesson.php
index 850813d782c..b234315591e 100644
--- a/mod/lesson/lang/en/lesson.php
+++ b/mod/lesson/lang/en/lesson.php
@@ -94,6 +94,8 @@ $string['comments'] = 'Your comments';
$string['completed'] = 'Completed';
$string['completederror'] = 'Complete the lesson';
$string['completethefollowingconditions'] = 'You must complete the following condition(s) in {$a} lesson before you can proceed.';
+$string['completionendreached'] = 'Require end reached';
+$string['completionendreached_desc'] = 'Student must reach the end of lesson page to complete this activity';
$string['conditionsfordependency'] = 'Condition(s) for the dependency';
$string['configactionaftercorrectanswer'] = 'The default action to take after a correct answer';
$string['configmaxanswers'] = 'Default maximum number of answers per page';
diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php
index 7bab80f8d5c..776be81207e 100644
--- a/mod/lesson/lib.php
+++ b/mod/lesson/lib.php
@@ -750,6 +750,8 @@ function lesson_supports($feature) {
return true;
case FEATURE_GRADE_HAS_GRADE:
return true;
+ case FEATURE_COMPLETION_HAS_RULES:
+ return true;
case FEATURE_GRADE_OUTCOMES:
return true;
case FEATURE_BACKUP_MOODLE2:
@@ -761,6 +763,32 @@ function lesson_supports($feature) {
}
}
+/**
+ * Obtains the automatic completion state for this lesson based on any conditions
+ * in lesson settings.
+ *
+ * @param object $course Course
+ * @param object $cm course-module
+ * @param int $userid User ID
+ * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
+ * @return bool True if completed, false if not, $type if conditions not set.
+ */
+function lesson_get_completion_state($course, $cm, $userid, $type) {
+ global $CFG, $DB;
+
+ // Get lesson details.
+ $lesson = $DB->get_record('lesson', array('id' => $cm->instance), '*',
+ MUST_EXIST);
+
+ // If completion option is enabled, evaluate it and return true/false.
+ if ($lesson->completionendreached) {
+ return $DB->record_exists('lesson_timer', array(
+ 'lessonid' => $lesson->id, 'userid' => $userid, 'completed' => 1));
+ } else {
+ // Completion option is not enabled so just return $type.
+ return $type;
+ }
+}
/**
* This function extends the settings navigation block for the site.
*
diff --git a/mod/lesson/locallib.php b/mod/lesson/locallib.php
index dc018522604..568970a3e40 100644
--- a/mod/lesson/locallib.php
+++ b/mod/lesson/locallib.php
@@ -1251,7 +1251,7 @@ class lesson extends lesson_base {
* will continue from a previous attempt
* @return stdClass The new timer
*/
- public function update_timer($restart=false, $continue=false) {
+ public function update_timer($restart=false, $continue=false, $endreached =false) {
global $USER, $DB;
// clock code
// get time information for this user
@@ -1272,6 +1272,7 @@ class lesson extends lesson_base {
}
$timer->lessontime = time();
+ $timer->completed = $endreached;
$DB->update_record('lesson_timer', $timer);
return $timer;
}
@@ -1295,7 +1296,7 @@ class lesson extends lesson_base {
));
$event->trigger();
- return $this->update_timer(false, false);
+ return $this->update_timer(false, false, true);
}
/**
diff --git a/mod/lesson/mod_form.php b/mod/lesson/mod_form.php
index 3d739c3f913..8475ddc37c5 100644
--- a/mod/lesson/mod_form.php
+++ b/mod/lesson/mod_form.php
@@ -343,5 +343,28 @@ class mod_lesson_mod_form extends moodleform_mod {
return $errors;
}
+
+ /**
+ * Display module-specific activity completion rules.
+ * Part of the API defined by moodleform_mod
+ * @return array Array of string IDs of added items, empty array if none
+ */
+ public function add_completion_rules() {
+ $mform = $this->_form;
+
+ $mform->addElement('checkbox', 'completionendreached', get_string('completionendreached', 'lesson'),
+ get_string('completionendreached_desc', 'lesson'));
+ return array('completionendreached');
+ }
+
+ /**
+ * Called during validation. Indicates whether a module-specific completion rule is selected.
+ *
+ * @param array $data Input data (not yet validated)
+ * @return bool True if one or more rules is enabled, false if none are.
+ */
+ public function completion_rule_enabled($data) {
+ return !empty($data['completionendreached']);
+ }
}
diff --git a/mod/lesson/tests/behat/completion_condition_end_reached.feature b/mod/lesson/tests/behat/completion_condition_end_reached.feature
new file mode 100644
index 00000000000..feae2dc8deb
--- /dev/null
+++ b/mod/lesson/tests/behat/completion_condition_end_reached.feature
@@ -0,0 +1,70 @@
+@mod @mod_lesson
+Feature: Set end of lesson reached as a completion condition for a lesson
+ In order to ensure students really see all lesson pages
+ As a teacher
+ I need to set end of lesson reached to mark the lesson activity as completed
+
+ @javascript
+ Scenario: Set end reached as a condition
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | student1 | Student | 1 | student1@asd.com |
+ | teacher1 | Teacher | 1 | teacher1@asd.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 "admin"
+ And I set the following administration settings values:
+ | Enable completion tracking | 1 |
+ And I log out
+ And I log in as "teacher1"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I click on "Edit settings" "link" in the "Administration" "block"
+ And I set the following fields to these values:
+ | Enable completion tracking | Yes |
+ And I press "Save and display"
+ And I add a "Lesson" to section "1" and I fill the form with:
+ | Name | Test lesson |
+ | Description | Test lesson description |
+ | Completion tracking | Show activity as complete when conditions are met |
+ | completionendreached | 1 |
+ And I follow "Test lesson"
+ And 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 | 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"
+ Then I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_lesson ')]/descendant::img[@alt='Not completed: Test lesson']" "xpath_element"
+ And I follow "Test lesson"
+ And I press "Next page"
+ And I follow "Course 1"
+ And I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_lesson ')]/descendant::img[@alt='Not completed: Test lesson']" "xpath_element"
+ And I follow "Course 1"
+ And I follow "Test lesson"
+ And I press "Next page"
+ And I press "Next page"
+ And I follow "Course 1"
+ And I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_lesson ')]/descendant::img[@alt='Completed: Test lesson']" "xpath_element"
+ And I log out
+ And I log in as "teacher1"
+ And I follow "Course 1"
+ And "Student 1" user has completed "Test lesson" activity
diff --git a/mod/lesson/upgrade.txt b/mod/lesson/upgrade.txt
new file mode 100644
index 00000000000..5fd45b49d96
--- /dev/null
+++ b/mod/lesson/upgrade.txt
@@ -0,0 +1,8 @@
+This files describes API changes in the lesson code.
+
+=== 2.9 ===
+A third optional boolean parameter $endreached was added to lesson::update_timer to indicate that end of lesson was reached. This is used by 'completionendreached' custom completion rule.
+
+=== Earlier changes ===
+
+* Were not documented in this way. Sorry.
diff --git a/mod/lesson/version.php b/mod/lesson/version.php
index 74cbcacac27..ac10eb593a2 100644
--- a/mod/lesson/version.php
+++ b/mod/lesson/version.php
@@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2014111000; // The current module version (Date: YYYYMMDDXX)
+$plugin->version = 2014112300; // The current module version (Date: YYYYMMDDXX)
$plugin->requires = 2014110400; // Requires this Moodle version
$plugin->component = 'mod_lesson'; // Full name of the plugin (used for diagnostics)
$plugin->cron = 0;
diff --git a/mod/lesson/view.php b/mod/lesson/view.php
index 097a93cdb11..6a31b53cee4 100644
--- a/mod/lesson/view.php
+++ b/mod/lesson/view.php
@@ -434,6 +434,12 @@ if ($pageid != LESSON_EOL) {
$lesson->stop_timer();
$gradeinfo = lesson_grade($lesson, $ntries);
+ // Update completion state.
+ $completion = new completion_info($course);
+ if ($completion->is_enabled($cm) && $lesson->completionendreached) {
+ $completion->update_state($cm, COMPLETION_COMPLETE);
+ }
+
if ($gradeinfo->attempts) {
if (!$lesson->custom) {
$lessoncontent .= $lessonoutput->paragraph(get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions), 'center');