MDL-57924 mod_data: Move update record code to new function
[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
9fac7c86
JL
44 /**
45 * Set up for every test
46 */
47 public function setUp() {
48 global $DB;
49 $this->resetAfterTest();
50 $this->setAdminUser();
51
52 // Setup test data.
ef6aea9d
JL
53 $course = new stdClass();
54 $course->groupmode = SEPARATEGROUPS;
55 $course->groupmodeforce = true;
56 $this->course = $this->getDataGenerator()->create_course($course);
9fac7c86
JL
57 $this->data = $this->getDataGenerator()->create_module('data', array('course' => $this->course->id));
58 $this->context = context_module::instance($this->data->cmid);
59 $this->cm = get_coursemodule_from_instance('data', $this->data->id);
60
61 // Create users.
62 $this->student1 = self::getDataGenerator()->create_user();
63 $this->student2 = self::getDataGenerator()->create_user();
ef6aea9d 64 $this->student3 = self::getDataGenerator()->create_user();
9fac7c86
JL
65 $this->teacher = self::getDataGenerator()->create_user();
66
67 // Users enrolments.
68 $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
69 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
70 $this->getDataGenerator()->enrol_user($this->student1->id, $this->course->id, $this->studentrole->id, 'manual');
71 $this->getDataGenerator()->enrol_user($this->student2->id, $this->course->id, $this->studentrole->id, 'manual');
ef6aea9d 72 $this->getDataGenerator()->enrol_user($this->student3->id, $this->course->id, $this->studentrole->id, 'manual');
9fac7c86 73 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
ef6aea9d
JL
74
75 $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
76 $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
77 groups_add_member($this->group1, $this->student1);
78 groups_add_member($this->group1, $this->student2);
79 groups_add_member($this->group2, $this->student3);
9fac7c86
JL
80 }
81
067b3fda
JL
82 /**
83 * Test get databases by courses
84 */
85 public function test_mod_data_get_databases_by_courses() {
86 global $DB;
87
88 $this->resetAfterTest(true);
89
90 // Create users.
91 $student = self::getDataGenerator()->create_user();
92 $teacher = self::getDataGenerator()->create_user();
93
94 // Set to the student user.
95 self::setUser($student);
96
97 // Create courses to add the modules.
98 $course1 = self::getDataGenerator()->create_course();
99 $course2 = self::getDataGenerator()->create_course();
100
101 // First database.
102 $record = new stdClass();
103 $record->introformat = FORMAT_HTML;
104 $record->course = $course1->id;
105 $database1 = self::getDataGenerator()->create_module('data', $record);
106
107 // Second database.
108 $record = new stdClass();
109 $record->introformat = FORMAT_HTML;
110 $record->course = $course2->id;
111 $database2 = self::getDataGenerator()->create_module('data', $record);
112
113 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
114 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
115
116 // Users enrolments.
117 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
118 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual');
119
120 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
121 $enrol = enrol_get_plugin('manual');
122 $enrolinstances = enrol_get_instances($course2->id, true);
123 foreach ($enrolinstances as $courseenrolinstance) {
124 if ($courseenrolinstance->enrol == "manual") {
125 $instance2 = $courseenrolinstance;
126 break;
127 }
128 }
129 $enrol->enrol_user($instance2, $student->id, $studentrole->id);
130
131 // Create what we expect to be returned when querying the two courses.
132 // First for the student user.
133 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'comments', 'timeavailablefrom',
134 'timeavailableto', 'timeviewfrom', 'timeviewto', 'requiredentries', 'requiredentriestoview',
f97305b0
JL
135 'intro', 'introformat', 'introfiles', 'maxentries', 'rssarticles', 'singletemplate', 'listtemplate',
136 'listtemplateheader', 'listtemplatefooter', 'addtemplate', 'rsstemplate', 'rsstitletemplate',
137 'csstemplate', 'jstemplate', 'asearchtemplate', 'approval', 'defaultsort', 'defaultsortdir', 'manageapproved');
067b3fda
JL
138
139 // Add expected coursemodule.
140 $database1->coursemodule = $database1->cmid;
7ef49bd3 141 $database1->introfiles = [];
067b3fda 142 $database2->coursemodule = $database2->cmid;
7ef49bd3 143 $database2->introfiles = [];
067b3fda
JL
144
145 $expected1 = array();
146 $expected2 = array();
147 foreach ($expectedfields as $field) {
f97305b0
JL
148 if ($field == 'approval' or $field == 'manageapproved') {
149 $database1->{$field} = (bool) $database1->{$field};
150 $database2->{$field} = (bool) $database2->{$field};
151 }
067b3fda
JL
152 $expected1[$field] = $database1->{$field};
153 $expected2[$field] = $database2->{$field};
154 }
8352aa50
JL
155 $expected1['comments'] = (bool) $expected1['comments'];
156 $expected2['comments'] = (bool) $expected2['comments'];
067b3fda
JL
157
158 $expecteddatabases = array();
159 $expecteddatabases[] = $expected2;
160 $expecteddatabases[] = $expected1;
161
162 // Call the external function passing course ids.
163 $result = mod_data_external::get_databases_by_courses(array($course2->id, $course1->id));
8352aa50 164 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
165 $this->assertEquals($expecteddatabases, $result['databases']);
166
167 // Call the external function without passing course id.
168 $result = mod_data_external::get_databases_by_courses();
8352aa50 169 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
170 $this->assertEquals($expecteddatabases, $result['databases']);
171
172 // Unenrol user from second course and alter expected databases.
173 $enrol->unenrol_user($instance2, $student->id);
174 array_shift($expecteddatabases);
175
176 // Call the external function without passing course id.
177 $result = mod_data_external::get_databases_by_courses();
8352aa50 178 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
179 $this->assertEquals($expecteddatabases, $result['databases']);
180
181 // Call for the second course we unenrolled the user from, expected warning.
182 $result = mod_data_external::get_databases_by_courses(array($course2->id));
183 $this->assertCount(1, $result['warnings']);
8352aa50 184 $this->assertEquals('1', $result['warnings'][0]['warningcode']);
067b3fda
JL
185 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
186
187 // Now, try as a teacher for getting all the additional fields.
188 self::setUser($teacher);
189
f97305b0 190 $additionalfields = array('scale', 'assessed', 'assesstimestart', 'assesstimefinish', 'editany', 'notification', 'timemodified');
067b3fda
JL
191
192 foreach ($additionalfields as $field) {
f97305b0
JL
193 if ($field == 'editany') {
194 $database1->{$field} = (bool) $database1->{$field};
8352aa50 195 }
f97305b0 196 $expecteddatabases[0][$field] = $database1->{$field};
067b3fda
JL
197 }
198 $result = mod_data_external::get_databases_by_courses();
8352aa50
JL
199 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
200 $this->assertEquals($expecteddatabases, $result['databases']);
201
202 // Admin should get all the information.
203 self::setAdminUser();
204
205 $result = mod_data_external::get_databases_by_courses(array($course1->id));
206 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
207 $this->assertEquals($expecteddatabases, $result['databases']);
208 }
9fac7c86
JL
209
210 /**
211 * Test view_database invalid id.
212 */
213 public function test_view_database_invalid_id() {
214
215 // Test invalid instance id.
216 $this->setExpectedException('moodle_exception');
217 mod_data_external::view_database(0);
218 }
219
220 /**
221 * Test view_database not enrolled user.
222 */
223 public function test_view_database_not_enrolled_user() {
224
225 $usernotenrolled = self::getDataGenerator()->create_user();
226 $this->setUser($usernotenrolled);
227
228 $this->setExpectedException('moodle_exception');
229 mod_data_external::view_database(0);
230 }
231
232 /**
233 * Test view_database no capabilities.
234 */
235 public function test_view_database_no_capabilities() {
236 // Test user with no capabilities.
237 // We need a explicit prohibit since this capability is allowed for students by default.
238 assign_capability('mod/data:viewpage', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
239 accesslib_clear_all_caches_for_unit_testing();
240
241 $this->setExpectedException('moodle_exception');
242 mod_data_external::view_database(0);
243 }
244
245 /**
246 * Test view_database.
247 */
248 public function test_view_database() {
249
250 // Test user with full capabilities.
251 $this->setUser($this->student1);
252
253 // Trigger and capture the event.
254 $sink = $this->redirectEvents();
255
256 $result = mod_data_external::view_database($this->data->id);
257 $result = external_api::clean_returnvalue(mod_data_external::view_database_returns(), $result);
258
259 $events = $sink->get_events();
260 $this->assertCount(1, $events);
261 $event = array_shift($events);
262
263 // Checking that the event contains the expected values.
264 $this->assertInstanceOf('\mod_data\event\course_module_viewed', $event);
265 $this->assertEquals($this->context, $event->get_context());
266 $moodledata = new \moodle_url('/mod/data/view.php', array('id' => $this->cm->id));
267 $this->assertEquals($moodledata, $event->get_url());
268 $this->assertEventContextNotUsed($event);
269 $this->assertNotEmpty($event->get_name());
270 }
cac43b9b
JL
271
272 /**
273 * Test get_data_access_information for student.
274 */
275 public function test_get_data_access_information_student() {
276 global $DB;
277 // Modify the database to add access restrictions.
278 $this->data->timeavailablefrom = time() + DAYSECS;
279 $this->data->requiredentries = 2;
280 $this->data->requiredentriestoview = 2;
281 $DB->update_record('data', $this->data);
282
283 // Test user with full capabilities.
284 $this->setUser($this->student1);
285
286 $result = mod_data_external::get_data_access_information($this->data->id);
287 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
288
ef6aea9d 289 $this->assertEquals($this->group1->id, $result['groupid']);
cac43b9b
JL
290
291 $this->assertFalse($result['canmanageentries']);
292 $this->assertFalse($result['canapprove']);
293 $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions.
294 $this->assertFalse($result['timeavailable']);
295 $this->assertFalse($result['inreadonlyperiod']);
296 $this->assertEquals(0, $result['numentries']);
297 $this->assertEquals($this->data->requiredentries, $result['entrieslefttoadd']);
298 $this->assertEquals($this->data->requiredentriestoview, $result['entrieslefttoview']);
299 }
300
301 /**
302 * Test get_data_access_information for teacher.
303 */
304 public function test_get_data_access_information_teacher() {
305 global $DB;
306 // Modify the database to add access restrictions.
307 $this->data->timeavailablefrom = time() + DAYSECS;
308 $this->data->requiredentries = 2;
309 $this->data->requiredentriestoview = 2;
310 $DB->update_record('data', $this->data);
311
312 // Test user with full capabilities.
313 $this->setUser($this->teacher);
314
315 $result = mod_data_external::get_data_access_information($this->data->id);
316 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
317
318 $this->assertEquals(0, $result['groupid']);
319
320 $this->assertTrue($result['canmanageentries']);
321 $this->assertTrue($result['canapprove']);
322 $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions.
323 $this->assertTrue($result['timeavailable']);
324 $this->assertFalse($result['inreadonlyperiod']);
325 $this->assertEquals(0, $result['numentries']);
326 $this->assertEquals(0, $result['entrieslefttoadd']);
327 $this->assertEquals(0, $result['entrieslefttoview']);
328 }
ef6aea9d
JL
329
330 /**
331 * Helper method to populate the database with some entries.
332 *
333 * @return array the entry ids created
334 */
335 public function populate_database_with_entries() {
336 global $DB;
337
771effef
JL
338 // Force approval.
339 $DB->set_field('data', 'approval', 1, array('id' => $this->data->id));
ef6aea9d
JL
340 $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
341 $fieldtypes = array('checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url');
342
343 $count = 1;
344 // Creating test Fields with default parameter values.
345 foreach ($fieldtypes as $fieldtype) {
346 $fieldname = 'field-' . $count;
347 $record = new StdClass();
348 $record->name = $fieldname;
349 $record->type = $fieldtype;
350 $record->required = 1;
351
352 $generator->create_field($record, $this->data);
353 $count++;
354 }
355 // Get all the fields created.
356 $fields = $DB->get_records('data_fields', array('dataid' => $this->data->id), 'id');
357
358 // Populate with contents, creating a new entry.
359 $contents = array();
360 $contents[] = array('opt1', 'opt2', 'opt3', 'opt4');
361 $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows.
362 $contents[] = 'menu1';
363 $contents[] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4');
364 $contents[] = '12345';
365 $contents[] = 'radioopt1';
366 $contents[] = 'text for testing';
367 $contents[] = '<p>text area testing<br /></p>';
368 $contents[] = array('example.url', 'sampleurl');
369 $count = 0;
370 $fieldcontents = array();
371 foreach ($fields as $fieldrecord) {
372 $fieldcontents[$fieldrecord->id] = $contents[$count++];
373 }
374
375 $this->setUser($this->student1);
376 $entry11 = $generator->create_entry($this->data, $fieldcontents, $this->group1->id);
377 $this->setUser($this->student2);
378 $entry12 = $generator->create_entry($this->data, $fieldcontents, $this->group1->id);
771effef 379 $entry13 = $generator->create_entry($this->data, $fieldcontents, $this->group1->id);
ef6aea9d
JL
380
381 $this->setUser($this->student3);
382 $entry21 = $generator->create_entry($this->data, $fieldcontents, $this->group2->id);
771effef
JL
383
384 // Approve all except $entry13.
385 $DB->set_field('data_records', 'approved', 1, ['id' => $entry11]);
386 $DB->set_field('data_records', 'approved', 1, ['id' => $entry12]);
387 $DB->set_field('data_records', 'approved', 1, ['id' => $entry21]);
388
389 return [$entry11, $entry12, $entry13, $entry21];
ef6aea9d
JL
390 }
391
392 /**
393 * Test get_entries
394 */
395 public function test_get_entries() {
396 global $DB;
771effef 397 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
ef6aea9d
JL
398
399 // First of all, expect to see only my group entries (not other users in other groups ones).
400 $this->setUser($this->student1);
401 $result = mod_data_external::get_entries($this->data->id);
402 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
403 $this->assertCount(0, $result['warnings']);
404 $this->assertCount(2, $result['entries']);
405 $this->assertEquals(2, $result['totalcount']);
406 $this->assertEquals($entry11, $result['entries'][0]['id']);
407 $this->assertEquals($this->student1->id, $result['entries'][0]['userid']);
408 $this->assertEquals($this->group1->id, $result['entries'][0]['groupid']);
409 $this->assertEquals($this->data->id, $result['entries'][0]['dataid']);
410 $this->assertEquals($entry12, $result['entries'][1]['id']);
411 $this->assertEquals($this->student2->id, $result['entries'][1]['userid']);
412 $this->assertEquals($this->group1->id, $result['entries'][1]['groupid']);
413 $this->assertEquals($this->data->id, $result['entries'][1]['dataid']);
414 // Other user in same group.
415 $this->setUser($this->student2);
416 $result = mod_data_external::get_entries($this->data->id);
417 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
418 $this->assertCount(0, $result['warnings']);
771effef
JL
419 $this->assertCount(3, $result['entries']); // I can see my entry not approved yet.
420 $this->assertEquals(3, $result['totalcount']);
ef6aea9d
JL
421
422 // Now try with the user in the second group that must see only one entry.
423 $this->setUser($this->student3);
424 $result = mod_data_external::get_entries($this->data->id);
425 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
426 $this->assertCount(0, $result['warnings']);
427 $this->assertCount(1, $result['entries']);
428 $this->assertEquals(1, $result['totalcount']);
429 $this->assertEquals($entry21, $result['entries'][0]['id']);
430 $this->assertEquals($this->student3->id, $result['entries'][0]['userid']);
431 $this->assertEquals($this->group2->id, $result['entries'][0]['groupid']);
432 $this->assertEquals($this->data->id, $result['entries'][0]['dataid']);
433
434 // Now, as teacher we should see all (we have permissions to view all groups).
435 $this->setUser($this->teacher);
436 $result = mod_data_external::get_entries($this->data->id);
437 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
438 $this->assertCount(0, $result['warnings']);
771effef
JL
439 $this->assertCount(4, $result['entries']); // I can see the not approved one.
440 $this->assertEquals(4, $result['totalcount']);
ef6aea9d
JL
441
442 $entries = $DB->get_records('data_records', array('dataid' => $this->data->id), 'id');
771effef 443 $this->assertCount(4, $entries);
ef6aea9d
JL
444 $count = 0;
445 foreach ($entries as $entry) {
446 $this->assertEquals($entry->id, $result['entries'][$count]['id']);
447 $count++;
448 }
449
450 // Basic test passing the parameter (instead having to calculate it).
451 $this->setUser($this->student1);
452 $result = mod_data_external::get_entries($this->data->id, $this->group1->id);
453 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
454 $this->assertCount(0, $result['warnings']);
455 $this->assertCount(2, $result['entries']);
456 $this->assertEquals(2, $result['totalcount']);
457
458 // Test ordering (reverse).
459 $this->setUser($this->student1);
460 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, false, null, 'DESC');
461 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
462 $this->assertCount(0, $result['warnings']);
463 $this->assertCount(2, $result['entries']);
464 $this->assertEquals(2, $result['totalcount']);
465 $this->assertEquals($entry12, $result['entries'][0]['id']);
466
467 // Test pagination.
468 $this->setUser($this->student1);
469 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, false, null, null, 0, 1);
470 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
471 $this->assertCount(0, $result['warnings']);
472 $this->assertCount(1, $result['entries']);
473 $this->assertEquals(2, $result['totalcount']);
474 $this->assertEquals($entry11, $result['entries'][0]['id']);
475
476 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, false, null, null, 1, 1);
477 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
478 $this->assertCount(0, $result['warnings']);
479 $this->assertCount(1, $result['entries']);
480 $this->assertEquals(2, $result['totalcount']);
481 $this->assertEquals($entry12, $result['entries'][0]['id']);
482
483 // Now test the return contents.
484 data_generate_default_template($this->data, 'listtemplate', 0, false, true); // Generate a default list template.
485 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, true, null, null, 0, 2);
486 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
487 $this->assertCount(0, $result['warnings']);
488 $this->assertCount(2, $result['entries']);
489 $this->assertEquals(2, $result['totalcount']);
490 $this->assertCount(9, $result['entries'][0]['contents']);
491 $this->assertCount(9, $result['entries'][1]['contents']);
492 // Search for some content.
493 $this->assertTrue(strpos($result['listviewcontents'], 'opt1') !== false);
494 $this->assertTrue(strpos($result['listviewcontents'], 'January') !== false);
495 $this->assertTrue(strpos($result['listviewcontents'], 'menu1') !== false);
496 $this->assertTrue(strpos($result['listviewcontents'], 'text for testing') !== false);
497 $this->assertTrue(strpos($result['listviewcontents'], 'sampleurl') !== false);
498 }
771effef
JL
499
500 /**
501 * Test get_entry_visible_groups.
502 */
503 public function test_get_entry_visible_groups() {
504 global $DB;
505
506 $DB->set_field('course', 'groupmode', VISIBLEGROUPS, ['id' => $this->course->id]);
507 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
508
509 // Check I can see my approved group entries.
510 $this->setUser($this->student1);
511 $result = mod_data_external::get_entry($entry11);
512 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
513 $this->assertCount(0, $result['warnings']);
514 $this->assertEquals($entry11, $result['entry']['id']);
515 $this->assertTrue($result['entry']['approved']);
516 $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it.
517
518 // Entry from other group.
519 $result = mod_data_external::get_entry($entry21);
520 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
521 $this->assertCount(0, $result['warnings']);
522 $this->assertEquals($entry21, $result['entry']['id']);
523 }
524
525 /**
526 * Test get_entry_separated_groups.
527 */
528 public function test_get_entry_separated_groups() {
529 global $DB;
530 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
531
532 // Check I can see my approved group entries.
533 $this->setUser($this->student1);
534 $result = mod_data_external::get_entry($entry11);
535 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
536 $this->assertCount(0, $result['warnings']);
537 $this->assertEquals($entry11, $result['entry']['id']);
538 $this->assertTrue($result['entry']['approved']);
539 $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it.
540
541 // Retrieve contents.
542 data_generate_default_template($this->data, 'singletemplate', 0, false, true);
543 $result = mod_data_external::get_entry($entry11, true);
544 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
545 $this->assertCount(0, $result['warnings']);
546 $this->assertCount(9, $result['entry']['contents']);
547 $this->assertTrue(strpos($result['entryviewcontents'], 'opt1') !== false);
548 $this->assertTrue(strpos($result['entryviewcontents'], 'January') !== false);
549 $this->assertTrue(strpos($result['entryviewcontents'], 'menu1') !== false);
550 $this->assertTrue(strpos($result['entryviewcontents'], 'text for testing') !== false);
551 $this->assertTrue(strpos($result['entryviewcontents'], 'sampleurl') !== false);
552
553 // This is in my group but I'm not the author.
554 $result = mod_data_external::get_entry($entry12);
555 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
556 $this->assertCount(0, $result['warnings']);
557 $this->assertEquals($entry12, $result['entry']['id']);
558 $this->assertTrue($result['entry']['approved']);
559 $this->assertFalse($result['entry']['canmanageentry']); // Not mine.
560
561 $this->setUser($this->student3);
562 $result = mod_data_external::get_entry($entry21);
563 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
564 $this->assertCount(0, $result['warnings']);
565 $this->assertEquals($entry21, $result['entry']['id']);
566 $this->assertTrue($result['entry']['approved']);
567 $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it.
568
569 // As teacher I should be able to see all the entries.
570 $this->setUser($this->teacher);
571 $result = mod_data_external::get_entry($entry11);
572 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
573 $this->assertEquals($entry11, $result['entry']['id']);
574
575 $result = mod_data_external::get_entry($entry12);
576 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
577 $this->assertEquals($entry12, $result['entry']['id']);
578 // This is the not approved one.
579 $result = mod_data_external::get_entry($entry13);
580 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
581 $this->assertEquals($entry13, $result['entry']['id']);
582
583 $result = mod_data_external::get_entry($entry21);
584 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
585 $this->assertEquals($entry21, $result['entry']['id']);
586
587 // Now, try to get an entry not approved yet.
588 $this->setUser($this->student1);
589 $this->expectException('moodle_exception');
590 $result = mod_data_external::get_entry($entry13);
591 }
592
593 /**
594 * Test get_entry from other group in separated groups.
595 */
596 public function test_get_entry_other_group_separated_groups() {
597 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
598
599 // We should not be able to view other gropu entries (in separated groups).
600 $this->setUser($this->student1);
601 $this->expectException('moodle_exception');
602 $result = mod_data_external::get_entry($entry21);
603 }
a934c896
JL
604
605 /**
606 * Test get_fields.
607 */
608 public function test_get_fields() {
609 global $DB;
610 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
611
612 $this->setUser($this->student1);
613 $result = mod_data_external::get_fields($this->data->id);
614 $result = external_api::clean_returnvalue(mod_data_external::get_fields_returns(), $result);
615
616 // Basically compare we retrieve all the fields and the correct values.
617 $fields = $DB->get_records('data_fields', array('dataid' => $this->data->id), 'id');
618 foreach ($result['fields'] as $field) {
619 $this->assertEquals($field, (array) $fields[$field['id']]);
620 }
621 }
56b8edcb
JL
622
623 /**
624 * Test search_entries.
625 */
626 public function test_search_entries() {
627 global $DB;
628 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
629
630 // First do a normal text search as student 1. I should see my two group entries.
631 $this->setUser($this->student1);
632 $result = mod_data_external::search_entries($this->data->id, 0, false, 'text');
633 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
634 $this->assertCount(2, $result['entries']);
635 $this->assertEquals(2, $result['totalcount']);
636
637 // Now as the other student I should receive my not approved entry. Apply ordering here.
638 $this->setUser($this->student2);
639 $result = mod_data_external::search_entries($this->data->id, 0, false, 'text', [], DATA_APPROVED, 'ASC');
640 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
641 $this->assertCount(3, $result['entries']);
642 $this->assertEquals(3, $result['totalcount']);
643 // The not approved one should be the first.
644 $this->assertEquals($entry13, $result['entries'][0]['id']);
645
646 // Now as the other group student.
647 $this->setUser($this->student3);
648 $result = mod_data_external::search_entries($this->data->id, 0, false, 'text');
649 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
650 $this->assertCount(1, $result['entries']);
651 $this->assertEquals(1, $result['totalcount']);
652 $this->assertEquals($this->student3->id, $result['entries'][0]['userid']);
653
654 // Same normal text search as teacher.
655 $this->setUser($this->teacher);
656 $result = mod_data_external::search_entries($this->data->id, 0, false, 'text');
657 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
658 $this->assertCount(4, $result['entries']); // I can see all groups and non approved.
659 $this->assertEquals(4, $result['totalcount']);
660
661 // Pagination.
662 $this->setUser($this->teacher);
663 $result = mod_data_external::search_entries($this->data->id, 0, false, 'text', [], DATA_TIMEADDED, 'ASC', 0, 2);
664 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
665 $this->assertCount(2, $result['entries']); // Only 2 per page.
666 $this->assertEquals(4, $result['totalcount']);
667
668 // Now advanced search or not dinamic fields (user firstname for example).
669 $this->setUser($this->student1);
670 $advsearch = [
671 ['name' => 'fn', 'value' => json_encode($this->student2->firstname)]
672 ];
673 $result = mod_data_external::search_entries($this->data->id, 0, false, '', $advsearch);
674 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
675 $this->assertCount(1, $result['entries']);
676 $this->assertEquals(1, $result['totalcount']);
677 $this->assertEquals($this->student2->id, $result['entries'][0]['userid']); // I only found mine!
678
679 // Advanced search for fields.
680 $field = $DB->get_record('data_fields', array('type' => 'url'));
681 $advsearch = [
682 ['name' => 'f_' . $field->id , 'value' => 'sampleurl']
683 ];
684 $result = mod_data_external::search_entries($this->data->id, 0, false, '', $advsearch);
685 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
686 $this->assertCount(2, $result['entries']); // Found two entries matching this.
687 $this->assertEquals(2, $result['totalcount']);
688
689 // Combined search.
690 $field2 = $DB->get_record('data_fields', array('type' => 'number'));
691 $advsearch = [
692 ['name' => 'f_' . $field->id , 'value' => 'sampleurl'],
693 ['name' => 'f_' . $field2->id , 'value' => '12345'],
694 ['name' => 'ln', 'value' => json_encode($this->student2->lastname)]
695 ];
696 $result = mod_data_external::search_entries($this->data->id, 0, false, '', $advsearch);
697 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
698 $this->assertCount(1, $result['entries']); // Only one matching everything.
699 $this->assertEquals(1, $result['totalcount']);
700
701 // Combined search (no results).
702 $field2 = $DB->get_record('data_fields', array('type' => 'number'));
703 $advsearch = [
704 ['name' => 'f_' . $field->id , 'value' => 'sampleurl'],
705 ['name' => 'f_' . $field2->id , 'value' => '98780333'], // Non existent number.
706 ];
707 $result = mod_data_external::search_entries($this->data->id, 0, false, '', $advsearch);
708 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result);
709 $this->assertCount(0, $result['entries']); // Only one matching everything.
710 $this->assertEquals(0, $result['totalcount']);
711 }
229158fe
JL
712
713 /**
714 * Test approve_entry.
715 */
716 public function test_approve_entry() {
717 global $DB;
718 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
719
720 $this->setUser($this->teacher);
721 $this->assertEquals(0, $DB->get_field('data_records', 'approved', array('id' => $entry13)));
722 $result = mod_data_external::approve_entry($entry13);
723 $result = external_api::clean_returnvalue(mod_data_external::approve_entry_returns(), $result);
724 $this->assertEquals(1, $DB->get_field('data_records', 'approved', array('id' => $entry13)));
725 }
726
727 /**
728 * Test unapprove_entry.
729 */
730 public function test_unapprove_entry() {
731 global $DB;
732 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
733
734 $this->setUser($this->teacher);
735 $this->assertEquals(1, $DB->get_field('data_records', 'approved', array('id' => $entry11)));
736 $result = mod_data_external::approve_entry($entry11, false);
737 $result = external_api::clean_returnvalue(mod_data_external::approve_entry_returns(), $result);
738 $this->assertEquals(0, $DB->get_field('data_records', 'approved', array('id' => $entry11)));
739 }
740
741 /**
742 * Test approve_entry missing permissions.
743 */
744 public function test_approve_entry_missing_permissions() {
745 global $DB;
746 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
747
748 $this->setUser($this->student1);
749 $this->expectException('moodle_exception');
750 mod_data_external::approve_entry($entry13);
751 }
67bb168e
JL
752
753 /**
754 * Test delete_entry as teacher. Check I can delete any entry.
755 */
756 public function test_delete_entry_as_teacher() {
757 global $DB;
758 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
759
760 $this->setUser($this->teacher);
761 $result = mod_data_external::delete_entry($entry11);
762 $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result);
763 $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry11)));
764
765 // Entry in other group.
766 $result = mod_data_external::delete_entry($entry21);
767 $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result);
768 $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry21)));
769 }
770
771 /**
772 * Test delete_entry as student. Check I can delete my own entries.
773 */
774 public function test_delete_entry_as_student() {
775 global $DB;
776 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
777
778 $this->setUser($this->student1);
779 $result = mod_data_external::delete_entry($entry11);
780 $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result);
781 $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry11)));
782 }
783
784 /**
785 * Test delete_entry as student in read only mode period. Check I cannot delete my own entries in that period.
786 */
787 public function test_delete_entry_as_student_in_read_only_period() {
788 global $DB;
789 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
790 // Set a time period.
791 $this->data->timeviewfrom = time() - HOURSECS;
792 $this->data->timeviewto = time() + HOURSECS;
793 $DB->update_record('data', $this->data);
794
795 $this->setUser($this->student1);
796 $this->expectException('moodle_exception');
797 mod_data_external::delete_entry($entry11);
798 }
799
800 /**
801 * Test delete_entry with an user missing permissions.
802 */
803 public function test_delete_entry_missing_permissions() {
804 global $DB;
805 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
806
807 $this->setUser($this->student1);
808 $this->expectException('moodle_exception');
809 mod_data_external::delete_entry($entry21);
810 }
61c640c1
JL
811
812 /**
813 * Test add_entry.
814 */
815 public function test_add_entry() {
816 global $DB;
817 // First create the record structure and add some entries.
818 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
819
820 $this->setUser($this->student1);
821 $newentrydata = [];
822 $fields = $DB->get_records('data_fields', array('dataid' => $this->data->id), 'id');
823 // Prepare the new entry data.
824 foreach ($fields as $field) {
825 $subfield = $value = '';
826
827 switch ($field->type) {
828 case 'checkbox':
829 $value = ['opt1', 'opt2'];
830 break;
831 case 'date':
832 // Add two extra.
833 $newentrydata[] = [
834 'fieldid' => $field->id,
835 'subfield' => 'day',
836 'value' => json_encode('5')
837 ];
838 $newentrydata[] = [
839 'fieldid' => $field->id,
840 'subfield' => 'month',
841 'value' => json_encode('1')
842 ];
843 $subfield = 'year';
844 $value = '1981';
845 break;
846 case 'menu':
847 $value = 'menu1';
848 break;
849 case 'multimenu':
850 $value = ['multimenu1', 'multimenu4'];
851 break;
852 case 'number':
853 $value = 6;
854 break;
855 case 'radiobutton':
856 $value = 'radioopt1';
857 break;
858 case 'text':
859 $value = 'some text';
860 break;
861 case 'textarea':
862 $newentrydata[] = [
863 'fieldid' => $field->id,
864 'subfield' => 'content1',
865 'value' => json_encode(FORMAT_MOODLE)
866 ];
867 $newentrydata[] = [
868 'fieldid' => $field->id,
869 'subfield' => 'itemid',
870 'value' => json_encode(0)
871 ];
872 $value = 'more text';
873 break;
874 case 'url':
875 $value = 'https://moodle.org';
876 $subfield = 0;
877 break;
878 }
879
880 $newentrydata[] = [
881 'fieldid' => $field->id,
882 'subfield' => $subfield,
883 'value' => json_encode($value)
884 ];
885 }
886 $result = mod_data_external::add_entry($this->data->id, 0, $newentrydata);
887 $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result);
888
889 $newentryid = $result['newentryid'];
890 $result = mod_data_external::get_entry($newentryid, 0, true);
891 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result);
892 $this->assertEquals($this->student1->id, $result['entry']['userid']);
893 $this->assertCount(9, $result['entry']['contents']);
894 foreach ($result['entry']['contents'] as $content) {
895 $field = $fields[$content['fieldid']];
896 // Stored content same that the one retrieved by WS.
897 $dbcontent = $DB->get_record('data_content', array('fieldid' => $field->id, 'recordid' => $newentryid));
898 $this->assertEquals($dbcontent->content, $content['content']);
899
900 // Now double check everything stored is correct.
901 if ($field->type == 'checkbox') {
902 $this->assertEquals('opt1##opt2', $content['content']);
903 continue;
904 }
905 if ($field->type == 'date') {
906 $this->assertEquals(347500800, $content['content']); // Date in gregorian format.
907 continue;
908 }
909 if ($field->type == 'menu') {
910 $this->assertEquals('menu1', $content['content']);
911 continue;
912 }
913 if ($field->type == 'multimenu') {
914 $this->assertEquals('multimenu1##multimenu4', $content['content']);
915 continue;
916 }
917 if ($field->type == 'number') {
918 $this->assertEquals(6, $content['content']);
919 continue;
920 }
921 if ($field->type == 'radiobutton') {
922 $this->assertEquals('radioopt1', $content['content']);
923 continue;
924 }
925 if ($field->type == 'text') {
926 $this->assertEquals('some text', $content['content']);
927 continue;
928 }
929 if ($field->type == 'textarea') {
930 $this->assertEquals('more text', $content['content']);
931 $this->assertEquals(FORMAT_MOODLE, $content['content1']);
932 continue;
933 }
934 if ($field->type == 'url') {
935 $this->assertEquals('https://moodle.org', $content['content']);
936 continue;
937 }
938 $this->assertEquals('multimenu1##multimenu4', $content['content']);
939 }
940
941 // Now, try to add another entry but removing some required data.
942 unset($newentrydata[0]);
943 $result = mod_data_external::add_entry($this->data->id, 0, $newentrydata);
944 $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result);
945 $this->assertEquals(0, $result['newentryid']);
946 $this->assertCount(0, $result['generalnotifications']);
947 $this->assertCount(1, $result['fieldnotifications']);
948 $this->assertEquals('field-1', $result['fieldnotifications'][0]['fieldname']);
949 $this->assertEquals(get_string('errormustsupplyvalue', 'data'), $result['fieldnotifications'][0]['notification']);
950 }
951
952 /**
953 * Test add_entry empty_form.
954 */
955 public function test_add_entry_empty_form() {
956 $result = mod_data_external::add_entry($this->data->id, 0, []);
957 $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result);
958 $this->assertEquals(0, $result['newentryid']);
959 $this->assertCount(1, $result['generalnotifications']);
960 $this->assertCount(0, $result['fieldnotifications']);
961 $this->assertEquals(get_string('emptyaddform', 'data'), $result['generalnotifications'][0]);
962 }
963
964 /**
965 * Test add_entry read_only_period.
966 */
967 public function test_add_entry_read_only_period() {
968 global $DB;
969 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
970 // Set a time period.
971 $this->data->timeviewfrom = time() - HOURSECS;
972 $this->data->timeviewto = time() + HOURSECS;
973 $DB->update_record('data', $this->data);
974
975 $this->setUser($this->student1);
976 $this->expectExceptionMessage(get_string('noaccess', 'data'));
977 $this->expectException('moodle_exception');
978 mod_data_external::add_entry($this->data->id, 0, []);
979 }
980
981 /**
982 * Test add_entry max_num_entries.
983 */
984 public function test_add_entry_max_num_entries() {
985 global $DB;
986 list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries();
987 // Set a time period.
988 $this->data->maxentries = 1;
989 $DB->update_record('data', $this->data);
990
991 $this->setUser($this->student1);
992 $this->expectExceptionMessage(get_string('noaccess', 'data'));
993 $this->expectException('moodle_exception');
994 mod_data_external::add_entry($this->data->id, 0, []);
995 }
067b3fda 996}