Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | 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 mod_data;
18
 
19
use externallib_advanced_testcase;
20
use mod_data_external;
21
use core_external\external_api;
22
use core_external\external_settings;
23
 
24
defined('MOODLE_INTERNAL') || die();
25
 
26
global $CFG;
27
 
28
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
29
 
30
/**
31
 * Database module external functions tests
32
 *
33
 * @package    mod_data
34
 * @category   external
35
 * @copyright  2015 Juan Leyva <juan@moodle.com>
36
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 * @since      Moodle 2.9
38
 * @coversDefaultClass \mod_data_external
39
 */
40
class externallib_test extends externallib_advanced_testcase {
41
 
42
    /** @var stdClass Test module context. */
43
    protected $context;
44
 
45
    /** @var stdClass Test course.*/
46
    protected $course;
47
 
48
    /** @var stdClass Test course module. */
49
    protected $cm;
50
 
51
    /** @var  stdClass Test database activity. */
52
    protected $database;
53
 
54
    /** @var stdClass Test group 1. */
55
    protected $group1;
56
 
57
    /** @var stdClass Test group 2. */
58
    protected $group2;
59
 
60
    /** @var stdClass Test student 1. */
61
    protected $student1;
62
 
63
    /** @var stdClass Test student 2. */
64
    protected $student2;
65
 
66
    /** @var stdClass Test student 3. */
67
    protected $student3;
68
 
69
    /** @var stdClass Test student 4. */
70
    protected $student4;
71
 
72
    /** @var stdClass Student role. */
73
    protected $studentrole;
74
 
75
    /** @var stdClass Test teacher. */
76
    protected $teacher;
77
 
78
    /** @var stdClass Teacher role. */
79
    protected $teacherrole;
80
 
81
    /**
82
     * Set up for every test
83
     */
84
    public function setUp(): void {
85
        global $DB;
86
        $this->resetAfterTest();
87
        $this->setAdminUser();
88
 
89
        // Setup test data.
90
        $course = new \stdClass();
91
        $course->groupmode = SEPARATEGROUPS;
92
        $course->groupmodeforce = true;
93
        $this->course = $this->getDataGenerator()->create_course($course);
94
        $this->database = $this->getDataGenerator()->create_module('data', array('course' => $this->course->id));
95
        $this->context = \context_module::instance($this->database->cmid);
96
        $this->cm = get_coursemodule_from_instance('data', $this->database->id);
97
 
98
        // Create users.
99
        $this->student1 = self::getDataGenerator()->create_user(['firstname' => 'Olivia', 'lastname' => 'Smith']);
100
        $this->student2 = self::getDataGenerator()->create_user(['firstname' => 'Ezra', 'lastname' => 'Johnson']);
101
        $this->student3 = self::getDataGenerator()->create_user(['firstname' => 'Amelia', 'lastname' => 'Williams']);
102
        $this->teacher = self::getDataGenerator()->create_user(['firstname' => 'Asher', 'lastname' => 'Jones']);
103
 
104
        // Users enrolments.
105
        $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
106
        $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
107
        $this->getDataGenerator()->enrol_user($this->student1->id, $this->course->id, $this->studentrole->id, 'manual');
108
        $this->getDataGenerator()->enrol_user($this->student2->id, $this->course->id, $this->studentrole->id, 'manual');
109
        $this->getDataGenerator()->enrol_user($this->student3->id, $this->course->id, $this->studentrole->id, 'manual');
110
        $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
111
 
112
        $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
113
        $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
114
        groups_add_member($this->group1, $this->student1);
115
        groups_add_member($this->group1, $this->student2);
116
        groups_add_member($this->group2, $this->student3);
117
    }
118
 
119
    /**
120
     * Add a test field to the database activity instance to be used in the unit tests.
121
     *
122
     * @return \data_field_base
123
     */
124
    protected function add_test_field(): \data_field_base {
125
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
126
 
127
        // Add fields.
128
        $fieldrecord = new \stdClass();
129
        $fieldrecord->name = 'Test field'; // Identifier of the records for testing.
130
        $fieldrecord->type = 'text';
131
        return $generator->create_field($fieldrecord, $this->database);
132
    }
133
 
134
    /**
135
     * Test get databases by courses
136
     */
137
    public function test_mod_data_get_databases_by_courses() {
138
        global $DB;
139
 
140
        $this->resetAfterTest(true);
141
 
142
        // Create users.
143
        $student = self::getDataGenerator()->create_user();
144
        $teacher = self::getDataGenerator()->create_user();
145
 
146
        // Set to the student user.
147
        self::setUser($student);
148
 
149
        // Create courses to add the modules.
150
        $course1 = self::getDataGenerator()->create_course();
151
        $course2 = self::getDataGenerator()->create_course();
152
 
153
        // First database.
154
        $record = new \stdClass();
155
        $record->introformat = FORMAT_HTML;
156
        $record->course = $course1->id;
157
        // Set multilang text to check that is properly filtered to "en" only.
158
        $record->name = '<span lang="en" class="multilang">English</span><span lang="es" class="multilang">Español</span>';
159
        $record->intro = '<button>Test with HTML allowed.</button>';
160
        $database1 = self::getDataGenerator()->create_module('data', $record);
161
 
162
        // Second database.
163
        $record = new \stdClass();
164
        $record->introformat = FORMAT_HTML;
165
        $record->course = $course2->id;
166
        $database2 = self::getDataGenerator()->create_module('data', $record);
167
 
168
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
169
        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
170
 
171
        // Users enrolments.
172
        $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
173
        $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual');
174
 
175
        // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
176
        $enrol = enrol_get_plugin('manual');
177
        $enrolinstances = enrol_get_instances($course2->id, true);
178
        foreach ($enrolinstances as $courseenrolinstance) {
179
            if ($courseenrolinstance->enrol == "manual") {
180
                $instance2 = $courseenrolinstance;
181
                break;
182
            }
183
        }
184
        $enrol->enrol_user($instance2, $student->id, $studentrole->id);
185
 
186
        // Enable multilang filter to on content and heading.
187
        \filter_manager::reset_caches();
188
        filter_set_global_state('multilang', TEXTFILTER_ON);
189
        filter_set_applies_to_strings('multilang', true);
190
        // Set WS filtering.
191
        $wssettings = external_settings::get_instance();
192
        $wssettings->set_filter(true);
193
 
194
        // Create what we expect to be returned when querying the two courses.
195
        // First for the student user.
196
        $expectedfields = array('id', 'coursemodule', 'course', 'name', 'comments', 'timeavailablefrom',
197
                            'timeavailableto', 'timeviewfrom', 'timeviewto', 'requiredentries', 'requiredentriestoview',
198
                            'intro', 'introformat', 'introfiles', 'lang',
199
                            'maxentries', 'rssarticles', 'singletemplate', 'listtemplate',
200
                            'listtemplateheader', 'listtemplatefooter', 'addtemplate', 'rsstemplate', 'rsstitletemplate',
201
                            'csstemplate', 'jstemplate', 'asearchtemplate', 'approval',
202
                            'defaultsort', 'defaultsortdir', 'manageapproved');
203
 
204
        // Add expected coursemodule.
205
        $database1->coursemodule = $database1->cmid;
206
        $database1->introfiles = [];
207
        $database1->lang = '';
208
        $database2->coursemodule = $database2->cmid;
209
        $database2->introfiles = [];
210
        $database2->lang = '';
211
 
212
        $expected1 = array();
213
        $expected2 = array();
214
        foreach ($expectedfields as $field) {
215
            if ($field == 'approval' or $field == 'manageapproved') {
216
                $database1->{$field} = (bool) $database1->{$field};
217
                $database2->{$field} = (bool) $database2->{$field};
218
            }
219
            $expected1[$field] = $database1->{$field};
220
            $expected2[$field] = $database2->{$field};
221
        }
222
        $expected1['name'] = 'English'; // Lang filtered expected.
223
        $expected1['comments'] = (bool) $expected1['comments'];
224
        $expected2['comments'] = (bool) $expected2['comments'];
225
 
226
        $expecteddatabases = array();
227
        $expecteddatabases[] = $expected2;
228
        $expecteddatabases[] = $expected1;
229
 
230
        // Call the external function passing course ids.
231
        $result = mod_data_external::get_databases_by_courses(array($course2->id, $course1->id));
232
        $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
233
        $this->assertEquals($expecteddatabases, $result['databases']);
234
 
235
        // Call the external function without passing course id.
236
        $result = mod_data_external::get_databases_by_courses();
237
        $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
238
        $this->assertEquals($expecteddatabases, $result['databases']);
239
 
240
        // Unenrol user from second course and alter expected databases.
241
        $enrol->unenrol_user($instance2, $student->id);
242
        array_shift($expecteddatabases);
243
 
244
        // Call the external function without passing course id.
245
        $result = mod_data_external::get_databases_by_courses();
246
        $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
247
        $this->assertEquals($expecteddatabases, $result['databases']);
248
 
249
        // Call for the second course we unenrolled the user from, expected warning.
250
        $result = mod_data_external::get_databases_by_courses(array($course2->id));
251
        $this->assertCount(1, $result['warnings']);
252
        $this->assertEquals('1', $result['warnings'][0]['warningcode']);
253
        $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
254
 
255
        // Now, try as a teacher for getting all the additional fields.
256
        self::setUser($teacher);
257
 
258
        $additionalfields = array('scale', 'assessed', 'assesstimestart', 'assesstimefinish', 'editany', 'notification', 'timemodified');
259
 
260
        foreach ($additionalfields as $field) {
261
            if ($field == 'editany') {
262
                $database1->{$field} = (bool) $database1->{$field};
263
            }
264
            $expecteddatabases[0][$field] = $database1->{$field};
265
        }
266
        $result = mod_data_external::get_databases_by_courses();
267
        $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
268
        $this->assertEquals($expecteddatabases, $result['databases']);
269
 
270
        // Admin should get all the information.
271
        self::setAdminUser();
272
 
273
        $result = mod_data_external::get_databases_by_courses(array($course1->id));
274
        $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
275
        $this->assertEquals($expecteddatabases, $result['databases']);
276
    }
277
 
278
    /**
279
     * Test view_database invalid id.
280
     */
281
    public function test_view_database_invalid_id() {
282
 
283
        // Test invalid instance id.
284
        $this->expectException('moodle_exception');
285
        mod_data_external::view_database(0);
286
    }
287
 
288
    /**
289
     * Test view_database not enrolled user.
290
     */
291
    public function test_view_database_not_enrolled_user() {
292
 
293
        $usernotenrolled = self::getDataGenerator()->create_user();
294
        $this->setUser($usernotenrolled);
295
 
296
        $this->expectException('moodle_exception');
297
        mod_data_external::view_database(0);
298
    }
299
 
300
    /**
301
     * Test view_database no capabilities.
302
     */
303
    public function test_view_database_no_capabilities() {
304
        // Test user with no capabilities.
305
        // We need a explicit prohibit since this capability is allowed for students by default.
306
        assign_capability('mod/data:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
307
        accesslib_clear_all_caches_for_unit_testing();
308
 
309
        $this->expectException('moodle_exception');
310
        mod_data_external::view_database(0);
311
    }
312
 
313
    /**
314
     * Test view_database.
315
     */
316
    public function test_view_database() {
317
 
318
        // Test user with full capabilities.
319
        $this->setUser($this->student1);
320
 
321
        // Trigger and capture the event.
322
        $sink = $this->redirectEvents();
323
 
324
        $result = mod_data_external::view_database($this->database->id);
325
        $result = external_api::clean_returnvalue(mod_data_external::view_database_returns(), $result);
326
 
327
        $events = $sink->get_events();
328
        $this->assertCount(1, $events);
329
        $event = array_shift($events);
330
 
331
        // Checking that the event contains the expected values.
332
        $this->assertInstanceOf('\mod_data\event\course_module_viewed', $event);
333
        $this->assertEquals($this->context, $event->get_context());
334
        $moodledata = new \moodle_url('/mod/data/view.php', array('id' => $this->cm->id));
335
        $this->assertEquals($moodledata, $event->get_url());
336
        $this->assertEventContextNotUsed($event);
337
        $this->assertNotEmpty($event->get_name());
338
    }
339
 
340
    /**
341
     * Test get_data_access_information for student.
342
     */
343
    public function test_get_data_access_information_student() {
344
        global $DB;
345
 
346
        // Add a field to database to let users add new entries.
347
        $this->add_test_field();
348
 
349
        // Modify the database to add access restrictions.
350
        $this->database->timeavailablefrom = time() + DAYSECS;
351
        $this->database->requiredentries = 2;
352
        $this->database->requiredentriestoview = 2;
353
        $DB->update_record('data', $this->database);
354
 
355
        // Test user with full capabilities.
356
        $this->setUser($this->student1);
357
 
358
        $result = mod_data_external::get_data_access_information($this->database->id);
359
        $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
360
 
361
        $this->assertEquals($this->group1->id, $result['groupid']);
362
 
363
        $this->assertFalse($result['canmanageentries']);
364
        $this->assertFalse($result['canapprove']);
365
        $this->assertTrue($result['canaddentry']);  // It return true because it doen't check time restrictions.
366
        $this->assertFalse($result['timeavailable']);
367
        $this->assertFalse($result['inreadonlyperiod']);
368
        $this->assertEquals(0, $result['numentries']);
369
        $this->assertEquals($this->database->requiredentries, $result['entrieslefttoadd']);
370
        $this->assertEquals($this->database->requiredentriestoview, $result['entrieslefttoview']);
371
    }
372
 
373
    /**
374
     * Test get_data_access_information for teacher.
375
     */
376
    public function test_get_data_access_information_teacher() {
377
        global $DB;
378
 
379
        // Add a field to database to let users add new entries.
380
        $this->add_test_field();
381
 
382
        // Modify the database to add access restrictions.
383
        $this->database->timeavailablefrom = time() + DAYSECS;
384
        $this->database->requiredentries = 2;
385
        $this->database->requiredentriestoview = 2;
386
        $DB->update_record('data', $this->database);
387
 
388
        // Test user with full capabilities.
389
        $this->setUser($this->teacher);
390
 
391
        $result = mod_data_external::get_data_access_information($this->database->id);
392
        $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
393
 
394
        $this->assertEquals(0, $result['groupid']);
395
 
396
        $this->assertTrue($result['canmanageentries']);
397
        $this->assertTrue($result['canapprove']);
398
        $this->assertTrue($result['canaddentry']);  // It return true because it doen't check time restrictions.
399
        $this->assertTrue($result['timeavailable']);
400
        $this->assertFalse($result['inreadonlyperiod']);
401
        $this->assertEquals(0, $result['numentries']);
402
        $this->assertEquals(0, $result['entrieslefttoadd']);
403
        $this->assertEquals(0, $result['entrieslefttoview']);
404
    }
405
 
406
    /**
407
     * Test get_data_access_information with groups.
408
     */
409
    public function test_get_data_access_information_groups() {
410
        global $DB;
411
 
412
        // Add a field to database to let users add new entries.
413
        $this->add_test_field();
414
 
415
        $DB->set_field('course', 'groupmode', VISIBLEGROUPS, ['id' => $this->course->id]);
416
 
417
        // Check I can see my group.
418
        $this->setUser($this->student1);
419
 
420
        $result = mod_data_external::get_data_access_information($this->database->id);
421
        $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
422
 
423
        $this->assertEquals($this->group1->id, $result['groupid']); // My group is correctly found.
424
        $this->assertFalse($result['canmanageentries']);
425
        $this->assertFalse($result['canapprove']);
426
        $this->assertTrue($result['canaddentry']);  // I can entries in my groups.
427
        $this->assertTrue($result['timeavailable']);
428
        $this->assertFalse($result['inreadonlyperiod']);
429
        $this->assertEquals(0, $result['numentries']);
430
        $this->assertEquals(0, $result['entrieslefttoadd']);
431
        $this->assertEquals(0, $result['entrieslefttoview']);
432
 
433
        // Check the other course group in visible groups mode.
434
        $result = mod_data_external::get_data_access_information($this->database->id, $this->group2->id);
435
        $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
436
 
437
        $this->assertEquals($this->group2->id, $result['groupid']); // The group is correctly found.
438
        $this->assertFalse($result['canmanageentries']);
439
        $this->assertFalse($result['canapprove']);
440
        $this->assertFalse($result['canaddentry']);  // I cannot add entries in other groups.
441
        $this->assertTrue($result['timeavailable']);
442
        $this->assertFalse($result['inreadonlyperiod']);
443
        $this->assertEquals(0, $result['numentries']);
444
        $this->assertEquals(0, $result['entrieslefttoadd']);
445
        $this->assertEquals(0, $result['entrieslefttoview']);
446
    }
447
 
448
    /**
449
     * Helper method to populate the database with some entries.
450
     *
451
     * @return array the entry ids created
452
     */
453
    public function populate_database_with_entries() {
454
        global $DB;
455
 
456
        // Force approval.
457
        $DB->set_field('data', 'approval', 1, array('id' => $this->database->id));
458
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
459
        $fieldtypes = array('checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url');
460
 
461
        $count = 1;
462
        // Creating test Fields with default parameter values.
463
        foreach ($fieldtypes as $fieldtype) {
464
            $fieldname = 'field-' . $count;
465
            $record = new \stdClass();
466
            $record->name = $fieldname;
467
            $record->type = $fieldtype;
468
            $record->required = 1;
469
 
470
            $generator->create_field($record, $this->database);
471
            $count++;
472
        }
473
        // Get all the fields created.
474
        $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id');
475
 
476
        // Populate with contents, creating a new entry.
477
        $contents = array();
478
        $contents[] = array('opt1', 'opt2', 'opt3', 'opt4');
479
        $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows.
480
        $contents[] = 'menu1';
481
        $contents[] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4');
482
        $contents[] = '12345';
483
        $contents[] = 'radioopt1';
484
        $contents[] = 'text for testing';
485
        $contents[] = '<p>text area testing<br /></p>';
486
        $contents[] = array('example.url', 'sampleurl');
487
        $count = 0;
488
        $fieldcontents = array();
489
        foreach ($fields as $fieldrecord) {
490
            $fieldcontents[$fieldrecord->id] = $contents[$count++];
491
        }
492
 
493
        $this->setUser($this->student1);
494
        $entry11 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id, ['Cats', 'Dogs']);
495
        $this->setUser($this->student2);
496
        $entry12 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id, ['Cats']);
497
        $entry13 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id);
498
        // Entry not in group.
499
        $entry14 = $generator->create_entry($this->database, $fieldcontents, 0);
500
 
501
        $this->setUser($this->student3);
502
        $entry21 = $generator->create_entry($this->database, $fieldcontents, $this->group2->id);
503
 
504
        // Approve all except $entry13.
505
        $DB->set_field('data_records', 'approved', 1, ['id' => $entry11]);
506
        $DB->set_field('data_records', 'approved', 1, ['id' => $entry12]);
507
        $DB->set_field('data_records', 'approved', 1, ['id' => $entry14]);
508
        $DB->set_field('data_records', 'approved', 1, ['id' => $entry21]);
509
 
510
        return [$entry11, $entry12, $entry13, $entry14, $entry21];
511
    }
512
 
513
    /**
514
     * Test get_entries
515
     */
516
    public function test_get_entries() {
517
        global $DB;
518
 
519
        // Check the behaviour when the database has no entries.
520
        $result = mod_data_external::get_entries($this->database->id);
521
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
522
        $this->assertEmpty($result['entries']);
523
 
524
        $result = mod_data_external::get_entries($this->database->id, 0, true);
525
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
526
        $this->assertEmpty($result['entries']);
527
        $this->assertEmpty($result['listviewcontents']);
528
 
529
        // Add a few fields to the database.
530
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
531
 
532
        // First of all, expect to see only my group entries (not other users in other groups ones).
533
        // We may expect entries without group also.
534
        $this->setUser($this->student1);
535
        $result = mod_data_external::get_entries($this->database->id);
536
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
537
        $this->assertCount(0, $result['warnings']);
538
        $this->assertCount(3, $result['entries']);
539
        $this->assertEquals(3, $result['totalcount']);
540
        $this->assertEquals($entry11, $result['entries'][0]['id']);
541
        $this->assertCount(2, $result['entries'][0]['tags']);
542
        $this->assertEquals($this->student1->id, $result['entries'][0]['userid']);
543
        $this->assertEquals($this->group1->id, $result['entries'][0]['groupid']);
544
        $this->assertEquals($this->database->id, $result['entries'][0]['dataid']);
545
        $this->assertEquals($entry12, $result['entries'][1]['id']);
546
        $this->assertCount(1, $result['entries'][1]['tags']);
547
        $this->assertEquals('Cats', $result['entries'][1]['tags'][0]['rawname']);
548
        $this->assertEquals($this->student2->id, $result['entries'][1]['userid']);
549
        $this->assertEquals($this->group1->id, $result['entries'][1]['groupid']);
550
        $this->assertEquals($this->database->id, $result['entries'][1]['dataid']);
551
        $this->assertEquals($entry14, $result['entries'][2]['id']);
552
        $this->assertEquals($this->student2->id, $result['entries'][2]['userid']);
553
        $this->assertEquals(0, $result['entries'][2]['groupid']);
554
        $this->assertEquals($this->database->id, $result['entries'][2]['dataid']);
555
        // Other user in same group.
556
        $this->setUser($this->student2);
557
        $result = mod_data_external::get_entries($this->database->id);
558
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
559
        $this->assertCount(0, $result['warnings']);
560
        $this->assertCount(4, $result['entries']);  // I can see my entry is pending approval.
561
        $this->assertEquals(4, $result['totalcount']);
562
 
563
        // Now try with the user in the second group that must see only two entries (his group entry and the one without group).
564
        $this->setUser($this->student3);
565
        $result = mod_data_external::get_entries($this->database->id);
566
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
567
        $this->assertCount(0, $result['warnings']);
568
        $this->assertCount(2, $result['entries']);
569
        $this->assertEquals(2, $result['totalcount']);
570
        $this->assertEquals($entry14, $result['entries'][0]['id']);
571
        $this->assertEquals($this->student2->id, $result['entries'][0]['userid']);
572
        $this->assertEquals(0, $result['entries'][0]['groupid']);
573
        $this->assertEquals($this->database->id, $result['entries'][0]['dataid']);
574
        $this->assertEquals($entry21, $result['entries'][1]['id']);
575
        $this->assertEquals($this->student3->id, $result['entries'][1]['userid']);
576
        $this->assertEquals($this->group2->id, $result['entries'][1]['groupid']);
577
        $this->assertEquals($this->database->id, $result['entries'][1]['dataid']);
578
 
579
        // Now, as teacher we should see all (we have permissions to view all groups).
580
        $this->setUser($this->teacher);
581
        $result = mod_data_external::get_entries($this->database->id);
582
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
583
        $this->assertCount(0, $result['warnings']);
584
        $this->assertCount(5, $result['entries']);  // I can see the not approved one.
585
        $this->assertEquals(5, $result['totalcount']);
586
 
587
        $entries = $DB->get_records('data_records', array('dataid' => $this->database->id), 'id');
588
        $this->assertCount(5, $entries);
589
        $count = 0;
590
        foreach ($entries as $entry) {
591
            $this->assertEquals($entry->id, $result['entries'][$count]['id']);
592
            $count++;
593
        }
594
 
595
        // Basic test passing the parameter (instead having to calculate it).
596
        $this->setUser($this->student1);
597
        $result = mod_data_external::get_entries($this->database->id, $this->group1->id);
598
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
599
        $this->assertCount(0, $result['warnings']);
600
        $this->assertCount(3, $result['entries']);
601
        $this->assertEquals(3, $result['totalcount']);
602
 
603
        // Test ordering (reverse).
604
        $this->setUser($this->student1);
605
        $result = mod_data_external::get_entries($this->database->id, $this->group1->id, false, null, 'DESC');
606
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
607
        $this->assertCount(0, $result['warnings']);
608
        $this->assertCount(3, $result['entries']);
609
        $this->assertEquals(3, $result['totalcount']);
610
        $this->assertEquals($entry14, $result['entries'][0]['id']);
611
 
612
        // Test pagination.
613
        $this->setUser($this->student1);
614
        $result = mod_data_external::get_entries($this->database->id, $this->group1->id, false, null, null, 0, 1);
615
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
616
        $this->assertCount(0, $result['warnings']);
617
        $this->assertCount(1, $result['entries']);
618
        $this->assertEquals(3, $result['totalcount']);
619
        $this->assertEquals($entry11, $result['entries'][0]['id']);
620
 
621
        $result = mod_data_external::get_entries($this->database->id, $this->group1->id, false, null, null, 1, 1);
622
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
623
        $this->assertCount(0, $result['warnings']);
624
        $this->assertCount(1, $result['entries']);
625
        $this->assertEquals(3, $result['totalcount']);
626
        $this->assertEquals($entry12, $result['entries'][0]['id']);
627
 
628
        // Now test the return contents.
629
        data_generate_default_template($this->database, 'listtemplate', 0, false, true); // Generate a default list template.
630
        $result = mod_data_external::get_entries($this->database->id, $this->group1->id, true, null, null, 0, 2);
631
        $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
632
        $this->assertCount(0, $result['warnings']);
633
        $this->assertCount(2, $result['entries']);
634
        $this->assertEquals(3, $result['totalcount']);
635
        $this->assertCount(9, $result['entries'][0]['contents']);
636
        $this->assertCount(9, $result['entries'][1]['contents']);
637
        // Search for some content.
638
        $this->assertTrue(strpos($result['listviewcontents'], 'opt1') !== false);
639
        $this->assertTrue(strpos($result['listviewcontents'], 'January') !== false);
640
        $this->assertTrue(strpos($result['listviewcontents'], 'menu1') !== false);
641
        $this->assertTrue(strpos($result['listviewcontents'], 'text for testing') !== false);
642
        $this->assertTrue(strpos($result['listviewcontents'], 'sampleurl') !== false);
643
    }
644
 
645
    /**
646
     * Test get_entry_visible_groups.
647
     */
648
    public function test_get_entry_visible_groups() {
649
        global $DB;
650
 
651
        $DB->set_field('course', 'groupmode', VISIBLEGROUPS, ['id' => $this->course->id]);
652
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
653
 
654
        // Check I can see my approved group entries.
655
        $this->setUser($this->student1);
656
        $result = mod_data_external::get_entry($entry11);
657
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
658
        $this->assertCount(0, $result['warnings']);
659
        $this->assertEquals($entry11, $result['entry']['id']);
660
        $this->assertTrue($result['entry']['approved']);
661
        $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it.
662
 
663
        // Entry from other group.
664
        $result = mod_data_external::get_entry($entry21);
665
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
666
        $this->assertCount(0, $result['warnings']);
667
        $this->assertEquals($entry21, $result['entry']['id']);
668
    }
669
 
670
    /**
671
     * Test get_entry_separated_groups.
672
     */
673
    public function test_get_entry_separated_groups() {
674
        global $DB;
675
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
676
 
677
        // Check I can see my approved group entries.
678
        $this->setUser($this->student1);
679
        $result = mod_data_external::get_entry($entry11);
680
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
681
        $this->assertCount(0, $result['warnings']);
682
        $this->assertEquals($entry11, $result['entry']['id']);
683
        $this->assertTrue($result['entry']['approved']);
684
        $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it.
685
 
686
        // Retrieve contents.
687
        data_generate_default_template($this->database, 'singletemplate', 0, false, true);
688
        $result = mod_data_external::get_entry($entry11, true);
689
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
690
        $this->assertCount(0, $result['warnings']);
691
        $this->assertCount(9, $result['entry']['contents']);
692
        $this->assertTrue(strpos($result['entryviewcontents'], 'opt1') !== false);
693
        $this->assertTrue(strpos($result['entryviewcontents'], 'January') !== false);
694
        $this->assertTrue(strpos($result['entryviewcontents'], 'menu1') !== false);
695
        $this->assertTrue(strpos($result['entryviewcontents'], 'text for testing') !== false);
696
        $this->assertTrue(strpos($result['entryviewcontents'], 'sampleurl') !== false);
697
 
698
        // This is in my group but I'm not the author.
699
        $result = mod_data_external::get_entry($entry12);
700
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
701
        $this->assertCount(0, $result['warnings']);
702
        $this->assertEquals($entry12, $result['entry']['id']);
703
        $this->assertTrue($result['entry']['approved']);
704
        $this->assertFalse($result['entry']['canmanageentry']); // Not mine.
705
 
706
        $this->setUser($this->student3);
707
        $result = mod_data_external::get_entry($entry21);
708
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
709
        $this->assertCount(0, $result['warnings']);
710
        $this->assertEquals($entry21, $result['entry']['id']);
711
        $this->assertTrue($result['entry']['approved']);
712
        $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it.
713
 
714
        // As teacher I should be able to see all the entries.
715
        $this->setUser($this->teacher);
716
        $result = mod_data_external::get_entry($entry11);
717
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
718
        $this->assertEquals($entry11, $result['entry']['id']);
719
 
720
        $result = mod_data_external::get_entry($entry12);
721
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
722
        $this->assertEquals($entry12, $result['entry']['id']);
723
        // This is the not approved one.
724
        $result = mod_data_external::get_entry($entry13);
725
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
726
        $this->assertEquals($entry13, $result['entry']['id']);
727
 
728
        $result = mod_data_external::get_entry($entry21);
729
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
730
        $this->assertEquals($entry21, $result['entry']['id']);
731
 
732
        // Now, try to get a pending approval.
733
        $this->setUser($this->student1);
734
        $this->expectException('moodle_exception');
735
        $result = mod_data_external::get_entry($entry13);
736
    }
737
 
738
    /**
739
     * Test get_entry from other group in separated groups.
740
     */
741
    public function test_get_entry_other_group_separated_groups() {
742
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
743
 
744
        // We should not be able to view other gropu entries (in separated groups).
745
        $this->setUser($this->student1);
746
        $this->expectException('moodle_exception');
747
        $result = mod_data_external::get_entry($entry21);
748
    }
749
 
750
    /**
751
     * Test get_fields.
752
     */
753
    public function test_get_fields() {
754
        global $DB;
755
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
756
 
757
        $this->setUser($this->student1);
758
        $result = mod_data_external::get_fields($this->database->id);
759
        $result = external_api::clean_returnvalue(mod_data_external::get_fields_returns(), $result);
760
 
761
        // Basically compare we retrieve all the fields and the correct values.
762
        $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id');
763
        foreach ($result['fields'] as $field) {
764
            $this->assertEquals($field, (array) $fields[$field['id']]);
765
        }
766
    }
767
 
768
    /**
769
     * Test get_fields_database_without_fields.
770
     */
771
    public function test_get_fields_database_without_fields() {
772
 
773
        $this->setUser($this->student1);
774
        $result = mod_data_external::get_fields($this->database->id);
775
        $result = external_api::clean_returnvalue(mod_data_external::get_fields_returns(), $result);
776
 
777
        $this->assertEmpty($result['fields']);
778
    }
779
 
780
    /**
781
     * Test search_entries.
782
     */
783
    public function test_search_entries() {
784
        global $DB;
785
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
786
 
787
        $this->setUser($this->student1);
788
        // Empty search, it should return all the visible entries.
789
        $result = mod_data_external::search_entries($this->database->id, 0, false);
790
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
791
        $this->assertCount(3, $result['entries']);
792
        $this->assertEquals(3, $result['totalcount']);
793
 
794
        // Search for something that does not exists.
795
        $result = mod_data_external::search_entries($this->database->id, 0, false, 'abc');
796
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
797
        $this->assertCount(0, $result['entries']);
798
        $this->assertEquals(0, $result['totalcount']);
799
 
800
        // Search by text matching all the entries.
801
        $result = mod_data_external::search_entries($this->database->id, 0, false, 'text');
802
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
803
        $this->assertCount(3, $result['entries']);
804
        $this->assertEquals(3, $result['totalcount']);
805
        $this->assertEquals(3, $result['maxcount']);
806
 
807
        // Now as the other student I should receive my not approved entry. Apply ordering here.
808
        $this->setUser($this->student2);
809
        $result = mod_data_external::search_entries($this->database->id, 0, false, 'text', [], DATA_APPROVED, 'ASC');
810
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
811
        $this->assertCount(4, $result['entries']);
812
        $this->assertEquals(4, $result['totalcount']);
813
        $this->assertEquals(4, $result['maxcount']);
814
        // The not approved one should be the first.
815
        $this->assertEquals($entry13, $result['entries'][0]['id']);
816
 
817
        // Now as the other group student.
818
        $this->setUser($this->student3);
819
        $result = mod_data_external::search_entries($this->database->id, 0, false, 'text');
820
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
821
        $this->assertCount(2, $result['entries']);
822
        $this->assertEquals(2, $result['totalcount']);
823
        $this->assertEquals(2, $result['maxcount']);
824
        $this->assertEquals($this->student2->id, $result['entries'][0]['userid']);
825
        $this->assertEquals($this->student3->id, $result['entries'][1]['userid']);
826
 
827
        // Same normal text search as teacher.
828
        $this->setUser($this->teacher);
829
        $result = mod_data_external::search_entries($this->database->id, 0, false, 'text');
830
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
831
        $this->assertCount(5, $result['entries']);  // I can see all groups and non approved.
832
        $this->assertEquals(5, $result['totalcount']);
833
        $this->assertEquals(5, $result['maxcount']);
834
 
835
        // Pagination.
836
        $this->setUser($this->teacher);
837
        $result = mod_data_external::search_entries($this->database->id, 0, false, 'text', [], DATA_TIMEADDED, 'ASC', 0, 2);
838
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
839
        $this->assertCount(2, $result['entries']);  // Only 2 per page.
840
        $this->assertEquals(5, $result['totalcount']);
841
        $this->assertEquals(5, $result['maxcount']);
842
 
843
        // Now advanced search or not dinamic fields (user firstname for example).
844
        $this->setUser($this->student1);
845
        $advsearch = [
846
            ['name' => 'fn', 'value' => json_encode($this->student2->firstname)]
847
        ];
848
        $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch);
849
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
850
        $this->assertCount(2, $result['entries']);
851
        $this->assertEquals(2, $result['totalcount']);
852
        $this->assertEquals(3, $result['maxcount']);
853
        $this->assertEquals($this->student2->id, $result['entries'][0]['userid']);  // I only found mine!
854
 
855
        // Advanced search for fields.
856
        $field = $DB->get_record('data_fields', array('type' => 'url'));
857
        $advsearch = [
858
            ['name' => 'f_' . $field->id , 'value' => 'sampleurl']
859
        ];
860
        $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch);
861
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
862
        $this->assertCount(3, $result['entries']);  // Found two entries matching this.
863
        $this->assertEquals(3, $result['totalcount']);
864
        $this->assertEquals(3, $result['maxcount']);
865
 
866
        // Combined search.
867
        $field2 = $DB->get_record('data_fields', array('type' => 'number'));
868
        $advsearch = [
869
            ['name' => 'f_' . $field->id , 'value' => 'sampleurl'],
870
            ['name' => 'f_' . $field2->id , 'value' => '12345'],
871
            ['name' => 'ln', 'value' => json_encode($this->student2->lastname)]
872
        ];
873
        $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch);
874
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
875
        $this->assertCount(2, $result['entries']);  // Only one matching everything.
876
        $this->assertEquals(2, $result['totalcount']);
877
        $this->assertEquals(3, $result['maxcount']);
878
 
879
        // Combined search (no results).
880
        $field2 = $DB->get_record('data_fields', array('type' => 'number'));
881
        $advsearch = [
882
            ['name' => 'f_' . $field->id , 'value' => 'sampleurl'],
883
            ['name' => 'f_' . $field2->id , 'value' => '98780333'], // Non existent number.
884
        ];
885
        $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch);
886
        $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
887
        $this->assertCount(0, $result['entries']);  // Only one matching everything.
888
        $this->assertEquals(0, $result['totalcount']);
889
        $this->assertEquals(3, $result['maxcount']);
890
    }
891
 
892
    /**
893
     * Test approve_entry.
894
     */
895
    public function test_approve_entry() {
896
        global $DB;
897
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
898
 
899
        $this->setUser($this->teacher);
900
        $this->assertEquals(0, $DB->get_field('data_records', 'approved', array('id' => $entry13)));
901
        $result = mod_data_external::approve_entry($entry13);
902
        $result = external_api::clean_returnvalue(mod_data_external::approve_entry_returns(), $result);
903
        $this->assertEquals(1, $DB->get_field('data_records', 'approved', array('id' => $entry13)));
904
    }
905
 
906
    /**
907
     * Test unapprove_entry.
908
     */
909
    public function test_unapprove_entry() {
910
        global $DB;
911
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
912
 
913
        $this->setUser($this->teacher);
914
        $this->assertEquals(1, $DB->get_field('data_records', 'approved', array('id' => $entry11)));
915
        $result = mod_data_external::approve_entry($entry11, false);
916
        $result = external_api::clean_returnvalue(mod_data_external::approve_entry_returns(), $result);
917
        $this->assertEquals(0, $DB->get_field('data_records', 'approved', array('id' => $entry11)));
918
    }
919
 
920
    /**
921
     * Test approve_entry missing permissions.
922
     */
923
    public function test_approve_entry_missing_permissions() {
924
        global $DB;
925
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
926
 
927
        $this->setUser($this->student1);
928
        $this->expectException('moodle_exception');
929
        mod_data_external::approve_entry($entry13);
930
    }
931
 
932
    /**
933
     * Test delete_entry as teacher. Check I can delete any entry.
934
     */
935
    public function test_delete_entry_as_teacher() {
936
        global $DB;
937
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
938
 
939
        $this->setUser($this->teacher);
940
        $result = mod_data_external::delete_entry($entry11);
941
        $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result);
942
        $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry11)));
943
 
944
        // Entry in other group.
945
        $result = mod_data_external::delete_entry($entry21);
946
        $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result);
947
        $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry21)));
948
    }
949
 
950
    /**
951
     * Test delete_entry as student. Check I can delete my own entries.
952
     */
953
    public function test_delete_entry_as_student() {
954
        global $DB;
955
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
956
 
957
        $this->setUser($this->student1);
958
        $result = mod_data_external::delete_entry($entry11);
959
        $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result);
960
        $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry11)));
961
    }
962
 
963
    /**
964
     * Test delete_entry as student in read only mode period. Check I cannot delete my own entries in that period.
965
     */
966
    public function test_delete_entry_as_student_in_read_only_period() {
967
        global $DB;
968
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
969
        // Set a time period.
970
        $this->database->timeviewfrom = time() - HOURSECS;
971
        $this->database->timeviewto = time() + HOURSECS;
972
        $DB->update_record('data', $this->database);
973
 
974
        $this->setUser($this->student1);
975
        $this->expectException('moodle_exception');
976
        mod_data_external::delete_entry($entry11);
977
    }
978
 
979
    /**
980
     * Test delete_entry with an user missing permissions.
981
     */
982
    public function test_delete_entry_missing_permissions() {
983
        global $DB;
984
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
985
 
986
        $this->setUser($this->student1);
987
        $this->expectException('moodle_exception');
988
        mod_data_external::delete_entry($entry21);
989
    }
990
 
991
    /**
992
     * Test add_entry.
993
     */
994
    public function test_add_entry() {
995
        global $DB;
996
        // First create the record structure and add some entries.
997
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
998
 
999
        $this->setUser($this->student1);
1000
        $newentrydata = [];
1001
        $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id');
1002
        // Prepare the new entry data.
1003
        foreach ($fields as $field) {
1004
            $subfield = $value = '';
1005
 
1006
            switch ($field->type) {
1007
                case 'checkbox':
1008
                    $value = ['opt1', 'opt2'];
1009
                    break;
1010
                case 'date':
1011
                    // Add two extra.
1012
                    $newentrydata[] = [
1013
                        'fieldid' => $field->id,
1014
                        'subfield' => 'day',
1015
                        'value' => json_encode('5')
1016
                    ];
1017
                    $newentrydata[] = [
1018
                        'fieldid' => $field->id,
1019
                        'subfield' => 'month',
1020
                        'value' => json_encode('1')
1021
                    ];
1022
                    $subfield = 'year';
1023
                    $value = '1981';
1024
                    break;
1025
                case 'menu':
1026
                    $value = 'menu1';
1027
                    break;
1028
                case 'multimenu':
1029
                    $value = ['multimenu1', 'multimenu4'];
1030
                    break;
1031
                case 'number':
1032
                    $value = 6;
1033
                    break;
1034
                case 'radiobutton':
1035
                    $value = 'radioopt1';
1036
                    break;
1037
                case 'text':
1038
                    $value = 'some text';
1039
                    break;
1040
                case 'textarea':
1041
                    $newentrydata[] = [
1042
                        'fieldid' => $field->id,
1043
                        'subfield' => 'content1',
1044
                        'value' => json_encode(FORMAT_MOODLE)
1045
                    ];
1046
                    $newentrydata[] = [
1047
                        'fieldid' => $field->id,
1048
                        'subfield' => 'itemid',
1049
                        'value' => json_encode(0)
1050
                    ];
1051
                    $value = 'more text';
1052
                    break;
1053
                case 'url':
1054
                    $value = 'https://moodle.org';
1055
                    $subfield = 0;
1056
                    break;
1057
            }
1058
 
1059
            $newentrydata[] = [
1060
                'fieldid' => $field->id,
1061
                'subfield' => $subfield,
1062
                'value' => json_encode($value)
1063
            ];
1064
        }
1065
        $result = mod_data_external::add_entry($this->database->id, 0, $newentrydata);
1066
        $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result);
1067
 
1068
        $newentryid = $result['newentryid'];
1069
        $result = mod_data_external::get_entry($newentryid, true);
1070
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
1071
        $this->assertEquals($this->student1->id, $result['entry']['userid']);
1072
        $this->assertCount(9, $result['entry']['contents']);
1073
        foreach ($result['entry']['contents'] as $content) {
1074
            $field = $fields[$content['fieldid']];
1075
            // Stored content same that the one retrieved by WS.
1076
            $dbcontent = $DB->get_record('data_content', array('fieldid' => $field->id, 'recordid' => $newentryid));
1077
            $this->assertEquals($dbcontent->content, $content['content']);
1078
 
1079
            // Now double check everything stored is correct.
1080
            if ($field->type == 'checkbox') {
1081
                $this->assertEquals('opt1##opt2', $content['content']);
1082
                continue;
1083
            }
1084
            if ($field->type == 'date') {
1085
                $this->assertEquals(347500800, $content['content']); // Date in gregorian format.
1086
                continue;
1087
            }
1088
            if ($field->type == 'menu') {
1089
                $this->assertEquals('menu1', $content['content']);
1090
                continue;
1091
            }
1092
            if ($field->type == 'multimenu') {
1093
                $this->assertEquals('multimenu1##multimenu4', $content['content']);
1094
                continue;
1095
            }
1096
            if ($field->type == 'number') {
1097
                $this->assertEquals(6, $content['content']);
1098
                continue;
1099
            }
1100
            if ($field->type == 'radiobutton') {
1101
                $this->assertEquals('radioopt1', $content['content']);
1102
                continue;
1103
            }
1104
            if ($field->type == 'text') {
1105
                $this->assertEquals('some text', $content['content']);
1106
                continue;
1107
            }
1108
            if ($field->type == 'textarea') {
1109
                $this->assertEquals('more text', $content['content']);
1110
                $this->assertEquals(FORMAT_MOODLE, $content['content1']);
1111
                continue;
1112
            }
1113
            if ($field->type == 'url') {
1114
                $this->assertEquals('https://moodle.org', $content['content']);
1115
                continue;
1116
            }
1117
            $this->assertEquals('multimenu1##multimenu4', $content['content']);
1118
        }
1119
 
1120
        // Now, try to add another entry but removing some required data.
1121
        unset($newentrydata[0]);
1122
        $result = mod_data_external::add_entry($this->database->id, 0, $newentrydata);
1123
        $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result);
1124
        $this->assertEquals(0, $result['newentryid']);
1125
        $this->assertCount(0, $result['generalnotifications']);
1126
        $this->assertCount(1, $result['fieldnotifications']);
1127
        $this->assertEquals('field-1', $result['fieldnotifications'][0]['fieldname']);
1128
        $this->assertEquals(get_string('errormustsupplyvalue', 'data'), $result['fieldnotifications'][0]['notification']);
1129
    }
1130
 
1131
    /**
1132
     * Test add_entry empty_form.
1133
     */
1134
    public function test_add_entry_empty_form() {
1135
 
1136
        // Add a field to database to let users add new entries.
1137
        $this->add_test_field();
1138
 
1139
        $result = mod_data_external::add_entry($this->database->id, 0, []);
1140
        $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result);
1141
        $this->assertEquals(0, $result['newentryid']);
1142
        $this->assertCount(1, $result['generalnotifications']);
1143
        $this->assertCount(0, $result['fieldnotifications']);
1144
        $this->assertEquals(get_string('emptyaddform', 'data'), $result['generalnotifications'][0]);
1145
    }
1146
 
1147
    /**
1148
     * Test add_entry read_only_period.
1149
     */
1150
    public function test_add_entry_read_only_period() {
1151
        global $DB;
1152
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1153
        // Set a time period.
1154
        $this->database->timeviewfrom = time() - HOURSECS;
1155
        $this->database->timeviewto = time() + HOURSECS;
1156
        $DB->update_record('data', $this->database);
1157
 
1158
        $this->setUser($this->student1);
1159
        $this->expectExceptionMessage(get_string('noaccess', 'data'));
1160
        $this->expectException('moodle_exception');
1161
        mod_data_external::add_entry($this->database->id, 0, []);
1162
    }
1163
 
1164
    /**
1165
     * Test add_entry max_num_entries.
1166
     */
1167
    public function test_add_entry_max_num_entries() {
1168
        global $DB;
1169
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1170
        // Set a time period.
1171
        $this->database->maxentries = 1;
1172
        $DB->update_record('data', $this->database);
1173
 
1174
        $this->setUser($this->student1);
1175
        $this->expectExceptionMessage(get_string('noaccess', 'data'));
1176
        $this->expectException('moodle_exception');
1177
        mod_data_external::add_entry($this->database->id, 0, []);
1178
    }
1179
 
1180
    /**
1181
     * Test add_entry invalid group.
1182
     */
1183
    public function test_add_entry_invalid_group() {
1184
 
1185
        // Add a field to database to let users add new entries.
1186
        $this->add_test_field();
1187
 
1188
        $this->setUser($this->student1);
1189
        $this->expectExceptionMessage(get_string('noaccess', 'data'));
1190
        $this->expectException('moodle_exception');
1191
        mod_data_external::add_entry($this->database->id, $this->group2->id, []);
1192
    }
1193
 
1194
    /**
1195
     * Test add_entry for an empty database (no fields).
1196
     *
1197
     * @covers ::add_entry
1198
     */
1199
    public function test_add_entry_empty_database() {
1200
        $this->expectException('moodle_exception');
1201
        mod_data_external::add_entry($this->database->id, 0, []);
1202
    }
1203
 
1204
    /**
1205
     * Test update_entry.
1206
     */
1207
    public function test_update_entry() {
1208
        global $DB;
1209
        // First create the record structure and add some entries.
1210
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1211
 
1212
        $this->setUser($this->student1);
1213
        $newentrydata = [];
1214
        $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id');
1215
        // Prepare the new entry data.
1216
        foreach ($fields as $field) {
1217
            $subfield = $value = '';
1218
 
1219
            switch ($field->type) {
1220
                case 'checkbox':
1221
                    $value = ['opt1', 'opt2'];
1222
                    break;
1223
                case 'date':
1224
                    // Add two extra.
1225
                    $newentrydata[] = [
1226
                        'fieldid' => $field->id,
1227
                        'subfield' => 'day',
1228
                        'value' => json_encode('5')
1229
                    ];
1230
                    $newentrydata[] = [
1231
                        'fieldid' => $field->id,
1232
                        'subfield' => 'month',
1233
                        'value' => json_encode('1')
1234
                    ];
1235
                    $subfield = 'year';
1236
                    $value = '1981';
1237
                    break;
1238
                case 'menu':
1239
                    $value = 'menu1';
1240
                    break;
1241
                case 'multimenu':
1242
                    $value = ['multimenu1', 'multimenu4'];
1243
                    break;
1244
                case 'number':
1245
                    $value = 6;
1246
                    break;
1247
                case 'radiobutton':
1248
                    $value = 'radioopt2';
1249
                    break;
1250
                case 'text':
1251
                    $value = 'some text';
1252
                    break;
1253
                case 'textarea':
1254
                    $newentrydata[] = [
1255
                        'fieldid' => $field->id,
1256
                        'subfield' => 'content1',
1257
                        'value' => json_encode(FORMAT_MOODLE)
1258
                    ];
1259
                    $newentrydata[] = [
1260
                        'fieldid' => $field->id,
1261
                        'subfield' => 'itemid',
1262
                        'value' => json_encode(0)
1263
                    ];
1264
                    $value = 'more text';
1265
                    break;
1266
                case 'url':
1267
                    $value = 'https://moodle.org';
1268
                    $subfield = 0;
1269
                    break;
1270
            }
1271
 
1272
            $newentrydata[] = [
1273
                'fieldid' => $field->id,
1274
                'subfield' => $subfield,
1275
                'value' => json_encode($value)
1276
            ];
1277
        }
1278
        $result = mod_data_external::update_entry($entry11, $newentrydata);
1279
        $result = external_api::clean_returnvalue(mod_data_external::update_entry_returns(), $result);
1280
        $this->assertTrue($result['updated']);
1281
        $this->assertCount(0, $result['generalnotifications']);
1282
        $this->assertCount(0, $result['fieldnotifications']);
1283
 
1284
        $result = mod_data_external::get_entry($entry11, true);
1285
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
1286
        $this->assertEquals($this->student1->id, $result['entry']['userid']);
1287
        $this->assertCount(9, $result['entry']['contents']);
1288
        foreach ($result['entry']['contents'] as $content) {
1289
            $field = $fields[$content['fieldid']];
1290
            // Stored content same that the one retrieved by WS.
1291
            $dbcontent = $DB->get_record('data_content', array('fieldid' => $field->id, 'recordid' => $entry11));
1292
            $this->assertEquals($dbcontent->content, $content['content']);
1293
 
1294
            // Now double check everything stored is correct.
1295
            if ($field->type == 'checkbox') {
1296
                $this->assertEquals('opt1##opt2', $content['content']);
1297
                continue;
1298
            }
1299
            if ($field->type == 'date') {
1300
                $this->assertEquals(347500800, $content['content']); // Date in gregorian format.
1301
                continue;
1302
            }
1303
            if ($field->type == 'menu') {
1304
                $this->assertEquals('menu1', $content['content']);
1305
                continue;
1306
            }
1307
            if ($field->type == 'multimenu') {
1308
                $this->assertEquals('multimenu1##multimenu4', $content['content']);
1309
                continue;
1310
            }
1311
            if ($field->type == 'number') {
1312
                $this->assertEquals(6, $content['content']);
1313
                continue;
1314
            }
1315
            if ($field->type == 'radiobutton') {
1316
                $this->assertEquals('radioopt2', $content['content']);
1317
                continue;
1318
            }
1319
            if ($field->type == 'text') {
1320
                $this->assertEquals('some text', $content['content']);
1321
                continue;
1322
            }
1323
            if ($field->type == 'textarea') {
1324
                $this->assertEquals('more text', $content['content']);
1325
                $this->assertEquals(FORMAT_MOODLE, $content['content1']);
1326
                continue;
1327
            }
1328
            if ($field->type == 'url') {
1329
                $this->assertEquals('https://moodle.org', $content['content']);
1330
                continue;
1331
            }
1332
            $this->assertEquals('multimenu1##multimenu4', $content['content']);
1333
        }
1334
 
1335
        // Now, try to update the entry but removing some required data.
1336
        unset($newentrydata[0]);
1337
        $result = mod_data_external::update_entry($entry11, $newentrydata);
1338
        $result = external_api::clean_returnvalue(mod_data_external::update_entry_returns(), $result);
1339
        $this->assertFalse($result['updated']);
1340
        $this->assertCount(0, $result['generalnotifications']);
1341
        $this->assertCount(1, $result['fieldnotifications']);
1342
        $this->assertEquals('field-1', $result['fieldnotifications'][0]['fieldname']);
1343
        $this->assertEquals(get_string('errormustsupplyvalue', 'data'), $result['fieldnotifications'][0]['notification']);
1344
    }
1345
 
1346
    /**
1347
     * Test update_entry sending empty data.
1348
     */
1349
    public function test_update_entry_empty_data() {
1350
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1351
 
1352
        $this->setUser($this->student1);
1353
        $result = mod_data_external::update_entry($entry11, []);
1354
        $result = external_api::clean_returnvalue(mod_data_external::update_entry_returns(), $result);
1355
        $this->assertFalse($result['updated']);
1356
        $this->assertCount(1, $result['generalnotifications']);
1357
        $this->assertCount(9, $result['fieldnotifications']);
1358
        $this->assertEquals(get_string('emptyaddform', 'data'), $result['generalnotifications'][0]);
1359
    }
1360
 
1361
    /**
1362
     * Test update_entry in read only period.
1363
     */
1364
    public function test_update_entry_read_only_period() {
1365
        global $DB;
1366
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1367
        // Set a time period.
1368
        $this->database->timeviewfrom = time() - HOURSECS;
1369
        $this->database->timeviewto = time() + HOURSECS;
1370
        $DB->update_record('data', $this->database);
1371
 
1372
        $this->setUser($this->student1);
1373
        $this->expectExceptionMessage(get_string('noaccess', 'data'));
1374
        $this->expectException('moodle_exception');
1375
        mod_data_external::update_entry($entry11, []);
1376
    }
1377
 
1378
    /**
1379
     * Test update_entry other_user.
1380
     */
1381
    public function test_update_entry_other_user() {
1382
        // Try to update other user entry.
1383
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1384
        $this->setUser($this->student2);
1385
        $this->expectExceptionMessage(get_string('noaccess', 'data'));
1386
        $this->expectException('moodle_exception');
1387
        mod_data_external::update_entry($entry11, []);
1388
    }
1389
 
1390
    /**
1391
     * Test get_entry_rating_information.
1392
     */
1393
    public function test_get_entry_rating_information() {
1394
        global $DB, $CFG;
1395
        require_once($CFG->dirroot . '/rating/lib.php');
1396
 
1397
        $DB->set_field('data', 'assessed', RATING_AGGREGATE_SUM, array('id' => $this->database->id));
1398
        $DB->set_field('data', 'scale', 100, array('id' => $this->database->id));
1399
        list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries();
1400
 
1401
        $user1 = self::getDataGenerator()->create_user();
1402
        $user2 = self::getDataGenerator()->create_user();
1403
        $this->getDataGenerator()->enrol_user($user1->id, $this->course->id, $this->studentrole->id, 'manual');
1404
        $this->getDataGenerator()->enrol_user($user2->id, $this->course->id, $this->studentrole->id, 'manual');
1405
 
1406
        // Rate the entry as user1.
1407
        $rating1 = new \stdClass();
1408
        $rating1->contextid = $this->context->id;
1409
        $rating1->component = 'mod_data';
1410
        $rating1->ratingarea = 'entry';
1411
        $rating1->itemid = $entry11;
1412
        $rating1->rating = 50;
1413
        $rating1->scaleid = 100;
1414
        $rating1->userid = $user1->id;
1415
        $rating1->timecreated = time();
1416
        $rating1->timemodified = time();
1417
        $rating1->id = $DB->insert_record('rating', $rating1);
1418
 
1419
        // Rate the entry as user2.
1420
        $rating2 = new \stdClass();
1421
        $rating2->contextid = $this->context->id;
1422
        $rating2->component = 'mod_data';
1423
        $rating2->ratingarea = 'entry';
1424
        $rating2->itemid = $entry11;
1425
        $rating2->rating = 100;
1426
        $rating2->scaleid = 100;
1427
        $rating2->userid = $user2->id;
1428
        $rating2->timecreated = time() + 1;
1429
        $rating2->timemodified = time() + 1;
1430
        $rating2->id = $DB->insert_record('rating', $rating2);
1431
 
1432
        // As student, retrieve ratings information.
1433
        $this->setUser($this->student2);
1434
        $result = mod_data_external::get_entry($entry11);
1435
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
1436
        $this->assertCount(1, $result['ratinginfo']['ratings']);
1437
        $this->assertFalse($result['ratinginfo']['ratings'][0]['canviewaggregate']);
1438
        $this->assertFalse($result['ratinginfo']['canviewall']);
1439
        $this->assertFalse($result['ratinginfo']['ratings'][0]['canrate']);
1440
        $this->assertTrue(!isset($result['ratinginfo']['ratings'][0]['count']));
1441
 
1442
        // Now, as teacher, I should see the info correctly.
1443
        $this->setUser($this->teacher);
1444
        $result = mod_data_external::get_entry($entry11);
1445
        $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
1446
        $this->assertCount(1, $result['ratinginfo']['ratings']);
1447
        $this->assertTrue($result['ratinginfo']['ratings'][0]['canviewaggregate']);
1448
        $this->assertTrue($result['ratinginfo']['canviewall']);
1449
        $this->assertTrue($result['ratinginfo']['ratings'][0]['canrate']);
1450
        $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['count']);
1451
        $this->assertEquals(100, $result['ratinginfo']['ratings'][0]['aggregate']); // Expect maximium scale value.
1452
    }
1453
}