return false;
}
+/**
+ * This function updates the calendar events from the information stored in the module table and the course
+ * module table.
+ *
+ * @param string $modulename Module name
+ * @param stdClass $instance Module object. Either the $instance or the $cm must be supplied.
+ * @param stdClass $cm Course module object. Either the $instance or the $cm must be supplied.
+ * @return bool Returns true if calendar events are updated.
+ * @since Moodle 3.3.4
+ */
+function course_module_update_calendar_events($modulename, $instance = null, $cm = null) {
+ global $DB;
+
+ if (isset($instance) || isset($cm)) {
+
+ if (!isset($instance)) {
+ $instance = $DB->get_record($modulename, array('id' => $cm->instance), '*', MUST_EXIST);
+ }
+ if (!isset($cm)) {
+ $cm = get_coursemodule_from_instance($modulename, $instance->id, $instance->course);
+ }
+ course_module_calendar_event_update_process($instance, $cm);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Update all instances through out the site or in a course.
+ *
+ * @param string $modulename Module type to update.
+ * @param integer $courseid Course id to update events. 0 for the whole site.
+ * @return bool Returns True if the update was successful.
+ * @since Moodle 3.3.4
+ */
+function course_module_bulk_update_calendar_events($modulename, $courseid = 0) {
+ global $DB;
+
+ $instances = null;
+ if ($courseid) {
+ if (!$instances = $DB->get_records($modulename, array('course' => $courseid))) {
+ return false;
+ }
+ } else {
+ if (!$instances = $DB->get_records($modulename)) {
+ return false;
+ }
+ }
+
+ foreach ($instances as $instance) {
+ $cm = get_coursemodule_from_instance($modulename, $instance->id, $instance->course);
+ course_module_calendar_event_update_process($instance, $cm);
+ }
+ return true;
+}
+
+/**
+ * Calendar events for a module instance are updated.
+ *
+ * @param stdClass $instance Module instance object.
+ * @param stdClass $cm Course Module object.
+ * @since Moodle 3.3.4
+ */
+function course_module_calendar_event_update_process($instance, $cm) {
+ // We need to call *_refresh_events() first because some modules delete 'old' events at the end of the code which
+ // will remove the completion events.
+ $refresheventsfunction = $cm->modname . '_refresh_events';
+ if (function_exists($refresheventsfunction)) {
+ call_user_func($refresheventsfunction, $cm->course, $instance, $cm);
+ }
+ $completionexpected = (!empty($cm->completionexpected)) ? $cm->completionexpected : null;
+ \core_completion\api::update_completion_date_event($cm->id, $cm->modname, $instance, $completionexpected);
+}
+
/**
* Moves a section within a course, from a position to another.
* Be very careful: $section and $destination refer to section number,
$this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($completedcourse));
$this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($inprogresscourse));
}
+
+ /**
+ * Test the main function for updating all calendar events for a module.
+ */
+ public function test_course_module_calendar_event_update_process() {
+ global $DB;
+
+ $this->resetAfterTest();
+ $this->setAdminUser();
+
+ $completionexpected = time();
+ $duedate = time();
+
+ $course = $this->getDataGenerator()->create_course(['enablecompletion' => COMPLETION_ENABLED]);
+ $assign = $this->getDataGenerator()->create_module('assign', [
+ 'course' => $course,
+ 'completionexpected' => $completionexpected,
+ 'duedate' => $duedate
+ ]);
+
+ $cm = get_coursemodule_from_instance('assign', $assign->id, $course->id);
+ $events = $DB->get_records('event', ['courseid' => $course->id, 'instance' => $assign->id]);
+ // Check that both events are using the expected dates.
+ foreach ($events as $event) {
+ if ($event->eventtype == \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED) {
+ $this->assertEquals($completionexpected, $event->timestart);
+ }
+ if ($event->eventtype == ASSIGN_EVENT_TYPE_DUE) {
+ $this->assertEquals($duedate, $event->timestart);
+ }
+ }
+
+ // We have to manually update the module and the course module.
+ $newcompletionexpected = time() + DAYSECS * 60;
+ $newduedate = time() + DAYSECS * 45;
+ $newmodulename = 'Assign - new name';
+
+ $moduleobject = (object)array('id' => $assign->id, 'duedate' => $newduedate, 'name' => $newmodulename);
+ $DB->update_record('assign', $moduleobject);
+ $cmobject = (object)array('id' => $cm->id, 'completionexpected' => $newcompletionexpected);
+ $DB->update_record('course_modules', $cmobject);
+
+ $assign = $DB->get_record('assign', ['id' => $assign->id]);
+ $cm = get_coursemodule_from_instance('assign', $assign->id, $course->id);
+
+ course_module_calendar_event_update_process($assign, $cm);
+
+ $events = $DB->get_records('event', ['courseid' => $course->id, 'instance' => $assign->id]);
+ // Now check that the details have been updated properly from the function.
+ foreach ($events as $event) {
+ if ($event->eventtype == \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED) {
+ $this->assertEquals($newcompletionexpected, $event->timestart);
+ $this->assertEquals(get_string('completionexpectedfor', 'completion', (object)['instancename' => $newmodulename]),
+ $event->name);
+ }
+ if ($event->eventtype == ASSIGN_EVENT_TYPE_DUE) {
+ $this->assertEquals($newduedate, $event->timestart);
+ $this->assertEquals($newmodulename, $event->name);
+ }
+ }
+ }
+
+ /**
+ * Test the higher level checks for updating calendar events for an instance.
+ */
+ public function test_course_module_update_calendar_events() {
+ $this->resetAfterTest();
+ $this->setAdminUser();
+
+ $completionexpected = time();
+ $duedate = time();
+
+ $course = $this->getDataGenerator()->create_course(['enablecompletion' => COMPLETION_ENABLED]);
+ $assign = $this->getDataGenerator()->create_module('assign', [
+ 'course' => $course,
+ 'completionexpected' => $completionexpected,
+ 'duedate' => $duedate
+ ]);
+
+ $cm = get_coursemodule_from_instance('assign', $assign->id, $course->id);
+
+ // Both the instance and cm objects are missing.
+ $this->assertFalse(course_module_update_calendar_events('assign'));
+ // Just using the assign instance.
+ $this->assertTrue(course_module_update_calendar_events('assign', $assign));
+ // Just using the course module object.
+ $this->assertTrue(course_module_update_calendar_events('assign', null, $cm));
+ // Using both the assign instance and the course module object.
+ $this->assertTrue(course_module_update_calendar_events('assign', $assign, $cm));
+ }
+
+ /**
+ * Test the higher level checks for updating calendar events for a module.
+ */
+ public function test_course_module_bulk_update_calendar_events() {
+ $this->resetAfterTest();
+ $this->setAdminUser();
+
+ $completionexpected = time();
+ $duedate = time();
+
+ $course = $this->getDataGenerator()->create_course(['enablecompletion' => COMPLETION_ENABLED]);
+ $course2 = $this->getDataGenerator()->create_course(['enablecompletion' => COMPLETION_ENABLED]);
+ $assign = $this->getDataGenerator()->create_module('assign', [
+ 'course' => $course,
+ 'completionexpected' => $completionexpected,
+ 'duedate' => $duedate
+ ]);
+
+ // No assign instances in this course.
+ $this->assertFalse(course_module_bulk_update_calendar_events('assign', $course2->id));
+ // No book instances for the site.
+ $this->assertFalse(course_module_bulk_update_calendar_events('book'));
+ // Update all assign instances.
+ $this->assertTrue(course_module_bulk_update_calendar_events('assign'));
+ // Update the assign instances for this course.
+ $this->assertTrue(course_module_bulk_update_calendar_events('assign', $course->id));
+ }
}