diff --git a/inc/check_UTF8.php b/inc/check_UTF8.php index 80fa01d1..e3c93dbf 100644 --- a/inc/check_UTF8.php +++ b/inc/check_UTF8.php @@ -221,8 +221,8 @@ function check_string($ics){ return false; } } else { - dbg_error_log( "LOG check_string","the string is UTF8 compliant"); +// dbg_error_log( "LOG check_string","the string is UTF8 compliant"); return true; } } -?> \ No newline at end of file +?> diff --git a/scripts/archive-old-events.php b/scripts/archive-old-events.php new file mode 100755 index 00000000..ba542278 --- /dev/null +++ b/scripts/archive-old-events.php @@ -0,0 +1,210 @@ +#!/usr/bin/env php + +* @copyright Morphoss Ltd +* @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later +*/ +$script_file = __FILE__; + +chdir(str_replace('/scripts/archive-old-events.php','/htdocs',$script_file)); +$_SERVER['SERVER_NAME'] = 'localhost'; + +/** +* Call with something like e.g.: +* +* scripts/archive-old-events.php -a archive -p karora -o P93D +* +*/ + +$args = (object) array(); +$args->debug = false; +$args->principal = false; +$args->collection = false; + +$args->older = 'P190D'; +$args->delete = false; +$args->archive_suffix = 'archive'; +$debugging = null; + + +function parse_arguments() { + global $args; + + $opts = getopt( 'a:c:o:p:s:dh' ); + foreach( $opts AS $k => $v ) { + switch( $k ) { + case 'a': $args->archive_suffix = $v; break; + case 'c': $args->collection = $v; break; + case 'o': $args->older = $v; break; + case 'p': $args->principal = $v; break; + case 's': $_SERVER['SERVER_NAME'] = $v; break; + case 'd': $args->debug = true; $debugging = explode(',',$v); break; + case 'h': usage(); break; + default: $args->{$k} = $v; + } + } + $bad = false; + if ( $args->principal === false ) { + echo "You must supply a principal.\n"; + $bad = true; + } + if ( $args->collection === false ) { + echo "You must supply a collection.\n"; + $bad = true; + } + if ( $bad ) { + usage(); + } +} + +function usage() { + + echo << Appendeded (after a '-') to the name of the original calendar to give + the archive calendar name. Default 'archive'. + -o Archive events completed this much prior to the current + date. Default 'P-190D' + -p The name of the principal to do the archiving for (required). + -c The name of the collection to do the archiving for (required). + -s The servername to be used to identify the DAViCal configuration file. + + -d xxx Enable debugging where 'xxx' is a comma-separated list of debug subsystems + +USAGE; + exit(0); +} + +parse_arguments(); + +if ( $args->debug && is_array($debugging )) { + foreach( $debugging AS $v ) { + $c->dbg[$v] = 1; + } +} + +require_once("./always.php"); +require_once('AwlQuery.php'); +require_once('AwlCache.php'); +require_once('RRule-v2.php'); +require_once('vCalendar.php'); + + +/** +* Essentially what we are doing is: +* +DELETE FROM caldav_data JOIN calendar_item USING(dav_id) + WHERE dav_name LIKE '/someprincipal/%' + AND ( + (rrule IS NULL AND dtend < archive_before_date) + OR (last_instance_end < archive_before_date) + ) + +*/ +$recent = new RepeatRuleDateTime(gmdate('Ymd\THis\Z')); +$recent->modify('P-6D'); +$archive_before_date = new RepeatRuleDateTime(gmdate('Ymd\THis\Z')); +$archive_before_date->modify( $args->older ); +if ( $archive_before_date > $recent ) { + echo "Cowardly refusing to archive events before "+$archive_before_date->format('Y-m-d H:i:s') + "\n"; +} + + +if ( $args->debug ) printf( "Archiving event instances finished before '%s'\n", $archive_before_date->UTC() ); + +// SQL to create an archive collection but only if it doesn't exist already. +$archive_collection_sql = <<principal, $args->collection ); +$collection_archive = sprintf( '/%s/%s-%s/', $args->principal, $args->collection, $args->archive_suffix ); + +$sqlargs = array( + ':collection_dav_name' => $collection_dav_name, + ':archive_dav_name' => $collection_archive + ); +$qry = new AwlQuery($archive_collection_sql, $sqlargs); +$qry->query_time_warning = 5; // Don't warn on queries unless they take more than 5 seconds. +if ( $qry->Exec(__CLASS__, __LINE__, __FILE__) ) { + $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = ?', $collection_dav_name ); + if ( $qry->rows() != 1 ) { + printf( "Could not find source collection '%s'\n", $collection_dav_name); + exit(1); + } + $row = $qry->Fetch(); + $source_collection_id = $row->collection_id; + + $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = ?', $collection_archive ); + if ( $qry->rows() != 1 ) { + printf( "Could not create archive collection '%s'!\n", $collection_archive); + exit(2); + } + $row = $qry->Fetch(); + $archive_collection_id = $row->collection_id; + + $archive_sql = <<debug ) printf( "%s\n", $archive_sql ); + + $sqlargs[':archive_before_date'] = $archive_before_date->FloatOrUTC(); + $sqlargs[':source_collection_id'] = $source_collection_id; + $sqlargs[':archive_collection_id'] = $archive_collection_id; + $qry->QDo($archive_sql, $sqlargs); + + /** + * At this point we've done all the work, we just have to inform the rest of the world that + * everything has changed underneath it. + */ + + // Now ensure the collection tag changes... + $sql = 'UPDATE collection SET dav_etag = random(), modified = current_timestamp WHERE collection_id IN (:source_id, :archive_id)'; + $sqlargs = array( + ':source_id' => $source_collection_id, + ':archive_id' => $archive_collection_id + ); + $qry->QDo($sql, $sqlargs); + + // Delete the sync tokens... + $sql = 'DELETE FROM sync_tokens WHERE collection_id IN (:source_id, :archive_id)'; + $qry->QDo($sql, $sqlargs); + + // Delete the sync_changes... + $sql = 'DELETE FROM sync_changes WHERE collection_id IN (:source_id, :archive_id)'; + $qry->QDo($sql, $sqlargs); + + // Uncache anything to do with the collection, or the archive + $cache = getCacheInstance(); + $cache_ns = 'collection-'.preg_replace( '{/[^/]*$}', '/', $collection_dav_name); + $cache->delete( $cache_ns, null ); + $cache_ns = 'collection-'.preg_replace( '{/[^/]*$}', '/', $collection_archive); + $cache->delete( $cache_ns, null ); +}