MDL-53566 core: Add support for context locking
[moodle.git] / lib / tests / accesslib_has_capability_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * A collection of tests for accesslib::has_capability().
19  *
20  * @package    core
21  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 /**
28  * Unit tests tests for has_capability.
29  *
30  * @package    core
31  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
32  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33  */
34 class accesslib_has_capability_testcase extends \advanced_testcase {
36     /**
37      * Unit tests to check the operation of locked contexts.
38      *
39      * Note: We only check the admin user here.
40      * If the admin cannot do it, then no-one can.
41      *
42      * @dataProvider locked_context_provider
43      * @param   string[]    $lockedcontexts The list of contexts, by name, to mark as locked
44      * @param   string[]    $blocked The list of contexts which will be 'blocked' by has_capability
45      */
46     public function test_locked_contexts($lockedcontexts, $blocked) {
47         global $DB;
49         $this->resetAfterTest();
50         set_config('contextlocking', 1);
52         $generator = $this->getDataGenerator();
53         $otheruser = $generator->create_user();
55         // / (system)
56         // /Cat1
57         // /Cat1/Block
58         // /Cat1/Course1
59         // /Cat1/Course1/Block
60         // /Cat1/Course2
61         // /Cat1/Course2/Block
62         // /Cat1/Cat1a
63         // /Cat1/Cat1a/Block
64         // /Cat1/Cat1a/Course1
65         // /Cat1/Cat1a/Course1/Block
66         // /Cat1/Cat1a/Course2
67         // /Cat1/Cat1a/Course2/Block
68         // /Cat1/Cat1b
69         // /Cat1/Cat1b/Block
70         // /Cat1/Cat1b/Course1
71         // /Cat1/Cat1b/Course1/Block
72         // /Cat1/Cat1b/Course2
73         // /Cat1/Cat1b/Course2/Block
74         // /Cat2
75         // /Cat2/Block
76         // /Cat2/Course1
77         // /Cat2/Course1/Block
78         // /Cat2/Course2
79         // /Cat2/Course2/Block
80         // /Cat2/Cat2a
81         // /Cat2/Cat2a/Block
82         // /Cat2/Cat2a/Course1
83         // /Cat2/Cat2a/Course1/Block
84         // /Cat2/Cat2a/Course2
85         // /Cat2/Cat2a/Course2/Block
86         // /Cat2/Cat2b
87         // /Cat2/Cat2b/Block
88         // /Cat2/Cat2b/Course1
89         // /Cat2/Cat2b/Course1/Block
90         // /Cat2/Cat2b/Course2
91         // /Cat2/Cat2b/Course2/Block
93         $adminuser = \core_user::get_user_by_username('admin');
94         $contexts = (object) [
95             'system' => \context_system::instance(),
96             'adminuser' => \context_user::instance($adminuser->id),
97         ];
99         $cat1 = $generator->create_category();
100         $cat1a = $generator->create_category(['parent' => $cat1->id]);
101         $cat1b = $generator->create_category(['parent' => $cat1->id]);
103         $contexts->cat1 = \context_coursecat::instance($cat1->id);
104         $contexts->cat1a = \context_coursecat::instance($cat1a->id);
105         $contexts->cat1b = \context_coursecat::instance($cat1b->id);
107         $cat1course1 = $generator->create_course(['category' => $cat1->id]);
108         $cat1course2 = $generator->create_course(['category' => $cat1->id]);
109         $cat1acourse1 = $generator->create_course(['category' => $cat1a->id]);
110         $cat1acourse2 = $generator->create_course(['category' => $cat1a->id]);
111         $cat1bcourse1 = $generator->create_course(['category' => $cat1b->id]);
112         $cat1bcourse2 = $generator->create_course(['category' => $cat1b->id]);
114         $contexts->cat1course1 = \context_course::instance($cat1course1->id);
115         $contexts->cat1acourse1 = \context_course::instance($cat1acourse1->id);
116         $contexts->cat1bcourse1 = \context_course::instance($cat1bcourse1->id);
117         $contexts->cat1course2 = \context_course::instance($cat1course2->id);
118         $contexts->cat1acourse2 = \context_course::instance($cat1acourse2->id);
119         $contexts->cat1bcourse2 = \context_course::instance($cat1bcourse2->id);
121         $cat1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1->id]);
122         $cat1ablock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1a->id]);
123         $cat1bblock = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1b->id]);
124         $cat1course1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course1->id]);
125         $cat1course2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1course2->id]);
126         $cat1acourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse1->id]);
127         $cat1acourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1acourse2->id]);
128         $cat1bcourse1block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse1->id]);
129         $cat1bcourse2block = $generator->create_block('online_users', ['parentcontextid' => $contexts->cat1bcourse2->id]);
131         $contexts->cat1block = \context_block::instance($cat1block->id);
132         $contexts->cat1ablock = \context_block::instance($cat1ablock->id);
133         $contexts->cat1bblock = \context_block::instance($cat1bblock->id);
134         $contexts->cat1course1block = \context_block::instance($cat1course1block->id);
135         $contexts->cat1course2block = \context_block::instance($cat1course2block->id);
136         $contexts->cat1acourse1block = \context_block::instance($cat1acourse1block->id);
137         $contexts->cat1acourse2block = \context_block::instance($cat1acourse2block->id);
138         $contexts->cat1bcourse1block = \context_block::instance($cat1bcourse1block->id);
139         $contexts->cat1bcourse2block = \context_block::instance($cat1bcourse2block->id);
141         $writecapability = 'moodle/block:edit';
142         $readcapability = 'moodle/block:view';
143         $managecapability = 'moodle/site:managecontextlocks';
145         $this->setAdminUser();
146         $totest = (array) $contexts;
147         foreach ($totest as $context) {
148             $this->assertTrue(has_capability($writecapability, $context));
149             $this->assertTrue(has_capability($readcapability, $context));
150             $this->assertTrue(has_capability($managecapability, $context));
151         }
153         // Lock the specified contexts.
154         foreach ($lockedcontexts as $contextname => $value) {
155             $contexts->$contextname->set_locked($value);
156         }
158         // All read capabilities should remain.
159         foreach ((array) $contexts as $context) {
160             $this->assertTrue(has_capability($readcapability, $context));
161             $this->assertTrue(has_capability($managecapability, $context));
162         }
164         // Check writes.
165         foreach ((array) $contexts as $contextname => $context) {
166             if (false !== array_search($contextname, $blocked)) {
167                 $this->assertFalse(has_capability($writecapability, $context));
168             } else {
169                 $this->assertTrue(has_capability($writecapability, $context));
170             }
171         }
173         $this->setUser($otheruser);
174         // Check writes.
175         foreach ((array) $contexts as $contextname => $context) {
176             $this->assertFalse(has_capability($writecapability, $context));
177         }
179         // Disable the contextlocking experimental feature.
180         set_config('contextlocking', 0);
182         $this->setAdminUser();
183         // All read capabilities should remain.
184         foreach ((array) $contexts as $context) {
185             $this->assertTrue(has_capability($readcapability, $context));
186             $this->assertTrue(has_capability($managecapability, $context));
187         }
189         // All write capabilities should now be present again.
190         foreach ((array) $contexts as $contextname => $context) {
191             $this->assertTrue(has_capability($writecapability, $context));
192         }
194         $this->setUser($otheruser);
195         // Check writes.
196         foreach ((array) $contexts as $contextname => $context) {
197             $this->assertFalse(has_capability($writecapability, $context));
198         }
199     }
201     /**
202      * Data provider for testing that has_capability() deals with locked contexts.
203      *
204      * @return  array
205      */
206     public function locked_context_provider() {
207         return [
208             'All unlocked' => [
209                 'locked' => [
210                 ],
211                 'blockedwrites' => [
212                 ],
213             ],
214             'User is locked (yes, this is weird)' => [
215                 'locked' => [
216                     'adminuser' => true,
217                 ],
218                 'blockedwrites' => [
219                     'adminuser',
220                 ],
221             ],
222             'Cat1/Block locked' => [
223                 'locked' => [
224                     'cat1block' => true,
225                 ],
226                 'blockedwrites' => [
227                     'cat1block',
228                 ],
229             ],
230             'Cat1' => [
231                 'locked' => [
232                     'cat1' => true,
233                 ],
234                 'blockedwrites' => [
235                     'cat1',
236                     'cat1block',
237                     'cat1a',
238                     'cat1ablock',
239                     'cat1b',
240                     'cat1bblock',
241                     'cat1course1',
242                     'cat1course1block',
243                     'cat1course2',
244                     'cat1course2block',
245                     'cat1acourse1',
246                     'cat1acourse1block',
247                     'cat1acourse2',
248                     'cat1acourse2block',
249                     'cat1bcourse1',
250                     'cat1bcourse1block',
251                     'cat1bcourse2',
252                     'cat1bcourse2block',
253                 ],
254             ],
255             'Cat1 locked and a child explicitly unlocked' => [
256                 'locked' => [
257                     'cat1' => true,
258                     'cat1a' => false,
259                 ],
260                 'blockedwrites' => [
261                     'cat1',
262                     'cat1block',
263                     'cat1a',
264                     'cat1ablock',
265                     'cat1b',
266                     'cat1bblock',
267                     'cat1course1',
268                     'cat1course1block',
269                     'cat1course2',
270                     'cat1course2block',
271                     'cat1acourse1',
272                     'cat1acourse1block',
273                     'cat1acourse2',
274                     'cat1acourse2block',
275                     'cat1bcourse1',
276                     'cat1bcourse1block',
277                     'cat1bcourse2',
278                     'cat1bcourse2block',
279                 ],
280             ],
281         ];
282     }