Update instance range columns when a collection's timezone changes

TODO: Handle the case where it is updated through the web UI
This commit is contained in:
Jamie McClymont 2019-01-08 13:05:34 +13:00
parent 7b55b7b1f2
commit fe443bf2e6
4 changed files with 76 additions and 0 deletions

View File

@ -231,6 +231,9 @@ function UpdateCollectionTimezones( $username, $new_timezone=null ) {
if ( empty($new_timezone) ) return;
$qry = new AwlQuery('UPDATE collection SET timezone=? WHERE dav_name LIKE ? AND is_calendar', '/'.$username.'/%', $new_timezone);
$qry->Exec();
require_once("instance_range.php");
update_instance_ranges($dav_resource->dav_name());
}
/**

View File

@ -275,6 +275,8 @@ foreach( $setprops AS $k => $setting ) {
$qry->QDo('UPDATE collection SET timezone = :tzid WHERE dav_name = :dav_name',
array( ':tzid' => $tzid, ':dav_name' => $dav_resource->dav_name()) );
require_once("instance_range.php");
update_instance_ranges($dav_resource->dav_name());
}
else {
add_failure('set', $tag, 'HTTP/1.1 409 Conflict', translate("calendar-timezone property is only valid for a calendar."));
@ -389,6 +391,8 @@ foreach( $rmprops AS $k => $setting ) {
case 'urn:ietf:params:xml:ns:caldav:calendar-timezone':
if ( $dav_resource->IsCollection() && $dav_resource->IsCalendar() && ! $dav_resource->IsBinding() ) {
$qry->QDo('UPDATE collection SET timezone = NULL WHERE dav_name = :dav_name', array( ':dav_name' => $dav_resource->dav_name()) );
require_once("instance_range.php");
update_instance_ranges($dav_resource->dav_name());
}
else {
add_failure('rm', $tag, 'HTTP/1.1 403 Forbidden',

55
inc/instance_range.php Normal file
View File

@ -0,0 +1,55 @@
<?php
require_once("RRule.php");
require_once("vCalendar.php");
function update_instance_ranges(string $collection_dav_name) {
// This can take a while, since vCalendar parsing is very slow, and we're
// going to parse every event in the collection!
//
// Since we might be doing this during a caldav request which we'd rather not
// have fail, we increase the execution time limit to prevent timeouts
set_time_limit(120);
$qry = new AwlQuery();
$in_transaction = ($qry->TransactionState() == 1);
if ( ! $in_transaction ) $qry->Begin();
$qry->QDo(
"SELECT d.dav_id, c.collection_id, d.caldav_data, c.timezone, i.first_instance_start, i.last_instance_end
FROM caldav_data d
INNER JOIN collection c ON d.collection_id = c.collection_id
INNER JOIN calendar_item i ON d.collection_id = i.collection_id AND d.dav_id = i.dav_id
WHERE c.dav_name = :dav_name",
[":dav_name" => $collection_dav_name]
);
while( $row = $qry->Fetch() ) {
$range = getVCalendarRange(new vCalendar($row->caldav_data), $row->timezone);
$new_start = isset($range->from) ? $range->from->UTC() : null;
$new_end = isset($range->until) ? $range->until->UTC() : null;
if ($new_start != $row->first_instance_start || $new_end != $row->last_instance_end) {
$inner_qry = new AwlQuery(
"UPDATE calendar_item
SET first_instance_start = :first_instance_start,
last_instance_end = :last_instance_end
WHERE collection_id = :collection_id AND dav_id = :dav_id",
[
":dav_id" => $row->dav_id,
":collection_id" => $row->collection_id,
":first_instance_start" => $new_start,
":last_instance_end" => $new_end
]
);
$inner_qry->Exec('UpdateInstanceRange',__LINE__,__FILE__);
}
}
if ( ! $in_transaction ) $qry->Commit();
}
?>

View File

@ -91,7 +91,14 @@ if ( $can_write_collection && $editor->IsSubmit() ) {
}
else {
$c->messages[] = i18n("Updating Collection.");
// We need to know whether to update_instance_ranges, which is an expensive
// operation we should only do if the collection timezone has been updated
$tzqry = new AwlQuery( "SELECT timezone FROM collection WHERE collection_id=:id", [ ":id" => $id ] );
$tzqry->Exec('collection-edit',__LINE__,__FILE__);
$old_tz = $tzqry->Fetch()->timezone;
}
if ( !$editor->Write() ) {
$c->messages[] = i18n("Failed to write collection.");
if ( $id > 0 ) $editor->GetRecord();
@ -121,6 +128,13 @@ if ( $can_write_collection && $editor->IsSubmit() ) {
$c->messages[] = i18n('The file is not UTF-8 encoded, please check the error for more details.');
}
}
if ($editor->IsCreate() || $old_tz != $_POST['timezone']) {
dbg_error_log('collection-edit', 'Need to update instance ranges, this will take a while...');
require_once("instance_range.php");
update_instance_ranges($editor->Value('dav_name'));
}
// Uncache anything to do with the collection
$cache = getCacheInstance();
$cache->delete( 'collection-'.$editor->Value('dav_name'), null );