Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 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/>.
16
 
17
namespace core\session;
18
 
19
use core\context\course as context_course;
20
use core\context\system as context_system;
21
 
22
/**
23
 * Unit tests for loginas_helper class.
24
 *
25
 * @package core
26
 * @author Jason den Dulk <jasondendulk@catalyst-au.net>
27
 * @covers \core\session\loginas_helper
28
 * @copyright 2025 Catalyst IT
29
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30
 */
31
final class loginas_helper_test extends \advanced_testcase {
32
    /**
33
     * Tests various users wanting to login as other users of the same role.
34
     */
35
    public function test_loginas_same_role(): void {
36
        global $CFG, $DB;
37
 
38
        $this->resetAfterTest();
39
 
40
        $managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
41
 
42
        $user1 = $this->getDataGenerator()->create_user();
43
        $user2 = $this->getDataGenerator()->create_user();
44
 
45
        // By default, users cannot login as other users.
46
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user1, $user2));
47
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user2, $user1));
48
 
49
        // Admins can login as other admins.
50
        $originalsiteadmins = $CFG->siteadmins;
51
        $CFG->siteadmins .= ',' . $user1->id . ',' . $user2->id;
52
        $systemcontext = context_system::instance();
53
        $this->assertEquals($systemcontext, loginas_helper::get_context_user_can_login_as($user1, $user2));
54
        $this->assertEquals($systemcontext, loginas_helper::get_context_user_can_login_as($user2, $user1));
55
 
56
        // Managers can login as other managers.
57
        $user1 = $this->getDataGenerator()->create_user();
58
        $user2 = $this->getDataGenerator()->create_user();
59
        role_assign($managerrole, $user1->id, $systemcontext->id);
60
        role_assign($managerrole, $user2->id, $systemcontext->id);
61
 
62
        $this->assertEquals($systemcontext, loginas_helper::get_context_user_can_login_as($user1, $user2));
63
        $this->assertEquals($systemcontext, loginas_helper::get_context_user_can_login_as($user2, $user1));
64
 
65
        // Course managers can login as other course managers, but only in the course context.
66
        $user1 = $this->getDataGenerator()->create_user();
67
        $user2 = $this->getDataGenerator()->create_user();
68
 
69
        $course = $this->getDataGenerator()->create_course();
70
        $coursecontext = context_course::instance($course->id);
71
        $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'manager');
72
        $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'manager');
73
 
74
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user1, $user2));
75
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user2, $user1));
76
 
77
        $this->assertEquals($coursecontext, loginas_helper::get_context_user_can_login_as($user1, $user2, $course));
78
        $this->assertEquals($coursecontext, loginas_helper::get_context_user_can_login_as($user2, $user1, $course));
79
 
80
        // Students cannot login as another student.
81
        $user1 = $this->getDataGenerator()->create_user();
82
        $user2 = $this->getDataGenerator()->create_user();
83
 
84
        $course = $this->getDataGenerator()->create_course();
85
        $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
86
        $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
87
 
88
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user1, $user2));
89
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user2, $user1));
90
 
91
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user1, $user2, $course));
92
        $this->assertNull(loginas_helper::get_context_user_can_login_as($user2, $user1, $course));
93
    }
94
 
95
    /**
96
     * Tests trying to login as a deleted user.
97
     */
98
    public function test_loginas_deleted_user(): void {
99
        global $USER;
100
 
101
        $this->resetAfterTest();
102
        $this->setAdminUser();
103
 
104
        // Sanity check that ordinary login as works.
105
        $user = $this->getDataGenerator()->create_user();
106
        $this->assertEquals(context_system::instance(), loginas_helper::get_context_user_can_login_as($USER, $user));
107
 
108
        // Cannot login as a user that has been deleted.
109
        $user = $this->getDataGenerator()->create_user(['deleted' => true]);
110
        $this->assertNull(loginas_helper::get_context_user_can_login_as($USER, $user));
111
    }
112
 
113
    /**
114
     * Tests various users wanting to login as other users of differing roles.
115
     */
116
    public function test_loginas_different_roles(): void {
117
        global $CFG, $DB;
118
 
119
        $this->resetAfterTest();
120
 
121
        $systemcontext = context_system::instance();
122
        $managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
123
        $originalsiteadmins = $CFG->siteadmins;
124
 
125
        $users = [];
126
        for ($i = 0; $i < 11; ++$i) {
127
            $users[] = $this->getDataGenerator()->create_user();
128
        }
129
 
130
        $courses = [
131
            $this->getDataGenerator()->create_course(),
132
            $this->getDataGenerator()->create_course(),
133
        ];
134
        $coursecontexts = [
135
            context_course::instance($courses[0]->id),
136
            context_course::instance($courses[1]->id),
137
        ];
138
 
139
        // User 0 is an admin.
140
        $CFG->siteadmins .= ',' . $users[0]->id;
141
 
142
        // User 1 is a manager.
143
        role_assign($managerrole, $users[1]->id, $systemcontext->id);
144
 
145
        // User 2 is a manager and an admin.
146
        $CFG->siteadmins .= ',' . $users[2]->id;
147
        role_assign($managerrole, $users[2]->id, $systemcontext->id);
148
 
149
        // User 3 is a course manager for course 0.
150
        $this->getDataGenerator()->enrol_user($users[3]->id, $courses[0]->id, 'manager');
151
 
152
        // User 4 is a course manager for course 0 and a site manager.
153
        $this->getDataGenerator()->enrol_user($users[4]->id, $courses[0]->id, 'manager');
154
        role_assign($managerrole, $users[4]->id, $systemcontext->id);
155
 
156
        // User 5 is a course manager for course 0 and an admin.
157
        $this->getDataGenerator()->enrol_user($users[5]->id, $courses[0]->id, 'manager');
158
        $CFG->siteadmins .= ',' . $users[5]->id;
159
 
160
        // User 6 is a student for course 0.
161
        $this->getDataGenerator()->enrol_user($users[6]->id, $courses[0]->id, 'student');
162
 
163
        // User 7 is a student for course 0 and an admin.
164
        $this->getDataGenerator()->enrol_user($users[7]->id, $courses[0]->id, 'student');
165
        $CFG->siteadmins .= ',' . $users[7]->id;
166
 
167
        // User 8 is a course manager for course 1.
168
        $this->getDataGenerator()->enrol_user($users[8]->id, $courses[1]->id, 'manager');
169
 
170
        // User 9 is a student for course 1.
171
        $this->getDataGenerator()->enrol_user($users[9]->id, $courses[1]->id, 'student');
172
 
173
        // User 10 is a user without courses or roles.
174
 
175
        // This matrix defines loginas expectations. 'S' = system context. # = course context. 'X' = nothing.
176
        $matrix = [
177
            // ... 0    1    2    3    4    5    6    7    8    9    10.
178
 
179
            1 => ['X', 'X', 'X', 'S', 'S', 'X', 'S', 'X', 'S', 'S', 'S'],
180
            2 => ['S', 'S', 'X', 'S', 'S', 'S', 'S', 'S', 'S', 'S', 'S'],
181
            3 => ['X', 'X', 'X', 'X', 'X', 'X', '0', 'X', 'X', 'X', 'X'],
182
            4 => ['X', 'S', 'X', 'S', 'X', 'X', 'S', 'X', 'S', 'S', 'S'],
183
            5 => ['S', 'S', 'S', 'S', 'S', 'X', 'S', 'S', 'S', 'S', 'S'],
184
            6 => ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'],
185
            7 => ['S', 'S', 'S', 'S', 'S', 'S', 'S', 'X', 'S', 'S', 'S'],
186
            8 => ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '1', 'X'],
187
            9 => ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'],
188
            10 => ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'],
189
        ];
190
 
191
        // Now test each user against each other user, and compare the results to the expectation matrix.
192
        foreach ($users as $uid => $user) {
193
            foreach ($users as $oid => $other) {
194
                $resultsnocourse = loginas_helper::get_context_user_can_login_as($user, $other);
195
                $resultscourse0 = loginas_helper::get_context_user_can_login_as($user, $other, $courses[0]);
196
                $resultscourse1 = loginas_helper::get_context_user_can_login_as($user, $other, $courses[1]);
197
 
198
                switch ($matrix[$uid][$oid]) {
199
                    case 'X':
200
                        // No loginas is possible.
201
                        $this->assertNull($resultsnocourse);
202
                        $this->assertNull($resultscourse0);
203
                        $this->assertNull($resultscourse1);
204
                        break;
205
                    case 'S':
206
                        // Loginas can happen at the site level.
207
                        $this->assertEquals($systemcontext, $resultsnocourse);
208
                        $this->assertEquals($systemcontext, $resultscourse0);
209
                        $this->assertEquals($systemcontext, $resultscourse1);
210
                        break;
211
                    case '0':
212
                        // Loginas can only happen within the context of course 0.
213
                        $this->assertNull($resultsnocourse);
214
                        $this->assertEquals($coursecontexts[0], $resultscourse0);
215
                        $this->assertNull($resultscourse1);
216
                        break;
217
                    case '1':
218
                        // Loginas can only happen within the context of course 1.
219
                        $this->assertNull($resultsnocourse);
220
                        $this->assertNull($resultscourse0);
221
                        $this->assertEquals($coursecontexts[1], $resultscourse1);
222
                        break;
223
                }
224
            }
225
        }
226
    }
227
 
228
    /**
229
     * Providor function for test_loginas_groups().
230
     *
231
     * @return array[]
232
     */
233
    public static function loginas_groups_providor(): array {
234
        return [
235
            'Separate groups' => [
236
                'groupmode' => SEPARATEGROUPS,
237
                'accessallgroups' => true,
238
                'canloginassamegroup' => true,
239
                'canloginasdifferentgroup' => true,
240
            ],
241
            'Separate groups, no access' => [
242
                'groupmode' => SEPARATEGROUPS,
243
                'accessallgroups' => false,
244
                'canloginassamegroup' => true,
245
                'canloginasdifferentgroup' => false,
246
            ],
247
            'Visible groups' => [
248
                'groupmode' => VISIBLEGROUPS,
249
                'accessallgroups' => true,
250
                'canloginassamegroup' => true,
251
                'canloginasdifferentgroup' => true,
252
            ],
253
            'Visible groups, no access' => [
254
                'groupmode' => VISIBLEGROUPS,
255
                'accessallgroups' => false,
256
                'canloginassamegroup' => true,
257
                'canloginasdifferentgroup' => true,
258
            ],
259
        ];
260
    }
261
 
262
    /**
263
     * Tests users wanting to login as other users of different groups.
264
     *
265
     * @param int $groupmode
266
     * @param bool $accessallgroups
267
     * @param bool $canloginassamegroup
268
     * @param bool $canloginasdifferentgroup
269
     *
270
     * @dataProvider loginas_groups_providor
271
     */
272
    public function test_loginas_groups(
273
        int $groupmode,
274
        bool $accessallgroups,
275
        bool $canloginassamegroup,
276
        bool $canloginasdifferentgroup
277
    ): void {
278
        global $DB;
279
 
280
        $this->resetAfterTest();
281
 
282
        // Set up manager and students.
283
        $manager = $this->getDataGenerator()->create_user();
284
        $student1 = $this->getDataGenerator()->create_user();
285
        $student2 = $this->getDataGenerator()->create_user();
286
 
287
        $course = $this->getDataGenerator()->create_course(['groupmode' => $groupmode]);
288
        $coursecontext = context_course::instance($course->id);
289
 
290
        // Add or remove accessallgroups permission.
291
        $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager'], MUST_EXIST);
292
        $permission = $accessallgroups ? CAP_ALLOW : CAP_PREVENT;
293
        assign_capability('moodle/site:accessallgroups', $permission, $managerroleid, $coursecontext, true);
294
 
295
        $this->getDataGenerator()->enrol_user($manager->id, $course->id, 'manager');
296
        $this->getDataGenerator()->enrol_user($student1->id, $course->id, 'student');
297
        $this->getDataGenerator()->enrol_user($student2->id, $course->id, 'student');
298
 
299
        // Manager and student 1 are in the same group. Student 2 is in a different group.
300
        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
301
        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
302
 
303
        $this->getDataGenerator()->create_group_member(['groupid' => $group1->id, 'userid' => $manager->id]);
304
        $this->getDataGenerator()->create_group_member(['groupid' => $group1->id, 'userid' => $student1->id]);
305
        $this->getDataGenerator()->create_group_member(['groupid' => $group2->id, 'userid' => $student2->id]);
306
 
307
        // Manager wants to login as a student in the same group.
308
        $this->assertEquals(
309
            $canloginassamegroup,
310
            (bool) loginas_helper::get_context_user_can_login_as($manager, $student1, $course)
311
        );
312
        // Manager wants to login as a student in a different group.
313
        $this->assertEquals(
314
            $canloginasdifferentgroup,
315
            (bool) loginas_helper::get_context_user_can_login_as($manager, $student2, $course)
316
        );
317
    }
318
}