first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
@core @core_block
Feature: Add blocks
In order to add more functionality to pages
As a teacher
I need to add blocks to pages
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
When I add the "Blog menu" block
Then I should see "View my entries about this course"
@javascript
Scenario: Add a block to a course with Javascript enabled
Scenario: Add a block to a course with Javascript disabled
@@ -0,0 +1,53 @@
@block @core_block @javascript @addablocklink
Feature: Add a block when main feature is enabled
In order to add a block to my course
As a teacher
Some blocks should be only added to courses if the main feature they are based on is enabled.
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And I am on the "C1" "course" page logged in as "admin"
Scenario Outline: The block can be added when main feature is enabled
Given the following config values are set as admin:
| <settingname1> | 1 | <settingplugin1> |
| <settingname2> | 1 | |
And I turn editing mode on
When I click on "Add a block" "link"
Then I should see "<blockname>"
Examples:
| blockname | settingname1 | settingname2 | settingplugin1 |
| Accessibility review | enableaccessibilitytools | | |
| Blog menu | enableblogs | | |
| Recent blog entries | enableblogs | | |
| Blog tags | enableblogs | usetags | |
| Comments | usecomments | | |
| Course completion status | enablecompletion | | |
| Global search | enableglobalsearch | | |
| Latest badges | enablebadges | | |
| Tags | usetags | | |
| Learning plans | enabled | | core_competency |
Scenario Outline: The block cannot be added when main feature is disabled
Given the following config values are set as admin:
| <settingname1> | 0 | <settingplugin1> |
| <settingname2> | 0 | |
And I turn editing mode on
When I click on "Add a block" "link"
Then I should not see "<blockname>"
Examples:
| blockname | settingname1 | settingname2 | settingplugin1 |
| Accessibility review | enableaccessibilitytools | | |
| Blog menu | enableblogs | | |
| Recent blog entries | enableblogs | | |
| Blog tags | enableblogs | usetags | |
| Comments | usecomments | | |
| Course completion status | enablecompletion | | |
| Global search | enableglobalsearch | | |
| Latest badges | enablebadges | | |
| Tags | usetags | | |
| Learning plans | enabled | | core_competency |
@@ -0,0 +1,101 @@
@block @core_block @javascript
Feature: Add a block when main feature is disabled
In order to add a block to my course
As a teacher
Some blocks should be only added to courses if the main feature they are based on is enabled.
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And I am on the "C1" "course" page logged in as "admin"
Scenario Outline: The block is displayed even when main feature is disabled
Given the following config values are set as admin:
| <settingname1> | 1 | <settingplugin1> |
And I turn editing mode on
And I add the "<blockname>" block
When the following config values are set as admin:
| <settingname1> | 0 | <settingplugin1> |
Then I should see "<blockname>"
Examples:
| blockname | settingname1 | settingplugin1 |
| Accessibility review | enableaccessibilitytools | |
| Blog menu | enableblogs | |
| Recent blog entries | enableblogs | |
| Comments | usecomments | |
| Course completion status | enablecompletion | |
| Global search | enableglobalsearch | |
| Latest badges | enablebadges | |
| Tags | usetags | |
| Learning plans | enabled | core_competency |
Scenario Outline: The block is displayed even when main feature is disabled (2 settings)
Given the following config values are set as admin:
| <settingname1> | 1 |
| <settingname2> | 1 |
And I turn editing mode on
And I add the "<blockname>" block
When the following config values are set as admin:
| <settingname1> | 0 |
| <settingname2> | 0 |
Then I should see "<blockname>"
Examples:
| blockname | settingname1 | settingname2 |
| Blog tags | enableblogs | usetags |
Scenario Outline: The block can be removed even when main feature is disabled
Given the following config values are set as admin:
| <settingname1> | 1 | <settingplugin1> |
And I turn editing mode on
And I add the "<blockname>" block
And I open the "<blockname>" blocks action menu
And I click on "Delete <blockname> block" "link" in the "<blockname>" "block"
And "Delete block?" "dialogue" should exist
And I click on "Cancel" "button" in the "Delete block?" "dialogue"
And I should see "<blockname>"
When the following config values are set as admin:
| <settingname1> | 0 | <settingplugin1> |
And I open the "<blockname>" blocks action menu
And I click on "Delete <blockname> block" "link" in the "<blockname>" "block"
And "Delete block?" "dialogue" should exist
And I click on "Delete" "button" in the "Delete block?" "dialogue"
Then I should not see "<blockname>"
Examples:
| blockname | settingname1 | settingplugin1 |
| Accessibility review | enableaccessibilitytools | |
| Blog menu | enableblogs | |
| Recent blog entries | enableblogs | |
| Comments | usecomments | |
| Course completion status | enablecompletion | |
| Global search | enableglobalsearch | |
| Latest badges | enablebadges | |
| Tags | usetags | |
| Learning plans | enabled | core_competency |
Scenario Outline: The block can be removed even when main feature is disabled (2 settings)
Given the following config values are set as admin:
| <settingname1> | 1 |
| <settingname2> | 1 |
And I turn editing mode on
And I add the "<blockname>" block
And I open the "<blockname>" blocks action menu
And I click on "Delete <blockname> block" "link" in the "<blockname>" "block"
And "Delete block?" "dialogue" should exist
And I click on "Cancel" "button" in the "Delete block?" "dialogue"
And I should see "<blockname>"
When the following config values are set as admin:
| <settingname1> | 0 |
| <settingname2> | 0 |
And I open the "<blockname>" blocks action menu
And I click on "Delete <blockname> block" "link" in the "<blockname>" "block"
And "Delete block?" "dialogue" should exist
And I click on "Delete" "button" in the "Delete block?" "dialogue"
Then I should not see "<blockname>"
Examples:
| blockname | settingname1 | settingname2 |
| Blog tags | enableblogs | usetags |
+200
View File
@@ -0,0 +1,200 @@
<?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/>.
/**
* Steps definitions related with blocks.
*
* @package core_block
* @category test
* @copyright 2012 David Monllaó
* @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.
use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
use Behat\Gherkin\Node\TableNode as TableNode;
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
/**
* Blocks management steps definitions.
*
* @package core_block
* @category test
* @copyright 2012 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_blocks extends behat_base {
/**
* Adds the selected block. Editing mode must be previously enabled.
*
* @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block$/
* @param string $blockname
*/
public function i_add_the_block($blockname) {
$addblock = get_string('addblock');
$this->execute('behat_general::i_click_on_in_the', [$addblock, 'link_exact', '.add_block_button', 'css_element']);
if (!$this->running_javascript()) {
$this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', '#region-main', 'css_element']);
} else {
$this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
}
}
/**
* Adds the selected block to the specified region
*
* Editing mode must be previously enabled.
*
* @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block to the "(?P<region_string>(?:[^"]|\\")*)" region$/
* @param string $blockname
* @param string $region
*/
public function i_add_the_block_to_the_region(string $blockname, string $region) {
if (!$this->running_javascript()) {
throw new coding_exception('Adding block to specific region is not possible with Javascript disabled');
}
if ($region === "default") {
$region = "";
}
$csselement = 'a[data-key="addblock"][data-blockregion='.behat_context_helper::escape($region).']';
$addblock = get_string('addblock');
$this->execute('behat_general::i_click_on', [$csselement, 'css_element']);
$this->execute('behat_general::i_click_on_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
}
/**
* Adds the selected block to the specified region and fills configuration form.
*
* Editing mode must be previously enabled.
*
* @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block to the (?P<region_string>(?:[^"]|\\")*) region with:$/
* @param string $blockname
* @param string $region
* @param TableNode $data
*/
public function i_add_the_block_to_the_region_with(string $blockname, string $region, TableNode $data) {
$blocklabel = get_string('textellipsis', 'moodle', $blockname);
$this->execute('behat_blocks::i_add_the_block_to_the_region', [$blocklabel, $region]);
$this->wait_for_pending_js();
$dialogname = get_string('addblock', 'core_block', $blockname);
$this->execute('behat_forms::i_set_the_following_fields_in_container_to_these_values',
[$dialogname, "dialogue", $data]);
$this->execute('behat_general::i_click_on_in_the', ["Save changes", 'button', $dialogname, 'dialogue']);
}
/**
* Adds the selected block if it is not already present. Editing mode must be previously enabled.
*
* @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block if not present$/
* @param string $blockname
*/
public function i_add_the_block_if_not_present($blockname) {
try {
$this->get_text_selector_node('block', $blockname);
} catch (ElementNotFoundException $e) {
$this->execute('behat_blocks::i_add_the_block', [$blockname]);
}
}
/**
* Opens a block's actions menu if it is not already opened.
*
* @Given /^I open the "(?P<block_name_string>(?:[^"]|\\")*)" blocks action menu$/
* @throws DriverException The step is not available when Javascript is disabled
* @param string $blockname
*/
public function i_open_the_blocks_action_menu($blockname) {
if (!$this->running_javascript()) {
// Action menu does not need to be open if Javascript is off.
return;
}
// If it is already opened we do nothing.
$blocknode = $this->get_text_selector_node('block', $blockname);
if ($blocknode->hasClass('action-menu-shown')) {
return;
}
$this->execute('behat_general::i_click_on_in_the',
array("a[data-toggle='dropdown']", "css_element", $this->escape($blockname), "block")
);
}
/**
* Clicks on Configure block for specified block. Page must be in editing mode.
*
* Argument block_name may be either the name of the block or CSS class of the block.
*
* @Given /^I configure the "(?P<block_name_string>(?:[^"]|\\")*)" block$/
* @param string $blockname
*/
public function i_configure_the_block($blockname) {
// Note that since $blockname may be either block name or CSS class, we can not use the exact label of "Configure" link.
$this->execute("behat_blocks::i_open_the_blocks_action_menu", $this->escape($blockname));
$this->execute('behat_general::i_click_on_in_the',
array("Configure", "link", $this->escape($blockname), "block")
);
}
/**
* Ensures that block can be added to the page but does not actually add it.
*
* @Then /^the add block selector should contain "(?P<block_name_string>(?:[^"]|\\")*)" block$/
* @param string $blockname
*/
public function the_add_block_selector_should_contain_block($blockname) {
$addblock = get_string('addblock');
$this->execute('behat_general::i_click_on', [$addblock, 'link_exact']);
$cancelstr = get_string('cancel');
if (!$this->running_javascript()) {
$this->execute('behat_general::should_exist_in_the', [$blockname, 'link_exact', '#region-main', 'css_element']);
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'link_exact', '#region-main', 'css_element']);
} else {
$this->execute('behat_general::should_exist_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'button', $addblock, 'dialogue']);
}
}
/**
* Ensures that block can not be added to the page.
*
* @Then /^the add block selector should not contain "(?P<block_name_string>(?:[^"]|\\")*)" block$/
* @param string $blockname
*/
public function the_add_block_selector_should_not_contain_block($blockname) {
$addblock = get_string('addblock');
$this->execute('behat_general::i_click_on', [$addblock, 'link_exact']);
$cancelstr = get_string('cancel');
if (!$this->running_javascript()) {
$this->execute('behat_general::should_not_exist_in_the', [$blockname, 'link_exact', '#region-main', 'css_element']);
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'link_exact', '#region-main', 'css_element']);
} else {
$this->execute('behat_general::should_not_exist_in_the', [$blockname, 'link_exact', $addblock, 'dialogue']);
$this->execute('behat_general::i_click_on_in_the', [$cancelstr, 'button', $addblock, 'dialogue']);
}
}
}
@@ -0,0 +1,71 @@
@core @core_block
Feature: Add and configure blocks throughout the site
In order to maintain some patterns across all the site
As a manager
I need to set and configure blocks throughout the site
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| manager1 | Manager | 1 | manager1@example.com |
| teacher1 | teacher | 1 | teacher@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "system role assigns" exist:
| user | course | role |
| manager1 | Acceptance test site | manager |
# Allow at least one role assignment in the block context:
And I log in as "admin"
And I navigate to "Users > Permissions > Define roles" in site administration
And I follow "Edit Non-editing teacher role"
And I set the following fields to these values:
| Block | 1 |
And I press "Save changes"
And I log out
Scenario: Add and configure a block throughtout the site
Given I log in as "manager1"
And I am on site homepage
And I turn editing mode on
And I add the "Comments" block
And I configure the "Comments" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
When I am on "Course 1" course homepage
Then I should see "Comments" in the "Comments" "block"
And I should see "Save comment" in the "Comments" "block"
And I am on site homepage
And I configure the "Comments" block
And I set the following fields to these values:
| Default weight | -10 (first) |
And I press "Save changes"
And I am on "Course 1" course homepage
# The first block matching the pattern should be top-left block
And I should see "Comments" in the "//*[@id='region-pre' or @id='block-region-side-pre']/descendant::*[contains(concat(' ', normalize-space(@class), ' '), ' block_comments ')]" "xpath_element"
Scenario: Blocks on the dashboard page can have roles assigned to them
Given I log in as "manager1"
When I turn editing mode on
Then I should see "Assign roles in Recently accessed items block"
Scenario: Blocks on courses can have roles assigned to them
Given I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I add the "Search forums" block
Then I should see "Assign roles in Search forums block"
@javascript
Scenario: Blocks can safely be customised
Given I log in as "admin"
And I am on homepage
And I turn editing mode on
And I add the "Text" block to the default region with:
| Text block title | Foo " onload="document.getElementsByTagName('body')[0].remove()" alt=" |
| Content | Example |
Then I should see "Example" in the "block_html" "block"
Then I should see "document.getElementsByTagName"
+33
View File
@@ -0,0 +1,33 @@
@core @core_block
Feature: Block removal via modal
In order to remove blocks
As a teacher
I need to use a modal to confirm the block to delete
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| search_forums | Course | C1 | course-view-* | side-pre |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
@javascript
Scenario: Removing a block via modal should remove the block on the page
Given I open the "Search forums" blocks action menu
When I click on "Delete Search forums block" "link" in the "Search forums" "block"
Then "Delete block?" "dialogue" should exist
And I click on "Delete" "button" in the "Delete block?" "dialogue"
And I wait to be redirected
And "Search forums" "block" should not exist
@javascript
Scenario: Cancel removing a block via modal should retain the block on the page
Given I open the "Search forums" blocks action menu
When I click on "Delete Search forums block" "link" in the "Search forums" "block"
Then "Delete block?" "dialogue" should exist
And I click on "Cancel" "button" in the "Delete block?" "dialogue"
And I should not see "Delete block?"
And "Search forums" "block" should exist
@@ -0,0 +1,54 @@
@core @core_block
Feature: Show hidden blocks in a docked block region when editing
In order to edit blocks in a hidden region
As a teacher
I need to be able to see the blocks when editing is on
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| admin | C1 | editingteacher |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| search_forums | Course | C1 | course-view-* | side-pre |
| news_items | Course | C1 | course-view-* | side-pre |
| calendar_upcoming | Course | C1 | course-view-* | side-pre |
| recent_activity | Course | C1 | course-view-* | side-pre |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
# Hide all the blocks in the non-default region
And I configure the "Search forums" block
And I set the following fields to these values:
| Visible | No |
And I click on "Save changes" "button"
And I configure the "Latest announcements" block
And I set the following fields to these values:
| Visible | No |
And I click on "Save changes" "button"
And I configure the "Upcoming events" block
And I set the following fields to these values:
| Visible | No |
And I click on "Save changes" "button"
And I configure the "Recent activity" block
And I set the following fields to these values:
| Visible | No |
When I click on "Save changes" "button"
# Editing is on so they should be visible
Then I should see "Search forums"
And I should see "Latest announcements"
And I should see "Upcoming events"
And I should see "Recent activity"
And I turn editing mode off
# Editing is off, so they should no longer be visible
And I should not see "Search forums"
And I should not see "Latest announcements"
And I should not see "Upcoming events"
And I should not see "Recent activity"
@javascript
Scenario: Check that a region with only hidden blocks is not docked in editing mode (javascript enabled)
Scenario: Check that a region with only hidden blocks is not docked in editing mode (javascript disabled)
+29
View File
@@ -0,0 +1,29 @@
@core @core_block
Feature: Block visibility
In order to configure blocks visibility
As a teacher
I need to show and hide blocks on a page
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| search_forums | Course | C1 | course-view-* | side-pre |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
@javascript
Scenario: Hiding all blocks on the page should remove the column they're in
When I open the "Search forums" blocks action menu
And I click on "Configure Search forums block" "link" in the "Search forums" "block"
And I set the field "Region" to "Right"
And I press "Save changes"
And I turn editing mode off
Then ".empty-region-side-post" "css_element" should not exist in the "body" "css_element"
And I turn editing mode on
And I open the "Search forums" blocks action menu
And I click on "Hide Search forums block" "link" in the "Search forums" "block"
And I turn editing mode off
And ".empty-region-side-post" "css_element" should exist in the "body" "css_element"
+55
View File
@@ -0,0 +1,55 @@
@core @core_block
Feature: Block appearances
In order to configure blocks appearance
As a teacher
I need to add and modify block configuration for the page
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | teacher | 1 | teacher1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| assign | Test assign name | C1 | assign1 |
| book | Test book name | C1 | book1 |
And the following "mod_book > chapter" exists:
| book | Test book name |
| title | Book title |
| content | Book content test test |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| comments | Course | C1 | course-view-* | side-pre |
And I am on the "Course 1" course page logged in as teacher1
And I turn editing mode on
And I configure the "Comments" block
And I set the following fields to these values:
| Display on page types | Any page |
And I press "Save changes"
Scenario: Block settings can be modified so that a block apprears on any page
When I click on "Test assign name" "link" in the "region-main" "region"
Then I should see "Comments" in the "Comments" "block"
And I am on "Course 1" course homepage
And I configure the "Comments" block
And I set the following fields to these values:
| Display on page types | Any course page |
And I press "Save changes"
And I turn editing mode off
And I click on "Test assign name" "link" in the "region-main" "region"
And I should not see "Comments"
Scenario: Block settings can be modified so that a block can be hidden
When I click on "Test book name" "link" in the "region-main" "region"
And I configure the "Comments" block
And I set the following fields to these values:
| Visible | No |
And I press "Save changes"
And I am on "Course 1" course homepage with editing mode off
And I click on "Test book name" "link" in the "region-main" "region"
Then I should not see "Comments"
+41
View File
@@ -0,0 +1,41 @@
@core @core_block
Feature: Block region moving
In order to configure blocks appearance
As a teacher
I need to modify block region for the page
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | teacher | 1 | teacher1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | course | name |
| assign | C1 | Test assign name |
| book | C1 | Test book name |
And the following "mod_book > chapter" exists:
| book | Test book name |
| title | Book title |
| content | Book content test test |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| comments | Course | C1 | course-view-* | side-pre |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I configure the "Comments" block
And I set the following fields to these values:
| Display on page types | Any page |
And I press "Save changes"
Scenario: Block settings can be modified so that a block can be moved
When I follow "Test book name"
And I configure the "Comments" block
And I set the following fields to these values:
| Region | Right |
And I press "Save changes"
And I should see "Comments" in the "//*[@id='region-post' or @id='block-region-side-post']" "xpath_element"
@@ -0,0 +1,38 @@
@core @core_block
Feature: Allowed blocks controls
In order to prevent the use of some blocks
As an admin
I need to restrict some blocks to be used in courses
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
Scenario: Blocks can be added with the default permissions
Given I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
When I add the "Course completion status" block
And I add the "Activities" block
Then I should see "Activities" in the "Activities" "block"
And I should see "Course completion status" in the "Course completion status" "block"
Scenario: Blocks can not be added when the admin restricts the permissions
Given the following "role capability" exists:
| role | editingteacher |
| block/activity_modules:addinstance | prohibit |
And I log in as "admin"
And I am on the "Course 1" "permissions" page
And I override the system permissions of "Teacher" role with:
| block/completionstatus:addinstance | Prohibit |
And I log out
When I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Then the add block selector should not contain "Activities" block
And the add block selector should not contain "Course completion status" block
@@ -0,0 +1,45 @@
@core @core_block
Feature: The context of a block can always be returned to it's original state.
In order to revert actions when configuring blocks
As an admin
I need to be able to return the block to original state
Scenario: Add and configure a block to display on every page and revert back
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "activities" exist:
| activity | name | intro | course | section | idnumber |
| assign | Assignment1 | Description | C1 | 1 | assign1 |
| assign | Assignment2 | Description | C1 | 1 | assign1 |
And I log in as "admin"
When I am on "Course 1" course homepage with editing mode on
And I add the "Tags" block
Then I should see "Tags" in the "Tags" "block"
And I navigate to course participants
And I configure the "Tags" block
And I set the following fields to these values:
| Display on page types | Any page |
And I press "Save changes"
And I am on "Course 1" course homepage
And I follow "Assignment1"
And I configure the "Tags" block
And I set the following fields to these values:
| Display on page types | Any assignment module page |
And I press "Save changes"
And I should see "Tags" in the "Tags" "block"
And I am on "Course 1" course homepage
And "Tags" "block" should not exist
And I navigate to course participants
And "Tags" "block" should not exist
And I am on "Course 1" course homepage
And I follow "Assignment2"
And I should see "Tags" in the "Tags" "block"
And I configure the "Tags" block
And I set the following fields to these values:
| Display on page types | Any page |
And I press "Save changes"
And I am on "Course 1" course homepage
And I should see "Tags" in the "Tags" "block"
And I navigate to course participants
And I should see "Tags" in the "Tags" "block"
+28
View File
@@ -0,0 +1,28 @@
<?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/>.
/**
* Coverage information for the core_block subsystem.
*
* @copyright 2021 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
return new class extends phpunit_coverage_info {
/** @var array The list of files relative to the plugin root to include in coverage generation. */
protected $includelistfiles = [
'moodleblock.class.php',
];
};
+539
View File
@@ -0,0 +1,539 @@
<?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/>.
namespace core_block;
use core_block_external;
use externallib_advanced_testcase;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/my/lib.php');
/**
* External block functions unit tests
*
* @package core_block
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Test get_course_blocks
*/
public function test_get_course_blocks(): void {
global $DB, $FULLME;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
$page = new \moodle_page();
$page->set_context(\context_course::instance($course->id));
$page->set_pagelayout('course');
$course->format = course_get_format($course)->get_format();
$page->set_pagetype('course-view-' . $course->format);
$page->blocks->load_blocks();
$newblock = 'calendar_upcoming';
$page->blocks->add_block_at_end_of_default_region($newblock);
$this->setUser($user);
// Check for the new block.
$result = core_block_external::get_course_blocks($course->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
// Expect the new block.
$this->assertCount(1, $result['blocks']);
$this->assertEquals($newblock, $result['blocks'][0]['name']);
}
/**
* Test get_course_blocks on site home
*/
public function test_get_course_blocks_site_home(): void {
global $DB, $FULLME;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$page = new \moodle_page();
$page->set_context(\context_course::instance(SITEID));
$page->set_pagelayout('frontpage');
$page->set_pagetype('site-index');
$page->blocks->load_blocks();
$newblock = 'calendar_upcoming';
$page->blocks->add_block_at_end_of_default_region($newblock);
$this->setUser($user);
// Check for the new block.
$result = core_block_external::get_course_blocks(SITEID);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
// Expect the new block.
$this->assertCount(1, $result['blocks']);
$this->assertEquals($newblock, $result['blocks'][0]['name']);
}
/**
* Test get_course_blocks
*/
public function test_get_course_blocks_overrides(): void {
global $DB, $CFG, $FULLME;
$this->resetAfterTest(true);
$CFG->defaultblocks_override = 'search_forums,course_list:calendar_upcoming,recent_activity';
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
$this->setUser($user);
// Try default blocks.
$result = core_block_external::get_course_blocks($course->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
// Expect 4 default blocks.
$this->assertCount(4, $result['blocks']);
$expectedblocks = array('navigation', 'settings', 'search_forums', 'course_list',
'calendar_upcoming', 'recent_activity');
foreach ($result['blocks'] as $block) {
if (!in_array($block['name'], $expectedblocks)) {
$this->fail("Unexpected block found: " . $block['name']);
}
}
}
/**
* Test get_course_blocks contents
*/
public function test_get_course_blocks_contents(): void {
global $DB, $FULLME;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
$coursecontext = \context_course::instance($course->id);
// Create a HTML block.
$title = 'Some course info';
$body = 'Some course info<br /><p>Some contents</p>';
$bodyformat = FORMAT_MOODLE;
$page = new \moodle_page();
$page->set_context($coursecontext);
$page->set_pagelayout('course');
$course->format = course_get_format($course)->get_format();
$page->set_pagetype('course-view-' . $course->format);
$page->blocks->load_blocks();
$newblock = 'html';
$page->blocks->add_block_at_end_of_default_region($newblock);
$this->setUser($user);
// Re-create the page.
$page = new \moodle_page();
$page->set_context($coursecontext);
$page->set_pagelayout('course');
$course->format = course_get_format($course)->get_format();
$page->set_pagetype('course-view-' . $course->format);
$page->blocks->load_blocks();
$blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
$block = end($blocks);
$block = block_instance('html', $block->instance);
$nonscalar = [
'something' => true,
];
$configdata = (object) [
'title' => $title,
'text' => [
'itemid' => 0,
'text' => $body,
'format' => $bodyformat,
],
'nonscalar' => $nonscalar
];
$block->instance_config_save((object) $configdata);
$filename = 'img.png';
$filerecord = array(
'contextid' => \context_block::instance($block->instance->id)->id,
'component' => 'block_html',
'filearea' => 'content',
'itemid' => 0,
'filepath' => '/',
'filename' => $filename,
);
// Create an area to upload the file.
$fs = get_file_storage();
// Create a file from the string that we made earlier.
$file = $fs->create_file_from_string($filerecord, 'some fake content (should be an image).');
// Check for the new block.
$result = core_block_external::get_course_blocks($course->id, true);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
// Expect the new block.
$this->assertCount(1, $result['blocks']);
$this->assertEquals($title, $result['blocks'][0]['contents']['title']);
$this->assertEquals($body, $result['blocks'][0]['contents']['content']);
$this->assertEquals(FORMAT_HTML, $result['blocks'][0]['contents']['contentformat']); // Format change for external.
$this->assertEquals('', $result['blocks'][0]['contents']['footer']);
$this->assertCount(1, $result['blocks'][0]['contents']['files']);
$this->assertEquals($newblock, $result['blocks'][0]['name']);
$configcounts = 0;
foreach ($result['blocks'][0]['configs'] as $config) {
if ($config['type'] = 'plugin' && $config['name'] == 'allowcssclasses' && $config['value'] == json_encode('0')) {
$configcounts++;
} else if ($config['type'] = 'instance' && $config['name'] == 'text' && $config['value'] == json_encode($body)) {
$configcounts++;
} else if ($config['type'] = 'instance' && $config['name'] == 'title' && $config['value'] == json_encode($title)) {
$configcounts++;
} else if ($config['type'] = 'instance' && $config['name'] == 'format' && $config['value'] == json_encode('0')) {
$configcounts++;
} else if ($config['type'] = 'instance' && $config['name'] == 'nonscalar' &&
$config['value'] == json_encode($nonscalar)) {
$configcounts++;
}
}
$this->assertEquals(5, $configcounts);
}
/**
* Test get_course_blocks contents with mathjax.
*/
public function test_get_course_blocks_contents_with_mathjax(): void {
global $DB, $CFG;
$this->resetAfterTest(true);
// Enable MathJax filter in content and headings.
$this->configure_filters([
['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
]);
// Create a few stuff to test with.
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
$coursecontext = \context_course::instance($course->id);
// Create a HTML block.
$title = 'My block $$(a+b)=2$$';
$body = 'My block contents $$(a+b)=2$$';
$bodyformat = FORMAT_MOODLE;
$page = new \moodle_page();
$page->set_context($coursecontext);
$page->set_pagelayout('course');
$course->format = course_get_format($course)->get_format();
$page->set_pagetype('course-view-' . $course->format);
$page->blocks->load_blocks();
$newblock = 'html';
$page->blocks->add_block_at_end_of_default_region($newblock);
$this->setUser($user);
// Re-create the page.
$page = new \moodle_page();
$page->set_context($coursecontext);
$page->set_pagelayout('course');
$course->format = course_get_format($course)->get_format();
$page->set_pagetype('course-view-' . $course->format);
$page->blocks->load_blocks();
$blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
$block = end($blocks);
$block = block_instance('html', $block->instance);
$nonscalar = [
'something' => true,
];
$configdata = (object) [
'title' => $title,
'text' => [
'itemid' => 0,
'text' => $body,
'format' => $bodyformat,
],
'nonscalar' => $nonscalar
];
$block->instance_config_save((object) $configdata);
// Check for the new block.
$result = core_block_external::get_course_blocks($course->id, true);
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
// Format the original data.
$sitecontext = \context_system::instance();
$title = \core_external\util::format_string($title, $coursecontext->id);
list($body, $bodyformat) = \core_external\util::format_text($body, $bodyformat, $coursecontext, 'block_html', 'content');
// Check that the block data is formatted.
$this->assertCount(1, $result['blocks']);
$this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
$result['blocks'][0]['contents']['title']);
$this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
$result['blocks'][0]['contents']['content']);
$this->assertEquals($title, $result['blocks'][0]['contents']['title']);
$this->assertEquals($body, $result['blocks'][0]['contents']['content']);
}
/**
* Test user get default dashboard blocks.
*/
public function test_get_dashboard_blocks_default_dashboard(): void {
global $PAGE, $DB;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
// Force a setting change to check the returned blocks settings.
set_config('displaycategories', 0, 'block_myoverview');
$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
// Get the expected default blocks.
$alldefaultblocksordered = $DB->get_records_menu(
'block_instances',
array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
'defaultregion, defaultweight ASC',
'id, blockname'
);
$this->setUser($user);
// Check for the default blocks.
$result = core_block_external::get_dashboard_blocks($user->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
// Expect all default blocks defined in blocks_add_default_system_blocks().
$this->assertCount(count($alldefaultblocksordered), $result['blocks']);
$returnedblocks = array();
foreach ($result['blocks'] as $block) {
// Check all the returned blocks are in the expected blocks array.
$this->assertContains($block['name'], $alldefaultblocksordered);
$returnedblocks[] = $block['name'];
// Check the configuration returned for this default block.
if ($block['name'] == 'myoverview') {
// Convert config to associative array to avoid DB sorting randomness.
$config = array_column($block['configs'], null, 'name');
$this->assertArrayHasKey('displaycategories', $config);
$this->assertEquals(json_encode('0'), $config['displaycategories']['value']);
$this->assertEquals('plugin', $config['displaycategories']['type']);
}
}
// Check that we received the blocks in the expected order.
$this->assertEquals(array_values($alldefaultblocksordered), $returnedblocks);
}
/**
* Test user get default dashboard blocks including a sticky block.
*/
public function test_get_dashboard_blocks_default_dashboard_including_sticky_block(): void {
global $PAGE, $DB;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
// Get the expected default blocks.
$alldefaultblocks = $DB->get_records_menu(
'block_instances', array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
'',
'id, blockname'
);
// Now, add a sticky block.
$page = new \moodle_page();
$page->set_context(\context_system::instance());
$page->set_pagetype('my-index');
$page->set_url(new \moodle_url('/'));
$page->blocks->add_region('side-pre');
$page->blocks->load_blocks();
$page->blocks->add_block('myprofile', 'side-pre', 0, true, '*');
$this->setUser($user);
// Check for the default blocks plus the sticky.
$result = core_block_external::get_dashboard_blocks($user->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
// Expect all default blocks defined in blocks_add_default_system_blocks() plus sticky one.
$this->assertCount(count($alldefaultblocks) + 1, $result['blocks']);
$found = false;
foreach ($result['blocks'] as $block) {
if ($block['name'] == 'myprofile') {
$this->assertEquals('side-pre', $block['region']);
$found = true;
continue;
}
// Check that the block is in the expected blocks array.
$this->assertContains($block['name'], $alldefaultblocks);
}
$this->assertTrue($found);
}
/**
* Test admin get user's custom dashboard blocks.
*/
public function test_get_dashboard_blocks_custom_user_dashboard(): void {
global $PAGE, $DB;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
$systempage = $DB->get_record('my_pages', array('userid' => null, 'name' => MY_PAGE_DEFAULT, 'private' => true));
// Get the expected default blocks.
$alldefaultblocks = $DB->get_records_menu(
'block_instances',
array('pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id),
'',
'id, blockname'
);
// Add a custom block.
$page = new \moodle_page();
$page->set_context(\context_user::instance($user->id));
$page->set_pagelayout('mydashboard');
$page->set_pagetype('my-index');
$page->blocks->add_region('content');
$currentpage = my_get_page($user->id, MY_PAGE_PRIVATE);
$page->set_subpage($currentpage->id);
$page->blocks->load_blocks();
$page->blocks->add_block('myprofile', 'content', 0, false);
$this->setAdminUser();
// Check for the new block as admin for a user.
$result = core_block_external::get_dashboard_blocks($user->id);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
// Expect all default blocks defined in blocks_add_default_system_blocks() plus the one we added.
$this->assertCount(count($alldefaultblocks) + 1, $result['blocks']);
$found = false;
foreach ($result['blocks'] as $block) {
if ($block['name'] == 'myprofile') {
$this->assertEquals('content', $block['region']);
$found = true;
continue;
}
// Check that the block is in the expected blocks array.
$this->assertContains($block['name'], $alldefaultblocks);
}
$this->assertTrue($found);
}
/**
* Test user tries to get other user blocks not having permission.
*/
public function test_get_dashboard_blocks_other_user_missing_permissions(): void {
$this->resetAfterTest(true);
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$this->setUser($user1);
$this->expectException('moodle_exception');
core_block_external::get_dashboard_blocks($user2->id);
}
/**
* Test user get default dashboard blocks for my courses page.
*/
public function test_get_dashboard_blocks_my_courses(): void {
global $PAGE, $DB;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
// Force a setting change to check the returned blocks settings.
set_config('displaycategories', 0, 'block_myoverview');
$systempage = $DB->get_record('my_pages', ['userid' => null, 'name' => MY_PAGE_COURSES, 'private' => false]);
// Get the expected default blocks.
$alldefaultblocksordered = $DB->get_records_menu(
'block_instances',
['pagetypepattern' => 'my-index', 'subpagepattern' => $systempage->id],
'defaultregion, defaultweight ASC',
'id, blockname'
);
$this->setUser($user);
// Check for the default blocks.
$result = core_block_external::get_dashboard_blocks($user->id, false, MY_PAGE_COURSES);
// We need to execute the return values cleaning process to simulate the web service server.
$result = \core_external\external_api::clean_returnvalue(core_block_external::get_dashboard_blocks_returns(), $result);
// Expect all default blocks defined in blocks_add_default_system_blocks().
$this->assertCount(count($alldefaultblocksordered), $result['blocks']);
$returnedblocks = [];
foreach ($result['blocks'] as $block) {
// Check all the returned blocks are in the expected blocks array.
$this->assertContains($block['name'], $alldefaultblocksordered);
$returnedblocks[] = $block['name'];
// Check the configuration returned for this default block.
if ($block['name'] == 'myoverview') {
// Convert config to associative array to avoid DB sorting randomness.
$config = array_column($block['configs'], null, 'name');
$this->assertArrayHasKey('displaycategories', $config);
$this->assertEquals(json_encode('0'), $config['displaycategories']['value']);
$this->assertEquals('plugin', $config['displaycategories']['type']);
}
}
// Check that we received the blocks in the expected order.
$this->assertEquals(array_values($alldefaultblocksordered), $returnedblocks);
}
/**
* Test user passing the wrong page type and getting an exception.
*/
public function test_get_dashboard_blocks_incorrect_page(): void {
global $PAGE;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
$this->setUser($user);
$this->expectException('moodle_exception');
// Check for the default blocks with a fake page, no need to assign as it'll throw.
core_block_external::get_dashboard_blocks($user->id, false, 'fakepage');
}
}
+437
View File
@@ -0,0 +1,437 @@
<?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/>.
/**
* Data provider tests.
*
* @package core_block
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_block\privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use core_block\privacy\provider;
/**
* Data provider testcase class.
*
* @package core_block
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
public function setUp(): void {
$this->resetAfterTest();
}
public function test_get_contexts_for_userid(): void {
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$u1ctx = \context_user::instance($u1->id);
$u2ctx = \context_user::instance($u2->id);
$manager = $this->get_block_manager(['region-a'], $c1ctx);
$manager->add_block('myprofile', 'region-a', 0, false);
$manager->load_blocks();
$blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
$manager = $this->get_block_manager(['region-a'], $c2ctx);
$manager->add_block('login', 'region-a', 0, false);
$manager->add_block('mentees', 'region-a', 1, false);
$manager->load_blocks();
list($blocklogin, $blockmentees) = $manager->get_blocks_for_region('region-a');
$manager = $this->get_block_manager(['region-a'], $u1ctx);
$manager->add_block('private_files', 'region-a', 0, false);
$manager->load_blocks();
$blockprivatefiles = $manager->get_blocks_for_region('region-a')[0];
$this->set_hidden_pref($blocklogin, true, $u1->id);
$this->set_hidden_pref($blockprivatefiles, true, $u1->id);
$this->set_docked_pref($blockmyprofile, true, $u1->id);
$this->set_docked_pref($blockmentees, true, $u1->id);
$this->set_docked_pref($blockmentees, true, $u2->id);
$contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
$this->assertCount(4, $contextids);
$this->assertTrue(in_array($blocklogin->context->id, $contextids));
$this->assertTrue(in_array($blockprivatefiles->context->id, $contextids));
$this->assertTrue(in_array($blockmyprofile->context->id, $contextids));
$this->assertTrue(in_array($blockmentees->context->id, $contextids));
$contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
$this->assertCount(1, $contextids);
$this->assertTrue(in_array($blockmentees->context->id, $contextids));
}
/**
* Test that user IDs are returned for a given context.
*/
public function test_get_users_in_context(): void {
global $DB;
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$manager = $this->get_block_manager(['region-a'], \context_course::instance($course->id));
$manager->add_block('myprofile', 'region-a', 0, false);
$manager->load_blocks();
$blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
$this->set_hidden_pref($blockmyprofile, true, $u1->id);
$this->set_hidden_pref($blockmyprofile, true, $u3->id);
$this->set_docked_pref($blockmyprofile, true, $u2->id);
$this->set_docked_pref($blockmyprofile, true, $u3->id);
$records = $DB->get_records('block_instances', ['blockname' => 'myprofile']);
$record = array_shift($records);
$blockcontext = \context_block::instance($record->id);
$userlist = new \core_privacy\local\request\userlist($blockcontext, 'core_block');
provider::get_users_in_context($userlist);
$this->assertCount(3, $userlist->get_userids());
}
public function test_delete_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$u1ctx = \context_user::instance($u1->id);
$u2ctx = \context_user::instance($u2->id);
$manager = $this->get_block_manager(['region-a'], $c1ctx);
$manager->add_block('myprofile', 'region-a', 0, false);
$manager->load_blocks();
$blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
$manager = $this->get_block_manager(['region-a'], $c2ctx);
$manager->add_block('login', 'region-a', 0, false);
$manager->add_block('mentees', 'region-a', 1, false);
$manager->load_blocks();
list($blocklogin, $blockmentees) = $manager->get_blocks_for_region('region-a');
$manager = $this->get_block_manager(['region-a'], $u1ctx);
$manager->add_block('private_files', 'region-a', 0, false);
$manager->load_blocks();
$blockprivatefiles = $manager->get_blocks_for_region('region-a')[0];
$this->set_hidden_pref($blocklogin, true, $u1->id);
$this->set_hidden_pref($blocklogin, true, $u2->id);
$this->set_hidden_pref($blockprivatefiles, true, $u1->id);
$this->set_hidden_pref($blockmyprofile, true, $u1->id);
$this->set_docked_pref($blockmyprofile, true, $u1->id);
$this->set_docked_pref($blockmentees, true, $u1->id);
$this->set_docked_pref($blockmentees, true, $u2->id);
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockprivatefiles->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockmyprofile->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
provider::delete_data_for_user(new approved_contextlist($u1, 'core_block', [$blocklogin->context->id,
$blockmyprofile->context->id, $blockmentees->context->id]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockprivatefiles->instance->id}hidden"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockmyprofile->instance->id}hidden"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
}
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$u1ctx = \context_user::instance($u1->id);
$u2ctx = \context_user::instance($u2->id);
$manager = $this->get_block_manager(['region-a'], $c1ctx);
$manager->add_block('myprofile', 'region-a', 0, false);
$manager->load_blocks();
$blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
$manager = $this->get_block_manager(['region-a'], $c2ctx);
$manager->add_block('login', 'region-a', 0, false);
$manager->add_block('mentees', 'region-a', 1, false);
$manager->load_blocks();
list($blocklogin, $blockmentees) = $manager->get_blocks_for_region('region-a');
$manager = $this->get_block_manager(['region-a'], $u1ctx);
$manager->add_block('private_files', 'region-a', 0, false);
$manager->load_blocks();
$blockprivatefiles = $manager->get_blocks_for_region('region-a')[0];
$this->set_hidden_pref($blocklogin, true, $u1->id);
$this->set_hidden_pref($blocklogin, true, $u2->id);
$this->set_hidden_pref($blockprivatefiles, true, $u1->id);
$this->set_hidden_pref($blockmyprofile, true, $u1->id);
$this->set_docked_pref($blockmyprofile, true, $u1->id);
$this->set_docked_pref($blockmentees, true, $u1->id);
$this->set_docked_pref($blockmentees, true, $u2->id);
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockprivatefiles->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockmyprofile->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
// Nothing happens.
provider::delete_data_for_all_users_in_context($c1ctx);
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockprivatefiles->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockmyprofile->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
// Delete one block.
provider::delete_data_for_all_users_in_context($blocklogin->context);
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockprivatefiles->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockmyprofile->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
// Delete another block.
provider::delete_data_for_all_users_in_context($blockmyprofile->context);
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "block{$blocklogin->instance->id}hidden"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockprivatefiles->instance->id}hidden"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "block{$blockmyprofile->instance->id}hidden"]));
$this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
$this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
}
/**
* Test the deletion of data related to a context and a list of users.
*/
public function test_delete_data_for_users(): void {
global $DB;
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$manager = $this->get_block_manager(['region-a'], \context_course::instance($course->id));
$manager->add_block('myprofile', 'region-a', 0, false);
$manager->load_blocks();
$blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
$this->set_hidden_pref($blockmyprofile, true, $u1->id);
$this->set_hidden_pref($blockmyprofile, true, $u3->id);
$this->set_docked_pref($blockmyprofile, true, $u2->id);
$this->set_docked_pref($blockmyprofile, true, $u3->id);
$records = $DB->get_records('block_instances', ['blockname' => 'myprofile']);
$record = array_shift($records);
$blockcontext = \context_block::instance($record->id);
$userlist = new \core_privacy\local\request\userlist($blockcontext, 'core_block');
provider::get_users_in_context($userlist);
$this->assertCount(3, $userlist->get_userids());
// Delete preferences for user 1 and 3 for the my profile block.
$userlist = new \core_privacy\local\request\approved_userlist($blockcontext, 'core_block', [$u1->id, $u3->id]);
provider::delete_data_for_users($userlist);
// Only user 2's preference is left.
$this->assertCount(1, $DB->get_records('user_preferences',
['name' => "docked_block_instance_{$blockcontext->instanceid}"]));
// All of these are gone.
$this->assertEmpty($DB->get_records('user_preferences',
['name' => "block{$blockcontext->instanceid}hidden"]));
}
public function test_export_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$u1ctx = \context_user::instance($u1->id);
$u2ctx = \context_user::instance($u2->id);
$yes = transform::yesno(true);
$no = transform::yesno(false);
$manager = $this->get_block_manager(['region-a'], $c1ctx);
$manager->add_block('myprofile', 'region-a', 0, false);
$manager->add_block('login', 'region-a', 1, false);
$manager->add_block('mentees', 'region-a', 2, false);
$manager->add_block('private_files', 'region-a', 3, false);
$manager->load_blocks();
list($bmyprofile, $blogin, $bmentees, $bprivatefiles) = $manager->get_blocks_for_region('region-a');
// Set some user preferences.
$this->set_hidden_pref($blogin, true, $u1->id);
$this->set_docked_pref($blogin, false, $u1->id);
$this->set_docked_pref($blogin, true, $u2->id);
$this->set_hidden_pref($bprivatefiles, false, $u1->id);
$this->set_docked_pref($bprivatefiles, true, $u2->id);
$this->set_docked_pref($bmyprofile, true, $u1->id);
$this->set_docked_pref($bmentees, true, $u2->id);
// Export data.
provider::export_user_data(new approved_contextlist($u1, 'core_block', [$bmyprofile->context->id, $blogin->context->id,
$bmentees->context->id, $bprivatefiles->context->id]));
$prefs = writer::with_context($bmentees->context)->get_user_context_preferences('core_block');
$this->assertEmpty((array) $prefs);
$prefs = writer::with_context($blogin->context)->get_user_context_preferences('core_block');
$this->assertEquals($no, $prefs->block_is_docked->value);
$this->assertEquals($yes, $prefs->block_is_hidden->value);
$prefs = writer::with_context($bprivatefiles->context)->get_user_context_preferences('core_block');
$this->assertObjectNotHasProperty('block_is_docked', $prefs);
$this->assertEquals($no, $prefs->block_is_hidden->value);
$prefs = writer::with_context($bmyprofile->context)->get_user_context_preferences('core_block');
$this->assertEquals($yes, $prefs->block_is_docked->value);
$this->assertObjectNotHasProperty('block_is_hidden', $prefs);
}
/**
* Get the block manager.
*
* @param array $regions The regions.
* @param \context $context The context.
* @param string $pagetype The page type.
* @param string $subpage The sub page.
* @return \block_manager
*/
protected function get_block_manager($regions, $context, $pagetype = 'page-type', $subpage = '') {
$page = new \moodle_page();
$page->set_context($context);
$page->set_pagetype($pagetype);
$page->set_subpage($subpage);
$page->set_url(new \moodle_url('/'));
$blockmanager = new \block_manager($page);
$blockmanager->add_regions($regions, false);
$blockmanager->set_default_region($regions[0]);
return $blockmanager;
}
/**
* Set a docked preference.
*
* @param \block_base $block The block.
* @param bool $value The value.
* @param int $userid The user ID.
*/
protected function set_docked_pref($block, $value, $userid) {
set_user_preference("docked_block_instance_{$block->instance->id}", $value, $userid);
}
/**
* Set a hidden preference.
*
* @param \block_base $block The block.
* @param bool $value The value.
* @param int $userid The user ID.
*/
protected function set_hidden_pref($block, $value, $userid) {
set_user_preference("block{$block->instance->id}hidden", $value, $userid);
}
}