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