Merge branch 'MOODLE_311_STABLE' into install_311_STABLE
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Template configuraton file for github actions CI/CD.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2020 onwards Eloy Lafuente (stronk7) {@link https://stronk7.com}
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// This cannot be used out from a github actions workflow, so just exit.
|
||||
getenv('GITHUB_WORKFLOW') || die; // phpcs:ignore moodle.Files.MoodleInternal.MoodleInternalGlobalState
|
||||
|
||||
unset($CFG);
|
||||
global $CFG;
|
||||
$CFG = new stdClass();
|
||||
|
||||
$CFG->dbtype = getenv('dbtype');
|
||||
$CFG->dblibrary = 'native';
|
||||
$CFG->dbhost = '127.0.0.1';
|
||||
$CFG->dbname = 'test';
|
||||
$CFG->dbuser = 'test';
|
||||
$CFG->dbpass = 'test';
|
||||
$CFG->prefix = 'm_';
|
||||
$CFG->dboptions = ['dbcollation' => 'utf8mb4_bin'];
|
||||
|
||||
$host = 'localhost';
|
||||
$CFG->wwwroot = "http://{$host}";
|
||||
$CFG->dataroot = realpath(dirname(__DIR__)) . '/moodledata';
|
||||
$CFG->admin = 'admin';
|
||||
$CFG->directorypermissions = 0777;
|
||||
|
||||
// Debug options - possible to be controlled by flag in future.
|
||||
$CFG->debug = (E_ALL | E_STRICT); // DEBUG_DEVELOPER.
|
||||
$CFG->debugdisplay = 1;
|
||||
$CFG->debugstringids = 1; // Add strings=1 to url to get string ids.
|
||||
$CFG->perfdebug = 15;
|
||||
$CFG->debugpageinfo = 1;
|
||||
$CFG->allowthemechangeonurl = 1;
|
||||
$CFG->passwordpolicy = 0;
|
||||
$CFG->cronclionly = 0;
|
||||
$CFG->pathtophp = getenv('pathtophp');
|
||||
|
||||
$CFG->phpunit_dataroot = realpath(dirname(__DIR__)) . '/phpunitdata';
|
||||
$CFG->phpunit_prefix = 't_';
|
||||
|
||||
define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080');
|
||||
define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080');
|
||||
|
||||
define('TEST_SESSION_REDIS_HOST', 'localhost');
|
||||
define('TEST_CACHESTORE_REDIS_TESTSERVERS', 'localhost');
|
||||
|
||||
// TODO: add others (solr, mongodb, memcached, ldap...).
|
||||
|
||||
// Too much for now: define('PHPUNIT_LONGTEST', true); // Only leaves a few tests out and they are run later by CI.
|
||||
|
||||
require_once(__DIR__ . '/lib/setup.php');
|
||||
@@ -0,0 +1,103 @@
|
||||
name: Core
|
||||
|
||||
on: [push]
|
||||
|
||||
env:
|
||||
php: 7.4
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Configuring node & npm
|
||||
shell: bash -l {0}
|
||||
run: nvm install
|
||||
|
||||
- name: Installing node stuff
|
||||
run: npm install
|
||||
|
||||
- name: Running grunt
|
||||
run: npx grunt
|
||||
|
||||
- name: Looking for uncommitted changes
|
||||
# Add all files to the git index and then run diff --cached to see all changes.
|
||||
# This ensures that we get the status of all files, including new files.
|
||||
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
|
||||
run: |
|
||||
git add .
|
||||
git reset -- npm-shrinkwrap.json
|
||||
git diff --cached --exit-code
|
||||
|
||||
PHPUnit:
|
||||
runs-on: ${{ matrix.os }}
|
||||
services:
|
||||
exttests:
|
||||
image: moodlehq/moodle-exttests
|
||||
ports:
|
||||
- 8080:80
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
php: 7.2
|
||||
db: mysqli
|
||||
- os: ubuntu-18.04
|
||||
php: 7.4
|
||||
db: pgsql
|
||||
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: johanmeiring/mysql-action@tmpfs-patch
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 5.7
|
||||
mysql database: test
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
use tmpfs: true
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
uses: m4nu56/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: 9.6
|
||||
postgresql db: test
|
||||
postgresql user: test
|
||||
postgresql password: test
|
||||
|
||||
- name: Configuring git vars
|
||||
uses: rlespinasse/[email protected]
|
||||
|
||||
- name: Setting up PHP ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
run: |
|
||||
echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
|
||||
cp .github/workflows/config-template.php config.php
|
||||
mkdir ../moodledata
|
||||
sudo locale-gen en_AU.UTF-8
|
||||
php admin/tool/phpunit/cli/init.php --no-composer-self-update
|
||||
|
||||
- name: Running PHPUnit tests
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
run: vendor/bin/phpunit -v
|
||||
+29
-71
@@ -16,31 +16,9 @@ services:
|
||||
- mysql
|
||||
- docker
|
||||
|
||||
php:
|
||||
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
|
||||
- 7.4
|
||||
- 7.2
|
||||
|
||||
addons:
|
||||
postgresql: "9.6"
|
||||
|
||||
env:
|
||||
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
|
||||
# start first so that the total run time is not too high.
|
||||
#
|
||||
# We only run MySQL on PHP 7.2, so run that first.
|
||||
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
|
||||
# Postgres is significantly is pretty reasonable in its run-time.
|
||||
|
||||
# Run CI Tests without running PHPUnit.
|
||||
- DB=none TASK=CITEST
|
||||
|
||||
# Run unit tests on Postgres
|
||||
- DB=pgsql TASK=PHPUNIT
|
||||
|
||||
# Perform an upgrade test too.
|
||||
- DB=pgsql TASK=UPGRADE
|
||||
|
||||
jobs:
|
||||
# Enable fast finish.
|
||||
# This will fail the build if a single job fails (except those in allow_failures).
|
||||
@@ -48,12 +26,35 @@ jobs:
|
||||
fast_finish: true
|
||||
|
||||
include:
|
||||
# Run mysql only on highest - it's just too slow
|
||||
- php: 7.4
|
||||
# First all the lowest php ones (7.2)
|
||||
- php: 7.2
|
||||
env: DB=none TASK=CITEST
|
||||
- php: 7.2
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present
|
||||
php: 7.2
|
||||
env: DB=pgsql TASK=PHPUNIT
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all"
|
||||
php: 7.2
|
||||
env: DB=mysqli TASK=PHPUNIT
|
||||
|
||||
# Then, conditionally, all the highest php ones (7.4)
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 7.4
|
||||
env: DB=none TASK=CITEST
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 7.4
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
|
||||
|
||||
- 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
|
||||
env: DB=pgsql TASK=PHPUNIT
|
||||
|
||||
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all")
|
||||
php: 7.4
|
||||
env: DB=mysqli TASK=PHPUNIT
|
||||
# Run grunt/npm install on highest version too ('node' is an alias for the latest node.js version.)
|
||||
- php: 7.4
|
||||
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -113,7 +114,7 @@ install:
|
||||
before_script:
|
||||
- phpenv config-rm xdebug.ini
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' -o "$TASK" = 'UPGRADE' ];
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
# Copy generic configuration in place.
|
||||
cp config-dist.php config.php ;
|
||||
@@ -224,32 +225,6 @@ before_script:
|
||||
export phpcmd=`which php`;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# Upgrade test
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$TASK" = 'UPGRADE' ];
|
||||
then
|
||||
# We need the official upstream.
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
# Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
|
||||
git fetch upstream MOODLE_30_STABLE;
|
||||
git checkout MOODLE_30_STABLE;
|
||||
|
||||
# Perform the upgrade
|
||||
php admin/cli/install_database.php --agree-license --adminpass=Password [email protected] --fullname="Upgrade test" --shortname=Upgrade;
|
||||
|
||||
# Return to the previous commit
|
||||
git checkout -;
|
||||
|
||||
# Perform the upgrade
|
||||
php admin/cli/upgrade.php --non-interactive --allow-unstable ;
|
||||
|
||||
# The local_ci repository can be used to check upgrade savepoints.
|
||||
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci ;
|
||||
fi
|
||||
|
||||
script:
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
@@ -275,23 +250,6 @@ script:
|
||||
git diff --cached --exit-code ;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# Upgrade test
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$TASK" = 'UPGRADE' ];
|
||||
then
|
||||
cp local/ci/check_upgrade_savepoints/check_upgrade_savepoints.php ./check_upgrade_savepoints.php
|
||||
result=`php check_upgrade_savepoints.php`;
|
||||
# Check if there are problems
|
||||
count=`echo "$result" | grep -P "ERROR|WARN" | wc -l` ;
|
||||
if (($count > 0));
|
||||
then
|
||||
echo "$result"
|
||||
exit 1 ;
|
||||
fi
|
||||
fi
|
||||
|
||||
after_script:
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
@tool_behat
|
||||
Feature: Verify that the inplace editable field works as expected
|
||||
In order to use behat step definitions
|
||||
As a test write
|
||||
I need to ensure that the inplace editable works in forms
|
||||
|
||||
Background:
|
||||
Given the following "course" exists:
|
||||
| fullname | Course 1 |
|
||||
| shortname | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | idnumber |
|
||||
| forum | C1 | My first forum | forum1 |
|
||||
| assign | C1 | My first assignment | assign1 |
|
||||
| quiz | C1 | My first quiz | quiz1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
|
||||
@javascript
|
||||
Scenario: Using an inplace editable updates the name of an activity
|
||||
When I set the field "Edit title" in the "My first assignment" "activity" to "Coursework submission"
|
||||
Then I should see "Coursework submission"
|
||||
And I should not see "My first assignment"
|
||||
But I should see "My first forum"
|
||||
And I should see "My first quiz"
|
||||
And I set the field "Edit title" in the "Coursework submission" "activity" to "My first assignment"
|
||||
And I should not see "Coursework submission"
|
||||
But I should see "My first assignment"
|
||||
And I should see "My first forum"
|
||||
And I should see "My first quiz"
|
||||
@@ -27,6 +27,9 @@ require_once('../../config.php');
|
||||
$issuerid = required_param('id', PARAM_INT);
|
||||
$wantsurl = new moodle_url(optional_param('wantsurl', '', PARAM_URL));
|
||||
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->set_url(new moodle_url('/auth/oauth2/login.php', ['id' => $issuerid]));
|
||||
|
||||
require_sesskey();
|
||||
|
||||
if (!\auth_oauth2\api::is_enabled()) {
|
||||
|
||||
@@ -105,6 +105,9 @@ class block_section_links extends block_base {
|
||||
}
|
||||
}
|
||||
|
||||
// Whether or not section name should be displayed.
|
||||
$showsectionname = !empty($config->showsectionname) ? true : false;
|
||||
|
||||
// Prepare an array of sections to create links for.
|
||||
$sections = array();
|
||||
$canviewhidden = has_capability('moodle/course:update', $context);
|
||||
@@ -126,13 +129,17 @@ class block_section_links extends block_base {
|
||||
$sections[$i]->highlight = true;
|
||||
$sectiontojumpto = $section->section;
|
||||
}
|
||||
if ($showsectionname) {
|
||||
$sections[$i]->name = $courseformat->get_section_name($i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($sections)) {
|
||||
// Render the sections.
|
||||
$renderer = $this->page->get_renderer('block_section_links');
|
||||
$this->content->text = $renderer->render_section_links($this->page->course, $sections, $sectiontojumpto);
|
||||
$this->content->text = $renderer->render_section_links($this->page->course, $sections,
|
||||
$sectiontojumpto, $showsectionname);
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
|
||||
@@ -82,5 +82,8 @@ class block_section_links_edit_form extends block_edit_form {
|
||||
$mform->addHelpButton('config_incby'.$i, 'incby'.$i, 'block_section_links');
|
||||
}
|
||||
|
||||
$mform->addElement('selectyesno', 'config_showsectionname', get_string('showsectionname', 'block_section_links'));
|
||||
$mform->setDefault('config_showsectionname', !empty($config->showsectionname) ? 1 : 0);
|
||||
$mform->addHelpButton('config_showsectionname', 'showsectionname', 'block_section_links');
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,8 @@ $string['numsections2'] = 'Alternative number of sections';
|
||||
$string['numsections2_help'] = 'Once the number of sections in the course reaches this number then the Alternative increment by value is used.';
|
||||
$string['pluginname'] = 'Section links';
|
||||
$string['section_links:addinstance'] = 'Add a new section links block';
|
||||
$string['showsectionname'] = 'Display section name';
|
||||
$string['showsectionname_help'] = 'Display section name in addition to section number';
|
||||
$string['topics'] = 'Topics';
|
||||
$string['weeks'] = 'Weeks';
|
||||
$string['privacy:metadata'] = 'The Section links block only shows data stored in other locations.';
|
||||
|
||||
@@ -38,10 +38,12 @@ class block_section_links_renderer extends plugin_renderer_base {
|
||||
* @param stdClass $course The course we are rendering for.
|
||||
* @param array $sections An array of section objects to render.
|
||||
* @param bool|int The section to provide a jump to link for.
|
||||
* @param bool $showsectionname Whether or not section name should be displayed.
|
||||
* @return string The HTML to display.
|
||||
*/
|
||||
public function render_section_links(stdClass $course, array $sections, $jumptosection = false) {
|
||||
$html = html_writer::start_tag('ol', array('class' => 'inline-list'));
|
||||
public function render_section_links(stdClass $course, array $sections, $jumptosection = false, $showsectionname = false) {
|
||||
$olparams = $showsectionname ? ['class' => 'unlist'] : ['class' => 'inline-list'];
|
||||
$html = html_writer::start_tag('ol', $olparams);
|
||||
foreach ($sections as $section) {
|
||||
$attributes = array();
|
||||
if (!$section->visible) {
|
||||
@@ -49,6 +51,9 @@ class block_section_links_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$html .= html_writer::start_tag('li');
|
||||
$sectiontext = $section->section;
|
||||
if ($showsectionname) {
|
||||
$sectiontext .= ': ' . $section->name;
|
||||
}
|
||||
if ($section->highlight) {
|
||||
$sectiontext = html_writer::tag('strong', $sectiontext);
|
||||
}
|
||||
|
||||
@@ -48,4 +48,9 @@ if ($ADMIN->fulltree) {
|
||||
get_string('incby'.$i.'_help', 'block_section_links'),
|
||||
$selected[$i][1], $increments));
|
||||
}
|
||||
|
||||
$settings->add(new admin_setting_configcheckbox('block_section_links/showsectionname',
|
||||
get_string('showsectionname', 'block_section_links'),
|
||||
get_string('showsectionname_help', 'block_section_links'),
|
||||
0));
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
@block @block_section_links
|
||||
Feature: The Section links block can be configured to display section name in addition to section number
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | numsections | coursedisplay |
|
||||
| Course 1 | C1 | 0 | 10 | 1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | section |
|
||||
| assign | First assignment | C1 | assign1 | 7 |
|
||||
And 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 I log in as "admin"
|
||||
And I set the following administration settings values:
|
||||
| showsectionname | 1 |
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Section links" block
|
||||
And I log out
|
||||
|
||||
Scenario: Student can see section name under the Section links block
|
||||
Given I log in as "student1"
|
||||
When I am on "Course 1" course homepage
|
||||
Then I should see "7: Topic 7" in the "Section links" "block"
|
||||
And I follow "7: Topic 7"
|
||||
And I should see "First assignment"
|
||||
|
||||
Scenario: Teacher can configure existing Section links block to display section number or section name
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I configure the "Section links" block
|
||||
And I set the following fields to these values:
|
||||
| Display section name | No |
|
||||
And I click on "Save changes" "button"
|
||||
Then I should not see "7: Topic 7" in the "Section links" "block"
|
||||
And I should see "7" in the "Section links" "block"
|
||||
And I follow "7"
|
||||
And I should see "First assignment"
|
||||
@@ -0,0 +1,6 @@
|
||||
This file describes API changes in the section_links block code.
|
||||
|
||||
=== 3.11 ===
|
||||
|
||||
* New optional parameter $showsectionname has been added to render_section_links(). Setting this to true will display
|
||||
section name in addition to section number.
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2020110900; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2020110901; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2020110300; // Requires this Moodle version
|
||||
$plugin->component = 'block_section_links'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -150,4 +150,17 @@ class behat_block_site_main_menu extends behat_base {
|
||||
$xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., $activityname)]";
|
||||
$this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of partial named selectors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_partial_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector('Activity', [
|
||||
"//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., %locator%)]"
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ Feature: Edit activities in main menu block
|
||||
|
||||
@javascript
|
||||
Scenario: Edit name of acitivity in-place in site main menu block
|
||||
Given I log in as "admin"
|
||||
Given the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | Acceptance test site |
|
||||
| name | My forum name |
|
||||
| idnumber | forum |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I navigate to "Turn editing on" in current page administration
|
||||
And I add the "Main menu" block
|
||||
When I add a "Forum" to section "0" and I fill the form with:
|
||||
| Forum name | My forum name |
|
||||
And I click on "Edit title" "link" in the "My forum name" activity in site main menu block
|
||||
And I set the field "New name for activity My forum name" to "New forum name"
|
||||
And I press the enter key
|
||||
When I set the field "Edit title" in the "My forum name" "block_site_main_menu > Activity" to "New forum name"
|
||||
Then I should not see "My forum name"
|
||||
And I should see "New forum name"
|
||||
And I follow "New forum name"
|
||||
|
||||
@@ -158,4 +158,17 @@ class behat_block_social_activities extends behat_base {
|
||||
$xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., $activityname)]";
|
||||
$this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of partial named selectors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_partial_named_selectors(): array {
|
||||
return [
|
||||
new behat_component_named_selector('Activity', [
|
||||
"//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., %locator%)]",
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,7 @@ Feature: Edit activities in social activities block
|
||||
And I click on "Add a new Forum" "link" in the "Add an activity or resource" "dialogue"
|
||||
And I set the field "Forum name" to "My forum name"
|
||||
And I press "Save and return to course"
|
||||
And I click on "Edit title" "link" in the "My forum name" activity in social activities block
|
||||
And I set the field "New name for activity My forum name" to "New forum name"
|
||||
And I press the enter key
|
||||
When I set the field "Edit title" in the "My forum name" "block_social_activities > Activity" to "New forum name"
|
||||
Then I should not see "My forum name" in the "Social activities" "block"
|
||||
And I should see "New forum name"
|
||||
And I follow "New forum name"
|
||||
@@ -84,4 +82,3 @@ Feature: Edit activities in social activities block
|
||||
And I should not see "My forum name" in the "Social activities" "block"
|
||||
And I click on "My forum name" "link" in the "Recent activity" "block"
|
||||
And I should see "My forum name" in the ".breadcrumb" "css_element"
|
||||
And I log out
|
||||
|
||||
@@ -62,9 +62,7 @@ Feature: Add cohorts of users
|
||||
@javascript
|
||||
Scenario: Edit cohort name in-place
|
||||
When I follow "Cohorts"
|
||||
And I click on "Edit cohort name" "link" in the "Test cohort name" "table_row"
|
||||
And I set the field "New name for cohort Test cohort name" to "Students cohort"
|
||||
And I press the enter key
|
||||
And I set the field "Edit cohort name" to "Students cohort"
|
||||
Then I should not see "Test cohort name"
|
||||
And I should see "Students cohort"
|
||||
And I follow "Cohorts"
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
],
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "8.5.*",
|
||||
"moodlehq/behat-extension": "3.310.0",
|
||||
"moodlehq/behat-extension": "3.311.0",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"instaclick/php-webdriver": "dev-local as 1.x-dev"
|
||||
}
|
||||
|
||||
Generated
+151
-339
File diff suppressed because it is too large
Load Diff
@@ -324,6 +324,9 @@ $CFG->admin = 'admin';
|
||||
// Use the igbinary serializer instead of the php default one. Note that phpredis must be compiled with
|
||||
// igbinary support to make the setting to work. Also, if you change the serializer you have to flush the database!
|
||||
// $CFG->session_redis_serializer_use_igbinary = false; // Optional, default is PHP builtin serializer.
|
||||
// $CFG->session_redis_compressor = 'none'; // Optional, possible values are:
|
||||
// // 'gzip' - PHP GZip compression
|
||||
// // 'zstd' - PHP Zstandard compression
|
||||
//
|
||||
// Please be aware that when selecting Memcached for sessions that it is advised to use a dedicated
|
||||
// memcache server. The memcached extension does not provide isolated environments for individual uses.
|
||||
|
||||
@@ -53,9 +53,7 @@ Feature: Sections can be edited and deleted in topics format
|
||||
|
||||
@javascript
|
||||
Scenario: Inline edit section name in topics format
|
||||
When I click on "Edit topic name" "link" in the "li#section-1" "css_element"
|
||||
And I set the field "New name for topic Topic 1" to "Midterm evaluation"
|
||||
And I press the enter key
|
||||
When I set the field "Edit topic name" in the "li#section-1" "css_element" to "Midterm evaluation"
|
||||
Then I should not see "Topic 1" in the "region-main" "region"
|
||||
And "New name for topic" "field" should not exist
|
||||
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
|
||||
|
||||
@@ -54,9 +54,7 @@ Feature: Sections can be edited and deleted in weeks format
|
||||
|
||||
@javascript
|
||||
Scenario: Inline edit section name in weeks format
|
||||
When I click on "Edit week name" "link" in the "li#section-1" "css_element"
|
||||
And I set the field "New name for week 1 May - 7 May" to "Midterm evaluation"
|
||||
And I press the enter key
|
||||
When I set the field "Edit week name" in the "li#section-1" "css_element" to "Midterm evaluation"
|
||||
Then I should not see "1 May - 7 May" in the "region-main" "region"
|
||||
And "New name for week" "field" should not exist
|
||||
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
|
||||
|
||||
@@ -15,15 +15,16 @@ Feature: Edit activity name in-place
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activity" exists:
|
||||
| course | C1 |
|
||||
| activity | forum |
|
||||
| name | Test forum name |
|
||||
| description | Test forum description |
|
||||
| idnumber | forum1 |
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Description | Test forum description |
|
||||
# Rename activity
|
||||
And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Test forum name')]" "xpath_element"
|
||||
And I set the field "New name for activity Test forum name" to "Good news"
|
||||
And I press the enter key
|
||||
And I set the field "Edit title" in the "Test forum name" "activity" to "Good news"
|
||||
Then I should not see "Test forum name" in the ".course-content" "css_element"
|
||||
And "New name for activity Test forum name" "field" should not exist
|
||||
And I should see "Good news"
|
||||
@@ -32,7 +33,7 @@ Feature: Edit activity name in-place
|
||||
And I should not see "Test forum name"
|
||||
# Cancel renaming
|
||||
And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Good news')]" "xpath_element"
|
||||
And I set the field "New name for activity Good news" to "Terrible news"
|
||||
And I type "Terrible news"
|
||||
And I press the escape key
|
||||
And "New name for activity Good news" "field" should not exist
|
||||
And I should see "Good news"
|
||||
|
||||
@@ -852,22 +852,12 @@ class behat_course extends behat_base {
|
||||
* @param string $newactivityname
|
||||
*/
|
||||
public function i_change_activity_name_to($activityname, $newactivityname) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
throw new DriverException('Change activity name step is not available with Javascript disabled');
|
||||
}
|
||||
|
||||
$activity = $this->escape($activityname);
|
||||
|
||||
$this->execute('behat_course::i_click_on_in_the_activity',
|
||||
array(get_string('edittitle'), "link", $activity)
|
||||
);
|
||||
|
||||
// Adding chr(10) to save changes.
|
||||
$this->execute('behat_forms::i_set_the_field_to',
|
||||
array('title', $this->escape($newactivityname) . chr(10))
|
||||
);
|
||||
|
||||
$this->execute('behat_forms::i_set_the_field_in_container_to', [
|
||||
get_string('edittitle'),
|
||||
$activityname,
|
||||
'activity',
|
||||
$newactivityname
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,6 @@ Feature: Managers can manage categories for course custom fields
|
||||
Then I should see "Other fields" in the "#customfield_catlist" "css_element"
|
||||
And I navigate to "Reports > Logs" in site administration
|
||||
And I press "Get these logs"
|
||||
And I log out
|
||||
|
||||
Scenario: Edit a category name for custom course fields
|
||||
Given the following "custom field categories" exist:
|
||||
@@ -20,15 +19,12 @@ Feature: Managers can manage categories for course custom fields
|
||||
| Category for test | core_course | course | 0 |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Courses > Course custom fields" in site administration
|
||||
And I click on "Edit category name" "link" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element"
|
||||
And I set the field "New value for Category for test" to "Good fields"
|
||||
And I press the enter key
|
||||
And I set the field "Edit category name" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element" to "Good fields"
|
||||
Then I should not see "Category for test" in the "#customfield_catlist" "css_element"
|
||||
And "New value for Category for test" "field" should not exist
|
||||
And I should see "Good fields" in the "#customfield_catlist" "css_element"
|
||||
And I navigate to "Reports > Logs" in site administration
|
||||
And I press "Get these logs"
|
||||
And I log out
|
||||
|
||||
Scenario: Delete a category for custom course fields
|
||||
Given the following "custom field categories" exist:
|
||||
@@ -46,7 +42,6 @@ Feature: Managers can manage categories for course custom fields
|
||||
Then I should not see "Test category" in the "#customfield_catlist" "css_element"
|
||||
And I navigate to "Reports > Logs" in site administration
|
||||
And I press "Get these logs"
|
||||
And I log out
|
||||
|
||||
Scenario: Move field in the course custom fields to another category
|
||||
Given the following "custom field categories" exist:
|
||||
@@ -78,7 +73,6 @@ Feature: Managers can manage categories for course custom fields
|
||||
And I press "Move \"Field1\""
|
||||
And I follow "After field Field2"
|
||||
And "Field1" "text" should appear after "Field2" "text"
|
||||
And I log out
|
||||
|
||||
Scenario: Reorder course custom field categories
|
||||
Given the following "custom field categories" exist:
|
||||
@@ -108,4 +102,3 @@ Feature: Managers can manage categories for course custom fields
|
||||
And "Field1" "text" should appear after "Category1" "text"
|
||||
And "Category2" "text" should appear after "Field1" "text"
|
||||
And "Category3" "text" should appear after "Category2" "text"
|
||||
And I log out
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* CLI sync for full external database synchronisation.
|
||||
*
|
||||
* Sample cron entry:
|
||||
* # 5 minutes past 4am
|
||||
* 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/database/cli/sync.php
|
||||
*
|
||||
* Notes:
|
||||
* - it is required to use the web server account when executing PHP CLI scripts
|
||||
* - you need to change the "www-data" to match the apache user account
|
||||
* - use "su" if "sudo" not available
|
||||
*
|
||||
* @deprecated since Moodle 3.7 MDL-59986 - please do not use this CLI script any more, use scheduled task instead.
|
||||
* @todo MDL-63266 This will be deleted in Moodle 3.11.
|
||||
* @package enrol_database
|
||||
* @copyright 2010 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__.'/../../../config.php');
|
||||
require_once("$CFG->libdir/clilib.php");
|
||||
|
||||
// Now get cli options.
|
||||
list($options, $unrecognized) = cli_get_params(array('verbose'=>false, 'help'=>false), array('v'=>'verbose', 'h'=>'help'));
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help']) {
|
||||
$help =
|
||||
"Execute enrol sync with external database.
|
||||
The enrol_database plugin must be enabled and properly configured.
|
||||
|
||||
Options:
|
||||
-v, --verbose Print verbose progress information
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
\$ sudo -u www-data /usr/bin/php enrol/database/cli/sync.php
|
||||
|
||||
Sample cron entry:
|
||||
# 5 minutes past 4am
|
||||
5 4 * * * sudo -u www-data /usr/bin/php /var/www/moodle/enrol/database/cli/sync.php
|
||||
";
|
||||
|
||||
echo $help;
|
||||
die;
|
||||
}
|
||||
|
||||
cli_problem('[ENROL DATABASE] The sync enrolments cron script has been deprecated. Please use the scheduled task instead.');
|
||||
|
||||
// Abort execution of the CLI script if the enrol_database\task\sync_enrolments is enabled.
|
||||
$task = \core\task\manager::get_scheduled_task('enrol_database\task\sync_enrolments');
|
||||
if (!$task->get_disabled()) {
|
||||
cli_error('[ENROL DATABASE] The scheduled task sync_enrolments is enabled, the cron execution has been aborted.');
|
||||
}
|
||||
|
||||
if (!enrol_is_enabled('database')) {
|
||||
cli_error('enrol_database plugin is disabled, synchronisation stopped', 2);
|
||||
}
|
||||
|
||||
if (empty($options['verbose'])) {
|
||||
$trace = new null_progress_trace();
|
||||
} else {
|
||||
$trace = new text_progress_trace();
|
||||
}
|
||||
|
||||
/** @var enrol_database_plugin $enrol */
|
||||
$enrol = enrol_get_plugin('database');
|
||||
$result = 0;
|
||||
|
||||
$result = $result | $enrol->sync_courses($trace);
|
||||
$result = $result | $enrol->sync_enrolments($trace);
|
||||
|
||||
exit($result);
|
||||
@@ -1,5 +1,8 @@
|
||||
This files describes API changes in the enrol_database code.
|
||||
|
||||
=== 3.11 ===
|
||||
* Final deprecation enrol/database/cli/sync.php. Refer below for substitute.
|
||||
|
||||
=== 3.9 ===
|
||||
* Class enrol_database_admin_setting_category has been removed. This class was only used by the database
|
||||
enrolment plugin settings and it was replaced by admin_settings_coursecat_select.
|
||||
|
||||
@@ -80,6 +80,7 @@ $string['profilelabel'] = '{$a->label}: {$a->profile} {$a->operator} {$a->value}
|
||||
$string['profilelabelnovalue'] = '{$a->label}: {$a->profile} {$a->operator}';
|
||||
$string['removeall'] = 'Remove all filters';
|
||||
$string['removeselected'] = 'Remove selected';
|
||||
$string['replacefilters'] = 'Replace filters';
|
||||
$string['selectlabel'] = '{$a->label} {$a->operator} {$a->value}';
|
||||
$string['startswith'] = 'starts with';
|
||||
$string['tablenosave'] = 'Changes in table above are saved automatically.';
|
||||
|
||||
+5
-1303
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,6 @@ class behat_field_manager {
|
||||
* @return behat_form_field
|
||||
*/
|
||||
public static function get_form_field_from_label($label, RawMinkContext $context) {
|
||||
|
||||
// There are moodle form elements that are not directly related with
|
||||
// a basic HTML form field, we should also take care of them.
|
||||
// The DOM node.
|
||||
@@ -172,6 +171,10 @@ class behat_field_manager {
|
||||
} else if ($tagname == 'select') {
|
||||
// Select tag.
|
||||
return 'select';
|
||||
} else if ($tagname == 'span') {
|
||||
if ($fieldnode->hasAttribute('data-inplaceeditable') && $fieldnode->getAttribute('data-inplaceeditable')) {
|
||||
return 'inplaceeditable';
|
||||
}
|
||||
}
|
||||
|
||||
// We can not provide a closer field type.
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* The Interface for a behat root context.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright 2020 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Interface for a behat root context.
|
||||
*
|
||||
* This interface should be implemented by the behat_base context, and behat form fields, and it should be paired with
|
||||
* the behat_session_trait.
|
||||
*
|
||||
* It should not be necessary to implement this interface, and the behat_session_trait trait in normal circumstances.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright 2020 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface behat_session_interface {
|
||||
/**
|
||||
* Small timeout.
|
||||
*
|
||||
* A reduced timeout for cases where self::TIMEOUT is too much
|
||||
* and a simple $this->getSession()->getPage()->find() could not
|
||||
* be enough.
|
||||
*
|
||||
* @deprecated since Moodle 3.7 MDL-64979 - please use get_reduced_timeout() instead
|
||||
* @todo MDL-64982 This will be deleted in Moodle 3.11
|
||||
* @see behat_base::get_reduced_timeout()
|
||||
*/
|
||||
const REDUCED_TIMEOUT = 2;
|
||||
|
||||
/**
|
||||
* The timeout for each Behat step (load page, wait for an element to load...).
|
||||
*
|
||||
* @deprecated since Moodle 3.7 MDL-64979 - please use get_timeout() instead
|
||||
* @todo MDL-64982 This will be deleted in Moodle 3.11
|
||||
* @see behat_base::get_timeout()
|
||||
*/
|
||||
const TIMEOUT = 6;
|
||||
|
||||
/**
|
||||
* And extended timeout for specific cases.
|
||||
*
|
||||
* @deprecated since Moodle 3.7 MDL-64979 - please use get_extended_timeout() instead
|
||||
* @todo MDL-64982 This will be deleted in Moodle 3.11
|
||||
* @see behat_base::get_extended_timeout()
|
||||
*/
|
||||
const EXTENDED_TIMEOUT = 10;
|
||||
|
||||
/**
|
||||
* The JS code to check that the page is ready.
|
||||
*
|
||||
* The document must be complete and either M.util.pending_js must be empty, or it must not be defined at all.
|
||||
*/
|
||||
const PAGE_READY_JS = "document.readyState === 'complete' && " .
|
||||
"(typeof M !== 'object' || typeof M.util !== 'object' || " .
|
||||
"typeof M.util.pending_js === 'undefined' || M.util.pending_js.length === 0)";
|
||||
|
||||
/**
|
||||
* Returns the Mink session.
|
||||
*
|
||||
* @param string|null $name name of the session OR active session will be used
|
||||
* @return \Behat\Mink\Session
|
||||
*/
|
||||
public function getSession($name = null);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -135,7 +135,7 @@ class behat_partial_named_selector extends \Behat\Mink\Selector\PartialNamedSele
|
||||
*/
|
||||
protected static $moodleselectors = array(
|
||||
'activity' => <<<XPATH
|
||||
.//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][normalize-space(.) = %locator% ]
|
||||
.//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][descendant::*[contains(normalize-space(.), %locator%)]]
|
||||
XPATH
|
||||
, 'block' => <<<XPATH
|
||||
.//*[@data-block][contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or
|
||||
@@ -262,6 +262,11 @@ XPATH
|
||||
.//*[@data-passwordunmask='wrapper']
|
||||
/descendant::input[@id = %locator% or @id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
|
||||
XPATH
|
||||
,
|
||||
'inplaceeditable' => <<<XPATH
|
||||
.//descendant::span[@data-inplaceeditable][descendant::a[%titleMatch%]]
|
||||
XPATH
|
||||
,
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
use Behat\Mink\Session as Session,
|
||||
Behat\Mink\Element\NodeElement as NodeElement;
|
||||
use Behat\Mink\Element\NodeElement;
|
||||
use Behat\Mink\Session;
|
||||
|
||||
/**
|
||||
* Representation of a form field.
|
||||
@@ -38,7 +38,10 @@ use Behat\Mink\Session as Session,
|
||||
* @copyright 2012 David Monllaó
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_form_field {
|
||||
class behat_form_field implements behat_session_interface {
|
||||
|
||||
// All of the functionality of behat_base is shared with form fields via the behat_session_trait trait.
|
||||
use behat_session_trait;
|
||||
|
||||
/**
|
||||
* @var Session Behat session.
|
||||
@@ -55,6 +58,16 @@ class behat_form_field {
|
||||
*/
|
||||
protected $fieldlocator = false;
|
||||
|
||||
/**
|
||||
* Returns the Mink session.
|
||||
*
|
||||
* @param string|null $name name of the session OR active session will be used
|
||||
* @return \Behat\Mink\Session
|
||||
*/
|
||||
public function getSession($name = null) {
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* General constructor with the node and the session to interact with.
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Custom interaction with inplace editable elements.
|
||||
*
|
||||
* @package core_form
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/behat_form_text.php');
|
||||
|
||||
/**
|
||||
* Custom interaction with inplace editable elements.
|
||||
*
|
||||
* @package core_form
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_form_inplaceeditable extends behat_form_text {
|
||||
/**
|
||||
* Sets the value to a field.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function set_value($value) {
|
||||
// Require JS to run this step.
|
||||
self::require_javascript();
|
||||
|
||||
// Click to enable editing.
|
||||
self::execute(
|
||||
'behat_general::i_click_on_in_the',
|
||||
[
|
||||
'[data-inplaceeditablelink]',
|
||||
'css_element',
|
||||
$this->field,
|
||||
'NodeElement',
|
||||
]
|
||||
);
|
||||
|
||||
// Note: It is not possible to use the NodeElement->keyDown() and related functions because
|
||||
// this can trigger a focusOnElement call each time.
|
||||
// Instead use the behat_base::type_keys() function.
|
||||
|
||||
// The inplace editable selects all existing content on focus.
|
||||
// Clear the existing value.
|
||||
self::type_keys($this->session, [behat_keys::BACKSPACE]);
|
||||
|
||||
// Type in the new value, followed by ENTER to save the value.
|
||||
self::type_keys($this->session, array_merge(
|
||||
str_split($value),
|
||||
[behat_keys::ENTER]
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,19 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class redis extends handler {
|
||||
/**
|
||||
* Compressor: none.
|
||||
*/
|
||||
const COMPRESSION_NONE = 'none';
|
||||
/**
|
||||
* Compressor: PHP GZip.
|
||||
*/
|
||||
const COMPRESSION_GZIP = 'gzip';
|
||||
/**
|
||||
* Compressor: PHP Zstandard.
|
||||
*/
|
||||
const COMPRESSION_ZSTD = 'zstd';
|
||||
|
||||
/** @var string $host save_path string */
|
||||
protected $host = '';
|
||||
/** @var int $port The port to connect to */
|
||||
@@ -56,6 +69,8 @@ class redis extends handler {
|
||||
protected $lockretry = 100;
|
||||
/** @var int $serializer The serializer to use */
|
||||
protected $serializer = \Redis::SERIALIZER_PHP;
|
||||
/** @var int $compressor The compressor to use */
|
||||
protected $compressor = self::COMPRESSION_NONE;
|
||||
/** @var string $lasthash hash of the session data content */
|
||||
protected $lasthash = null;
|
||||
|
||||
@@ -122,6 +137,10 @@ class redis extends handler {
|
||||
if (isset($CFG->session_redis_lock_expire)) {
|
||||
$this->lockexpire = (int)$CFG->session_redis_lock_expire;
|
||||
}
|
||||
|
||||
if (isset($CFG->session_redis_compressor)) {
|
||||
$this->compressor = $CFG->session_redis_compressor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +287,8 @@ class redis extends handler {
|
||||
if ($this->requires_write_lock()) {
|
||||
$this->lock_session($id);
|
||||
}
|
||||
$sessiondata = $this->connection->get($id);
|
||||
$sessiondata = $this->uncompress($this->connection->get($id));
|
||||
|
||||
if ($sessiondata === false) {
|
||||
if ($this->requires_write_lock()) {
|
||||
$this->unlock_session($id);
|
||||
@@ -285,6 +305,53 @@ class redis extends handler {
|
||||
return $sessiondata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses session data.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
private function compress($value) {
|
||||
switch ($this->compressor) {
|
||||
case self::COMPRESSION_NONE:
|
||||
return $value;
|
||||
case self::COMPRESSION_GZIP:
|
||||
return gzencode($value);
|
||||
case self::COMPRESSION_ZSTD:
|
||||
return zstd_compress($value);
|
||||
default:
|
||||
debugging("Invalid compressor: {$this->compressor}");
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompresses session data.
|
||||
*
|
||||
* @param string $value
|
||||
* @return mixed
|
||||
*/
|
||||
private function uncompress($value) {
|
||||
if ($value === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($this->compressor) {
|
||||
case self::COMPRESSION_NONE:
|
||||
break;
|
||||
case self::COMPRESSION_GZIP:
|
||||
$value = gzdecode($value);
|
||||
break;
|
||||
case self::COMPRESSION_ZSTD:
|
||||
$value = zstd_uncompress($value);
|
||||
break;
|
||||
default:
|
||||
debugging("Invalid compressor: {$this->compressor}");
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the serialized session data to our session store.
|
||||
*
|
||||
@@ -312,6 +379,8 @@ class redis extends handler {
|
||||
// There can be race conditions on new sessions racing each other but we can
|
||||
// address that in the future.
|
||||
try {
|
||||
$data = $this->compress($data);
|
||||
|
||||
$this->connection->setex($id, $this->timeout, $data);
|
||||
} catch (RedisException $e) {
|
||||
error_log('Failed talking to redis: '.$e->getMessage());
|
||||
|
||||
+26
-7
@@ -7801,7 +7801,14 @@ function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php'
|
||||
$filepath = $allplugins[$pluginname] . DIRECTORY_SEPARATOR . $file;
|
||||
if (file_exists($filepath)) {
|
||||
include_once($filepath);
|
||||
$pluginfunctions[$plugintype . '_' . $pluginname] = $functionname;
|
||||
|
||||
// Now that the file is loaded, we must verify the function still exists.
|
||||
if (function_exists($functionname)) {
|
||||
$pluginfunctions[$plugintype . '_' . $pluginname] = $functionname;
|
||||
} else {
|
||||
// Invalidate the cache for next run.
|
||||
\cache_helper::invalidate_by_definition('core', 'plugin_functions');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7834,6 +7841,7 @@ function get_plugins_with_function($function, $file = 'lib.php', $include = true
|
||||
// Clearning the filename as cache_helper::hash_key only allows a-zA-Z0-9_.
|
||||
$key = $function . '_' . clean_param($file, PARAM_ALPHA);
|
||||
$pluginfunctions = $cache->get($key);
|
||||
$dirty = false;
|
||||
|
||||
// Use the plugin manager to check that plugins are currently installed.
|
||||
$pluginmanager = \core_plugin_manager::instance();
|
||||
@@ -7848,14 +7856,14 @@ function get_plugins_with_function($function, $file = 'lib.php', $include = true
|
||||
foreach ($plugins as $plugin => $function) {
|
||||
if (!isset($installedplugins[$plugin])) {
|
||||
// Plugin code is still present on disk but it is not installed.
|
||||
unset($pluginfunctions[$plugintype][$plugin]);
|
||||
continue;
|
||||
$dirty = true;
|
||||
break 2;
|
||||
}
|
||||
|
||||
// Cache might be out of sync with the codebase, skip the plugin if it is not available.
|
||||
if (empty($allplugins[$plugin])) {
|
||||
unset($pluginfunctions[$plugintype][$plugin]);
|
||||
continue;
|
||||
$dirty = true;
|
||||
break 2;
|
||||
}
|
||||
|
||||
$fileexists = file_exists($allplugins[$plugin] . DIRECTORY_SEPARATOR . $file);
|
||||
@@ -7864,11 +7872,22 @@ function get_plugins_with_function($function, $file = 'lib.php', $include = true
|
||||
include_once($allplugins[$plugin] . DIRECTORY_SEPARATOR . $file);
|
||||
} else if (!$fileexists) {
|
||||
// If the file is not available any more it should not be returned.
|
||||
unset($pluginfunctions[$plugintype][$plugin]);
|
||||
$dirty = true;
|
||||
break 2;
|
||||
}
|
||||
|
||||
// Check if the function still exists in the file.
|
||||
if ($include && !function_exists($function)) {
|
||||
$dirty = true;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $pluginfunctions;
|
||||
|
||||
// If the cache is dirty, we should fall through and let it rebuild.
|
||||
if (!$dirty) {
|
||||
return $pluginfunctions;
|
||||
}
|
||||
}
|
||||
|
||||
$pluginfunctions = array();
|
||||
|
||||
@@ -41,26 +41,6 @@ use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
|
||||
*/
|
||||
class behat_deprecated extends behat_base {
|
||||
|
||||
/**
|
||||
* Docks a block. Editing mode should be previously enabled.
|
||||
* @throws ExpectationException
|
||||
* @param string $blockname
|
||||
* @return void
|
||||
* @deprecated since Moodle 3.7 MDL-64506 - please do not use this definition step any more.
|
||||
* @todo MDL-65215 This will be deleted in Moodle 3.11.
|
||||
*/
|
||||
public function i_dock_block($blockname) {
|
||||
|
||||
$message = "Block docking is no longer used as of MDL-64506. Please update your tests.";
|
||||
$this->deprecated_message($message);
|
||||
|
||||
// Looking for both title and alt.
|
||||
$xpath = "//input[@type='image'][@title='" . get_string('dockblock', 'block', $blockname) . "' or @alt='" . get_string('addtodock', 'block') . "']";
|
||||
$this->execute('behat_general::i_click_on_in_the',
|
||||
array($xpath, "xpath_element", $this->escape($blockname), "block")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if $CFG->behat_usedeprecated is not allowed.
|
||||
*
|
||||
|
||||
@@ -116,6 +116,30 @@ class core_session_redis_testcase extends advanced_testcase {
|
||||
$this->assertSessionNoLocks();
|
||||
}
|
||||
|
||||
public function test_compression_read_and_write_works() {
|
||||
global $CFG;
|
||||
|
||||
$CFG->session_redis_compressor = \core\session\redis::COMPRESSION_GZIP;
|
||||
|
||||
$sess = new \core\session\redis();
|
||||
$sess->init();
|
||||
$this->assertTrue($sess->handler_write('sess1', 'DATA'));
|
||||
$this->assertSame('DATA', $sess->handler_read('sess1'));
|
||||
$this->assertTrue($sess->handler_close());
|
||||
|
||||
if (extension_loaded('zstd')) {
|
||||
$CFG->session_redis_compressor = \core\session\redis::COMPRESSION_ZSTD;
|
||||
|
||||
$sess = new \core\session\redis();
|
||||
$sess->init();
|
||||
$this->assertTrue($sess->handler_write('sess2', 'DATA'));
|
||||
$this->assertSame('DATA', $sess->handler_read('sess2'));
|
||||
$this->assertTrue($sess->handler_close());
|
||||
}
|
||||
|
||||
$CFG->session_redis_compressor = \core\session\redis::COMPRESSION_NONE;
|
||||
}
|
||||
|
||||
public function test_session_blocks_with_existing_session() {
|
||||
$sess = new \core\session\redis();
|
||||
$sess->init();
|
||||
|
||||
@@ -4,6 +4,7 @@ information provided here is intended especially for developers.
|
||||
=== 3.11 ===
|
||||
* New optional parameter $extracontent for print_collapsible_region_start(). This allows developers to add interactive HTML elements
|
||||
(e.g. a help icon) after the collapsible region's toggle link.
|
||||
* Final deprecation i_dock_block() in behat_deprecated.php
|
||||
|
||||
=== 3.10 ===
|
||||
* PHPUnit has been upgraded to 8.5. That comes with a few changes:
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("core_message/message_drawer",["jquery","core/custom_interaction_events","core/pubsub","core_message/message_drawer_view_contact","core_message/message_drawer_view_contacts","core_message/message_drawer_view_conversation","core_message/message_drawer_view_group_info","core_message/message_drawer_view_overview","core_message/message_drawer_view_search","core_message/message_drawer_view_settings","core_message/message_drawer_router","core_message/message_drawer_routes","core_message/message_drawer_events","core/pending","core/drawer"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={DRAWER:"[data-region=\"right-hand-drawer\"]",JUMPTO:".popover-region [data-region=\"jumpto\"]",PANEL_BODY_CONTAINER:"[data-region=\"panel-body-container\"]",PANEL_HEADER_CONTAINER:"[data-region=\"panel-header-container\"]",VIEW_CONTACT:"[data-region=\"view-contact\"]",VIEW_CONTACTS:"[data-region=\"view-contacts\"]",VIEW_CONVERSATION:"[data-region=\"view-conversation\"]",VIEW_GROUP_INFO:"[data-region=\"view-group-info\"]",VIEW_OVERVIEW:"[data-region=\"view-overview\"]",VIEW_SEARCH:"[data-region=\"view-search\"]",VIEW_SETTINGS:"[data-region=\"view-settings\"]",ROUTES:"[data-route]",ROUTES_BACK:"[data-route-back]",HEADER_CONTAINER:"[data-region=\"header-container\"]",BODY_CONTAINER:"[data-region=\"body-container\"]",FOOTER_CONTAINER:"[data-region=\"footer-container\"]",CLOSE_BUTTON:"[data-action=\"closedrawer\"]"},q=function(a,b,c){var d=b.find(p.HEADER_CONTAINER).find(c);if(!d.length){d=b.find(p.PANEL_HEADER_CONTAINER).find(c)}var e=b.find(p.BODY_CONTAINER).find(c);if(!e.length){e=b.find(p.PANEL_BODY_CONTAINER).find(c)}var f=b.find(p.FOOTER_CONTAINER).find(c);return[a,d.length?d:null,e.length?e:null,f.length?f:null]},r=[[l.VIEW_CONTACT,p.VIEW_CONTACT,d.show,d.description],[l.VIEW_CONTACTS,p.VIEW_CONTACTS,e.show,e.description],[l.VIEW_CONVERSATION,p.VIEW_CONVERSATION,f.show,f.description],[l.VIEW_GROUP_INFO,p.VIEW_GROUP_INFO,g.show,g.description],[l.VIEW_OVERVIEW,p.VIEW_OVERVIEW,h.show,h.description],[l.VIEW_SEARCH,p.VIEW_SEARCH,i.show,i.description],[l.VIEW_SETTINGS,p.VIEW_SETTINGS,j.show,j.description]],s=function(a,b){r.forEach(function(c){k.add(a,c[0],q(a,b,c[1]),c[2],c[3])})},t=function(a,b){if(!b.attr("data-shown")){k.go(a,l.VIEW_OVERVIEW);b.attr("data-shown",!0)}var c=o.getDrawerRoot(b);if(c.length){o.show(c)}},u=function(a){var b=o.getDrawerRoot(a);if(b.length){o.hide(b)}},v=function(a){var b=o.getDrawerRoot(a);if(b.length){return o.isVisible(b)}return!0},w=function(b){a(p.DRAWER).attr("data-origin",b)},x=function(d,e,f){b.define(e,[b.events.activate]);var g=/^data-route-param-?(\d*)$/;e.on(b.events.activate,p.ROUTES,function(b,c){for(var e=a(b.target).closest(p.ROUTES),f=e.attr("data-route"),h=[],j=0;j<e[0].attributes.length;j++){h.push(e[0].attributes[j])}var l=h.filter(function(a){var b=a.nodeName,c=g.test(b);return c});l.sort(function(c,a){var b=g.exec(c.nodeName),d=g.exec(a.nodeName),e=1<b.length?b[1]:0,f=1<d.length?d[1]:0;if(e<f){return-1}else if(f<e){return 1}else{return 0}});var m=l.map(function(a){return a.nodeValue}),n=[d,f].concat(m);k.go.apply(null,n);c.originalEvent.preventDefault()});e.on(b.events.activate,p.ROUTES_BACK,function(a,b){k.back(d);b.originalEvent.preventDefault()});e.on("hide.bs.collapse",".collapse",function(b){var c=new n;a(b.target).one("hidden.bs.collapse",function(){c.resolve()})});e.on("show.bs.collapse",".collapse",function(b){var c=new n;a(b.target).one("shown.bs.collapse",function(){c.resolve()})});a(p.JUMPTO).focus(function(){var b=a(p.HEADER_CONTAINER).find("input:visible");if(b.length){b.focus()}else{a(p.HEADER_CONTAINER).find(p.ROUTES_BACK).focus()}});a(p.DRAWER).focus(function(){var b=a(this).attr("data-origin");if(b){a("#"+b).focus()}});if(!f){c.subscribe(m.SHOW,function(){t(d,e)});c.subscribe(m.HIDE,function(){u(e)});c.subscribe(m.TOGGLE_VISIBILITY,function(b){if(v(e)){u(e);a(p.JUMPTO).attr("tabindex",-1)}else{t(d,e);w(b);a(p.JUMPTO).attr("tabindex",0)}})}c.subscribe(m.SHOW_CONVERSATION,function(a){w(a.buttonid);t(d,e);k.go(d,l.VIEW_CONVERSATION,a.conversationid)});var h=e.find(p.CLOSE_BUTTON);h.on(b.events.activate,function(){c.publish(m.TOGGLE_VISIBILITY)});c.subscribe(m.CREATE_CONVERSATION_WITH_USER,function(a){w(a.buttonid);t(d,e);k.go(d,l.VIEW_CONVERSATION,null,"create",a.userid)});c.subscribe(m.SHOW_SETTINGS,function(){t(d,e);k.go(d,l.VIEW_SETTINGS)});c.subscribe(m.PREFERENCES_UPDATED,function(a){var b=a.filter(function(a){return"message_entertosend"==a.type}),c=b.length?b[0]:null;if(c){var d=e.find(p.FOOTER_CONTAINER).find(p.VIEW_CONVERSATION);d.attr("data-enter-to-send",c.value)}})};return{init:function init(b,c,d,e){b=a(b);s(c,b);x(c,b,d);if(d){t(c,b);if(e){var f=e.params||[];f=[c,e.path].concat(f);k.go.apply(null,f)}}}}});
|
||||
define ("core_message/message_drawer",["jquery","core/custom_interaction_events","core/pubsub","core_message/message_drawer_view_contact","core_message/message_drawer_view_contacts","core_message/message_drawer_view_conversation","core_message/message_drawer_view_group_info","core_message/message_drawer_view_overview","core_message/message_drawer_view_search","core_message/message_drawer_view_settings","core_message/message_drawer_router","core_message/message_drawer_routes","core_message/message_drawer_events","core/pending","core/drawer"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={DRAWER:"[data-region=\"right-hand-drawer\"]",JUMPTO:".popover-region [data-region=\"jumpto\"]",PANEL_BODY_CONTAINER:"[data-region=\"panel-body-container\"]",PANEL_HEADER_CONTAINER:"[data-region=\"panel-header-container\"]",VIEW_CONTACT:"[data-region=\"view-contact\"]",VIEW_CONTACTS:"[data-region=\"view-contacts\"]",VIEW_CONVERSATION:"[data-region=\"view-conversation\"]",VIEW_GROUP_INFO:"[data-region=\"view-group-info\"]",VIEW_OVERVIEW:"[data-region=\"view-overview\"]",VIEW_SEARCH:"[data-region=\"view-search\"]",VIEW_SETTINGS:"[data-region=\"view-settings\"]",ROUTES:"[data-route]",ROUTES_BACK:"[data-route-back]",HEADER_CONTAINER:"[data-region=\"header-container\"]",BODY_CONTAINER:"[data-region=\"body-container\"]",FOOTER_CONTAINER:"[data-region=\"footer-container\"]",CLOSE_BUTTON:"[data-action=\"closedrawer\"]"},q=function(a,b,c){var d=b.find(p.HEADER_CONTAINER).find(c);if(!d.length){d=b.find(p.PANEL_HEADER_CONTAINER).find(c)}var e=b.find(p.BODY_CONTAINER).find(c);if(!e.length){e=b.find(p.PANEL_BODY_CONTAINER).find(c)}var f=b.find(p.FOOTER_CONTAINER).find(c);return[a,d.length?d:null,e.length?e:null,f.length?f:null]},r=[[l.VIEW_CONTACT,p.VIEW_CONTACT,d.show,d.description],[l.VIEW_CONTACTS,p.VIEW_CONTACTS,e.show,e.description],[l.VIEW_CONVERSATION,p.VIEW_CONVERSATION,f.show,f.description],[l.VIEW_GROUP_INFO,p.VIEW_GROUP_INFO,g.show,g.description],[l.VIEW_OVERVIEW,p.VIEW_OVERVIEW,h.show,h.description],[l.VIEW_SEARCH,p.VIEW_SEARCH,i.show,i.description],[l.VIEW_SETTINGS,p.VIEW_SETTINGS,j.show,j.description]],s=function(a,b){r.forEach(function(c){k.add(a,c[0],q(a,b,c[1]),c[2],c[3])})},t=function(a,b){if(!b.attr("data-shown")){k.go(a,l.VIEW_OVERVIEW);b.attr("data-shown",!0)}var c=o.getDrawerRoot(b);if(c.length){o.show(c)}},u=function(a){var b=o.getDrawerRoot(a);if(b.length){o.hide(b)}},v=function(a){var b=o.getDrawerRoot(a);if(b.length){return o.isVisible(b)}return!0},w=function(b){a(p.DRAWER).attr("data-origin",b)},x=function(d,e,f){b.define(e,[b.events.activate]);var g=/^data-route-param-?(\d*)$/;e.on(b.events.activate,p.ROUTES,function(b,c){for(var e=a(b.target).closest(p.ROUTES),f=e.attr("data-route"),h=[],j=0;j<e[0].attributes.length;j++){h.push(e[0].attributes[j])}var l=h.filter(function(a){var b=a.nodeName,c=g.test(b);return c});l.sort(function(c,a){var b=g.exec(c.nodeName),d=g.exec(a.nodeName),e=1<b.length?b[1]:0,f=1<d.length?d[1]:0;if(e<f){return-1}else if(f<e){return 1}else{return 0}});var m=l.map(function(a){return a.nodeValue}),n=[d,f].concat(m);k.go.apply(null,n);c.originalEvent.preventDefault()});e.on(b.events.activate,p.ROUTES_BACK,function(a,b){k.back(d);b.originalEvent.preventDefault()});e.on("hide.bs.collapse",".collapse",function(b){var c=new n;a(b.target).one("hidden.bs.collapse",function(){c.resolve()})});e.on("show.bs.collapse",".collapse",function(b){var c=new n;a(b.target).one("shown.bs.collapse",function(){c.resolve()})});a(p.JUMPTO).focus(function(){var b=e.find(p.CLOSE_BUTTON);if(b.length){b.focus()}else{a(p.HEADER_CONTAINER).find(p.ROUTES_BACK).focus()}});a(p.DRAWER).focus(function(){var b=a(this).attr("data-origin");if(b){a("#"+b).focus()}});if(!f){c.subscribe(m.SHOW,function(){t(d,e)});c.subscribe(m.HIDE,function(){u(e)});c.subscribe(m.TOGGLE_VISIBILITY,function(b){if(v(e)){u(e);a(p.JUMPTO).attr("tabindex",-1)}else{t(d,e);w(b);a(p.JUMPTO).attr("tabindex",0)}})}c.subscribe(m.SHOW_CONVERSATION,function(a){w(a.buttonid);t(d,e);k.go(d,l.VIEW_CONVERSATION,a.conversationid)});var h=e.find(p.CLOSE_BUTTON);h.on(b.events.activate,function(){var b=a(p.DRAWER).attr("data-origin");if(b){a("#"+b).focus()}c.publish(m.TOGGLE_VISIBILITY)});c.subscribe(m.CREATE_CONVERSATION_WITH_USER,function(a){w(a.buttonid);t(d,e);k.go(d,l.VIEW_CONVERSATION,null,"create",a.userid)});c.subscribe(m.SHOW_SETTINGS,function(){t(d,e);k.go(d,l.VIEW_SETTINGS)});c.subscribe(m.PREFERENCES_UPDATED,function(a){var b=a.filter(function(a){return"message_entertosend"==a.type}),c=b.length?b[0]:null;if(c){var d=e.find(p.FOOTER_CONTAINER).find(p.VIEW_CONVERSATION);d.attr("data-enter-to-send",c.value)}})};return{init:function init(b,c,d,e){b=a(b);s(c,b);x(c,b,d);if(d){t(c,b);if(e){var f=e.params||[];f=[c,e.path].concat(f);k.go.apply(null,f)}}}}});
|
||||
//# sourceMappingURL=message_drawer.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -254,7 +254,7 @@ function(
|
||||
});
|
||||
|
||||
$(SELECTORS.JUMPTO).focus(function() {
|
||||
var firstInput = $(SELECTORS.HEADER_CONTAINER).find('input:visible');
|
||||
var firstInput = root.find(SELECTORS.CLOSE_BUTTON);
|
||||
if (firstInput.length) {
|
||||
firstInput.focus();
|
||||
} else {
|
||||
@@ -298,6 +298,10 @@ function(
|
||||
|
||||
var closebutton = root.find(SELECTORS.CLOSE_BUTTON);
|
||||
closebutton.on(CustomEvents.events.activate, function() {
|
||||
var button = $(SELECTORS.DRAWER).attr('data-origin');
|
||||
if (button) {
|
||||
$('#' + button).focus();
|
||||
}
|
||||
PubSub.publish(Events.TOGGLE_VISIBILITY);
|
||||
});
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
{{< core/drawer}}
|
||||
{{$drawercontent}}
|
||||
<div id="message-drawer-{{uniqid}}" class="message-app" data-region="message-drawer" role="region">
|
||||
<div class="closewidget bg-light border-bottom text-right">
|
||||
<a class="text-dark" data-action="closedrawer" href="#">
|
||||
<div class="closewidget text-right pr-2">
|
||||
<a class="text-dark btn-link" data-action="closedrawer" href="#">
|
||||
{{#pix}} i/window_close, core, {{#str}} closebuttontitle {{/str}} {{/pix}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="hidden border-bottom px-2 py-3" aria-hidden="true" data-region="view-contacts">
|
||||
<div class="hidden border-bottom p-1 px-sm-2" aria-hidden="true" data-region="view-contacts">
|
||||
<div class="d-flex align-items-center">
|
||||
{{#isdrawer}}
|
||||
<div class="align-self-stretch">
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
}}
|
||||
|
||||
<div
|
||||
class="hidden bg-white position-relative border-bottom p-1 p-sm-2"
|
||||
class="hidden bg-white position-relative border-bottom p-1 px-sm-2"
|
||||
aria-hidden="true"
|
||||
data-region="view-conversation"
|
||||
>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="border-bottom p-1 px-sm-2 py-sm-3" aria-hidden="false" {{^isdrawer}}data-in-panel="true"{{/isdrawer}} data-region="view-overview">
|
||||
<div class="border-bottom p-1 px-sm-2" aria-hidden="false" {{^isdrawer}}data-in-panel="true"{{/isdrawer}} data-region="view-overview">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="input-group simplesearchform">
|
||||
<input
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
}}
|
||||
|
||||
<div class="hidden border-bottom px-2 py-3 view-search" {{^isdrawer}}data-in-panel="true"{{/isdrawer}} aria-hidden="true" data-region="view-search">
|
||||
<div class="hidden border-bottom p-1 px-sm-2 view-search" {{^isdrawer}}data-in-panel="true"{{/isdrawer}} aria-hidden="true" data-region="view-search">
|
||||
<div class="d-flex align-items-center">
|
||||
<a
|
||||
class="mr-2 align-self-stretch d-flex align-items-center"
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
}}
|
||||
|
||||
<div class="hidden border-bottom px-2 py-3" aria-hidden="true" data-region="view-settings">
|
||||
<div class="hidden border-bottom p-1 px-sm-2 pb-sm-3" aria-hidden="true" data-region="view-settings">
|
||||
<div class="d-flex align-items-center">
|
||||
{{#isdrawer}}
|
||||
<div class="align-self-stretch" >
|
||||
|
||||
@@ -12,16 +12,16 @@ Feature: Edited book chapters handle tags correctly
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "activity" exists:
|
||||
| activity | book |
|
||||
| course | C1 |
|
||||
| idnumber | book1 |
|
||||
| name | Test book |
|
||||
| description | A book about dreams |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Book" to section "1" and I fill the form with:
|
||||
| Name | Test book |
|
||||
| Description | A book about dreams! |
|
||||
And I log out
|
||||
|
||||
Scenario: Book chapter edition of custom tags works as expected
|
||||
Given I log in as "teacher1"
|
||||
|
||||
@@ -28,85 +28,9 @@ require_once(__DIR__.'/lib.php');
|
||||
require_once($CFG->dirroot.'/mod/book/locallib.php');
|
||||
|
||||
/**
|
||||
* Generate toc structure and titles
|
||||
*
|
||||
* @deprecated since Moodle 3.7
|
||||
* @param array $chapters
|
||||
* @param stdClass $book
|
||||
* @param stdClass $cm
|
||||
* @return array
|
||||
*/
|
||||
function booktool_print_get_toc($chapters, $book, $cm) {
|
||||
debugging('booktool_print_get_toc() is deprecated. Please use booktool_print renderer
|
||||
function render_print_book_toc().', DEBUG_DEVELOPER);
|
||||
|
||||
$first = true;
|
||||
$titles = array();
|
||||
|
||||
$context = context_module::instance($cm->id);
|
||||
|
||||
$toc = ''; // Representation of toc (HTML).
|
||||
|
||||
switch ($book->numbering) {
|
||||
case BOOK_NUM_NONE:
|
||||
$toc .= html_writer::start_tag('div', array('class' => 'book_toc_none'));
|
||||
break;
|
||||
case BOOK_NUM_NUMBERS:
|
||||
$toc .= html_writer::start_tag('div', array('class' => 'book_toc_numbered'));
|
||||
break;
|
||||
case BOOK_NUM_BULLETS:
|
||||
$toc .= html_writer::start_tag('div', array('class' => 'book_toc_bullets'));
|
||||
break;
|
||||
case BOOK_NUM_INDENTED:
|
||||
$toc .= html_writer::start_tag('div', array('class' => 'book_toc_indented'));
|
||||
break;
|
||||
}
|
||||
|
||||
$toc .= html_writer::tag('a', '', array('name' => 'toc')); // Representation of toc (HTML).
|
||||
|
||||
$toc .= html_writer::tag('h2', get_string('toc', 'mod_book'));
|
||||
$toc .= html_writer::start_tag('ul');
|
||||
foreach ($chapters as $ch) {
|
||||
if (!$ch->hidden) {
|
||||
$title = book_get_chapter_title($ch->id, $chapters, $book, $context);
|
||||
if (!$ch->subchapter) {
|
||||
|
||||
if ($first) {
|
||||
$toc .= html_writer::start_tag('li');
|
||||
} else {
|
||||
$toc .= html_writer::end_tag('ul');
|
||||
$toc .= html_writer::end_tag('li');
|
||||
$toc .= html_writer::start_tag('li');
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ($first) {
|
||||
$toc .= html_writer::start_tag('li');
|
||||
$toc .= html_writer::start_tag('ul');
|
||||
$toc .= html_writer::start_tag('li');
|
||||
} else {
|
||||
$toc .= html_writer::start_tag('li');
|
||||
}
|
||||
|
||||
}
|
||||
$titles[$ch->id] = $title;
|
||||
$toc .= html_writer::link(new moodle_url('#ch'.$ch->id), $title, array('title' => s($title)));
|
||||
if (!$ch->subchapter) {
|
||||
$toc .= html_writer::start_tag('ul');
|
||||
} else {
|
||||
$toc .= html_writer::end_tag('li');
|
||||
}
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
|
||||
$toc .= html_writer::end_tag('ul');
|
||||
$toc .= html_writer::end_tag('li');
|
||||
$toc .= html_writer::end_tag('ul');
|
||||
$toc .= html_writer::end_tag('div');
|
||||
|
||||
$toc = str_replace('<ul></ul>', '', $toc); // Cleanup of invalid structures.
|
||||
|
||||
return array($toc, $titles);
|
||||
function booktool_print_get_toc() {
|
||||
throw new coding_exception(__FUNCTION__ . ' can not be used any more. Please use booktool_print renderer
|
||||
function render_print_book_toc().');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
This files describes API changes in the book code.
|
||||
|
||||
=== 3.11 ===
|
||||
* Final deprecation - booktool_print_get_toc(). Please use render_print_book_toc() instead.
|
||||
|
||||
=== 3.8 ===
|
||||
|
||||
* The following functions have been finally deprecated and can not be used anymore:
|
||||
|
||||
@@ -130,8 +130,7 @@ Feature: The forum search allows users to perform advanced searches for forum po
|
||||
And I press "Search forums"
|
||||
And I should see "Advanced search"
|
||||
And I set the field "Is tagged with" to "SearchedTag"
|
||||
And I click on "[data-value='SearchedTag']" "css_element"
|
||||
And I press the escape key
|
||||
And I press the enter key
|
||||
When I press "Search forums"
|
||||
Then I should see "My subject"
|
||||
And I should not see "Your subjective"
|
||||
|
||||
+14
-1
@@ -2074,6 +2074,18 @@ function lti_calculate_custom_parameter($value) {
|
||||
return implode(",", groups_get_user_groups($COURSE->id, $USER->id)[0]);
|
||||
case 'Context.id.history':
|
||||
return implode(",", get_course_history($COURSE));
|
||||
case 'CourseSection.timeFrame.begin':
|
||||
if (empty($COURSE->startdate)) {
|
||||
return "";
|
||||
}
|
||||
$dt = new DateTime("@$COURSE->startdate", new DateTimeZone('UTC'));
|
||||
return $dt->format(DateTime::ATOM);
|
||||
case 'CourseSection.timeFrame.end':
|
||||
if (empty($COURSE->enddate)) {
|
||||
return "";
|
||||
}
|
||||
$dt = new DateTime("@$COURSE->enddate", new DateTimeZone('UTC'));
|
||||
return $dt->format(DateTime::ATOM);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -3739,7 +3751,8 @@ function lti_get_capabilities() {
|
||||
'CourseSection.label' => 'context_label',
|
||||
'CourseSection.sourcedId' => 'lis_course_section_sourcedid',
|
||||
'CourseSection.longDescription' => '$COURSE->summary',
|
||||
'CourseSection.timeFrame.begin' => '$COURSE->startdate',
|
||||
'CourseSection.timeFrame.begin' => null,
|
||||
'CourseSection.timeFrame.end' => null,
|
||||
'ResourceLink.id' => 'resource_link_id',
|
||||
'ResourceLink.title' => 'resource_link_title',
|
||||
'ResourceLink.description' => 'resource_link_description',
|
||||
|
||||
@@ -21,9 +21,7 @@ Feature: Rename external tools via inline editing
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "External tool" to section "1" and I fill the form with:
|
||||
| Activity name | Test tool activity 1 |
|
||||
And I click on "Edit title" "link" in the "li#section-1" "css_element"
|
||||
And I set the field "New name for activity Test tool activity 1" to "Test tool activity renamed"
|
||||
And I press the enter key
|
||||
And I set the field "Edit title" in the "li#section-1" "css_element" to "Test tool activity renamed"
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
Then I should not see "Test tool activity 1"
|
||||
And I should see "Test tool activity renamed"
|
||||
|
||||
@@ -397,7 +397,8 @@ class behat_mod_quiz extends behat_question_base {
|
||||
|
||||
$this->execute('behat_general::assert_page_contains_text', $this->escape(get_string('edittitleinstructions')));
|
||||
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('maxmark', $this->escape($newmark) . chr(10)));
|
||||
$this->execute('behat_general::i_type', [$newmark]);
|
||||
$this->execute('behat_general::i_press_named_key', ['', 'enter']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -653,7 +654,9 @@ class behat_mod_quiz extends behat_question_base {
|
||||
|
||||
$this->execute('behat_general::assert_page_contains_text', $this->escape(get_string('edittitleinstructions')));
|
||||
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('section', $this->escape($sectionheading) . chr(10)));
|
||||
$this->execute('behat_general::i_press_named_key', ['', 'backspace']);
|
||||
$this->execute('behat_general::i_type', [$sectionheading]);
|
||||
$this->execute('behat_general::i_press_named_key', ['', 'enter']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,16 +17,19 @@ Feature: Edit quiz marks with no attempts
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | grade | decimalpoints | questiondecimalpoints |
|
||||
| quiz | Quiz 1 | C1 | quiz1 | 20 | 2 | -1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "True/False" question to the "Quiz 1" quiz with:
|
||||
| Question name | First question |
|
||||
| Question text | Answer me |
|
||||
| Default mark | 2.0 |
|
||||
And I add a "True/False" question to the "Quiz 1" quiz with:
|
||||
| Question name | Second question |
|
||||
| Question text | Answer again |
|
||||
| Default mark | 3.0 |
|
||||
|
||||
And the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Test questions |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | First question | Answer me |
|
||||
| Test questions | truefalse | Second question | Answer again |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page | maxmark |
|
||||
| First question | 1 | 2.0 |
|
||||
| Second question | 1 | 3.0 |
|
||||
And I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
|
||||
|
||||
@javascript
|
||||
Scenario: Set the max mark for a question.
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ class get_available_gateways extends external_api {
|
||||
new external_single_structure([
|
||||
'shortname' => new external_value(PARAM_PLUGIN, 'Name of the plugin'),
|
||||
'name' => new external_value(PARAM_TEXT, 'Human readable name of the gateway'),
|
||||
'description' => new external_value(PARAM_TEXT, 'description of the gateway'),
|
||||
'description' => new external_value(PARAM_RAW, 'description of the gateway'),
|
||||
'surcharge' => new external_value(PARAM_INT, 'percentage of surcharge when using the gateway'),
|
||||
'cost' => new external_value(PARAM_TEXT,
|
||||
'Cost in human-readable form (amount plus surcharge with currency sign)'),
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
function xmldb_paygw_paypal_install() {
|
||||
global $CFG;
|
||||
|
||||
// Enable the Paypal payment gateway on installation. It still needs to be configured and enabled for accounts.
|
||||
$order = (!empty($CFG->paygw_plugins_sortorder)) ? explode(',', $CFG->paygw_plugins_sortorder) : [];
|
||||
set_config('paygw_plugins_sortorder', join(',', array_merge($order, ['paypal'])));
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<input class="custom-control-input" type="radio" name="payby" id="id-payby-{{uniqid}}-{{shortname}}" data-cost="{{cost}}" data-surcharge="{{surcharge}}" value="{{shortname}}" {{#checked}} checked="checked" {{/checked}} />
|
||||
<label class="custom-control-label bg-light border p-3 my-3" for="id-payby-{{uniqid}}-{{shortname}}">
|
||||
<p class="h3">{{name}}</p>
|
||||
<p class="content mb-2">{{description}}</p>
|
||||
<p class="content mb-2">{{{description}}}</p>
|
||||
{{#pix}} img, paygw_{{shortname}} {{/pix}}
|
||||
</label>
|
||||
</div>
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -211,7 +211,7 @@ define(['jquery', 'core/dragdrop'], function($, dragDrop) {
|
||||
|
||||
// Resize them to the same size.
|
||||
$('.dropzones .droppreview').css('padding', '0');
|
||||
var numGroups = $('select.draggroup').first().find('option').length;
|
||||
var numGroups = $('.draggroup select').first().find('option').length;
|
||||
for (var group = 1; group <= numGroups; group++) {
|
||||
dragDropToImageForm.resizeAllDragsAndDropsInGroup(group);
|
||||
}
|
||||
@@ -398,9 +398,8 @@ define(['jquery', 'core/dragdrop'], function($, dragDrop) {
|
||||
top = Math.round(dropPosition.top - backgroundPosition.top);
|
||||
|
||||
// Constrain coordinates to be inside the background.
|
||||
// The -10 here matches the +10 in resizeAllDragsAndDropsInGroup().
|
||||
left = Math.max(0, Math.min(left, backgroundImage.width() - drop.width() - 10));
|
||||
top = Math.max(0, Math.min(top, backgroundImage.height() - drop.height() - 10));
|
||||
left = Math.round(Math.max(0, Math.min(left, backgroundImage.outerWidth() - drop.outerWidth())));
|
||||
top = Math.round(Math.max(0, Math.min(top, backgroundImage.outerHeight() - drop.outerHeight())));
|
||||
|
||||
// Update the form.
|
||||
dragDropToImageForm.form.setFormValue('drops', [dropNo, 'xleft'], left);
|
||||
|
||||
@@ -99,6 +99,7 @@ form.mform fieldset#id_previewareaheader .dragitems {
|
||||
form.mform fieldset#id_previewareaheader .droppreview {
|
||||
position: absolute;
|
||||
cursor: move;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.que.ddimageortext .dragitems.readonly .drag {
|
||||
|
||||
@@ -106,7 +106,7 @@ class qtype_essay_renderer extends qtype_renderer {
|
||||
*/
|
||||
public function files_input(question_attempt $qa, $numallowed,
|
||||
question_display_options $options) {
|
||||
global $CFG;
|
||||
global $CFG, $COURSE;
|
||||
require_once($CFG->dirroot . '/lib/form/filemanager.php');
|
||||
|
||||
$pickeroptions = new stdClass();
|
||||
@@ -122,7 +122,12 @@ class qtype_essay_renderer extends qtype_renderer {
|
||||
$pickeroptions->accepted_types = $qa->get_question()->filetypeslist;
|
||||
|
||||
$fm = new form_filemanager($pickeroptions);
|
||||
$fm->options->maxbytes = $qa->get_question()->maxbytes;;
|
||||
$fm->options->maxbytes = get_user_max_upload_file_size(
|
||||
$this->page->context,
|
||||
$CFG->maxbytes,
|
||||
$COURSE->maxbytes,
|
||||
$qa->get_question()->maxbytes
|
||||
);
|
||||
$filesrenderer = $this->page->get_renderer('core', 'files');
|
||||
|
||||
$text = '';
|
||||
|
||||
@@ -8,8 +8,8 @@ I need to choose the appropriate maxbytes for attachments
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | T1 | Teacher1 | teacher1@moodle.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
| fullname | shortname | category | maxbytes |
|
||||
| Course 1 | C1 | 0 | 1048576 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
@@ -18,15 +18,24 @@ I need to choose the appropriate maxbytes for attachments
|
||||
| Course | C1 | Test questions |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | template | attachments | maxbytes |
|
||||
| Test questions | essay | essay-1-20MB | editor | 1 | 20971520 |
|
||||
Given I log in as "teacher1"
|
||||
| Test questions | essay | essay-1-512KB | editor | 1 | 524288 |
|
||||
| Test questions | essay | essay-1-max | editor | 1 | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Question bank" in current page administration
|
||||
|
||||
@javascript @_switch_window
|
||||
Scenario: Preview an Essay question and see the allowed maximum file sizes and number of attachments.
|
||||
When I choose "Preview" action for "essay-1-20MB" in the question bank
|
||||
When I choose "Preview" action for "essay-1-512KB" in the question bank
|
||||
And I switch to "questionpreview" window
|
||||
And I should see "Please write a story about a frog."
|
||||
And I should see "Maximum file size: 20MB, maximum number of files: 1"
|
||||
Then I should see "Please write a story about a frog."
|
||||
And I should see "Maximum file size: 512KB, maximum number of files: 1"
|
||||
And I switch to the main window
|
||||
|
||||
@javascript @_switch_window
|
||||
Scenario: Preview an Essay question with Course upload limit and see the allowed maximum file size.
|
||||
When I choose "Preview" action for "essay-1-max" in the question bank
|
||||
And I switch to "questionpreview" window
|
||||
Then I should see "Please write a story about a frog."
|
||||
And I should see "Maximum file size: 1MB, maximum number of files: 1"
|
||||
And I switch to the main window
|
||||
|
||||
@@ -28,15 +28,11 @@ Feature: Managers can create and manage tag collections
|
||||
Scenario: Adding tag collections
|
||||
When I follow "Hobbies"
|
||||
Then I should see "Nothing to display"
|
||||
And I log out
|
||||
|
||||
Scenario: Editing tag collections
|
||||
When I click on "Edit tag collection name" "link" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element"
|
||||
And I set the field "New name for tag collection Hobbies" to "Newname"
|
||||
And I press the enter key
|
||||
When I set the field "Edit tag collection name" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element" to "Newname"
|
||||
Then I should not see "Hobbies"
|
||||
And I should see "Newname"
|
||||
And I log out
|
||||
|
||||
Scenario: Resorting tag collections
|
||||
When I follow "Add tag collection"
|
||||
@@ -48,41 +44,34 @@ Feature: Managers can create and manage tag collections
|
||||
And "Blogging" "link" should appear before "Hobbies" "link"
|
||||
And I click on "Move down" "link" in the "Blogging" "table_row"
|
||||
And "Blogging" "link" should appear after "Hobbies" "link"
|
||||
And I log out
|
||||
|
||||
Scenario: Deleting tag collections
|
||||
When I click on "Delete" "link" in the "Hobbies" "table_row"
|
||||
Then I should see "Are you sure you want to delete tag collection \"Hobbies\"?"
|
||||
And I press "Yes"
|
||||
And I should not see "Hobbies"
|
||||
And I log out
|
||||
|
||||
Scenario: Assigning tag area to tag collection
|
||||
And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element"
|
||||
And I should not see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element"
|
||||
When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element"
|
||||
And I set the field "Change tag collection of area User interests" to "Hobbies"
|
||||
When I set the field "Change tag collection" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" to "Hobbies"
|
||||
Then I should not see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element"
|
||||
And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Hobbies')]" "xpath_element"
|
||||
And I should see "Hobbies" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element"
|
||||
And I log out
|
||||
|
||||
Scenario: Disabling tag areas
|
||||
When I click on "Disable" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element"
|
||||
And I should not see "User interests" in the "table.tag-collections-table" "css_element"
|
||||
And I click on "Enable" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element"
|
||||
And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element"
|
||||
And I log out
|
||||
|
||||
Scenario: Deleting non-empty tag collections
|
||||
When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element"
|
||||
And I set the field "Change tag collection of area User interests" to "Hobbies"
|
||||
When I set the field "Change tag collection" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" to "Hobbies"
|
||||
And I click on "Delete" "link" in the "Hobbies" "table_row"
|
||||
Then I should see "Are you sure you want to delete tag collection \"Hobbies\"?"
|
||||
And I press "Yes"
|
||||
And I should not see "Hobbies"
|
||||
And I should see "User interests" in the "//table[contains(@class,'tag-collections-table')]//tr[contains(.,'Default collection')]" "xpath_element"
|
||||
And I log out
|
||||
|
||||
Scenario: Moving tags when changing tag collections
|
||||
And I open my profile in edit mode
|
||||
@@ -90,8 +79,7 @@ Feature: Managers can create and manage tag collections
|
||||
And I set the field "List of interests" to "Swimming, Tag0, Tag3"
|
||||
And I press "Update profile"
|
||||
And I navigate to "Appearance > Manage tags" in site administration
|
||||
When I click on "Change tag collection" "link" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element"
|
||||
And I set the field "Change tag collection of area User interests" to "Hobbies"
|
||||
When I set the field "Change tag collection" in the "//table[contains(@class,'tag-areas-table')]//tr[contains(.,'User interests')]" "xpath_element" to "Hobbies"
|
||||
And I follow "Hobbies"
|
||||
Then I should see "Swimming"
|
||||
And I should see "Tag0"
|
||||
@@ -107,7 +95,6 @@ Feature: Managers can create and manage tag collections
|
||||
And I should see "Tag3"
|
||||
And I should see "Tag1"
|
||||
And I should see "Tag2"
|
||||
And I log out
|
||||
|
||||
Scenario: Creating searchable and non-searchable tag collections
|
||||
And I follow "Add tag collection"
|
||||
@@ -129,4 +116,3 @@ Feature: Managers can create and manage tag collections
|
||||
And I click on "Site pages" "list_item" in the "Navigation" "block"
|
||||
And I click on "Tags" "link" in the "Navigation" "block"
|
||||
And "Select tag collection" "select" should not exist
|
||||
And I log out
|
||||
|
||||
@@ -158,19 +158,14 @@ Feature: Users can edit tags to add description or rename
|
||||
And I navigate to "Appearance > Manage tags" in site administration
|
||||
And I follow "Default collection"
|
||||
# Renaming tag to a valid name
|
||||
And I click on "Edit tag name" "link" in the "Cat" "table_row"
|
||||
And I set the field "New name for tag Cat" to "Kitten"
|
||||
And I press the enter key
|
||||
And I set the field "Edit tag name" in the "Cat" "table_row" to "Kitten"
|
||||
Then I should not see "Cat"
|
||||
And "New name for tag" "field" should not exist
|
||||
And I wait until "Kitten" "link" exists
|
||||
And I follow "Default collection"
|
||||
And I should see "Kitten"
|
||||
And I should not see "Cat"
|
||||
# Renaming tag to an invalid name
|
||||
And I click on "Edit tag name" "link" in the "Turtle" "table_row"
|
||||
And I set the field "New name for tag Turtle" to "DOG"
|
||||
And I press the enter key
|
||||
And I set the field "Edit tag name" in the "Turtle" "table_row" to "DOG"
|
||||
And I should see "The tag name is already in use. Do you want to combine these tags?"
|
||||
And I click on "Cancel" "button" in the "Confirm" "dialogue"
|
||||
And "New name for tag" "field" should not exist
|
||||
@@ -183,7 +178,7 @@ Feature: Users can edit tags to add description or rename
|
||||
And I should not see "DOG"
|
||||
# Cancel tag renaming
|
||||
And I click on "Edit tag name" "link" in the "Dog" "table_row"
|
||||
And I set the field "New name for tag Dog" to "Penguin"
|
||||
And I type "Penguin"
|
||||
And I press the escape key
|
||||
And "New name for tag" "field" should not exist
|
||||
And I should see "Turtle"
|
||||
@@ -197,9 +192,7 @@ Feature: Users can edit tags to add description or rename
|
||||
When I log in as "manager1"
|
||||
And I navigate to "Appearance > Manage tags" in site administration
|
||||
And I follow "Default collection"
|
||||
And I click on "Edit tag name" "link" in the "Turtle" "table_row"
|
||||
And I set the field "New name for tag Turtle" to "DOG"
|
||||
And I press the enter key
|
||||
And I set the field "Edit tag name" in the "Turtle" "table_row" to "DOG"
|
||||
And I should see "The tag name is already in use. Do you want to combine these tags?"
|
||||
And I press "Yes"
|
||||
Then I should not see "Turtle"
|
||||
|
||||
@@ -124,10 +124,6 @@ $right-drawer-width: 320px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.closewidget {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
display: block;
|
||||
right: $right-drawer-width * -1;
|
||||
@@ -147,10 +143,6 @@ $right-drawer-width: 320px;
|
||||
height: 100%;
|
||||
z-index: $zindex-fixed;
|
||||
}
|
||||
.closewidget {
|
||||
display: block;
|
||||
padding: 0 0.2rem;
|
||||
}
|
||||
}
|
||||
body.drawer-open-left,
|
||||
body.drawer-open-right {
|
||||
|
||||
@@ -14174,8 +14174,6 @@ body.drawer-ease {
|
||||
padding: 0;
|
||||
visibility: visible;
|
||||
opacity: 1; }
|
||||
[data-region=right-hand-drawer] .closewidget {
|
||||
display: none; }
|
||||
[data-region=right-hand-drawer].hidden {
|
||||
display: block;
|
||||
right: -320px;
|
||||
@@ -14191,9 +14189,6 @@ body.drawer-ease {
|
||||
top: 0;
|
||||
height: 100%;
|
||||
z-index: 1030; }
|
||||
[data-region=right-hand-drawer] .closewidget {
|
||||
display: block;
|
||||
padding: 0 0.2rem; }
|
||||
body.drawer-open-left,
|
||||
body.drawer-open-right {
|
||||
overflow: hidden; } }
|
||||
|
||||
@@ -14389,8 +14389,6 @@ body.drawer-ease {
|
||||
padding: 0;
|
||||
visibility: visible;
|
||||
opacity: 1; }
|
||||
[data-region=right-hand-drawer] .closewidget {
|
||||
display: none; }
|
||||
[data-region=right-hand-drawer].hidden {
|
||||
display: block;
|
||||
right: -320px;
|
||||
@@ -14406,9 +14404,6 @@ body.drawer-ease {
|
||||
top: 0;
|
||||
height: 100%;
|
||||
z-index: 1030; }
|
||||
[data-region=right-hand-drawer] .closewidget {
|
||||
display: block;
|
||||
padding: 0 0.2rem; }
|
||||
body.drawer-open-left,
|
||||
body.drawer-open-right {
|
||||
overflow: hidden; } }
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
|
||||
$formaction = required_param('formaction', PARAM_LOCALURL);
|
||||
$id = required_param('id', PARAM_INT);
|
||||
@@ -78,7 +79,8 @@ if ($formaction == 'bulkchange.php') {
|
||||
|
||||
if (empty($plugin) AND $operationname == 'download_participants') {
|
||||
// Check permissions.
|
||||
if (has_capability('moodle/course:manageactivities', $context)) {
|
||||
$pagecontext = ($course->id == SITEID) ? context_system::instance() : $context;
|
||||
if (course_can_view_participants($pagecontext)) {
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
|
||||
if (isset($plugins[$dataformat])) {
|
||||
if ($plugins[$dataformat]->is_enabled()) {
|
||||
|
||||
+17
-11
@@ -101,6 +101,12 @@ class user_filtering {
|
||||
// Fist the new filter form.
|
||||
$this->_addform = new user_add_filter_form($baseurl, array('fields' => $this->_fields, 'extraparams' => $extraparams));
|
||||
if ($adddata = $this->_addform->get_data()) {
|
||||
// Clear previous filters.
|
||||
if (!empty($adddata->replacefilters)) {
|
||||
$SESSION->user_filtering = [];
|
||||
}
|
||||
|
||||
// Add new filters.
|
||||
foreach ($this->_fields as $fname => $field) {
|
||||
$data = $field->check_data($adddata);
|
||||
if ($data === false) {
|
||||
@@ -111,19 +117,16 @@ class user_filtering {
|
||||
}
|
||||
$SESSION->user_filtering[$fname][] = $data;
|
||||
}
|
||||
// Clear the form.
|
||||
$_POST = array();
|
||||
$this->_addform = new user_add_filter_form($baseurl, array('fields' => $this->_fields, 'extraparams' => $extraparams));
|
||||
}
|
||||
|
||||
// Now the active filters.
|
||||
$this->_activeform = new user_active_filter_form($baseurl, array('fields' => $this->_fields, 'extraparams' => $extraparams));
|
||||
if ($adddata = $this->_activeform->get_data()) {
|
||||
if (!empty($adddata->removeall)) {
|
||||
if ($activedata = $this->_activeform->get_data()) {
|
||||
if (!empty($activedata->removeall)) {
|
||||
$SESSION->user_filtering = array();
|
||||
|
||||
} else if (!empty($adddata->removeselected) and !empty($adddata->filter)) {
|
||||
foreach ($adddata->filter as $fname => $instances) {
|
||||
} else if (!empty($activedata->removeselected) and !empty($activedata->filter)) {
|
||||
foreach ($activedata->filter as $fname => $instances) {
|
||||
foreach ($instances as $i => $val) {
|
||||
if (empty($val)) {
|
||||
continue;
|
||||
@@ -135,11 +138,14 @@ class user_filtering {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear+reload the form.
|
||||
$_POST = array();
|
||||
$this->_activeform = new user_active_filter_form($baseurl, array('fields' => $this->_fields, 'extraparams' => $extraparams));
|
||||
}
|
||||
// Now the active filters.
|
||||
|
||||
// Rebuild the forms if filters data was processed.
|
||||
if ($adddata || $activedata) {
|
||||
$_POST = []; // Reset submitted data.
|
||||
$this->_addform = new user_add_filter_form($baseurl, ['fields' => $this->_fields, 'extraparams' => $extraparams]);
|
||||
$this->_activeform = new user_active_filter_form($baseurl, ['fields' => $this->_fields, 'extraparams' => $extraparams]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,8 @@ class user_add_filter_form extends moodleform {
|
||||
* Form definition.
|
||||
*/
|
||||
public function definition() {
|
||||
global $SESSION;
|
||||
|
||||
$mform =& $this->_form;
|
||||
$fields = $this->_customdata['fields'];
|
||||
$extraparams = $this->_customdata['extraparams'];
|
||||
@@ -54,8 +56,15 @@ class user_add_filter_form extends moodleform {
|
||||
}
|
||||
}
|
||||
|
||||
// Add button.
|
||||
$mform->addElement('submit', 'addfilter', get_string('addfilter', 'filters'));
|
||||
// Add buttons.
|
||||
$replacefiltersbutton = $mform->createElement('submit', 'replacefilters', get_string('replacefilters', 'filters'));
|
||||
$addfilterbutton = $mform->createElement('submit', 'addfilter', get_string('addfilter', 'filters'));
|
||||
$buttons = array_filter([
|
||||
empty($SESSION->user_filtering) ? null : $replacefiltersbutton,
|
||||
$addfilterbutton,
|
||||
]);
|
||||
|
||||
$mform->addGroup($buttons);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -29,9 +29,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2020112100.00; // 20201109 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2020112700.00; // 20201109 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '3.11dev (Build: 20201121)';// Human-friendly version name
|
||||
$release = '3.11dev (Build: 20201127)';// Human-friendly version name
|
||||
$branch = '311'; // This version's branch.
|
||||
$maturity = MATURITY_ALPHA; // This version's maturity level.
|
||||
|
||||
Reference in New Issue
Block a user