diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index 6903de17..0747b0af 100644 --- a/.github/workflows/moodle-ci.yml +++ b/.github/workflows/moodle-ci.yml @@ -128,7 +128,7 @@ jobs: - name: Initialise moodle-plugin-ci run: | - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3 + composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4 echo $(cd ci/bin; pwd) >> $GITHUB_PATH echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH sudo locale-gen en_AU.UTF-8 diff --git a/classes/completion/custom_completion.php b/classes/completion/custom_completion.php new file mode 100644 index 00000000..e477c750 --- /dev/null +++ b/classes/completion/custom_completion.php @@ -0,0 +1,107 @@ +. + +declare(strict_types=1); + +namespace mod_ratingallocate\completion; + +use context_module; +use core_completion\activity_custom_completion; + +/** + * Activity custom completion subclass for the ratingallocate activity. + * + * Class for defining the custom completion rules of ratingallocate and fetching the completion statuses + * of the custom completion rules for a given ratingallocate instance and a user. + * + * @package mod_ratingallocate + * @copyright Irina Hoppe Uni Münster + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class custom_completion extends activity_custom_completion { + + /** + * Fetches the completion state for a given completion rule. + * + * @param string $rule The completion rule. + * @return int The completion state. + * @throws \moodle_exception + */ + public function get_state(string $rule): int { + global $DB; + $status = false; + $this->validate_rule($rule); + + $userid = $this->userid; + $instance = $this->cm->instance; + + if (!$DB->get_record('ratingallocate', ['id' => $instance])) { + throw new \moodle_exception('Unable to find ratingallocate instance with id ' . $instance); + } + + if ($rule == 'completionvote') { + $sql = "SELECT * FROM {ratingallocate_ratings} r INNER JOIN {ratingallocate_choices} c on r.choiceid=c.id " . + "WHERE r.userid= :userid AND c.ratingallocateid= :ratingallocateid AND c.active=1"; + $votesofuser = $DB->get_records_sql($sql, ['userid' => $userid, 'ratingallocateid' => $instance]); + $status = count($votesofuser) > 0; + } else if ($rule == 'completionallocation') { + $sql = "SELECT * FROM {ratingallocate_allocations} a INNER JOIN {ratingallocate_choices} c + ON a.choiceid = c.id WHERE userid= :userid AND a.ratingallocateid= :ratingallocateid AND c.active=1"; + $allocationsofuser = $DB->get_records_sql($sql, ['userid' => $userid, 'ratingallocateid' => $instance]); + $status = count($allocationsofuser) > 0; + } + + return $status ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE; + } + + /** + * Fetch the list of custom completion rules that this module defines. + * + * @return array + */ + public static function get_defined_custom_rules(): array { + return [ + 'completionvote', + 'completionallocation', + ]; + } + + /** + * Returns an associative array of the descriptions of custom completion rules. + * + * @return array + */ + public function get_custom_rule_descriptions(): array { + return [ + 'completionvote' => get_string('completionvote_desc', RATINGALLOCATE_MOD_NAME), + 'completionallocation' => get_string('completionallocation_desc', RATINGALLOCATE_MOD_NAME), + ]; + } + + /** + * Returns an array of all completion rules, in the order they should be displayed to users. + * + * @return array + */ + public function get_sort_order(): array { + return [ + 'completionview', + 'completionvote', + 'completionallocation', + ]; + } +} + diff --git a/db/install.xml b/db/install.xml index 5433f236..3ca1d6f0 100644 --- a/db/install.xml +++ b/db/install.xml @@ -23,6 +23,8 @@ + + diff --git a/db/upgrade.php b/db/upgrade.php index c6885680..777594ca 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -218,5 +218,24 @@ function xmldb_ratingallocate_upgrade($oldversion) { upgrade_mod_savepoint(true, 2023050900, 'ratingallocate'); } + if ($oldversion < 2024080900) { + + // Define completionrules fields to be added to ratingallocate. + $table = new xmldb_table('ratingallocate'); + $votefield = new xmldb_field('completionvote', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, false, '0'); + $allocationfield = new xmldb_field('completionallocation', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, false, '0'); + + // Conditionally launch add field notification_send. + if (!$dbman->field_exists($table, $votefield)) { + $dbman->add_field($table, $votefield); + } + if (!$dbman->field_exists($table, $allocationfield)) { + $dbman->add_field($table, $allocationfield); + } + + // Ratingallocate savepoint reached. + upgrade_mod_savepoint(true, 2024080900, 'ratingallocate'); + } + return true; } diff --git a/lang/en/ratingallocate.php b/lang/en/ratingallocate.php index 24cbddf5..a9551325 100644 --- a/lang/en/ratingallocate.php +++ b/lang/en/ratingallocate.php @@ -304,6 +304,13 @@ $string['err_required'] = 'You need to provide a value for this field.'; $string['err_minimum'] = 'The minimum value for this field is {$a}.'; $string['err_maximum'] = 'The maximum value for this field is {$a}.'; + +$string['completionvote'] = "Vote in the activity"; +$string['completionallocation'] = "Been allocated to a choice"; +$string['completionvote_help'] = "To complete this activity, users have to submit a vote."; +$string['completionallocation_help'] = "To complete this activity, users have to be allocated to a choice."; +$string['completionvote_desc'] = "Vote"; +$string['completionallocation_desc'] = "Be allocated"; // // $string['show_choices_header'] = 'List of all choices'; diff --git a/lib.php b/lib.php index 8008cb25..6f8a56ea 100644 --- a/lib.php +++ b/lib.php @@ -70,6 +70,8 @@ function ratingallocate_supports($feature) { return true; case FEATURE_COMPLETION_TRACKS_VIEWS: return true; + case FEATURE_COMPLETION_HAS_RULES: + return true; default : return null; } @@ -760,12 +762,14 @@ function ratingallocate_reset_course_form_defaults($course) { * @param stdClass $coursemodule The coursemodule object (record). * @return cached_cm_info An object on information that the courses * will know about (most noticeably, an icon). + * @throws dml_exception */ function ratingallocate_get_coursemodule_info($coursemodule) { global $DB; $dbparams = ['id' => $coursemodule->instance]; - if (! $ratingallocate = $DB->get_record('ratingallocate', $dbparams)) { + $fields = 'id, name, intro, introformat, accesstimestart, accesstimestop, completionvote, completionallocation'; + if (!$ratingallocate = $DB->get_record(RATINGALLOCATE_MOD_NAME, $dbparams, $fields)) { return false; } @@ -774,7 +778,13 @@ function ratingallocate_get_coursemodule_info($coursemodule) { if ($coursemodule->showdescription) { // Convert intro to html. Do not filter cached version, filters run at display time. - $result->content = format_module_intro('ratingallocate', $ratingallocate, $coursemodule->id, false); + $result->content = format_module_intro(RATINGALLOCATE_MOD_NAME, $ratingallocate, $coursemodule->id, false); + } + + // Populate the custom completion rules as key => value pairs, but only if the completion mode is 'automatic'. + if ($coursemodule->completion == COMPLETION_TRACKING_AUTOMATIC) { + $result->customdata['customcompletionrules']['completionvote'] = $ratingallocate->completionvote; + $result->customdata['customcompletionrules']['completionallocation'] = $ratingallocate->completionallocation; } // Populate some other values that can be used in calendar or on dashboard. @@ -787,3 +797,37 @@ function ratingallocate_get_coursemodule_info($coursemodule) { return $result; } + +/** + * Callback which returns human-readable strings describing the active completion custom rules for the module instance. + * + * @param cm_info|stdClass $cm object with fields ->completion and ->customdata['customcompletionrules'] + * @return array $descriptions the array of descriptions for the custom rules. + */ +function mod_ratingallocate_get_completion_active_rule_descriptions($cm) { + // Values will be present in cm_info, and we assume these are up to date. + if (empty($cm->customdata['customcompletionrules']) || $cm->completion != COMPLETION_TRACKING_AUTOMATIC) { + return []; + } + + $descriptions = []; + + foreach ($cm->customdata['customcompletionrules'] as $key => $val) { + switch ($key) { + case 'completionvote': + if ($val == 1) { + $descriptions[] = get_string('copletionvotedesc', RATINGALLOCATE_MOD_NAME); + } + break; + case 'completionallocation': + if ($val == 1) { + $descriptions[] = get_string('copletionallocationdesc', RATINGALLOCATE_MOD_NAME); + } + break; + default: + break; + } + } + + return $descriptions; +} diff --git a/locallib.php b/locallib.php index fc9f82fe..dea65099 100644 --- a/locallib.php +++ b/locallib.php @@ -187,6 +187,7 @@ class ratingallocate { /** * Returns all users enrolled in the course the ratingallocate is in, who were able to access the activity + * @return Array of user records * @throws moodle_exception */ public function get_raters_in_course(): array { @@ -303,6 +304,13 @@ private function process_action_start_distribution() { \core\output\notification::NOTIFY_SUCCESS); } } + $raters = $this->get_raters_in_course(); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($raters as $rater) { + $completion->update_state($this->coursemodule, COMPLETION_UNKNOWN, $rater->id); + } + } redirect(new moodle_url('/mod/ratingallocate/view.php', ['id' => $this->coursemodule->id])); return; @@ -645,6 +653,14 @@ private function process_action_delete_choice() { $DB->delete_records(this_db\ratingallocate_ch_gengroups::TABLE, ['choiceid' => $choiceid]); $DB->delete_records(this_db\ratingallocate_choices::TABLE, ['id' => $choiceid]); + $raters = $this->get_raters_in_course(); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($raters as $rater) { + $completion->update_state($this->coursemodule, COMPLETION_INCOMPLETE, $rater->id); + } + } + redirect(new moodle_url('/mod/ratingallocate/view.php', ['id' => $this->coursemodule->id, 'action' => ACTION_SHOW_CHOICES]), get_string('choice_deleted_notification', RATINGALLOCATE_MOD_NAME, @@ -727,6 +743,13 @@ private function process_action_manual_allocation() { ['id' => $this->coursemodule->id, 'action' => ACTION_MANUAL_ALLOCATION])); } } + $raters = $this->get_raters_in_course(); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($raters as $rater) { + $completion->update_state($this->coursemodule, COMPLETION_UNKNOWN, $rater->id); + } + } } $output .= $OUTPUT->heading(get_string('manual_allocation', RATINGALLOCATE_MOD_NAME), 2); @@ -1020,6 +1043,13 @@ public function distribute_users_without_choice(string $distributionalgorithm): // At this point we tried to assign all the users. It is possible that users remain undistributed, though. $transaction->allow_commit(); + + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($possibleusers as $userid) { + $completion->update_state($this->coursemodule, COMPLETION_UNKNOWN, $userid); + } + } } /** @@ -1195,6 +1225,9 @@ private function process_default() { } + $completion = new completion_info($this->course); + $completion->set_module_viewed($this->coursemodule); + // Logging. $event = \mod_ratingallocate\event\ratingallocate_viewed::create_simple( context_module::instance($this->coursemodule->id), $this->ratingallocateid); @@ -1402,6 +1435,15 @@ public function distrubute_choices() { $distributor = new solver_edmonds_karp(); $timestart = microtime(true); $distributor->distribute_users($this); + + $completion = new completion_info($this->course); + $raters = $this->get_raters_in_course(); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($raters as $rater) { + $completion->update_state($this->coursemodule, COMPLETION_UNKNOWN, $rater->id); + } + + } $timeneeded = (microtime(true) - $timestart); // Set algorithm status to finished. @@ -1611,8 +1653,16 @@ public function get_allocations() { * Removes all allocations for choices in $ratingallocateid */ public function clear_all_allocations() { - $this->db->delete_records('ratingallocate_allocations', ['ratingallocateid' => intval - ($this->ratingallocateid)]); + $this->db->delete_records('ratingallocate_allocations', ['ratingallocateid' => intval($this->ratingallocateid)]); + $raters = $this->get_raters_in_course(); + + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($raters as $rater) { + $completion->update_state($this->coursemodule, COMPLETION_INCOMPLETE, $rater->id); + } + } + } /** @@ -1751,7 +1801,7 @@ public function get_users_with_ratings() { * Deletes all ratings in this ratingallocate */ public function delete_all_ratings() { - global $DB; + global $DB, $USER; $transaction = $DB->start_delegated_transaction(); @@ -1772,6 +1822,11 @@ public function delete_all_ratings() { $transaction->allow_commit(); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + $completion->update_state($this->coursemodule, COMPLETION_INCOMPLETE, $USER->id); + } + // Logging. $event = \mod_ratingallocate\event\all_ratings_deleted::create_simple( context_module::instance($this->coursemodule->id), $this->ratingallocateid); @@ -1806,6 +1861,11 @@ public function delete_ratings_of_user($userid) { $transaction->allow_commit(); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + $completion->update_state($this->coursemodule, COMPLETION_INCOMPLETE, $userid); + } + // Logging. $event = \mod_ratingallocate\event\rating_deleted::create_simple( context_module::instance($this->coursemodule->id), $this->ratingallocateid); @@ -1862,7 +1922,10 @@ public function save_ratings_to_db($userid, array $data) { $transaction->allow_commit(); $completion = new completion_info($this->course); - $completion->set_module_viewed($this->coursemodule); + if ($completion->is_enabled()) { + $completion->set_module_viewed($this->coursemodule, $userid); + $completion->update_state($this->coursemodule, COMPLETION_UNKNOWN, $userid); + } // Logging. $event = \mod_ratingallocate\event\rating_saved::create_simple( @@ -2000,6 +2063,14 @@ public function save_manual_allocation_form($allocdata, $userdata) { $event->trigger(); $transaction->allow_commit(); + + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + foreach ($allusers as $rater) { + $completion->update_state($this->coursemodule, COMPLETION_UNKNOWN, $rater->id); + } + } + } catch (Exception $e) { if (isset($transaction)) { $transaction->rollback($e); @@ -2054,6 +2125,10 @@ public function remove_allocation($choiceid, $userid) { 'choiceid' => $choiceid, 'userid' => $userid, ]); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + $completion->update_state($this->coursemodule, COMPLETION_INCOMPLETE, $userid); + } return true; } @@ -2067,6 +2142,10 @@ public function remove_allocations($userid) { 'userid' => $userid, 'ratingallocateid' => $this->ratingallocateid, ]); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + $completion->update_state($this->coursemodule, COMPLETION_INCOMPLETE, $userid); + } } /** @@ -2081,6 +2160,10 @@ public function add_allocation($choiceid, $userid) { 'userid' => $userid, 'ratingallocateid' => $this->ratingallocateid, ]); + $completion = new completion_info($this->course); + if ($completion->is_enabled($this->coursemodule)) { + $completion->update_state($this->coursemodule, COMPLETION_COMPLETE, $userid); + } return true; } diff --git a/mod_form.php b/mod_form.php index 0879f737..42510f15 100644 --- a/mod_form.php +++ b/mod_form.php @@ -231,7 +231,7 @@ private function add_settings_field($stratfieldid, array $value, $strategyid, Mo * @throws coding_exception */ public function definition_after_data() { - parent::definition_after_data(); + $mform = &$this->_form; $data = $this->current; @@ -272,8 +272,12 @@ public function definition_after_data() { } $mform->removeElement($strategyplaceholder); } + + // Call parent function after, in order to have completiontracking working properly. + parent::definition_after_data(); } + /** * Checks that accesstimestart is before accesstimestop */ @@ -324,4 +328,88 @@ public function validation($data, $files) { private function get_settingsfield_identifier($strategy, $key) { return self::STRATEGY_OPTIONS . '[' . $strategy . '][' . $key . ']'; } + + /** + * Add elements for setting the custom completion rules. + * + * @return array List of added element names. + */ + public function add_completion_rules() { + $mform = $this->_form; + + $mform->addElement('advcheckbox', $this->get_suffixed_name('vote'), ' ', get_string('completionvote', RATINGALLOCATE_MOD_NAME)); + $mform->addElement('advcheckbox', $this->get_suffixed_name('allocation'), ' ', get_string('completionallocation', RATINGALLOCATE_MOD_NAME)); + + // Set default to not checked. + $mform->setDefault($this->get_suffixed_name('vote'), 0); + $mform->setDefault($this->get_suffixed_name('allocation'), 0); + + // Add help buttons. + $mform->addHelpButton($this->get_suffixed_name('vote'), 'completionvote', RATINGALLOCATE_MOD_NAME); + $mform->addHelpButton($this->get_suffixed_name('allocation'), 'completionallocation', RATINGALLOCATE_MOD_NAME); + + return [$this->get_suffixed_name('vote'), $this->get_suffixed_name('allocation')]; + } + + /** + * Returns the suffixed name for custom completion elements. + * + * @param string $fieldname + * @return string + */ + protected function get_suffixed_name(string $fieldname): string { + // Counterintuitively don't use function get_suffix(), since data isn't saved correctly in DB otherwise. + return 'completion' . $fieldname; + } + + /** + * Called during validaiton to see wether some activitiy-specific completion rules are selected. + * + * @param array $data Input data not yet validated. + * @return bool True if one or more rules are enabled, false if none are. + */ + public function completion_rule_enabled($data) { + return ($data[$this->get_suffixed_name('vote')] == 1 || $data[$this->get_suffixed_name('allocation')] == 1); + } + + /** + * Allows module to modify data returned by get_moduleinfo_data() or prepare_new_moduleinfo_data() before calling set_data(). + * This method is also called in the bulk activity completion form. + * Only available on moodleform_mod. + * + * @param $defaultvalues + * @return void + */ + public function data_preprocessing(&$defaultvalues) { + if (empty($defaultvalues[$this->get_suffixed_name('vote')])) { + $defaultvalues[$this->get_suffixed_name('vote')] = 0; + } + if (empty($defaultvalues[$this->get_suffixed_name('allocation')])) { + $defaultvalues[$this->get_suffixed_name('allocation')] = 0; + } + } + + /** + * Allows module to modify the data returned by form get_data(). + * This method is also called in the bulk activity completion form. + * + * Only available on moodleform_mod. + * + * @param stdClass $data the form data to be modified. + */ + public function data_postprocessing($data) { + parent::data_postprocessing($data); + // Turn off completion settings if the checkboxes aren't ticked. + if (!empty($data->completionunlocked)) { + $completion = $data->completion; + $autocompletion = !empty($completion) && $completion == COMPLETION_TRACKING_AUTOMATIC; + if (empty($data->{$this->get_suffixed_name('vote')}) || !$autocompletion) { + $data->{$this->get_suffixed_name('vote')} = 0; + } + if (empty($data->{$this->get_suffixed_name('allocation')}) || !$autocompletion) { + $data->{$this->get_suffixed_name('allocation')} = 0; + } + } + } + } diff --git a/tests/behat/completion_condition_allocation.feature b/tests/behat/completion_condition_allocation.feature new file mode 100644 index 00000000..ab83b5a1 --- /dev/null +++ b/tests/behat/completion_condition_allocation.feature @@ -0,0 +1,48 @@ +@mod @mod_ratingallocate @core_completion +Feature: Set a ratingallocate activity marked as completed when a user has been allocated + In order to ensure a student has been allocated + As a teacher + I need to set the ratingallocate to complete when the student has an allocation + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | student1 | Student | 1 | student1@example.com | + | student2 | Student | 2 | student2@example.com | + | teacher1 | Teacher | 1 | teacher1@example.com | + And the following "courses" exist: + | fullname | shortname | category | enablecompletion | + | Course 1 | C1 | 0 | 1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + And the following "activities" exist: + | activity | course | idnumber | name | completion | completionallocation | accesstimestart | accesstimestop | + | ratingallocate | C1 | ra1 | My Fair Allocation | 2 | 1 | ##2 days ago## | ##yesterday## | + And the following choices exist: + | title | explanation | maxsize | ratingallocate | + | C1 | Test | 1 | My Fair Allocation | + | C2 | Test | 0 | My Fair Allocation | + And the following ratings exist: + | choice | user | rating | + | C1 | student1 | 1 | + | C1 | student2 | 0 | + | C2 | student1 | 0 | + | C2 | student2 | 0 | + And I log in as "teacher1" + And I am on the "My Fair Allocation" "mod_ratingallocate > View" page + And I run the scheduled task "mod_ratingallocate\task\cron_task" + And I press "Publish Allocation" + And I wait "1" seconds + And I run the scheduled task "core\task\completion_regular_task" + And I wait "1" seconds + And I log out + + @javascript + Scenario: User completes ratingallocate only if they have been allocated + When I log in as "teacher1" + And I am on "Course 1" course homepage + Then "Student 1" user has completed "My Fair Allocation" activity + And "Student 2" user has not completed "My Fair Allocation" activity diff --git a/tests/behat/completion_condition_vote.feature b/tests/behat/completion_condition_vote.feature new file mode 100644 index 00000000..b904d29f --- /dev/null +++ b/tests/behat/completion_condition_vote.feature @@ -0,0 +1,43 @@ +@mod @mod_ratingallocate @core_completion +Feature: Set a ratingallocate activity marked as completed when a user submits a vote + In order to ensure a student has voted in the activity + As a teacher + I need to set the ratingallocate to complete when the student has voted + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | student1 | Student | 1 | student1@example.com | + | student2 | Student | 2 | student2@example.com | + | teacher1 | Teacher | 1 | teacher1@example.com | + And the following "courses" exist: + | fullname | shortname | category | enablecompletion | + | Course 1 | C1 | 0 | 1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + And the following "activities" exist: + | activity | course | idnumber | name | completion | completionvote | + | ratingallocate | C1 | ra1 | My Fair Allocation | 2 | 1 | + And I log in as "teacher1" + And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page + And I add a new choice with the values: + | title | My first choice | + | Description (optional) | Test 1 | + | maxsize | 2 | + + @javascript + Scenario: User completes ratingallocate only if they voted + When I log in as "student1" + And I am on the "My Fair Allocation" "mod_ratingallocate > View" page + And I press "Edit Rating" + And I press "Save changes" + And I log out + And I log in as "teacher1" + And I am on "Course 1" course homepage + And I navigate to "Reports" in current page administration + And I click on "Activity completion" "link" + Then "Completed" "icon" should exist in the "Student 1" "table_row" + And "Completed" "icon" should not exist in the "Student 2" "table_row" diff --git a/tests/behat/completion_manual.feature b/tests/behat/completion_manual.feature new file mode 100644 index 00000000..8e14026a --- /dev/null +++ b/tests/behat/completion_manual.feature @@ -0,0 +1,41 @@ +@mod @mod_ratingallocate @core_completion +Feature: Manually mark a ratingallocate activity as completed + In order to meet manual ratingallocate completion requirements + As a student + I need to be able to view and modify my ratingallocate manual completion status + + Background: + 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 | enablecompletion | + | Course 1 | C1 | 0 | 1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + And the following "activities" exist: + | activity | course | idnumber | name | completion | + | ratingallocate | C1 | ra1 | My Fair Allocation | 1 | + And I log in as "teacher1" + And I am on the "My Fair Allocation" "mod_ratingallocate > Choices" page + And I add a new choice with the values: + | title | My first choice | + | Description (optional) | Test 1 | + | maxsize | 2 | + + @javascript + Scenario: Use manual completion as teacher + When I log in as "teacher1" + And I am on the "My Fair Allocation" "mod_ratingallocate > View" page + Then the manual completion button for "My Fair Allocation" should be disabled + + @javascript + Scenario: Use manual completion student view + When I log in as "student1" + And I am on the "My Fair Allocation" "mod_ratingallocate > View" page + Then the manual completion button of "My Fair Allocation" is displayed as "Mark as done" + And I toggle the manual completion state of "My Fair Allocation" + And the manual completion button of "My Fair Allocation" is displayed as "Done" diff --git a/tests/mod_generator_test.php b/tests/mod_generator_test.php index f3c2d233..f3ada301 100644 --- a/tests/mod_generator_test.php +++ b/tests/mod_generator_test.php @@ -73,6 +73,8 @@ public function test_create_instance(): void { 'algorithmstarttime' => null, 'algorithmstatus' => '0', 'runalgorithmbycron' => '1', + 'completionvote' => '0', + 'completionallocation' => '0', ]; $this->assertEquals(json_decode(json_encode($expectedvaluesdb, false)), reset($records)); diff --git a/version.php b/version.php index b122377e..bf60a6cc 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024060300; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2024080900; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2022112800; // Requires Moodle 4.1 and higher. $plugin->maturity = MATURITY_STABLE; $plugin->release = 'v4.4-r1';