Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion classes/condition.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class condition extends \core_availability\condition {
public function __construct($structure) {
$this->userids = [];
if (isset($structure->userids)) {
$this->userids = $structure->userids;
$this->userids = (array)$structure->userids;
}
// Ensure compatibility with old version.
if (isset($structure->userid)) {
Expand Down
77 changes: 58 additions & 19 deletions tests/availability_user_condition_testcase.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,36 @@
/**
* Testcase for availability_user
*/
class availability_user_condition_testcase extends \advanced_testcase {
/** @var \core_availability\mock_info */
protected \core_availability\mock_info $info;
/** @var \core_availability\capability_checker */
protected \core_availability\capability_checker $capabilitychecker;
/** @var condition A condition using the old structure (single userid) */
protected condition $cond;
/** @var condition A condition using the new structure (multiple userids) */
protected condition $newcond;
/** @var condition A condition using multiple userids */
protected condition $multiplecond;
/** @var \stdClass */
protected \stdClass $user1;
/** @var \stdClass */
protected \stdClass $user2;
/** @var \stdClass */
protected \stdClass $user3;
/** @var \stdClass */
protected \stdClass $user4;
class availability_user_condition_testcase extends advanced_testcase {
/** @var $info */
protected $info;

/** @var $capabilitychecker */
protected $capabilitychecker;

/** @var $user1 */
protected $user1;

/** @var $user2 */
protected $user2;

/** @var $user3 */
protected $user3;

/** @var $user4 */
protected $user4;

/** @var $cond */
protected $cond;

/** @var $newcond */
protected $newcond;

/** @var $multiplecond */
protected $multiplecond;

/** @var $emptycond */
protected $emptycond;

/**
* Load necessary libs
Expand Down Expand Up @@ -96,6 +107,10 @@ public function setUp(): void {
$multiplestructure = new \stdClass();
$multiplestructure->userids = [$this->user1->id, $this->user2->id, $this->user3->id];
$this->multiplecond = new condition($multiplestructure);

$emptystructure = new stdClass();
$emptystructure->userids = [];
$this->emptycond = new condition($emptystructure);
}

/**
Expand Down Expand Up @@ -291,4 +306,28 @@ public function test_users_multiple_filter_not() {
$this->assertFalse(in_array($this->user3->id, $filtereduserids));
$this->assertTrue(in_array($this->user4->id, $filtereduserids));
}

/**
* Check availability logic when no users are selected.
*
* @return void
*/
public function test_empty_user_list_availability() {
global $USER;
$this->setUser($this->user1);
$this->assertFalse($this->emptycond->is_available(false, $this->info, true, $USER->id));
$this->assertTrue($this->emptycond->is_available(true, $this->info, true, $USER->id));
}

/**
* Ensure full description does not fail when no users are selected.
*
* @return void
*/
public function test_empty_user_list_full_description() {
$this->assertEquals(
get_string('requires_certain_user', 'availability_user'),
$this->emptycond->get_description(true, false, $this->info)
);
}
}
92 changes: 92 additions & 0 deletions tests/behat/availability_user.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
@availability @availability_user
Feature: availability_user
In order to control student access to activities
As a teacher
I need to set user conditions which prevent student access

Background:
Given the following "courses" exist:
| fullname | shortname | format | numsections |
| Course 1 | C1 | topics | 3 |
And the following "users" exist:
| username | firstname | lastname |
| teacher1 | Teacher | One |
| student1 | Alice | Smith |
| student2 | Bob | Jones |
| student3 | Carol | White |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
And the following "activities" exist:
| activity | course | name |
| page | C1 | P1 |

@javascript
Scenario: Restricting access to a single user works correctly
Given I am on the "P1" "page activity editing" page logged in as "teacher1"
And I expand all fieldsets
And I click on "Add restriction..." "button"
And I click on "#availability_addrestriction_user" "css_element"
And I set the field "availability_user_userids" to "Alice Smith"
And I click on ".availability-item .availability-eye img" "css_element"
And I click on "Save and return to course" "button"

# student1 (Alice) should see P1, others should not.
When I am on the "Course 1" "course" page logged in as "student1"
Then I should see "P1" in the "region-main" "region"

When I am on the "Course 1" "course" page logged in as "student2"
Then I should not see "P1" in the "region-main" "region"

@javascript
Scenario: Selecting all users via Ctrl+A saves all of them correctly
# Regression test: Ctrl+A on the multi-select was broken because the plugin
# listened to 'click' (never fired for keyboard selection) and fillValue used
# a broken YUI chain get('options').get('_nodes') returning array-of-arrays.
Given I am on the "P1" "page activity editing" page logged in as "teacher1"
And I expand all fieldsets
And I click on "Add restriction..." "button"
And I click on "#availability_addrestriction_user" "css_element"
# Click the first option to give the select keyboard focus, then Ctrl+A.
And I click on "Alice Smith" "option" in the "#availability_user_userids" "css_element"
And I press the ctrl a key
And I click on ".availability-item .availability-eye img" "css_element"
And I click on "Save and return to course" "button"

# All three students must be allowed — none should be excluded.
When I am on the "Course 1" "course" page logged in as "student1"
Then I should see "P1" in the "region-main" "region"

When I am on the "Course 1" "course" page logged in as "student2"
Then I should see "P1" in the "region-main" "region"

When I am on the "Course 1" "course" page logged in as "student3"
Then I should see "P1" in the "region-main" "region"

# Re-open and verify all three names are still selected (save/load round-trip).
When I am on the "P1" "page activity editing" page logged in as "teacher1"
And I expand all fieldsets
Then the field "availability_user_userids" matches value "Bob Jones, Teacher One, Alice Smith, Carol White"

@javascript
Scenario: Selecting a subset of users saves the correct subset
Given I am on the "P1" "page activity editing" page logged in as "teacher1"
And I expand all fieldsets
And I click on "Add restriction..." "button"
And I click on "#availability_addrestriction_user" "css_element"
And I set the field "availability_user_userids" to "Alice Smith, Bob Jones"
And I click on ".availability-item .availability-eye img" "css_element"
And I click on "Save and return to course" "button"

# Alice and Bob can see P1; Carol cannot.
When I am on the "Course 1" "course" page logged in as "student1"
Then I should see "P1" in the "region-main" "region"

When I am on the "Course 1" "course" page logged in as "student2"
Then I should see "P1" in the "region-main" "region"

When I am on the "Course 1" "course" page logged in as "student3"
Then I should not see "P1" in the "region-main" "region"
4 changes: 2 additions & 2 deletions version.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();

$plugin->component = 'availability_user';
$plugin->release = '0.2.2';
$plugin->version = 2024082101;
$plugin->release = '0.4.0';
$plugin->version = 2026050600;
$plugin->requires = 2020061500;
$plugin->maturity = MATURITY_STABLE;
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ M.availability_user.form.getNode = function(json) {
if (!M.availability_user.form.addedEvents) {
M.availability_user.form.addedEvents = true;
var root = Y.one('#fitem_id_availabilityconditionsjson');
root.delegate('click', function() {
root.delegate('change', function() {
M.core_availability.form.update();
}, '.availability_user select');
}
Expand All @@ -50,14 +50,13 @@ M.availability_user.form.getNode = function(json) {
};

M.availability_user.form.fillValue = function(value, node) {
var userSelect = node.one('#availability_user_userids');
var options = userSelect.get('options').get('_nodes');
var users = [];
options.forEach(function(o) {
if (o.get('selected')) {
users.push(o.get('value'));
var options = node.getDOMNode().querySelectorAll('select option');
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
users.push(options[i].value);
}
});
}
value.userids = users;
};

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ M.availability_user.form.getNode = function(json) {
if (!M.availability_user.form.addedEvents) {
M.availability_user.form.addedEvents = true;
var root = Y.one('#fitem_id_availabilityconditionsjson');
root.delegate('click', function() {
root.delegate('change', function() {
M.core_availability.form.update();
}, '.availability_user select');
}
Expand All @@ -50,14 +50,13 @@ M.availability_user.form.getNode = function(json) {
};

M.availability_user.form.fillValue = function(value, node) {
var userSelect = node.one('#availability_user_userids');
var options = userSelect.get('options').get('_nodes');
var users = [];
options.forEach(function(o) {
if (o.get('selected')) {
users.push(o.get('value'));
var options = node.getDOMNode().querySelectorAll('select option');
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
users.push(options[i].value);
}
});
}
value.userids = users;
};

Expand Down
13 changes: 6 additions & 7 deletions yui/src/form/js/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ M.availability_user.form.getNode = function(json) {
if (!M.availability_user.form.addedEvents) {
M.availability_user.form.addedEvents = true;
var root = Y.one('#fitem_id_availabilityconditionsjson');
root.delegate('click', function() {
root.delegate('change', function() {
M.core_availability.form.update();
}, '.availability_user select');
}
Expand All @@ -48,13 +48,12 @@ M.availability_user.form.getNode = function(json) {
};

M.availability_user.form.fillValue = function(value, node) {
var userSelect = node.one('#availability_user_userids');
var options = userSelect.get('options').get('_nodes');
var users = [];
options.forEach(function(o) {
if (o.get('selected')) {
users.push(o.get('value'));
var options = node.getDOMNode().querySelectorAll('select option');
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
users.push(options[i].value);
}
});
}
value.userids = users;
};