MDL-23919 mod_data: add requiredentries to completion settings

Added required entries text field to the completion criteria area.
This field accepts a number.

If the legacy Entries required field has a value greater than 0 it will
be displayed and editable. For new instances this field will not be displayed.
This commit is contained in:
Marcus Green 2017-03-19 16:41:30 +00:00
parent bf919ddf02
commit f9729dcfe0
10 changed files with 285 additions and 12 deletions

View File

@ -45,7 +45,7 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
'addtemplate', 'rsstemplate', 'rsstitletemplate', 'csstemplate',
'jstemplate', 'asearchtemplate', 'approval', 'manageapproved', 'scale',
'assessed', 'assesstimestart', 'assesstimefinish', 'defaultsort',
'defaultsortdir', 'editany', 'notification', 'timemodified', 'config'));
'defaultsortdir', 'editany', 'notification', 'timemodified', 'config', 'completionentries'));
$fields = new backup_nested_element('fields');

View File

@ -42,6 +42,7 @@
<FIELD NAME="notification" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Notify people when things change"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time the settings for this database module instance were last modified."/>
<FIELD NAME="config" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="completionentries" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="Number of entries required for completion"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

View File

@ -97,6 +97,21 @@ function xmldb_data_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2016090600, 'data');
}
if ($oldversion < 2017032800) {
// Define field completionentries to be added to data. Require a number of entries to be considered complete.
$table = new xmldb_table('data');
$field = new xmldb_field('completionentries', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'config');
// Conditionally launch add field timemodified.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Data savepoint reached.
upgrade_mod_savepoint(true, 2017032800, 'data');
}
// Automatically generated Moodle v3.2.0 release upgrade line.
// Put any upgrade step following this.

View File

@ -70,6 +70,8 @@ $string['comments'] = 'Comments';
$string['commentsaved'] = 'Comment saved';
$string['commentsn'] = '{$a} comment(s)';
$string['commentsoff'] = 'Comments feature is not enabled';
$string['completionentries'] = 'Require entries';
$string['completionentriescount'] = 'Count of entries';
$string['configenablerssfeeds'] = 'This switch will enable the possibility of RSS feeds for all databases. You will still need to turn feeds on manually in the settings for each database.';
$string['confirmdeletefield'] = 'You are about to delete this field, are you sure?';
$string['confirmdeleterecord'] = 'Are you sure you want to delete this entry?';
@ -301,8 +303,12 @@ $string['recordssaved'] = 'entries saved';
$string['requireapproval'] = 'Approval required';
$string['requireapproval_help'] = 'If enabled, entries require approving by a teacher before they are viewable by everyone.';
$string['required'] = 'Required';
$string['requiredentries'] = 'Entries required for completion';
$string['requiredentries_help'] = 'The number of entries a student is required to submit before the activity can be considered complete.';
$string['requiredentries'] = 'Entries required for completion (old)';
$string['requiredentries_help'] = "If set, a message is displayed stating the number of entries required for completion. Note that this setting is not connected to activity completion.
For entries required for activity completion, the new Activity completion setting 'Require entries' should be used. To remove this setting completely, set to none, then save changes.
Please use the Entries required fields in the Activity completion section instead.";
$string['requiredentrieswarning'] = 'This setting has been replaced by an Activity completion setting "Require entries"';
$string['requiredentriestoview'] = 'Entries required before viewing';
$string['requiredentriestoview_help'] = 'The number of entries a student is required to submit before they can view entries from other students.

View File

@ -872,10 +872,13 @@ function data_atmaxentries($data){
* @param object $data
* @return int
*/
function data_numentries($data){
function data_numentries($data, $userid=null) {
global $USER, $DB;
if ($userid === null) {
$userid = $USER->id;
}
$sql = 'SELECT COUNT(*) FROM {data_records} WHERE dataid=? AND userid=?';
return $DB->count_records_sql($sql, array($data->id, $USER->id));
return $DB->count_records_sql($sql, array($data->id, $userid));
}
/**
@ -916,6 +919,9 @@ function data_add_record($data, $groupid=0){
));
$event->trigger();
$course = get_course($cm->course);
data_update_completion_state($course, $cm);
return $record->id;
}
@ -3940,11 +3946,15 @@ function data_delete_record($recordid, $data, $courseid, $cmid) {
));
$event->add_record_snapshot('data_records', $deleterecord);
$event->trigger();
$course = get_course($courseid);
$cm = get_coursemodule_from_instance('data', $data->id, 0, false, MUST_EXIST);
data_update_completion_state($course, $cm);
return true;
}
}
}
return false;
}
@ -4124,6 +4134,62 @@ function data_set_config(&$database, $key, $value) {
$DB->set_field('data', 'config', $database->config, ['id' => $database->id]);
}
}
/**
* Sets the automatic completion state for this database item based on the
* count of on its entries.
* @since Moodle 3.3
* @param object $course Course
* @param object $cm course-module
*/
function data_update_completion_state($course, $cm) {
global $DB;
// Get data details.
$data = $DB->get_record('data', array('id' => $cm->instance), '*', MUST_EXIST);
// If completion option is enabled, evaluate it and return true/false.
$completion = new completion_info($course);
if ($data->completionentries && $completion->is_enabled($cm)) {
$numentries = data_numentries($data);
// Check the number of entries required against the number of entries already made.
if ($data->completionentries > 0 && $numentries >= $data->completionentries) {
$completion->update_state($cm, COMPLETION_COMPLETE);
} else {
if ($completion->is_enabled($cm)) {
$completion->update_state($cm, COMPLETION_INCOMPLETE);
}
}
}
}
/**
* Obtains the automatic completion state for this database item based on any conditions
* on its settings. The call for this is in completion lib where the modulename is appended
* to the function name. This is why there are unused parameters.
*
* @since Moodle 3.3
* @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 data_get_completion_state($course, $cm, $userid, $type) {
global $DB;
$result = $type; // Default return value
// Get data details.
$data = $DB->get_record('data', array('id' => $cm->instance), '*', MUST_EXIST);
// If completion option is enabled, evaluate it and return true/false.
if ($data->completionentries) {
$data = $DB->get_record('data', array('id' => $cm->instance));
$numentries = data_numentries($data);
// Check the number of entries required against the number of entries already made.
if ($data->completionentries > 0 && $numentries >= $data->completionentries) {
$result = true;
} else {
$result = false;
}
}
return $result;
}
/**
* Mark the activity completed (if required) and trigger the course_module_viewed event.

View File

@ -8,7 +8,7 @@ require_once ($CFG->dirroot.'/course/moodleform_mod.php');
class mod_data_mod_form extends moodleform_mod {
function definition() {
global $CFG, $DB;
global $CFG, $DB, $OUTPUT;
$mform =& $this->_form;
@ -42,8 +42,16 @@ class mod_data_mod_form extends moodleform_mod {
$countoptions = array(0=>get_string('none'))+
(array_combine(range(1, DATA_MAX_ENTRIES), // Keys.
range(1, DATA_MAX_ENTRIES))); // Values.
$mform->addElement('select', 'requiredentries', get_string('requiredentries', 'data'), $countoptions);
$mform->addHelpButton('requiredentries', 'requiredentries', 'data');
/*only show fields if there are legacy values from
*before completionentries was added*/
if (!empty($this->current->requiredentries)) {
$group = array();
$group[] = $mform->createElement('select', 'requiredentries',
get_string('requiredentries', 'data'), $countoptions);
$mform->addGroup($group, 'requiredentriesgroup', get_string('requiredentries', 'data'), array(''), false);
$mform->addHelpButton('requiredentriesgroup', 'requiredentries', 'data');
$mform->addElement('html', $OUTPUT->notification( get_string('requiredentrieswarning', 'data')));
}
$mform->addElement('select', 'requiredentriestoview', get_string('requiredentriestoview', 'data'), $countoptions);
$mform->addHelpButton('requiredentriestoview', 'requiredentriestoview', 'data');
@ -104,9 +112,69 @@ class mod_data_mod_form extends moodleform_mod {
return $errors;
}
function data_preprocessing(&$default_values){
parent::data_preprocessing($default_values);
/**
* 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;
$group = array();
$group[] = $mform->createElement('checkbox', 'completionentriesendabled', '',
get_string('completionentriescount', 'data'));
$group[] = $mform->createElement('text', 'completionentries',
get_string('completionentriescount', 'data'), array('size' => '1'));
$mform->addGroup($group, 'completionentriesgroup', get_string('completionentries', 'data'),
array(' '), false);
$mform->disabledIf('completionentries', 'completionentriesendabled', 'notchecked');
$mform->setDefault('completionentries', 1);
$mform->setType('completionentries', PARAM_INT);
/* This ensures the elements are disabled unless completion rules are enabled */
return array('completionentriesgroup');
}
/**
* Called during validation. Indicates if a module-specific completion rule is selected.
*
* @param array $data
* @return bool True if one or more rules is enabled, false if none are.
*/
public function completion_rule_enabled($data) {
return ($data['completionentries'] != 0);
}
/**
* Set up the completion checkbox which is not part of standard data.
*
* @param array $defaultvalues
*
*/
public function data_preprocessing(&$defaultvalues) {
$defaultvalues['completionentriesendabled'] = !empty($defaultvalues['completionentries']) ? 1 : 0;
parent::data_preprocessing($defaultvalues);
}
/**
* Turn off this completion setting if the checkbox is not ticked
*
* @return boolean indicates if any data was submitted
*/
public function get_data() {
$data = parent::get_data();
if (!$data) {
return false;
}
if (!empty($data->completionunlocked)) {
$autocompletion = !empty($data->completion) && $data->completion == COMPLETION_TRACKING_AUTOMATIC;
if (empty($data->completionentries) || !$autocompletion) {
$data->completionentries = 0;
}
}
$data->completionunlocked = true;
return $data;
}
}

View File

@ -8,6 +8,10 @@
height: 34px;
}
.path-mod-data #id_entrieshdr div .alert.alert-danger {
margin-bottom: 2rem;
}
#page-mod-data-view img.list_picture {
border: 0;
}

View File

@ -0,0 +1,59 @@
@mod @mod_data
Feature: Set entries required as a completion condition for a data item
In order to ensure students make a minimum number of entries
As a teacher
I need to set entries required to mark the database activity as completed
Scenario:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| teacher1 | Teacher | 1 | teacher1@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 "C1"
And I turn editing mode on
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
| Enable completion tracking | Yes |
And I press "Save and display"
#Two entries required to complete the activity
And I add a "Database" to section "1" and I fill the form with:
| Name | Test database name |
| Description | Test database description |
| Completion tracking | Show activity as complete when conditions are met |
| completionentriesendabled | checked |
| completionentries | 2 |
And I follow "Course 1"
And I add a "Text input" field to "Test database name" database and I fill the form with:
| Field name | Test field name |
And I follow "C1"
And I log out
When I log in as "student1"
And I follow "C1"
And I add an entry to "Test database name" database with:
| Test field name | Student original entry |
And I press "Save and view"
And I follow "C1"
And I log out
And I log in as "teacher1"
And I follow "C1"
#One entry is not enough to mark as complete
And "Student 1" user has not completed "Test database name" activity
And I log out
When I log in as "student1"
And I follow "C1"
And I add an entry to "Test database name" database with:
| Test field name | Student second entry |
And I press "Save and view"
And I log out
And I log in as "teacher1"
And I follow "C1"
Then "Student 1" user has completed "Test database name" activity
And I log out

View File

@ -54,6 +54,60 @@ class mod_data_lib_testcase extends advanced_testcase {
}
}
/**
* Confirms that completionentries is working
* Sets it to 1, confirms that
* it is not complete. Inserts a record and
* confirms that it is complete.
*/
public function test_data_completion() {
global $DB, $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$CFG->enablecompletion = 1;
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$record = new stdClass();
$record->course = $course->id;
$record->name = "Mod data completion test";
$record->intro = "Some intro of some sort";
$record->completionentries = "1";
/* completion=2 means Show activity commplete when condition is met and completionentries means 1 record is
* required for the activity to be considered complete
*/
$module = $this->getDataGenerator()->create_module('data', $record, array('completion' => 2, 'completionentries' => 1));
$cm = get_coursemodule_from_instance('data', $module->id, $course->id);
$completion = new completion_info($course);
$completiondata = $completion->get_data($cm, true, 0);
/* Confirm it is not complete as there are no entries */
$this->assertNotEquals(1, $completiondata->completionstate);
$field = data_get_field_new('text', $module);
$fielddetail = new stdClass();
$fielddetail->d = $module->id;
$fielddetail->mode = 'add';
$fielddetail->type = 'text';
$fielddetail->sesskey = sesskey();
$fielddetail->name = 'Name';
$fielddetail->description = 'Some name';
$field->define_field($fielddetail);
$field->insert_field();
$recordid = data_add_record($module);
$datacontent = array();
$datacontent['fieldid'] = $field->field->id;
$datacontent['recordid'] = $recordid;
$datacontent['content'] = 'Asterix';
$contentid = $DB->insert_record('data_content', $datacontent);
$cm = get_coursemodule_from_instance('data', $module->id, $course->id);
$completion = new completion_info($course);
$completiondata = $completion->get_data($cm);
/* Confirm it is complete because it has 1 entry */
$this->assertEquals(1, $completiondata->completionstate);
}
public function test_data_delete_record() {
global $DB;

View File

@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016120510; // The current module version (Date: YYYYMMDDXX)
$plugin->version = 2017032800; // The current module version (Date: YYYYMMDDXX)
$plugin->requires = 2016112900; // Requires this Moodle version
$plugin->component = 'mod_data'; // Full name of the plugin (used for diagnostics)
$plugin->cron = 0;