Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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_course;
18
 
19
use core_course_category;
20
use core_course_list_element;
21
use course_capability_assignment;
22
 
23
defined('MOODLE_INTERNAL') || die();
24
 
25
global $CFG;
26
require_once($CFG->dirroot.'/course/lib.php');
27
require_once($CFG->dirroot.'/course/tests/fixtures/course_capability_assignment.php');
28
 
29
/**
30
 * Course and category management helper class tests.
31
 *
32
 * @package    core_course
33
 * @copyright  2013 Sam Hemelryk
34
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
class management_helper_test extends \advanced_testcase {
37
 
38
    /** Category management capability: moodle/category:manage */
39
    const CATEGORY_MANAGE = 'moodle/category:manage';
40
    /** View hidden category capability: moodle/category:viewhiddencategories */
41
    const CATEGORY_VIEWHIDDEN = 'moodle/category:viewhiddencategories';
42
    /** View course capability: moodle/course:visibility */
43
    const COURSE_VIEW = 'moodle/course:visibility';
44
    /** View hidden course capability: moodle/course:viewhiddencourses */
45
    const COURSE_VIEWHIDDEN = 'moodle/course:viewhiddencourses';
46
 
47
    /**
48
     * Returns a user object and its assigned new role.
49
     *
50
     * @param testing_data_generator $generator
51
     * @param $contextid
52
     * @return array The user object and the role ID
53
     */
54
    protected function get_user_objects(\testing_data_generator $generator, $contextid) {
55
        global $USER;
56
 
57
        if (empty($USER->id)) {
58
            $user  = $generator->create_user();
59
            $this->setUser($user);
60
        }
61
        $roleid = create_role('Test role', 'testrole', 'Test role description');
62
        if (!is_array($contextid)) {
63
            $contextid = array($contextid);
64
        }
65
        foreach ($contextid as $cid) {
66
            $assignid = role_assign($roleid, $user->id, $cid);
67
        }
68
        return array($user, $roleid);
69
    }
70
 
71
    /**
72
     * Tests:
73
     *   - action_category_hide
74
     *   - action_category_show
75
     *
76
     * In order to show/hide the user must have moodle/category:manage on the parent context.
77
     * In order to view hidden categories the user must have moodle/category:viewhiddencategories
78
     */
11 efrain 79
    public function test_action_category_hide_and_show(): void {
1 efrain 80
        global $DB;
81
        $this->resetAfterTest(true);
82
 
83
        $generator = $this->getDataGenerator();
84
        $category = $generator->create_category();
85
        $subcategory = $generator->create_category(array('parent' => $category->id));
86
        $course = $generator->create_course(array('category' => $subcategory->id));
87
        $context = $category->get_context();
88
        $subcontext = $subcategory->get_context();
89
        $parentcontext = $context->get_parent_context();
90
        list($user, $roleid) = $this->get_user_objects($generator, $parentcontext->id);
91
 
92
        $this->assertEquals(1, $category->visible);
93
 
94
        $parentassignment = course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $parentcontext->id);
95
        course_capability_assignment::allow(self::CATEGORY_VIEWHIDDEN, $roleid, $parentcontext->id);
96
        course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $context->id);
97
        course_capability_assignment::allow(array(self::COURSE_VIEW, self::COURSE_VIEWHIDDEN), $roleid, $subcontext->id);
98
 
99
        $this->assertTrue(\core_course\management\helper::action_category_hide($category));
100
        $cat = core_course_category::get($category->id);
101
        $subcat = core_course_category::get($subcategory->id);
102
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
103
        $this->assertEquals(0, $cat->visible);
104
        $this->assertEquals(0, $cat->visibleold);
105
        $this->assertEquals(0, $subcat->visible);
106
        $this->assertEquals(1, $subcat->visibleold);
107
        $this->assertEquals(0, $course->visible);
108
        $this->assertEquals(1, $course->visibleold);
109
        // This doesn't change anything but should succeed still.
110
        $this->assertTrue(\core_course\management\helper::action_category_hide($category));
111
        $cat = core_course_category::get($category->id);
112
        $subcat = core_course_category::get($subcategory->id);
113
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
114
        $this->assertEquals(0, $cat->visible);
115
        $this->assertEquals(0, $cat->visibleold);
116
        $this->assertEquals(0, $subcat->visible);
117
        $this->assertEquals(1, $subcat->visibleold);
118
        $this->assertEquals(0, $course->visible);
119
        $this->assertEquals(1, $course->visibleold);
120
 
121
        $this->assertTrue(\core_course\management\helper::action_category_show($category));
122
        $cat = core_course_category::get($category->id);
123
        $subcat = core_course_category::get($subcategory->id);
124
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
125
        $this->assertEquals(1, $cat->visible);
126
        $this->assertEquals(1, $cat->visibleold);
127
        $this->assertEquals(1, $subcat->visible);
128
        $this->assertEquals(1, $subcat->visibleold);
129
        $this->assertEquals(1, $course->visible);
130
        $this->assertEquals(1, $course->visibleold);
131
        // This doesn't change anything but should succeed still.
132
        $this->assertTrue(\core_course\management\helper::action_category_show($category));
133
        $cat = core_course_category::get($category->id);
134
        $subcat = core_course_category::get($subcategory->id);
135
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
136
        $this->assertEquals(1, $cat->visible);
137
        $this->assertEquals(1, $cat->visibleold);
138
        $this->assertEquals(1, $subcat->visible);
139
        $this->assertEquals(1, $subcat->visibleold);
140
        $this->assertEquals(1, $course->visible);
141
        $this->assertEquals(1, $course->visibleold);
142
 
143
        $parentassignment->assign(CAP_PROHIBIT);
144
 
145
        try {
146
            \core_course\management\helper::action_category_hide($category);
147
            $this->fail('Expected exception did not occur when trying to hide a category without permission.');
148
        } catch (\moodle_exception $ex) {
149
            // The category must still be visible.
150
            $cat = core_course_category::get($category->id);
151
            $subcat = core_course_category::get($subcategory->id);
152
            $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
153
            $this->assertEquals(1, $cat->visible);
154
            $this->assertEquals(1, $cat->visibleold);
155
            $this->assertEquals(1, $subcat->visible);
156
            $this->assertEquals(1, $subcat->visibleold);
157
            $this->assertEquals(1, $course->visible);
158
            $this->assertEquals(1, $course->visibleold);
159
        }
160
 
161
        // Hide the category so that we can test helper::show.
162
        $parentassignment->assign(CAP_ALLOW);
163
        \core_course\management\helper::action_category_hide($category);
164
        $cat = core_course_category::get($category->id);
165
        $subcat = core_course_category::get($subcategory->id);
166
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
167
        $this->assertEquals(0, $cat->visible);
168
        $this->assertEquals(0, $cat->visibleold);
169
        $this->assertEquals(0, $subcat->visible);
170
        $this->assertEquals(1, $subcat->visibleold);
171
        $this->assertEquals(0, $course->visible);
172
        $this->assertEquals(1, $course->visibleold);
173
 
174
        $parentassignment->assign(CAP_PROHIBIT);
175
 
176
        try {
177
            \core_course\management\helper::action_category_show($category);
178
            $this->fail('Expected exception did not occur when trying to show a category without permission.');
179
        } catch (\moodle_exception $ex) {
180
            // The category must still be hidden.
181
            $cat = core_course_category::get($category->id);
182
            $subcat = core_course_category::get($subcategory->id);
183
            $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
184
            $this->assertEquals(0, $cat->visible);
185
            $this->assertEquals(0, $cat->visibleold);
186
            $this->assertEquals(0, $subcat->visible);
187
            $this->assertEquals(1, $subcat->visibleold);
188
            $this->assertEquals(0, $course->visible);
189
            $this->assertEquals(1, $course->visibleold);
190
        }
191
 
192
        $parentassignment->assign(CAP_PREVENT);
193
        // Now we have capability on the category and subcategory but not the parent.
194
        // Try to mark the subcategory as visible. This should be possible although its parent is set to hidden.
195
        $this->assertTrue(\core_course\management\helper::action_category_show($subcategory));
196
        $cat = core_course_category::get($category->id);
197
        $subcat = core_course_category::get($subcategory->id);
198
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
199
        $this->assertEquals(0, $cat->visible);
200
        $this->assertEquals(0, $cat->visibleold);
201
        $this->assertEquals(0, $subcat->visible);
202
        $this->assertEquals(1, $subcat->visibleold);
203
        $this->assertEquals(0, $course->visible);
204
        $this->assertEquals(1, $course->visibleold);
205
 
206
        // Now make the parent visible for the next test.
207
        $parentassignment->assign(CAP_ALLOW);
208
        $this->assertTrue(\core_course\management\helper::action_category_show($category));
209
        $cat = core_course_category::get($category->id);
210
        $subcat = core_course_category::get($subcategory->id);
211
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
212
        $this->assertEquals(1, $cat->visible);
213
        $this->assertEquals(1, $cat->visibleold);
214
        $this->assertEquals(1, $subcat->visible);
215
        $this->assertEquals(1, $subcat->visibleold);
216
        $this->assertEquals(1, $course->visible);
217
        $this->assertEquals(1, $course->visibleold);
218
 
219
        $parentassignment->assign(CAP_PREVENT);
220
        // Make sure we can change the subcategory visibility.
221
        $this->assertTrue(\core_course\management\helper::action_category_hide($subcategory));
222
        // But not the category visibility.
223
        try {
224
            \core_course\management\helper::action_category_hide($category);
225
            $this->fail('Expected exception did not occur when trying to hide a category without permission.');
226
        } catch (\moodle_exception $ex) {
227
            // The category must still be visible.
228
            $this->assertEquals(1, core_course_category::get($category->id)->visible);
229
        }
230
    }
231
 
232
    /**
233
     * Tests hiding and showing of a category by its ID.
234
     *
235
     * This mimics the logic of {@link test_action_category_hide_and_show()}
236
     */
11 efrain 237
    public function test_action_category_hide_and_show_by_id(): void {
1 efrain 238
        global $DB;
239
        $this->resetAfterTest(true);
240
 
241
        $generator = $this->getDataGenerator();
242
        $category = $generator->create_category();
243
        $subcategory = $generator->create_category(array('parent' => $category->id));
244
        $course = $generator->create_course(array('category' => $subcategory->id));
245
        $context = $category->get_context();
246
        $parentcontext = $context->get_parent_context();
247
        $subcontext = $subcategory->get_context();
248
        list($user, $roleid) = $this->get_user_objects($generator, $parentcontext->id);
249
 
250
        $this->assertEquals(1, $category->visible);
251
 
252
        $parentassignment = course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $parentcontext->id);
253
        course_capability_assignment::allow(self::CATEGORY_VIEWHIDDEN, $roleid, $parentcontext->id);
254
        course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $context->id);
255
        course_capability_assignment::allow(array(self::COURSE_VIEW, self::COURSE_VIEWHIDDEN), $roleid, $subcontext->id);
256
 
257
        $this->assertTrue(\core_course\management\helper::action_category_hide_by_id($category->id));
258
        $cat = core_course_category::get($category->id);
259
        $subcat = core_course_category::get($subcategory->id);
260
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
261
        $this->assertEquals(0, $cat->visible);
262
        $this->assertEquals(0, $cat->visibleold);
263
        $this->assertEquals(0, $subcat->visible);
264
        $this->assertEquals(1, $subcat->visibleold);
265
        $this->assertEquals(0, $course->visible);
266
        $this->assertEquals(1, $course->visibleold);
267
        // This doesn't change anything but should succeed still.
268
        $this->assertTrue(\core_course\management\helper::action_category_hide_by_id($category->id));
269
        $cat = core_course_category::get($category->id);
270
        $subcat = core_course_category::get($subcategory->id);
271
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
272
        $this->assertEquals(0, $cat->visible);
273
        $this->assertEquals(0, $cat->visibleold);
274
        $this->assertEquals(0, $subcat->visible);
275
        $this->assertEquals(1, $subcat->visibleold);
276
        $this->assertEquals(0, $course->visible);
277
        $this->assertEquals(1, $course->visibleold);
278
 
279
        $this->assertTrue(\core_course\management\helper::action_category_show_by_id($category->id));
280
        $cat = core_course_category::get($category->id);
281
        $subcat = core_course_category::get($subcategory->id);
282
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
283
        $this->assertEquals(1, $cat->visible);
284
        $this->assertEquals(1, $cat->visibleold);
285
        $this->assertEquals(1, $subcat->visible);
286
        $this->assertEquals(1, $subcat->visibleold);
287
        $this->assertEquals(1, $course->visible);
288
        $this->assertEquals(1, $course->visibleold);
289
        // This doesn't change anything but should succeed still.
290
        $this->assertTrue(\core_course\management\helper::action_category_show_by_id($category->id));
291
        $cat = core_course_category::get($category->id);
292
        $subcat = core_course_category::get($subcategory->id);
293
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
294
        $this->assertEquals(1, $cat->visible);
295
        $this->assertEquals(1, $cat->visibleold);
296
        $this->assertEquals(1, $subcat->visible);
297
        $this->assertEquals(1, $subcat->visibleold);
298
        $this->assertEquals(1, $course->visible);
299
        $this->assertEquals(1, $course->visibleold);
300
 
301
        $parentassignment->assign(CAP_PROHIBIT);
302
 
303
        try {
304
            \core_course\management\helper::action_category_hide_by_id($category->id);
305
            $this->fail('Expected exception did not occur when trying to hide a category without permission.');
306
        } catch (\moodle_exception $ex) {
307
            // The category must still be visible.
308
            $cat = core_course_category::get($category->id);
309
            $subcat = core_course_category::get($subcategory->id);
310
            $this->assertEquals(1, $cat->visible);
311
            $this->assertEquals(1, $cat->visibleold);
312
            $this->assertEquals(1, $subcat->visible);
313
            $this->assertEquals(1, $subcat->visibleold);
314
            $this->assertEquals(1, $course->visible);
315
            $this->assertEquals(1, $course->visibleold);
316
        }
317
 
318
        // Hide the category so that we can test helper::show.
319
        $parentassignment->assign(CAP_ALLOW);
320
        \core_course\management\helper::action_category_hide_by_id($category->id);
321
        $cat = core_course_category::get($category->id);
322
        $subcat = core_course_category::get($subcategory->id);
323
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
324
        $this->assertEquals(0, $cat->visible);
325
        $this->assertEquals(0, $cat->visibleold);
326
        $this->assertEquals(0, $subcat->visible);
327
        $this->assertEquals(1, $subcat->visibleold);
328
        $this->assertEquals(0, $course->visible);
329
        $this->assertEquals(1, $course->visibleold);
330
 
331
        $parentassignment->assign(CAP_PROHIBIT);
332
 
333
        try {
334
            \core_course\management\helper::action_category_show_by_id($category->id);
335
            $this->fail('Expected exception did not occur when trying to show a category without permission.');
336
        } catch (\moodle_exception $ex) {
337
            // The category must still be hidden.
338
            $cat = core_course_category::get($category->id);
339
            $subcat = core_course_category::get($subcategory->id);
340
            $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
341
            $this->assertEquals(0, $cat->visible);
342
            $this->assertEquals(0, $cat->visibleold);
343
            $this->assertEquals(0, $subcat->visible);
344
            $this->assertEquals(1, $subcat->visibleold);
345
            $this->assertEquals(0, $course->visible);
346
            $this->assertEquals(1, $course->visibleold);
347
        }
348
 
349
        $parentassignment->assign(CAP_PREVENT);
350
        // Now we have capability on the category and subcategory but not the parent.
351
        // Try to mark the subcategory as visible. This should be possible although its parent is set to hidden.
352
        $this->assertTrue(\core_course\management\helper::action_category_show($subcategory));
353
        $cat = core_course_category::get($category->id);
354
        $subcat = core_course_category::get($subcategory->id);
355
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
356
        $this->assertEquals(0, $cat->visible);
357
        $this->assertEquals(0, $cat->visibleold);
358
        $this->assertEquals(0, $subcat->visible);
359
        $this->assertEquals(1, $subcat->visibleold);
360
        $this->assertEquals(0, $course->visible);
361
        $this->assertEquals(1, $course->visibleold);
362
 
363
        // Now make the parent visible for the next test.
364
        $parentassignment->assign(CAP_ALLOW);
365
        $this->assertTrue(\core_course\management\helper::action_category_show_by_id($category->id));
366
        $cat = core_course_category::get($category->id);
367
        $subcat = core_course_category::get($subcategory->id);
368
        $course = $DB->get_record('course', array('id' => $course->id), 'id, visible, visibleold', MUST_EXIST);
369
        $this->assertEquals(1, $cat->visible);
370
        $this->assertEquals(1, $cat->visibleold);
371
        $this->assertEquals(1, $subcat->visible);
372
        $this->assertEquals(1, $subcat->visibleold);
373
        $this->assertEquals(1, $course->visible);
374
        $this->assertEquals(1, $course->visibleold);
375
 
376
        $parentassignment->assign(CAP_PREVENT);
377
        // Make sure we can change the subcategory visibility.
378
        $this->assertTrue(\core_course\management\helper::action_category_hide($subcategory));
379
        // But not the category visibility.
380
        try {
381
            \core_course\management\helper::action_category_hide_by_id($category->id);
382
            $this->fail('Expected exception did not occur when trying to hide a category without permission.');
383
        } catch (\moodle_exception $ex) {
384
            // The category must still be visible.
385
            $this->assertEquals(1, core_course_category::get($category->id)->visible);
386
        }
387
    }
388
 
389
    /**
390
     * Test moving courses between categories.
391
     */
11 efrain 392
    public function test_action_category_move_courses_into(): void {
1 efrain 393
        global $DB, $CFG;
394
        $this->resetAfterTest(true);
395
 
396
        $generator = $this->getDataGenerator();
397
        $cat1 = $generator->create_category();
398
        $cat2 = $generator->create_category();
399
        $sub1 = $generator->create_category(array('parent' => $cat1->id));
400
        $sub2 = $generator->create_category(array('parent' => $cat1->id));
401
        $course1 = $generator->create_course(array('category' => $cat1->id));
402
        $course2 = $generator->create_course(array('category' => $sub1->id));
403
        $course3 = $generator->create_course(array('category' => $sub1->id));
404
        $course4 = $generator->create_course(array('category' => $cat2->id));
405
 
406
        $syscontext = \context_system::instance();
407
 
408
        list($user, $roleid) = $this->get_user_objects($generator, $syscontext->id);
409
 
410
        course_capability_assignment::allow(array(self::CATEGORY_MANAGE, self::CATEGORY_VIEWHIDDEN), $roleid, $syscontext->id);
411
 
412
        // Check they are where we think they are.
413
        $this->assertEquals(1, $cat1->get_courses_count());
414
        $this->assertEquals(1, $cat2->get_courses_count());
415
        $this->assertEquals(2, $sub1->get_courses_count());
416
        $this->assertEquals(0, $sub2->get_courses_count());
417
 
418
        // Move the courses in sub category 1 to sub category 2.
419
        $this->assertTrue(
420
            \core_course\management\helper::action_category_move_courses_into($sub1, $sub2, array($course2->id, $course3->id))
421
        );
422
 
423
        $this->assertEquals(1, $cat1->get_courses_count());
424
        $this->assertEquals(1, $cat2->get_courses_count());
425
        $this->assertEquals(0, $sub1->get_courses_count());
426
        $this->assertEquals(2, $sub2->get_courses_count());
427
 
428
        $courses = $DB->get_records('course', array('category' => $sub2->id), 'id');
429
        $this->assertEquals(array((int)$course2->id, (int)$course3->id), array_keys($courses));
430
 
431
        // Move the courses in sub category 2 back into to sub category 1.
432
        $this->assertTrue(
433
            \core_course\management\helper::action_category_move_courses_into($sub2, $sub1, array($course2->id, $course3->id))
434
        );
435
 
436
        $this->assertEquals(1, $cat1->get_courses_count());
437
        $this->assertEquals(1, $cat2->get_courses_count());
438
        $this->assertEquals(2, $sub1->get_courses_count());
439
        $this->assertEquals(0, $sub2->get_courses_count());
440
 
441
        $courses = $DB->get_records('course', array('category' => $sub1->id), 'id');
442
        $this->assertEquals(array((int)$course2->id, (int)$course3->id), array_keys($courses));
443
 
444
        // Try moving just one course.
445
        $this->assertTrue(
446
            \core_course\management\helper::action_category_move_courses_into($cat2, $sub2, array($course4->id))
447
        );
448
        $this->assertEquals(1, $cat1->get_courses_count());
449
        $this->assertEquals(0, $cat2->get_courses_count());
450
        $this->assertEquals(2, $sub1->get_courses_count());
451
        $this->assertEquals(1, $sub2->get_courses_count());
452
        $courses = $DB->get_records('course', array('category' => $sub2->id), 'id');
453
        $this->assertEquals(array((int)$course4->id), array_keys($courses));
454
 
455
        // Try moving a course from a category its not part of.
456
        try {
457
            \core_course\management\helper::action_category_move_courses_into($cat2, $sub2, array($course4->id));
458
            $this->fail('Moved a course from a category it wasn\'t within');
459
        } catch (\moodle_exception $exception) {
460
            // Check that everything is as it was.
461
            $this->assertEquals(1, $cat1->get_courses_count());
462
            $this->assertEquals(0, $cat2->get_courses_count());
463
            $this->assertEquals(2, $sub1->get_courses_count());
464
            $this->assertEquals(1, $sub2->get_courses_count());
465
        }
466
 
467
        // Now try that again with two courses, one of which is in the right place.
468
        try {
469
            \core_course\management\helper::action_category_move_courses_into($cat2, $sub2, array($course4->id, $course1->id));
470
            $this->fail('Moved a course from a category it wasn\'t within');
471
        } catch (\moodle_exception $exception) {
472
            // Check that everything is as it was. Nothing should have been moved.
473
            $this->assertEquals(1, $cat1->get_courses_count());
474
            $this->assertEquals(0, $cat2->get_courses_count());
475
            $this->assertEquals(2, $sub1->get_courses_count());
476
            $this->assertEquals(1, $sub2->get_courses_count());
477
        }
478
 
479
        // Current state:
480
        // * $cat1 => $course1
481
        //    * $sub1 => $course2, $course3
482
        //    * $sub2 => $course4
483
        // * $cat2 =>.
484
 
485
        // Prevent the user from being able to move into $sub2.
486
        $sub2cap = course_capability_assignment::prohibit(self::CATEGORY_MANAGE, $roleid, $sub2->get_context()->id);
487
        $sub2 = core_course_category::get($sub2->id);
488
        // Suppress debugging messages for a moment.
489
        $olddebug = $CFG->debug;
490
        $CFG->debug = 0;
491
 
492
        // Try to move a course into sub2. This shouldn't be possible because you should always be able to undo what you've done.
493
        // Try moving just one course.
494
        try {
495
            \core_course\management\helper::action_category_move_courses_into($sub1, $sub2, array($course2->id));
496
            $this->fail('Invalid move of course between categories, action can\'t be undone.');
497
        } catch (\moodle_exception $ex) {
498
            $this->assertEquals(get_string('cannotmovecourses', 'error'), $ex->getMessage());
499
        }
500
        // Nothing should have changed.
501
        $this->assertEquals(1, $cat1->get_courses_count());
502
        $this->assertEquals(0, $cat2->get_courses_count());
503
        $this->assertEquals(2, $sub1->get_courses_count());
504
        $this->assertEquals(1, $sub2->get_courses_count());
505
 
506
        // Now try moving a course out of sub2. Again should not be possible.
507
        // Try to move a course into sub2. This shouldn't be possible because you should always be able to undo what you've done.
508
        // Try moving just one course.
509
        try {
510
            \core_course\management\helper::action_category_move_courses_into($sub2, $cat2, array($course4->id));
511
            $this->fail('Invalid move of course between categories, action can\'t be undone.');
512
        } catch (\moodle_exception $ex) {
513
            $this->assertEquals(get_string('cannotmovecourses', 'error'), $ex->getMessage());
514
        }
515
        // Nothing should have changed.
516
        $this->assertEquals(1, $cat1->get_courses_count());
517
        $this->assertEquals(0, $cat2->get_courses_count());
518
        $this->assertEquals(2, $sub1->get_courses_count());
519
        $this->assertEquals(1, $sub2->get_courses_count());
520
 
521
        $CFG->debug = $olddebug;
522
    }
523
 
524
    /**
525
     * Test moving a categories up and down.
526
     */
11 efrain 527
    public function test_action_category_movedown_and_moveup(): void {
1 efrain 528
        global $DB;
529
        $this->resetAfterTest(true);
530
 
531
        $generator = $this->getDataGenerator();
532
        $parent = $generator->create_category();
533
        $cat1 = $generator->create_category(array('parent' => $parent->id, 'name' => 'One'));
534
        $cat2 = $generator->create_category(array('parent' => $parent->id, 'name' => 'Two'));
535
        $cat3 = $generator->create_category(array('parent' => $parent->id, 'name' => 'Three'));
536
 
537
        $syscontext = \context_system::instance();
538
        list($user, $roleid) = $this->get_user_objects($generator, $syscontext->id);
539
        course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $syscontext->id);
540
 
541
        // Check everything is where we expect it to be.
542
        $this->assertEquals(
543
            array('One', 'Two', 'Three'),
544
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
545
        );
546
 
547
        // Move the top category down one.
548
        $this->assertTrue(\core_course\management\helper::action_category_change_sortorder_down_one($cat1));
549
        // Reload out objects.
550
        $cat1 = core_course_category::get($cat1->id);
551
        $cat2 = core_course_category::get($cat2->id);
552
        $cat3 = core_course_category::get($cat3->id);
553
        // Verify that caches were cleared.
554
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat1->id)), $cat1->sortorder);
555
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat2->id)), $cat2->sortorder);
556
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat3->id)), $cat3->sortorder);
557
        // Verify sorting.
558
        $this->assertEquals(
559
            array('Two', 'One', 'Three'),
560
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
561
        );
562
 
563
        // Move the bottom category up one.
564
        $this->assertTrue(\core_course\management\helper::action_category_change_sortorder_up_one($cat3));
565
        // Reload out objects.
566
        $cat1 = core_course_category::get($cat1->id);
567
        $cat2 = core_course_category::get($cat2->id);
568
        $cat3 = core_course_category::get($cat3->id);
569
        // Verify that caches were cleared.
570
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat1->id)), $cat1->sortorder);
571
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat2->id)), $cat2->sortorder);
572
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat3->id)), $cat3->sortorder);
573
        // Verify sorting.
574
        $this->assertEquals(
575
            array('Two', 'Three', 'One'),
576
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
577
        );
578
 
579
        // Move the top category down one.
580
        $this->assertTrue(\core_course\management\helper::action_category_change_sortorder_down_one_by_id($cat2->id));
581
        $this->assertEquals(
582
            array('Three', 'Two', 'One'),
583
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
584
        );
585
 
586
        // Move the top category down one.
587
        $this->assertTrue(\core_course\management\helper::action_category_change_sortorder_up_one_by_id($cat1->id));
588
        $this->assertEquals(
589
            array('Three', 'One', 'Two'),
590
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
591
        );
592
 
593
        // Reload out objects the above actions will have caused the objects to become stale.
594
        $cat1 = core_course_category::get($cat1->id);
595
        $cat2 = core_course_category::get($cat2->id);
596
        $cat3 = core_course_category::get($cat3->id);
597
        // Verify that caches were cleared.
598
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat1->id)), $cat1->sortorder);
599
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat2->id)), $cat2->sortorder);
600
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat3->id)), $cat3->sortorder);
601
        // Verify sorting.
602
 
603
        // Test moving the top category up one. Nothing should change but it should return false.
604
        $this->assertFalse(\core_course\management\helper::action_category_change_sortorder_up_one($cat3));
605
        // Reload out objects.
606
        $cat1 = core_course_category::get($cat1->id);
607
        $cat2 = core_course_category::get($cat2->id);
608
        $cat3 = core_course_category::get($cat3->id);
609
        // Verify that caches were cleared.
610
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat1->id)), $cat1->sortorder);
611
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat2->id)), $cat2->sortorder);
612
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat3->id)), $cat3->sortorder);
613
        // Verify sorting.
614
        $this->assertEquals(
615
            array('Three', 'One', 'Two'),
616
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
617
        );
618
 
619
        // Test moving the bottom category down one. Nothing should change but it should return false.
620
        $this->assertFalse(\core_course\management\helper::action_category_change_sortorder_down_one($cat2));
621
        // Reload out objects.
622
        $cat1 = core_course_category::get($cat1->id);
623
        $cat2 = core_course_category::get($cat2->id);
624
        $cat3 = core_course_category::get($cat3->id);
625
        // Verify that caches were cleared.
626
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat1->id)), $cat1->sortorder);
627
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat2->id)), $cat2->sortorder);
628
        $this->assertEquals($DB->get_field('course_categories', 'sortorder', array('id' => $cat3->id)), $cat3->sortorder);
629
        // Verify sorting.
630
        $this->assertEquals(
631
            array('Three', 'One', 'Two'),
632
            array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
633
        );
634
 
635
        // Prevent moving on the parent.
636
        course_capability_assignment::prevent(self::CATEGORY_MANAGE, $roleid, $parent->get_context()->id);
637
        try {
638
            \core_course\management\helper::action_category_change_sortorder_up_one($cat1);
639
        } catch (\moodle_exception $exception) {
640
            // Check everything is still where it should be.
641
            $this->assertEquals(
642
                array('Three', 'One', 'Two'),
643
                array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
644
            );
645
        }
646
        try {
647
            \core_course\management\helper::action_category_change_sortorder_down_one($cat3);
648
        } catch (\moodle_exception $exception) {
649
            // Check everything is still where it should be.
650
            $this->assertEquals(
651
                array('Three', 'One', 'Two'),
652
                array_keys($DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder', 'name'))
653
            );
654
        }
655
    }
656
 
657
    /**
658
     * Test resorting of courses within a category.
659
     *
660
     * \core_course\management\helper::action_category_resort_courses
661
     */
11 efrain 662
    public function test_action_category_resort_courses(): void {
1 efrain 663
        global $DB;
664
        $this->resetAfterTest(true);
665
 
666
        $generator = $this->getDataGenerator();
667
        $category = $generator->create_category();
668
        $course1 = $generator->create_course(array('category' => $category->id, 'fullname' => 'Experimental Chemistry',
669
            'shortname' => 'Course A', 'idnumber' => '10001'));
670
        $course2 = $generator->create_course(array('category' => $category->id, 'fullname' => 'Learn to program: Jade',
671
            'shortname' => 'Beginning Jade', 'idnumber' => '10003'));
672
        $course3 = $generator->create_course(array('category' => $category->id, 'fullname' => 'Advanced algebra',
673
            'shortname' => 'Advanced algebra', 'idnumber' => '10002'));
674
        $syscontext = \context_system::instance();
675
 
676
        // Update category object from DB so the course count is correct.
677
        $category = core_course_category::get($category->id);
678
 
679
        list($user, $roleid) = $this->get_user_objects($generator, $syscontext->id);
680
        $caps = course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $syscontext->id);
681
 
682
        // Check that sort order in the DB matches what we've got in the cache.
683
        $courses = $category->get_courses();
684
        $this->assertIsArray($courses);
685
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
686
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
687
 
688
        // Resort by fullname.
689
        \core_course\management\helper::action_category_resort_courses($category, 'fullname');
690
        $courses = $category->get_courses();
691
        $this->assertIsArray($courses);
692
        $this->assertEquals(array($course3->id, $course1->id, $course2->id), array_keys($courses));
693
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
694
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
695
 
696
        // Resort by shortname.
697
        \core_course\management\helper::action_category_resort_courses($category, 'shortname');
698
        $courses = $category->get_courses();
699
        $this->assertIsArray($courses);
700
        $this->assertEquals(array($course3->id, $course2->id, $course1->id), array_keys($courses));
701
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
702
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
703
 
704
        // Resort by idnumber.
705
        \core_course\management\helper::action_category_resort_courses($category, 'idnumber');
706
        $courses = $category->get_courses();
707
        $this->assertIsArray($courses);
708
        $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
709
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
710
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
711
 
712
        // Try with a field that cannot be sorted on.
713
        try {
714
            \core_course\management\helper::action_category_resort_courses($category, 'category');
715
            $this->fail('Category courses resorted by invalid sort field.');
716
        } catch (\coding_exception $exception) {
717
            // Test things are as they were before.
718
            $courses = $category->get_courses();
719
            $this->assertIsArray($courses);
720
            $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
721
            $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
722
            $this->assertEquals(array_keys($dbcourses), array_keys($courses));
723
        }
724
 
725
        // Try with a completely bogus field.
726
        try {
727
            \core_course\management\helper::action_category_resort_courses($category, 'monkeys');
728
            $this->fail('Category courses resorted by completely ridiculous field.');
729
        } catch (\coding_exception $exception) {
730
            // Test things are as they were before.
731
            $courses = $category->get_courses();
732
            $this->assertIsArray($courses);
733
            $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
734
            $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
735
            $this->assertEquals(array_keys($dbcourses), array_keys($courses));
736
        }
737
 
738
        // Prohibit resorting.
739
        $caps->assign(CAP_PROHIBIT);
740
        // Refresh our coursecat object.
741
        $category = core_course_category::get($category->id);
742
 
743
        // We should no longer have permission to do this. Test it out!
744
        try {
745
            \core_course\management\helper::action_category_resort_courses($category, 'shortname');
746
            $this->fail('Courses sorted without having the required permission.');
747
        } catch (\moodle_exception $exception) {
748
            // Check its the right exception.
749
            $this->assertEquals('core_course_category::can_resort', $exception->debuginfo);
750
            // Test things are as they were before.
751
            $courses = $category->get_courses();
752
            $this->assertIsArray($courses);
753
            $this->assertEquals(array($course1->id, $course3->id, $course2->id), array_keys($courses));
754
            $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder');
755
            $this->assertEquals(array_keys($dbcourses), array_keys($courses));
756
        }
757
    }
758
 
759
    /**
760
     * Tests resorting sub categories of a course.
761
     *
762
     * \core_course\management\helper::action_category_resort_courses
763
     */
11 efrain 764
    public function test_action_category_resort_subcategories(): void {
1 efrain 765
        global $DB;
766
        $this->resetAfterTest(true);
767
 
768
        $generator = $this->getDataGenerator();
769
        $parent = $generator->create_category();
770
        $cat1 = $generator->create_category(array('parent' => $parent->id, 'name' => 'School of Science', 'idnumber' => '10001'));
771
        $cat2 = $generator->create_category(array('parent' => $parent->id, 'name' => 'School of Commerce', 'idnumber' => '10003'));
772
        $cat3 = $generator->create_category(array('parent' => $parent->id, 'name' => 'School of Arts', 'idnumber' => '10002'));
773
 
774
        $syscontext = \context_system::instance();
775
        list($user, $roleid) = $this->get_user_objects($generator, $syscontext->id);
776
        $caps = course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $syscontext->id);
777
 
778
        $categories = $parent->get_children();
779
        $this->assertIsArray($categories);
780
        $dbcategories = $DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder');
781
        $this->assertEquals(array_keys($dbcategories), array_keys($categories));
782
 
783
        // Test sorting by name.
784
        \core_course\management\helper::action_category_resort_subcategories($parent, 'name');
785
        $categories = $parent->get_children();
786
        $this->assertIsArray($categories);
787
        $this->assertEquals(array($cat3->id, $cat2->id, $cat1->id), array_keys($categories));
788
        $dbcategories = $DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder');
789
        $this->assertEquals(array_keys($dbcategories), array_keys($categories));
790
 
791
        // Test sorting by idnumber.
792
        \core_course\management\helper::action_category_resort_subcategories($parent, 'idnumber');
793
        $categories = $parent->get_children();
794
        $this->assertIsArray($categories);
795
        $this->assertEquals(array($cat1->id, $cat3->id, $cat2->id), array_keys($categories));
796
        $dbcategories = $DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder');
797
        $this->assertEquals(array_keys($dbcategories), array_keys($categories));
798
 
799
        // Try with an invalid field.
800
        try {
801
            \core_course\management\helper::action_category_resort_subcategories($parent, 'summary');
802
            $this->fail('Categories resorted by invalid field.');
803
        } catch (\coding_exception $exception) {
804
            // Check that nothing was changed.
805
            $categories = $parent->get_children();
806
            $this->assertIsArray($categories);
807
            $this->assertEquals(array($cat1->id, $cat3->id, $cat2->id), array_keys($categories));
808
            $dbcategories = $DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder');
809
            $this->assertEquals(array_keys($dbcategories), array_keys($categories));
810
        }
811
 
812
        // Try with a completely bogus field.
813
        try {
814
            \core_course\management\helper::action_category_resort_subcategories($parent, 'monkeys');
815
            $this->fail('Categories resorted by completely bogus field.');
816
        } catch (\coding_exception $exception) {
817
            // Check that nothing was changed.
818
            $categories = $parent->get_children();
819
            $this->assertIsArray($categories);
820
            $this->assertEquals(array($cat1->id, $cat3->id, $cat2->id), array_keys($categories));
821
            $dbcategories = $DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder');
822
            $this->assertEquals(array_keys($dbcategories), array_keys($categories));
823
        }
824
 
825
        // Test resorting the top level category (puke).
826
        $topcat = core_course_category::get(0);
827
        \core_course\management\helper::action_category_resort_subcategories($topcat, 'name');
828
        $categories = $topcat->get_children();
829
        $this->assertIsArray($categories);
830
        $dbcategories = $DB->get_records('course_categories', array('parent' => '0'), 'sortorder');
831
        $this->assertEquals(array_keys($dbcategories), array_keys($categories));
832
 
833
        // Prohibit resorting.
834
        $caps->assign(CAP_PROHIBIT);
835
        // Refresh our coursecat object.
836
        $parent = core_course_category::get($parent->id);
837
 
838
        // We should no longer have permission to do this. Test it out!
839
        try {
840
            \core_course\management\helper::action_category_resort_subcategories($parent, 'idnumber');
841
            $this->fail('Categories sorted without having the required permission.');
842
        } catch (\moodle_exception $exception) {
843
            // Check its the right exception.
844
            $this->assertEquals('core_course_category::can_resort', $exception->debuginfo);
845
            // Test things are as they were before.
846
            $categories = $parent->get_children();
847
            $this->assertIsArray($categories);
848
            $this->assertEquals(array($cat1->id, $cat3->id, $cat2->id), array_keys($categories));
849
            $dbcategories = $DB->get_records('course_categories', array('parent' => $parent->id), 'sortorder');
850
            $this->assertEquals(array_keys($dbcategories), array_keys($categories));
851
        }
852
    }
853
 
854
    /**
855
     * Test hiding and showing of a course.
856
     *
857
     * @see \core_course\management\helper::action_course_hide
858
     * @see \core_course\management\helper::action_course_show
859
     */
11 efrain 860
    public function test_action_course_hide_show(): void {
1 efrain 861
        $this->resetAfterTest(true);
862
 
863
        $generator = $this->getDataGenerator();
864
        $category = $generator->create_category();
865
        $course = $generator->create_course();
866
 
867
        $coursecontext = \context_course::instance($course->id);
868
 
869
        list($user, $roleid) = $this->get_user_objects($generator, $coursecontext->id);
870
        $caps = array(self::COURSE_VIEW, self::COURSE_VIEWHIDDEN);
871
        $assignment = course_capability_assignment::allow($caps, $roleid, $coursecontext->id);
872
 
873
        $course = new core_course_list_element(get_course($course->id));
874
 
875
        // Check it is set to what we think it is.
876
        $this->assertEquals('1', $course->visible);
877
        $this->assertEquals('1', $course->visibleold);
878
 
879
        // Test hiding the course.
880
        $this->assertTrue(\core_course\management\helper::action_course_hide($course));
881
        // Refresh the course.
882
        $course = new core_course_list_element(get_course($course->id));
883
        $this->assertEquals('0', $course->visible);
884
        $this->assertEquals('0', $course->visibleold);
885
 
886
        // Test hiding the course again.
887
        $this->assertTrue(\core_course\management\helper::action_course_hide($course));
888
        // Refresh the course.
889
        $course = new core_course_list_element(get_course($course->id));
890
        $this->assertEquals('0', $course->visible);
891
        $this->assertEquals('0', $course->visibleold);
892
 
893
        // Test showing the course.
894
        $this->assertTrue(\core_course\management\helper::action_course_show($course));
895
        // Refresh the course.
896
        $course = new core_course_list_element(get_course($course->id));
897
        $this->assertEquals('1', $course->visible);
898
        $this->assertEquals('1', $course->visibleold);
899
 
900
        // Test showing the course again. Shouldn't change anything.
901
        $this->assertTrue(\core_course\management\helper::action_course_show($course));
902
        // Refresh the course.
903
        $course = new core_course_list_element(get_course($course->id));
904
        $this->assertEquals('1', $course->visible);
905
        $this->assertEquals('1', $course->visibleold);
906
 
907
        // Revoke the permissions.
908
        $assignment->revoke();
909
        $course = new core_course_list_element(get_course($course->id));
910
 
911
        try {
912
            \core_course\management\helper::action_course_show($course);
913
        } catch (\moodle_exception $exception) {
914
            $this->assertEquals('core_course_list_element::can_change_visbility', $exception->debuginfo);
915
        }
916
    }
917
 
918
    /**
919
     * Test hiding and showing of a course.
920
     *
921
     * @see \core_course\management\helper::action_course_hide_by_record
922
     * @see \core_course\management\helper::action_course_show_by_record
923
     */
11 efrain 924
    public function test_action_course_hide_show_by_record(): void {
1 efrain 925
        $this->resetAfterTest(true);
926
 
927
        $generator = $this->getDataGenerator();
928
        $category = $generator->create_category();
929
        $course = $generator->create_course();
930
 
931
        $coursecontext = \context_course::instance($course->id);
932
 
933
        list($user, $roleid) = $this->get_user_objects($generator, $coursecontext->id);
934
        $caps = array(self::COURSE_VIEW, self::COURSE_VIEWHIDDEN);
935
        $assignment = course_capability_assignment::allow($caps, $roleid, $coursecontext->id);
936
 
937
        $course = get_course($course->id);
938
 
939
        // Check it is set to what we think it is.
940
        $this->assertEquals('1', $course->visible);
941
        $this->assertEquals('1', $course->visibleold);
942
 
943
        // Test hiding the course.
944
        $this->assertTrue(\core_course\management\helper::action_course_hide_by_record($course));
945
        // Refresh the course.
946
        $course = get_course($course->id);
947
        $this->assertEquals('0', $course->visible);
948
        $this->assertEquals('0', $course->visibleold);
949
 
950
        // Test hiding the course again. Shouldn't change anything.
951
        $this->assertTrue(\core_course\management\helper::action_course_hide_by_record($course));
952
        // Refresh the course.
953
        $course = get_course($course->id);
954
        $this->assertEquals('0', $course->visible);
955
        $this->assertEquals('0', $course->visibleold);
956
 
957
        // Test showing the course.
958
        $this->assertTrue(\core_course\management\helper::action_course_show_by_record($course));
959
        // Refresh the course.
960
        $course = get_course($course->id);
961
        $this->assertEquals('1', $course->visible);
962
        $this->assertEquals('1', $course->visibleold);
963
 
964
        // Test showing the course again. Shouldn't change anything.
965
        $this->assertTrue(\core_course\management\helper::action_course_show_by_record($course));
966
        // Refresh the course.
967
        $course = get_course($course->id);
968
        $this->assertEquals('1', $course->visible);
969
        $this->assertEquals('1', $course->visibleold);
970
 
971
        // Revoke the permissions.
972
        $assignment->revoke();
973
        $course = get_course($course->id);
974
 
975
        try {
976
            \core_course\management\helper::action_course_show_by_record($course);
977
        } catch (\moodle_exception $exception) {
978
            $this->assertEquals('core_course_list_element::can_change_visbility', $exception->debuginfo);
979
        }
980
    }
981
 
982
    /**
983
     * Tests moving a course up and down by one.
984
     */
11 efrain 985
    public function test_action_course_movedown_and_moveup(): void {
1 efrain 986
        global $DB;
987
 
988
        $this->resetAfterTest(true);
989
 
990
        $generator = $this->getDataGenerator();
991
        $category = $generator->create_category();
992
        $course3 = $generator->create_course(array('category' => $category->id));
993
        $course2 = $generator->create_course(array('category' => $category->id));
994
        $course1 = $generator->create_course(array('category' => $category->id));
995
        $context = $category->get_context();
996
 
997
        // Update category object from DB so the course count is correct.
998
        $category = core_course_category::get($category->id);
999
 
1000
        list($user, $roleid) = $this->get_user_objects($generator, $context->id);
1001
        $caps = course_capability_assignment::allow(self::CATEGORY_MANAGE, $roleid, $context->id);
1002
 
1003
        $courses = $category->get_courses();
1004
        $this->assertIsArray($courses);
1005
        $this->assertEquals(array($course1->id, $course2->id, $course3->id), array_keys($courses));
1006
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1007
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1008
 
1009
        // Move a course down.
1010
        $this->assertTrue(
1011
            \core_course\management\helper::action_course_change_sortorder_down_one(
1012
                new core_course_list_element(get_course($course1->id)), $category)
1013
        );
1014
        $courses = $category->get_courses();
1015
        $this->assertIsArray($courses);
1016
        $this->assertEquals(array($course2->id, $course1->id, $course3->id), array_keys($courses));
1017
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1018
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1019
 
1020
        // Move a course up.
1021
        $this->assertTrue(
1022
            \core_course\management\helper::action_course_change_sortorder_up_one(
1023
                new core_course_list_element(get_course($course3->id)), $category)
1024
        );
1025
        $courses = $category->get_courses();
1026
        $this->assertIsArray($courses);
1027
        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
1028
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1029
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1030
 
1031
        // Move a course down by record.
1032
        $this->assertTrue(
1033
            \core_course\management\helper::action_course_change_sortorder_down_one_by_record(get_course($course2->id), $category)
1034
        );
1035
        $courses = $category->get_courses();
1036
        $this->assertIsArray($courses);
1037
        $this->assertEquals(array($course3->id, $course2->id, $course1->id), array_keys($courses));
1038
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1039
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1040
 
1041
        // Move a course up by record.
1042
        $this->assertTrue(
1043
            \core_course\management\helper::action_course_change_sortorder_up_one_by_record(get_course($course2->id), $category)
1044
        );
1045
        $courses = $category->get_courses();
1046
        $this->assertIsArray($courses);
1047
        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
1048
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1049
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1050
 
1051
        // Try move the bottom course down. This should return false and nothing changes.
1052
        $this->assertFalse(
1053
            \core_course\management\helper::action_course_change_sortorder_down_one(
1054
                new core_course_list_element(get_course($course1->id)), $category)
1055
        );
1056
        $courses = $category->get_courses();
1057
        $this->assertIsArray($courses);
1058
        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
1059
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1060
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1061
 
1062
        // Try move the top course up. This should return false and nothing changes.
1063
        $this->assertFalse(
1064
            \core_course\management\helper::action_course_change_sortorder_up_one(
1065
                new core_course_list_element(get_course($course2->id)), $category)
1066
        );
1067
        $courses = $category->get_courses();
1068
        $this->assertIsArray($courses);
1069
        $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
1070
        $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1071
        $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1072
 
1073
        // Prohibit the ability to move.
1074
        $caps->assign(CAP_PROHIBIT);
1075
        // Reload the category.
1076
        $category = core_course_category::get($category->id);
1077
 
1078
        try {
1079
            \core_course\management\helper::action_course_change_sortorder_down_one(
1080
                new core_course_list_element(get_course($course2->id)), $category);
1081
            $this->fail('Course moved without having the required permissions.');
1082
        } catch (\moodle_exception $exception) {
1083
            // Check nothing has changed.
1084
            $courses = $category->get_courses();
1085
            $this->assertIsArray($courses);
1086
            $this->assertEquals(array($course2->id, $course3->id, $course1->id), array_keys($courses));
1087
            $dbcourses = $DB->get_records('course', array('category' => $category->id), 'sortorder', 'id');
1088
            $this->assertEquals(array_keys($dbcourses), array_keys($courses));
1089
        }
1090
    }
1091
 
1092
    /**
1093
     * Tests the fetching of actions for a category.
1094
     */
11 efrain 1095
    public function test_get_category_listitem_actions(): void {
1 efrain 1096
        global $PAGE;
1097
        $this->resetAfterTest(true);
1098
 
1099
        $PAGE->set_url(new \moodle_url('/course/management.php'));
1100
 
1101
        $generator = $this->getDataGenerator();
1102
        $category = $generator->create_category();
1103
        $context = \context_system::instance();
1104
        list($user, $roleid) = $this->get_user_objects($generator, $context->id);
1105
        course_capability_assignment::allow(array(
1106
            self::CATEGORY_MANAGE,
1107
            self::CATEGORY_VIEWHIDDEN,
1108
            'moodle/role:assign',
1109
            'moodle/cohort:view',
1110
            'moodle/filter:manage'
1111
        ), $roleid, $context->id);
1112
 
1113
        $actions = \core_course\management\helper::get_category_listitem_actions($category);
1114
        $this->assertIsArray($actions);
1115
        $this->assertArrayHasKey('edit', $actions);
1116
        $this->assertArrayHasKey('hide', $actions);
1117
        $this->assertArrayHasKey('show', $actions);
1118
        $this->assertArrayHasKey('moveup', $actions);
1119
        $this->assertArrayHasKey('movedown', $actions);
1120
        $this->assertArrayHasKey('delete', $actions);
1121
        $this->assertArrayHasKey('permissions', $actions);
1122
        $this->assertArrayHasKey('cohorts', $actions);
1123
        $this->assertArrayHasKey('filters', $actions);
1124
    }
1125
 
1126
    /**
1127
     * Tests fetching the course actions.
1128
     */
11 efrain 1129
    public function test_get_course_detail_actions(): void {
1 efrain 1130
        $this->resetAfterTest(true);
1131
 
1132
        $generator = $this->getDataGenerator();
1133
        $category = $generator->create_category();
1134
        $course = $generator->create_course();
1135
        $context = \context_system::instance();
1136
        list($user, $roleid) = $this->get_user_objects($generator, $context->id);
1137
        $generator->enrol_user($user->id, $course->id, $roleid);
1138
        course_capability_assignment::allow(array(
1139
            self::COURSE_VIEW,
1140
            self::COURSE_VIEWHIDDEN,
1141
            'moodle/course:update',
1142
            'moodle/course:enrolreview',
1143
            'moodle/course:delete',
1144
            'moodle/backup:backupcourse',
1145
            'moodle/restore:restorecourse'
1146
        ), $roleid, $context->id);
1147
 
1148
        $actions = \core_course\management\helper::get_course_detail_actions(new core_course_list_element($course));
1149
        $this->assertIsArray($actions);
1150
        $this->assertArrayHasKey('view', $actions);
1151
        $this->assertArrayHasKey('edit', $actions);
1152
        $this->assertArrayHasKey('enrolledusers', $actions);
1153
        $this->assertArrayHasKey('delete', $actions);
1154
        $this->assertArrayHasKey('hide', $actions);
1155
        $this->assertArrayHasKey('backup', $actions);
1156
        $this->assertArrayHasKey('restore', $actions);
1157
    }
1158
 
1159
    /**
1160
     * Test fetching course details.
1161
     */
11 efrain 1162
    public function test_get_course_detail_array(): void {
1 efrain 1163
        $this->resetAfterTest(true);
1164
 
1165
        $generator = $this->getDataGenerator();
1166
        $category = $generator->create_category();
1167
        $course = $generator->create_course();
1168
        $context = \context_system::instance();
1169
        list($user, $roleid) = $this->get_user_objects($generator, $context->id);
1170
        $generator->enrol_user($user->id, $course->id, $roleid);
1171
        course_capability_assignment::allow(array(
1172
            self::COURSE_VIEW,
1173
            self::COURSE_VIEWHIDDEN,
1174
            'moodle/course:update',
1175
            'moodle/course:enrolreview',
1176
            'moodle/course:delete',
1177
            'moodle/backup:backupcourse',
1178
            'moodle/restore:restorecourse',
1179
            'moodle/site:accessallgroups'
1180
        ), $roleid, $context->id);
1181
 
1182
        $details = \core_course\management\helper::get_course_detail_array(new core_course_list_element($course));
1183
        $this->assertIsArray($details);
1184
        $this->assertArrayHasKey('format', $details);
1185
        $this->assertArrayHasKey('fullname', $details);
1186
        $this->assertArrayHasKey('shortname', $details);
1187
        $this->assertArrayHasKey('idnumber', $details);
1188
        $this->assertArrayHasKey('category', $details);
1189
        $this->assertArrayHasKey('groupings', $details);
1190
        $this->assertArrayHasKey('groups', $details);
1191
        $this->assertArrayHasKey('roleassignments', $details);
1192
        $this->assertArrayHasKey('enrolmentmethods', $details);
1193
        $this->assertArrayHasKey('sections', $details);
1194
        $this->assertArrayHasKey('modulesused', $details);
1195
    }
1196
 
11 efrain 1197
    public function test_move_courses_into_category(): void {
1 efrain 1198
        global $DB, $CFG;
1199
        $this->resetAfterTest(true);
1200
 
1201
        $generator = $this->getDataGenerator();
1202
        $cat1 = $generator->create_category();
1203
        $cat2 = $generator->create_category();
1204
        $sub1 = $generator->create_category(array('parent' => $cat1->id));
1205
        $sub2 = $generator->create_category(array('parent' => $cat1->id));
1206
        $course1 = $generator->create_course(array('category' => $cat1->id));
1207
        $course2 = $generator->create_course(array('category' => $sub1->id));
1208
        $course3 = $generator->create_course(array('category' => $sub1->id));
1209
        $course4 = $generator->create_course(array('category' => $cat2->id));
1210
 
1211
        $syscontext = \context_system::instance();
1212
 
1213
        list($user, $roleid) = $this->get_user_objects($generator, $syscontext->id);
1214
 
1215
        course_capability_assignment::allow(array(self::CATEGORY_MANAGE, self::CATEGORY_VIEWHIDDEN), $roleid, $syscontext->id);
1216
 
1217
        // Check they are where we think they are.
1218
        $this->assertEquals(1, $cat1->get_courses_count());
1219
        $this->assertEquals(1, $cat2->get_courses_count());
1220
        $this->assertEquals(2, $sub1->get_courses_count());
1221
        $this->assertEquals(0, $sub2->get_courses_count());
1222
 
1223
        // Move the courses in sub category 1 to sub category 2.
1224
        $this->assertTrue(
1225
            \core_course\management\helper::move_courses_into_category($sub2->id, array($course2->id, $course3->id))
1226
        );
1227
 
1228
        $this->assertEquals(1, $cat1->get_courses_count());
1229
        $this->assertEquals(1, $cat2->get_courses_count());
1230
        $this->assertEquals(0, $sub1->get_courses_count());
1231
        $this->assertEquals(2, $sub2->get_courses_count());
1232
 
1233
        $courses = $DB->get_records('course', array('category' => $sub2->id), 'id');
1234
        $this->assertEquals(array((int)$course2->id, (int)$course3->id), array_keys($courses));
1235
 
1236
        // Move the courses in sub category 2 back into to sub category 1.
1237
        $this->assertTrue(
1238
            \core_course\management\helper::move_courses_into_category($sub1->id, array($course2->id, $course3->id))
1239
        );
1240
 
1241
        $this->assertEquals(1, $cat1->get_courses_count());
1242
        $this->assertEquals(1, $cat2->get_courses_count());
1243
        $this->assertEquals(2, $sub1->get_courses_count());
1244
        $this->assertEquals(0, $sub2->get_courses_count());
1245
 
1246
        $courses = $DB->get_records('course', array('category' => $sub1->id), 'id');
1247
        $this->assertEquals(array((int)$course2->id, (int)$course3->id), array_keys($courses));
1248
 
1249
        // Try moving just one course.
1250
        $this->assertTrue(
1251
            \core_course\management\helper::move_courses_into_category($sub2->id, $course4->id)
1252
        );
1253
        $this->assertEquals(1, $cat1->get_courses_count());
1254
        $this->assertEquals(0, $cat2->get_courses_count());
1255
        $this->assertEquals(2, $sub1->get_courses_count());
1256
        $this->assertEquals(1, $sub2->get_courses_count());
1257
        $courses = $DB->get_records('course', array('category' => $sub2->id), 'id');
1258
        $this->assertEquals(array((int)$course4->id), array_keys($courses));
1259
 
1260
        // Current state:
1261
        // * $cat1 => $course1
1262
        //    * $sub1 => $course2, $course3
1263
        //    * $sub2 => $course4
1264
        // * $cat2 =>.
1265
 
1266
        // Prevent the user from being able to move into $sub2.
1267
        $sub2cap = course_capability_assignment::prohibit(self::CATEGORY_MANAGE, $roleid, $sub2->get_context()->id);
1268
        $sub2 = core_course_category::get($sub2->id);
1269
        // Suppress debugging messages for a moment.
1270
        $olddebug = $CFG->debug;
1271
        $CFG->debug = 0;
1272
 
1273
        // Try to move a course into sub2. This shouldn't be possible because you should always be able to undo what you've done.
1274
        // Try moving just one course.
1275
        try {
1276
            \core_course\management\helper::move_courses_into_category($sub2->id, array($course2->id));
1277
            $this->fail('Invalid move of course between categories, action can\'t be undone.');
1278
        } catch (\moodle_exception $ex) {
1279
            $this->assertEquals(get_string('cannotmovecourses', 'error'), $ex->getMessage());
1280
        }
1281
        // Nothing should have changed.
1282
        $this->assertEquals(1, $cat1->get_courses_count());
1283
        $this->assertEquals(0, $cat2->get_courses_count());
1284
        $this->assertEquals(2, $sub1->get_courses_count());
1285
        $this->assertEquals(1, $sub2->get_courses_count());
1286
 
1287
        // Now try moving a course out of sub2. Again should not be possible.
1288
        // Try to move a course into sub2. This shouldn't be possible because you should always be able to undo what you've done.
1289
        // Try moving just one course.
1290
        try {
1291
            \core_course\management\helper::move_courses_into_category($cat2->id, array($course4->id));
1292
            $this->fail('Invalid move of course between categories, action can\'t be undone.');
1293
        } catch (\moodle_exception $ex) {
1294
            $this->assertEquals(get_string('cannotmovecourses', 'error'), $ex->getMessage());
1295
        }
1296
        // Nothing should have changed.
1297
        $this->assertEquals(1, $cat1->get_courses_count());
1298
        $this->assertEquals(0, $cat2->get_courses_count());
1299
        $this->assertEquals(2, $sub1->get_courses_count());
1300
        $this->assertEquals(1, $sub2->get_courses_count());
1301
 
1302
        $CFG->debug = $olddebug;
1303
    }
1304
 
1305
}