remove sync_cms
sync from google calendar is not used anymore
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user