From 755d7909a57cd4716ff609581bcd81a5116f4a76 Mon Sep 17 00:00:00 2001 From: Colin Kuskie Date: Tue, 30 Jun 2009 15:43:40 +0000 Subject: [PATCH] Fix iCal processing in the Calendar module and workflow. Errors with generation and processing. --- docs/changelog/7.x.x.txt | 1 + lib/WebGUI/Asset/Wobject/Calendar.pm | 37 ++++-- .../Workflow/Activity/CalendarUpdateFeeds.pm | 34 ++---- t/Workflow/Activity/CalendarUpdateFeeds.t | 114 ++++++++++++++++++ 4 files changed, 153 insertions(+), 33 deletions(-) create mode 100644 t/Workflow/Activity/CalendarUpdateFeeds.t diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 5f19fa9b5..947cd777b 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,6 +1,7 @@ 7.7.13 - fixed #10574: Creating Calendar Entry - fixed #10522: Metadata value & label problem + - fixed #10594: iCal title display error. 7.7.12 - Updated auth to allow sending back of non-text/html mime types. diff --git a/lib/WebGUI/Asset/Wobject/Calendar.pm b/lib/WebGUI/Asset/Wobject/Calendar.pm index 0a0174b4f..03f56be81 100644 --- a/lib/WebGUI/Asset/Wobject/Calendar.pm +++ b/lib/WebGUI/Asset/Wobject/Calendar.pm @@ -671,11 +671,22 @@ TODO: Allow WebGUI::DateTime objects to be passed as the parameters. This is the main API method to get events from a calendar, so it must be flexible. -C is a hash reference with the following keys: +=head3 startDate - order - The order to return the events. Will default to the - sortEventsBy asset property. Valid values are: - 'time', 'sequenceNumber' +A date with optional time in MySQL format. + +=head3 endDate + +A date with optional time in MySQL format. + +=head3 options + +A hash reference with any the following keys and values: + +=head4 order + +The order to return the events. Will default to the sortEventsBy asset property. +Valid values are: 'time', 'sequenceNumber' =cut @@ -698,21 +709,23 @@ sub getEventsIn { # Create objects and adjust for timezone + warn "start: $start\n"; + warn "end: $end\n"; my ($startDate,$startTime) = split / /, $start; my ($endDate,$endTime) = split / /, $end; #use Data::Dumper; #$self->session->errorHandler->warn( Dumper [caller(1), caller(2), caller(3)] ); - my $startTz = WebGUI::DateTime->new($self->session, mysql => $start, time_zone => $tz) - ->set_time_zone("UTC")->toMysql; - my $endTz = WebGUI::DateTime->new($self->session, mysql => $end, time_zone => $tz) - ->set_time_zone("UTC")->toMysql; + my $startTz = WebGUI::DateTime->new($self->session, mysql => $start, time_zone => $tz)->set_time_zone("UTC")->toMysql; + my $endTz = WebGUI::DateTime->new($self->session, mysql => $end, time_zone => $tz)->set_time_zone("UTC")->toMysql; + warn $startTz; + warn $endTz; my $where = qq{ ( - Event.startTime IS NULL - && Event.endTime IS NULL + Event.startTime IS NULL + && Event.endTime IS NULL && !( Event.startDate >= '$endDate' @@ -720,7 +733,7 @@ sub getEventsIn { ) ) || ( - CONCAT(Event.startDate,' ',Event.startTime) >= '$startTz' + CONCAT(Event.startDate,' ',Event.startTime) >= '$startTz' && CONCAT(Event.startDate,' ',Event.startTime) < '$endTz' ) }; @@ -1738,7 +1751,7 @@ sub wrapIcal { $text =~ s/([,;\\])/\\$1/g; $text =~ s/\n/\\n/g; - my @text = ($text =~ m/.{0,75}/g); + my @text = ($text =~ m/.{1,75}/g); return join "\r\n ",@text; } diff --git a/lib/WebGUI/Workflow/Activity/CalendarUpdateFeeds.pm b/lib/WebGUI/Workflow/Activity/CalendarUpdateFeeds.pm index 865273d53..016860f10 100644 --- a/lib/WebGUI/Workflow/Activity/CalendarUpdateFeeds.pm +++ b/lib/WebGUI/Workflow/Activity/CalendarUpdateFeeds.pm @@ -121,7 +121,6 @@ sub execute { [$session->getId,$feed->{assetId},"SPECTRE"]); } #/KLUDGE - #warn "FEED URL: ".$feed->{url} ."\n"; ## Somebody point me to a DECENT iCalendar parser... # Text::vFile perhaps? @@ -148,10 +147,10 @@ sub execute { my $active = 0; # Parser on/off my %current_event = (); - my $current_entry = ""; my %events; my $line_number = 0; - for my $line (split /[\r\n]+/,$data) { + $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/; @@ -160,6 +159,7 @@ sub execute { if ($line =~ /^BEGIN:VEVENT$/i) { $active = 1; + next LINE; } elsif ($line =~ /^END:VEVENT$/i) { $active = 0; @@ -169,15 +169,12 @@ sub execute { $events{$uid} = {%current_event}; $self->session->log->info( "Found event $uid from feed " . $feed->{feedId} ); %current_event = (); - } - elsif ($line =~ /^ /) { - # Add to entry data - $current_entry .= substr $line, 1; + next LINE; } else { # Flush old entry # KEY;ATTRIBUTE=VALUE;ATTRIBUTE=VALUE:KEYVALUE - my ($key_attrs,$value) = split /:/,$current_entry,2; + my ($key_attrs,$value) = split /:/,$line,2; my @attrs = $key_attrs ? (split /;/, $key_attrs) : (); my $key = shift @attrs; my %attrs; @@ -186,13 +183,7 @@ sub execute { $attrs{lc $attr_key} = $attr_value; } - # Unescape value - - $current_event{lc $key} = [\%attrs,$value]; - - # Start new entry - $current_entry = $line; } } @@ -330,23 +321,24 @@ sub execute { } # If there are X-WebGUI-* fields - for my $key (grep /^X-WEBGUI-/, keys %{$events{$id}}) { + for my $key (grep /^x-webgui-/, keys %{$events{$id}}) { my $property_name = $key; - $property_name =~ s/^X-WEBGUI-//; + $property_name =~ s/^x-webgui-//; + $property_name = lc $property_name; - if (lc $property_name eq "groupidedit") + if ($property_name eq "groupidedit") { $properties->{groupIdEdit} = $events{$id}->{$key}->[1]; } - elsif (lc $property_name eq "groupidview") + elsif ($property_name eq "groupidview") { $properties->{groupIdView} = $events{$id}->{$key}->[1]; } - elsif (lc $property_name eq "url") + elsif ($property_name eq "url") { $properties->{url} = $events{$id}->{$key}->[1]; } - elsif (lc $property_name eq "menutitle") + elsif ($property_name eq "menutitle") { $properties->{menuTitle} = $events{$id}->{$key}->[1]; } @@ -538,7 +530,7 @@ sub _icalToMySQL { sub _unwrapIcalText { my $text = shift; - $text =~ s/\\([.;\\])/$1/g; + $text =~ s/\\([,;\\])/$1/g; return $text; } diff --git a/t/Workflow/Activity/CalendarUpdateFeeds.t b/t/Workflow/Activity/CalendarUpdateFeeds.t new file mode 100644 index 000000000..95c71b5c9 --- /dev/null +++ b/t/Workflow/Activity/CalendarUpdateFeeds.t @@ -0,0 +1,114 @@ +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2009 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------- +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------- + +use FindBin; +use strict; +use lib "$FindBin::Bin/../../lib"; + +use WebGUI::Test; +use WebGUI::Session; +use WebGUI::Utility; +use WebGUI::Workflow::Activity::CalendarUpdateFeeds; +use WebGUI::Asset::Wobject::Calendar; + +use Test::More; +use Test::Deep; + +if (!$ENV{WEBGUI_LIVE}) { + plan skip_all => 'No website available'; +} +else { + plan tests => 10; # increment this value for each test you create +} + +my $session = WebGUI::Test->session; + +my $home = WebGUI::Asset->getDefault($session); +my $sender = $home->addChild({ + className => 'WebGUI::Asset::Wobject::Calendar', + title => 'Sending Calendar', +}); +my $receiver = $home->addChild({ + className => 'WebGUI::Asset::Wobject::Calendar', + title => 'Receiving Calendar', +}); + +$session->db->setRow('Calendar_feeds', 'feedId', { + feedId => 'new', + assetId => $receiver->getId, + url => $session->url->getSiteURL.$session->url->gateway($sender->getUrl('func=ical')), + feedType => 'ical', +}); + +my $dt = WebGUI::DateTime->new($session, time()); +$dt->add(days => 1); + +my $party = $sender->addChild({ + className => 'WebGUI::Asset::Event', + title => 'WebGUI 100th Anniversary', + menuTitle => 'Anniversary', + description => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', ##Set at longer than 72 characters to test for line wrapping + url => 'webgui_anniversary', + startDate => $dt->toDatabaseDate, ##Times and dates have to be entered in UTC + endDate => $dt->toDatabaseDate, + timeZone => 'America/Chicago', + location => 'Madison, Wisconsin', + groupIdView => 7, + groupIdEdit => 12, + ownerUserId => 3, +}, undef, undef, {skipAutoCommitWorkflows => 1}); + +my $tag = WebGUI::VersionTag->getWorking($session); +$tag->commit; +WebGUI::Test->tagsToRollback($tag); + +my $workflow = WebGUI::Workflow->create($session, + { + enabled => 1, + objectType => 'None', + mode => 'realtime', + }, +); +my $icalFetch = $workflow->addActivity('WebGUI::Workflow::Activity::CalendarUpdateFeeds'); + +my $instance1 = WebGUI::Workflow::Instance->create($session, + { + workflowId => $workflow->getId, + skipSpectreNotification => 1, + } +); + +my $oldEvents = $receiver->getLineage(['children'], { returnObjects => 1, }); +is(scalar @{ $oldEvents }, 0, 'receiving calendar has no events'); + +my $retVal; + +$retVal = $instance1->run(); +is($retVal, 'complete', 'cleanup: activity complete'); +$retVal = $instance1->run(); +is($retVal, 'done', 'cleanup: activity is done'); +$instance1->delete; + +my $newEvents = $receiver->getLineage(['children'], { returnObjects => 1, }); + +is(scalar @{ $newEvents }, 1, 'ical import of 1 event'); +my $anniversary = pop @{ $newEvents }; + +is($anniversary->get('title'), $party->get('title'), 'transferred title'); +is($anniversary->get('menuTitle'), $party->get('menuTitle'), '... menuTitle'); +is($anniversary->get('groupIdView'), $party->get('groupIdView'), '... groupIdView'); +is($anniversary->get('groupIdEdit'), $party->get('groupIdEdit'), '... groupIdEdit'); +is($anniversary->get('url'), $party->get('url').'2', '... url (accounting for duplicate)'); +is($anniversary->get('description'), $party->get('description'), '... description, checks for line wrapping'); + +END { + $instance1 && $instance1->delete('skipNotify'); + $workflow && $workflow->delete; +}