Move Calendar feeds into the Calendar Asset table as JSON collateral.
Update tests and workflows to follow.
This commit is contained in:
parent
bfd25d6de2
commit
22d462166f
5 changed files with 425 additions and 309 deletions
|
|
@ -1,4 +1,5 @@
|
|||
7.7.19
|
||||
- fixed #10833: Calendar feeds not versioned, not duplicated
|
||||
- fixed #10831: Graphing tab in Poll is not i18n'ed
|
||||
- fixed #10829: Extra field in Poll Property tab
|
||||
- refactored out JSON collateral module, to use with any module in WebGUI.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ use Getopt::Long;
|
|||
use WebGUI::Session;
|
||||
use WebGUI::Storage;
|
||||
use WebGUI::Asset;
|
||||
use WebGUI::Asset::Wobject::Calendar;
|
||||
use JSON;
|
||||
|
||||
|
||||
my $toVersion = '7.7.19';
|
||||
|
|
@ -33,6 +35,7 @@ my $session = start(); # this line required
|
|||
# upgrade functions go here
|
||||
addInboxSmsNotificationTemplateIdSetting($session);
|
||||
upgradeJSONDatabaseFields($session);
|
||||
moveCalendarFeedsToJSON($session);
|
||||
finish($session); # this line required
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
@ -92,6 +95,30 @@ sub upgradeJSONDatabaseFields {
|
|||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
sub moveCalendarFeedsToJSON {
|
||||
my $session = shift;
|
||||
print "\tMoveing Calendar feeds from database collateral to JSON... " unless $quiet;
|
||||
$session->db->write(q|ALTER TABLE Calendar ADD COLUMN icalFeeds LONGTEXT|);
|
||||
my $getCalendar = WebGUI::Asset::Wobject::Calendar->getIsa($session);
|
||||
while (my $calendar = $getCalendar->()) {
|
||||
my $feeds = $session->db->buildHashRefOfHashRefs(
|
||||
"select * from Calendar_feeds where assetId=?",
|
||||
[$calendar->getId],
|
||||
"feedId"
|
||||
);
|
||||
foreach my $feedParams (values %{ $feeds }) {
|
||||
delete $feedParams->{assetId};
|
||||
$calendar->addFeed($feedParams);
|
||||
}
|
||||
##Copy the JSON across all the revisions of this Calendar.
|
||||
my $jsonFeeds = $session->db->quickScalar('select icalFeeds from Calendar where assetId=? and revisionDate=?', [ $calendar->getId, $calendar->get('revisionDate')]);
|
||||
$session->db->write('update Calendar set icalFeeds=? where assetId=?', [$jsonFeeds, $calendar->getId]);
|
||||
}
|
||||
$session->db->write(q|DROP TABLE Calendar_feeds|);
|
||||
|
||||
print "DONE!\n" unless $quiet;
|
||||
}
|
||||
|
||||
# -------------- DO NOT EDIT BELOW THIS LINE --------------------------------
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ use WebGUI::Search;
|
|||
use WebGUI::Form;
|
||||
use WebGUI::HTML;
|
||||
use WebGUI::DateTime;
|
||||
use Class::C3;
|
||||
|
||||
use base 'WebGUI::Asset::Wobject';
|
||||
use base qw/WebGUI::Asset::Wobject WebGUI::JSONCollateral/;
|
||||
|
||||
use DateTime;
|
||||
use JSON;
|
||||
|
|
@ -255,6 +256,14 @@ sub definition {
|
|||
unitsAvailable => [ qw( days weeks months years ) ],
|
||||
},
|
||||
|
||||
icalFeeds => {
|
||||
fieldType => "textarea",
|
||||
defaultValue => [],
|
||||
serialize => 1,
|
||||
noFormPost => 1,
|
||||
tab => "display",
|
||||
},
|
||||
|
||||
icalInterval => {
|
||||
fieldType => "interval",
|
||||
defaultValue => $session->datetime->intervalToSeconds( 3, 'months' ),
|
||||
|
|
@ -309,6 +318,45 @@ sub addChild {
|
|||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 addFeed ( $feedParams )
|
||||
|
||||
Adds a new Feed to this calendar. This is a wrapper around WebGUI::JSONCollateral's setJSONCollateral
|
||||
method.
|
||||
|
||||
=head3 $feedParams
|
||||
|
||||
A hashref of parameters that describe the feed.
|
||||
|
||||
=head4 feedId
|
||||
|
||||
GUID for this feed.
|
||||
|
||||
=head4 url
|
||||
|
||||
URL for this feed.
|
||||
|
||||
=head4 lastUpdated
|
||||
|
||||
The date this feed was added, or edited last.
|
||||
|
||||
=head4 lastResult
|
||||
|
||||
The results of what happened the last time this feed was accessed to pull iCal.
|
||||
|
||||
=head4 feedType
|
||||
|
||||
What kind of feed this is.
|
||||
|
||||
=cut
|
||||
|
||||
sub addFeed {
|
||||
my $self = shift;
|
||||
my $feedParams = shift;
|
||||
return $self->setJSONCollateral('icalFeeds', 'feedId', 'new', $feedParams);
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 appendTemplateVarsDateTime( var, datetime [, prefix ] )
|
||||
|
||||
Append template vars from the given datetime. C<var> is a hash reference.
|
||||
|
|
@ -460,6 +508,25 @@ sub createSubscriptionGroup {
|
|||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 deleteFeed ( $feedId )
|
||||
|
||||
Deletes a Feed from this calendar. This is a wrapper around WebGUI::JSONCollateral's deleteJSONCollateral
|
||||
method.
|
||||
|
||||
=head3 $feedId
|
||||
|
||||
GUID of the feed to delete.
|
||||
|
||||
=cut
|
||||
|
||||
sub deleteFeed {
|
||||
my $self = shift;
|
||||
my $feedId = shift;
|
||||
return $self->deleteJSONCollateral('icalFeeds', 'feedId', $feedId);
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 getEditForm
|
||||
|
||||
Adds an additional tab for feeds.
|
||||
|
|
@ -613,9 +680,9 @@ ENDHTML
|
|||
# Add the existing feeds
|
||||
my $feeds = $self->getFeeds();
|
||||
$tab->raw('<script type="text/javascript">'."\n");
|
||||
for my $feedId (keys %$feeds) {
|
||||
my %row = %{ $feeds->{ $feedId } };
|
||||
$tab->raw("FeedsManager.addFeed('feeds','".$feedId."',".JSON->new->encode( \%row ).");\n");
|
||||
for my $feed (@{ $feeds }) {
|
||||
my $feedId = $feed->{feedId};
|
||||
$tab->raw("FeedsManager.addFeed('feeds','".$feedId."',".JSON->new->encode( $feed ).");\n");
|
||||
}
|
||||
$tab->raw('</script>');
|
||||
|
||||
|
|
@ -779,9 +846,28 @@ sub getEventVars {
|
|||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 getFeed ( $feedId )
|
||||
|
||||
Gets the data structure for one particular feed from this Calendar. This is a wrapper
|
||||
for getJSONCollateral.
|
||||
|
||||
=head3 $feedId
|
||||
|
||||
The GUID of the feed to fetch.
|
||||
|
||||
=cut
|
||||
|
||||
sub getFeed {
|
||||
my $self = shift;
|
||||
my $feedId = shift;
|
||||
return $self->getJSONCollateral('icalFeeds', 'feedId', $feedId);
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 getFeeds ( )
|
||||
|
||||
Gets a hashref of hashrefs of all the feeds attached to this calendar.
|
||||
Gets an arrayref of hashrefs of all the feeds attached to this calendar.
|
||||
|
||||
TODO: Format lastUpdated into the user's time zone
|
||||
|
||||
|
|
@ -789,12 +875,7 @@ TODO: Format lastUpdated into the user's time zone
|
|||
|
||||
sub getFeeds {
|
||||
my $self = shift;
|
||||
|
||||
return $self->session->db->buildHashRefOfHashRefs(
|
||||
"select * from Calendar_feeds where assetId=?",
|
||||
[$self->get("assetId")],
|
||||
"feedId"
|
||||
);
|
||||
return $self->get('icalFeeds');
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
@ -952,28 +1033,21 @@ sub processPropertiesFromFormPost {
|
|||
my @feedsFromForm = keys %feeds;
|
||||
|
||||
# Delete old feeds that are not in @feeds
|
||||
my @oldFeeds
|
||||
= $session->db->buildArray(
|
||||
"select feedId from Calendar_feeds where assetId=?",
|
||||
[$self->get("assetId")]
|
||||
);
|
||||
my @oldFeeds = map { $_->{feedId} } @{ $self->getFeeds };
|
||||
|
||||
for my $feedId (@oldFeeds) {
|
||||
if (!grep /^$feedId$/, @feedsFromForm) {
|
||||
$session->db->write(
|
||||
"delete from Calendar_feeds where feedId=? and assetId=?",
|
||||
[$feedId,$self->get("assetId")]
|
||||
);
|
||||
if (!isIn($feedId, @feedsFromForm)) {
|
||||
$self->deleteFeed($feedId);
|
||||
}
|
||||
}
|
||||
|
||||
# Create new feeds
|
||||
for my $feedId (grep /^new(\d+)/, @feedsFromForm) {
|
||||
$session->db->setRow("Calendar_feeds","feedId",{
|
||||
feedId => "new",
|
||||
assetId => $self->get("assetId"),
|
||||
$self->addFeed({
|
||||
url => $form->param("feeds-".$feedId),
|
||||
feedType => "ical",
|
||||
lastUpdated => 'never',
|
||||
lastResult => '',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -983,18 +1057,26 @@ sub processPropertiesFromFormPost {
|
|||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
=head2 purge ( )
|
||||
=head2 setFeed ( $feedId, $feedParams )
|
||||
|
||||
Handle Asset specific purge tasks.
|
||||
Adds a new Feed to this calendar. This is a wrapper around WebGUI::JSONCollateral's setJSONCollateral
|
||||
method.
|
||||
|
||||
Delete iCal feeds for this Calendar.
|
||||
=head3 $feedId
|
||||
|
||||
The GUID of the feed to update.
|
||||
|
||||
=head3 $feedParams
|
||||
|
||||
See L<addFeed> for a list of parameters.
|
||||
|
||||
=cut
|
||||
|
||||
sub purge {
|
||||
my $self = shift;
|
||||
$self->session->db->write('delete from Calendar_feeds where assetId=?',[$self->get('assetId')]);
|
||||
$self->SUPER::purge;
|
||||
sub setFeed {
|
||||
my $self = shift;
|
||||
my $feedId = shift;
|
||||
my $feedParams = shift;
|
||||
return $self->setJSONCollateral('icalFeeds', 'feedId', $feedId, $feedParams);
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use WebGUI::Asset::Wobject::Calendar;
|
|||
use WebGUI::Asset::Event;
|
||||
use WebGUI::DateTime;
|
||||
use DateTime::TimeZone;
|
||||
use Data::Dumper;
|
||||
|
||||
use LWP::UserAgent;
|
||||
use JSON ();
|
||||
|
|
@ -92,284 +93,286 @@ sub execute {
|
|||
my $feedList;
|
||||
if ($instance->getScratch('events')) {
|
||||
$eventList = JSON::from_json($instance->getScratch('events'));
|
||||
$feedList = JSON::from_json($instance->getScratch('feeds'));
|
||||
$feedList = JSON::from_json($instance->getScratch('feeds'));
|
||||
}
|
||||
else {
|
||||
my $ua = LWP::UserAgent->new(agent => "WebGUI");
|
||||
my $sth = $self->session->db->read("select * from Calendar_feeds");
|
||||
my $getCalendar = WebGUI::Asset::Wobject::Calendar->getIsa($session);
|
||||
|
||||
FEED: while (my $feed = $sth->hashRef) {
|
||||
my $calendar = WebGUI::Asset->newByDynamicClass($self->session,$feed->{assetId});
|
||||
if (!defined $calendar) {
|
||||
$self->session->errorHandler->error("Calendar object failed to instanciate. Did you commit the calendar wobject?");
|
||||
next FEED;
|
||||
CALENDAR: while (my $calendar = $getCalendar->()) {
|
||||
my $calendarTitle = $calendar->getTitle;
|
||||
my $calendarId = $calendar->getId;
|
||||
if ( $calendar->get( "state" ) ne "published" ) {
|
||||
$session->log->info( "Calendar $calendarTitle ($calendarId) is not state='published', skipping..." );
|
||||
next CALENDAR;
|
||||
}
|
||||
elsif ( $calendar->get( "state" ) ne "published" ) {
|
||||
$self->session->errorHandler->info( "Calendar is not state='published', skipping..." );
|
||||
next FEED;
|
||||
elsif (! scalar @{ $calendar->getFeeds } ) {
|
||||
$session->log->info( "Calendar $calendarTitle ($calendarId) has no feeds, skipping..." );
|
||||
next CALENDAR;
|
||||
}
|
||||
|
||||
$session->log->info( "Calendar $calendarTitle ($calendarId) has feeds, fetching..." );
|
||||
#!!! KLUDGE - If the feed is on the same server, set a scratch value
|
||||
# I do not know how dangerous this is, so THIS MUST CHANGE!
|
||||
# Preferably: Spectre would add a userSession to the database,
|
||||
# and send the appropriate cookie with the request.
|
||||
my $sitename = $self->session->config->get("sitename")->[0];
|
||||
if ($feed->{url} =~ m{http://[^/]*$sitename})
|
||||
{
|
||||
$feed->{url} .= ( $feed->{url} =~ /[?]/ ? ";" : "?" ) . "adminId=".$session->getId;
|
||||
$self->session->db->write("REPLACE INTO userSessionScratch (sessionId,name,value) VALUES (?,?,?)",
|
||||
[$session->getId,$feed->{assetId},"SPECTRE"]);
|
||||
}
|
||||
#/KLUDGE
|
||||
|
||||
## Somebody point me to a DECENT iCalendar parser...
|
||||
# Text::vFile perhaps?
|
||||
|
||||
# Get the feed
|
||||
my $response = $ua->get($feed->{url});
|
||||
|
||||
if (!$response->is_success) {
|
||||
# Update the result and last updated fields
|
||||
$self->session->db->write("update Calendar_feeds set lastResult=?,lastUpdated=? where feedId=?",
|
||||
[($response->message || $response->content),$dt,$feed->{feedId}]);
|
||||
next FEED;
|
||||
}
|
||||
|
||||
my $data = $response->content;
|
||||
# If doesn't start with BEGIN:VCALENDAR then error
|
||||
unless ($data =~ /^BEGIN:VCALENDAR/i) {
|
||||
# Update the result and last updated fields
|
||||
$self->session->db->write(
|
||||
"update Calendar_feeds set lastResult=?,lastUpdated=? where feedId=?",
|
||||
["Not an iCalendar feed",$dt,$feed->{feedId}]);
|
||||
next FEED;
|
||||
}
|
||||
|
||||
my $active = 0; # Parser on/off
|
||||
my %current_event = ();
|
||||
my %events;
|
||||
my $line_number = 0;
|
||||
$data =~ s/[ \t]?[\r\n]+[ \t]+/ /msg; #Process line continuations
|
||||
LINE: for my $line (split /[\r\n]+/,$data) {
|
||||
chomp $line;
|
||||
$line_number++;
|
||||
next unless $line =~ /\w/;
|
||||
|
||||
#warn "LINE $line_number: $line\n";
|
||||
|
||||
if ($line =~ /^BEGIN:VEVENT$/i) {
|
||||
$active = 1;
|
||||
next LINE;
|
||||
my $sitename = $session->config->get("sitename")->[0];
|
||||
FEED: foreach my $feed (@{ $calendar->getFeeds }) {
|
||||
if ($feed->{url} =~ m{http://[^/]*$sitename}) {
|
||||
$feed->{url} .= ( $feed->{url} =~ /[?]/ ? ";" : "?" ) . "adminId=".$session->getId;
|
||||
$session->db->write("REPLACE INTO userSessionScratch (sessionId,name,value) VALUES (?,?,?)",
|
||||
[$session->getId,$calendar->getId,"SPECTRE"]);
|
||||
}
|
||||
elsif ($line =~ /^END:VEVENT$/i) {
|
||||
$active = 0;
|
||||
# Flush event
|
||||
my $uid = lc $current_event{uid}[1];
|
||||
delete $current_event{uid};
|
||||
$events{$uid} = {%current_event};
|
||||
$self->session->log->info( "Found event $uid from feed " . $feed->{feedId} );
|
||||
%current_event = ();
|
||||
next LINE;
|
||||
#/KLUDGE
|
||||
|
||||
## Somebody point me to a DECENT iCalendar parser...
|
||||
# Text::vFile perhaps?
|
||||
|
||||
# Get the feed
|
||||
$session->log->info( "Trying Calendar feed ".$feed->{url}." for $calendarTitle" );
|
||||
my $response = $ua->get($feed->{url});
|
||||
|
||||
if (!$response->is_success) {
|
||||
# Update the result and last updated fields
|
||||
$feed->{lastResult} = $response->message || $response->content;
|
||||
$feed->{lastUpdated} = $dt;
|
||||
$calendar->setFeed($feed->{feedId}, $feed);
|
||||
$session->log->info( "Calendar feed ".$feed->{url}." for $calendarTitle failed" );
|
||||
next FEED;
|
||||
}
|
||||
else {
|
||||
# Flush old entry
|
||||
# KEY;ATTRIBUTE=VALUE;ATTRIBUTE=VALUE:KEYVALUE
|
||||
my ($key_attrs,$value) = split /:/,$line,2;
|
||||
my @attrs = $key_attrs ? (split /;/, $key_attrs) : ();
|
||||
my $key = shift @attrs;
|
||||
my %attrs;
|
||||
while (my $attribute = shift @attrs) {
|
||||
my ($attr_key, $attr_value) = split /=/, $attribute, 2;
|
||||
$attrs{lc $attr_key} = $attr_value;
|
||||
|
||||
my $data = $response->content;
|
||||
# If doesn't start with BEGIN:VCALENDAR then error
|
||||
unless ($data =~ /^BEGIN:VCALENDAR/i) {
|
||||
# Update the result and last updated fields
|
||||
$feed->{lastResult} = "Not an iCalendar feed";
|
||||
$feed->{lastUpdated} = $dt;
|
||||
$calendar->setFeed($feed->{feedId}, $feed);
|
||||
next FEED;
|
||||
}
|
||||
|
||||
my $active = 0; # Parser on/off
|
||||
my %current_event = ();
|
||||
my %events;
|
||||
my $line_number = 0;
|
||||
$data =~ s/[ \t]?[\r\n]+[ \t]+/ /msg; #Process line continuations
|
||||
LINE: for my $line (split /[\r\n]+/,$data) {
|
||||
chomp $line;
|
||||
$line_number++;
|
||||
next unless $line =~ /\w/;
|
||||
|
||||
#warn "LINE $line_number: $line\n";
|
||||
|
||||
if ($line =~ /^BEGIN:VEVENT$/i) {
|
||||
$active = 1;
|
||||
next LINE;
|
||||
}
|
||||
elsif ($line =~ /^END:VEVENT$/i) {
|
||||
$active = 0;
|
||||
# Flush event
|
||||
my $uid = lc $current_event{uid}[1];
|
||||
delete $current_event{uid};
|
||||
$events{$uid} = {%current_event};
|
||||
$session->log->info( "Found event $uid from feed " . $feed->{feedId} );
|
||||
%current_event = ();
|
||||
next LINE;
|
||||
}
|
||||
else {
|
||||
# Flush old entry
|
||||
# KEY;ATTRIBUTE=VALUE;ATTRIBUTE=VALUE:KEYVALUE
|
||||
my ($key_attrs,$value) = split /:/,$line,2;
|
||||
my @attrs = $key_attrs ? (split /;/, $key_attrs) : ();
|
||||
my $key = shift @attrs;
|
||||
my %attrs;
|
||||
while (my $attribute = shift @attrs) {
|
||||
my ($attr_key, $attr_value) = split /=/, $attribute, 2;
|
||||
$attrs{lc $attr_key} = $attr_value;
|
||||
}
|
||||
|
||||
$current_event{lc $key} = [\%attrs,$value];
|
||||
$current_event{lc $key} = [\%attrs,$value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $feedData = $feedList->{$feed->{feedId}} = {
|
||||
added => 0,
|
||||
updated => 0,
|
||||
errored => 0,
|
||||
assetId => $feed->{assetId},
|
||||
};
|
||||
EVENT: for my $id (keys %events) {
|
||||
#use Data::Dumper;
|
||||
#warn "EVENT: $id; ".Dumper $events{$id};
|
||||
|
||||
# Prepare event data
|
||||
my $properties = {
|
||||
feedUid => $id,
|
||||
feedId => $feed->{feedId},
|
||||
description => _unwrapIcalText($events{$id}->{description}->[1]),
|
||||
title => _unwrapIcalText($events{$id}->{summary}->[1]),
|
||||
location => _unwrapIcalText($events{$id}->{location}->[1]),
|
||||
menuTitle => substr($events{$id}->{summary}->[1],0,15),
|
||||
className => 'WebGUI::Asset::Event',
|
||||
isHidden => 1,
|
||||
my $feedData = $feedList->{$feed->{feedId}} = {
|
||||
added => 0,
|
||||
updated => 0,
|
||||
errored => 0,
|
||||
assetId => $calendar->getId,
|
||||
};
|
||||
EVENT: for my $id (keys %events) {
|
||||
#use Data::Dumper;
|
||||
#warn "EVENT: $id; ".Dumper $events{$id};
|
||||
|
||||
# Prepare the date
|
||||
my $dtstart = $events{$id}->{dtstart}->[1];
|
||||
if ($dtstart =~ /T/) {
|
||||
my ($date, $time) = split /T/, $dtstart;
|
||||
# Prepare event data
|
||||
my $properties = {
|
||||
feedUid => $id,
|
||||
feedId => $feed->{feedId},
|
||||
description => _unwrapIcalText($events{$id}->{description}->[1]),
|
||||
title => _unwrapIcalText($events{$id}->{summary}->[1]),
|
||||
location => _unwrapIcalText($events{$id}->{location}->[1]),
|
||||
menuTitle => substr($events{$id}->{summary}->[1],0,15),
|
||||
className => 'WebGUI::Asset::Event',
|
||||
isHidden => 1,
|
||||
};
|
||||
|
||||
my ($year, $month, $day) = $date =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
my ($hour, $minute, $second) = $time =~ /(\d{2})(\d{2})(\d{2})/;
|
||||
my $tz = $events{$id}->{dtstart}->[0]->{tzid};
|
||||
if (!$tz || !DateTime::TimeZone->is_valid_name($tz)) {
|
||||
$tz = "UTC";
|
||||
# Prepare the date
|
||||
my $dtstart = $events{$id}->{dtstart}->[1];
|
||||
if ($dtstart =~ /T/) {
|
||||
my ($date, $time) = split /T/, $dtstart;
|
||||
|
||||
my ($year, $month, $day) = $date =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
my ($hour, $minute, $second) = $time =~ /(\d{2})(\d{2})(\d{2})/;
|
||||
my $tz = $events{$id}->{dtstart}->[0]->{tzid};
|
||||
if (!$tz || !DateTime::TimeZone->is_valid_name($tz)) {
|
||||
$tz = "UTC";
|
||||
}
|
||||
|
||||
($properties->{startDate}, $properties->{startTime}) =
|
||||
split / /, WebGUI::DateTime->new(
|
||||
year => $year,
|
||||
month => $month,
|
||||
day => $day,
|
||||
hour => $hour,
|
||||
minute => $minute,
|
||||
second => $second,
|
||||
time_zone => $tz,
|
||||
)->toMysql;
|
||||
$properties->{timeZone} = $tz;
|
||||
}
|
||||
elsif ($dtstart =~ /(\d{4})(\d{2})(\d{2})/) {
|
||||
my ($year, $month, $day) = $dtstart =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
$properties->{startDate} = join "-",$year,$month,$day;
|
||||
}
|
||||
elsif ($dtstart) {
|
||||
$session->log->warn(
|
||||
"Workflow::Activity::CalendarUpdateFeeds"
|
||||
. " -- '$dtstart' does not appear to be a valid date"
|
||||
);
|
||||
$feedData->{errored}++;
|
||||
next EVENT;
|
||||
}
|
||||
|
||||
($properties->{startDate}, $properties->{startTime}) =
|
||||
split / /, WebGUI::DateTime->new(
|
||||
year => $year,
|
||||
month => $month,
|
||||
day => $day,
|
||||
hour => $hour,
|
||||
minute => $minute,
|
||||
second => $second,
|
||||
time_zone => $tz,
|
||||
)->toMysql;
|
||||
$properties->{timeZone} = $tz;
|
||||
}
|
||||
elsif ($dtstart =~ /(\d{4})(\d{2})(\d{2})/) {
|
||||
my ($year, $month, $day) = $dtstart =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
$properties->{startDate} = join "-",$year,$month,$day;
|
||||
}
|
||||
elsif ($dtstart) {
|
||||
$session->errorHandler->warn(
|
||||
"Workflow::Activity::CalendarUpdateFeeds"
|
||||
. " -- '$dtstart' does not appear to be a valid date"
|
||||
);
|
||||
$feedData->{errored}++;
|
||||
next EVENT;
|
||||
}
|
||||
my $dtend = $events{$id}->{dtend}->[1];
|
||||
my $duration = $events{$id}->{duration}->[1];
|
||||
if ($dtend =~ /T/) {
|
||||
my ($date, $time) = split /T/, $dtend;
|
||||
|
||||
my $dtend = $events{$id}->{dtend}->[1];
|
||||
my $duration = $events{$id}->{duration}->[1];
|
||||
if ($dtend =~ /T/) {
|
||||
my ($date, $time) = split /T/, $dtend;
|
||||
my ($year, $month, $day) = $date =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
my ($hour, $minute, $second) = $time =~ /(\d{2})(\d{2})(\d{2})/;
|
||||
my $tz = $events{$id}->{dtend}->[0]->{tzid};
|
||||
if (!$tz || !DateTime::TimeZone->is_valid_name($tz)) {
|
||||
$tz = "UTC";
|
||||
}
|
||||
|
||||
my ($year, $month, $day) = $date =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
my ($hour, $minute, $second) = $time =~ /(\d{2})(\d{2})(\d{2})/;
|
||||
my $tz = $events{$id}->{dtend}->[0]->{tzid};
|
||||
if (!$tz || !DateTime::TimeZone->is_valid_name($tz)) {
|
||||
$tz = "UTC";
|
||||
($properties->{endDate}, $properties->{endTime}) =
|
||||
split / /, WebGUI::DateTime->new(
|
||||
year => $year,
|
||||
month => $month,
|
||||
day => $day,
|
||||
hour => $hour,
|
||||
minute => $minute,
|
||||
second => $second,
|
||||
time_zone => $tz,
|
||||
)->toMysql;
|
||||
$properties->{timeZone} = $tz;
|
||||
}
|
||||
elsif ($dtend =~ /(\d{4})(\d{2})(\d{2})/) {
|
||||
my ($year, $month, $day) = $dtend =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
|
||||
my $endDateLet = WebGUI::DateTime->new( year => $year, month => $month, day => $day);
|
||||
$endDateLet->subtract( days => 1 );
|
||||
$properties->{endDate} = $endDateLet->toDatabaseDate;
|
||||
}
|
||||
# If we can't parse it, forget the whole event
|
||||
elsif ($dtend) {
|
||||
$session->log->warn(
|
||||
"Workflow::Activity::CalendarUpdateFeeds"
|
||||
. " -- '$dtend' does not appear to be a valid date"
|
||||
);
|
||||
$feedData->{errored}++;
|
||||
next EVENT;
|
||||
}
|
||||
# No dtend, but we have duration!
|
||||
elsif ($duration) {
|
||||
my ($days, $hours, $minutes, $seconds)
|
||||
= $duration =~ m{
|
||||
P
|
||||
(?:(\d+)D)? # Days
|
||||
T
|
||||
(?:(\d+)H)? # Hours
|
||||
(?:(\d+)M)? # Minutes
|
||||
(?:(\d+)S)? # Seconds
|
||||
}ix;
|
||||
my $startDate = $properties->{startDate};
|
||||
# Fill in bogus value to get a WebGUI::DateTime object,
|
||||
# we'll figure out what we actually need later
|
||||
my $startTime = $properties->{startTime} || "00:00:00";
|
||||
my $datetime = WebGUI::DateTime->new($session,$startDate." ".$startTime);
|
||||
|
||||
$datetime->add(
|
||||
days => $days || 0,
|
||||
hours => $hours || 0,
|
||||
minutes => $minutes || 0,
|
||||
seconds => $seconds || 0,
|
||||
);
|
||||
|
||||
$properties->{endDate} = $datetime->toDatabaseDate;
|
||||
# If it not an all-day event, set the end time too
|
||||
if ($properties->{startTime}) {
|
||||
$properties->{endTime} = $datetime->toDatabaseTime;
|
||||
}
|
||||
}
|
||||
# No dtend, no duration, just copy the start
|
||||
else {
|
||||
$properties->{endDate} = $properties->{startDate};
|
||||
$properties->{endTime} = $properties->{startTime};
|
||||
}
|
||||
|
||||
($properties->{endDate}, $properties->{endTime}) =
|
||||
split / /, WebGUI::DateTime->new(
|
||||
year => $year,
|
||||
month => $month,
|
||||
day => $day,
|
||||
hour => $hour,
|
||||
minute => $minute,
|
||||
second => $second,
|
||||
time_zone => $tz,
|
||||
)->toMysql;
|
||||
$properties->{timeZone} = $tz;
|
||||
}
|
||||
elsif ($dtend =~ /(\d{4})(\d{2})(\d{2})/) {
|
||||
my ($year, $month, $day) = $dtend =~ /(\d{4})(\d{2})(\d{2})/;
|
||||
# If there are X-WebGUI-* fields
|
||||
for my $key (grep /^x-webgui-/, keys %{$events{$id}}) {
|
||||
my $property_name = $key;
|
||||
$property_name =~ s/^x-webgui-//;
|
||||
$property_name = lc $property_name;
|
||||
|
||||
my $endDateLet = WebGUI::DateTime->new( year => $year, month => $month, day => $day);
|
||||
$endDateLet->subtract( days => 1 );
|
||||
$properties->{endDate} = $endDateLet->toDatabaseDate;
|
||||
}
|
||||
# If we can't parse it, forget the whole event
|
||||
elsif ($dtend) {
|
||||
$session->errorHandler->warn(
|
||||
"Workflow::Activity::CalendarUpdateFeeds"
|
||||
. " -- '$dtend' does not appear to be a valid date"
|
||||
);
|
||||
$feedData->{errored}++;
|
||||
next EVENT;
|
||||
}
|
||||
# No dtend, but we have duration!
|
||||
elsif ($duration) {
|
||||
my ($days, $hours, $minutes, $seconds)
|
||||
= $duration =~ m{
|
||||
P
|
||||
(?:(\d+)D)? # Days
|
||||
T
|
||||
(?:(\d+)H)? # Hours
|
||||
(?:(\d+)M)? # Minutes
|
||||
(?:(\d+)S)? # Seconds
|
||||
}ix;
|
||||
my $startDate = $properties->{startDate};
|
||||
# Fill in bogus value to get a WebGUI::DateTime object,
|
||||
# we'll figure out what we actually need later
|
||||
my $startTime = $properties->{startTime} || "00:00:00";
|
||||
my $datetime = WebGUI::DateTime->new($session,$startDate." ".$startTime);
|
||||
|
||||
$datetime->add(
|
||||
days => $days || 0,
|
||||
hours => $hours || 0,
|
||||
minutes => $minutes || 0,
|
||||
seconds => $seconds || 0,
|
||||
);
|
||||
|
||||
$properties->{endDate} = $datetime->toDatabaseDate;
|
||||
# If it not an all-day event, set the end time too
|
||||
if ($properties->{startTime}) {
|
||||
$properties->{endTime} = $datetime->toDatabaseTime;
|
||||
if ($property_name eq "groupidedit") {
|
||||
$properties->{groupIdEdit} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
elsif ($property_name eq "groupidview") {
|
||||
$properties->{groupIdView} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
elsif ($property_name eq "url") {
|
||||
$properties->{url} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
elsif ($property_name eq "menutitle") {
|
||||
$properties->{menuTitle} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
# No dtend, no duration, just copy the start
|
||||
else {
|
||||
$properties->{endDate} = $properties->{startDate};
|
||||
$properties->{endTime} = $properties->{startTime};
|
||||
}
|
||||
|
||||
# If there are X-WebGUI-* fields
|
||||
for my $key (grep /^x-webgui-/, keys %{$events{$id}}) {
|
||||
my $property_name = $key;
|
||||
$property_name =~ s/^x-webgui-//;
|
||||
$property_name = lc $property_name;
|
||||
my $recur;
|
||||
if ($events{$id}->{rrule}) {
|
||||
$recur = _icalToRecur($session, $properties->{startDate}, $events{$id}->{rrule}->[1]);
|
||||
}
|
||||
|
||||
if ($property_name eq "groupidedit")
|
||||
{
|
||||
$properties->{groupIdEdit} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
elsif ($property_name eq "groupidview")
|
||||
{
|
||||
$properties->{groupIdView} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
elsif ($property_name eq "url")
|
||||
{
|
||||
$properties->{url} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
elsif ($property_name eq "menutitle")
|
||||
{
|
||||
$properties->{menuTitle} = $events{$id}->{$key}->[1];
|
||||
}
|
||||
# save events for later
|
||||
push @$eventList, {
|
||||
properties => $properties,
|
||||
recur => $recur,
|
||||
};
|
||||
}
|
||||
|
||||
my $recur;
|
||||
if ($events{$id}->{rrule}) {
|
||||
$recur = _icalToRecur($session, $properties->{startDate}, $events{$id}->{rrule}->[1]);
|
||||
}
|
||||
|
||||
# save events for later
|
||||
push @$eventList, {
|
||||
properties => $properties,
|
||||
recur => $recur,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
my $currentVersionTag = WebGUI::VersionTag->getWorking($self->session, 1);
|
||||
my $currentVersionTag = WebGUI::VersionTag->getWorking($session, 1);
|
||||
if ($currentVersionTag) {
|
||||
$currentVersionTag->clearWorking;
|
||||
}
|
||||
my $ttl = $self->getTTL;
|
||||
$self->session->log->info( "Have to add " . scalar( @$eventList ) . " events..." );
|
||||
while (@$eventList) {
|
||||
$session->log->info( "Have to add " . scalar( @$eventList ) . " events..." );
|
||||
while (@{ $eventList }) {
|
||||
if ($startTime + $ttl < time()) {
|
||||
$instance->setScratch('events', JSON::to_json($eventList));
|
||||
$instance->setScratch('feeds', JSON::to_json($feedList));
|
||||
my $newVersionTag = WebGUI::VersionTag->getWorking($self->session, 1);
|
||||
$instance->setScratch('feeds', JSON::to_json($feedList));
|
||||
my $newVersionTag = WebGUI::VersionTag->getWorking($session, 1);
|
||||
if ($newVersionTag) {
|
||||
$newVersionTag->requestCommit;
|
||||
}
|
||||
|
|
@ -379,19 +382,19 @@ sub execute {
|
|||
$session->user({user => $previousUser});
|
||||
return $self->WAITING(1);
|
||||
}
|
||||
my $eventData = shift @$eventList;
|
||||
my $recur = $eventData->{recur};
|
||||
my $eventData = shift @$eventList;
|
||||
my $recur = $eventData->{recur};
|
||||
my $properties = $eventData->{properties};
|
||||
my $id = $properties->{feedUid};
|
||||
my $feed = $feedList->{$properties->{feedId}};
|
||||
my $id = $properties->{feedUid};
|
||||
my $feed = $feedList->{$properties->{feedId}};
|
||||
|
||||
# Update event
|
||||
my $assetId = $self->session->db->quickScalar("select assetId from Event where feedUid=?",[$id]);
|
||||
my $assetId = $session->db->quickScalar("select assetId from Event where feedUid=?",[$id]);
|
||||
|
||||
# If this event already exists, update
|
||||
if ($assetId) {
|
||||
$self->session->log->info( "Updating existing asset $assetId" );
|
||||
my $event = WebGUI::Asset->newByDynamicClass($self->session,$assetId);
|
||||
$session->log->info( "Updating existing asset $assetId" );
|
||||
my $event = WebGUI::Asset->newByDynamicClass($session,$assetId);
|
||||
|
||||
if ($event) {
|
||||
$event->update($properties);
|
||||
|
|
@ -399,8 +402,8 @@ sub execute {
|
|||
}
|
||||
}
|
||||
else {
|
||||
$self->session->log->info( "Creating new Event!" );
|
||||
my $calendar = WebGUI::Asset->newByDynamicClass($self->session,$feed->{assetId});
|
||||
$session->log->info( "Creating new Event!" );
|
||||
my $calendar = WebGUI::Asset->newByDynamicClass($session,$feed->{assetId});
|
||||
my $event = $calendar->addChild($properties, undef, undef, { skipAutoCommitWorkflows => 1});
|
||||
$feed->{added}++;
|
||||
if ($recur) {
|
||||
|
|
@ -411,9 +414,9 @@ sub execute {
|
|||
|
||||
# TODO: Only update if last-updated field is
|
||||
# greater than the event's lastUpdated property
|
||||
$self->session->log->info( scalar @$eventList . " events left to load" );
|
||||
$session->log->info( scalar @$eventList . " events left to load" );
|
||||
}
|
||||
my $newVersionTag = WebGUI::VersionTag->getWorking($self->session, 1);
|
||||
my $newVersionTag = WebGUI::VersionTag->getWorking($session, 1);
|
||||
if ($newVersionTag) {
|
||||
$newVersionTag->requestCommit;
|
||||
}
|
||||
|
|
@ -422,8 +425,11 @@ sub execute {
|
|||
}
|
||||
for my $feedId (keys %$feedList) {
|
||||
my $feed = $feedList->{$feedId};
|
||||
$self->session->db->write("update Calendar_feeds set lastResult=?,lastUpdated=? where feedId=?",
|
||||
["Success! $feed->{added} added, $feed->{updated} updated, $feed->{errored} parsing errors",$dt,$feedId]);
|
||||
my $calendar = WebGUI::Asset->newByDynamicClass($session, $feed->{assetId});
|
||||
my $feedData = $calendar->getFeed($feedId);
|
||||
$feedData->{lastResult} = "Success! $feed->{added} added, $feed->{updated} updated, $feed->{errored} parsing errors";
|
||||
$feedData->{lastUpdated} = $dt;
|
||||
$calendar->setFeed($feedId, $feedData);
|
||||
}
|
||||
$instance->deleteScratch('events');
|
||||
$instance->deleteScratch('feeds');
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use WebGUI::Asset::Wobject::Calendar;
|
|||
|
||||
use Test::More;
|
||||
use Test::Deep;
|
||||
use Data::Dumper;
|
||||
|
||||
if (!$ENV{WEBGUI_LIVE}) {
|
||||
plan skip_all => 'No website available';
|
||||
|
|
@ -40,11 +41,10 @@ my $receiver = $home->addChild({
|
|||
title => 'Receiving Calendar',
|
||||
});
|
||||
|
||||
$session->db->setRow('Calendar_feeds', 'feedId', {
|
||||
feedId => 'new',
|
||||
assetId => $receiver->getId,
|
||||
$receiver->addFeed({
|
||||
url => $session->url->getSiteURL.$session->url->gateway($sender->getUrl('func=ical')),
|
||||
feedType => 'ical',
|
||||
lastUpdated => 'never',
|
||||
});
|
||||
|
||||
my $dt = WebGUI::DateTime->new($session, time());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue