Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84d3ae1b08 | |||
| 71f83af13c | |||
| d587d8b242 | |||
| f1b1570b02 | |||
| f9ca67a78d | |||
| c8f9140e70 | |||
| 47c211ba0e | |||
| 9f270d956e | |||
| 32ee8e3d34 | |||
| 77a1413fa0 | |||
| 14760d9787 | |||
| 03b6b93589 | |||
| 47402416fd | |||
| 0087cede97 | |||
| 264c405192 | |||
| 1742e0c27c | |||
| 7371cb4838 | |||
| c1512e8d89 | |||
| e5aaeed609 | |||
| a950ed04a7 | |||
| 964c98c8d9 | |||
| 635389b235 | |||
| 1385e3bc09 | |||
| 2dc581f717 | |||
| 4f8369c3f1 | |||
| 730b405d68 | |||
| 87c04f1e0b | |||
| f4df13fb6c | |||
| 4a8abf77ac | |||
| 7e48ec1820 | |||
| 05087afd40 | |||
| 56afed9678 | |||
| af8c168f78 | |||
| 4c52746b41 | |||
| 7768a35366 | |||
| 05847affc1 | |||
| f652a2b613 | |||
| 04d4cbde78 |
+2
-2
@@ -36,7 +36,7 @@ jobs:
|
||||
- php: 7.2
|
||||
env: DB=none TASK=CITEST
|
||||
- php: 7.2
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/gallium'
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present
|
||||
php: 7.2
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
env: DB=none TASK=CITEST
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 7.4
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/gallium'
|
||||
|
||||
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present)
|
||||
php: 7.4
|
||||
|
||||
@@ -20,9 +20,10 @@ Feature: Forms manipulation
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Quiz" to section "1"
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | name |
|
||||
| quiz | C1 | 1 | Quiz 1 |
|
||||
And I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
When I expand all fieldsets
|
||||
Then I should see "Close the quiz"
|
||||
And I should see "Group mode"
|
||||
|
||||
@@ -27,7 +27,8 @@ require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
$userid = required_param('userid', PARAM_INT); // The user id the key belongs to (for double-checking).
|
||||
$key = required_param('key', PARAM_ALPHANUMEXT); // The key generated by the tool_mobile_external::get_autologin_key() external function.
|
||||
$urltogo = optional_param('urltogo', $CFG->wwwroot, PARAM_URL); // URL to redirect.
|
||||
$urltogo = optional_param('urltogo', $CFG->wwwroot, PARAM_LOCALURL); // URL to redirect.
|
||||
$urltogo = $urltogo ?: $CFG->wwwroot;
|
||||
|
||||
$context = context_system::instance();
|
||||
$PAGE->set_context($context);
|
||||
|
||||
@@ -19,14 +19,13 @@ Feature: Backup user data
|
||||
And the following config values are set as admin:
|
||||
| coursebinenable | 1 | tool_recyclebin |
|
||||
| autohide | 0 | tool_recyclebin |
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | name | intro |
|
||||
| quiz | C1 | 1 | Quiz 1 | Test quiz description |
|
||||
|
||||
@javascript
|
||||
Scenario: Delete and restore a quiz with user data
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Quiz" to section "1" and I fill the form with:
|
||||
| Name | Quiz 1 |
|
||||
| Description | Test quiz description |
|
||||
Given I am on the "Quiz 1" "quiz activity" page logged in as teacher1
|
||||
And I add a "True/False" question to the "Quiz 1" quiz with:
|
||||
| Question name | TF1 |
|
||||
| Question text | First question |
|
||||
@@ -41,6 +40,8 @@ Feature: Backup user data
|
||||
| Correct answer | False |
|
||||
| Feedback for the response 'True'. | So you think it is true |
|
||||
| Feedback for the response 'False'. | So you think it is false |
|
||||
And I set the field "maxgrade" to "10.0"
|
||||
And I press "savechanges"
|
||||
And I log out
|
||||
When I am on the "Quiz 1" "quiz activity" page logged in as student1
|
||||
And I press "Attempt quiz now"
|
||||
|
||||
@@ -77,6 +77,7 @@ abstract class backup_cron_automated_helper {
|
||||
* First backup courses that do not have an entry in backup_courses first,
|
||||
* as they are likely new and never been backed up. Do the oldest modified courses first.
|
||||
* Then backup courses that have previously been backed up starting with the oldest next start time.
|
||||
* Finally, all else being equal, defer to the sortorder of the courses.
|
||||
*
|
||||
* @param null|int $now timestamp to use in course selection.
|
||||
* @return moodle_recordset The recordset of matching courses.
|
||||
@@ -93,7 +94,8 @@ abstract class backup_cron_automated_helper {
|
||||
LEFT JOIN {backup_courses} bc ON bc.courseid = c.id
|
||||
WHERE bc.nextstarttime IS NULL OR bc.nextstarttime < ?
|
||||
ORDER BY nextstarttime ASC,
|
||||
c.timemodified DESC';
|
||||
c.timemodified DESC,
|
||||
c.sortorder';
|
||||
|
||||
$params = array(
|
||||
$now, // Only get courses where the backup start time is in the past.
|
||||
|
||||
@@ -383,7 +383,7 @@ class backup_cron_helper_testcase extends advanced_testcase {
|
||||
$backupcourse3 = new stdClass;
|
||||
$backupcourse3->courseid = $course3->id;
|
||||
$backupcourse3->laststatus = testable_backup_cron_automated_helper::BACKUP_STATUS_OK;
|
||||
$backupcourse3->nextstarttime = 1554858160;
|
||||
$backupcourse3->nextstarttime = 1554822160;
|
||||
$DB->insert_record('backup_courses', $backupcourse3);
|
||||
|
||||
$backupcourse4 = new stdClass;
|
||||
|
||||
@@ -9,6 +9,9 @@ Feature: Comment on a blog entry
|
||||
| username | firstname | lastname | email |
|
||||
| testuser | Test | User | moodle@example.com |
|
||||
| testuser2 | Test2 | User2 | moodle2@example.com |
|
||||
And the following "core_blog > entries" exist:
|
||||
| subject | body | user |
|
||||
| Blog post from user 1 | User 1 blog post content | testuser |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
@@ -19,15 +22,6 @@ Feature: Comment on a blog entry
|
||||
| Page contexts | Display throughout the entire site |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "testuser"
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Site blogs" "link" in the "Navigation" "block"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | Blog post from user 1 |
|
||||
| Blog entry body | User 1 blog post content |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Commenting on my own blog entry
|
||||
|
||||
@@ -8,6 +8,10 @@ Feature: Delete a blog entry
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| testuser | Test | User | moodle@example.com |
|
||||
And the following "core_blog > entries" exist:
|
||||
| subject | body | user |
|
||||
| Blog post one | User 1 blog post content | testuser |
|
||||
| Blog post two | User 1 blog post content | testuser |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I turn editing mode on
|
||||
@@ -19,17 +23,6 @@ Feature: Delete a blog entry
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "testuser"
|
||||
And I click on "Site blogs" "link" in the "Navigation" "block"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | Blog post one |
|
||||
| Blog entry body | User 1 blog post content |
|
||||
And I press "Save changes"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | Blog post two |
|
||||
| Blog entry body | User 1 blog post content |
|
||||
And I press "Save changes"
|
||||
And I am on site homepage
|
||||
And I click on "Site blogs" "link" in the "Navigation" "block"
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Behat data generator for core_blog.
|
||||
*
|
||||
* @package core_blog
|
||||
* @category test
|
||||
* @copyright 2022 Noel De Martin
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behat data generator for core_blog.
|
||||
*
|
||||
* @package core_blog
|
||||
* @category test
|
||||
* @copyright 2022 Noel De Martin
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_core_blog_generator extends behat_generator_base {
|
||||
|
||||
/**
|
||||
* Get a list of the entities that can be created.
|
||||
*
|
||||
* @return array entity name => information about how to generate.
|
||||
*/
|
||||
protected function get_creatable_entities(): array {
|
||||
return [
|
||||
'entries' => [
|
||||
'singular' => 'entry',
|
||||
'datagenerator' => 'entry',
|
||||
'required' => ['subject', 'body'],
|
||||
'switchids' => ['user' => 'userid'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Generator for blog area.
|
||||
*
|
||||
* @package core_blog
|
||||
* @category test
|
||||
* @copyright 2022 Noel De Martin
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/blog/locallib.php');
|
||||
|
||||
/**
|
||||
* Blog module test data generator class
|
||||
*
|
||||
* @package core_blog
|
||||
* @category test
|
||||
* @copyright 2022 Noel De Martin
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_blog_generator extends component_generator_base {
|
||||
|
||||
/**
|
||||
* Create a blog entry
|
||||
*
|
||||
* @param array $data Entry data.
|
||||
* @return blog_entry Entry instance.
|
||||
*/
|
||||
public function create_entry(array $data = []): blog_entry {
|
||||
$data['publishstate'] = $data['publishstate'] ?? 'site';
|
||||
$data['summary'] = $data['summary'] ?? $data['body'];
|
||||
|
||||
$entry = new blog_entry(null, $data);
|
||||
$entry->add();
|
||||
|
||||
return $entry;
|
||||
}
|
||||
}
|
||||
@@ -34,9 +34,9 @@ Feature: Restrict sections availability through completion or grade conditions
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
And I press "Save and display"
|
||||
And I add a "Label" to section "1" and I fill the form with:
|
||||
| Label text | Test label |
|
||||
| Completion tracking | Students can manually mark the activity as completed |
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | intro | completion | idnumber |
|
||||
| label | C1 | 1 | Test label | 1 | 1 |
|
||||
And I add a "Page" to section "2" and I fill the form with:
|
||||
| Name | Test page name |
|
||||
| Description | Test page description |
|
||||
|
||||
@@ -12,7 +12,7 @@ Feature: We can change what we are viewing on the grader report
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 1 | student2@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
@@ -26,19 +26,15 @@ Feature: We can change what we are viewing on the grader report
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name 1 | student1 | This is a submission for assignment 1 |
|
||||
| Test assignment name 2 | student1 | This is a submission for assignment 2 |
|
||||
And I am on the "Test assignment name 1" "assign activity" page logged in as student1
|
||||
Then I should see "Submitted for grading"
|
||||
And I am on the "Test assignment name 2" "assign activity" page
|
||||
Then I should see "Submitted for grading"
|
||||
And I log out
|
||||
And the following "grade items" exist:
|
||||
| itemname | grademin | grademax | course |
|
||||
| Manual grade | 20 | 40 | C1 |
|
||||
And the following "grade grades" exist:
|
||||
| gradeitem | user | grade |
|
||||
| Test assignment name 1 | student1 | 80 |
|
||||
| Test assignment name 2 | student1 | 90 |
|
||||
| Manual grade | student1 | 30 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "80.00" to the user "Student 1" for the grade item "Test assignment name 1"
|
||||
And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment name 2"
|
||||
And I press "Save changes"
|
||||
And I turn editing mode off
|
||||
|
||||
@javascript
|
||||
Scenario: View and minimise the grader report containing hidden activities
|
||||
@@ -49,13 +45,15 @@ Feature: We can change what we are viewing on the grader report
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- | -5- | -6- |
|
||||
| Student 1 | 80 | 90 | 170 |
|
||||
| -1- | -4- | -5- | -6- | -7- |
|
||||
| Student 1 | 80 | 90 | 30 | 170 |
|
||||
And I click on "Change to aggregates only" "link"
|
||||
And I should not see "Test assignment name 1"
|
||||
And I should not see "Test assignment name 2"
|
||||
And I should not see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- |
|
||||
@@ -63,10 +61,11 @@ Feature: We can change what we are viewing on the grader report
|
||||
And I click on "Change to grades only" "link"
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Manual grade"
|
||||
And I should not see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- | -5- |
|
||||
| Student 1 | 80 | 90 |
|
||||
| -1- | -4- | -5- | -6- |
|
||||
| Student 1 | 80 | 90 | 30 |
|
||||
|
||||
@javascript @skip_chrome_zerosize
|
||||
Scenario: View and minimise the grader report containing hidden activities without the 'moodle/grade:viewhidden' capability
|
||||
@@ -84,21 +83,24 @@ Feature: We can change what we are viewing on the grader report
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- | -5- | -6- |
|
||||
| Student 1 | 80 | - | 80 |
|
||||
| -1- | -4- | -5- | -6- | -7- |
|
||||
| Student 1 | 80 | - | 30 | 105.71 |
|
||||
And I click on "Change to aggregates only" "link"
|
||||
And I should not see "Test assignment name 1"
|
||||
And I should not see "Test assignment name 2"
|
||||
And I should not see "Manual grade"
|
||||
And I should see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- |
|
||||
| Student 1 | 80 |
|
||||
| Student 1 | 105.71 |
|
||||
And I click on "Change to grades only" "link"
|
||||
And I should see "Test assignment name 1"
|
||||
And I should see "Test assignment name 2"
|
||||
And I should see "Manual grade"
|
||||
And I should not see "Course total"
|
||||
And the following should exist in the "user-grades" table:
|
||||
| -1- | -4- | -5- |
|
||||
| Student 1 | 80 | - |
|
||||
| -1- | -4- | -5- | -6- |
|
||||
| Student 1 | 80 | - | 30 |
|
||||
|
||||
@@ -150,6 +150,12 @@ class behat_core_generator extends behat_generator_base {
|
||||
'required' => ['fullname', 'course'],
|
||||
'switchids' => ['course' => 'courseid', 'gradecategory' => 'parent'],
|
||||
],
|
||||
'grade grades' => [
|
||||
'singular' => 'grade grade',
|
||||
'datagenerator' => 'grade_grade',
|
||||
'required' => ['gradeitem'],
|
||||
'switchids' => ['user' => 'userid', 'gradeitem' => 'itemid'],
|
||||
],
|
||||
'grade items' => [
|
||||
'singular' => 'grade item',
|
||||
'datagenerator' => 'grade_item',
|
||||
@@ -275,11 +281,33 @@ class behat_core_generator extends behat_generator_base {
|
||||
'required' => ['user', 'course', 'lastaccess'],
|
||||
'switchids' => ['user' => 'userid', 'course' => 'courseid'],
|
||||
],
|
||||
'notifications' => [
|
||||
'singular' => 'notification',
|
||||
'datagenerator' => 'notification',
|
||||
'required' => ['subject', 'userfrom', 'userto'],
|
||||
'switchids' => ['userfrom' => 'userfromid', 'userto' => 'usertoid'],
|
||||
],
|
||||
];
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grade item id using a name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return int The grade item id
|
||||
*/
|
||||
protected function get_gradeitem_id(string $name): int {
|
||||
global $DB;
|
||||
|
||||
if (!$id = $DB->get_field('grade_items', 'id', ['itemname' => $name])) {
|
||||
throw new Exception('The specified grade item with name "' . $name . '" could not be found.');
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any empty custom fields, to avoid errors when creating the course.
|
||||
*
|
||||
@@ -1009,6 +1037,39 @@ class behat_core_generator extends behat_generator_base {
|
||||
$DB->insert_record('badge_backpack', $backpack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates notifications to specific user.
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected function process_notification(array $data) {
|
||||
global $DB;
|
||||
|
||||
$notification = new stdClass();
|
||||
$notification->useridfrom = $data['userfromid'];
|
||||
$notification->useridto = $data['usertoid'];
|
||||
$notification->subject = $data['subject'];
|
||||
$notification->fullmessage = $data['subject'] . ' description';
|
||||
$notification->smallmessage = $data['subject'] . ' description';
|
||||
$notification->fullmessagehtml = $data['subject'] . ' description';
|
||||
|
||||
if ($data['timecreated'] !== 'null') {
|
||||
$notification->timecreated = $data['timecreated'];
|
||||
}
|
||||
|
||||
if ($data['timeread'] !== 'null') {
|
||||
$notification->timeread = $data['timeread'];
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
$popupnotification = new stdClass();
|
||||
$popupnotification->notificationid = $DB->insert_record('notifications', $notification);
|
||||
$DB->insert_record('message_popup_notifications', $popupnotification);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates user last access data within given courses.
|
||||
*
|
||||
|
||||
@@ -316,6 +316,36 @@ abstract class behat_generator_base {
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user id from it's username.
|
||||
* @throws Exception
|
||||
* @param string $username
|
||||
* @return int
|
||||
*/
|
||||
protected function get_userfrom_id(string $username) {
|
||||
global $DB;
|
||||
|
||||
if (!$id = $DB->get_field('user', 'id', ['username' => $username])) {
|
||||
throw new Exception('The specified user with username "' . $username . '" does not exist');
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user id from it's username.
|
||||
* @throws Exception
|
||||
* @param string $username
|
||||
* @return int
|
||||
*/
|
||||
protected function get_userto_id(string $username) {
|
||||
global $DB;
|
||||
|
||||
if (!$id = $DB->get_field('user', 'id', ['username' => $username])) {
|
||||
throw new Exception('The specified user with username "' . $username . '" does not exist');
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the role id from it's shortname.
|
||||
* @throws Exception
|
||||
|
||||
@@ -111,7 +111,7 @@ abstract class scheduled_task extends task_base {
|
||||
*/
|
||||
public function set_minute($minute, $expandr = true) {
|
||||
if ($minute === 'R' && $expandr) {
|
||||
$minute = mt_rand(self::HOURMIN, self::HOURMAX);
|
||||
$minute = mt_rand(self::MINUTEMIN, self::MINUTEMAX);
|
||||
}
|
||||
$this->minute = $minute;
|
||||
}
|
||||
|
||||
+2
-2
@@ -242,8 +242,8 @@ $tasks = array(
|
||||
array(
|
||||
'classname' => 'core\task\check_for_updates_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '0',
|
||||
'hour' => '*/2',
|
||||
'minute' => 'R',
|
||||
'hour' => 'R',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
|
||||
@@ -38,7 +38,7 @@ class processor implements \core_analytics\classifier, \core_analytics\regresso
|
||||
/**
|
||||
* The required version of the python package that performs all calculations.
|
||||
*/
|
||||
const REQUIRED_PIP_PACKAGE_VERSION = '2.6.5';
|
||||
const REQUIRED_PIP_PACKAGE_VERSION = '2.6.6';
|
||||
|
||||
/**
|
||||
* The python package is installed in a server.
|
||||
|
||||
+12
-2
@@ -978,8 +978,18 @@ function clean_param($param, $type) {
|
||||
return preg_replace('/[^a-zA-Z0-9_-]/i', '', $param);
|
||||
|
||||
case PARAM_SAFEPATH:
|
||||
// Remove everything not a-zA-Z0-9/_- .
|
||||
return preg_replace('/[^a-zA-Z0-9\/_-]/i', '', $param);
|
||||
// Replace MS \ separators.
|
||||
$param = str_replace('\\', '/', $param);
|
||||
// Remove any number of ../ to prevent path traversal.
|
||||
$param = preg_replace('/\.\.+\//', '', $param);
|
||||
// Remove everything not a-zA-Z0-9/:_- .
|
||||
$param = preg_replace('/[^a-zA-Z0-9\/:_-]/i', '', $param);
|
||||
// Remove leading slash.
|
||||
$param = ltrim($param, '/');
|
||||
if ($param === '.') {
|
||||
$param = '';
|
||||
}
|
||||
return $param;
|
||||
|
||||
case PARAM_FILE:
|
||||
// Strip all suspicious characters from filename.
|
||||
|
||||
@@ -1002,6 +1002,57 @@ EOD;
|
||||
return $gradecategory->get_record_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a grade_grade.
|
||||
*
|
||||
* @param array $record
|
||||
* @return grade_grade the grade record
|
||||
*/
|
||||
public function create_grade_grade(?array $record = null): grade_grade {
|
||||
global $DB, $USER;
|
||||
|
||||
$item = $DB->get_record('grade_items', ['id' => $record['itemid']]);
|
||||
$userid = $record['userid'] ?? $USER->id;
|
||||
|
||||
unset($record['itemid']);
|
||||
unset($record['userid']);
|
||||
|
||||
if ($item->itemtype === 'mod') {
|
||||
$cm = get_coursemodule_from_instance($item->itemmodule, $item->iteminstance);
|
||||
$module = new $item->itemmodule(context_module::instance($cm->id), $cm, false);
|
||||
$record['attemptnumber'] = $record['attemptnumber'] ?? 0;
|
||||
|
||||
$module->save_grade($userid, (object) $record);
|
||||
|
||||
$grade = grade_grade::fetch(['userid' => $userid, 'itemid' => $item->id]);
|
||||
} else {
|
||||
$grade = grade_grade::fetch(['userid' => $userid, 'itemid' => $item->id]);
|
||||
$record['rawgrade'] = $record['rawgrade'] ?? $record['grade'] ?? null;
|
||||
$record['finalgrade'] = $record['finalgrade'] ?? $record['grade'] ?? null;
|
||||
|
||||
unset($record['grade']);
|
||||
|
||||
if ($grade) {
|
||||
$fields = $grade->required_fields + array_keys($grade->optional_fields);
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$grade->{$field} = $record[$field] ?? $grade->{$field};
|
||||
}
|
||||
|
||||
$grade->update();
|
||||
} else {
|
||||
$record['userid'] = $userid;
|
||||
$record['itemid'] = $item->id;
|
||||
|
||||
$grade = new grade_grade($record, false);
|
||||
|
||||
$grade->insert();
|
||||
}
|
||||
}
|
||||
|
||||
return $grade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a grade_item.
|
||||
*
|
||||
|
||||
@@ -839,6 +839,40 @@ class core_moodlelib_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide some tested base url and expected results.
|
||||
*
|
||||
* @return array Array of tested base url and expected results.
|
||||
*/
|
||||
public function clean_param_safepath_provider(): array {
|
||||
return [
|
||||
// MS separator test.
|
||||
['c:\temp', 'c:/temp'],
|
||||
|
||||
// Leading slash test.
|
||||
['/tmp/', 'tmp/'],
|
||||
|
||||
// Path traversal test.
|
||||
['../../../../../etc/', 'etc/'],
|
||||
['../', ''],
|
||||
['.../...//', ''],
|
||||
['.', '']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test clean_param() method with PARAM_SAFEPATH type.
|
||||
*
|
||||
* @dataProvider clean_param_safepath_provider
|
||||
* @covers ::clean_param
|
||||
* @param string $path
|
||||
* @param string $expected
|
||||
*/
|
||||
public function test_clean_param_safepath(string $path, string $expected) {
|
||||
$result = clean_param($path, PARAM_SAFEPATH);
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function test_validate_param() {
|
||||
try {
|
||||
$param = validate_param('11a', PARAM_INT);
|
||||
|
||||
@@ -30,6 +30,7 @@ use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\userlist;
|
||||
use core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\approved_userlist;
|
||||
|
||||
/**
|
||||
@@ -42,6 +43,7 @@ use \core_privacy\local\request\approved_userlist;
|
||||
class provider implements
|
||||
\core_privacy\local\metadata\provider,
|
||||
\core_privacy\local\request\core_userlist_provider,
|
||||
\core_privacy\local\request\user_preference_provider,
|
||||
\core_privacy\local\request\plugin\provider {
|
||||
|
||||
/**
|
||||
@@ -125,4 +127,21 @@ class provider implements
|
||||
*/
|
||||
public static function delete_data_for_user(approved_contextlist $contextlist) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user preferences for the plugin
|
||||
*
|
||||
* @param int $userid
|
||||
*/
|
||||
public static function export_user_preferences(int $userid) {
|
||||
$preference = get_user_preferences('message_processor_email_email', null, $userid);
|
||||
if (!empty($preference)) {
|
||||
writer::export_user_preference(
|
||||
'message_email',
|
||||
'email',
|
||||
$preference,
|
||||
get_string('privacy:preference:email', 'message_email')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ $string['privacy:metadata:replyto'] = 'The email address to reply to.';
|
||||
$string['privacy:metadata:replytoname'] = 'Name of reply to recipient.';
|
||||
$string['privacy:metadata:subject'] = 'The subject line of the message.';
|
||||
$string['privacy:metadata:userfrom'] = 'The user sending the message.';
|
||||
$string['privacy:preference:email'] = 'Preferred email notification address';
|
||||
$string['tasksendemail'] = 'Messages digest mailings';
|
||||
|
||||
// Deprecated since Moodle 3.9.
|
||||
|
||||
@@ -13,28 +13,27 @@
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/**
|
||||
* Base class for unit tests for message_email.
|
||||
*
|
||||
* @package message_email
|
||||
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
namespace message_email\privacy;
|
||||
|
||||
use context_system;
|
||||
use core_message_external;
|
||||
use core_privacy\local\request\writer;
|
||||
use core_privacy\tests\provider_testcase;
|
||||
|
||||
use \core_privacy\tests\provider_testcase;
|
||||
/**
|
||||
* Unit tests for message\output\email\classes\privacy\provider.php
|
||||
*
|
||||
* @package message_email
|
||||
* @covers \message_email\privacy\provider
|
||||
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class message_email_testcase extends provider_testcase {
|
||||
class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Basic setup for these tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
public function setUp(): void {
|
||||
$this->resetAfterTest(true);
|
||||
}
|
||||
|
||||
@@ -56,5 +55,38 @@ class message_email_testcase extends provider_testcase {
|
||||
$contextlist = \message_email\privacy\provider::get_contexts_for_userid($user->id);
|
||||
$this->assertEmpty($contextlist);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exporting user preferences
|
||||
*/
|
||||
public function test_export_user_preferences(): void {
|
||||
global $CFG;
|
||||
|
||||
require_once("{$CFG->dirroot}/message/externallib.php");
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
// Submit configuration form, which adds the preferences..
|
||||
core_message_external::message_processor_config_form($user->id, 'email', [
|
||||
[
|
||||
'name' => 'email_email',
|
||||
'value' => 'alternate@example.com',
|
||||
],
|
||||
]);
|
||||
|
||||
// Switch to admin user (so we can validate preferences of the correct user are being exported).
|
||||
$this->setAdminUser();
|
||||
|
||||
provider::export_user_preferences($user->id);
|
||||
|
||||
$writer = writer::with_context(context_system::instance());
|
||||
$this->assertTrue($writer->has_any_data());
|
||||
|
||||
$preferences = $writer->get_user_preferences('message_email');
|
||||
$this->assertNotEmpty($preferences->email);
|
||||
|
||||
$this->assertEquals('alternate@example.com', $preferences->email->value);
|
||||
$this->assertEquals(get_string('privacy:preference:email', 'message_email'), $preferences->email->description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,61 +5,41 @@ Feature: Notification popover unread notifications
|
||||
I am notified about relevant events in Moodle
|
||||
|
||||
Background:
|
||||
# This will make sure popup notifications are enabled and create
|
||||
# two assignment notifications. One for the student submitting their
|
||||
# assignment and another for the teacher grading it.
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
# Make sure the popup notifications are enabled for assignments.
|
||||
And the following config values are set as admin:
|
||||
| popup_provider_mod_assign_assign_notification_permitted | permitted | message |
|
||||
| message_provider_mod_assign_assign_notification_loggedin | popup | message |
|
||||
| message_provider_mod_assign_assign_notification_loggedoff | popup | message |
|
||||
And the following "users" exist:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| submissiondrafts | 0 |
|
||||
# This should generate a notification.
|
||||
And the following "mod_assign > submissions" exist:
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name | student1 | I'm the student1 submission |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
# This should generate some notifications
|
||||
And the following "notifications" exist:
|
||||
| subject | userfrom | userto | timecreated | timeread |
|
||||
| Test 01 | student2 | student1 | 1654587996 | null |
|
||||
| Test 02 | student2 | student1 | 1654587997 | null |
|
||||
|
||||
Scenario: Notification popover shows correct unread count
|
||||
When I log in as "student1"
|
||||
Given I log in as "student1"
|
||||
# Confirm the popover is saying 1 unread notifications.
|
||||
Then I should see "1" in the "#nav-notification-popover-container [data-region='count-container']" "css_element"
|
||||
And I should see "2" in the "#nav-notification-popover-container [data-region='count-container']" "css_element"
|
||||
# Open the popover.
|
||||
And I open the notification popover
|
||||
# Confirm the submission notification is visible.
|
||||
And I should see "You have submitted your assignment submission for Test assignment name" in the "#nav-notification-popover-container" "css_element"
|
||||
When I open the notification popover
|
||||
# Confirm the notifications are visible.
|
||||
Then I should see "Test 01" in the "#nav-notification-popover-container" "css_element"
|
||||
And I should see "Test 02" in the "#nav-notification-popover-container" "css_element"
|
||||
|
||||
@_bug_phantomjs
|
||||
Scenario: Clicking a notification marks it as read
|
||||
When I log in as "student1"
|
||||
# Open the popover.
|
||||
Given I log in as "student1"
|
||||
# Open the notifications.
|
||||
When I open the notification popover
|
||||
And I follow "Test 01"
|
||||
And I open the notification popover
|
||||
# Click on the submission notification.
|
||||
And I follow "You have submitted your assignment submission for Test assignment name"
|
||||
And I follow "Test 02"
|
||||
|
||||
# Confirm the count element is hidden (i.e. there are no unread notifications).
|
||||
Then "[data-region='count-container']" "css_element" in the "#nav-notification-popover-container" "css_element" should not be visible
|
||||
|
||||
Scenario: Mark all notifications as read
|
||||
When I log in as "student1"
|
||||
# Open the popover.
|
||||
And I open the notification popover
|
||||
# Click the mark all as read button.
|
||||
Given I log in as "student1"
|
||||
When I open the notification popover
|
||||
And I click on "Mark all as read" "link" in the "#nav-notification-popover-container" "css_element"
|
||||
# Refresh the page to make sure we send a new request for the unread count.
|
||||
And I reload the page
|
||||
|
||||
@@ -632,7 +632,7 @@ class pdf extends TcpdfFpdi {
|
||||
$gsexec = \escapeshellarg($CFG->pathtogs);
|
||||
$tempdstarg = \escapeshellarg($tempdst);
|
||||
$tempsrcarg = \escapeshellarg($tempsrc);
|
||||
$command = "$gsexec -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=$tempdstarg $tempsrcarg";
|
||||
$command = "$gsexec -q -sDEVICE=pdfwrite -dSAFER -dBATCH -dNOPAUSE -sOutputFile=$tempdstarg $tempsrcarg";
|
||||
exec($command);
|
||||
if (!file_exists($tempdst)) {
|
||||
// Something has gone wrong in the conversion.
|
||||
|
||||
@@ -24,32 +24,27 @@ Feature: Users can view and search database entries
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| data | Test database name | Database intro | C1 | data1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Text input" field to "Test database name" database and I fill the form with:
|
||||
| Field name | Test field name |
|
||||
| Field description | Test field description |
|
||||
And I add a "Text input" field to "Test database name" database and I fill the form with:
|
||||
| Field name | Test field 2 name |
|
||||
| Field description | Test field 2 description |
|
||||
# To generate the default templates.
|
||||
And I follow "Templates"
|
||||
And I log out
|
||||
And the following "mod_data > fields" exist:
|
||||
| database | type | name | description |
|
||||
| data1 | text | Test field name | Test field description |
|
||||
| data1 | text | Test field 2 name | Test field 2 description |
|
||||
And the following "mod_data > templates" exist:
|
||||
| database | name |
|
||||
| data1 | singletemplate |
|
||||
| data1 | listtemplate |
|
||||
| data1 | addtemplate |
|
||||
| data1 | asearchtemplate |
|
||||
| data1 | rsstemplate |
|
||||
|
||||
Scenario: Students can add view, list and search entries
|
||||
Given I log in as "student1"
|
||||
Given the following "mod_data > entries" exist:
|
||||
| database | Test field name | Test field 2 name |
|
||||
| data1 | Student entry 1 | |
|
||||
| data1 | Student entry 2 | |
|
||||
| data1 | Student entry 3 | |
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test database name"
|
||||
And I add an entry to "Test database name" database with:
|
||||
| Test field name | Student entry 1 |
|
||||
And I press "Save and add another"
|
||||
And I add an entry to "Test database name" database with:
|
||||
| Test field name | Student entry 2 |
|
||||
And I press "Save and add another"
|
||||
And I add an entry to "Test database name" database with:
|
||||
| Test field name | Student entry 3 |
|
||||
And I press "Save and view"
|
||||
And I follow "Test database name"
|
||||
Then I should see "Student entry 1"
|
||||
And I should see "Student entry 2"
|
||||
And I should see "Student entry 3"
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Behat data generator for mod_data.
|
||||
*
|
||||
* @package mod_data
|
||||
* @category test
|
||||
* @copyright 2022 Noel De Martin
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_mod_data_generator extends behat_generator_base {
|
||||
|
||||
/**
|
||||
* Get a list of the entities that Behat can create using the generator step.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_creatable_entities(): array {
|
||||
return [
|
||||
'entries' => [
|
||||
'singular' => 'entry',
|
||||
'datagenerator' => 'entry',
|
||||
'required' => ['database'],
|
||||
'switchids' => ['database' => 'databaseid'],
|
||||
],
|
||||
'fields' => [
|
||||
'singular' => 'field',
|
||||
'datagenerator' => 'field',
|
||||
'required' => ['database', 'type', 'name'],
|
||||
'switchids' => ['database' => 'databaseid'],
|
||||
],
|
||||
'templates' => [
|
||||
'singular' => 'template',
|
||||
'datagenerator' => 'template',
|
||||
'required' => ['database', 'name'],
|
||||
'switchids' => ['database' => 'databaseid'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database id using an activity idnumber.
|
||||
*
|
||||
* @param string $idnumber
|
||||
* @return int The database id
|
||||
*/
|
||||
protected function get_database_id(string $idnumber): int {
|
||||
$cm = $this->get_cm_by_activity_name('data', $idnumber);
|
||||
|
||||
return $cm->instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an entry.
|
||||
*
|
||||
* @param array $data Entry data.
|
||||
*/
|
||||
public function process_entry(array $data): void {
|
||||
global $DB;
|
||||
|
||||
$database = $DB->get_record('data', ['id' => $data['databaseid']], '*', MUST_EXIST);
|
||||
|
||||
unset($data['databaseid']);
|
||||
|
||||
$data = array_reduce(array_keys($data), function ($fields, $fieldname) use ($data, $database) {
|
||||
global $DB;
|
||||
|
||||
$field = $DB->get_record('data_fields', ['name' => $fieldname, 'dataid' => $database->id], 'id', MUST_EXIST);
|
||||
|
||||
$fields[$field->id] = $data[$fieldname];
|
||||
|
||||
return $fields;
|
||||
}, []);
|
||||
|
||||
$this->get_data_generator()->create_entry($database, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field.
|
||||
*
|
||||
* @param array $data Field data.
|
||||
*/
|
||||
public function process_field(array $data): void {
|
||||
global $DB;
|
||||
|
||||
$database = $DB->get_record('data', ['id' => $data['databaseid']], '*', MUST_EXIST);
|
||||
|
||||
unset($data['databaseid']);
|
||||
|
||||
$this->get_data_generator()->create_field((object) $data, $database);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a template.
|
||||
*
|
||||
* @param array $data Template data.
|
||||
*/
|
||||
public function process_template(array $data): void {
|
||||
global $DB;
|
||||
|
||||
$database = $DB->get_record('data', ['id' => $data['databaseid']], '*', MUST_EXIST);
|
||||
|
||||
if (empty($data['content'])) {
|
||||
data_generate_default_template($database, $data['name']);
|
||||
} else {
|
||||
$newdata = new stdClass();
|
||||
$newdata->id = $database->id;
|
||||
$newdata->{$data['name']} = $data['content'];
|
||||
$DB->update_record('data', $newdata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module data generator.
|
||||
*
|
||||
* @return mod_data_generator Database data generator.
|
||||
*/
|
||||
protected function get_data_generator(): mod_data_generator {
|
||||
return $this->componentdatagenerator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,15 +42,36 @@ Feature: Posting to all groups in a separate group discussion is restricted to u
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | groupmode |
|
||||
| forum | Standard forum name | Standard forum description | C1 | sepgroups | 1 |
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| forum | name | subject | message | group |
|
||||
| sepgroups | Initial Disc ALL | Initial Disc ALL | Disc ALL content | All participants |
|
||||
| sepgroups | Initial Disc G1 | Initial Disc G1 | Disc G1 content | G1 |
|
||||
| sepgroups | Initial Disc G2 | Initial Disc G2 | Disc G2 content | G2 |
|
||||
| sepgroups | Initial Disc G3 | Initial Disc G3 | Disc G3 content | G3 |
|
||||
|
||||
Scenario: Teacher with accessallgroups can view all groups
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Standard forum name"
|
||||
Then the "Separate groups" select box should contain "All participants"
|
||||
Then the "Separate groups" select box should contain "Group A"
|
||||
Then the "Separate groups" select box should contain "Group B"
|
||||
Then the "Separate groups" select box should contain "Group C"
|
||||
And the "Separate groups" select box should contain "Group A"
|
||||
And the "Separate groups" select box should contain "Group B"
|
||||
And the "Separate groups" select box should contain "Group C"
|
||||
And I select "All participants" from the "Separate groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G1"
|
||||
And I should see "Initial Disc G2"
|
||||
And I should see "Initial Disc G2"
|
||||
And I select "Group A" from the "Separate groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G1"
|
||||
But I should not see "Initial Disc G2"
|
||||
And I should not see "Initial Disc G3"
|
||||
And I select "Group B" from the "Separate groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G2"
|
||||
But I should not see "Initial Disc G1"
|
||||
And I should not see "Initial Disc G3"
|
||||
|
||||
Scenario: Teacher with accessallgroups can select any group when posting
|
||||
Given I log in as "teacher1"
|
||||
@@ -249,14 +270,7 @@ Feature: Posting to all groups in a separate group discussion is restricted to u
|
||||
And I should see "Post a copy to all groups"
|
||||
|
||||
Scenario: Students can view all participants discussions in separate groups mode
|
||||
Given I log in as "teacher1"
|
||||
Given I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I add a new discussion to "Standard forum name" forum with:
|
||||
| Subject | Forum post to all participants |
|
||||
| Message | This is the body |
|
||||
| Group | All participants |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Standard forum name"
|
||||
Then I should see "Forum post to all participants"
|
||||
When I follow "Standard forum name"
|
||||
Then I should see "Initial Disc ALL"
|
||||
|
||||
@@ -33,15 +33,36 @@ Feature: Posting to all groups in a visible group discussion is restricted to us
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | groupmode |
|
||||
| forum | Standard forum name | Standard forum description | C1 | groups | 2 |
|
||||
And the following "mod_forum > discussions" exist:
|
||||
| forum | name | subject | message | group |
|
||||
| groups | Initial Disc ALL | Initial Disc ALL | Disc ALL content | All participants |
|
||||
| groups | Initial Disc G1 | Initial Disc G1 | Disc G1 content | G1 |
|
||||
| groups | Initial Disc G2 | Initial Disc G2 | Disc G2 content | G2 |
|
||||
| groups | Initial Disc G3 | Initial Disc G3 | Disc G3 content | G3 |
|
||||
|
||||
Scenario: Teacher with accessallgroups can view all groups
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Standard forum name"
|
||||
Then the "Visible groups" select box should contain "All participants"
|
||||
Then the "Visible groups" select box should contain "Group A"
|
||||
Then the "Visible groups" select box should contain "Group B"
|
||||
Then the "Visible groups" select box should contain "Group C"
|
||||
And the "Visible groups" select box should contain "Group A"
|
||||
And the "Visible groups" select box should contain "Group B"
|
||||
And the "Visible groups" select box should contain "Group C"
|
||||
And I select "All participants" from the "Visible groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G1"
|
||||
And I should see "Initial Disc G2"
|
||||
And I should see "Initial Disc G2"
|
||||
And I select "Group A" from the "Visible groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G1"
|
||||
But I should not see "Initial Disc G2"
|
||||
And I should not see "Initial Disc G3"
|
||||
And I select "Group B" from the "Visible groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G2"
|
||||
But I should not see "Initial Disc G1"
|
||||
And I should not see "Initial Disc G3"
|
||||
|
||||
Scenario: Teacher with accessallgroups can select any group when posting
|
||||
Given I log in as "teacher1"
|
||||
@@ -150,9 +171,24 @@ Feature: Posting to all groups in a visible group discussion is restricted to us
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Standard forum name"
|
||||
Then the "Visible groups" select box should contain "All participants"
|
||||
Then the "Visible groups" select box should contain "Group A"
|
||||
Then the "Visible groups" select box should contain "Group B"
|
||||
Then the "Visible groups" select box should contain "Group C"
|
||||
And the "Visible groups" select box should contain "Group A"
|
||||
And the "Visible groups" select box should contain "Group B"
|
||||
And the "Visible groups" select box should contain "Group C"
|
||||
And I select "All participants" from the "Visible groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G1"
|
||||
And I should see "Initial Disc G2"
|
||||
And I should see "Initial Disc G2"
|
||||
And I select "Group A" from the "Visible groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G1"
|
||||
But I should not see "Initial Disc G2"
|
||||
And I should not see "Initial Disc G3"
|
||||
And I select "Group B" from the "Visible groups" singleselect
|
||||
And I should see "Initial Disc ALL"
|
||||
And I should see "Initial Disc G2"
|
||||
But I should not see "Initial Disc G1"
|
||||
And I should not see "Initial Disc G3"
|
||||
|
||||
Scenario: Students in one group can only post in their group
|
||||
Given I log in as "student1"
|
||||
|
||||
@@ -35,7 +35,7 @@ class behat_mod_forum_generator extends behat_generator_base {
|
||||
'singular' => 'discussion',
|
||||
'datagenerator' => 'discussion',
|
||||
'required' => ['forum'],
|
||||
'switchids' => ['forum' => 'forumid', 'user' => 'userid'],
|
||||
'switchids' => ['forum' => 'forumid', 'user' => 'userid', 'group' => 'groupid'],
|
||||
],
|
||||
'posts' => [
|
||||
'singular' => 'post',
|
||||
@@ -62,6 +62,21 @@ class behat_mod_forum_generator extends behat_generator_base {
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group id from it's idnumber. It allows using 'All participants' as idnumber.
|
||||
*
|
||||
* @throws Exception
|
||||
* @param string $idnumber
|
||||
* @return int
|
||||
*/
|
||||
protected function get_group_id($idnumber): int {
|
||||
if ($idnumber === 'All participants') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return parent::get_group_id($idnumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocess discussion data.
|
||||
*
|
||||
|
||||
@@ -5,7 +5,6 @@ Feature: set label idnumber
|
||||
As a teacher
|
||||
I should create label activity and set an ID number
|
||||
|
||||
@javascript
|
||||
Scenario: label ID number input box should be shown.
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
@@ -18,12 +17,11 @@ Feature: set label idnumber
|
||||
| user | course | role |
|
||||
| teacher | C1 | editingteacher |
|
||||
| student | C1 | student |
|
||||
Given I log in as "teacher"
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | intro | idnumber |
|
||||
| label | C1 | 1 | Label with ID number set | C1LABEL1 |
|
||||
When I log in as "teacher"
|
||||
And I am on "Test" course homepage with editing mode on
|
||||
When I add a "label" to section "1" and I fill the form with:
|
||||
| Label text | Label with ID number set |
|
||||
| Availability | Show on course page |
|
||||
| ID number | C1LABEL1 |
|
||||
Then "Label with ID number set" activity should be visible
|
||||
And I turn editing mode off
|
||||
And "Label with ID number set" activity should be visible
|
||||
@@ -32,11 +30,7 @@ Feature: set label idnumber
|
||||
And I am on "Test" course homepage
|
||||
And I should see "Label with ID number set"
|
||||
And I log out
|
||||
And I log in as "teacher"
|
||||
And I am on "Test" course homepage
|
||||
And I turn editing mode on
|
||||
And I open "Label with ID number set" actions menu
|
||||
And I click on "Edit settings" "link" in the "Label with ID number set" activity
|
||||
And I am on the "Label with ID number set" "label activity editing" page logged in as teacher
|
||||
And I expand all fieldsets
|
||||
And I should see "ID number" in the "Common module settings" "fieldset"
|
||||
And the field "ID number" matches value "C1LABEL1"
|
||||
|
||||
@@ -5,8 +5,7 @@ Feature: Check label visibility works
|
||||
As a teacher
|
||||
I should create label activity
|
||||
|
||||
@javascript
|
||||
Scenario: Hidden label activity should be show as hidden.
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Test | C1 | 0 |
|
||||
@@ -18,38 +17,26 @@ Feature: Check label visibility works
|
||||
| user | course | role |
|
||||
| teacher | C1 | editingteacher |
|
||||
| student | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | intro | idnumber | visible |
|
||||
| label | C1 | 1 | Swanky label | 1 | 1 |
|
||||
| label | C1 | 1 | Swanky label 2 | 2 | 0 |
|
||||
|
||||
Scenario: Hidden label activity should be show as hidden.
|
||||
Given I log in as "teacher"
|
||||
And I am on "Test" course homepage with editing mode on
|
||||
When I add a "label" to section "1" and I fill the form with:
|
||||
| Label text | Swanky label |
|
||||
| Availability | Hide from students |
|
||||
Then "Swanky label" activity should be hidden
|
||||
When I am on "Test" course homepage with editing mode on
|
||||
Then "Swanky label 2" activity should be hidden
|
||||
And I turn editing mode off
|
||||
And "Swanky label" activity should be hidden
|
||||
Then "Swanky label 2" activity should be hidden
|
||||
And I log out
|
||||
And I log in as "student"
|
||||
And I am on "Test" course homepage
|
||||
And I should not see "Swanky label"
|
||||
And I should not see "Swanky label 2"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Visible label activity should be shown as visible.
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Test | C1 | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher | Teacher | Frist | teacher1@example.com |
|
||||
| student | Student | First | student1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher | C1 | editingteacher |
|
||||
| student | C1 | student |
|
||||
Given I log in as "teacher"
|
||||
And I am on "Test" course homepage with editing mode on
|
||||
When I add a "label" to section "1" and I fill the form with:
|
||||
| Label text | Swanky label |
|
||||
| Availability | Show on course page |
|
||||
When I am on "Test" course homepage with editing mode on
|
||||
Then "Swanky label" activity should be visible
|
||||
And I log out
|
||||
And I log in as "student"
|
||||
@@ -59,23 +46,9 @@ Feature: Check label visibility works
|
||||
|
||||
@javascript
|
||||
Scenario: Teacher can not show label inside the hidden section
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Test | C1 | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher | Teacher | Frist | teacher1@example.com |
|
||||
| student | Student | First | student1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher | C1 | editingteacher |
|
||||
| student | C1 | student |
|
||||
Given I log in as "teacher"
|
||||
And I am on "Test" course homepage with editing mode on
|
||||
When I add a "label" to section "1" and I fill the form with:
|
||||
| Label text | Swanky label |
|
||||
| Availability | Show on course page |
|
||||
And I hide section "1"
|
||||
When I hide section "1"
|
||||
Then "Swanky label" activity should be dimmed
|
||||
And I open "Swanky label" actions menu
|
||||
And "Swanky label" actions menu should not have "Show" item
|
||||
|
||||
@@ -56,7 +56,7 @@ class repost_crosssite_page implements renderable, templatable {
|
||||
*/
|
||||
public function __construct(string $url, array $post) {
|
||||
$this->params = array_map(function($k) use ($post) {
|
||||
return ["key" => $k, "value" => str_replace("\"", """, $post[$k])];
|
||||
return ["key" => $k, "value" => $post[$k]];
|
||||
}, array_keys($post));
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
}
|
||||
|
||||
}}
|
||||
<form action="{{{url}}}" method="POST" id="autopostme">
|
||||
<form action="{{url}}" method="POST" id="autopostme">
|
||||
{{#params}}
|
||||
<input type="hidden" name="{{{key}}}" value="{{{value}}}">
|
||||
<input type="hidden" name="{{key}}" value="{{value}}">
|
||||
{{/params}}
|
||||
<input type="hidden" name="repost" value="true">
|
||||
</form>
|
||||
|
||||
@@ -5,12 +5,12 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I turn editing mode on
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | name |
|
||||
| quiz | C1 | 1 | Quiz 1 |
|
||||
|
||||
Scenario: Quiz setting "Require the use of Safe Exam Browser" has all types, except "Use an existing template".
|
||||
When I add a "Quiz" to section "1"
|
||||
When I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And the "Require the use of Safe Exam Browser" select box should contain "Yes – Configure manually"
|
||||
And the "Require the use of Safe Exam Browser" select box should not contain "Yes – Use an existing template"
|
||||
@@ -22,7 +22,7 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "quizaccess_seb > seb templates" exist:
|
||||
| name |
|
||||
| Template 1 |
|
||||
When I add a "Quiz" to section "1"
|
||||
When I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And the "Require the use of Safe Exam Browser" select box should contain "Yes – Configure manually"
|
||||
And the "Require the use of Safe Exam Browser" select box should contain "Yes – Use an existing template"
|
||||
@@ -34,7 +34,7 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "quizaccess_seb > seb templates" exist:
|
||||
| name |
|
||||
| Template 1 |
|
||||
When I add a "Quiz" to section "1"
|
||||
When I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And I set the field "Require the use of Safe Exam Browser" to "No"
|
||||
Then I should not see "Upload Safe Exam Browser config file"
|
||||
@@ -66,7 +66,7 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "quizaccess_seb > seb templates" exist:
|
||||
| name |
|
||||
| Template 1 |
|
||||
When I add a "Quiz" to section "1"
|
||||
And I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And I set the field "Require the use of Safe Exam Browser" to "Yes – Use SEB client config"
|
||||
Then I should see "Show Safe Exam Browser download button"
|
||||
@@ -98,7 +98,7 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "quizaccess_seb > seb templates" exist:
|
||||
| name |
|
||||
| Template 1 |
|
||||
When I add a "Quiz" to section "1"
|
||||
And I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And I set the field "Require the use of Safe Exam Browser" to "Yes – Upload my own config"
|
||||
Then I should see "Upload Safe Exam Browser config file"
|
||||
@@ -130,7 +130,7 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "quizaccess_seb > seb templates" exist:
|
||||
| name |
|
||||
| Template 1 |
|
||||
When I add a "Quiz" to section "1"
|
||||
And I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And I set the field "Require the use of Safe Exam Browser" to "Yes – Use an existing template"
|
||||
Then I should see "Safe Exam Browser config template"
|
||||
@@ -164,7 +164,7 @@ Feature: Safe Exam Browser settings in quiz edit form
|
||||
Given the following "quizaccess_seb > seb templates" exist:
|
||||
| name |
|
||||
| Template 1 |
|
||||
When I add a "Quiz" to section "1"
|
||||
And I am on the "Quiz 1" "quiz activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And I set the field "Require the use of Safe Exam Browser" to "Yes – Configure manually"
|
||||
Then I should see "Show Safe Exam Browser download button"
|
||||
|
||||
@@ -18,39 +18,39 @@ Feature: Settings form fields disabled if not required
|
||||
| teacher | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And I log in as "teacher"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And the following "activities" exist:
|
||||
| activity | course | section | name |
|
||||
| quiz | C1 | 1 | Test quiz 1 |
|
||||
|
||||
@javascript
|
||||
Scenario: Depending on the number of attempts, different form fields are disabled.
|
||||
When I add a "Quiz" to section "1"
|
||||
When I am on the "Test quiz 1" "quiz activity editing" page logged in as teacher
|
||||
And I expand all fieldsets
|
||||
And I set the field "Name" to "Test quiz"
|
||||
And I set the field "Attempts allowed" to "1"
|
||||
Then the "Grading method" "field" should be disabled
|
||||
And the "Each attempt builds on the last" "field" should be disabled
|
||||
And the "id_delay1_enabled" "field" should be disabled
|
||||
And the "id_delay2_enabled" "field" should be disabled
|
||||
|
||||
When I set the field "Attempts allowed" to "2"
|
||||
Then the "Grading method" "field" should be enabled
|
||||
And I set the field "Attempts allowed" to "2"
|
||||
And the "Grading method" "field" should be enabled
|
||||
And the "Each attempt builds on the last" "field" should be enabled
|
||||
And the "id_delay1_enabled" "field" should be enabled
|
||||
And the "id_delay2_enabled" "field" should be disabled
|
||||
|
||||
When I set the field "Attempts allowed" to "3"
|
||||
Then the "Grading method" "field" should be enabled
|
||||
And I set the field "Attempts allowed" to "3"
|
||||
And the "Grading method" "field" should be enabled
|
||||
And the "Each attempt builds on the last" "field" should be enabled
|
||||
And the "id_delay1_enabled" "field" should be enabled
|
||||
And the "id_delay2_enabled" "field" should be enabled
|
||||
|
||||
When I set the field "Attempts allowed" to "Unlimited"
|
||||
Then the "Grading method" "field" should be enabled
|
||||
And I set the field "Attempts allowed" to "Unlimited"
|
||||
And the "Grading method" "field" should be enabled
|
||||
And the "Each attempt builds on the last" "field" should be enabled
|
||||
# And the "id_delay1_enabled" "field" should be enabled
|
||||
# And the "id_delay2_enabled" "field" should be enabled
|
||||
|
||||
When I press "Save and display"
|
||||
And I press "Save and display"
|
||||
And I navigate to "User overrides" in current page administration
|
||||
And I press "Add user override"
|
||||
And I set the following fields to these values:
|
||||
@@ -61,12 +61,12 @@ Feature: Settings form fields disabled if not required
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the field "Attempts allowed" to "1"
|
||||
Then the "Grading method" "field" should be enabled
|
||||
And the "Grading method" "field" should be enabled
|
||||
And the "Each attempt builds on the last" "field" should be enabled
|
||||
And the "id_delay1_enabled" "field" should be enabled
|
||||
And the "id_delay2_enabled" "field" should be enabled
|
||||
|
||||
When I press "Save and display"
|
||||
And I press "Save and display"
|
||||
And I navigate to "User overrides" in current page administration
|
||||
And I click on "Edit" "link" in the "region-main" "region"
|
||||
And I set the field "Attempts allowed" to "2"
|
||||
@@ -75,12 +75,12 @@ Feature: Settings form fields disabled if not required
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the field "Attempts allowed" to "1"
|
||||
Then the "Grading method" "field" should be enabled
|
||||
And the "Grading method" "field" should be enabled
|
||||
And the "Each attempt builds on the last" "field" should be enabled
|
||||
And the "id_delay1_enabled" "field" should be enabled
|
||||
And the "id_delay2_enabled" "field" should be disabled
|
||||
|
||||
When I press "Save and display"
|
||||
And I press "Save and display"
|
||||
And I navigate to "User overrides" in current page administration
|
||||
And I press "Add user override"
|
||||
And I set the following fields to these values:
|
||||
@@ -91,28 +91,31 @@ Feature: Settings form fields disabled if not required
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the field "Attempts allowed" to "1"
|
||||
Then the "Grading method" "field" should be enabled
|
||||
And the "Grading method" "field" should be enabled
|
||||
And the "Each attempt builds on the last" "field" should be enabled
|
||||
And the "id_delay1_enabled" "field" should be enabled
|
||||
And the "id_delay2_enabled" "field" should be enabled
|
||||
|
||||
@javascript
|
||||
Scenario: Depending on whether there is a close date, some review options are disabled.
|
||||
When I add a "Quiz" to section "1"
|
||||
When I log in as "teacher"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Quiz" to section "1"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Name" to "Test quiz"
|
||||
Then the "id_attemptclosed" "checkbox" should be disabled
|
||||
Then the "id_correctnessclosed" "checkbox" should be disabled
|
||||
Then the "id_marksclosed" "checkbox" should be disabled
|
||||
Then the "id_specificfeedbackclosed" "checkbox" should be disabled
|
||||
Then the "id_generalfeedbackclosed" "checkbox" should be disabled
|
||||
Then the "id_rightanswerclosed" "checkbox" should be disabled
|
||||
Then the "id_overallfeedbackclosed" "checkbox" should be disabled
|
||||
And the "id_correctnessclosed" "checkbox" should be disabled
|
||||
And the "id_marksclosed" "checkbox" should be disabled
|
||||
And the "id_specificfeedbackclosed" "checkbox" should be disabled
|
||||
And the "id_generalfeedbackclosed" "checkbox" should be disabled
|
||||
And the "id_rightanswerclosed" "checkbox" should be disabled
|
||||
And the "id_overallfeedbackclosed" "checkbox" should be disabled
|
||||
And I set the field "id_timeclose_enabled" to "1"
|
||||
Then the "id_attemptclosed" "checkbox" should be enabled
|
||||
Then the "id_correctnessclosed" "checkbox" should be enabled
|
||||
Then the "id_marksclosed" "checkbox" should be enabled
|
||||
Then the "id_specificfeedbackclosed" "checkbox" should be enabled
|
||||
Then the "id_generalfeedbackclosed" "checkbox" should be enabled
|
||||
Then the "id_rightanswerclosed" "checkbox" should be enabled
|
||||
Then the "id_overallfeedbackclosed" "checkbox" should be enabled
|
||||
And the "id_attemptclosed" "checkbox" should be enabled
|
||||
And the "id_correctnessclosed" "checkbox" should be enabled
|
||||
And the "id_marksclosed" "checkbox" should be enabled
|
||||
And the "id_specificfeedbackclosed" "checkbox" should be enabled
|
||||
And the "id_generalfeedbackclosed" "checkbox" should be enabled
|
||||
And the "id_rightanswerclosed" "checkbox" should be enabled
|
||||
And the "id_overallfeedbackclosed" "checkbox" should be enabled
|
||||
And I should not see "Repaginate now"
|
||||
|
||||
@@ -39,7 +39,8 @@ class mod_resource_generator extends testing_module_generator {
|
||||
* text file.
|
||||
*
|
||||
* @param array|stdClass $record data for module being generated. Requires 'course' key
|
||||
* (an id or the full object). Also can have any fields from add module form.
|
||||
* (an id or the full object). Also can have any fields from add module form, and a
|
||||
* 'defaultfilename' to set the name of the file created if no draft ID is supplied.
|
||||
* @param null|array $options general options for course module. Since 2.6 it is
|
||||
* possible to omit this argument by merging options into $record
|
||||
* @return stdClass record from module-defined table with additional field
|
||||
@@ -72,16 +73,17 @@ class mod_resource_generator extends testing_module_generator {
|
||||
throw new coding_exception('resource generator requires a current user');
|
||||
}
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
$filename = $record->defaultfilename ?? 'resource' . ($this->instancecount + 1) . '.txt';
|
||||
|
||||
// Pick a random context id for specified user.
|
||||
$record->files = file_get_unused_draft_itemid();
|
||||
|
||||
// Add actual file there.
|
||||
$filerecord = array('component' => 'user', 'filearea' => 'draft',
|
||||
$filerecord = ['component' => 'user', 'filearea' => 'draft',
|
||||
'contextid' => $usercontext->id, 'itemid' => $record->files,
|
||||
'filename' => 'resource' . ($this->instancecount+1) . '.txt', 'filepath' => '/');
|
||||
'filename' => $filename, 'filepath' => '/'];
|
||||
$fs = get_file_storage();
|
||||
$fs->create_file_from_string($filerecord, 'Test resource ' . ($this->instancecount+1) . ' file');
|
||||
$fs->create_file_from_string($filerecord, 'Test resource ' . $filename . ' file');
|
||||
}
|
||||
|
||||
// Do work to actually add the instance.
|
||||
|
||||
@@ -70,6 +70,21 @@ class mod_resource_generator_testcase extends advanced_testcase {
|
||||
// Check that generated resource module contains a file.
|
||||
$fs = get_file_storage();
|
||||
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', false, '', false);
|
||||
$this->assertEquals(1, count($files));
|
||||
$file = array_values($files)[0];
|
||||
$this->assertCount(1, $files);
|
||||
$this->assertEquals('resource3.txt', $file->get_filename());
|
||||
$this->assertEquals('Test resource resource3.txt file', $file->get_content());
|
||||
|
||||
// Create a new resource specifying the file name.
|
||||
$resource = $generator->create_instance(['course' => $SITE->id, 'defaultfilename' => 'myfile.pdf']);
|
||||
|
||||
// Check that generated resource module contains a file with the specified name.
|
||||
$cm = get_coursemodule_from_instance('resource', $resource->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', false, '', false);
|
||||
$file = array_values($files)[0];
|
||||
$this->assertCount(1, $files);
|
||||
$this->assertEquals('myfile.pdf', $file->get_filename());
|
||||
$this->assertEquals('Test resource myfile.pdf file', $file->get_content());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -496,7 +496,7 @@ function scorm_user_complete($course, $user, $mod, $scorm) {
|
||||
$report .= html_writer::start_tag('li').html_writer::start_tag('ul', array('class' => $liststyle));
|
||||
foreach ($usertrack as $element => $value) {
|
||||
if (substr($element, 0, 3) == 'cmi') {
|
||||
$report .= html_writer::tag('li', $element.' => '.s($value));
|
||||
$report .= html_writer::tag('li', s($element) . ' => ' . s($value));
|
||||
}
|
||||
}
|
||||
$report .= html_writer::end_tag('ul').html_writer::end_tag('li');
|
||||
|
||||
@@ -144,9 +144,9 @@ foreach ($trackdata as $element => $value) {
|
||||
}
|
||||
|
||||
if (empty($string) || $table->is_downloading()) {
|
||||
$row[] = $element;
|
||||
$row[] = s($element);
|
||||
} else {
|
||||
$row[] = $element.$OUTPUT->help_icon($string, 'scorm');
|
||||
$row[] = s($element) . $OUTPUT->help_icon($string, 'scorm');
|
||||
}
|
||||
if (strpos($element, '_time') === false) {
|
||||
$row[] = s($value);
|
||||
|
||||
@@ -152,7 +152,8 @@ class qformat_blackboard_six extends qformat_blackboard_six_base {
|
||||
}
|
||||
if ($examfile->getAttribute('type') == 'assessment/x-bb-pool') {
|
||||
if ($examfile->getAttribute('baseurl')) {
|
||||
$fileobj->filebase = $this->tempdir. '/' . $examfile->getAttribute('baseurl');
|
||||
$fileobj->filebase = clean_param($this->tempdir . '/'
|
||||
. $examfile->getAttribute('baseurl'), PARAM_SAFEPATH);
|
||||
}
|
||||
if ($content = $this->get_filecontent($examfile->getAttribute('file'))) {
|
||||
$fileobj->filetype = self::FILETYPE_POOL;
|
||||
|
||||
+2
-2
@@ -29,9 +29,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2020061514.00; // 20200615 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2020061515.00; // 20200615 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '3.9.14 (Build: 20220509)'; // Human-friendly version name
|
||||
$release = '3.9.15 (Build: 20220711)'; // Human-friendly version name
|
||||
$branch = '39'; // This version's branch.
|
||||
$maturity = MATURITY_STABLE; // This version's maturity level.
|
||||
|
||||
Reference in New Issue
Block a user