From b5a52acd9daa0bfeb2dc70a8f68eaff6465b3410 Mon Sep 17 00:00:00 2001 From: Jonathan Harker Date: Mon, 23 Jul 2012 13:49:43 +1200 Subject: [PATCH] MDL-16660: Add calendar import. Adds an extra import section alongside the existing export in the calendar views. Allows the user to import from either a file or a URL as a subscription, with an optional polling interval of hourly, daily, weekly, monthly, or annually. This subscription may be added to the user, group, global or course calendars. These subscriptions are tracked in a separate database table, and an extra column added to the events table to relate them to the subscription. The event uuid field is also expanded to allow for the RFC-2445 UID property. Subscriptions are listed on the calendar view page, and can be added and removed, manually polled, and the polling interval adjusted. Subscription events are updated on cron. --- calendar/lib.php | 538 +++++++++++++++++++++++++++++++++++++++++++ calendar/view.php | 7 + lang/en/calendar.php | 15 ++ lib/cronlib.php | 3 + lib/db/install.xml | 26 ++- lib/db/upgrade.php | 37 +++ version.php | 2 +- 7 files changed, 622 insertions(+), 6 deletions(-) mode change 100644 => 100755 lib/db/install.xml diff --git a/calendar/lib.php b/calendar/lib.php index a8d908d11ff..3cacace7e38 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -23,6 +23,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +require_once "{$CFG->libdir}/bennu/bennu.inc.php"; + /** * These are read by the administration component to provide default values */ @@ -86,6 +88,26 @@ define('CALENDAR_EVENT_GROUP', 4); define('CALENDAR_EVENT_USER', 8); +/** + * CALENDAR_IMPORT_FROM_FILE - import the calendar from a file + */ +define('CALENDAR_IMPORT_FROM_FILE', 0); + +/** + * CALENDAR_IMPORT_FROM_URL - import the calendar from a URL + */ +define('CALENDAR_IMPORT_FROM_URL', 1); + +/** + * CALENDAR_IMPORT_EVENT_UPDATED - imported event was updated + */ +define('CALENDAR_IMPORT_EVENT_UPDATED', 1); + +/** + * CALENDAR_IMPORT_EVENT_INSERTED - imported event was added by insert + */ +define('CALENDAR_IMPORT_EVENT_INSERTED', 2); + /** * Return the days of the week * @@ -2634,3 +2656,519 @@ class calendar_information { $renderer->add_pretend_calendar_block($block, BLOCK_POS_RIGHT); } } + +/** + * Returns option list for the pollinterval setting. + */ +function calendar_get_pollinterval_choices() { + return array( + '0' => get_string('never', 'calendar'), + '3600' => get_string('hourly', 'calendar'), + '86400' => get_string('daily', 'calendar'), + '604800' => get_string('weekly', 'calendar'), + '2628000' => get_string('monthly', 'calendar'), + '31536000' => get_string('annually', 'calendar'), + ); +} + +/** + * Returns available options for the calendar event type. + */ +function calendar_get_eventtype_choices($courseid) { + $choices = array(); + $allowed = new stdClass; + calendar_get_allowed_types($allowed, $courseid); + + if ($allowed->user) { + $choices[0] = get_string('userevents', 'calendar'); + } + if ($allowed->site) { + $choices[1] = get_string('globalevents', 'calendar'); + } + if (!empty($allowed->courses)) { + $choices[$courseid] = get_string('courseevents', 'calendar'); + } + if (!empty($allowed->groups) and is_array($allowed->groups)) { + $choices['group'] = get_string('group'); + } + + return array($choices, $allowed->groups); +} + +/** + * Form for adding a subscription to a Moodle course calendar. + */ +class calendar_addsubscription_form extends moodleform { + + function definition() { + $mform =& $this->_form; + $courseid = optional_param('course', 0, PARAM_INT); + + // code to show/hide the form from the heading + $mform->addElement('html', ''); + $mform->addElement('header', 'addsubscriptionform', 'Import calendar...'); + + $mform->addElement('text', 'name', get_string('subscriptionname', 'calendar'), 'maxlength="255" size="40"'); + $mform->addRule('name', get_string('required'), 'required'); + + $mform->addElement('html', "Please provide either a URL to a remote calendar, or upload a file."); + $choices = array(CALENDAR_IMPORT_FROM_FILE => get_string('importfromfile', 'calendar'), + CALENDAR_IMPORT_FROM_URL => get_string('importfromurl', 'calendar')); + $mform->addElement('select', 'importfrom', get_string('importcalendarfrom', 'calendar'), $choices); + $mform->setDefault('importfrom', CALENDAR_IMPORT_FROM_URL); + + $mform->addElement('text', 'url', get_string('importfromurl', 'calendar'), 'maxlength="255" size="50"'); + $mform->addElement('filepicker', 'importfile', get_string('importfromfile', 'calendar')); + + $mform->disabledIf('url', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_FILE); + $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL); + + $choices = calendar_get_pollinterval_choices(); + $mform->addElement('select', 'pollinterval', get_string('pollinterval', 'calendar'), $choices); + + $mform->setDefault('pollinterval', 604800); + $mform->addHelpButton('pollinterval', 'pollinterval', 'calendar'); + + // eventtype: 0 = user, 1 = global, anything else = course ID + list($choices, $groups) = calendar_get_eventtype_choices($courseid); + $mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $choices); + $mform->addRule('eventtype', get_string('required'), 'required'); + + if (!empty($groups) and is_array($groups)) { + $groupoptions = array(); + foreach ($groups as $group) { + $groupoptions[$group->id] = $group->name; + } + $mform->addElement('select', 'groupid', get_string('typegroup', 'calendar'), $groupoptions); + $mform->disabledIf('groupid', 'eventtype', 'noteq', 'group'); + } + + $mform->addElement('hidden', 'course', optional_param('course', 0, PARAM_INT)); + $mform->addElement('hidden', 'view', optional_param('view', 'upcoming', PARAM_ALPHA)); + $mform->addElement('hidden', 'cal_d', optional_param('cal_d', 0, PARAM_INT)); + $mform->addElement('hidden', 'cal_m', optional_param('cal_m', 0, PARAM_INT)); + $mform->addElement('hidden', 'cal_y', optional_param('cal_y', 0, PARAM_INT)); + $mform->addElement('hidden', 'id', optional_param('id', 0, PARAM_INT)); + + $mform->addElement('submit', 'add', get_string('add')); + + // *sigh* folding up the form breaks the filepicker control + // $mform->addElement('html', ''); + } + + function get_ical_data() { + $formdata = $this->get_data(); + switch ($formdata->importfrom) { + case CALENDAR_IMPORT_FROM_FILE: + $calendar = $this->get_file_content('importfile'); + break; + case CALENDAR_IMPORT_FROM_URL: + $calendar = file_get_contents($formdata->importurl); + break; + } + return $calendar; + } +} + +/** + * Add an iCalendar subscription to the database. + * @param object $sub The subscription object (e.g. from the form) + * @return int The insert ID, if any. + */ +function calendar_add_subscription($sub) { + global $DB, $USER; + $sub->courseid = $sub->eventtype; + if ($sub->eventtype == 'group') { + $sub->courseid = $sub->course; + } + $sub->userid = $USER->id; + + // file subscriptions never update. + if (empty($sub->url)) { + $sub->pollinterval = 0; + } + + if (!empty($sub->name)) { + if (empty($sub->id)) { + $id = $DB->insert_record('event_subscriptions', $sub); + return $id; + } else { + $DB->update_record('event_subscriptions', $sub); + return $sub->id; + } + } else { + print_error('errorbadsubscription', 'importcalendar'); + } +} + +/** + * Add an iCalendar event to the Moodle calendar. + * @param object $event The RFC-2445 iCalendar event + * @param int $courseid The course ID + * @param int $subscriptionid The iCalendar subscription ID + * @return int Code: 1=updated, 2=inserted, 0=error + */ +function calendar_add_icalendar_event($event, $courseid, $subscriptionid=null) { + global $DB, $USER; + + $eventrecord = new stdClass; + + // probably an unsupported X-MICROSOFT-CDO-BUSYSTATUS event. + if (empty($event->properties['SUMMARY'])) { + return 0; + } + + $name = $event->properties['SUMMARY'][0]->value; + $name = str_replace('\n', '
', $name); + $name = str_replace('\\', '', $name); + $name = preg_replace('/\s+/', ' ', $name); + $eventrecord->name = clean_param($name, PARAM_CLEAN); + + if (empty($event->properties['DESCRIPTION'][0]->value)) { + $description = ''; + } else { + $description = $event->properties['DESCRIPTION'][0]->value; + $description = str_replace('\n', '
', $description); + $description = str_replace('\\', '', $description); + $description = preg_replace('/\s+/', ' ', $description); + } + $eventrecord->description = clean_param($description, PARAM_CLEAN); + + // probably a repeating event with RRULE etc. TODO: skip for now + if (empty($event->properties['DTSTART'][0]->value)) { + return 0; + } + + $eventrecord->timestart = strtotime($event->properties['DTSTART'][0]->value); + if (empty($event->properties['DTEND'])) { + $eventrecord->timeduration = 3600; // one hour if no end time specified + } else { + $eventrecord->timeduration = strtotime($event->properties['DTEND'][0]->value) - $eventrecord->timestart; + } + $eventrecord->uuid = $event->properties['UID'][0]->value; + $eventrecord->timemodified = time(); + + // Add the iCal subscription details if required + if ($sub = $DB->get_record('event_subscriptions', array('id' => $subscriptionid))) { + $eventrecord->subscriptionid = $subscriptionid; + $eventrecord->userid = $sub->userid; + $eventrecord->groupid = $sub->groupid; + $eventrecord->courseid = $sub->courseid; + } else { + $eventrecord->userid = $USER->id; + $eventrecord->groupid = 0; // TODO: ??? + $eventrecord->courseid = $courseid; + } + + if ($updaterecord = $DB->get_record('event', array('uuid' => $eventrecord->uuid))) { + $eventrecord->id = $updaterecord->id; + if ($DB->update_record('event', $eventrecord)) { + return CALENDAR_IMPORT_EVENT_UPDATED; + } else { + return 0; + } + } else { + if ($DB->insert_record('event', $eventrecord)) { + return CALENDAR_IMPORT_EVENT_INSERTED; + } else { + return 0; + } + } +} + +/** + * Create the list of iCalendar subscriptions for a course calendar. + * @param int $courseid The course ID + * @return string The table output. + */ +function calendar_show_subscriptions($courseid, $importresults='') { + global $DB, $OUTPUT, $CFG, $USER; + + $view = optional_param('view', '', PARAM_ALPHA); + $sesskey = sesskey(); + $out = ''; + + $str->update = get_string('update'); + $str->remove = get_string('remove'); + $str->add = get_string('add'); + + $out .= $OUTPUT->box_start('generalbox calendarsubs'); + $out .= $importresults; + + $table = new html_table(); + $table->head = array('Calendar', 'Last Updated', 'Poll', 'Actions'); + $table->align = array('left', 'left', 'left', 'center'); + $table->width = '100%'; + $table->data = array(); + + $subs = $DB->get_records_sql('select * from {event_subscriptions} + where courseid = :courseid + or (courseid = 0 and userid = :userid)', + array('courseid' => $courseid, 'userid' => $USER->id)); + if (empty($subs)) { + $c = new html_table_cell("No calendar subscriptions."); + $c->colspan = 4; + $table->data[] = new html_table_row(array($c)); + } + foreach ($subs as $id => $sub) { + $label = empty($sub->url) ? $sub->name : "url}\">{$sub->name}"; + $c_url = new html_table_cell($label); + $lastupdated = empty($sub->lastupdated) + ? get_string('never', 'calendar') + : date('Y-m-d H:i:s', $sub->lastupdated); + $c_updated = new html_table_cell($lastupdated); + + if (empty($sub->url)) { + // don't update an iCal file, which has no URL. + $pollinterval = ''; + } else { + // assemble pollinterval control + $pollinterval = "
+
"; + } + + // assemble form for the subscription row + $rowform = " +
wwwroot}/calendar/view.php\" method=\"post\"> + {$pollinterval} +
+ + + + id}\" /> + " . (empty($sub->url) + ? '' + : "update}\" />") . " + remove}\" /> +
+
"; + $c_form = new html_table_cell($rowform); + $c_form->colspan = 2; + $table->data[] = new html_table_row(array($c_url, $c_updated, $c_form)); + } + $out .= html_writer::table($table); + + // form for adding a new subscription + $form = new calendar_addsubscription_form(); + $formdata = $form->get_data(); + if (empty($formdata)) { + $formdata = new stdClass; + $formdata->course = $courseid; + $form->set_data($formdata); + } + + // *sigh* there appears to be no function that returns Moodle Form HTML. + ob_start(); + $form->display(); + $buffer = ob_get_contents(); + $out .= $buffer; + ob_end_clean(); + + $out .= $OUTPUT->box_end(); + return $out; +} + +/** + * Add a subscription from the form data and add its events to the calendar. + * The form data will be either from the new subscription form, or from a form + * on one of the rows in the existing subscriptions table. + * @param int $courseid The course ID + * @return string A log of the import progress, including errors + */ +function calendar_process_subscription_form($courseid) { + global $DB; + + $form = new calendar_addsubscription_form(); + $formdata = $form->get_data(); + if (!empty($formdata)) { + if (empty($formdata->url) and empty($formdata->importfile)) { + print_error('errorrequiredurlorfile', 'calendar'); + } + if ($formdata->importfrom == CALENDAR_IMPORT_FROM_FILE) { + // blank the URL if it's a file import + $formdata->url = ''; + $subscriptionid = calendar_add_subscription($formdata); + $calendar = $form->get_ical_data(); + $ical = new iCalendar(); + $ical->unserialize($calendar); + return calendar_import_icalendar_events($ical, $courseid, $subscriptionid); + } else { + $subscriptionid = calendar_add_subscription($formdata); + return calendar_update_subscription_events($subscriptionid); + } + } else { + // process any subscription row form data + return calendar_process_subscription_row(); + } +} + +/** + * Update a subscription from the form data in one of the rows in the existing + * subscriptions table. + * @return string A log of the import progress, including errors + */ +function calendar_process_subscription_row() { + global $DB; + + $id = optional_param('id', 0, PARAM_INT); + $courseid = optional_param('course', 0, PARAM_INT); + $pollinterval = optional_param('pollinterval', 0, PARAM_INT); + $action = optional_param('action', '', PARAM_ALPHA); + + if (empty($id)) { + return ''; + } + + $str->update = get_string('update'); + $str->remove = get_string('remove'); + + // update or remove the subscription, based on action. + $sub = $DB->get_record('event_subscriptions', array('id' => $id), '*', MUST_EXIST); + switch ($action) { + case $str->update: + // skip updating file subscriptions + if (empty($sub->url)) { + break; + } + $sub->pollinterval = $pollinterval; + $DB->update_record('event_subscriptions', $sub); + + // update the events + return "

Calendar subscription '{$sub->name}' updated.

" . calendar_update_subscription_events($id); + break; + + case $str->remove: + $sesskey = required_param('sesskey', PARAM_ALPHANUM); + $DB->delete_records('event', array('subscriptionid' => $id)); + $DB->delete_records('event_subscriptions', array('id' => $id)); + return "Calendar subscription '{$sub->name}' removed."; + break; + + default: + break; + } + return ''; +} + +/** + * From a URL, fetch the calendar and return an iCalendar object. + * @param string $url The iCalendar URL + * @return object The iCalendar object + */ +function calendar_get_icalendar($url) { + $calendar = file_get_contents($url); + $ical = new iCalendar(); + $ical->unserialize($calendar); + return $ical; +} + +/** + * Import events from an iCalendar object into a course calendar. + * @param object $ical The iCalendar object + * @param integer $courseid The course ID for the calendar + * @param integer $subscriptionid The subscription ID + * @return string A log of the import progress, including + * errors + */ +function calendar_import_icalendar_events($ical, $courseid, $subscriptionid=null) { + global $DB; + $return = ''; + $eventcount = 0; + $updatecount = 0; + + // large calendars take a while... + ini_set('max_execution_time', 300); + + // mark all events in a subscription with a zero timestamp + if (!empty($subscriptionid)) { + $sql = "update {event} set timemodified = :time where subscriptionid = :id"; + $DB->execute($sql, array('time' => 0, 'id' => $subscriptionid)); + } + foreach($ical->components['VEVENT'] as $event) { + $res = calendar_add_icalendar_event($event, $courseid, $subscriptionid); + switch ($res) { + case CALENDAR_IMPORT_EVENT_UPDATED: + $updatecount++; + break; + case CALENDAR_IMPORT_EVENT_INSERTED: + $eventcount++; + break; + case 0: + $return .= '

Failed to add event: '.(empty($event->properties['SUMMARY'])?'(no title)':$event->properties['SUMMARY'][0]->value)."

\n"; + break; + } + } + $return .= "

Events imported: {$eventcount}

\n"; + $return .= "

Events updated: {$updatecount}

\n"; + + // delete remaining zero-marked events since they're not in remote calendar + if (!empty($subscriptionid)) { + $deletecount = $DB->count_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid)); + if (!empty($deletecount)) { + $sql = "delete from {event} where timemodified = :time and subscriptionid = :id"; + $DB->execute($sql, array('time' => 0, 'id' => $subscriptionid)); + $return .= "

Events deleted: {$deletecount}

\n"; + } + } + + return $return; +} + +/** + * Fetch a calendar subscription and update the events in the calendar. + * @param integer $subscriptionid The course ID for the calendar + * @return string A log of the import progress, including + * errors + */ +function calendar_update_subscription_events($subscriptionid) { + global $DB; + $return = ''; + + $sub = $DB->get_record('event_subscriptions', array('id' => $subscriptionid)); + if (empty($sub)) { + print_error('errorbadsubscription', 'calendar'); + } + // Don't update a file subscription. TODO: Update from a new uploaded file? + if (empty($sub->url)) { + return 'File subscription not updated.'; + } + $ical = calendar_get_icalendar($sub->url); + $return = calendar_import_icalendar_events($ical, $sub->courseid, $subscriptionid); + $sub->lastupdated = time(); + $DB->update_record('event_subscriptions', $sub); + return $return; +} + +/** + * Update calendar subscriptions. + */ +function calendar_cron() { + global $DB; + mtrace("Updating calendar subscriptions:"); + $time = time(); + foreach ($DB->get_records_sql('select * from {event_subscriptions} + where pollinterval > 0 and lastupdated + pollinterval < ?', array($time)) as $sub) { + mtrace(" Updating calendar subscription '{$sub->name}' in course {$sub->courseid}"); + $log = calendar_update_subscription_events($sub->id); + mtrace(trim(strip_tags($log))); + } + mtrace("Finished updating calendar subscriptions."); + return true; +} + diff --git a/calendar/view.php b/calendar/view.php index 8f5695667a5..01dead64a0f 100644 --- a/calendar/view.php +++ b/calendar/view.php @@ -80,6 +80,10 @@ if ($courseid != SITEID && !empty($courseid)) { } require_course_login($course); +if (calendar_user_can_add_event($course)) { + $importresults = calendar_process_subscription_form($courseid); +} + $calendar = new calendar_information($day, $mon, $yr); $calendar->prepare_for_view($course, $courses); @@ -147,6 +151,9 @@ switch($view) { //Link to calendar export page echo $OUTPUT->container_start('bottom'); +if (calendar_user_can_add_event($course)) { + echo calendar_show_subscriptions($courseid, $importresults); +} if (!empty($CFG->enablecalendarexport)) { echo $OUTPUT->single_button(new moodle_url('export.php', array('course'=>$courseid)), get_string('exportcalendar', 'calendar')); if (isloggedin()) { diff --git a/lang/en/calendar.php b/lang/en/calendar.php index 96b6c4f9a13..2aa1979b150 100644 --- a/lang/en/calendar.php +++ b/lang/en/calendar.php @@ -25,6 +25,7 @@ $string['advancedoptions'] = 'Advanced options'; $string['allday'] = 'All day'; +$string['annually'] = 'Annually'; $string['calendar'] = 'Calendar'; $string['calendarheading'] = '{$a} Calendar'; $string['calendarpreferences'] = 'Calendar preferences'; @@ -37,6 +38,7 @@ $string['course'] = 'Course'; $string['courseevent'] = 'Course event'; $string['courseevents'] = 'Course events'; $string['courses'] = 'Courses'; +$string['daily'] = 'Daily'; $string['dayview'] = 'Day view'; $string['dayviewtitle'] = 'Day view: {$a}'; $string['daywithnoevents'] = 'There are no events this day.'; @@ -49,12 +51,14 @@ $string['durationminutes'] = 'Duration in minutes'; $string['durationnone'] = 'Without duration'; $string['durationuntil'] = 'Until'; $string['editevent'] = 'Editing event'; +$string['errorbadsubscription'] = 'Calendar subscription not found.'; $string['errorbeforecoursestart'] = 'Cannot set event before course start date'; $string['errorinvaliddate'] = 'Invalid date'; $string['errorinvalidminutes'] = 'Specify duration in minutes by giving a number between 1 and 999.'; $string['errorinvalidrepeats'] = 'Specify the number of events by giving a number between 1 and 99.'; $string['errornodescription'] = 'Description is required'; $string['errornoeventname'] = 'Name is required'; +$string['errorrequiredurlorfile'] = 'Either a URL or a file is required to import a calendar.'; $string['eventdate'] = 'Date'; $string['eventdescription'] = 'Description'; $string['eventduration'] = 'Duration'; @@ -92,19 +96,28 @@ $string['hidecourseevents'] = 'Hide course events'; $string['hideglobalevents'] = 'Hide global events'; $string['hidegroupsevents'] = 'Hide group events'; $string['hideuserevents'] = 'Hide user events'; +$string['hourly'] = 'Hourly'; $string['ical'] = 'iCal'; +$string['importcalendar'] = 'Import calendar'; +$string['importcalendarfrom'] = 'Import from'; +$string['importfromfile'] = 'Calendar file (.ics)'; +$string['importfromurl'] = 'Calendar URL'; $string['invalidtimedurationminutes'] = 'The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.'; $string['invalidtimedurationuntil'] = 'The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.'; $string['iwanttoexport'] = 'Export'; $string['manyevents'] = '{$a} events'; $string['mon'] = 'Mon'; $string['monday'] = 'Monday'; +$string['monthly'] = 'Monthly'; $string['monthlyview'] = 'Monthly view'; $string['monthnext'] = 'Next month'; $string['monththis'] = 'This month'; +$string['never'] = 'Never'; $string['newevent'] = 'New event'; $string['noupcomingevents'] = 'There are no upcoming events'; $string['oneevent'] = '1 event'; +$string['pollinterval'] = 'Poll interval'; +$string['pollinterval_help'] = 'How often you would like the calendar to update with new events.'; $string['preferences'] = 'Preferences'; $string['preferences_available'] = 'Your personal preferences'; $string['pref_lookahead'] = 'Upcoming events look-ahead'; @@ -134,6 +147,7 @@ $string['showgroupsevents'] = 'Show group events'; $string['showuserevents'] = 'Show user events'; $string['shown'] = 'shown'; $string['spanningevents'] = 'Events underway'; +$string['subscriptionname'] = 'Calendar name'; $string['sun'] = 'Sun'; $string['sunday'] = 'Sunday'; $string['thu'] = 'Thu'; @@ -165,6 +179,7 @@ $string['userevent'] = 'User event'; $string['userevents'] = 'User events'; $string['wed'] = 'Wed'; $string['wednesday'] = 'Wednesday'; +$string['weekly'] = 'Weekly'; $string['weeknext'] = 'Next week'; $string['weekthis'] = 'This week'; $string['yesterday'] = 'Yesterday'; diff --git a/lib/cronlib.php b/lib/cronlib.php index c0b86afb8c1..79e808bd4d3 100644 --- a/lib/cronlib.php +++ b/lib/cronlib.php @@ -350,6 +350,9 @@ function cron_run() { cron_execute_plugin_type('gradereport'); mtrace('Finished gradebook plugins'); + // run calendar cron + require_once "{$CFG->dirroot}/calendar/lib.php"; + calendar_cron(); // Run external blog cron if needed if (!empty($CFG->enableblogs) && $CFG->useexternalblogs) { diff --git a/lib/db/install.xml b/lib/db/install.xml old mode 100644 new mode 100755 index 36176538feb..0b2ac107d37 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1,5 +1,5 @@ - @@ -487,9 +487,10 @@ - + - + + @@ -2848,7 +2849,7 @@ - +
@@ -2866,5 +2867,20 @@
+ + + + + + + + + + + + + + +
-
\ No newline at end of file + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index e57fb160119..db37df0d003 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -1260,5 +1260,42 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2012101500.01); } + if ($oldversion < 2012103000.00) { + // create new event_subscriptions table + $table = new xmldb_table('event_subscriptions'); + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('url', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); + $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('groupid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('pollinterval', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('lastupdated', XMLDB_TYPE_INTEGER, '10', null, null, null, null); + $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, ''); + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + if (!$dbman->table_exists($table)) { + $dbman->create_table($table); + } + // Main savepoint reached + upgrade_main_savepoint(true, 2012103000.00); + } + + if ($oldversion < 2012103000.01) { + // Add subscription field to the event table + $table = new xmldb_table('event'); + $field = new xmldb_field('subscriptionid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, 'timemodified'); + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Fix uuid field in event table to match RFC-2445 UID property + $field = new xmldb_field('uuid', XMLDB_TYPE_CHAR, 255, null, XMLDB_NOTNULL, null, '', 'visible'); + if ($dbman->field_exists($table, $field)) { + $dbman->change_field_precision($table, $field); + } + + // Main savepoint reached + upgrade_main_savepoint(true, 2012103000.01); + } + return true; } diff --git a/version.php b/version.php index 4bba4738bd0..27e40b93dfc 100644 --- a/version.php +++ b/version.php @@ -30,7 +30,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2012101800.00; // YYYYMMDD = weekly release date of this DEV branch +$version = 2012103000.01; // YYYYMMDD = weekly release date of this DEV branch // RR = release increments - 00 in DEV branches // .XX = incremental changes