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_completion;
18
 
19
use core_completion_external;
20
use core_external\external_api;
21
use externallib_advanced_testcase;
22
 
23
defined('MOODLE_INTERNAL') || die();
24
 
25
global $CFG;
26
 
27
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
28
 
29
/**
30
 * External completion functions unit tests
31
 *
32
 * @package    core_completion
33
 * @category   external
34
 * @copyright  2015 Juan Leyva <juan@moodle.com>
35
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 * @since      Moodle 2.9
37
 * @coversDefaultClass \core_completion_external
38
 */
39
class externallib_test extends externallib_advanced_testcase {
40
 
41
    /**
42
     * Test update_activity_completion_status_manually
43
     */
11 efrain 44
    public function test_update_activity_completion_status_manually(): void {
1 efrain 45
        global $DB, $CFG;
46
 
47
        $this->resetAfterTest(true);
48
 
49
        $CFG->enablecompletion = true;
50
        $user = $this->getDataGenerator()->create_user();
51
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
52
        $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id),
53
                                                             array('completion' => 1));
54
        $cm = get_coursemodule_from_id('data', $data->cmid);
55
 
56
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
57
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
58
 
59
        $this->setUser($user);
60
 
61
        $result = core_completion_external::update_activity_completion_status_manually($data->cmid, true);
62
        // We need to execute the return values cleaning process to simulate the web service server.
63
        $result = external_api::clean_returnvalue(
64
            core_completion_external::update_activity_completion_status_manually_returns(), $result);
65
 
66
        // Check in DB.
67
        $this->assertEquals(1, $DB->get_field('course_modules_completion', 'completionstate',
68
                            array('coursemoduleid' => $data->cmid)));
69
 
70
        // Check using the API.
71
        $completion = new \completion_info($course);
72
        $completiondata = $completion->get_data($cm);
73
        $this->assertEquals(1, $completiondata->completionstate);
74
        $this->assertTrue($result['status']);
75
 
76
        $result = core_completion_external::update_activity_completion_status_manually($data->cmid, false);
77
        // We need to execute the return values cleaning process to simulate the web service server.
78
        $result = external_api::clean_returnvalue(
79
            core_completion_external::update_activity_completion_status_manually_returns(), $result);
80
 
81
        $this->assertEquals(0, $DB->get_field('course_modules_completion', 'completionstate',
82
                            array('coursemoduleid' => $data->cmid)));
83
        $completiondata = $completion->get_data($cm);
84
        $this->assertEquals(0, $completiondata->completionstate);
85
        $this->assertTrue($result['status']);
86
    }
87
 
88
    /**
89
     * Test update_activity_completion_status
90
     */
11 efrain 91
    public function test_get_activities_completion_status(): void {
1 efrain 92
        global $DB, $CFG, $PAGE;
93
 
94
        $this->resetAfterTest(true);
95
 
96
        $CFG->enablecompletion = true;
97
        $student = $this->getDataGenerator()->create_user();
98
        $teacher = $this->getDataGenerator()->create_user();
99
 
100
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1,
101
                                                                    'groupmode' => SEPARATEGROUPS,
102
                                                                    'groupmodeforce' => 1));
103
        \availability_completion\condition::wipe_static_cache();
104
 
105
        $data = $this->getDataGenerator()->create_module('data',
106
            ['course' => $course->id],
107
            ['completion' => COMPLETION_TRACKING_MANUAL],
108
        );
109
        $forum = $this->getDataGenerator()->create_module('forum',
110
            ['course' => $course->id],
111
            ['completion' => COMPLETION_TRACKING_MANUAL],
112
        );
113
        $forumautocompletion = $this->getDataGenerator()->create_module('forum',
114
            ['course' => $course->id],
115
            ['showdescription' => true, 'completionview' => 1, 'completion' => COMPLETION_TRACKING_AUTOMATIC],
116
        );
117
        $availability = '{"op":"&","c":[{"type":"completion","cm":' . $forum->cmid .',"e":1}],"showc":[true]}';
118
        $assign = $this->getDataGenerator()->create_module('assign',
119
            ['course' => $course->id],
120
            ['availability' => $availability],
121
        );
122
        $assignautocompletion = $this->getDataGenerator()->create_module('assign',
123
            ['course' => $course->id], [
124
                'showdescription' => true,
125
                'completionview' => 1,
126
                'completion' => COMPLETION_TRACKING_AUTOMATIC,
127
                'completiongradeitemnumber' => 1,
128
                'completionpassgrade' => 1,
129
            ],
130
        );
131
        $page = $this->getDataGenerator()->create_module('page',  array('course' => $course->id),
132
                                                            array('completion' => 1, 'visible' => 0));
133
 
134
        $cmdata = get_coursemodule_from_id('data', $data->cmid);
135
        $cmforum = get_coursemodule_from_id('forum', $forum->cmid);
136
        $cmforumautocompletion = get_coursemodule_from_id('forum', $forumautocompletion->cmid);
137
 
138
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
139
        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
140
        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
141
        $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
142
 
143
        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
144
        $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
145
 
146
        // Teacher and student in different groups initially.
147
        groups_add_member($group1->id, $student->id);
148
        groups_add_member($group2->id, $teacher->id);
149
 
150
        $this->setUser($student);
151
        // Forum complete.
152
        $completion = new \completion_info($course);
153
        $completion->update_state($cmforum, COMPLETION_COMPLETE);
154
 
155
        $result = core_completion_external::get_activities_completion_status($course->id, $student->id);
156
        // We need to execute the return values cleaning process to simulate the web service server.
157
        $result = external_api::clean_returnvalue(
158
            core_completion_external::get_activities_completion_status_returns(), $result);
159
 
160
        // We added 6 activities, but only 4 with completion enabled and one of those is hidden.
161
        $numberofactivities = 6;
162
        $numberofhidden = 1;
163
        $numberofcompletions = $numberofactivities - $numberofhidden;
164
        $numberofstatusstudent = 4;
165
 
166
        $this->assertCount($numberofstatusstudent, $result['statuses']);
167
 
168
        $activitiesfound = 0;
169
        foreach ($result['statuses'] as $status) {
170
            if ($status['cmid'] == $forum->cmid and $status['modname'] == 'forum' and $status['instance'] == $forum->id) {
171
                $activitiesfound++;
172
                $this->assertEquals(COMPLETION_COMPLETE, $status['state']);
173
                $this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
174
                $this->assertTrue($status['valueused']);
175
                $this->assertTrue($status['hascompletion']);
176
                $this->assertFalse($status['isautomatic']);
177
                $this->assertTrue($status['istrackeduser']);
178
                $this->assertTrue($status['uservisible']);
179
                $details = $status['details'];
180
                $this->assertCount(0, $details);
181
                $this->assertTrue($status['isoverallcomplete']);
182
            } else if ($status['cmid'] == $forumautocompletion->cmid) {
183
                $activitiesfound++;
184
                $this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
185
                $this->assertEquals(COMPLETION_TRACKING_AUTOMATIC, $status['tracking']);
186
                $this->assertFalse($status['valueused']);
187
                $this->assertTrue($status['hascompletion']);
188
                $this->assertTrue($status['isautomatic']);
189
                $this->assertTrue($status['istrackeduser']);
190
                $this->assertTrue($status['uservisible']);
191
                $details = $status['details'];
192
                $this->assertCount(1, $details);
193
                $this->assertEquals('completionview', $details[0]['rulename']);
194
                $this->assertEquals(0, $details[0]['rulevalue']['status']);
195
                $this->assertFalse($status['isoverallcomplete']);
196
            } else if ($status['cmid'] == $assignautocompletion->cmid) {
197
                $activitiesfound++;
198
                $this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
199
                $this->assertEquals(COMPLETION_TRACKING_AUTOMATIC, $status['tracking']);
200
                $this->assertFalse($status['valueused']);
201
                $this->assertTrue($status['hascompletion']);
202
                $this->assertTrue($status['isautomatic']);
203
                $this->assertTrue($status['istrackeduser']);
204
                $this->assertTrue($status['uservisible']);
205
                $this->assertFalse($status['isoverallcomplete']);
206
                $details = $status['details'];
207
                $this->assertCount(3, $details);
208
                $expecteddetails = [
209
                    'completionview',
210
                    'completionusegrade',
211
                    'completionpassgrade',
212
                ];
213
                foreach ($expecteddetails as $index => $name) {
214
                    $this->assertEquals($name, $details[$index]['rulename']);
215
                    $this->assertEquals(0, $details[$index]['rulevalue']['status']);
216
                }
217
            } else if ($status['cmid'] == $data->cmid and $status['modname'] == 'data' and $status['instance'] == $data->id) {
218
                $activitiesfound++;
219
                $this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
220
                $this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
221
                $this->assertFalse($status['valueused']);
222
                $this->assertFalse($status['valueused']);
223
                $this->assertTrue($status['hascompletion']);
224
                $this->assertFalse($status['isautomatic']);
225
                $this->assertTrue($status['istrackeduser']);
226
                $this->assertTrue($status['uservisible']);
227
                $details = $status['details'];
228
                $this->assertCount(0, $details);
229
                $this->assertFalse($status['isoverallcomplete']);
230
            }
231
        }
232
        $this->assertEquals(4, $activitiesfound);
233
 
234
        // Teacher should see students status, they are in different groups but the teacher can access all groups.
235
        $this->setUser($teacher);
236
        $result = core_completion_external::get_activities_completion_status($course->id, $student->id);
237
        // We need to execute the return values cleaning process to simulate the web service server.
238
        $result = external_api::clean_returnvalue(
239
            core_completion_external::get_activities_completion_status_returns(), $result);
240
 
241
        $this->assertCount($numberofcompletions, $result['statuses']);
242
 
243
        // Override status by teacher.
244
        $completion->update_state($cmforum, COMPLETION_INCOMPLETE, $student->id, true);
245
 
246
        $result = core_completion_external::get_activities_completion_status($course->id, $student->id);
247
        // We need to execute the return values cleaning process to simulate the web service server.
248
        $result = external_api::clean_returnvalue(
249
            core_completion_external::get_activities_completion_status_returns(), $result);
250
 
251
        // Check forum has been overriden by the teacher.
252
        foreach ($result['statuses'] as $status) {
253
            if ($status['cmid'] == $forum->cmid) {
254
                $this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
255
                $this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
256
                $this->assertEquals($teacher->id, $status['overrideby']);
257
                $this->assertFalse($status['isoverallcomplete']);
258
                break;
259
            }
260
        }
261
 
262
        // Teacher should see his own completion status.
263
 
264
        // Forum complete for teacher.
265
        $completion = new \completion_info($course);
266
        $completion->update_state($cmforum, COMPLETION_COMPLETE);
267
 
268
        $result = core_completion_external::get_activities_completion_status($course->id, $teacher->id);
269
        // We need to execute the return values cleaning process to simulate the web service server.
270
        $result = external_api::clean_returnvalue(
271
            core_completion_external::get_activities_completion_status_returns(), $result);
272
 
273
        $this->assertCount($numberofcompletions, $result['statuses']);
274
 
275
        $activitiesfound = 0;
276
        foreach ($result['statuses'] as $status) {
277
            if ($status['cmid'] == $forum->cmid and $status['modname'] == 'forum' and $status['instance'] == $forum->id) {
278
                $activitiesfound++;
279
                $this->assertEquals(COMPLETION_COMPLETE, $status['state']);
280
                $this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
281
                $this->assertTrue($status['isoverallcomplete']);
282
            } else if (in_array($status['cmid'], [$forumautocompletion->cmid, $assignautocompletion->cmid])) {
283
                $activitiesfound++;
284
                $this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
285
                $this->assertEquals(COMPLETION_TRACKING_AUTOMATIC, $status['tracking']);
286
                $this->assertFalse($status['isoverallcomplete']);
287
            } else {
288
                $activitiesfound++;
289
                $this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
290
                $this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
291
                $this->assertFalse($status['isoverallcomplete']);
292
            }
293
        }
294
        $this->assertEquals(5, $activitiesfound);
295
 
296
        // Change teacher role capabilities (disable access all groups).
297
        $context = \context_course::instance($course->id);
298
        assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $context);
299
        accesslib_clear_all_caches_for_unit_testing();
300
 
301
        try {
302
            $result = core_completion_external::get_activities_completion_status($course->id, $student->id);
303
            $this->fail('Exception expected due to groups permissions.');
304
        } catch (\moodle_exception $e) {
305
            $this->assertEquals('accessdenied', $e->errorcode);
306
        }
307
 
308
        // Now add the teacher in the same group.
309
        groups_add_member($group1->id, $teacher->id);
310
        $result = core_completion_external::get_activities_completion_status($course->id, $student->id);
311
        // We need to execute the return values cleaning process to simulate the web service server.
312
        $result = external_api::clean_returnvalue(
313
            core_completion_external::get_activities_completion_status_returns(), $result);
314
        $this->assertCount($numberofcompletions, $result['statuses']);
315
    }
316
 
317
    /**
318
     * Test override_activity_completion_status
319
     */
11 efrain 320
    public function test_override_activity_completion_status(): void {
1 efrain 321
        global $DB, $CFG;
322
        $this->resetAfterTest(true);
323
 
324
        // Create course with teacher and student enrolled.
325
        $CFG->enablecompletion = true;
326
        $course  = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
327
        $student = $this->getDataGenerator()->create_user();
328
        $teacher = $this->getDataGenerator()->create_user();
329
        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
330
        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
331
        $teacherrole = $DB->get_record('role', ['shortname' => 'teacher']);
332
        $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
333
 
334
        // Create 2 activities, one with manual completion (data), one with automatic completion triggered by viewing it (forum).
335
        $data    = $this->getDataGenerator()->create_module('data', ['course' => $course->id], ['completion' => 1]);
336
        $forum   = $this->getDataGenerator()->create_module('forum',  ['course' => $course->id],
337
                                                            ['completion' => 2, 'completionview' => 1]);
338
        $cmdata = get_coursemodule_from_id('data', $data->cmid);
339
        $cmforum = get_coursemodule_from_id('forum', $forum->cmid);
340
 
341
        // Manually complete the data activity as the student.
342
        $this->setUser($student);
343
        $completion = new \completion_info($course);
344
        $completion->update_state($cmdata, COMPLETION_COMPLETE);
345
 
346
        // Test overriding the status of the manual-completion-activity 'incomplete'.
347
        $this->setUser($teacher);
348
        $result = core_completion_external::override_activity_completion_status($student->id, $data->cmid, COMPLETION_INCOMPLETE);
349
        $result = external_api::clean_returnvalue(core_completion_external::override_activity_completion_status_returns(), $result);
350
        $this->assertEquals($result['state'], COMPLETION_INCOMPLETE);
351
        $completiondata = $completion->get_data($cmdata, false, $student->id);
352
        $this->assertEquals(COMPLETION_INCOMPLETE, $completiondata->completionstate);
353
 
354
        // Test overriding the status of the manual-completion-activity back to 'complete'.
355
        $result = core_completion_external::override_activity_completion_status($student->id, $data->cmid, COMPLETION_COMPLETE);
356
        $result = external_api::clean_returnvalue(core_completion_external::override_activity_completion_status_returns(), $result);
357
        $this->assertEquals($result['state'], COMPLETION_COMPLETE);
358
        $completiondata = $completion->get_data($cmdata, false, $student->id);
359
        $this->assertEquals(COMPLETION_COMPLETE, $completiondata->completionstate);
360
 
361
        // Test overriding the status of the auto-completion-activity to 'complete'.
362
        $result = core_completion_external::override_activity_completion_status($student->id, $forum->cmid, COMPLETION_COMPLETE);
363
        $result = external_api::clean_returnvalue(core_completion_external::override_activity_completion_status_returns(), $result);
364
        $this->assertEquals($result['state'], COMPLETION_COMPLETE);
365
        $completionforum = $completion->get_data($cmforum, false, $student->id);
366
        $this->assertEquals(COMPLETION_COMPLETE, $completionforum->completionstate);
367
 
368
        // Test overriding the status of the auto-completion-activity to 'incomplete'.
369
        $result = core_completion_external::override_activity_completion_status($student->id, $forum->cmid, COMPLETION_INCOMPLETE);
370
        $result = external_api::clean_returnvalue(core_completion_external::override_activity_completion_status_returns(), $result);
371
        $this->assertEquals($result['state'], COMPLETION_INCOMPLETE);
372
        $completionforum = $completion->get_data($cmforum, false, $student->id);
373
        $this->assertEquals(COMPLETION_INCOMPLETE, $completionforum->completionstate);
374
 
375
        // Test overriding the status of the auto-completion-activity to an invalid state.
376
        $this->expectException('moodle_exception');
377
        core_completion_external::override_activity_completion_status($student->id, $forum->cmid, 3);
378
    }
379
 
380
    /**
381
     * Test overriding the activity completion status as a user without the capability to do so.
382
     */
11 efrain 383
    public function test_override_status_user_without_capability(): void {
1 efrain 384
        global $DB, $CFG;
385
        $this->resetAfterTest(true);
386
 
387
        // Create course with teacher and student enrolled.
388
        $CFG->enablecompletion = true;
389
        $course  = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
390
        $student = $this->getDataGenerator()->create_user();
391
        $teacher = $this->getDataGenerator()->create_user();
392
        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
393
        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
394
        $teacherrole = $DB->get_record('role', ['shortname' => 'teacher']);
395
        $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
396
        $coursecontext = \context_course::instance($course->id);
397
 
398
        // Create an activity with automatic completion (a forum).
399
        $forum   = $this->getDataGenerator()->create_module('forum',  ['course' => $course->id],
400
            ['completion' => 2, 'completionview' => 1]);
401
 
402
        // Test overriding the status of the activity for a user without the capability.
403
        $this->setUser($teacher);
404
        assign_capability('moodle/course:overridecompletion', CAP_PREVENT, $teacherrole->id, $coursecontext);
405
        $this->expectException('required_capability_exception');
406
        core_completion_external::override_activity_completion_status($student->id, $forum->cmid, COMPLETION_COMPLETE);
407
    }
408
 
409
    /**
410
     * Test get_course_completion_status
411
     */
11 efrain 412
    public function test_get_course_completion_status(): void {
1 efrain 413
        global $DB, $CFG, $COMPLETION_CRITERIA_TYPES;
414
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php');
415
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_date.php');
416
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_unenrol.php');
417
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php');
418
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_duration.php');
419
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_grade.php');
420
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_role.php');
421
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_course.php');
422
 
423
        $this->resetAfterTest(true);
424
 
425
        $CFG->enablecompletion = true;
426
        $student = $this->getDataGenerator()->create_user();
427
        $teacher = $this->getDataGenerator()->create_user();
428
 
429
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1,
430
                                                                    'groupmode' => SEPARATEGROUPS,
431
                                                                    'groupmodeforce' => 1));
432
 
433
        $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id),
434
                                                             array('completion' => 1));
435
        $forum = $this->getDataGenerator()->create_module('forum',  array('course' => $course->id),
436
                                                             array('completion' => 1));
437
        $assign = $this->getDataGenerator()->create_module('assign',  array('course' => $course->id));
438
 
439
        $cmdata = get_coursemodule_from_id('data', $data->cmid);
440
        $cmforum = get_coursemodule_from_id('forum', $forum->cmid);
441
 
442
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
443
        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
444
        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
445
        $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
446
 
447
        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
448
        $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
449
        // Teacher and student in different groups initially.
450
        groups_add_member($group1->id, $student->id);
451
        groups_add_member($group2->id, $teacher->id);
452
 
453
        // Set completion rules.
454
        $completion = new \completion_info($course);
455
 
456
        // Loop through each criteria type and run its update_config() method.
457
 
458
        $criteriadata = new \stdClass();
459
        $criteriadata->id = $course->id;
460
        $criteriadata->criteria_activity = array();
461
        // Some activities.
462
        $criteriadata->criteria_activity[$cmdata->id] = 1;
463
        $criteriadata->criteria_activity[$cmforum->id] = 1;
464
 
465
        // In a week criteria date value.
466
        $criteriadata->criteria_date_value = time() + WEEKSECS;
467
 
468
        // Self completion.
469
        $criteriadata->criteria_self = 1;
470
 
471
        foreach ($COMPLETION_CRITERIA_TYPES as $type) {
472
            $class = 'completion_criteria_'.$type;
473
            $criterion = new $class();
474
            $criterion->update_config($criteriadata);
475
        }
476
 
477
        // Handle overall aggregation.
478
        $aggdata = array(
479
            'course'        => $course->id,
480
            'criteriatype'  => null
481
        );
482
        $aggregation = new \completion_aggregation($aggdata);
483
        $aggregation->setMethod(COMPLETION_AGGREGATION_ALL);
484
        $aggregation->save();
485
 
486
        $aggdata['criteriatype'] = COMPLETION_CRITERIA_TYPE_ACTIVITY;
487
        $aggregation = new \completion_aggregation($aggdata);
488
        $aggregation->setMethod(COMPLETION_AGGREGATION_ALL);
489
        $aggregation->save();
490
 
491
        $this->setUser($student);
492
 
493
        $result = core_completion_external::get_course_completion_status($course->id, $student->id);
494
        // We need to execute the return values cleaning process to simulate the web service server.
495
        $studentresult = external_api::clean_returnvalue(
496
            core_completion_external::get_course_completion_status_returns(), $result);
497
 
498
        // 3 different criteria.
499
        $this->assertCount(3, $studentresult['completionstatus']['completions']);
500
 
501
        $this->assertEquals(COMPLETION_AGGREGATION_ALL, $studentresult['completionstatus']['aggregation']);
502
        $this->assertFalse($studentresult['completionstatus']['completed']);
503
 
504
        $this->assertEquals('No', $studentresult['completionstatus']['completions'][0]['status']);
505
        $this->assertEquals('No', $studentresult['completionstatus']['completions'][1]['status']);
506
        $this->assertEquals('No', $studentresult['completionstatus']['completions'][2]['status']);
507
 
508
        // Teacher should see students status, they are in different groups but the teacher can access all groups.
509
        $this->setUser($teacher);
510
        $result = core_completion_external::get_course_completion_status($course->id, $student->id);
511
        // We need to execute the return values cleaning process to simulate the web service server.
512
        $teacherresult = external_api::clean_returnvalue(
513
            core_completion_external::get_course_completion_status_returns(), $result);
514
 
515
        $this->assertEquals($studentresult, $teacherresult);
516
 
517
        // Change teacher role capabilities (disable access al goups).
518
        $context = \context_course::instance($course->id);
519
        assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $context);
520
        accesslib_clear_all_caches_for_unit_testing();
521
 
522
        try {
523
            $result = core_completion_external::get_course_completion_status($course->id, $student->id);
524
            $this->fail('Exception expected due to groups permissions.');
525
        } catch (\moodle_exception $e) {
526
            $this->assertEquals('accessdenied', $e->errorcode);
527
        }
528
 
529
        // Now add the teacher in the same group.
530
        groups_add_member($group1->id, $teacher->id);
531
        $result = core_completion_external::get_course_completion_status($course->id, $student->id);
532
        // We need to execute the return values cleaning process to simulate the web service server.
533
        $teacherresult = external_api::clean_returnvalue(
534
            core_completion_external::get_course_completion_status_returns(), $result);
535
 
536
        $this->assertEquals($studentresult, $teacherresult);
537
 
538
    }
539
 
540
    /**
541
     * Test mark_course_self_completed
542
     */
11 efrain 543
    public function test_mark_course_self_completed(): void {
1 efrain 544
        global $DB, $CFG;
545
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php');
546
 
547
        $this->resetAfterTest(true);
548
 
549
        $CFG->enablecompletion = true;
550
        $student = $this->getDataGenerator()->create_user();
551
        $teacher = $this->getDataGenerator()->create_user();
552
 
553
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
554
 
555
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
556
        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
557
 
558
        // Set completion rules.
559
        $completion = new \completion_info($course);
560
 
561
        $criteriadata = new \stdClass();
562
        $criteriadata->id = $course->id;
563
        $criteriadata->criteria_activity = array();
564
 
565
        // Self completion.
566
        $criteriadata->criteria_self = COMPLETION_CRITERIA_TYPE_SELF;
567
        $class = 'completion_criteria_self';
568
        $criterion = new $class();
569
        $criterion->update_config($criteriadata);
570
 
571
        // Handle overall aggregation.
572
        $aggdata = array(
573
            'course'        => $course->id,
574
            'criteriatype'  => null
575
        );
576
        $aggregation = new \completion_aggregation($aggdata);
577
        $aggregation->setMethod(COMPLETION_AGGREGATION_ALL);
578
        $aggregation->save();
579
 
580
        $this->setUser($student);
581
 
582
        $result = core_completion_external::mark_course_self_completed($course->id);
583
        // We need to execute the return values cleaning process to simulate the web service server.
584
        $result = external_api::clean_returnvalue(
585
            core_completion_external::mark_course_self_completed_returns(), $result);
586
 
587
        // We expect a valid result.
588
        $this->assertEquals(true, $result['status']);
589
 
590
        $result = core_completion_external::get_course_completion_status($course->id, $student->id);
591
        // We need to execute the return values cleaning process to simulate the web service server.
592
        $result = external_api::clean_returnvalue(
593
            core_completion_external::get_course_completion_status_returns(), $result);
594
 
595
        // Course must be completed.
596
        $this->assertEquals(COMPLETION_COMPLETE, $result['completionstatus']['completions'][0]['complete']);
597
 
598
        try {
599
            $result = core_completion_external::mark_course_self_completed($course->id);
600
            $this->fail('Exception expected due course already self completed.');
601
        } catch (\moodle_exception $e) {
602
            $this->assertEquals('useralreadymarkedcomplete', $e->errorcode);
603
        }
604
 
605
    }
606
 
607
}