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
 * Unit tests for (some of) mod/feedback/lib.php.
18
 *
19
 * @package    mod_feedback
20
 * @copyright  2016 Stephen Bourget
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
namespace mod_feedback;
24
 
25
use mod_feedback_completion;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
global $CFG;
29
require_once($CFG->dirroot . '/mod/feedback/lib.php');
30
 
31
/**
32
 * Unit tests for (some of) mod/feedback/lib.php.
33
 *
34
 * @copyright  2016 Stephen Bourget
35
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
37
class lib_test extends \advanced_testcase {
38
 
11 efrain 39
    public function test_feedback_initialise(): void {
1 efrain 40
        $this->resetAfterTest();
41
        $this->setAdminUser();
42
 
43
        $course = $this->getDataGenerator()->create_course();
44
        $params['course'] = $course->id;
45
        $params['timeopen'] = time() - 5 * MINSECS;
46
        $params['timeclose'] = time() + DAYSECS;
47
        $params['anonymous'] = 1;
48
        $params['intro'] = 'Some introduction text';
49
        $feedback = $this->getDataGenerator()->create_module('feedback', $params);
50
 
51
        // Test different ways to construct the structure object.
52
        $pseudocm = get_coursemodule_from_instance('feedback', $feedback->id); // Object similar to cm_info.
53
        $cm = get_fast_modinfo($course)->instances['feedback'][$feedback->id]; // Instance of cm_info.
54
 
55
        $constructorparams = [
56
            [$feedback, null],
57
            [null, $pseudocm],
58
            [null, $cm],
59
            [$feedback, $pseudocm],
60
            [$feedback, $cm],
61
        ];
62
 
63
        foreach ($constructorparams as $params) {
64
            $structure = new mod_feedback_completion($params[0], $params[1], 0);
65
            $this->assertTrue($structure->is_open());
66
            $this->assertTrue($structure->get_cm() instanceof \cm_info);
67
            $this->assertEquals($feedback->cmid, $structure->get_cm()->id);
68
            $this->assertEquals($feedback->intro, $structure->get_feedback()->intro);
69
        }
70
    }
71
 
72
    /**
73
     * Tests for mod_feedback_refresh_events.
74
     */
11 efrain 75
    public function test_feedback_refresh_events(): void {
1 efrain 76
        global $DB;
77
        $this->resetAfterTest();
78
        $this->setAdminUser();
79
 
80
        $timeopen = time();
81
        $timeclose = time() + 86400;
82
 
83
        $course = $this->getDataGenerator()->create_course();
84
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
85
        $params['course'] = $course->id;
86
        $params['timeopen'] = $timeopen;
87
        $params['timeclose'] = $timeclose;
88
        $feedback = $generator->create_instance($params);
89
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
90
        $context = \context_module::instance($cm->id);
91
 
92
        // Normal case, with existing course.
93
        $this->assertTrue(feedback_refresh_events($course->id));
94
        $eventparams = array('modulename' => 'feedback', 'instance' => $feedback->id, 'eventtype' => 'open');
95
        $openevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST);
96
        $this->assertEquals($openevent->timestart, $timeopen);
97
 
98
        $eventparams = array('modulename' => 'feedback', 'instance' => $feedback->id, 'eventtype' => 'close');
99
        $closeevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST);
100
        $this->assertEquals($closeevent->timestart, $timeclose);
101
        // In case the course ID is passed as a numeric string.
102
        $this->assertTrue(feedback_refresh_events('' . $course->id));
103
        // Course ID not provided.
104
        $this->assertTrue(feedback_refresh_events());
105
        $eventparams = array('modulename' => 'feedback');
106
        $events = $DB->get_records('event', $eventparams);
107
        foreach ($events as $event) {
108
            if ($event->modulename === 'feedback' && $event->instance === $feedback->id && $event->eventtype === 'open') {
109
                $this->assertEquals($event->timestart, $timeopen);
110
            }
111
            if ($event->modulename === 'feedback' && $event->instance === $feedback->id && $event->eventtype === 'close') {
112
                $this->assertEquals($event->timestart, $timeclose);
113
            }
114
        }
115
    }
116
 
117
    /**
118
     * Test check_updates_since callback.
119
     */
11 efrain 120
    public function test_check_updates_since(): void {
1 efrain 121
        global $DB;
122
 
123
        $this->resetAfterTest();
124
        $this->setAdminUser();
125
        $course = $this->getDataGenerator()->create_course();
126
 
127
        // Create user.
128
        $student = self::getDataGenerator()->create_user();
129
 
130
        // User enrolment.
131
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
132
        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
133
 
134
        $this->setCurrentTimeStart();
135
        $record = array(
136
            'course' => $course->id,
137
            'custom' => 0,
138
            'feedback' => 1,
139
        );
140
        $feedback = $this->getDataGenerator()->create_module('feedback', $record);
141
        $cm = get_coursemodule_from_instance('feedback', $feedback->id, $course->id);
142
        $cm = \cm_info::create($cm);
143
 
144
        $this->setUser($student);
145
        // Check that upon creation, the updates are only about the new configuration created.
146
        $onehourago = time() - HOURSECS;
147
        $updates = feedback_check_updates_since($cm, $onehourago);
148
        foreach ($updates as $el => $val) {
149
            if ($el == 'configuration') {
150
                $this->assertTrue($val->updated);
151
                $this->assertTimeCurrent($val->timeupdated);
152
            } else {
153
                $this->assertFalse($val->updated);
154
            }
155
        }
156
 
157
        $record = [
158
            'feedback' => $feedback->id,
159
            'userid' => $student->id,
160
            'timemodified' => time(),
161
            'random_response' => 0,
162
            'anonymous_response' => FEEDBACK_ANONYMOUS_NO,
163
            'courseid' => $course->id,
164
        ];
165
        $DB->insert_record('feedback_completed', (object)$record);
166
        $DB->insert_record('feedback_completedtmp', (object)$record);
167
 
168
        // Check now for finished and unfinished attempts.
169
        $updates = feedback_check_updates_since($cm, $onehourago);
170
        $this->assertTrue($updates->attemptsunfinished->updated);
171
        $this->assertCount(1, $updates->attemptsunfinished->itemids);
172
 
173
        $this->assertTrue($updates->attemptsfinished->updated);
174
        $this->assertCount(1, $updates->attemptsfinished->itemids);
175
    }
176
 
177
    /**
178
     * Test calendar event provide action open.
179
     */
11 efrain 180
    public function test_feedback_core_calendar_provide_event_action_open(): void {
1 efrain 181
        $this->resetAfterTest();
182
        $this->setAdminUser();
183
 
184
        $now = time();
185
        $course = $this->getDataGenerator()->create_course();
186
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
187
                'timeopen' => $now - DAYSECS, 'timeclose' => $now + DAYSECS]);
188
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
189
 
190
        $factory = new \core_calendar\action_factory();
191
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
192
 
193
        $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
194
        $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
195
        $this->assertInstanceOf('moodle_url', $actionevent->get_url());
196
        $this->assertEquals(1, $actionevent->get_item_count());
197
        $this->assertTrue($actionevent->is_actionable());
198
    }
199
 
200
    /**
201
     * Test calendar event provide action open, viewed by a different user.
202
     */
11 efrain 203
    public function test_feedback_core_calendar_provide_event_action_open_for_user(): void {
1 efrain 204
        global $DB;
205
 
206
        $this->resetAfterTest();
207
        $this->setAdminUser();
208
 
209
        $now = time();
210
        $user = $this->getDataGenerator()->create_user();
211
        $user2 = $this->getDataGenerator()->create_user();
212
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
213
        $course = $this->getDataGenerator()->create_course();
214
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
215
 
216
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
217
            'timeopen' => $now - DAYSECS, 'timeclose' => $now + DAYSECS]);
218
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
219
        $factory = new \core_calendar\action_factory();
220
 
221
        $this->setUser($user2);
222
 
223
        // User2 checking their events.
224
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
225
        $this->assertNull($actionevent);
226
 
227
        // User2 checking $user's events.
228
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
229
        $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
230
        $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
231
        $this->assertInstanceOf('moodle_url', $actionevent->get_url());
232
        $this->assertEquals(1, $actionevent->get_item_count());
233
        $this->assertTrue($actionevent->is_actionable());
234
    }
235
 
236
    /**
237
     * Test calendar event provide action closed.
238
     */
11 efrain 239
    public function test_feedback_core_calendar_provide_event_action_closed(): void {
1 efrain 240
        $this->resetAfterTest();
241
        $this->setAdminUser();
242
 
243
        $course = $this->getDataGenerator()->create_course();
244
        $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id,
245
                'timeclose' => time() - DAYSECS));
246
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
247
 
248
        $factory = new \core_calendar\action_factory();
249
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
250
 
251
        // No event on the dashboard if feedback is closed.
252
        $this->assertNull($actionevent);
253
    }
254
 
255
    /**
256
     * Test calendar event provide action closed, viewed by a different user.
257
     */
11 efrain 258
    public function test_feedback_core_calendar_provide_event_action_closed_for_user(): void {
1 efrain 259
        global $DB;
260
 
261
        $this->resetAfterTest();
262
        $this->setAdminUser();
263
 
264
        $course = $this->getDataGenerator()->create_course();
265
        $user = $this->getDataGenerator()->create_user();
266
        $user2 = $this->getDataGenerator()->create_user();
267
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
268
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
269
 
270
        $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id,
271
            'timeclose' => time() - DAYSECS));
272
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
273
        $factory = new \core_calendar\action_factory();
274
        $this->setUser($user2);
275
 
276
        // User2 checking their events.
277
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
278
        $this->assertNull($actionevent);
279
 
280
        // User2 checking $user's events.
281
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
282
 
283
        // No event on the dashboard if feedback is closed.
284
        $this->assertNull($actionevent);
285
    }
286
 
287
    /**
288
     * Test calendar event action open in future.
289
     *
290
     * @throws coding_exception
291
     */
11 efrain 292
    public function test_feedback_core_calendar_provide_event_action_open_in_future(): void {
1 efrain 293
        $this->resetAfterTest();
294
        $this->setAdminUser();
295
 
296
        $course = $this->getDataGenerator()->create_course();
297
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
298
                'timeopen' => time() + DAYSECS]);
299
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
300
 
301
        $factory = new \core_calendar\action_factory();
302
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
303
 
304
        $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
305
        $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
306
        $this->assertInstanceOf('moodle_url', $actionevent->get_url());
307
        $this->assertEquals(1, $actionevent->get_item_count());
308
        $this->assertFalse($actionevent->is_actionable());
309
    }
310
 
311
    /**
312
     * Test calendar event action open in future, viewed by a different user.
313
     *
314
     * @throws coding_exception
315
     */
11 efrain 316
    public function test_feedback_core_calendar_provide_event_action_open_in_future_for_user(): void {
1 efrain 317
        global $DB;
318
 
319
        $this->resetAfterTest();
320
        $this->setAdminUser();
321
 
322
        $course = $this->getDataGenerator()->create_course();
323
        $user = $this->getDataGenerator()->create_user();
324
        $user2 = $this->getDataGenerator()->create_user();
325
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
326
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
327
 
328
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
329
            'timeopen' => time() + DAYSECS]);
330
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
331
 
332
        $factory = new \core_calendar\action_factory();
333
        $this->setUser($user2);
334
 
335
        // User2 checking their events.
336
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
337
        $this->assertNull($actionevent);
338
 
339
        // User2 checking $user's events.
340
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
341
 
342
        $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
343
        $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
344
        $this->assertInstanceOf('moodle_url', $actionevent->get_url());
345
        $this->assertEquals(1, $actionevent->get_item_count());
346
        $this->assertFalse($actionevent->is_actionable());
347
    }
348
 
349
    /**
350
     * Test calendar event with no time specified.
351
     *
352
     * @throws coding_exception
353
     */
11 efrain 354
    public function test_feedback_core_calendar_provide_event_action_no_time_specified(): void {
1 efrain 355
        $this->resetAfterTest();
356
        $this->setAdminUser();
357
 
358
        $course = $this->getDataGenerator()->create_course();
359
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
360
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
361
 
362
        $factory = new \core_calendar\action_factory();
363
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
364
 
365
        $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
366
        $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
367
        $this->assertInstanceOf('moodle_url', $actionevent->get_url());
368
        $this->assertEquals(1, $actionevent->get_item_count());
369
        $this->assertTrue($actionevent->is_actionable());
370
    }
371
 
372
    /**
373
     * Test calendar event with no time specified, viewed by a different user.
374
     *
375
     * @throws coding_exception
376
     */
11 efrain 377
    public function test_feedback_core_calendar_provide_event_action_no_time_specified_for_user(): void {
1 efrain 378
        global $DB;
379
 
380
        $this->resetAfterTest();
381
        $this->setAdminUser();
382
 
383
        $course = $this->getDataGenerator()->create_course();
384
        $user = $this->getDataGenerator()->create_user();
385
        $user2 = $this->getDataGenerator()->create_user();
386
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
387
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
388
 
389
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
390
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
391
 
392
        $factory = new \core_calendar\action_factory();
393
        $this->setUser($user2);
394
 
395
        // User2 checking their events.
396
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
397
        $this->assertNull($actionevent);
398
 
399
        // User2 checking $user's events.
400
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
401
 
402
        $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
403
        $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
404
        $this->assertInstanceOf('moodle_url', $actionevent->get_url());
405
        $this->assertEquals(1, $actionevent->get_item_count());
406
        $this->assertTrue($actionevent->is_actionable());
407
    }
408
 
409
    /**
410
     * A user that can not submit feedback should not have an action.
411
     */
11 efrain 412
    public function test_feedback_core_calendar_provide_event_action_can_not_submit(): void {
1 efrain 413
        global $DB;
414
 
415
        $this->resetAfterTest();
416
        $this->setAdminUser();
417
 
418
        $user = $this->getDataGenerator()->create_user();
419
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
420
        $course = $this->getDataGenerator()->create_course();
421
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
422
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
423
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
424
        $context = \context_module::instance($cm->id);
425
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
426
 
427
        $this->setUser($user);
428
        assign_capability('mod/feedback:complete', CAP_PROHIBIT, $studentrole->id, $context);
429
 
430
        $factory = new \core_calendar\action_factory();
431
        $action = mod_feedback_core_calendar_provide_event_action($event, $factory);
432
 
433
        $this->assertNull($action);
434
    }
435
 
436
    /**
437
     * A user that can not submit feedback should not have an action, viewed by a different user.
438
     */
11 efrain 439
    public function test_feedback_core_calendar_provide_event_action_can_not_submit_for_user(): void {
1 efrain 440
        global $DB;
441
 
442
        $this->resetAfterTest();
443
        $this->setAdminUser();
444
 
445
        $user = $this->getDataGenerator()->create_user();
446
        $user2 = $this->getDataGenerator()->create_user();
447
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
448
        $course = $this->getDataGenerator()->create_course();
449
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
450
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
451
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
452
        $context = \context_module::instance($cm->id);
453
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
454
 
455
        assign_capability('mod/feedback:complete', CAP_PROHIBIT, $studentrole->id, $context);
456
        $factory = new \core_calendar\action_factory();
457
        $this->setUser($user2);
458
 
459
        // User2 checking their events.
460
 
461
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
462
        $this->assertNull($actionevent);
463
 
464
        // User2 checking $user's events.
465
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
466
 
467
        $this->assertNull($actionevent);
468
    }
469
 
470
    /**
471
     * A user that has already submitted feedback should not have an action.
472
     */
11 efrain 473
    public function test_feedback_core_calendar_provide_event_action_already_submitted(): void {
1 efrain 474
        global $DB;
475
 
476
        $this->resetAfterTest();
477
        $this->setAdminUser();
478
 
479
        $user = $this->getDataGenerator()->create_user();
480
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
481
        $course = $this->getDataGenerator()->create_course();
482
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
483
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
484
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
485
        $context = \context_module::instance($cm->id);
486
 
487
        $this->setUser($user);
488
 
489
        $record = [
490
            'feedback' => $feedback->id,
491
            'userid' => $user->id,
492
            'timemodified' => time(),
493
            'random_response' => 0,
494
            'anonymous_response' => FEEDBACK_ANONYMOUS_NO,
495
            'courseid' => 0,
496
        ];
497
        $DB->insert_record('feedback_completed', (object) $record);
498
 
499
        $factory = new \core_calendar\action_factory();
500
        $action = mod_feedback_core_calendar_provide_event_action($event, $factory);
501
 
502
        $this->assertNull($action);
503
    }
504
 
505
    /**
506
     * A user that has already submitted feedback should not have an action, viewed by a different user.
507
     */
11 efrain 508
    public function test_feedback_core_calendar_provide_event_action_already_submitted_for_user(): void {
1 efrain 509
        global $DB;
510
 
511
        $this->resetAfterTest();
512
        $this->setAdminUser();
513
 
514
        $user = $this->getDataGenerator()->create_user();
515
        $user2 = $this->getDataGenerator()->create_user();
516
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
517
        $course = $this->getDataGenerator()->create_course();
518
        $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
519
        $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
520
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
521
        $context = \context_module::instance($cm->id);
522
 
523
        $this->setUser($user);
524
 
525
        $record = [
526
            'feedback' => $feedback->id,
527
            'userid' => $user->id,
528
            'timemodified' => time(),
529
            'random_response' => 0,
530
            'anonymous_response' => FEEDBACK_ANONYMOUS_NO,
531
            'courseid' => 0,
532
        ];
533
        $DB->insert_record('feedback_completed', (object) $record);
534
 
535
        $factory = new \core_calendar\action_factory();
536
        $this->setUser($user2);
537
 
538
        // User2 checking their events.
539
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
540
        $this->assertNull($actionevent);
541
 
542
        // User2 checking $user's events.
543
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
544
 
545
        $this->assertNull($actionevent);
546
    }
547
 
11 efrain 548
    public function test_feedback_core_calendar_provide_event_action_already_completed(): void {
1 efrain 549
        $this->resetAfterTest();
550
        set_config('enablecompletion', 1);
551
        $this->setAdminUser();
552
 
553
        // Create the activity.
554
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
555
        $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id),
556
            array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
557
 
558
        // Get some additional data.
559
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
560
 
561
        // Create a calendar event.
562
        $event = $this->create_action_event($course->id, $feedback->id,
563
            \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
564
 
565
        // Mark the activity as completed.
566
        $completion = new \completion_info($course);
567
        $completion->set_module_viewed($cm);
568
 
569
        // Create an action factory.
570
        $factory = new \core_calendar\action_factory();
571
 
572
        // Decorate action event.
573
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
574
 
575
        // Ensure result was null.
576
        $this->assertNull($actionevent);
577
    }
578
 
11 efrain 579
    public function test_feedback_core_calendar_provide_event_action_already_completed_for_user(): void {
1 efrain 580
        $this->resetAfterTest();
581
        set_config('enablecompletion', 1);
582
        $this->setAdminUser();
583
 
584
        // Create the activity.
585
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
586
        $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id),
587
            array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
588
 
589
        // Enrol a student in the course.
590
        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
591
 
592
        // Get some additional data.
593
        $cm = get_coursemodule_from_instance('feedback', $feedback->id);
594
 
595
        // Create a calendar event.
596
        $event = $this->create_action_event($course->id, $feedback->id,
597
            \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
598
 
599
        // Mark the activity as completed for the student.
600
        $completion = new \completion_info($course);
601
        $completion->set_module_viewed($cm, $student->id);
602
 
603
        // Create an action factory.
604
        $factory = new \core_calendar\action_factory();
605
 
606
        // Decorate action event for the student.
607
        $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $student->id);
608
 
609
        // Ensure result was null.
610
        $this->assertNull($actionevent);
611
    }
612
 
613
    /**
614
     * Creates an action event.
615
     *
616
     * @param int $courseid The course id.
617
     * @param int $instanceid The feedback id.
618
     * @param string $eventtype The event type. eg. FEEDBACK_EVENT_TYPE_OPEN.
619
     * @return bool|calendar_event
620
     */
621
    private function create_action_event($courseid, $instanceid, $eventtype) {
622
        $event = new \stdClass();
623
        $event->name = 'Calendar event';
624
        $event->modulename = 'feedback';
625
        $event->courseid = $courseid;
626
        $event->instance = $instanceid;
627
        $event->type = CALENDAR_EVENT_TYPE_ACTION;
628
        $event->eventtype = $eventtype;
629
        $event->timestart = time();
630
 
631
        return \calendar_event::create($event);
632
    }
633
 
634
    /**
635
     * Test the callback responsible for returning the completion rule descriptions.
636
     * This function should work given either an instance of the module (cm_info), such as when checking the active rules,
637
     * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
638
     */
11 efrain 639
    public function test_mod_feedback_completion_get_active_rule_descriptions(): void {
1 efrain 640
        $this->resetAfterTest();
641
        $this->setAdminUser();
642
 
643
        // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
644
        $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
645
        $feedback1 = $this->getDataGenerator()->create_module('feedback', [
646
            'course' => $course->id,
647
            'completion' => 2,
648
            'completionsubmit' => 1
649
        ]);
650
        $feedback2 = $this->getDataGenerator()->create_module('feedback', [
651
            'course' => $course->id,
652
            'completion' => 2,
653
            'completionsubmit' => 0
654
        ]);
655
        $cm1 = \cm_info::create(get_coursemodule_from_instance('feedback', $feedback1->id));
656
        $cm2 = \cm_info::create(get_coursemodule_from_instance('feedback', $feedback2->id));
657
 
658
        // Data for the stdClass input type.
659
        // This type of input would occur when checking the default completion rules for an activity type, where we don't have
660
        // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
661
        $moddefaults = new \stdClass();
662
        $moddefaults->customdata = ['customcompletionrules' => ['completionsubmit' => 1]];
663
        $moddefaults->completion = 2;
664
 
665
        $activeruledescriptions = [get_string('completionsubmit', 'feedback')];
666
        $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
667
        $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions($cm2), []);
668
        $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
669
        $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions(new \stdClass()), []);
670
    }
671
 
672
    /**
673
     * An unknown event should not have min or max restrictions.
674
     */
11 efrain 675
    public function test_get_valid_event_timestart_range_unknown_event(): void {
1 efrain 676
        global $CFG, $DB;
677
        require_once($CFG->dirroot . "/calendar/lib.php");
678
 
679
        $this->resetAfterTest(true);
680
        $this->setAdminUser();
681
        $generator = $this->getDataGenerator();
682
        $course = $generator->create_course();
683
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
684
        $timeopen = time();
685
        $timeclose = $timeopen + DAYSECS;
686
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
687
        $feedback->timeopen = $timeopen;
688
        $feedback->timeclose = $timeclose;
689
        $DB->update_record('feedback', $feedback);
690
 
691
        $event = new \calendar_event([
692
            'name' => 'Test event',
693
            'description' => '',
694
            'format' => 1,
695
            'courseid' => $course->id,
696
            'groupid' => 0,
697
            'userid' => 2,
698
            'modulename' => 'feedback',
699
            'instance' => $feedback->id,
700
            'eventtype' => 'SOME UNKNOWN EVENT',
701
            'timestart' => $timeopen,
702
            'timeduration' => 86400,
703
            'visible' => 1
704
        ]);
705
 
706
        list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
707
        $this->assertNull($min);
708
        $this->assertNull($max);
709
    }
710
 
711
    /**
712
     * A FEEDBACK_EVENT_TYPE_OPEN should have a max timestart equal to the activity
713
     * close time.
714
     */
11 efrain 715
    public function test_get_valid_event_timestart_range_event_type_open(): void {
1 efrain 716
        global $CFG, $DB;
717
        require_once($CFG->dirroot . "/calendar/lib.php");
718
 
719
        $this->resetAfterTest(true);
720
        $this->setAdminUser();
721
        $generator = $this->getDataGenerator();
722
        $course = $generator->create_course();
723
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
724
        $timeopen = time();
725
        $timeclose = $timeopen + DAYSECS;
726
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
727
        $feedback->timeopen = $timeopen;
728
        $feedback->timeclose = $timeclose;
729
        $DB->update_record('feedback', $feedback);
730
 
731
        $event = new \calendar_event([
732
            'name' => 'Test event',
733
            'description' => '',
734
            'format' => 1,
735
            'courseid' => $course->id,
736
            'groupid' => 0,
737
            'userid' => 2,
738
            'modulename' => 'feedback',
739
            'instance' => $feedback->id,
740
            'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
741
            'timestart' => $timeopen,
742
            'timeduration' => 86400,
743
            'visible' => 1
744
        ]);
745
 
746
        list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
747
        $this->assertNull($min);
748
        $this->assertEquals($timeclose, $max[0]);
749
        $this->assertNotEmpty($max[1]);
750
    }
751
 
752
    /**
753
     * A FEEDBACK_EVENT_TYPE_OPEN should not have a max timestamp if the activity
754
     * doesn't have a close date.
755
     */
11 efrain 756
    public function test_get_valid_event_timestart_range_event_type_open_no_close(): void {
1 efrain 757
        global $CFG, $DB;
758
        require_once($CFG->dirroot . "/calendar/lib.php");
759
 
760
        $this->resetAfterTest(true);
761
        $this->setAdminUser();
762
        $generator = $this->getDataGenerator();
763
        $course = $generator->create_course();
764
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
765
        $timeopen = time();
766
        $timeclose = $timeopen + DAYSECS;
767
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
768
        $feedback->timeopen = $timeopen;
769
        $feedback->timeclose = 0;
770
        $DB->update_record('feedback', $feedback);
771
 
772
        $event = new \calendar_event([
773
            'name' => 'Test event',
774
            'description' => '',
775
            'format' => 1,
776
            'courseid' => $course->id,
777
            'groupid' => 0,
778
            'userid' => 2,
779
            'modulename' => 'feedback',
780
            'instance' => $feedback->id,
781
            'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
782
            'timestart' => $timeopen,
783
            'timeduration' => 86400,
784
            'visible' => 1
785
        ]);
786
 
787
        list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
788
        $this->assertNull($min);
789
        $this->assertNull($max);
790
    }
791
 
792
    /**
793
     * A FEEDBACK_EVENT_TYPE_CLOSE should have a min timestart equal to the activity
794
     * open time.
795
     */
11 efrain 796
    public function test_get_valid_event_timestart_range_event_type_close(): void {
1 efrain 797
        global $CFG, $DB;
798
        require_once($CFG->dirroot . "/calendar/lib.php");
799
 
800
        $this->resetAfterTest(true);
801
        $this->setAdminUser();
802
        $generator = $this->getDataGenerator();
803
        $course = $generator->create_course();
804
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
805
        $timeopen = time();
806
        $timeclose = $timeopen + DAYSECS;
807
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
808
        $feedback->timeopen = $timeopen;
809
        $feedback->timeclose = $timeclose;
810
        $DB->update_record('feedback', $feedback);
811
 
812
        $event = new \calendar_event([
813
            'name' => 'Test event',
814
            'description' => '',
815
            'format' => 1,
816
            'courseid' => $course->id,
817
            'groupid' => 0,
818
            'userid' => 2,
819
            'modulename' => 'feedback',
820
            'instance' => $feedback->id,
821
            'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
822
            'timestart' => $timeopen,
823
            'timeduration' => 86400,
824
            'visible' => 1
825
        ]);
826
 
827
        list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
828
        $this->assertEquals($timeopen, $min[0]);
829
        $this->assertNotEmpty($min[1]);
830
        $this->assertNull($max);
831
    }
832
 
833
    /**
834
     * A FEEDBACK_EVENT_TYPE_CLOSE should not have a minimum timestamp if the activity
835
     * doesn't have an open date.
836
     */
11 efrain 837
    public function test_get_valid_event_timestart_range_event_type_close_no_open(): void {
1 efrain 838
        global $CFG, $DB;
839
        require_once($CFG->dirroot . "/calendar/lib.php");
840
 
841
        $this->resetAfterTest(true);
842
        $this->setAdminUser();
843
        $generator = $this->getDataGenerator();
844
        $course = $generator->create_course();
845
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
846
        $timeopen = time();
847
        $timeclose = $timeopen + DAYSECS;
848
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
849
        $feedback->timeopen = 0;
850
        $feedback->timeclose = $timeclose;
851
        $DB->update_record('feedback', $feedback);
852
 
853
        $event = new \calendar_event([
854
            'name' => 'Test event',
855
            'description' => '',
856
            'format' => 1,
857
            'courseid' => $course->id,
858
            'groupid' => 0,
859
            'userid' => 2,
860
            'modulename' => 'feedback',
861
            'instance' => $feedback->id,
862
            'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
863
            'timestart' => $timeopen,
864
            'timeduration' => 86400,
865
            'visible' => 1
866
        ]);
867
 
868
        list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
869
        $this->assertNull($min);
870
        $this->assertNull($max);
871
    }
872
 
873
    /**
874
     * An unkown event type should not change the feedback instance.
875
     */
11 efrain 876
    public function test_mod_feedback_core_calendar_event_timestart_updated_unknown_event(): void {
1 efrain 877
        global $CFG, $DB;
878
        require_once($CFG->dirroot . "/calendar/lib.php");
879
 
880
        $this->resetAfterTest(true);
881
        $this->setAdminUser();
882
        $generator = $this->getDataGenerator();
883
        $course = $generator->create_course();
884
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
885
        $timeopen = time();
886
        $timeclose = $timeopen + DAYSECS;
887
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
888
        $feedback->timeopen = $timeopen;
889
        $feedback->timeclose = $timeclose;
890
        $DB->update_record('feedback', $feedback);
891
 
892
        // Create a valid event.
893
        $event = new \calendar_event([
894
            'name' => 'Test event',
895
            'description' => '',
896
            'format' => 1,
897
            'courseid' => $course->id,
898
            'groupid' => 0,
899
            'userid' => 2,
900
            'modulename' => 'feedback',
901
            'instance' => $feedback->id,
902
            'eventtype' => FEEDBACK_EVENT_TYPE_OPEN . "SOMETHING ELSE",
903
            'timestart' => 1,
904
            'timeduration' => 86400,
905
            'visible' => 1
906
        ]);
907
 
908
        mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
909
 
910
        $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
911
        $this->assertEquals($timeopen, $feedback->timeopen);
912
        $this->assertEquals($timeclose, $feedback->timeclose);
913
    }
914
 
915
    /**
916
     * A FEEDBACK_EVENT_TYPE_OPEN event should update the timeopen property of
917
     * the feedback activity.
918
     */
11 efrain 919
    public function test_mod_feedback_core_calendar_event_timestart_updated_open_event(): void {
1 efrain 920
        global $CFG, $DB;
921
        require_once($CFG->dirroot . "/calendar/lib.php");
922
 
923
        $this->resetAfterTest(true);
924
        $this->setAdminUser();
925
        $generator = $this->getDataGenerator();
926
        $course = $generator->create_course();
927
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
928
        $timeopen = time();
929
        $timeclose = $timeopen + DAYSECS;
930
        $timemodified = 1;
931
        $newtimeopen = $timeopen - DAYSECS;
932
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
933
        $feedback->timeopen = $timeopen;
934
        $feedback->timeclose = $timeclose;
935
        $feedback->timemodified = $timemodified;
936
        $DB->update_record('feedback', $feedback);
937
 
938
        // Create a valid event.
939
        $event = new \calendar_event([
940
            'name' => 'Test event',
941
            'description' => '',
942
            'format' => 1,
943
            'courseid' => $course->id,
944
            'groupid' => 0,
945
            'userid' => 2,
946
            'modulename' => 'feedback',
947
            'instance' => $feedback->id,
948
            'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
949
            'timestart' => $newtimeopen,
950
            'timeduration' => 86400,
951
            'visible' => 1
952
        ]);
953
 
954
        mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
955
 
956
        $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
957
        // Ensure the timeopen property matches the event timestart.
958
        $this->assertEquals($newtimeopen, $feedback->timeopen);
959
        // Ensure the timeclose isn't changed.
960
        $this->assertEquals($timeclose, $feedback->timeclose);
961
        // Ensure the timemodified property has been changed.
962
        $this->assertNotEquals($timemodified, $feedback->timemodified);
963
    }
964
 
965
    /**
966
     * A FEEDBACK_EVENT_TYPE_CLOSE event should update the timeclose property of
967
     * the feedback activity.
968
     */
11 efrain 969
    public function test_mod_feedback_core_calendar_event_timestart_updated_close_event(): void {
1 efrain 970
        global $CFG, $DB;
971
        require_once($CFG->dirroot . "/calendar/lib.php");
972
 
973
        $this->resetAfterTest(true);
974
        $this->setAdminUser();
975
        $generator = $this->getDataGenerator();
976
        $course = $generator->create_course();
977
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
978
        $timeopen = time();
979
        $timeclose = $timeopen + DAYSECS;
980
        $timemodified = 1;
981
        $newtimeclose = $timeclose + DAYSECS;
982
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
983
        $feedback->timeopen = $timeopen;
984
        $feedback->timeclose = $timeclose;
985
        $feedback->timemodified = $timemodified;
986
        $DB->update_record('feedback', $feedback);
987
 
988
        // Create a valid event.
989
        $event = new \calendar_event([
990
            'name' => 'Test event',
991
            'description' => '',
992
            'format' => 1,
993
            'courseid' => $course->id,
994
            'groupid' => 0,
995
            'userid' => 2,
996
            'modulename' => 'feedback',
997
            'instance' => $feedback->id,
998
            'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
999
            'timestart' => $newtimeclose,
1000
            'timeduration' => 86400,
1001
            'visible' => 1
1002
        ]);
1003
 
1004
        mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
1005
 
1006
        $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1007
        // Ensure the timeclose property matches the event timestart.
1008
        $this->assertEquals($newtimeclose, $feedback->timeclose);
1009
        // Ensure the timeopen isn't changed.
1010
        $this->assertEquals($timeopen, $feedback->timeopen);
1011
        // Ensure the timemodified property has been changed.
1012
        $this->assertNotEquals($timemodified, $feedback->timemodified);
1013
    }
1014
 
1015
    /**
1016
     * If a student somehow finds a way to update the calendar event
1017
     * then the callback should not be executed to update the activity
1018
     * properties as well because that would be a security issue.
1019
     */
11 efrain 1020
    public function test_student_role_cant_update_time_close_event(): void {
1 efrain 1021
        global $CFG, $DB;
1022
        require_once($CFG->dirroot . '/calendar/lib.php');
1023
 
1024
        $this->resetAfterTest();
1025
        $this->setAdminUser();
1026
 
1027
        $generator = $this->getDataGenerator();
1028
        $user = $generator->create_user();
1029
        $course = $generator->create_course();
1030
        $context = \context_course::instance($course->id);
1031
        $roleid = $generator->create_role();
1032
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
1033
        $timeopen = time();
1034
        $timeclose = $timeopen + DAYSECS;
1035
        $timemodified = 1;
1036
        $newtimeclose = $timeclose + DAYSECS;
1037
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
1038
        $feedback->timeopen = $timeopen;
1039
        $feedback->timeclose = $timeclose;
1040
        $feedback->timemodified = $timemodified;
1041
        $DB->update_record('feedback', $feedback);
1042
 
1043
        $generator->enrol_user($user->id, $course->id, 'student');
1044
        $generator->role_assign($roleid, $user->id, $context->id);
1045
 
1046
        // Create a valid event.
1047
        $event = new \calendar_event([
1048
            'name' => 'Test event',
1049
            'description' => '',
1050
            'format' => 1,
1051
            'courseid' => $course->id,
1052
            'groupid' => 0,
1053
            'userid' => $user->id,
1054
            'modulename' => 'feedback',
1055
            'instance' => $feedback->id,
1056
            'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
1057
            'timestart' => $newtimeclose,
1058
            'timeduration' => 86400,
1059
            'visible' => 1
1060
        ]);
1061
 
1062
        assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1063
        assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $roleid, $context, true);
1064
 
1065
        $this->setUser($user);
1066
 
1067
        mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
1068
 
1069
        $newfeedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1070
        // The activity shouldn't have been updated because the user
1071
        // doesn't have permissions to do it.
1072
        $this->assertEquals($timeclose, $newfeedback->timeclose);
1073
    }
1074
 
1075
    /**
1076
     * The activity should update if a teacher modifies the calendar
1077
     * event.
1078
     */
11 efrain 1079
    public function test_teacher_role_can_update_time_close_event(): void {
1 efrain 1080
        global $CFG, $DB;
1081
        require_once($CFG->dirroot . '/calendar/lib.php');
1082
 
1083
        $this->resetAfterTest();
1084
        $this->setAdminUser();
1085
 
1086
        $generator = $this->getDataGenerator();
1087
        $user = $generator->create_user();
1088
        $course = $generator->create_course();
1089
        $context = \context_course::instance($course->id);
1090
        $roleid = $generator->create_role();
1091
        $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
1092
        $timeopen = time();
1093
        $timeclose = $timeopen + DAYSECS;
1094
        $timemodified = 1;
1095
        $newtimeclose = $timeclose + DAYSECS;
1096
        $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
1097
        $feedback->timeopen = $timeopen;
1098
        $feedback->timeclose = $timeclose;
1099
        $feedback->timemodified = $timemodified;
1100
        $DB->update_record('feedback', $feedback);
1101
 
1102
        $generator->enrol_user($user->id, $course->id, 'teacher');
1103
        $generator->role_assign($roleid, $user->id, $context->id);
1104
 
1105
        // Create a valid event.
1106
        $event = new \calendar_event([
1107
            'name' => 'Test event',
1108
            'description' => '',
1109
            'format' => 1,
1110
            'courseid' => $course->id,
1111
            'groupid' => 0,
1112
            'userid' => $user->id,
1113
            'modulename' => 'feedback',
1114
            'instance' => $feedback->id,
1115
            'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
1116
            'timestart' => $newtimeclose,
1117
            'timeduration' => 86400,
1118
            'visible' => 1
1119
        ]);
1120
 
1121
        assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1122
        assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleid, $context, true);
1123
 
1124
        $this->setUser($user);
1125
 
1126
        $sink = $this->redirectEvents();
1127
 
1128
        mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
1129
 
1130
        $triggeredevents = $sink->get_events();
1131
        $moduleupdatedevents = array_filter($triggeredevents, function($e) {
1132
            return is_a($e, 'core\event\course_module_updated');
1133
        });
1134
 
1135
        $newfeedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1136
        // The activity should have been updated because the user
1137
        // has permissions to do it.
1138
        $this->assertEquals($newtimeclose, $newfeedback->timeclose);
1139
        // A course_module_updated event should be fired if the module
1140
        // was successfully modified.
1141
        $this->assertNotEmpty($moduleupdatedevents);
1142
    }
1143
 
1144
    /**
1145
     * A user who does not have capabilities to add events to the calendar should be able to create an feedback.
1146
     */
11 efrain 1147
    public function test_creation_with_no_calendar_capabilities(): void {
1 efrain 1148
        $this->resetAfterTest();
1149
        $course = self::getDataGenerator()->create_course();
1150
        $context = \context_course::instance($course->id);
1151
        $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher');
1152
        $roleid = self::getDataGenerator()->create_role();
1153
        self::getDataGenerator()->role_assign($roleid, $user->id, $context->id);
1154
        assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
1155
        $generator = self::getDataGenerator()->get_plugin_generator('mod_feedback');
1156
        // Create an instance as a user without the calendar capabilities.
1157
        $this->setUser($user);
1158
        $time = time();
1159
        $params = array(
1160
            'course' => $course->id,
1161
            'timeopen' => $time + 200,
1162
            'timeclose' => $time + 2000,
1163
        );
1164
        $generator->create_instance($params);
1165
    }
1166
}