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_cohort;
18
 
19
use core_cohort_external;
20
use core_external\external_api;
21
use externallib_advanced_testcase;
22
use core_cohort\customfield\cohort_handler;
23
 
24
defined('MOODLE_INTERNAL') || die();
25
 
26
global $CFG;
27
 
28
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
29
require_once($CFG->dirroot . '/cohort/externallib.php');
30
 
31
/**
32
 * External cohort API
33
 *
34
 * @package    core_cohort
35
 * @category   external
36
 * @copyright  MediaTouch 2000 srl
37
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38
 */
39
class externallib_test extends externallib_advanced_testcase {
40
 
41
    /**
42
     * Create cohort custom fields for testing.
43
     */
44
    protected function create_custom_fields(): void {
45
        $fieldcategory = self::getDataGenerator()->create_custom_field_category([
46
            'component' => 'core_cohort',
47
            'area' => 'cohort',
48
            'name' => 'Other fields',
49
        ]);
50
        self::getDataGenerator()->create_custom_field([
51
            'shortname' => 'testfield1',
52
            'name' => 'Custom field',
53
            'type' => 'text',
54
            'categoryid' => $fieldcategory->get('id'),
55
        ]);
56
        self::getDataGenerator()->create_custom_field([
57
            'shortname' => 'testfield2',
58
            'name' => 'Custom field',
59
            'type' => 'text',
60
            'categoryid' => $fieldcategory->get('id'),
61
        ]);
62
    }
63
 
64
    /**
65
     * Test create_cohorts
66
     */
11 efrain 67
    public function test_create_cohorts(): void {
1 efrain 68
        global $DB;
69
 
70
        $this->resetAfterTest(true);
71
 
72
        set_config('allowcohortthemes', 1);
73
 
74
        $contextid = \context_system::instance()->id;
75
        $category = $this->getDataGenerator()->create_category();
76
 
77
        // Custom fields.
78
        $this->create_custom_fields();
79
 
80
        $cohort1 = array(
81
            'categorytype' => array('type' => 'id', 'value' => $category->id),
82
            'name' => 'cohort test 1',
83
            'idnumber' => 'cohorttest1',
84
            'description' => 'This is a description for cohorttest1',
85
            'theme' => 'classic'
86
            );
87
 
88
        $cohort2 = array(
89
            'categorytype' => array('type' => 'system', 'value' => ''),
90
            'name' => 'cohort test 2',
91
            'idnumber' => 'cohorttest2',
92
            'description' => 'This is a description for cohorttest2',
93
            'visible' => 0
94
            );
95
 
96
        $cohort3 = array(
97
            'categorytype' => array('type' => 'id', 'value' => $category->id),
98
            'name' => 'cohort test 3',
99
            'idnumber' => 'cohorttest3',
100
            'description' => 'This is a description for cohorttest3'
101
            );
102
        $roleid = $this->assignUserCapability('moodle/cohort:manage', $contextid);
103
 
104
        $cohort4 = array(
105
            'categorytype' => array('type' => 'id', 'value' => $category->id),
106
            'name' => 'cohort test 4',
107
            'idnumber' => 'cohorttest4',
108
            'description' => 'This is a description for cohorttest4',
109
            'theme' => 'classic'
110
            );
111
 
112
        $cohort5 = array(
113
            'categorytype' => array('type' => 'id', 'value' => $category->id),
114
            'name' => 'cohort test 5 (with custom fields)',
115
            'idnumber' => 'cohorttest5',
116
            'description' => 'This is a description for cohorttest5',
117
            'customfields' => array(
118
                array(
119
                    'shortname' => 'testfield1',
120
                    'value' => 'Test value 1',
121
                ),
122
                array(
123
                    'shortname' => 'testfield2',
124
                    'value' => 'Test value 2',
125
                ),
126
            ),
127
        );
128
 
129
        // Call the external function.
130
        $this->setCurrentTimeStart();
131
        $createdcohorts = core_cohort_external::create_cohorts(array($cohort1, $cohort2));
132
        $createdcohorts = external_api::clean_returnvalue(core_cohort_external::create_cohorts_returns(), $createdcohorts);
133
 
134
        // Check we retrieve the good total number of created cohorts + no error on capability.
135
        $this->assertEquals(2, count($createdcohorts));
136
 
137
        foreach ($createdcohorts as $createdcohort) {
138
            $dbcohort = $DB->get_record('cohort', array('id' => $createdcohort['id']));
139
            if ($createdcohort['idnumber'] == $cohort1['idnumber']) {
140
                $conid = $DB->get_field('context', 'id', array('instanceid' => $cohort1['categorytype']['value'],
141
                        'contextlevel' => CONTEXT_COURSECAT));
142
                $this->assertEquals($dbcohort->contextid, $conid);
143
                $this->assertEquals($dbcohort->name, $cohort1['name']);
144
                $this->assertEquals($dbcohort->description, $cohort1['description']);
145
                $this->assertEquals($dbcohort->visible, 1); // Field was not specified, ensure it is visible by default.
146
                // As $CFG->allowcohortthemes is enabled, theme must be initialised.
147
                $this->assertEquals($dbcohort->theme, $cohort1['theme']);
148
            } else if ($createdcohort['idnumber'] == $cohort2['idnumber']) {
149
                $this->assertEquals($dbcohort->contextid, \context_system::instance()->id);
150
                $this->assertEquals($dbcohort->name, $cohort2['name']);
151
                $this->assertEquals($dbcohort->description, $cohort2['description']);
152
                $this->assertEquals($dbcohort->visible, $cohort2['visible']);
153
                // Although $CFG->allowcohortthemes is enabled, no theme is defined for this cohort.
154
                $this->assertEquals($dbcohort->theme, '');
155
            } else {
156
                $this->fail('Unrecognised cohort found');
157
            }
158
            $this->assertTimeCurrent($dbcohort->timecreated);
159
            $this->assertTimeCurrent($dbcohort->timemodified);
160
        }
161
 
162
        $createdcohorts = core_cohort_external::create_cohorts(array($cohort5));
163
        $createdcohorts = external_api::clean_returnvalue(core_cohort_external::create_cohorts_returns(), $createdcohorts);
164
 
165
        $this->assertCount(1, $createdcohorts);
166
        $createdcohort = reset($createdcohorts);
167
        $dbcohort = $DB->get_record('cohort', array('id' => $createdcohort['id']));
168
        $this->assertEquals($cohort5['name'], $dbcohort->name);
169
        $this->assertEquals($cohort5['description'], $dbcohort->description);
170
        $this->assertEquals(1, $dbcohort->visible);
171
        $this->assertEquals('', $dbcohort->theme);
172
 
173
        $data = cohort_handler::create()->export_instance_data_object($createdcohort['id'], true);
174
        $this->assertEquals('Test value 1', $data->testfield1);
175
        $this->assertEquals('Test value 2', $data->testfield2);
176
 
177
        // Call when $CFG->allowcohortthemes is disabled.
178
        set_config('allowcohortthemes', 0);
179
        $createdcohorts = core_cohort_external::create_cohorts(array($cohort4));
180
        $createdcohorts = external_api::clean_returnvalue(core_cohort_external::create_cohorts_returns(), $createdcohorts);
181
        foreach ($createdcohorts as $createdcohort) {
182
            $dbcohort = $DB->get_record('cohort', array('id' => $createdcohort['id']));
183
            if ($createdcohort['idnumber'] == $cohort4['idnumber']) {
184
                $conid = $DB->get_field('context', 'id', array('instanceid' => $cohort4['categorytype']['value'],
185
                        'contextlevel' => CONTEXT_COURSECAT));
186
                $this->assertEquals($dbcohort->contextid, $conid);
187
                $this->assertEquals($dbcohort->name, $cohort4['name']);
188
                $this->assertEquals($dbcohort->description, $cohort4['description']);
189
                $this->assertEquals($dbcohort->visible, 1); // Field was not specified, ensure it is visible by default.
190
                $this->assertEquals($dbcohort->theme, ''); // As $CFG->allowcohortthemes is disabled, theme must be empty.
191
            }
192
        }
193
 
194
        // Call without required capability.
195
        $this->unassignUserCapability('moodle/cohort:manage', $contextid, $roleid);
196
        $this->expectException(\required_capability_exception::class);
197
        $createdcohorts = core_cohort_external::create_cohorts(array($cohort3));
198
    }
199
 
200
    /**
201
     * Test delete_cohorts
202
     */
11 efrain 203
    public function test_delete_cohorts(): void {
1 efrain 204
        global $USER, $CFG, $DB;
205
 
206
        $this->resetAfterTest(true);
207
 
208
        $cohort1 = self::getDataGenerator()->create_cohort();
209
        $cohort2 = self::getDataGenerator()->create_cohort();
210
        // Check the cohorts were correctly created.
211
        $this->assertEquals(2, $DB->count_records_select('cohort', ' (id = :cohortid1 OR id = :cohortid2)',
212
                array('cohortid1' => $cohort1->id, 'cohortid2' => $cohort2->id)));
213
 
214
        $contextid = $cohort1->contextid;
215
        $roleid = $this->assignUserCapability('moodle/cohort:manage', $contextid);
216
 
217
        // Call the external function.
218
        core_cohort_external::delete_cohorts(array($cohort1->id, $cohort2->id));
219
 
220
        // Check we retrieve no cohorts + no error on capability.
221
        $this->assertEquals(0, $DB->count_records_select('cohort', ' (id = :cohortid1 OR id = :cohortid2)',
222
                array('cohortid1' => $cohort1->id, 'cohortid2' => $cohort2->id)));
223
 
224
        // Call without required capability.
225
        $cohort1 = self::getDataGenerator()->create_cohort();
226
        $cohort2 = self::getDataGenerator()->create_cohort();
227
        $this->unassignUserCapability('moodle/cohort:manage', $contextid, $roleid);
228
        $this->expectException(\required_capability_exception::class);
229
        core_cohort_external::delete_cohorts(array($cohort1->id, $cohort2->id));
230
    }
231
 
232
    /**
233
     * Test get_cohorts
234
     */
11 efrain 235
    public function test_get_cohorts(): void {
1 efrain 236
        $this->resetAfterTest(true);
237
 
238
        // Custom fields.
239
        $this->create_custom_fields();
240
 
241
        set_config('allowcohortthemes', 1);
242
 
243
        $cohort1 = array(
244
            'contextid' => 1,
245
            'name' => 'cohortnametest1',
246
            'idnumber' => 'idnumbertest1',
247
            'description' => 'This is a description for cohort 1',
248
            'theme' => 'classic',
249
            'customfield_testfield1' => 'Test value 1',
250
            'customfield_testfield2' => 'Test value 2',
251
        );
252
 
253
        // We need a site admin to be able to populate cohorts custom fields.
254
        $this->setAdminUser();
255
 
256
        $cohort1 = self::getDataGenerator()->create_cohort($cohort1);
257
        $cohort2 = self::getDataGenerator()->create_cohort();
258
 
259
        $context = \context_system::instance();
260
        $roleid = $this->assignUserCapability('moodle/cohort:view', $context->id);
261
 
262
        // Call the external function.
263
        $returnedcohorts = core_cohort_external::get_cohorts(array(
264
            $cohort1->id, $cohort2->id));
265
        $returnedcohorts = external_api::clean_returnvalue(core_cohort_external::get_cohorts_returns(), $returnedcohorts);
266
 
267
        // Check we retrieve the good total number of enrolled cohorts + no error on capability.
268
        $this->assertEquals(2, count($returnedcohorts));
269
 
270
        foreach ($returnedcohorts as $enrolledcohort) {
271
            if ($enrolledcohort['idnumber'] == $cohort1->idnumber) {
272
                $this->assertEquals($cohort1->name, $enrolledcohort['name']);
273
                $this->assertEquals($cohort1->description, $enrolledcohort['description']);
274
                $this->assertEquals($cohort1->visible, $enrolledcohort['visible']);
275
                $this->assertEquals($cohort1->theme, $enrolledcohort['theme']);
276
                $this->assertIsArray($enrolledcohort['customfields']);
277
                $this->assertCount(2, $enrolledcohort['customfields']);
278
                $actual = [];
279
                foreach ($enrolledcohort['customfields'] as $customfield) {
280
                    $this->assertArrayHasKey('name', $customfield);
281
                    $this->assertArrayHasKey('shortname', $customfield);
282
                    $this->assertArrayHasKey('type', $customfield);
283
                    $this->assertArrayHasKey('valueraw', $customfield);
284
                    $this->assertArrayHasKey('value', $customfield);
285
                    $actual[$customfield['shortname']] = $customfield;
286
                }
287
                $this->assertEquals('Test value 1', $actual['testfield1']['value']);
288
                $this->assertEquals('Test value 2', $actual['testfield2']['value']);
289
            }
290
        }
291
 
292
        // Check that a user with cohort:manage can see the cohort.
293
        $this->unassignUserCapability('moodle/cohort:view', $context->id, $roleid);
294
        $roleid = $this->assignUserCapability('moodle/cohort:manage', $context->id, $roleid);
295
        // Call the external function.
296
        $returnedcohorts = core_cohort_external::get_cohorts(array(
297
            $cohort1->id, $cohort2->id));
298
        $returnedcohorts = external_api::clean_returnvalue(core_cohort_external::get_cohorts_returns(), $returnedcohorts);
299
 
300
        // Check we retrieve the good total number of enrolled cohorts + no error on capability.
301
        $this->assertEquals(2, count($returnedcohorts));
302
 
303
        // Check when allowcohortstheme is disabled, theme is not returned.
304
        set_config('allowcohortthemes', 0);
305
        $returnedcohorts = core_cohort_external::get_cohorts(array(
306
            $cohort1->id));
307
        $returnedcohorts = external_api::clean_returnvalue(core_cohort_external::get_cohorts_returns(), $returnedcohorts);
308
        foreach ($returnedcohorts as $enrolledcohort) {
309
            if ($enrolledcohort['idnumber'] == $cohort1->idnumber) {
310
                $this->assertNull($enrolledcohort['theme']);
311
            }
312
        }
313
    }
314
 
315
    /**
316
     * Test update_cohorts
317
     */
11 efrain 318
    public function test_update_cohorts(): void {
1 efrain 319
        global $DB;
320
 
321
        $this->resetAfterTest(true);
322
 
323
        // Custom fields.
324
        $this->create_custom_fields();
325
 
326
        set_config('allowcohortthemes', 0);
327
 
328
        $cohort1 = self::getDataGenerator()->create_cohort(array('visible' => 0));
329
 
330
        $data = cohort_handler::create()->export_instance_data_object($cohort1->id, true);
331
        $this->assertNull($data->testfield1);
332
        $this->assertNull($data->testfield2);
333
 
334
        $cohort1 = array(
335
            'id' => $cohort1->id,
336
            'categorytype' => array('type' => 'id', 'value' => '1'),
337
            'name' => 'cohortnametest1',
338
            'idnumber' => 'idnumbertest1',
339
            'description' => 'This is a description for cohort 1',
340
            'theme' => 'classic',
341
            'customfields' => array(
342
                array(
343
                    'shortname' => 'testfield1',
344
                    'value' => 'Test value 1',
345
                ),
346
                array(
347
                    'shortname' => 'testfield2',
348
                    'value' => 'Test value 2',
349
                ),
350
            ),
351
        );
352
 
353
        $context = \context_system::instance();
354
        $roleid = $this->assignUserCapability('moodle/cohort:manage', $context->id);
355
 
356
        // Call the external function.
357
        core_cohort_external::update_cohorts(array($cohort1));
358
 
359
        $dbcohort = $DB->get_record('cohort', array('id' => $cohort1['id']));
360
        $contextid = $DB->get_field('context', 'id', array('instanceid' => $cohort1['categorytype']['value'],
361
        'contextlevel' => CONTEXT_COURSECAT));
362
        $this->assertEquals($dbcohort->contextid, $contextid);
363
        $this->assertEquals($dbcohort->name, $cohort1['name']);
364
        $this->assertEquals($dbcohort->idnumber, $cohort1['idnumber']);
365
        $this->assertEquals($dbcohort->description, $cohort1['description']);
366
        $this->assertEquals($dbcohort->visible, 0);
367
        $this->assertEmpty($dbcohort->theme);
368
        $data = cohort_handler::create()->export_instance_data_object($cohort1['id'], true);
369
        $this->assertEquals('Test value 1', $data->testfield1);
370
        $this->assertEquals('Test value 2', $data->testfield2);
371
 
372
        // Since field 'visible' was added in 2.8, make sure that update works correctly with and without this parameter.
373
        core_cohort_external::update_cohorts(array($cohort1 + array('visible' => 1)));
374
        $dbcohort = $DB->get_record('cohort', array('id' => $cohort1['id']));
375
        $this->assertEquals(1, $dbcohort->visible);
376
        core_cohort_external::update_cohorts(array($cohort1));
377
        $dbcohort = $DB->get_record('cohort', array('id' => $cohort1['id']));
378
        $this->assertEquals(1, $dbcohort->visible);
379
 
380
        // Call when $CFG->allowcohortthemes is enabled.
381
        set_config('allowcohortthemes', 1);
382
        core_cohort_external::update_cohorts(array($cohort1 + array('theme' => 'classic')));
383
        $dbcohort = $DB->get_record('cohort', array('id' => $cohort1['id']));
384
        $this->assertEquals('classic', $dbcohort->theme);
385
 
386
        // Call when $CFG->allowcohortthemes is disabled.
387
        set_config('allowcohortthemes', 0);
388
        core_cohort_external::update_cohorts(array($cohort1 + array('theme' => 'boost')));
389
        $dbcohort = $DB->get_record('cohort', array('id' => $cohort1['id']));
390
        $this->assertEquals('classic', $dbcohort->theme);
391
 
392
        // Updating custom fields.
393
        $cohort1['customfields'] = array(
394
            array(
395
                'shortname' => 'testfield1',
396
                'value' => 'Test value 1 updated',
397
            ),
398
            array(
399
                'shortname' => 'testfield2',
400
                'value' => 'Test value 2 updated',
401
            ),
402
        );
403
        core_cohort_external::update_cohorts(array($cohort1));
404
        $data = cohort_handler::create()->export_instance_data_object($cohort1['id'], true);
405
        $this->assertEquals('Test value 1 updated', $data->testfield1);
406
        $this->assertEquals('Test value 2 updated', $data->testfield2);
407
 
408
        // Call without required capability.
409
        $this->unassignUserCapability('moodle/cohort:manage', $context->id, $roleid);
410
        $this->expectException(\required_capability_exception::class);
411
        core_cohort_external::update_cohorts(array($cohort1));
412
    }
413
 
414
    /**
415
     * Verify handling of 'id' param.
416
     */
11 efrain 417
    public function test_update_cohorts_invalid_id_param(): void {
1 efrain 418
        $this->resetAfterTest(true);
419
        $cohort = self::getDataGenerator()->create_cohort();
420
 
421
        $cohort1 = array(
422
            'id' => 'THIS IS NOT AN ID',
423
            'name' => 'Changed cohort name',
424
            'categorytype' => array('type' => 'id', 'value' => '1'),
425
            'idnumber' => $cohort->idnumber,
426
        );
427
 
428
        try {
429
            core_cohort_external::update_cohorts(array($cohort1));
430
            $this->fail('Expecting invalid_parameter_exception exception, none occured');
431
        } catch (\invalid_parameter_exception $e1) {
432
            $this->assertStringContainsString('Invalid external api parameter: the value is "THIS IS NOT AN ID"', $e1->debuginfo);
433
        }
434
 
435
        $cohort1['id'] = 9.999; // Also not a valid id of a cohort.
436
        try {
437
            core_cohort_external::update_cohorts(array($cohort1));
438
            $this->fail('Expecting invalid_parameter_exception exception, none occured');
439
        } catch (\invalid_parameter_exception $e2) {
440
            $this->assertStringContainsString('Invalid external api parameter: the value is "9.999"', $e2->debuginfo);
441
        }
442
    }
443
 
444
    /**
445
     * Test update_cohorts without permission on the dest category.
446
     */
11 efrain 447
    public function test_update_cohorts_missing_dest(): void {
1 efrain 448
        global $USER, $CFG, $DB;
449
 
450
        $this->resetAfterTest(true);
451
 
452
        $category1 = self::getDataGenerator()->create_category(array(
453
            'name' => 'Test category 1'
454
        ));
455
        $category2 = self::getDataGenerator()->create_category(array(
456
            'name' => 'Test category 2'
457
        ));
458
        $context1 = \context_coursecat::instance($category1->id);
459
        $context2 = \context_coursecat::instance($category2->id);
460
 
461
        $cohort = array(
462
            'contextid' => $context1->id,
463
            'name' => 'cohortnametest1',
464
            'idnumber' => 'idnumbertest1',
465
            'description' => 'This is a description for cohort 1'
466
            );
467
        $cohort1 = self::getDataGenerator()->create_cohort($cohort);
468
 
469
        $roleid = $this->assignUserCapability('moodle/cohort:manage', $context1->id);
470
 
471
        $cohortupdate = array(
472
            'id' => $cohort1->id,
473
            'categorytype' => array('type' => 'id', 'value' => $category2->id),
474
            'name' => 'cohort update',
475
            'idnumber' => 'idnumber update',
476
            'description' => 'This is a description update'
477
            );
478
 
479
        // Call the external function.
480
        // Should fail because we don't have permission on the dest category
481
        $this->expectException(\required_capability_exception::class);
482
        core_cohort_external::update_cohorts(array($cohortupdate));
483
    }
484
 
485
    /**
486
     * Test update_cohorts without permission on the src category.
487
     */
11 efrain 488
    public function test_update_cohorts_missing_src(): void {
1 efrain 489
        global $USER, $CFG, $DB;
490
 
491
        $this->resetAfterTest(true);
492
 
493
        $category1 = self::getDataGenerator()->create_category(array(
494
            'name' => 'Test category 1'
495
        ));
496
        $category2 = self::getDataGenerator()->create_category(array(
497
            'name' => 'Test category 2'
498
        ));
499
        $context1 = \context_coursecat::instance($category1->id);
500
        $context2 = \context_coursecat::instance($category2->id);
501
 
502
        $cohort = array(
503
            'contextid' => $context1->id,
504
            'name' => 'cohortnametest1',
505
            'idnumber' => 'idnumbertest1',
506
            'description' => 'This is a description for cohort 1'
507
            );
508
        $cohort1 = self::getDataGenerator()->create_cohort($cohort);
509
 
510
        $roleid = $this->assignUserCapability('moodle/cohort:manage', $context2->id);
511
 
512
        $cohortupdate = array(
513
            'id' => $cohort1->id,
514
            'categorytype' => array('type' => 'id', 'value' => $category2->id),
515
            'name' => 'cohort update',
516
            'idnumber' => 'idnumber update',
517
            'description' => 'This is a description update'
518
            );
519
 
520
        // Call the external function.
521
        // Should fail because we don't have permission on the src category
522
        $this->expectException(\required_capability_exception::class);
523
        core_cohort_external::update_cohorts(array($cohortupdate));
524
    }
525
 
526
    /**
527
     * Test add_cohort_members
528
     */
11 efrain 529
    public function test_add_cohort_members(): void {
1 efrain 530
        global $DB;
531
 
532
        $this->resetAfterTest(true); // Reset all changes automatically after this test.
533
 
534
        $contextid = \context_system::instance()->id;
535
 
536
        $cohort = array(
537
            'contextid' => $contextid,
538
            'name' => 'cohortnametest1',
539
            'idnumber' => 'idnumbertest1',
540
            'description' => 'This is a description for cohort 1'
541
            );
542
        $cohort0 = self::getDataGenerator()->create_cohort($cohort);
543
        // Check the cohorts were correctly created.
544
        $this->assertEquals(1, $DB->count_records_select('cohort', ' (id = :cohortid0)',
545
            array('cohortid0' => $cohort0->id)));
546
 
547
        $cohort1 = array(
548
            'cohorttype' => array('type' => 'id', 'value' => $cohort0->id),
549
            'usertype' => array('type' => 'id', 'value' => '1')
550
            );
551
 
552
        $roleid = $this->assignUserCapability('moodle/cohort:assign', $contextid);
553
 
554
        // Call the external function.
555
        $addcohortmembers = core_cohort_external::add_cohort_members(array($cohort1));
556
        $addcohortmembers = external_api::clean_returnvalue(core_cohort_external::add_cohort_members_returns(), $addcohortmembers);
557
 
558
        // Check we retrieve the good total number of created cohorts + no error on capability.
559
        $this->assertEquals(1, count($addcohortmembers));
560
 
561
        foreach ($addcohortmembers as $addcohortmember) {
562
            $dbcohort = $DB->get_record('cohort_members', array('cohortid' => $cohort0->id));
563
            $this->assertEquals($dbcohort->cohortid, $cohort1['cohorttype']['value']);
564
            $this->assertEquals($dbcohort->userid, $cohort1['usertype']['value']);
565
        }
566
 
567
        // Call without required capability.
568
        $cohort2 = array(
569
            'cohorttype' => array('type' => 'id', 'value' => $cohort0->id),
570
            'usertype' => array('type' => 'id', 'value' => '2')
571
            );
572
        $this->unassignUserCapability('moodle/cohort:assign', $contextid, $roleid);
573
        $this->expectException(\required_capability_exception::class);
574
        $addcohortmembers = core_cohort_external::add_cohort_members(array($cohort2));
575
    }
576
 
577
    /**
578
     * Test delete_cohort_members
579
     */
11 efrain 580
    public function test_delete_cohort_members(): void {
1 efrain 581
        global $DB;
582
 
583
        $this->resetAfterTest(true); // Reset all changes automatically after this test.
584
 
585
        $cohort1 = self::getDataGenerator()->create_cohort();
586
        $user1 = self::getDataGenerator()->create_user();
587
        $cohort2 = self::getDataGenerator()->create_cohort();
588
        $user2 = self::getDataGenerator()->create_user();
589
 
590
        $context = \context_system::instance();
591
        $roleid = $this->assignUserCapability('moodle/cohort:assign', $context->id);
592
 
593
        $cohortaddmember1 = array(
594
            'cohorttype' => array('type' => 'id', 'value' => $cohort1->id),
595
            'usertype' => array('type' => 'id', 'value' => $user1->id)
596
            );
597
        $cohortmembers1 = core_cohort_external::add_cohort_members(array($cohortaddmember1));
598
        $cohortmembers1 = external_api::clean_returnvalue(core_cohort_external::add_cohort_members_returns(), $cohortmembers1);
599
 
600
        $cohortaddmember2 = array(
601
            'cohorttype' => array('type' => 'id', 'value' => $cohort2->id),
602
            'usertype' => array('type' => 'id', 'value' => $user2->id)
603
            );
604
        $cohortmembers2 = core_cohort_external::add_cohort_members(array($cohortaddmember2));
605
        $cohortmembers2 = external_api::clean_returnvalue(core_cohort_external::add_cohort_members_returns(), $cohortmembers2);
606
 
607
        // Check we retrieve no cohorts + no error on capability.
608
        $this->assertEquals(2, $DB->count_records_select('cohort_members', ' ((cohortid = :idcohort1 AND userid = :iduser1)
609
            OR (cohortid = :idcohort2 AND userid = :iduser2))',
610
            array('idcohort1' => $cohort1->id, 'iduser1' => $user1->id, 'idcohort2' => $cohort2->id, 'iduser2' => $user2->id)));
611
 
612
        // Call the external function.
613
         $cohortdel1 = array(
614
            'cohortid' => $cohort1->id,
615
            'userid' => $user1->id
616
            );
617
         $cohortdel2 = array(
618
            'cohortid' => $cohort2->id,
619
            'userid' => $user2->id
620
            );
621
        core_cohort_external::delete_cohort_members(array($cohortdel1, $cohortdel2));
622
 
623
        // Check we retrieve no cohorts + no error on capability.
624
        $this->assertEquals(0, $DB->count_records_select('cohort_members', ' ((cohortid = :idcohort1 AND userid = :iduser1)
625
            OR (cohortid = :idcohort2 AND userid = :iduser2))',
626
            array('idcohort1' => $cohort1->id, 'iduser1' => $user1->id, 'idcohort2' => $cohort2->id, 'iduser2' => $user2->id)));
627
 
628
        // Call without required capability.
629
        $this->unassignUserCapability('moodle/cohort:assign', $context->id, $roleid);
630
        $this->expectException(\required_capability_exception::class);
631
        core_cohort_external::delete_cohort_members(array($cohortdel1, $cohortdel2));
632
    }
633
 
634
    /**
635
     * Search cohorts.
636
     */
11 efrain 637
    public function test_search_cohorts(): void {
1 efrain 638
        global $DB, $CFG;
639
        $this->resetAfterTest(true);
640
 
641
        $this->create_custom_fields();
642
        $creator = $this->getDataGenerator()->create_user();
643
        $user = $this->getDataGenerator()->create_user();
644
        $catuser = $this->getDataGenerator()->create_user();
645
        $catcreator = $this->getDataGenerator()->create_user();
646
        $courseuser = $this->getDataGenerator()->create_user();
647
        $category = $this->getDataGenerator()->create_category();
648
        $othercategory = $this->getDataGenerator()->create_category();
649
        $course = $this->getDataGenerator()->create_course();
650
        $syscontext = \context_system::instance();
651
        $catcontext = \context_coursecat::instance($category->id);
652
        $coursecontext = \context_course::instance($course->id);
653
 
654
        // Fetching default authenticated user role.
655
        $authrole = $DB->get_record('role', array('id' => $CFG->defaultuserroleid));
656
 
657
        // Reset all default authenticated users permissions.
658
        unassign_capability('moodle/cohort:manage', $authrole->id);
659
 
660
        // Creating specific roles.
661
        $creatorrole = create_role('Creator role', 'creatorrole', 'creator role description');
662
        $userrole = create_role('User role', 'userrole', 'user role description');
663
        $courserole = create_role('Course user role', 'courserole', 'course user role description');
664
 
665
        assign_capability('moodle/cohort:manage', CAP_ALLOW, $creatorrole, $syscontext->id);
666
        assign_capability('moodle/cohort:view', CAP_ALLOW, $courserole, $syscontext->id);
667
 
668
        // Check for parameter $includes = 'parents'.
669
        role_assign($creatorrole, $creator->id, $syscontext->id);
670
        role_assign($creatorrole, $catcreator->id, $catcontext->id);
671
        role_assign($userrole, $user->id, $syscontext->id);
672
        role_assign($userrole, $catuser->id, $catcontext->id);
673
 
674
        // Enrol user in the course.
675
        $this->getDataGenerator()->enrol_user($courseuser->id, $course->id, 'courserole');
676
 
677
        $syscontext = array('contextid' => \context_system::instance()->id);
678
        $catcontext = array('contextid' => \context_coursecat::instance($category->id)->id);
679
        $othercatcontext = array('contextid' => \context_coursecat::instance($othercategory->id)->id);
680
        $coursecontext = array('contextid' => \context_course::instance($course->id)->id);
681
        $customfields = array(
682
            'contextid' => \context_system::instance()->id,
683
            'customfield_testfield1' => 'Test value 1',
684
            'customfield_testfield2' => 'Test value 2',
685
        );
686
 
687
        // We need a site admin to be able to populate cohorts custom fields.
688
        $this->setAdminUser();
689
 
690
        $cohort1 = $this->getDataGenerator()->create_cohort(array_merge($syscontext, array('name' => 'Cohortsearch 1')));
691
        $cohort2 = $this->getDataGenerator()->create_cohort(array_merge($catcontext, array('name' => 'Cohortsearch 2')));
692
        $cohort3 = $this->getDataGenerator()->create_cohort(array_merge($othercatcontext, array('name' => 'Cohortsearch 3')));
693
        $cohort4 = $this->getDataGenerator()->create_cohort(array_merge($customfields, array('name' => 'Cohortsearch 4')));
694
 
695
        // A user without permission in the system.
696
        $this->setUser($user);
697
        try {
698
            $result = core_cohort_external::search_cohorts("Cohortsearch", $syscontext, 'parents');
699
            $this->fail('Invalid permissions in system');
700
        } catch (\required_capability_exception $e) {
701
            // All good.
702
        }
703
 
704
        // A user without permission in a category.
705
        $this->setUser($catuser);
706
        try {
707
            $result = core_cohort_external::search_cohorts("Cohortsearch", $catcontext, 'parents');
708
            $this->fail('Invalid permissions in category');
709
        } catch (\required_capability_exception $e) {
710
            // All good.
711
        }
712
 
713
        // A user with permissions in the system.
714
        $this->setUser($creator);
715
        $result = core_cohort_external::search_cohorts("Cohortsearch 4", $syscontext, 'parents');
716
        $this->assertCount(1, $result['cohorts']);
717
        $this->assertEquals('Cohortsearch 4', $result['cohorts'][$cohort4->id]->name);
718
 
719
        // A user with permissions in the system, searching category context.
720
        $result = core_cohort_external::search_cohorts("Cohortsearch 4", $catcontext, 'parents');
721
        $this->assertCount(1, $result['cohorts']);
722
        $this->assertEquals('Cohortsearch 4', $result['cohorts'][$cohort4->id]->name);
723
 
724
        $this->assertEqualsCanonicalizing([
725
            'Test value 1',
726
            'Test value 2',
727
        ], array_column($result['cohorts'][$cohort4->id]->customfields, 'value'));
728
 
729
        $actual = [];
730
        foreach ($result['cohorts'][$cohort4->id]->customfields as $customfield) {
731
            $this->assertArrayHasKey('name', $customfield);
732
            $this->assertArrayHasKey('shortname', $customfield);
733
            $this->assertArrayHasKey('type', $customfield);
734
            $this->assertArrayHasKey('valueraw', $customfield);
735
            $this->assertArrayHasKey('value', $customfield);
736
            $actual[$customfield['shortname']] = $customfield;
737
        }
738
 
739
        // A user with permissions in the category.
740
        $this->setUser($catcreator);
741
        $result = core_cohort_external::search_cohorts("Cohortsearch", $catcontext, 'parents');
742
        $this->assertCount(3, $result['cohorts']);
743
        $cohorts = array();
744
        foreach ($result['cohorts'] as $cohort) {
745
            $cohorts[] = $cohort->name;
746
        }
747
        $this->assertTrue(in_array('Cohortsearch 1', $cohorts));
748
 
749
        // Check for parameter $includes = 'self'.
750
        $this->setUser($creator);
751
        $result = core_cohort_external::search_cohorts("Cohortsearch", $othercatcontext, 'self');
752
        $this->assertCount(1, $result['cohorts']);
753
        $this->assertEquals('Cohortsearch 3', $result['cohorts'][$cohort3->id]->name);
754
 
755
        // Check for parameter $includes = 'all'.
756
        $this->setUser($creator);
757
        $result = core_cohort_external::search_cohorts("Cohortsearch", $syscontext, 'all');
758
        $this->assertCount(4, $result['cohorts']);
759
 
760
        // A user in the course context with the system cohort:view capability. Check that all the system cohorts are returned.
761
        $this->setUser($courseuser);
762
        $result = core_cohort_external::search_cohorts("Cohortsearch", $coursecontext, 'all');
763
        $this->assertCount(2, $result['cohorts']);
764
        $this->assertEquals('Cohortsearch 1', $result['cohorts'][$cohort1->id]->name);
765
 
766
        // Detect invalid parameter $includes.
767
        $this->setUser($creator);
768
        try {
769
            $result = core_cohort_external::search_cohorts("Cohortsearch", $syscontext, 'invalid');
770
            $this->fail('Invalid parameter includes');
771
        } catch (\coding_exception $e) {
772
            // All good.
773
        }
774
    }
775
}