remove sync_cms

sync from google calendar is not used anymore
This commit is contained in:
Milan
2023-02-26 23:02:18 +01:00
parent 66ee4ce41e
commit 3ee57b448e
24 changed files with 0 additions and 1370 deletions

View File

@@ -1,18 +0,0 @@
<config>
start_dir /home/calcms/agenda/admin/jobs/start/
log_dir /home/calcms/agenda/admin/jobs/logs/
<job>
title potsdam : sender berlin -> 88vier.de
name potsdam_to_88vier.de
command /home/radio/calcms/sync_cms/sync_jobs/calcms_to_google.sh -7 31 potsdam
</job>
<job>
title frb : sender berlin -> 88vier.de
name frb_to_88vier.de
command /home/radio/calcms/sync_cms/sync_jobs/calcms_to_google.sh -7 31 frb
</job>
</config>

View File

@@ -1,33 +0,0 @@
<source>
<access>
hostname localhost
port 3306
database calcms
username calcms_read
password password
</access>
<date>
time_zone Europe/Berlin
</date>
project 88vier
<projects>
<88vier>
name 88vier
title 88vier Studio Ansage
start_date 2010-05-01
end_date 2020-06-01
</88vier>
</projects>
location ansage
<mapping>
event_details_url http://senderberlin.org/programm/sendung/<TMPL_VAR event_id>.html
</mapping>
<system>
debug 1
</system>
</source>

View File

@@ -1,33 +0,0 @@
<source>
<access>
hostname localhost
port 3306
database calcms
username calcms_read
password password
</access>
<date>
time_zone Europe/Berlin
</date>
project 88vier
<projects>
<88vier>
name 88vier
title 88vier Colaboradio
start_date 2010-05-01
end_date 2020-06-01
</88vier>
</projects>
location colabo
<mapping>
event_details_url http://senderberlin.org/programm/sendung/<TMPL_VAR event_id>.html
</mapping>
<system>
debug 1
</system>
</source>

View File

@@ -1,33 +0,0 @@
<source>
<access>
hostname localhost
port 3306
database calcms
username calcms_read
password password
</access>
<date>
time_zone Europe/Berlin
</date>
project 88vier
<projects>
<88vier>
name 88vier
title 88vier FRB
start_date 2010-05-01
end_date 2020-06-01
</88vier>
</projects>
location frb
<mapping>
event_details_url http://senderberlin.org/programm/sendung/<TMPL_VAR event_id>.html
</mapping>
<system>
debug 1
</system>
</source>

View File

@@ -1,33 +0,0 @@
<source>
<access>
hostname localhost
port 3306
database calcms
username calcms_read
password password
</access>
<date>
time_zone Europe/Berlin
</date>
project 88vier
<projects>
<88vier>
name 88vier
title 88vier PI-Radio
start_date 2010-05-01
end_date 2020-06-01
</88vier>
</projects>
location piradio
<mapping>
event_details_url http://piradio.de/programm/sendung/<TMPL_VAR event_id>.html
</mapping>
<system>
debug 1
</system>
</source>

View File

@@ -1,33 +0,0 @@
<source>
<access>
hostname localhost
port 3306
database calcms
username calcms_read
password password
</access>
<date>
time_zone Europe/Berlin
</date>
project 88vier
<projects>
<88vier>
name 88vier
title 88vier Frrapo
start_date 2010-05-01
end_date 2020-06-01
</88vier>
</projects>
location potsdam
<mapping>
event_details_url http://senderberlin.org/programm/sendung/<TMPL_VAR event_id>.html
</mapping>
<system>
debug 1
</system>
</source>

View File

@@ -1,21 +0,0 @@
<target>
<access>
calendarId your-id
serviceAccount your-accounr@developer.gserviceaccount.com
serviceAccountKeyFile googleApi.key
</access>
<date>
time_zone Europe/Berlin
</date>
<mapping>
title <TMPL_VAR location> : <TMPL_VAR series_name> - <TMPL_VAR title>
content <TMPL_VAR excerpt> <a href="<TMPL_VAR event_details_url>">mehr zur Sendung</a>
</mapping>
<system>
debug 1
</system>
</target>

View File

@@ -1,21 +0,0 @@
<target>
<access>
calendarId your-calendar-id
serviceAccount your-account@developer.gserviceaccount.com
serviceAccountKeyFile googleApi.key
</access>
<date>
time_zone Europe/Berlin
</date>
<mapping>
title <TMPL_VAR location> : <TMPL_VAR series_name> - <TMPL_VAR title>
content <TMPL_VAR excerpt> <a href="<TMPL_VAR event_details_url>">mehr zur Sendung</a>
</mapping>
<system>
debug 1
</system>
</target>

View File

@@ -1,21 +0,0 @@
<target>
<access>
calendarId your-id@group.calendar.google.com
serviceAccount your-account@developer.gserviceaccount.com
serviceAccountKeyFile googleApi.key
</access>
<date>
time_zone Europe/Berlin
</date>
<mapping>
title <TMPL_VAR location> : <TMPL_VAR series_name> - <TMPL_VAR title>
content <TMPL_VAR excerpt> <a href="<TMPL_VAR event_details_url>">mehr zur Sendung</a>
</mapping>
<system>
debug 1
</system>
</target>

View File

@@ -1,21 +0,0 @@
<target>
<access>
calendarId your-id@group.calendar.google.com
serviceAccount your-account@developer.gserviceaccount.com
serviceAccountKeyFile googleApi.key
</access>
<date>
time_zone Europe/Berlin
</date>
<mapping>
title <TMPL_VAR location> - <TMPL_VAR series_name> - <TMPL_VAR title>
content <TMPL_VAR excerpt> <a href="<TMPL_VAR event_details_url>">mehr zur Sendung</a>
</mapping>
<system>
debug 1
</system>
</target>

View File

@@ -1,23 +0,0 @@
<target>
type google_calendar2
<access>
calendarId 8nh18f858098u4ji4qrsmfrcr4@group.calendar.google.com
serviceAccount 433089473368-bv26eveq03b7nhb9p62nu3ts7htgb4g3@developer.gserviceaccount.com
serviceAccountKeyFile /home/radio/googleApi.key
</access>
<date>
time_zone Europe/Berlin
</date>
<mapping>
title <TMPL_VAR location> : <TMPL_VAR series_name> - <TMPL_VAR title>
content <TMPL_VAR excerpt> <a href="<TMPL_VAR event_details_url>">mehr zur Sendung</a>
</mapping>
<system>
debug 1
</system>
</target>

View File

@@ -1,135 +0,0 @@
package CalcmsEvents;
use strict;
use warnings;
use Common ('info','error');
use DateTime;
use Data::Dumper;
use creole_wiki;
use events;
use time;
#use config;
my $settings = {};
sub init($) {
$settings = shift || {};
}
sub set($$) {
my $key = shift;
my $value = shift;
$settings->{$key} = $value;
}
sub get($) {
my $key = shift;
return $settings->{$key};
}
# return a list of start_min, start_max request parameters.
sub splitRequest($$$) {
my $from = shift;
my $till = shift;
my $timeZone = shift;
return undef unless defined $from;
return undef unless defined $till;
return undef if $from eq '';
return undef if $till eq '';
my $dates = [];
my $start = time::get_datetime( $from, $timeZone );
my $end = time::get_datetime( $till, $timeZone );
#build a list of dates
my $date = $start;
my @dates = ();
while ( $date < $end ) {
push @dates, $date;
$date = $date->clone->add( days => 7 );
}
my $duration = $end - $date;
push @dates, $end->clone if $duration->delta_seconds <= 0;
#build a list of parameters from dates
$start = shift @dates;
for my $end (@dates) {
push @$dates,
{
from => $start,
till => $end
};
$start = $end;
}
return $dates;
}
#get a hash with per-day-lists days of a google calendar, given by its url defined at $calendar_name
sub getEvents($$) {
my $from = shift;
my $till = shift;
my $last_update = get('last_update');
info "getEvents from $from till $till";
my $request_parameters = {
from_date => $from,
till_date => $till,
project => get('project'),
archive => 'all',
template => 'no'
};
my $location = get('location') || '';
$request_parameters->{location} = $location if $location ne '';
my $config = $settings;
my %params = ();
my $request = {
url => $ENV{QUERY_STRING},
params => {
original => \%params,
checked => events::check_params( $config, $request_parameters, $settings ),
},
};
my $sourceEvents = events::get( $config, $request, $settings );
#return events by date
my $eventsByDate = {};
for my $source (@$sourceEvents) {
$source->{calcms_start} = $source->{start};
my $key = substr( $source->{start}, 0, 10 );
push @{ $eventsByDate->{$key} }, $source;
}
return $eventsByDate;
}
sub mapToSchema {
my $event = shift;
#override settings by source map filter
for my $key ( keys %{ get('mapping') } ) {
$event->{$key} = get('mapping')->{$key};
}
#resolve variables set in mapped values
for my $mkey ( keys %{ get('mapping') } ) {
for my $key ( keys %{$event} ) {
my $val = $event->{$key};
$val = $event->{$key} if ( $mkey eq $key );
$event->{$mkey} =~ s/<TMPL_VAR $key>/$val/g;
}
}
return $event;
}
#do not delete last line
1;

View File

@@ -1,75 +0,0 @@
package Common;
use warnings;
use strict;
use Fcntl ':flock';
use base 'Exporter';
our @EXPORT_OK = ( 'info', 'error' );
sub checkSingleInstance() {
open my $self, '<', $0 or die "Couldn't open self: $!";
flock $self, LOCK_EX | LOCK_NB or die "This script $0 is already running";
}
sub loadFile($) {
my $filename = shift;
my $content = '';
open my $file, '<', $filename || die("cannot load $filename");
while (<$file>) {
$content .= $_;
}
close $file;
return $content;
}
sub saveFile($$) {
my $filename = shift;
my $content = shift;
open my $file, ">:utf8", $filename || die("cannot write $filename");
print $file $content;
close $file;
}
sub getModifiedAt {
my $file = shift;
my @stats = stat $file;
return 0 if scalar @stats == 0;
my $modifiedAt = $stats[9];
return $modifiedAt;
}
sub execute($) {
my $command = shift;
print "EXEC:\t$command\n";
my $result = `$command`;
my $exitCode = ( $? >> 8 );
print "ERROR! exitCode=$?\n" if $exitCode > 0;
return ( $exitCode, $result );
}
my $debug = 0;
sub debug($$) {
my $level = shift;
my $message = shift;
print $message. "\n" if $debug > $level;
}
sub error ($) {
print "\nERROR: $_[0]\nsee $0 --help for help";
exit 1;
}
sub info ($) {
my $message = shift;
if ( $message =~ /^\n/ ) {
$message =~ s/^\n//g;
print "\n";
}
print "INFO:\t$message\n";
}
return 1;

View File

@@ -1,197 +0,0 @@
package GoogleCalendar;
use strict;
use warnings;
use Data::Dumper;
use lib '../calcms/';
use Common ( 'info', 'error' );
use GoogleCalendarApi();
use time();
my $settings = {};
my $cal = undef;
my $debug = 1;
sub set($$) {
my $key = shift;
my $value = shift;
$settings->{$key} = $value;
}
sub get($) {
my $key = shift;
return $settings->{$key};
}
sub init($) {
$settings = shift || {};
my $access = get('access');
# 1. create service account at https://console.developers.google.com/
# 2. enable Calendar API
# 3. share calendar with service account for update permissions
# see http://search.cpan.org/~shigeta/Google-API-Client-0.13/lib/Google/API/Client.pm
my $serviceAccount = $access->{serviceAccount};
my $serviceAccountKeyFile = $access->{serviceAccountKeyFile};
my $calendarId = $access->{calendarId};
my $serviceAccountKey = Common::loadFile($serviceAccountKeyFile);
my $calendar = GoogleCalendarApi->new(
{
'serviceAccount' => $serviceAccount,
'privateKey' => $serviceAccountKey,
'calendarId' => $calendarId,
'debug' => 0
}
);
$cal = $calendar;
}
#map event schema to target schema
sub mapToSchema {
my $event = shift;
#clone event
my $targetEvent = {};
for my $key ( keys %{$event} ) {
$targetEvent->{$key} = $event->{$key};
}
if ( defined $event->{recurrence} && ref( $event->{recurrence} ) eq 'HASH' ) {
$targetEvent->{reference} .= '[' . $event->{recurrence}->{number} . ']' if ( $event->{recurrence}->{number} > 0 );
$targetEvent->{recurrence} = $event->{recurrence}->{number} + 0;
}
$targetEvent->{rating} = 0;
$targetEvent->{visibility} = 0;
#set project by project's date range
my $projects = get('projects');
if ( ref($projects) eq 'HASH' ) {
for my $projectName ( keys %$projects ) {
my $project = get('projects')->{$projectName};
my $start = substr( $event->{start}, 0, 10 );
if ( $start ge $project->{start_date} && $start le $project->{end_date} ) {
$targetEvent->{project} = $project->{name};
}
}
}
#override settings by target map filter
for my $key ( keys %{ get('mapping') } ) {
$targetEvent->{$key} = get('mapping')->{$key};
}
#resolve variables set in mapped values
for my $mkey ( keys %{ get('mapping') } ) {
for my $key ( sort keys %{$targetEvent} ) {
my $val = $targetEvent->{$key};
$val = $event->{$key} if $mkey eq $key;
$targetEvent->{$mkey} =~ s/<TMPL_VAR $key>/$val/g;
}
}
$targetEvent->{title} =~ s/\s+$//g;
$targetEvent->{title} =~ s/\s*\#$//g;
$targetEvent->{title} =~ s/\s*\-\s*$//g;
my $schema = { event => $targetEvent };
return $schema;
}
#this is done before sync and allows to delete old events before adding new
sub getEvents {
my $event = shift;
return undef if get('date')->{'time_zone'} eq '';
return undef if $event->{start} eq '';
return undef if $event->{end} eq '';
#delete a span of dates
my $timeZone = get('date')->{'time_zone'};
my $start = time::get_datetime( $event->{start}, $timeZone );
my $end = time::get_datetime( $event->{end}, $timeZone );
info( "search target for events from " . $start . " to " . $end );
#search datetime with same timezone
my $events = $cal->getEvents(
{
timeMin => $cal->getDateTime( $start->datetime, $timeZone ),
timeMax => $cal->getDateTime( $end->datetime, $timeZone ),
maxResults => 50,
singleEvents => 'true',
orderBy => 'startTime'
}
);
return $events;
}
# insert a new event
sub insertEvent {
my $event = shift;
my $entity = $event->{event};
$entity->{'html_content'} = markup::creole_to_html( $entity->{'content'} );
my $timeZone = get('date')->{'time_zone'};
my $start = $cal->getDateTime( $entity->{start}, $timeZone );
my $end = $cal->getDateTime( $entity->{end}, $timeZone );
#info "insert event\t$start\t$entity->{title}";
my $entry = {
start => $start,
end => $end,
summary => $entity->{title},
description => $entity->{content},
location => $entity->{location},
transparency => 'transparent',
status => 'confirmed'
};
my $result = $cal->insertEvent($entry);
my $id = $result->{id};
}
sub deleteEvent {
my $event = shift;
#info "delete event";
$cal->deleteEvent( $event->{id} );
}
sub fixFields {
my $event = shift;
#lower case for upper case titles longer than 4 characters
for my $attr ( 'series_name', 'title' ) {
my $val = $event->{$attr};
my $c = 0;
while ( $val =~ /\b([A-Z]{5,99})\b/ && $c < 10 ) {
my $word = $1;
my $lower = lc $word;
$lower =~ s/^([a-z])/\u$1/gi;
$val =~ s/$word/$lower/g;
$c++;
}
$event->{$attr} = $val if $event->{$attr} ne $val;
}
for my $attr ( 'series_name', 'title', 'excerpt', 'content' ) {
my $val = $event->{$attr};
$val =~ s/^\s*(.*?)\s*$/$1/g;
$val =~ s/^[ \t]/ /g;
$event->{$attr} = $val if $event->{$attr} ne $val;
}
return $event;
}
#do not delete last line
1;

View File

@@ -1,250 +0,0 @@
package GoogleCalendarApi;
use strict;
use warnings;
use JSON;
use JSON::WebToken;
use LWP::UserAgent;
use HTML::Entities;
use URI::Escape;
use Data::Dumper;
use DateTime;
use Time::HiRes qw(sleep);
use Common ( 'info', 'error' );
sub new {
my $class = shift;
my $params = shift;
#print Dumper($class);
my $self = {};
for my $attr ( 'calendarId', 'debug' ) {
$self->{$attr} = $params->{$attr} if defined $params->{$attr};
}
$self->{debug} = 1;
my $instance = bless $self, $class;
if ( ( defined $params->{serviceAccount} ) && ( defined $params->{privateKey} ) ) {
$instance->login( $params->{serviceAccount}, $params->{privateKey} );
}
return $instance;
}
sub setCalendar {
my $self = shift;
my $calendarId = shift;
$self->{calendarId} = $calendarId;
}
sub getBasicUrl {
my $self = shift;
return 'https://www.googleapis.com/calendar/v3/calendars/' . encode_entities( $self->{calendarId} );
}
#https://developers.google.com/google-apps/calendar/v3/reference/events/list
#returns {
# 'timeZone' => 'Europe/Berlin',
# 'description' => "Radioprogramm von Pi Radio f\x{fc}r 88vier.de",
# 'defaultReminders' => [],
# 'accessRole' => 'owner',
# 'etag' => '"1415821582086000"',
# 'kind' => 'calendar#events',
# 'summary' => '88vier.de Pi Radio (Programm)',
# 'updated' => '2014-11-12T19:46:22.086Z',
# 'items' => [...]
# }
sub getEvents {
my $self = shift;
my $params = shift;
my $url = '/events?';
for my $param (
'iCalUID', 'alwaysIncludeEmail', 'maxAttendees', 'maxResults',
'orderBy', 'pageToken', 'privateExtendedProperty', 'q',
'sharedExtendedProperty', 'showDeleted', 'showHiddenInvitations', 'singleEvents',
'syncToken', 'timeZone'
)
{
$url .= '&' . $param . '=' . uri_escape( $params->{$param} ) if defined $params->{$param};
}
for my $param ( 'timeMin', 'timeMax', 'updatedMin' ) {
$url .= '&' . $param . '=' . uri_escape( $self->formatDateTime( $params->{$param} ) ) if defined $params->{$param};
}
my $result = $self->httpRequest( 'GET', $url );
return $result;
}
# sleep 0.25 seconds to prevent hitting the 5.0 requests/second/user rate
#sub sleep{
# my $this=shift;
# my $duration=shift;
# $duration=1 unless defined $duration;
# select(undef, undef, undef, $duration);
#}
#https://developers.google.com/google-apps/calendar/v3/reference/events/delete
sub deleteEvent {
my $self = shift;
my $eventId = shift;
my $url = '/events/' . $eventId;
#DELETE https://www.googleapis.com/calendar/v3/calendars/calendarId/events/eventId
my $result = $self->httpRequest( 'DELETE', $url );
#$self->sleep();
return $result;
}
#https://developers.google.com/google-apps/calendar/v3/reference/events/insert
sub insertEvent {
my $self = shift;
my $params = shift;
my $event = {
start => {
dateTime => $self->formatDateTime( $params->{start} )
},
end => {
dateTime => $self->formatDateTime( $params->{end} )
},
summary => $params->{summary} || '',
description => $params->{description} || '',
location => $params->{location} || '',
status => $params->{confirmed} || 'confirmed'
};
$event = encode_json $event;
#POST https://www.googleapis.com/calendar/v3/calendars/calendarId/events
my $url = '/events';
my $result = $self->httpRequest( 'POST', $url, $event );
#$self->sleep();
return $result;
}
# send a HTTP request
sub httpRequest {
my $self = shift;
my $method = shift;
my $url = shift;
my $content = shift || '';
sleep 0.3;
print STDERR "$method " . $url . "\n" if $self->{debug};
die("missing url") unless defined $url;
die("calendarId not set") unless defined $self->{calendarId};
die("not logged in ") unless defined $self->{api};
#prepend basic url including calendar id
$url = $self->getBasicUrl() . $url;
print STDERR "$method " . $url . "\n" if $self->{debug};
my $response = undef;
if ( $method eq 'GET' ) {
$response = $self->{api}->get($url);
} elsif ( ( $method eq 'POST' ) || ( $method eq 'PUT' ) ) {
#return;
print STDERR $content . "\n" if $self->{debug};
my $request = HTTP::Request->new( $method, $url );
$request->header( 'Content-Type' => 'application/json' );
$request->content($content);
$response = $self->{api}->request($request);
} elsif ( $method eq 'DELETE' ) {
#return;
$response = $self->{api}->delete($url);
}
if ( $response->is_success ) {
my $content = $response->content;
return {} if $content eq '';
return decode_json($content);
} else {
print "ERROR:\n";
print "Code: " . $response->code . "\n";
print "Message: " . $response->message . "\n";
print $response->content . "\n";
die;
}
}
# write datetime object to string
sub formatDateTime {
my $self = shift;
my $dt = shift;
my $datetime = $dt->format_cldr("yyyy-MM-ddTHH:mm:ssZZZZZ");
print STDERR "$dt -> $datetime\n" if $self->{debug};
return $datetime;
}
# parse datetime from string to object
sub getDateTime {
my $self = shift;
my $datetime = shift;
my $timezone = shift;
return if ( !defined $datetime ) or ( $datetime eq '' );
my @l = split /[\-\;T\s\:\+\.]/, $datetime;
$datetime = DateTime->new(
year => $l[0],
month => $l[1],
day => $l[2],
hour => $l[3],
minute => $l[4],
second => $l[5],
time_zone => $timezone
);
return $datetime;
}
# login with serviceAccount and webToken (from privateKey)
sub login {
my $self = shift;
my $serviceAccount = shift;
my $privateKey = shift;
# https://developers.google.com/accounts/docs/OAuth2ServiceAccount
my $time = time;
#create JSON Web Token
my $jwt = JSON::WebToken->encode(
{
iss => $serviceAccount,
scope => 'https://www.googleapis.com/auth/calendar',
aud => 'https://accounts.google.com/o/oauth2/token',
exp => $time + 3600,
iat => $time,
},
$privateKey,
'RS256',
{ typ => 'JWT' }
);
#send JSON web token to authentication service
$self->{auth} = LWP::UserAgent->new();
my $response = $self->{auth}->post(
'https://accounts.google.com/o/oauth2/token',
{
grant_type => encode_entities('urn:ietf:params:oauth:grant-type:jwt-bearer'),
assertion => $jwt
}
);
die( $response->code, "\n", $response->content, "\n" ) unless $response->is_success();
my $data = decode_json( $response->content );
#create a new user agent and set token to bearer
$self->{api} = LWP::UserAgent->new();
$self->{api}->default_header( Authorization => 'Bearer ' . $data->{access_token} );
print STDERR "login successful\n" if $self->{debug};
return $data;
}
1;

View File

@@ -1,81 +0,0 @@
#! /usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use FindBin;
use lib "$FindBin::Bin/lib";
use lib "$FindBin::Bin/../calcms";
use Common ( 'info', 'error' );
use config();
use time();
use log();
$| = 1;
sub runJobs {
my $jobs = shift;
my $startDir = shift;
my $logDir = shift;
for my $job (@$jobs) {
my $startFile = $startDir . '/' . $job->{name} . '.start.txt';
my $startAge = Common::getModifiedAt($startFile);
next if $startAge == 0;
my $logFile = $logDir . '/' . $job->{name} . '.log';
my $logAge = Common::getModifiedAt($logFile);
next if $startAge < $logAge;
# read parameters form start file
my $content = log::load_file($startFile);
#execute command
my $command = $job->{command} . ' 2>&1 > ' . $logFile;
my ( $exitCode, $result ) = Common::execute($command);
error "exitCode=$exitCode on $command" if $exitCode != 0;
}
}
sub check() {
my $configFile = shift @ARGV;
error qq{cannot read $configFile "$configFile"} unless -e $configFile;
my $config = config::get($configFile);
my $startDir = $config->{start_dir} || '';
error 'missing configuration of jobs/start_dir!' if $startDir eq '';
error "job dir does not exist '$startDir'" unless -e $startDir;
error "cannot read from job dir '$startDir'. Please check permissions!" unless -w $startDir;
my $logDir = $config->{log_dir} || '';
error 'missing configuration of jobs/log_dir' if $logDir eq '';
error "job log dir does not exist '$logDir'" unless -e $logDir;
error "cannot read from job log dir '$logDir'. Please check permissions!" unless -r $logDir;
error "cannot write to job log dir '$logDir'. Please check permissions!" unless -w $logDir;
my $jobs = $config->{job};
error "no jobs defined!" if scalar @$jobs == 0;
return ( $jobs, $startDir, $logDir );
}
sub main() {
info "INIT\t" . time::time_to_datetime();
Common::checkSingleInstance();
my ( $jobs, $startDir, $logDir ) = check();
#exit after a at most 10 minute timeout in case of hanging process
local $SIG{ALRM} = sub { die "ERROR: exit due to synchronization hangs\n" };
alarm 10 * 60;
runJobs( $jobs, $startDir, $logDir );
info "DONE\t" . time::time_to_datetime();
}
main();

View File

@@ -1,292 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;
use Config::General;
use DateTime;
use DateTime::Duration;
use IO::Socket::INET;
use Fcntl ':flock';
use FindBin;
use lib "$FindBin::Bin/lib";
use lib "$FindBin::Bin/../../calcms";
use Common ( 'info', 'error' );
use GoogleCalendar;
use CalcmsEvents;
Common::checkSingleInstance();
BEGIN {
$ENV{LANG} = "en_US.UTF-8";
}
$| = 1;
my $sourceConfigFile = '';
my $targetConfigFile = '';
my $debug = 1;
my $from = undef;
my $till = undef;
GetOptions(
"from=s" => \$from,
"till=s" => \$till,
"source=s" => \$sourceConfigFile,
"target=s" => \$targetConfigFile,
);
#source and taget settings are loaded from config files
my $settings = {};
error "set one of folling parameters: --from, --till" unless $from || $till;
init();
sync();
info "$0 done.";
exit 0;
#sync all events, splitting multi-day-requests into multiple 1-day-requests to avoid large result sets
sub sync {
my $timeZone = CalcmsEvents::get('date')->{time_zone};
my $from = CalcmsEvents::get('start_min');
my $till = CalcmsEvents::get('start_max');
info "sync from $from till $till at $timeZone";
#prepare target
info "last update: " . ( CalcmsEvents::get('last_update') || '' );
if ( my $days = CalcmsEvents::splitRequest( $from, $till, $timeZone ) ) {
for my $date (@$days) {
syncTimespan( $date->{from}, $date->{till} );
}
} else {
syncTimespan( $from, $till );
}
info "\nset last-update time: $settings->{event}->{update_start}";
setLastUpdateTime( $sourceConfigFile, $targetConfigFile, $settings->{event}->{update_start} );
}
#sync all events of a given source timespan
sub syncTimespan {
my $from = shift;
my $till = shift;
#get a list of all days and their events
my $sourceEvents = CalcmsEvents::getEvents( $from, $till );
my @dates = keys %$sourceEvents;
if ( scalar @dates == 0 ) {
info "\nno entries found.";
return;
}
#sort lists of date and time (same time events should be preserved)
for my $date ( sort { $a cmp $b } @dates ) {
syncEvents( $sourceEvents->{$date} );
}
}
#syncronize a list of source events to target events
sub syncEvents($) {
my $sourceEvents = shift;
my @sourceEvents = sort { $a->{calcms_start} cmp $b->{calcms_start} } @$sourceEvents;
$sourceEvents = \@sourceEvents;
my $start = $sourceEvents->[0]->{start};
my $end = $sourceEvents->[-1]->{end};
my $targetEvents = GoogleCalendar::getEvents(
{
start => $start,
end => $end
}
);
$targetEvents = $targetEvents->{items};
info "google:" . scalar(@$targetEvents) . " vs " . scalar(@$sourceEvents);
# mark all known target events
my $targetEventsByKey = {};
for my $event (@$targetEvents) {
#print Dumper($event);
next if $event->{status} eq 'canceled';
my $key = getGoogleEventToString($event);
$targetEventsByKey->{$key} = $event;
}
# mark all knwon source events
my $sourceEventsByKey = {};
for my $event (@$sourceEvents) {
$event = CalcmsEvents::mapToSchema($event);
$event = GoogleCalendar::mapToSchema($event);
my $key = getCalcmsEventToString($event);
$sourceEventsByKey->{$key} = $event;
}
# delete target entries without matching source entries
for my $key ( keys %$targetEventsByKey ) {
next if defined $sourceEventsByKey->{$key};
my $event = $targetEventsByKey->{$key};
info "delete $key ";
print Dumper($event);
GoogleCalendar::deleteEvent($event);
}
# insert source entries without matching target entries
for my $key ( keys %$sourceEventsByKey ) {
if ( defined $targetEventsByKey->{$key} ) {
info "$key is up to date";
next;
}
my $event = $sourceEventsByKey->{$key};
info "insert $key";
GoogleCalendar::insertEvent($event);
}
}
sub getGoogleEventToString {
my $event = shift;
my $result = "\n";
$result .= "start: " . substr( $event->{start}->{dateTime}, 0, 19 ) . "\n";
$result .= "end : " . substr( $event->{end}->{dateTime}, 0, 19 ) . "\n";
$result .= "title: $event->{summary}\n";
$result .= "desc : $event->{description}\n";
return $result;
}
sub getCalcmsEventToString {
my $event = shift;
my $result = "\n";
$result .= "start: " . substr( $event->{event}->{start_datetime}, 0, 19 ) . "\n";
$result .= "end : " . substr( $event->{event}->{end_datetime}, 0, 19 ) . "\n";
$result .= "title: $event->{event}->{title}\n";
$result .= "desc : $event->{event}->{content}\n";
return $result;
}
#import requested source and target libs
sub init {
binmode STDOUT, ":utf8";
{
#require target config file
error "missing target parameter!" unless $targetConfigFile =~ /\S/;
error "target file: '$targetConfigFile' does not exist" unless -e $targetConfigFile;
error "cannot read target file: '$targetConfigFile'" unless -r $targetConfigFile;
my $config = new Config::General($targetConfigFile);
$config = $config->{DefaultConfig}->{target};
GoogleCalendar::init($config);
}
{
#require source config file
error "missing source parameter!" unless $sourceConfigFile =~ /\S/;
error "source file: '$sourceConfigFile' does not exist" unless -e $sourceConfigFile;
error "cannot read source file: '$sourceConfigFile'" unless -r $sourceConfigFile;
my $config = new Config::General($sourceConfigFile);
$config = $config->{DefaultConfig}->{source};
$config->{last_update} = getLastUpdateTime( $sourceConfigFile, $targetConfigFile );
CalcmsEvents::init($config);
}
$from .= 'T00:00' if $from =~ /^\d\d\d\d\-\d\d\-\d\d$/;
$till .= 'T23:59' if $till =~ /^\d\d\d\d\-\d\d\-\d\d$/;
if ( $from =~ /^([-+]?\d+$)/ ) {
my $days = $1;
my $duration = new DateTime::Duration( days => $days );
$from = DateTime->today->add_duration($duration);
}
if ( $till =~ /^([-+]?\d+$)/ ) {
my $days = $1 + 1;
my $duration = new DateTime::Duration( days => $days );
$till = DateTime->today->add_duration($duration);
}
CalcmsEvents::set( 'start_min', $from ) if defined $from;
CalcmsEvents::set( 'start_max', $till ) if defined $till;
my $now = time();
$now = time::time_to_datetime($now);
$settings->{event} = {
update_start => time::time_to_datetime( time() ),
modified_at => $now,
};
}
#output usage on error or --help parameter
sub usage {
print qq{
update all/modified events from source at target.
USAGE: sync_cms.pl [--read,--update] [--modified,--all] --source s --target t
on using --from and --till requests will be processed as multiple single-day-requests.
parameters:
--read show all events without updating database
--update update target database with source events
--source source configuration file
--target target configuration file
--from start of date range: datetime (YYYY-MM-DDTHH:MM::SS) or days from today (e.g. -1 for yesterday, +1 for tomorrow)
--till end of date range: datetime (YYYY-MM-DDTHH:MM::SS) or days from today (e.g. -1 for yesterday, +1 for tomorrow)
examples:
update modified
perl sync_cms.pl --update --source=config/source/program.cfg --target=config/target/calcms.cfg
update a given time range
perl sync_cms.pl --update --all --from=2009-09-01T00:00:00 --till=2009-11-22T23:59:59 --source=config/source/program.cfg --target=config/target/calcms.cfg
update from last 2 days until next 3 days
perl sync_cms.pl --update --from=-2 --till=+3 --source=config/source/program.cfg --target=config/target/calcms.cfg
};
exit 1;
}
#load last update time out of sync.data
sub getLastUpdateTime {
my $source = shift;
my $target = shift;
my $date = undef;
return undef unless -r "sync.data";
my $content = Common::loadFile("sync.data");
if ( $content =~ /$source\s+\->\s+$target\s+:\s+(\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2})/ ) {
$date = $1;
}
return $date;
}
#save last update time to sync.data
sub setLastUpdateTime {
my $source = shift;
my $target = shift;
my $date = shift;
my $data = '';
if ( -r "sync.data" ) {
$data = Common::loadFile("sync.data");
}
if ( $data =~ /$source\s+\->\s+$target\s+:\s+(\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2})/ ) {
$data =~ s/($source\s+\->\s+$target\s+:)\s+\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}/$1\t$date/gi;
} else {
$data .= "$source\t\->\t$target\t:\t$date\n";
}
$data =~ s/[\r\n]+/\n/g;
Common::saveFile( "sync.data", $data );
}

View File

@@ -1,13 +0,0 @@
#!/bin/sh
from=$1
till=$2
project=$3
export LC_ALL="de_DE.utf8"
export LANGUAGE="de_DE.utf8"
set -x
cd /home/radio/calcms/sync_cms
nice -n 10 perl sync_cms.pl --from=$from --till=$till --source=config/source/calcms_$project.cfg --target=config/target/88vier_$project.cfg 2>&1

View File

@@ -1,7 +0,0 @@
#/bin/sh
./sync_project.sh "$1" "$2" piradio
./sync_project.sh "$1" "$2" potsdam
./sync_project.sh "$1" "$2" ansage
./sync_project.sh "$1" "$2" collabo
./sync_project.sh "$1" "$2" frb

View File

@@ -1,6 +0,0 @@
#!/bin/sh
file=/home/radio/piradio.de/agenda/admin/jobs/start/ansage_to_88vier.de.start.txt
touch $file
chown radio:www-data $file

View File

@@ -1,6 +0,0 @@
#!/bin/sh
file=/home/radio/piradio.de/agenda/admin/jobs/start/colabo_to_88vier.de.start.txt
touch $file
chown radio:www-data $file

View File

@@ -1,6 +0,0 @@
#!/bin/sh
file=/home/radio/piradio.de/agenda/admin/jobs/start/frb_to_88vier.de.start.txt
touch $file
chown radio:www-data $file

View File

@@ -1,6 +0,0 @@
#!/bin/sh
file=/home/radio/piradio.de/agenda/admin/jobs/start/piradio_to_88vier.de.start.txt
touch $file
chown radio:www-data $file

View File

@@ -1,6 +0,0 @@
#!/bin/sh
file=/home/radio/piradio.de/agenda/admin/jobs/start/potsdam_to_88vier.de.start.txt
touch $file
chown radio:www-data $file