Commit 3073af84 authored by Robert Rollins's avatar Robert Rollins

Issue [#2113513]: Users may now exclude the DTSTAMP field from their feeds.

Some ical feed readers will erroneously take the DTSTAMP field into
consideration when comparing a new download to a previous one, and end up
treating all events as having been updated, because their DTSTAMP field is
different. This new option lets you get around those buggy readers.

I also added the CREATED field, which was embarassingly missing until now.
parent b86d9315
......@@ -331,14 +331,19 @@ class date_ical_plugin_row_ical_entity extends views_plugin_row {
$this->entities[$id] = NULL;
}
// Pull the 'changed' date from the entity, so that subscription clients can tell if the event has been updated.
// According to the iCal standard, LAST-MODIFIED must be UTC. Fortunately, Drupal stores timestamps in the DB
// as UTC, so we just need to specify that UTC be used rather than the server's local timezone.
// According to the iCal standard, CREATED and LAST-MODIFIED must be UTC.
// Fortunately, Drupal stores timestamps in the DB as UTC, so we just need
// to specify that UTC be used rather than the server's local timezone.
if (isset($entity->created)) {
$event['created'] = new DateObject($entity->created, new DateTimeZone('UTC'));
}
// Pull the 'changed' date from the entity (if available), so that
// subscription clients can tell if the event has been updated.
if (isset($entity->changed)) {
$event['last-modified'] = new DateObject($entity->changed, new DateTimeZone('UTC'));
}
else if (isset($entity->created)) {
// If the changed date isn't set, but the created date is, use that instead.
// If changed is unset, but created is, use that for last-modified.
$event['last-modified'] = new DateObject($entity->created, new DateTimeZone('UTC'));
}
......
......@@ -104,6 +104,7 @@ class date_ical_plugin_row_ical_fields extends views_plugin_row {
// because this function must be compatible with views_plugin_row::render().
$args = func_get_args();
$row_index = $args[1];
$date_field_name = $this->options['date_field'];
// Fetch the event's date information.
try {
......@@ -123,33 +124,38 @@ class date_ical_plugin_row_ical_fields extends views_plugin_row {
// Create the event by starting with the date array from this row.
$event = $date;
// Add the LAST-MODIFIED and URL components based on the original entity.
// Add the CREATED, LAST-MODIFIED, and URL components based on the entity.
// According to the iCal standard, CREATED and LAST-MODIFIED must be UTC.
// Fortunately, Drupal stores timestamps in the DB as UTC, so we just need
// to specify that UTC be used rather than the server's local timezone.
$entity = $row->_field_data[$this->view->base_field]['entity'];
$entity_type = $row->_field_data[$this->view->base_field]['entity_type'];
if (isset($entity->created)) {
$event['created'] = new DateObject($entity->created, new DateTimeZone('UTC'));
}
if (isset($entity->changed)) {
$event['last-modified'] = new DateObject($entity->changed, new DateTimeZone('UTC'));
}
else if (isset($entity->created)) {
// If the changed date isn't set, but the created date is, use that instead.
// If changed is unset, but created is, use that for last-modified.
$event['last-modified'] = new DateObject($entity->created, new DateTimeZone('UTC'));
}
$uri = entity_uri($entity_type, $entity);
$uri['options']['absolute'] = TRUE;
$event['url'] = url($uri['path'], $uri['options']);
// Generate a unique ID for this event by emulating the way the Date module
// creates a Date ID.
if (isset($row->{"field_data_{$this->options['date_field']}_delta"})) {
$date_field_delta = $row->{"field_data_{$this->options['date_field']}_delta"};
if (isset($row->{"field_data_{$date_field_name}_delta"})) {
$date_field_delta = $row->{"field_data_{$date_field_name}_delta"};
}
else {
// I'm not sure why the "field_data_<field_name>_delta" field is part of
// I'm not sure why the "field_data_{field_name}_delta" field is part of
// the $row, so it's possible that it will sometimes be missing. If it
// is, make an educated guess about the delta by comparing this row's
// start date to each of the entity's dates.
$date_field_delta = 0;
foreach ($entity->{$this->options['date_field']}['und'] as $ndx => $date_array) {
foreach ($entity->{$date_field_name}['und'] as $ndx => $date_array) {
if ($date['start']->originalTime == $date_array['value']) {
$date_field_delta = $ndx;
break;
......@@ -157,7 +163,6 @@ class date_ical_plugin_row_ical_fields extends views_plugin_row {
}
}
$entity_id = $row->{$this->view->base_field};
$date_field_name = $this->options['date_field'];
$domain = check_plain($_SERVER['SERVER_NAME']);
$event['uid'] = "calendar.$entity_id.$date_field_name.$date_field_delta@$domain";
......
......@@ -10,7 +10,7 @@
*/
class date_ical_plugin_style_ical_feed extends views_plugin_style {
function _get_option($option_name) {
protected function _get_option($option_name) {
return isset($this->options[$option_name]) ? $this->options[$option_name] : '';
}
......@@ -51,8 +51,9 @@ class date_ical_plugin_style_ical_feed extends views_plugin_style {
function option_definition() {
$options = parent::option_definition();
$options['cal_name'] = array('default' => array());
$options['no_calname'] = array('default' => array());
$options['disable_webcal'] = array('default' => array());
$options['no_calname'] = array('default' => FALSE, 'bool' => TRUE);
$options['disable_webcal'] = array('default' => FALSE, 'bool' => TRUE);
$options['exclude_dtstamp'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
......@@ -82,6 +83,15 @@ class date_ical_plugin_style_ical_feed extends views_plugin_style {
clients to easily subscribe to the feed. If you want your users to instead download this iCal
feed as a file, activate this option."),
);
$form['exclude_dtstamp'] = array(
'#type' => 'checkbox',
'#title' => t('Exclude DTSTAMP'),
'#default_value' => $this->_get_option('exclude_dtstamp'),
'#description' => t("By default, the feed will set each event's DTSTAMP property to the time at which the feed got downloaded.
Some feed readers will (incorrectly) look at the DTSTAMP value when they compare different downloads of the same feed, and
conclcude that the event has been updated (even though it hasn't actually changed). Enable this option to exclude the DTSTAMP
field from your feeds, so that these buggy feed readers won't mark every event as updated every time they check."),
);
}
function render() {
......@@ -309,6 +319,18 @@ class date_ical_plugin_style_ical_feed extends views_plugin_style {
$lm['timezone']
);
}
if (!empty($event['created'])) {
$created = $event['created']->toArray();
$vevent->setCreated(
$created['year'],
$created['month'],
$created['day'],
$created['hour'],
$created['minute'],
$created['second'],
$created['timezone']
);
}
// Allow other modules to alter the VEVENT object.
drupal_alter('date_ical_feed_ical_vevent_render', $vevent, $this->view, $event);
......@@ -331,6 +353,22 @@ class date_ical_plugin_style_ical_feed extends views_plugin_style {
// might be going too far.
$output = str_replace('\,', ',', $output);
$output = str_replace('\;', ';', $output);
// In order to respect the Exclude DTSTAMP option, we unfortunately have
// to parse out the DTSTAMP properties after they get rendered. Simply
// using deleteProperty('DTSTAMP') doesn't work, because iCalcreator
// considers the DTSTAMP to be essential, and will re-create it when
// createCalendar() is called.
if ($this->_get_option('exclude_dtstamp')) {
$filtered_lines = array();
foreach (explode("\r\n", $output) as $line) {
if (strpos($line, 'DTSTAMP') === 0) {
continue;
}
$filtered_lines[] = $line;
}
$output = implode("\r\n", $filtered_lines);
}
}
// These steps shouldn't be run when doing a Preview on the View config page.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment