mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
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.
This commit is contained in:
parent
7e8ae12a7a
commit
b5a52acd9d
538
calendar/lib.php
538
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', '<script type="text/javascript"><!--
|
||||
function showhide_subform() {
|
||||
divs = document.getElementById("addsubscriptionform").getElementsByTagName("div");
|
||||
for (var i = 0; i < divs.length; ++i) {
|
||||
if (divs[i].style.display=="none") {
|
||||
divs[i].style.display = "block";
|
||||
} else {
|
||||
divs[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
//--></script>');
|
||||
$mform->addElement('header', 'addsubscriptionform', '<a name="targetsubcriptionform" onclick="showhide_subform()">Import calendar...</a>');
|
||||
|
||||
$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', '<script type="text/javascript">showhide_subform()</script>');
|
||||
}
|
||||
|
||||
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', '<br />', $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', '<br />', $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 : "<a href=\"{$sub->url}\">{$sub->name}</a>";
|
||||
$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 = '<input type="hidden" name="pollinterval" value="0" />';
|
||||
} else {
|
||||
// assemble pollinterval control
|
||||
$pollinterval = "<div style=\"float:left\">
|
||||
<select name=\"pollinterval\">\n";
|
||||
foreach (calendar_get_pollinterval_choices() as $k => $v) {
|
||||
$selected = ($k == $sub->pollinterval) ? ' selected' : '';
|
||||
$pollinterval .= "<option value=\"{$k}\"{$selected}>{$v}</option>\n";
|
||||
}
|
||||
$pollinterval .= "</select></div>";
|
||||
}
|
||||
|
||||
// assemble form for the subscription row
|
||||
$rowform = "
|
||||
<form action=\"{$CFG->wwwroot}/calendar/view.php\" method=\"post\">
|
||||
{$pollinterval}
|
||||
<div style=\"float:right\">
|
||||
<input type=\"hidden\" name=\"sesskey\" value=\"{$sesskey}\" />
|
||||
<input type=\"hidden\" name=\"view\" value=\"{$view}\" />
|
||||
<input type=\"hidden\" name=\"course\" value=\"{$courseid}\" />
|
||||
<input type=\"hidden\" name=\"id\" value=\"{$sub->id}\" />
|
||||
" . (empty($sub->url)
|
||||
? ''
|
||||
: "<input type=\"submit\" name=\"action\" value=\"{$str->update}\" />") . "
|
||||
<input type=\"submit\" name=\"action\" value=\"{$str->remove}\" />
|
||||
</div>
|
||||
</form>";
|
||||
$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 "<p>Calendar subscription '{$sub->name}' updated.</p>" . 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 .= '<p>Failed to add event: '.(empty($event->properties['SUMMARY'])?'(no title)':$event->properties['SUMMARY'][0]->value)." </p>\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$return .= "<p> Events imported: {$eventcount} </p>\n";
|
||||
$return .= "<p> Events updated: {$updatecount} </p>\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 .= "<p> Events deleted: {$deletecount} </p>\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;
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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';
|
||||
|
@ -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) {
|
||||
|
26
lib/db/install.xml
Normal file → Executable file
26
lib/db/install.xml
Normal file → Executable file
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20121002" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20121011" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -487,9 +487,10 @@
|
||||
<FIELD NAME="timestart" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="eventtype" NEXT="timeduration"/>
|
||||
<FIELD NAME="timeduration" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timestart" NEXT="visible"/>
|
||||
<FIELD NAME="visible" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="timeduration" NEXT="uuid"/>
|
||||
<FIELD NAME="uuid" TYPE="char" LENGTH="36" NOTNULL="true" SEQUENCE="false" PREVIOUS="visible" NEXT="sequence"/>
|
||||
<FIELD NAME="uuid" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="visible" NEXT="sequence"/>
|
||||
<FIELD NAME="sequence" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="uuid" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="sequence"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="sequence" NEXT="subscriptionid"/>
|
||||
<FIELD NAME="subscriptionid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="timemodified"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
@ -2848,7 +2849,7 @@
|
||||
<KEY NAME="fk_usercreated" TYPE="foreign" FIELDS="usercreated" REFTABLE="user" REFFIELDS="id" PREVIOUS="uq_area_method"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="grading_instances" COMMENT="Grading form instance is an assessment record for one gradable item assessed by one rater" PREVIOUS="grading_definitions">
|
||||
<TABLE NAME="grading_instances" COMMENT="Grading form instance is an assessment record for one gradable item assessed by one rater" PREVIOUS="grading_definitions" NEXT="event_subscriptions">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="definitionid"/>
|
||||
<FIELD NAME="definitionid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The ID of the form definition this is instance of" PREVIOUS="id" NEXT="raterid"/>
|
||||
@ -2866,5 +2867,20 @@
|
||||
<KEY NAME="fk_raterid" TYPE="foreign" FIELDS="raterid" REFTABLE="user" REFFIELDS="id" PREVIOUS="fk_definitionid"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="event_subscriptions" COMMENT="Tracks subscriptions to remote calendars" PREVIOUS="grading_instances">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="url"/>
|
||||
<FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="courseid"/>
|
||||
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="url" NEXT="groupid"/>
|
||||
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="courseid" NEXT="userid"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="groupid" NEXT="pollinterval"/>
|
||||
<FIELD NAME="pollinterval" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="lastupdated"/>
|
||||
<FIELD NAME="lastupdated" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" PREVIOUS="pollinterval" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="lastupdated"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
</XMLDB>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user