See Release Notes
Long Term Support Release
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace core_calendar; use core_calendar_external; use externallib_advanced_testcase;> use core_external\external_api;defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/webservice/tests/helpers.php'); /** * External course functions unit tests * * @package core_calendar * @category external * @copyright 2012 Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.5 */ class externallib_test extends externallib_advanced_testcase { /** * Tests set up */ protected function setUp(): void { global $CFG; require_once($CFG->dirroot . '/calendar/externallib.php'); } /** Create calendar events or update them * Set $prop->id, if you want to do an update instead of creating an new event * * @param string $name Event title * @param int $userid User id * @param string $type Event type * @param int $repeats Number of repeated events to create * @param int $timestart Time stamp of the event start * @param mixed $prop List of event properties as array or object * @return mixed Event object or false; * @since Moodle 2.5 */ public static function create_calendar_event($name, $userid = 0, $type = 'user', $repeats = 0, $timestart = null, $prop = null) { global $CFG, $DB, $SITE; require_once("$CFG->dirroot/calendar/lib.php"); if (!empty($prop)) { if (is_array($prop)) { $prop = (object)$prop; } } else { $prop = new \stdClass(); } $prop->name = $name; if (empty($prop->eventtype)) { $prop->eventtype = $type; } if (empty($prop->repeats)) { $prop->repeats = $repeats; } if (empty($prop->timestart)) { $prop->timestart = time(); } if (empty($prop->timeduration)) { $prop->timeduration = 0; } if (empty($prop->timesort)) { $prop->timesort = 0; } if (empty($prop->type)) { $prop->type = CALENDAR_EVENT_TYPE_STANDARD; } if (empty($prop->repeats)) { $prop->repeat = 0; } else { $prop->repeat = 1; } if (empty($prop->userid)) { if (!empty($userid)) { $prop->userid = $userid; } else { $prop->userid = 0; } } if (!isset($prop->courseid)) { // Set a default value of the event's course ID field. if ($type === 'user') { // If it's a user event, course ID should be zero. $prop->courseid = 0; } else { // Otherwise, default to the site ID. $prop->courseid = $SITE->id; } } // Determine event priority. if ($prop->courseid == 0 && isset($prop->groupid) && $prop->groupid == 0 && !empty($prop->userid)) { // User override event. $prop->priority = CALENDAR_EVENT_USER_OVERRIDE_PRIORITY; } else if ($prop->courseid != $SITE->id && !empty($prop->groupid)) { // Group override event. $priorityparams = ['courseid' => $prop->courseid, 'groupid' => $prop->groupid]; // Group override event with the highest priority. $groupevents = $DB->get_records('event', $priorityparams, 'priority DESC', 'id, priority', 0, 1); $priority = 1; if (!empty($groupevents)) { $event = reset($groupevents); if (!empty($event->priority)) { $priority = $event->priority + 1; } } $prop->priority = $priority; } $event = new \calendar_event($prop); return $event->create($prop); } public function test_create_calendar_events () { global $DB, $USER; $this->setAdminUser(); $this->resetAfterTest(); $prevcount = count($DB->get_records("event")); // Create a few events and do asserts. $this->create_calendar_event('test', $USER->id); $where = $DB->sql_compare_text('name') ." = ?"; $count = count($DB->get_records_select("event", $where, array('test'))); $this->assertEquals(1, $count); $aftercount = count($DB->get_records("event")); $this->assertEquals($prevcount + 1, $aftercount); $this->create_calendar_event('user', $USER->id, 'user', 3); $where = $DB->sql_compare_text('name') ." = ?"; $count = count($DB->get_records_select("event", $where, array('user'))); $this->assertEquals(3, $count); $aftercount = count($DB->get_records("event")); $this->assertEquals($prevcount + 4, $aftercount); } /** * Test delete_calendar_events */ public function test_delete_calendar_events() { global $DB, $USER; $this->resetAfterTest(true); $this->setAdminUser(); // Create a few stuff to test with. $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $record = new \stdClass(); $record->courseid = $course->id; $group = $this->getDataGenerator()->create_group($record); $notdeletedcount = $DB->count_records('event'); // Let's create a few events. $siteevent = $this->create_calendar_event('site', $USER->id, 'site'); $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 2, time(), $record); $userevent = $this->create_calendar_event('user', $USER->id); $record = new \stdClass(); $record->courseid = $course->id; $record->groupid = $group->id; $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record); // Now lets try to delete stuff with proper rights. $events = array( array('eventid' => $siteevent->id, 'repeat' => 0), array('eventid' => $courseevent->id, 'repeat' => 1), array('eventid' => $userevent->id, 'repeat' => 0), array('eventid' => $groupevent->id, 'repeat' => 0) ); core_calendar_external::delete_calendar_events($events); // Check to see if things were deleted properly. $deletedcount = $DB->count_records('event'); $this->assertEquals($notdeletedcount, $deletedcount); // Let's create a few events. $siteevent = $this->create_calendar_event('site', $USER->id, 'site'); $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 3, time(), $record); $userevent = $this->create_calendar_event('user', $user->id); $record = new \stdClass(); $record->courseid = $course->id; $record->groupid = $group->id; $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record); $this->setuser($user); $sitecontext = \context_system::instance(); $coursecontext = \context_course::instance($course->id); $usercontext = \context_user::instance($user->id); $role = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); // Remove all caps. $this->unassignUserCapability('moodle/calendar:manageentries', $sitecontext->id, $role->id); $this->unassignUserCapability('moodle/calendar:manageentries', $coursecontext->id, $role->id); $this->unassignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id); $this->unassignUserCapability('moodle/calendar:manageownentries', $usercontext->id, $role->id); // Assign proper caps and attempt delete. $this->assignUserCapability('moodle/calendar:manageentries', $sitecontext->id, $role->id); $events = array( array('eventid' => $siteevent->id, 'repeat' => 0), ); core_calendar_external::delete_calendar_events($events); $deletedcount = $DB->count_records('event'); $count = $notdeletedcount+5; $this->assertEquals($count, $deletedcount); $this->assignUserCapability('moodle/calendar:manageentries', $sitecontext->id, $role->id); $events = array( array('eventid' => $courseevent->id, 'repeat' => 0), ); core_calendar_external::delete_calendar_events($events); $deletedcount = $DB->count_records('event'); $count = $notdeletedcount+4; $this->assertEquals($count, $deletedcount); $this->assignUserCapability('moodle/calendar:manageownentries', $usercontext->id, $role->id); $events = array( array('eventid' => $userevent->id, 'repeat' => 0), ); core_calendar_external::delete_calendar_events($events); $deletedcount = $DB->count_records('event'); $count = $notdeletedcount+3; $this->assertEquals($count, $deletedcount); $this->assignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id); $events = array( array('eventid' => $groupevent->id, 'repeat' => 0), ); core_calendar_external::delete_calendar_events($events); $deletedcount = $DB->count_records('event'); $count = $notdeletedcount+2; $this->assertEquals($count, $deletedcount); $notdeletedcount = $deletedcount; // Let us try deleting without caps. $siteevent = $this->create_calendar_event('site', $USER->id, 'site'); $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 3, time(), $record); $userevent = $this->create_calendar_event('user', $USER->id); $record = new \stdClass(); $record->courseid = $course->id; $record->groupid = $group->id; $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record); $this->setGuestUser(); $events = array( array('eventid' => $siteevent->id, 'repeat' => 0), array('eventid' => $courseevent->id, 'repeat' => 0), array('eventid' => $userevent->id, 'repeat' => 0), array('eventid' => $groupevent->id, 'repeat' => 0) ); $this->expectException(\moodle_exception::class); core_calendar_external::delete_calendar_events($events); } /** * Test get_calendar_events */ public function test_get_calendar_events() { global $DB, $USER; $this->resetAfterTest(true); set_config('calendar_adminseesall', 1); $this->setAdminUser(); // Create a few stuff to test with. $user = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $category = $this->getDataGenerator()->create_category(); $category2 = $this->getDataGenerator()->create_category(); $category2b = $this->getDataGenerator()->create_category(['parent' => $category2->id]); $course3 = $this->getDataGenerator()->create_course(['category' => $category2b->id]); $role = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user2->id, $course3->id, $role->id); $record = new \stdClass(); $record->courseid = $course->id; $group = $this->getDataGenerator()->create_group($record); $beforecount = $DB->count_records('event'); // Let's create a few events. $siteevent = $this->create_calendar_event('site', $USER->id, 'site'); // This event will have description with an inline fake image. $draftidfile = file_get_unused_draft_itemid(); $usercontext = \context_course::instance($course->id); $filerecord = array( 'contextid' => $usercontext->id, 'component' => 'user', 'filearea' => 'draft', 'itemid' => $draftidfile, 'filepath' => '/', 'filename' => 'fakeimage.png', ); $fs = get_file_storage(); $fs->create_file_from_string($filerecord, 'img contents'); $record = new \stdClass(); $record->courseid = $course->id; $record->groupid = 0; $record->description = array( 'format' => FORMAT_HTML, 'text' => 'Text with img <img src="@@PLUGINFILE@@/fakeimage.png">', 'itemid' => $draftidfile ); $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 2, time(), $record); $record = new \stdClass(); $record->courseid = 0; $record->groupid = 0; $userevent = $this->create_calendar_event('user', $USER->id, 'user', 0, time(), $record); $record = new \stdClass(); $record->courseid = $course->id; $record->groupid = $group->id; $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record); $paramevents = array ('eventids' => array($siteevent->id), 'courseids' => array($course->id), 'groupids' => array($group->id), 'categoryids' => array($category->id)); $options = array ('siteevents' => true, 'userevents' => true); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);// Check to see if we got all events. $this->assertEquals(5, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); $options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + 7*WEEKSECS); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(5, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); // Expect the same URL in the description of two different events (because they are repeated). $coursecontext = \context_course::instance($course->id); $expectedurl = "webservice/pluginfile.php/$coursecontext->id/calendar/event_description/$courseevent->id/fakeimage.png"; $withdescription = 0; foreach ($events['events'] as $event) { if (!empty($event['description'])) { $withdescription++; $this->assertStringContainsString($expectedurl, $event['description']); } } $this->assertEquals(2, $withdescription); // Let's play around with caps. // Create user event for the user $user. $record = new \stdClass(); $record->courseid = 0; $record->groupid = 0; $this->create_calendar_event('user', $user->id, 'user', 0, time(), $record); $this->setUser($user); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(2, count($events['events'])); // site, user. $this->assertEquals(2, count($events['warnings'])); // course, group. $role = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(4, count($events['events'])); // site, user, both course events. $this->assertEquals(1, count($events['warnings'])); // group. $options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + HOURSECS); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(3, count($events['events'])); // site, user, one course event. $this->assertEquals(1, count($events['warnings'])); // group. groups_add_member($group, $user); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(4, count($events['events'])); // site, user, group, one course event. $this->assertEquals(0, count($events['warnings'])); $paramevents = array ('courseids' => array($course->id), 'groupids' => array($group->id)); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(4, count($events['events'])); // site, user, group, one course event. $this->assertEquals(0, count($events['warnings'])); $paramevents = array ('groupids' => array($group->id, 23)); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(3, count($events['events'])); // site, user, group. $this->assertEquals(1, count($events['warnings'])); $paramevents = array ('courseids' => array(23)); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(2, count($events['events'])); // site, user. $this->assertEquals(1, count($events['warnings'])); $paramevents = array (); $options = array ('siteevents' => false, 'userevents' => false, 'timeend' => time() + 7*WEEKSECS); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(0, count($events['events'])); // nothing returned. $this->assertEquals(0, count($events['warnings'])); $paramevents = array ('eventids' => array($siteevent->id, $groupevent->id)); $options = array ('siteevents' => false, 'userevents' => false, 'timeend' => time() + 7*WEEKSECS); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(2, count($events['events'])); // site, group. $this->assertEquals(0, count($events['warnings'])); $paramevents = array ('eventids' => array($siteevent->id)); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(1, count($events['events'])); // site. $this->assertEquals(0, count($events['warnings'])); // Try getting a course event by its id. $paramevents = array ('eventids' => array($courseevent->id)); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(1, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); // Now, create an activity event. $this->setAdminUser(); $nexttime = time() + DAYSECS; $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id, 'duedate' => $nexttime)); $this->setUser($user); $paramevents = array ('courseids' => array($course->id)); $options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + WEEKSECS); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertCount(5, $events['events']); // Hide the assignment. set_coursemodule_visible($assign->cmid, 0); // Empty all the caches that may be affected by this change. accesslib_clear_all_caches_for_unit_testing(); \course_modinfo::clear_instance_cache(); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);// Expect one less. $this->assertCount(4, $events['events']); // Create some category events. $this->setAdminUser(); $record = new \stdClass(); $record->courseid = 0; $record->categoryid = $category->id; $record->timestart = time() - DAYSECS; $catevent1 = $this->create_calendar_event('category a', $USER->id, 'category', 0, time(), $record); $record = new \stdClass(); $record->courseid = 0; $record->categoryid = $category2->id; $record->timestart = time() + DAYSECS; $catevent2 = $this->create_calendar_event('category b', $USER->id, 'category', 0, time(), $record); // Now as student, make sure we get the events of the courses I am enrolled. $this->setUser($user2); $paramevents = array('categoryids' => array($category2b->id)); $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);// Should be just one, since there's just one category event of the course I am enrolled (course3 - cat2b). $this->assertEquals(1, count($events['events'])); $this->assertEquals($catevent2->id, $events['events'][0]['id']); $this->assertEquals($category2->id, $events['events'][0]['categoryid']); $this->assertEquals(0, count($events['warnings'])); // Now get category events but by course (there aren't course events in the course). $paramevents = array('courseids' => array($course3->id)); $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(1, count($events['events'])); $this->assertEquals($catevent2->id, $events['events'][0]['id']); $this->assertEquals(0, count($events['warnings'])); // Empty events in one where I'm not enrolled and one parent category // (parent of a category where this is a course where the user is enrolled). $paramevents = array('categoryids' => array($category2->id, $category->id)); $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(1, count($events['events'])); $this->assertEquals($catevent2->id, $events['events'][0]['id']); $this->assertEquals(0, count($events['warnings'])); // Admin can see all category events. $this->setAdminUser(); $paramevents = array('categoryids' => array($category->id, $category2->id, $category2b->id)); $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(2, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); $this->assertEquals($catevent1->id, $events['events'][0]['id']); $this->assertEquals($category->id, $events['events'][0]['categoryid']); $this->assertEquals($catevent2->id, $events['events'][1]['id']); $this->assertEquals($category2->id, $events['events'][1]['categoryid']); } /** * Test get_calendar_events with mathjax in the name. */ public function test_get_calendar_events_with_mathjax() { global $USER; $this->resetAfterTest(true); set_config('calendar_adminseesall', 1); $this->setAdminUser(); // Enable MathJax filter in content and headings. $this->configure_filters([ ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true], ]); // Create a site event with mathjax in the name and description. $siteevent = $this->create_calendar_event('Site Event $$(a+b)=2$$', $USER->id, 'site', 0, time(), ['description' => 'Site Event Description $$(a+b)=2$$']); // Now call the WebService. $events = core_calendar_external::get_calendar_events();< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);// Format the original data. $sitecontext = \context_system::instance(); $siteevent->name = $siteevent->format_external_name(); list($siteevent->description, $siteevent->descriptionformat) = $siteevent->format_external_text(); // Check that the event data is formatted. $this->assertCount(1, $events['events']); $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $events['events'][0]['name']); $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $events['events'][0]['description']); $this->assertEquals($siteevent->name, $events['events'][0]['name']); $this->assertEquals($siteevent->description, $events['events'][0]['description']); } /** * Test core_calendar_external::create_calendar_events */ public function test_core_create_calendar_events() { global $DB, $USER, $SITE; $this->resetAfterTest(true); $this->setAdminUser(); // Create a few stuff to test with. $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $record = new \stdClass(); $record->courseid = $course->id; $group = $this->getDataGenerator()->create_group($record); $prevcount = $DB->count_records('event'); // Let's create a few events. $events = array ( array('name' => 'site', 'courseid' => $SITE->id, 'eventtype' => 'site'), array('name' => 'course', 'courseid' => $course->id, 'eventtype' => 'course', 'repeats' => 2), array('name' => 'group', 'courseid' => $course->id, 'groupid' => $group->id, 'eventtype' => 'group'), array('name' => 'user') ); $eventsret = core_calendar_external::create_calendar_events($events);< $eventsret = \external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);> $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);// Check to see if things were created properly. $aftercount = $DB->count_records('event'); $this->assertEquals($prevcount + 5, $aftercount); $this->assertEquals(5, count($eventsret['events'])); $this->assertEquals(0, count($eventsret['warnings'])); $sitecontext = \context_system::instance(); $coursecontext = \context_course::instance($course->id); $this->setUser($user); $prevcount = $aftercount; $events = array ( array('name' => 'course', 'courseid' => $course->id, 'eventtype' => 'course', 'repeats' => 2), array('name' => 'group', 'courseid' => $course->id, 'groupid' => $group->id, 'eventtype' => 'group'), array('name' => 'user') ); $role = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); groups_add_member($group, $user); $this->assignUserCapability('moodle/calendar:manageentries', $coursecontext->id, $role->id); $this->assignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id); $eventsret = core_calendar_external::create_calendar_events($events);< $eventsret = \external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);> $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);// Check to see if things were created properly. $aftercount = $DB->count_records('event'); $this->assertEquals($prevcount + 4, $aftercount); $this->assertEquals(4, count($eventsret['events'])); $this->assertEquals(0, count($eventsret['warnings'])); // Check to see nothing was created without proper permission. $this->setGuestUser(); $prevcount = $DB->count_records('event'); $eventsret = core_calendar_external::create_calendar_events($events);< $eventsret = \external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);> $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);$aftercount = $DB->count_records('event'); $this->assertEquals($prevcount, $aftercount); $this->assertEquals(0, count($eventsret['events'])); $this->assertEquals(3, count($eventsret['warnings'])); $this->setUser($user); $this->unassignUserCapability('moodle/calendar:manageentries', $coursecontext->id, $role->id); $this->unassignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id); $prevcount = $DB->count_records('event'); $eventsret = core_calendar_external::create_calendar_events($events);< $eventsret = \external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);> $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);$aftercount = $DB->count_records('event'); $this->assertEquals($prevcount + 1, $aftercount); // User event. $this->assertEquals(1, count($eventsret['events'])); $this->assertEquals(2, count($eventsret['warnings'])); } /** * Requesting calendar events from a given time should return all events with a sort * time at or after the requested time. All events prior to that time should not * be return. * * If there are no events on or after the given time then an empty result set should * be returned. */ public function test_get_calendar_action_events_by_timesort_after_time() { $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $moduleinstance = $generator->create_instance(['course' => $course->id]); $this->getDataGenerator()->enrol_user($user->id, $course->id); $this->resetAfterTest(true); $this->setUser($user); $params = [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'modulename' => 'assign', 'instance' => $moduleinstance->id, 'courseid' => $course->id, ]; $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1])); $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2])); $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3])); $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4])); $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5])); $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6])); $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7])); $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8])); $result = core_calendar_external::get_calendar_action_events_by_timesort(5);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(4, $events); $this->assertEquals('Event 5', $events[0]['name']); $this->assertEquals('Event 6', $events[1]['name']); $this->assertEquals('Event 7', $events[2]['name']); $this->assertEquals('Event 8', $events[3]['name']); $this->assertEquals($event5->id, $result['firstid']); $this->assertEquals($event8->id, $result['lastid']); $result = core_calendar_external::get_calendar_action_events_by_timesort(9);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $this->assertEmpty($result['events']); $this->assertNull($result['firstid']); $this->assertNull($result['lastid']); // Requesting action events on behalf of another user. $this->setAdminUser(); $result = core_calendar_external::get_calendar_action_events_by_timesort(5, null, 0, 20, false, $user->id);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(4, $events); $this->assertEquals('Event 5', $events[0]['name']); $this->assertEquals('Event 6', $events[1]['name']); $this->assertEquals('Event 7', $events[2]['name']); $this->assertEquals('Event 8', $events[3]['name']); $this->assertEquals($event5->id, $result['firstid']); $this->assertEquals($event8->id, $result['lastid']); } /** * Requesting calendar events before a given time should return all events with a sort * time at or before the requested time (inclusive). All events after that time * should not be returned. * * If there are no events before the given time then an empty result set should be * returned. */ public function test_get_calendar_action_events_by_timesort_before_time() { $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $moduleinstance = $generator->create_instance(['course' => $course->id]); $this->getDataGenerator()->enrol_user($user->id, $course->id); $this->resetAfterTest(true); $this->setUser($user); $params = [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'modulename' => 'assign', 'instance' => $moduleinstance->id, 'courseid' => $course->id, ]; $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2])); $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3])); $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4])); $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5])); $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6])); $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7])); $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8])); $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 9])); $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 5);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(4, $events); $this->assertEquals('Event 1', $events[0]['name']); $this->assertEquals('Event 2', $events[1]['name']); $this->assertEquals('Event 3', $events[2]['name']); $this->assertEquals('Event 4', $events[3]['name']); $this->assertEquals($event1->id, $result['firstid']); $this->assertEquals($event4->id, $result['lastid']); $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 1);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $this->assertEmpty($result['events']); $this->assertNull($result['firstid']); $this->assertNull($result['lastid']); // Requesting action events on behalf of another user. $this->setAdminUser(); $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 5, 0, 20, false, $user->id);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(4, $events); $this->assertEquals('Event 1', $events[0]['name']); $this->assertEquals('Event 2', $events[1]['name']); $this->assertEquals('Event 3', $events[2]['name']); $this->assertEquals('Event 4', $events[3]['name']); $this->assertEquals($event1->id, $result['firstid']); $this->assertEquals($event4->id, $result['lastid']); } /** * Test retrieving event that was overridden for a user */ public function test_get_calendar_events_override() { $user = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $teacher = $this->getDataGenerator()->create_user(); $anotheruser = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $moduleinstance = $generator->create_instance(['course' => $course->id]); $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher'); $this->resetAfterTest(true); $this->setAdminUser(); $params = [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'modulename' => 'assign', 'instance' => $moduleinstance->id, ]; $now = time(); // Create two events - one for everybody in the course and one only for the first student. $event1 = $this->create_calendar_event('Base event', 0, 'due', 0, $now + DAYSECS, $params + ['courseid' => $course->id]); $event2 = $this->create_calendar_event('User event', $user->id, 'due', 0, $now + 2*DAYSECS, $params + ['courseid' => 0]); // Retrieve course events for the second student - only one "Base event" is returned. $this->setUser($user2); $paramevents = array('courseids' => array($course->id)); $options = array ('siteevents' => true, 'userevents' => true); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(1, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); $this->assertEquals('Base event', $events['events'][0]['name']); // Retrieve events for the first student - both events are returned. $this->setUser($user); $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(2, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); $this->assertEquals('Base event', $events['events'][0]['name']); $this->assertEquals('User event', $events['events'][1]['name']); // Retrieve events by id as a teacher, 'User event' should be returned since teacher has access to this course. $this->setUser($teacher); $paramevents = ['eventids' => [$event2->id]]; $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(1, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); $this->assertEquals('User event', $events['events'][0]['name']); // Retrieve events by id as another user, nothing should be returned. $this->setUser($anotheruser); $paramevents = ['eventids' => [$event2->id, $event1->id]]; $events = core_calendar_external::get_calendar_events($paramevents, $options);< $events = \external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);> $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);$this->assertEquals(0, count($events['events'])); $this->assertEquals(0, count($events['warnings'])); } /** * Requesting calendar events within a given time range should return all events with * a sort time between the lower and upper time bound (inclusive). * * If there are no events in the given time range then an empty result set should be * returned. */ public function test_get_calendar_action_events_by_timesort_time_range() { $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $moduleinstance = $generator->create_instance(['course' => $course->id]); $this->getDataGenerator()->enrol_user($user->id, $course->id); $this->resetAfterTest(true); $this->setUser($user); $params = [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'modulename' => 'assign', 'instance' => $moduleinstance->id, 'courseid' => $course->id, ]; $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1])); $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2])); $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3])); $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4])); $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5])); $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6])); $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7])); $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8])); $result = core_calendar_external::get_calendar_action_events_by_timesort(3, 6);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(4, $events); $this->assertEquals('Event 3', $events[0]['name']); $this->assertEquals('Event 4', $events[1]['name']); $this->assertEquals('Event 5', $events[2]['name']); $this->assertEquals('Event 6', $events[3]['name']); $this->assertEquals($event3->id, $result['firstid']); $this->assertEquals($event6->id, $result['lastid']); $result = core_calendar_external::get_calendar_action_events_by_timesort(10, 15);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $this->assertEmpty($result['events']); $this->assertNull($result['firstid']); $this->assertNull($result['lastid']); } /** * Requesting calendar events within a given time range and a limit and offset should return * the number of events up to the given limit value that have a sort time between the lower * and uppper time bound (inclusive) where the result set is shifted by the offset value. * * If there are no events in the given time range then an empty result set should be * returned. */ public function test_get_calendar_action_events_by_timesort_time_limit_offset() { $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $moduleinstance = $generator->create_instance(['course' => $course->id]); $this->getDataGenerator()->enrol_user($user->id, $course->id); $this->resetAfterTest(true); $this->setUser($user); $params = [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'modulename' => 'assign', 'instance' => $moduleinstance->id, 'courseid' => $course->id, ]; $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1])); $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2])); $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3])); $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4])); $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5])); $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6])); $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7])); $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8])); $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event3->id, 2);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(2, $events); $this->assertEquals('Event 4', $events[0]['name']); $this->assertEquals('Event 5', $events[1]['name']); $this->assertEquals($event4->id, $result['firstid']); $this->assertEquals($event5->id, $result['lastid']); $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event5->id, 2);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $events = $result['events']; $this->assertCount(2, $events); $this->assertEquals('Event 6', $events[0]['name']); $this->assertEquals('Event 7', $events[1]['name']); $this->assertEquals($event6->id, $result['firstid']); $this->assertEquals($event7->id, $result['lastid']); $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event7->id, 2);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_timesort_returns(), $result ); $this->assertEmpty($result['events']); $this->assertNull($result['firstid']); $this->assertNull($result['lastid']); } /** * Check that it is possible to restrict the calendar events to events where the user is not suspended in the course. */ public function test_get_calendar_action_events_by_timesort_suspended_course() { $this->resetAfterTest(); $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $this->setAdminUser(); $lesson = $this->getDataGenerator()->create_module('lesson', [ 'name' => 'Lesson 1', 'course' => $course->id, 'available' => time(), 'deadline' => (time() + (60 * 60 * 24 * 5)) ] ); $this->getDataGenerator()->enrol_user($user1->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED); $this->getDataGenerator()->enrol_user($user2->id, $course->id); $this->setUser($user1); $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true); $this->assertEmpty($result->events); $this->setUser($user2); $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true); $this->assertCount(1, $result->events); $this->assertEquals('Lesson 1 closes', $result->events[0]->name); } /** * Check that it is possible to get other user's events without the permission. */ public function test_get_calendar_action_events_by_timesort_for_other_users() { $this->resetAfterTest(); // Create test users. $user1 = $this->getDataGenerator()->create_user(['email' => 'student1@localhost.com']); $user2 = $this->getDataGenerator()->create_user(['email' => 'student2@localhost.com']); // Create test course. $course = $this->getDataGenerator()->create_course(); $this->setAdminUser(); // Create test activity and make it available only for student2. $lesson = $this->getDataGenerator()->create_module('lesson', [ 'name' => 'Lesson 1', 'course' => $course->id, 'available' => time(), 'deadline' => (time() + (60 * 60 * 24 * 5)), 'availability' => '{"op":"&","c":[{"type":"profile","sf":"email","op":"isequalto","v":"student2@localhost.com"}],"showc":[true]}' ] ); // Enrol. $this->getDataGenerator()->enrol_user($user1->id, $course->id); $this->getDataGenerator()->enrol_user($user2->id, $course->id); // Student2 can see the event. $this->setUser($user2); $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true); $this->assertCount(1, $result->events); $this->assertEquals('Lesson 1 closes', $result->events[0]->name); // Student1 cannot see the event. $this->setUser($user1); $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true); $this->assertEmpty($result->events); // Admin, Manager, Teacher can view student2's data. $this->setAdminUser(); $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true, $user2->id); $this->assertCount(1, $result->events); $this->assertEquals('Lesson 1 closes', $result->events[0]->name); // Student1 will see an exception if he/she trying to view student2's data. $this->setUser($user1); $this->expectException(\required_capability_exception::class); $this->expectExceptionMessage('error/nopermission'); $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true, $user2->id); } /** * Requesting calendar events from a given course and time should return all * events with a sort time at or after the requested time. All events prior * to that time should not be return. * * If there are no events on or after the given time then an empty result set should * be returned. */ public function test_get_calendar_action_events_by_course_after_time() { $user = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance1 = $generator->create_instance(['course' => $course1->id]); $instance2 = $generator->create_instance(['course' => $course2->id]); $records = []; $this->getDataGenerator()->enrol_user($user->id, $course1->id); $this->getDataGenerator()->enrol_user($user->id, $course2->id); $this->resetAfterTest(true); $this->setUser($user); for ($i = 1; $i < 19; $i++) { $courseid = ($i < 9) ? $course1->id : $course2->id; $instance = ($i < 9) ? $instance1->id : $instance2->id; $records[] = $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $courseid, 'timesort' => $i, 'modulename' => 'assign', 'instance' => $instance, ] ); } $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 5);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(4, $result); $this->assertEquals('Event 5', $result[0]['name']); $this->assertEquals('Event 6', $result[1]['name']); $this->assertEquals('Event 7', $result[2]['name']); $this->assertEquals('Event 8', $result[3]['name']); $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 9);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertEmpty($result); } /** * Requesting calendar events for a course and before a given time should return * all events with a sort time at or before the requested time (inclusive). All * events after that time should not be returned. * * If there are no events before the given time then an empty result set should be * returned. */ public function test_get_calendar_action_events_by_course_before_time() { $user = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance1 = $generator->create_instance(['course' => $course1->id]); $instance2 = $generator->create_instance(['course' => $course2->id]); $records = []; $this->getDataGenerator()->enrol_user($user->id, $course1->id); $this->getDataGenerator()->enrol_user($user->id, $course2->id); $this->resetAfterTest(true); $this->setUser($user); for ($i = 1; $i < 19; $i++) { $courseid = ($i < 9) ? $course1->id : $course2->id; $instance = ($i < 9) ? $instance1->id : $instance2->id; $records[] = $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $courseid, 'timesort' => $i + 1, 'modulename' => 'assign', 'instance' => $instance, ] ); } $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, null, 5);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(4, $result); $this->assertEquals('Event 1', $result[0]['name']); $this->assertEquals('Event 2', $result[1]['name']); $this->assertEquals('Event 3', $result[2]['name']); $this->assertEquals('Event 4', $result[3]['name']); $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, null, 1);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertEmpty($result); } /** * Requesting calendar events for a course and within a given time range should * return all events with a sort time between the lower and upper time bound * (inclusive). * * If there are no events in the given time range then an empty result set should be * returned. */ public function test_get_calendar_action_events_by_course_time_range() { $user = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance1 = $generator->create_instance(['course' => $course1->id]); $instance2 = $generator->create_instance(['course' => $course2->id]); $records = []; $this->getDataGenerator()->enrol_user($user->id, $course1->id); $this->getDataGenerator()->enrol_user($user->id, $course2->id); $this->resetAfterTest(true); $this->setUser($user); for ($i = 1; $i < 19; $i++) { $courseid = ($i < 9) ? $course1->id : $course2->id; $instance = ($i < 9) ? $instance1->id : $instance2->id; $records[] = $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $courseid, 'timesort' => $i, 'modulename' => 'assign', 'instance' => $instance, ] ); } $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 3, 6);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(4, $result); $this->assertEquals('Event 3', $result[0]['name']); $this->assertEquals('Event 4', $result[1]['name']); $this->assertEquals('Event 5', $result[2]['name']); $this->assertEquals('Event 6', $result[3]['name']); $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 10, 15);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertEmpty($result); } /** * Requesting calendar events for a course and within a given time range and a limit * and offset should return the number of events up to the given limit value that have * a sort time between the lower and uppper time bound (inclusive) where the result * set is shifted by the offset value. * * If there are no events in the given time range then an empty result set should be * returned. */ public function test_get_calendar_action_events_by_course_time_limit_offset() { $user = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance1 = $generator->create_instance(['course' => $course1->id]); $instance2 = $generator->create_instance(['course' => $course2->id]); $records = []; $this->getDataGenerator()->enrol_user($user->id, $course1->id); $this->getDataGenerator()->enrol_user($user->id, $course2->id); $this->resetAfterTest(true); $this->setUser($user); for ($i = 1; $i < 19; $i++) { $courseid = ($i < 9) ? $course1->id : $course2->id; $instance = ($i < 9) ? $instance1->id : $instance2->id; $records[] = $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $courseid, 'timesort' => $i, 'modulename' => 'assign', 'instance' => $instance, ] ); } $result = core_calendar_external::get_calendar_action_events_by_course( $course1->id, 2, 7, $records[2]->id, 2);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(2, $result); $this->assertEquals('Event 4', $result[0]['name']); $this->assertEquals('Event 5', $result[1]['name']); $result = core_calendar_external::get_calendar_action_events_by_course( $course1->id, 2, 7, $records[4]->id, 2);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(2, $result); $this->assertEquals('Event 6', $result[0]['name']); $this->assertEquals('Event 7', $result[1]['name']); $result = core_calendar_external::get_calendar_action_events_by_course( $course1->id, 2, 7, $records[6]->id, 2);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertEmpty($result); } /** * Test get_calendar_action_events_by_course with search feature */ public function test_get_calendar_action_events_by_course_with_search() { // Generate data. $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance = $generator->create_instance(['course' => $course->id]); // Enrol. $this->getDataGenerator()->enrol_user($user->id, $course->id); $this->resetAfterTest(true); $this->setUser($user); for ($i = 1; $i < 5; $i++) { $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $course->id, 'timesort' => $i, 'modulename' => 'assign', 'instance' => $instance->id, ] ); } // No result found for fake search. $result = core_calendar_external::get_calendar_action_events_by_course($course->id, null, null, 0, 20, 'Fake search');< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertEmpty($result); // Search for event name called 'Event 1'. $result = core_calendar_external::get_calendar_action_events_by_course($course->id, null, null, 0, 20, 'Event 1');< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(1, $result); $this->assertEquals('Event 1', $result[0]['name']); // Search for activity type called 'assign'. $result = core_calendar_external::get_calendar_action_events_by_course($course->id, null, null, 0, 20, 'assign');< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_course_returns(), $result ); $result = $result['events']; $this->assertCount(4, $result); $this->assertEquals('Event 1', $result[0]['name']); $this->assertEquals('Event 2', $result[1]['name']); $this->assertEquals('Event 3', $result[2]['name']); $this->assertEquals('Event 4', $result[3]['name']); } /** * Test that get_action_events_by_courses will return a list of events for each * course you provided as long as the user is enrolled in the course. */ public function test_get_action_events_by_courses() { $user = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $course3 = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance1 = $generator->create_instance(['course' => $course1->id]); $instance2 = $generator->create_instance(['course' => $course2->id]); $instance3 = $generator->create_instance(['course' => $course3->id]); $records = []; $mapresult = function($result) { $groupedbycourse = []; foreach ($result['groupedbycourse'] as $group) { $events = $group['events']; $courseid = $group['courseid']; $groupedbycourse[$courseid] = $events; } return $groupedbycourse; }; $this->getDataGenerator()->enrol_user($user->id, $course1->id); $this->getDataGenerator()->enrol_user($user->id, $course2->id); $this->resetAfterTest(true); $this->setUser($user); for ($i = 1; $i < 10; $i++) { if ($i < 3) { $courseid = $course1->id; $instance = $instance1->id; } else if ($i < 6) { $courseid = $course2->id; $instance = $instance2->id; } else { $courseid = $course3->id; $instance = $instance3->id; } $records[] = $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $courseid, 'timesort' => $i, 'modulename' => 'assign', 'instance' => $instance, ] ); } $result = core_calendar_external::get_calendar_action_events_by_courses([], 1);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $result = $result['groupedbycourse']; $this->assertEmpty($result); $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id], 3);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertEmpty($groupedbycourse[$course1->id]); $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id], 1);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertCount(2, $groupedbycourse[$course1->id]); $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']); $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']); $result = core_calendar_external::get_calendar_action_events_by_courses( [$course1->id, $course2->id], 1);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertCount(2, $groupedbycourse[$course1->id]); $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']); $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']); $this->assertCount(3, $groupedbycourse[$course2->id]); $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']); $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']); $this->assertEquals('Event 5', $groupedbycourse[$course2->id][2]['name']); $result = core_calendar_external::get_calendar_action_events_by_courses( [$course1->id, $course2->id], 2, 4);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertCount(2, $groupedbycourse); $this->assertCount(1, $groupedbycourse[$course1->id]); $this->assertEquals('Event 2', $groupedbycourse[$course1->id][0]['name']); $this->assertCount(2, $groupedbycourse[$course2->id]); $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']); $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']); $result = core_calendar_external::get_calendar_action_events_by_courses( [$course1->id, $course2->id], 1, null, 1);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertCount(2, $groupedbycourse); $this->assertCount(1, $groupedbycourse[$course1->id]); $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']); $this->assertCount(1, $groupedbycourse[$course2->id]); $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']); } /** * Test get_action_events_by_courses with search feature */ public function test_get_action_events_by_courses_with_search() { // Generate data. $user = $this->getDataGenerator()->create_user(); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $course3 = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance1 = $generator->create_instance(['course' => $course1->id]); $instance2 = $generator->create_instance(['course' => $course2->id]); $instance3 = $generator->create_instance(['course' => $course3->id]); $this->getDataGenerator()->enrol_user($user->id, $course1->id); $this->getDataGenerator()->enrol_user($user->id, $course2->id); $this->resetAfterTest(true); $this->setUser($user); $mapresult = function($result) { $groupedbycourse = []; foreach ($result['groupedbycourse'] as $group) { $events = $group['events']; $courseid = $group['courseid']; $groupedbycourse[$courseid] = $events; } return $groupedbycourse; }; for ($i = 1; $i < 10; $i++) { if ($i < 3) { $courseid = $course1->id; $instance = $instance1->id; } else if ($i < 6) { $courseid = $course2->id; $instance = $instance2->id; } else { $courseid = $course3->id; $instance = $instance3->id; } $records[] = $this->create_calendar_event( sprintf('Event %d', $i), $user->id, 'user', 0, 1, [ 'type' => CALENDAR_EVENT_TYPE_ACTION, 'courseid' => $courseid, 'timesort' => $i, 'modulename' => 'assign', 'instance' => $instance, ] ); } // No result found for fake search. $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id, $course2->id, $course3->id], 1, null, 20, 'Fake search');< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertEmpty($groupedbycourse[$course1->id]); $this->assertEmpty($groupedbycourse[$course2->id]); $this->assertArrayNotHasKey($course3->id, $groupedbycourse); // Search for event name called 'Event 1'. $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id, $course2->id, $course3->id], 1, null, 20, 'Event 1');< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertArrayNotHasKey($course3->id, $groupedbycourse); $this->assertCount(2, $groupedbycourse); $this->assertCount(1, $groupedbycourse[$course1->id]); $this->assertCount(0, $groupedbycourse[$course2->id]); $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']); // Search for activity type called 'assign'. $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id, $course2->id, $course3->id], 1, null, 20, 'assign');< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::get_calendar_action_events_by_courses_returns(), $result ); $groupedbycourse = $mapresult($result); $this->assertArrayNotHasKey($course3->id, $groupedbycourse); $this->assertCount(2, $groupedbycourse); $this->assertCount(2, $groupedbycourse[$course1->id]); $this->assertCount(3, $groupedbycourse[$course2->id]); $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']); $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']); $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']); $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']); $this->assertEquals('Event 5', $groupedbycourse[$course2->id][2]['name']); } /** * Test for deleting module events. */ public function test_delete_calendar_events_for_modules() { $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $nexttime = time() + DAYSECS; $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'duedate' => $nexttime]); $events = calendar_get_events(time(), $nexttime, true, true, true); $this->assertCount(1, $events); $params = []; foreach ($events as $event) { $params[] = [ 'eventid' => $event->id, 'repeat' => false ]; } $this->expectException(\moodle_exception::class); core_calendar_external::delete_calendar_events($params); } /** * Updating the event start day should change the date value but leave * the time of day unchanged. */ public function test_update_event_start_day() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $roleid = $generator->create_role(); $context = \context_system::instance(); $originalstarttime = new \DateTimeImmutable('2017-01-1T15:00:00+08:00'); $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00'); $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true); $this->setUser($user); $this->resetAfterTest(true); $event = $this->create_calendar_event( 'Test event', $user->id, 'user', 0, null, [ 'courseid' => 0, 'timestart' => $originalstarttime->getTimestamp() ] ); $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::update_event_start_day_returns(), $result ); $this->assertEquals($expected->getTimestamp(), $result['event']['timestart']); } /** * A user should not be able to edit an event that they don't have * capabilities for. */ public function test_update_event_start_day_no_permission() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $roleid = $generator->create_role(); $context = \context_system::instance(); $originalstarttime = new \DateTimeImmutable('2017-01-1T15:00:00+08:00'); $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00'); $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true); $this->setUser($user); $this->resetAfterTest(true); $event = $this->create_calendar_event( 'Test event', $user->id, 'user', 0, null, [ 'courseid' => 0, 'timestart' => $originalstarttime->getTimestamp() ] ); assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true); $this->expectException(\moodle_exception::class); $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::update_event_start_day_returns(), $result ); } /** * A user should not be able to update a module event. */ public function test_update_event_start_day_module_event() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $plugingenerator = $generator->get_plugin_generator('mod_assign'); $moduleinstance = $plugingenerator->create_instance(['course' => $course->id]); $roleid = $generator->create_role(); $context = \context_course::instance($course->id); $originalstarttime = new \DateTimeImmutable('2017-01-1T15:00:00+08:00'); $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00'); $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00'); $generator->role_assign($roleid, $user->id, $context->id); $generator->enrol_user($user->id, $course->id); $this->setUser($user); $this->resetAfterTest(true); $event = $this->create_calendar_event( 'Test event', $user->id, 'user', 0, null, [ 'modulename' => 'assign', 'instance' => $moduleinstance->id, 'courseid' => $course->id, 'timestart' => $originalstarttime->getTimestamp() ] ); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); $this->expectException(\moodle_exception::class); $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::update_event_start_day_returns(), $result ); } /** * Submit a request where the time duration until is earlier than the time * start in order to get a validation error from the server. */ public function test_submit_create_update_form_validation_error() { $user = $this->getDataGenerator()->create_user(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->sub($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'user', 'description' => [ 'text' => '', 'format' => 1, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $this->assertTrue($result['validationerror']); } /** * A user with the moodle/calendar:manageownentries capability at the * system context should be able to create a user event. */ public function test_submit_create_update_form_create_user_event() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $roleid = $generator->create_role(); $context = \context_system::instance(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'user', 'description' => [ 'text' => '', 'format' => 1, 'itemid' => 0 ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $event = $result['event']; $this->assertEquals($user->id, $event['userid']); $this->assertEquals($formdata['eventtype'], $event['eventtype']); $this->assertEquals($formdata['name'], $event['name']); } /** * A user without the moodle/calendar:manageownentries capability at the * system context should not be able to create a user event. */ public function test_submit_create_update_form_create_user_event_no_permission() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $roleid = $generator->create_role(); $context = \context_system::instance(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'user', 'description' => [ 'text' => '', 'format' => 1, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user); $this->expectException(\moodle_exception::class);< \external_api::clean_returnvalue(> external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); } /** * A user with the moodle/calendar:manageentries capability at the * site course context should be able to create a site event. */ public function test_submit_create_update_form_create_site_event() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $context = \context_system::instance(); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'site', 'description' => [ 'text' => '', 'format' => 1, 'itemid' => 0 ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $event = $result['event']; $this->assertEquals($user->id, $event['userid']); $this->assertEquals($formdata['eventtype'], $event['eventtype']); $this->assertEquals($formdata['name'], $event['name']); } /** * A user without the moodle/calendar:manageentries capability at the * site course context should not be able to create a site event. */ public function test_submit_create_update_form_create_site_event_no_permission() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $context = \context_course::instance(SITEID); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'site', 'description' => [ 'text' => '', 'format' => 1, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $this->assertTrue($result['validationerror']); } /** * A user that has the moodle/calendar:manageentries in a course that they * are enrolled in should be able to create a course event in that course. */ public function test_submit_create_update_form_create_course_event() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'course', 'courseid' => $course->id, 'description' => [ 'text' => '', 'format' => 1, 'itemid' => 0, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $event = $result['event']; $this->assertEquals($user->id, $event['userid']); $this->assertEquals($formdata['eventtype'], $event['eventtype']); $this->assertEquals($formdata['name'], $event['name']); $this->assertEquals($formdata['courseid'], $event['course']['id']); } /** * A user without the moodle/calendar:manageentries capability in a course * that they are enrolled in should not be able to create a course event in that course. */ public function test_submit_create_update_form_create_course_event_no_permission() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'course', 'courseid' => $course->id, 'description' => [ 'text' => '', 'format' => 1, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $this->assertTrue($result['validationerror']); } /** * A user should not be able to create an event for a course that they are * not enrolled in. */ public function test_submit_create_update_form_create_course_event_not_enrolled() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $course2 = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'course', 'courseid' => $course2->id, // Not enrolled. 'description' => [ 'text' => '', 'format' => 1, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $this->assertTrue($result['validationerror']); } /** * A user should be able to create an event for a group that they are a member of in * a course in which they are enrolled and have the moodle/calendar:manageentries capability. */ public function test_submit_create_update_form_create_group_event_group_member_manage_course() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $group = $generator->create_group(array('courseid' => $course->id)); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'group', 'groupid' => $group->id, 'groupcourseid' => $course->id, 'description' => [ 'text' => '', 'format' => 1, 'itemid' => 0 ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); $generator->create_group_member(['groupid' => $group->id, 'userid' => $user->id]); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $event = $result['event']; $this->assertEquals($user->id, $event['userid']); $this->assertEquals($formdata['eventtype'], $event['eventtype']); $this->assertEquals($formdata['name'], $event['name']); $this->assertEquals($group->id, $event['groupid']); } /** * A user should be able to create an event for a group that they are a member of in * a course in which they are enrolled and have the moodle/calendar:managegroupentries capability. */ public function test_submit_create_update_form_create_group_event_group_member_manage_group_entries() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $group = $generator->create_group(array('courseid' => $course->id)); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'group', 'groupid' => $group->id, 'groupcourseid' => $course->id, 'description' => [ 'text' => '', 'format' => 1, 'itemid' => 0 ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); $generator->create_group_member(['groupid' => $group->id, 'userid' => $user->id]); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true); assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $event = $result['event']; $this->assertEquals($user->id, $event['userid']); $this->assertEquals($formdata['eventtype'], $event['eventtype']); $this->assertEquals($formdata['name'], $event['name']); $this->assertEquals($group->id, $event['groupid']); } /** * A user should be able to create an event for any group in a course in which * they are enrolled and have the moodle/site:accessallgroups capability. */ public function test_submit_create_update_form_create_group_event_access_all_groups() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $group = $generator->create_group(array('courseid' => $course->id)); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'group', 'groupid' => $group->id, 'groupcourseid' => $course->id, 'description' => [ 'text' => '', 'format' => 1, 'itemid' => 0 ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $event = $result['event']; $this->assertEquals($user->id, $event['userid']); $this->assertEquals($formdata['eventtype'], $event['eventtype']); $this->assertEquals($formdata['name'], $event['name']); $this->assertEquals($group->id, $event['groupid']); } /** * A user should not be able to create an event for any group that they are not a * member of in a course in which they are enrolled but don't have the * moodle/site:accessallgroups capability. */ public function test_submit_create_update_form_create_group_event_non_member_no_permission() { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $group = $generator->create_group(array('courseid' => $course->id)); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $timestart = new \DateTime(); $interval = new \DateInterval("P1D"); // One day. $timedurationuntil = new \DateTime(); $timedurationuntil->add($interval); $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'name' => 'Test', 'timestart' => [ 'day' => $timestart->format('j'), 'month' => $timestart->format('n'), 'year' => $timestart->format('Y'), 'hour' => $timestart->format('G'), 'minute' => 0, ], 'eventtype' => 'group', 'groupid' => $group->id, 'groupcourseid' => $course->id, 'description' => [ 'text' => '', 'format' => 1, ], 'location' => 'Test', 'duration' => 1, 'timedurationuntil' => [ 'day' => $timedurationuntil->format('j'), 'month' => $timedurationuntil->format('n'), 'year' => $timedurationuntil->format('Y'), 'hour' => $timedurationuntil->format('G'), 'minute' => 0, ] ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true); $user->ignoresesskey = true; $this->resetAfterTest(true); $this->setUser($user);< $result = \external_api::clean_returnvalue(> $result = external_api::clean_returnvalue(core_calendar_external::submit_create_update_form_returns(), core_calendar_external::submit_create_update_form($querystring) ); $this->assertTrue($result['validationerror']); } /** * A user should not be able load the calendar monthly view for a course they cannot access. */ public function test_get_calendar_monthly_view_no_course_permission() { global $USER; $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $user1 = $generator->create_user(); $user2 = $generator->create_user(); $course = $generator->create_course(); $generator->enrol_user($user1->id, $course->id, 'student'); $name = 'Course Event (course' . $course->id . ')'; $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record); $timestart = new \DateTime(); // Admin can load the course.< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_monthly_view_returns(), core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'), $course->id, null, false, true, $timestart->format('j')) ); $this->assertEquals($data['courseid'], $course->id); // User enrolled in the course can load the course calendar. $this->setUser($user1);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_monthly_view_returns(), core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'), $course->id, null, false, true, $timestart->format('j')) ); $this->assertEquals($data['courseid'], $course->id); // User not enrolled in the course cannot load the course calendar. $this->setUser($user2); $this->expectException(\require_login_exception::class);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_monthly_view_returns(), core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'), $course->id, null, false, false, $timestart->format('j')) ); } /** * Test get_calendar_monthly_view when a day parameter is provided. */ public function test_get_calendar_monthly_view_with_day_provided() { $this->resetAfterTest(); $this->setAdminUser(); $timestart = new \DateTime();< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_monthly_view_returns(), core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'), SITEID, null, false, true, $timestart->format('j')) ); $this->assertEquals($data['date']['mday'], $timestart->format('d')); } /** * A user should not be able load the calendar day view for a course they cannot access. */ public function test_get_calendar_day_view_no_course_permission() { global $USER; $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $user1 = $generator->create_user(); $user2 = $generator->create_user(); $course = $generator->create_course(); $generator->enrol_user($user1->id, $course->id, 'student'); $name = 'Course Event (course' . $course->id . ')'; $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record); $timestart = new \DateTime(); // Admin can load the course.< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_day_view_returns(), core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'), $timestart->format('j'), $course->id, null) ); $this->assertEquals($data['courseid'], $course->id); // User enrolled in the course can load the course calendar. $this->setUser($user1);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_day_view_returns(), core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'), $timestart->format('j'), $course->id, null) ); $this->assertEquals($data['courseid'], $course->id); // User not enrolled in the course cannot load the course calendar. $this->setUser($user2); $this->expectException(\require_login_exception::class);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_day_view_returns(), core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'), $timestart->format('j'), $course->id, null) ); } /** * A user should not be able load the calendar upcoming view for a course they cannot access. */ public function test_get_calendar_upcoming_view_no_course_permission() { global $USER; $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $user1 = $generator->create_user(); $user2 = $generator->create_user(); $course = $generator->create_course(); $generator->enrol_user($user1->id, $course->id, 'student'); $name = 'Course Event (course' . $course->id . ')'; $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record); // Admin can load the course.< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_upcoming_view_returns(), core_calendar_external::get_calendar_upcoming_view($course->id, null) ); $this->assertEquals($data['courseid'], $course->id); // User enrolled in the course can load the course calendar. $this->setUser($user1);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_upcoming_view_returns(), core_calendar_external::get_calendar_upcoming_view($course->id, null) ); $this->assertEquals($data['courseid'], $course->id); // User not enrolled in the course cannot load the course calendar. $this->setUser($user2); $this->expectException(\require_login_exception::class);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_upcoming_view_returns(), core_calendar_external::get_calendar_upcoming_view($course->id, null) ); } /** * A user should not be able load the calendar event for a course they cannot access. */ public function test_get_calendar_event_by_id_no_course_permission() { global $USER; $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $user1 = $generator->create_user(); $user2 = $generator->create_user(); $course = $generator->create_course(); $generator->enrol_user($user1->id, $course->id, 'student'); $name = 'Course Event (course' . $course->id . ')'; $record = new \stdClass(); $record->courseid = $course->id; $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record); // Admin can load the course event.< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_event_by_id_returns(), core_calendar_external::get_calendar_event_by_id($courseevent->id) ); $this->assertEquals($data['event']['id'], $courseevent->id); // User enrolled in the course can load the course event. $this->setUser($user1);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_event_by_id_returns(), core_calendar_external::get_calendar_event_by_id($courseevent->id) ); $this->assertEquals($data['event']['id'], $courseevent->id); // User not enrolled in the course cannot load the course event. $this->setUser($user2); $this->expectException(\moodle_exception::class);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_event_by_id_returns(), core_calendar_external::get_calendar_event_by_id($courseevent->id) ); } /** * User data for testing reading calendar events. * * @return array */ public function get_calendar_event_by_id_prevent_read_other_users_events_data_provider(): array { $syscontext = \context_system::instance(); $managerrole = 'manager'; return [ [true, false, $syscontext, $managerrole, true], [false, false, $syscontext, $managerrole, false], [false, false, null, null, true], [false, true, null, null, false], ]; } /** * Prevent user from reading other user's event. * * @covers \core_calendar_external::get_calendar_event_by_id * @dataProvider get_calendar_event_by_id_prevent_read_other_users_events_data_provider * * @param bool $isadminevent Is admin's event * @param bool $isadmin Is current user admin user * @param null|stdClass $readerrolecontext Reader role context * @param null|string $readerrolename Role name * @param bool $expectexception Should the test throw exception */ public function test_get_calendar_event_by_id_prevent_read_other_users_events( bool $isadminevent, bool $isadmin, ?\stdClass $readerrolecontext, ?string $readerrolename, bool $expectexception) { global $USER, $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator(); if ($isadminevent) { $this->setAdminUser(); } else { $user = $generator->create_user(); $this->setUser($user); } $userevent = $this->create_calendar_event('user event', $USER->id, 'user', 0, time());< $results = \external_api::clean_returnvalue(> $results = external_api::clean_returnvalue(core_calendar_external::get_calendar_event_by_id_returns(), core_calendar_external::get_calendar_event_by_id($userevent->id) ); $event = reset($results); $this->assertEquals($userevent->id, $event['id']); if ($isadmin) { $this->setAdminUser(); } else { $reader = $generator->create_user(); if ($readerrolename && $readerrolecontext) { $managerroleid = $DB->get_field('role', 'id', ['shortname' => $readerrolename]); role_assign($managerroleid, $reader->id, $readerrolecontext->id); } $this->setUser($reader); } if ($expectexception) { // Setup if exception is expected for the test. $this->expectException(\moodle_exception::class); }< \external_api::clean_returnvalue(> external_api::clean_returnvalue(core_calendar_external::get_calendar_event_by_id_returns(), core_calendar_external::get_calendar_event_by_id($userevent->id) ); } /** * User data for testing editing or deleting calendar events. * * @return array */ public function edit_or_delete_other_users_events_data_provider(): array { $syscontext = \context_system::instance(); $managerrole = 'manager'; return [ [false, false, $syscontext, $managerrole, false], [false, true, $syscontext, $managerrole, true], [false, false, null, null, true], [true, false, null, null, false], ]; } /** * Test the behavior of deleting other users' user events. * * @dataProvider edit_or_delete_other_users_events_data_provider * @covers \core_calendar_external::delete_calendar_events * @param bool $isadmin Whether the current user is admin. * @param bool $isadminevent Whether it's an admin event or not. * @param stdClass|null $writerrolecontext The reader role context. * @param string|null $writerrolename The role name. * @param bool $expectexception Whether the test should throw an exception or not. */ public function test_delete_other_users_events(bool $isadmin, bool $isadminevent, ?\stdClass $writerrolecontext, ?string $writerrolename, bool $expectexception) { global $DB, $USER; $this->resetAfterTest(); $generator = $this->getDataGenerator(); if ($isadminevent) { $this->setAdminUser(); $user = $USER; } else { $user = $generator->create_user(); $this->setUser($user); } $userevent = $this->create_calendar_event('user event', $user->id, 'user', 0, time()); if ($isadmin) { $this->setAdminUser(); } else { $writer = $generator->create_user(); if ($writerrolename && $writerrolecontext) { $managerroleid = $DB->get_field('role', 'id', ['shortname' => $writerrolename]); role_assign($managerroleid, $writer->id, $writerrolecontext->id); } $this->setUser($writer); } if ($expectexception) { $this->expectException(\moodle_exception::class); } $events = [ ['eventid' => $userevent->id, 'repeat' => 0] ]; core_calendar_external::delete_calendar_events($events); } /** * Test the behavior of editing other users' user events * * @dataProvider edit_or_delete_other_users_events_data_provider * @covers \core_calendar_external::submit_create_update_form * @param bool $isadmin Whether the current user is admin. * @param bool $isadminevent Whether it's an admin event or not. * @param stdClass|null $writerrolecontext The reader role context. * @param string|null $writerrolename The role name. * @param bool $expectexception Whether the test should throw an exception or not. */ public function test_edit_other_users_events(bool $isadmin, bool $isadminevent, ?\stdClass $writerrolecontext, ?string $writerrolename, bool $expectexception) { global $DB, $USER; $this->resetAfterTest(); $generator = $this->getDataGenerator(); if ($isadminevent) { $this->setAdminUser(); $user = $USER; } else { $user = $generator->create_user(); } $formdata = [ 'id' => 0, 'userid' => $user->id, 'modulename' => '', 'instance' => 0, 'visible' => 1, 'eventtype' => 'user', 'name' => 'Test', 'timestart' => [ 'day' => 1, 'month' => 1, 'year' => 2021, 'hour' => 1, 'minute' => 0, ], 'description' => [ 'text' => 'xxxxx', 'format' => 1, 'itemid' => 0 ], 'location' => 'Test', 'duration' => 0, ]; $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata); $querystring = http_build_query($formdata, '', '&'); if ($isadmin) { $this->setAdminUser(); } else { $writer = $generator->create_user(); if ($writerrolename && $writerrolecontext) { $managerroleid = $DB->get_field('role', 'id', ['shortname' => $writerrolename]); role_assign($managerroleid, $writer->id, $writerrolecontext->id); } $this->setUser($writer); } $USER->ignoresesskey = true; if ($expectexception) { $this->expectException(\moodle_exception::class); } core_calendar_external::submit_create_update_form($querystring); } /** * A user should not be able load the calendar events for a category they cannot see. */ public function test_get_calendar_events_hidden_category() { global $USER; $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $user1 = $generator->create_user(); $category = $generator->create_category(['visible' => 0]); $name = 'Category Event (category: ' . $category->id . ')'; $record = new \stdClass(); $record->categoryid = $category->id; $categoryevent = $this->create_calendar_event($name, $USER->id, 'category', 0, time(), $record); $events = [ 'eventids' => [$categoryevent->id] ]; $options = []; // Admin can load the category event.< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), core_calendar_external::get_calendar_events($events, $options) ); $this->assertEquals($data['events'][0]['id'], $categoryevent->id); // User with no special permission to see hidden categories will not see the event. $this->setUser($user1);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), core_calendar_external::get_calendar_events($events, $options) ); $this->assertCount(0, $data['events']); $this->assertEquals('nopermissions', $data['warnings'][0]['warningcode']); } /** * Test get_calendar_access_information for admins. */ public function test_get_calendar_access_information_for_admins() { global $CFG; $this->resetAfterTest(true); $this->setAdminUser(); $CFG->calendar_adminseesall = 1;< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_access_information_returns(), core_calendar_external::get_calendar_access_information() ); $this->assertTrue($data['canmanageownentries']); $this->assertTrue($data['canmanagegroupentries']); $this->assertTrue($data['canmanageentries']); } /** * Test get_calendar_access_information for authenticated users. */ public function test_get_calendar_access_information_for_authenticated_users() { $this->resetAfterTest(true); $this->setUser($this->getDataGenerator()->create_user());< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_access_information_returns(), core_calendar_external::get_calendar_access_information() ); $this->assertTrue($data['canmanageownentries']); $this->assertFalse($data['canmanagegroupentries']); $this->assertFalse($data['canmanageentries']); } /** * Test get_calendar_access_information for student users. */ public function test_get_calendar_access_information_for_student_users() { global $DB; $this->resetAfterTest(true); $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $role = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); $this->setUser($user);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_access_information_returns(), core_calendar_external::get_calendar_access_information($course->id) ); $this->assertTrue($data['canmanageownentries']); $this->assertFalse($data['canmanagegroupentries']); $this->assertFalse($data['canmanageentries']); } /** * Test get_calendar_access_information for teacher users. */ public function test_get_calendar_access_information_for_teacher_users() { global $DB; $this->resetAfterTest(true); $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(['groupmode' => 1]); $role = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); $this->getDataGenerator()->create_group(['courseid' => $course->id]); $this->setUser($user);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_calendar_access_information_returns(), core_calendar_external::get_calendar_access_information($course->id) ); $this->assertTrue($data['canmanageownentries']); $this->assertTrue($data['canmanagegroupentries']); $this->assertTrue($data['canmanageentries']); } /** * Test get_allowed_event_types for admins. */ public function test_get_allowed_event_types_for_admins() { global $CFG; $this->resetAfterTest(true); $this->setAdminUser(); $CFG->calendar_adminseesall = 1;< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_allowed_event_types_returns(), core_calendar_external::get_allowed_event_types() ); $this->assertEquals(['user', 'site', 'course', 'category'], $data['allowedeventtypes']); } /** * Test get_allowed_event_types for authenticated users. */ public function test_get_allowed_event_types_for_authenticated_users() { $this->resetAfterTest(true); $this->setUser($this->getDataGenerator()->create_user());< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_allowed_event_types_returns(), core_calendar_external::get_allowed_event_types() ); $this->assertEquals(['user'], $data['allowedeventtypes']); } /** * Test get_allowed_event_types for student users. */ public function test_get_allowed_event_types_for_student_users() { global $DB; $this->resetAfterTest(true); $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $role = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); $this->setUser($user);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_allowed_event_types_returns(), core_calendar_external::get_allowed_event_types($course->id) ); $this->assertEquals(['user'], $data['allowedeventtypes']); } /** * Test get_allowed_event_types for teacher users. */ public function test_get_allowed_event_types_for_teacher_users() { global $DB; $this->resetAfterTest(true); $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(['groupmode' => 1]); $role = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id); $this->getDataGenerator()->create_group(['courseid' => $course->id]); $this->setUser($user);< $data = \external_api::clean_returnvalue(> $data = external_api::clean_returnvalue(core_calendar_external::get_allowed_event_types_returns(), core_calendar_external::get_allowed_event_types($course->id) ); $this->assertEquals(['user', 'course', 'group'], $data['allowedeventtypes']); } /** * Test get_timestamps with string keys, with and without optional hour/minute values. */ public function test_get_timestamps_string_keys() { $this->resetAfterTest(true); $this->setAdminUser(); $time1 = new \DateTime('2018-12-30 00:00:00'); $time2 = new \DateTime('2019-03-27 23:59:00'); $dates = [ [ 'key' => 'from', 'year' => $time1->format('Y'), 'month' => $time1->format('m'), 'day' => $time1->format('d'), ], [ 'key' => 'to', 'year' => $time2->format('Y'), 'month' => (int) $time2->format('m'), 'day' => $time2->format('d'), 'hour' => $time2->format('H'), 'minute' => $time2->format('i'), ], ]; $expectedtimestamps = [ 'from' => $time1->getTimestamp(), 'to' => $time2->getTimestamp(), ]; $result = core_calendar_external::get_timestamps($dates); $this->assertEquals(['timestamps'], array_keys($result)); $this->assertEquals(2, count($result['timestamps'])); foreach ($result['timestamps'] as $data) { $this->assertTrue(in_array($data['key'], ['from', 'to'])); $this->assertEquals($expectedtimestamps[$data['key']], $data['timestamp']); } } /** * Test get_timestamps with no keys specified, with and without optional hour/minute values. */ public function test_get_timestamps_no_keys() { $this->resetAfterTest(true); $this->setAdminUser(); $time1 = new \DateTime('2018-12-30 00:00:00'); $time2 = new \DateTime('2019-03-27 23:59:00'); $dates = [ [ 'year' => $time1->format('Y'), 'month' => $time1->format('m'), 'day' => $time1->format('d'), ], [ 'year' => $time2->format('Y'), 'month' => (int) $time2->format('m'), 'day' => $time2->format('d'), 'hour' => $time2->format('H'), 'minute' => $time2->format('i'), ], ]; $expectedtimestamps = [ 0 => $time1->getTimestamp(), 1 => $time2->getTimestamp(), ]; $result = core_calendar_external::get_timestamps($dates); $this->assertEquals(['timestamps'], array_keys($result)); $this->assertEquals(2, count($result['timestamps'])); foreach ($result['timestamps'] as $data) { $this->assertEquals($expectedtimestamps[$data['key']], $data['timestamp']); } } }