Add an Event method for returning a non-inclusive end DataTime object.

Have Calendar use that for determining the end of a week in viewWeek.
Fix getEventsIn to do all comparisons in UTC so that extra events are not added in.
This commit is contained in:
Colin Kuskie 2009-07-03 05:04:43 +00:00
parent f04a162ea3
commit 1bcae0d3bc
4 changed files with 213 additions and 37 deletions

View file

@ -391,6 +391,28 @@ sub getDateTimeEnd {
}
}
####################################################################
=head2 getDateTimeEndNI
Since the iCal standard is that ending dates are non-inclusive (they
do not include the second at the end of the time period), this method
provide a copy of the DateTime object that is 1 second earlier than
the set ending time.
It's just one line of DateTime code to adjust this on any object, but
this is encapsulated here to make sure that the same amount of time
is used EVERYWHERE.
=cut
sub getDateTimeEndNI {
my $self = shift;
my $dt = $self->getDateTimeEnd;
$dt->subtract(seconds => 1);
return $dt;
}
@ -1277,7 +1299,8 @@ sub getTemplateVars {
$var{ "startDateEpoch" } = $dtStart->epoch;
# End date/time
my $dtEnd = $self->getDateTimeEnd;
my $dtEnd = $self->getDateTimeEnd;
my $dtEndNI = $self->getDateTimeEndNI;
$var{ "endDateSecond" } = sprintf "%02d", $dtEnd->second;
$var{ "endDateMinute" } = sprintf "%02d", $dtEnd->minute;

View file

@ -674,11 +674,11 @@ This is the main API method to get events from a calendar, so it must be flexibl
=head3 startDate
A date with optional time in MySQL format.
A date, with optional time, in UTC, in MySQL format.
=head3 endDate
A date with optional time in MySQL format.
A date, with optional time, in UTC, in MySQL format.
=head3 options
@ -700,8 +700,6 @@ sub getEventsIn {
$params->{order} = '' if $params->{order} !~ /^(?:time|sequencenumber)/i;
my $order_by_type = $params->{order} ? lc($params->{order}) : $self->get('sortEventsBy');
my $tz = $self->session->datetime->getTimeZone;
# Warn and return undef if no startDate or endDate
unless ($start && $end) {
$self->session->errorHandler->warn("WebGUI::Asset::Wobject::Calendar->getEventsIn() called with not enough arguments at ".join('::',(caller)[1,2]));
@ -710,14 +708,9 @@ sub getEventsIn {
# Create objects and adjust for timezone
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 ($startDate) = split / /, $start;
my ($endDate) = split / /, $end;
my $where
= qq{
(
@ -730,8 +723,8 @@ sub getEventsIn {
)
)
|| (
CONCAT(Event.startDate,' ',Event.startTime) >= '$startTz'
&& CONCAT(Event.startDate,' ',Event.startTime) < '$endTz'
CONCAT(Event.startDate,' ',Event.startTime) >= '$start'
&& CONCAT(Event.startDate,' ',Event.startTime) < '$end'
)
};
@ -749,7 +742,6 @@ sub getEventsIn {
my $orderby = join ',', @order_priority;
my $events
= $self->getLineage(["descendants"], {
returnObjects => 1,
@ -758,9 +750,9 @@ sub getEventsIn {
orderByClause => $orderby,
whereClause => $where,
});
#? Perhaps use Stow to cache Events ?#
return @{$events};
}
@ -1441,6 +1433,7 @@ sub viewWeek {
#### Get all the events in this time period
# Get the range of the epoch of this week
my $dt = WebGUI::DateTime->new($self->session, $params->{start});
$dt->set_time_zone($tz);
$dt->truncate( to => "day");
# Apply First Day of Week settings
@ -1479,7 +1472,7 @@ sub viewWeek {
# Get the week this event is in, and add it to that week in
# the template variables
my $dt_event_start = $event->getDateTimeStart;
my $dt_event_end = $event->getDateTimeEnd;
my $dt_event_end = $event->getDateTimeEndNI;
#Handle events that start before this week or end after this week.
if ($dt_event_start < $dt) {
@ -1491,7 +1484,7 @@ sub viewWeek {
}
my $start_dow = ($dt_event_start->day_of_week - $first_dow) % 7;
my $end_dow = ($dt_event_end->day_of_week - $first_dow) % 7;
my $end_dow = ($dt_event_end->day_of_week - $first_dow) % 7;
my $sequence_number = $session->db->dbh->selectcol_arrayref(
"SELECT sequenceNumber FROM Event WHERE assetId = ? ORDER BY revisionDate desc LIMIT 1",
@ -1645,26 +1638,26 @@ sub viewWeek {
# Get the week this event is in, and add it to that week in
# the template variables
my $dt_event_start = $event->getDateTimeStart;
my $dt_event_end = $event->getDateTimeEnd;
my $dt_event_end = $event->getDateTimeEndNI;
#Handle events that start before this week or end after this week.
if ($dt_event_start < $dt) {
$dt_event_start = $dt;
$dt_event_start = $dt->clone;
}
if ($dt_event_end > $dtEnd) {
$dt_event_end = $dtEnd;
$dt_event_end = $dtEnd->clone;
}
my $start_dow = ($dt_event_start->day_of_week - $first_dow) % 7;
my $end_dow = ($dt_event_end->day_of_week - $first_dow) % 7;
my $end_dow = ($dt_event_end->day_of_week - $first_dow) % 7;
my %eventTemplateVariables = $self->getEventVars($event);
foreach my $weekDay ($start_dow .. $end_dow) {
my $eventAssetId = $event->get( 'assetId' );
my %hash = %eventTemplateVariables;
my %hash = %eventTemplateVariables;
if ($sort_by_sequence && $can_edit_order) {
if (1) {

View file

@ -19,7 +19,7 @@ use WebGUI::Asset::Event;
use Test::More; # increment this value for each test you create
use Test::Deep;
plan tests => 9;
plan tests => 10;
my $session = WebGUI::Test->session;
@ -81,3 +81,5 @@ is($event3->isAllDay, 1, 'isAllDay is zero since it has no start or end time, ev
%templateVars = $event3->getTemplateVars();
is($templateVars{dateSpan}, 'Wednesday, August 16 &bull; Thursday, August 17 ', 'getTemplateVars: dateSpan with no times, across two days');
is($templateVars{isOneDay}, 0, 'getTemplateVars: isOneDay with different start and end dates');
cmp_ok($event3->getDateTimeEnd, '>', $event3->getDateTimeEndNI, 'getDateTimeEndNI is less than getDateTimeEnd');

View file

@ -30,6 +30,11 @@ my @icalWrapTests = (
out => '\;Escape more than one\; multiple\; semicolons\;',
comment => 'escape semicolons',
},
{
in => '\\Escape more than one\\ multiple\\ backslashes\\',
out => '\\\\Escape more than one\\\\ multiple\\\\ backslashes\\\\',
comment => 'escape backslashes',
},
{
in => "lots\nand\nlots\nof\nnewlines\n",
out => 'lots\\nand\\nlots\\nof\\nnewlines\\n',
@ -48,10 +53,11 @@ use WebGUI::Test;
use WebGUI::Session;
use Test::More;
use Test::Deep;
use Data::Dumper;
use WebGUI::Asset::Wobject::Calendar;
use WebGUI::Asset::Event;
plan tests => 5 + scalar @icalWrapTests;
plan tests => 10 + scalar @icalWrapTests;
my $session = WebGUI::Test->session;
@ -60,6 +66,7 @@ my $node = WebGUI::Asset->getImportNode($session);
my $versionTag = WebGUI::VersionTag->getWorking($session);
$versionTag->set({name=>"Calendar Test"});
WebGUI::Test->tagsToRollback($versionTag);
my $cal = $node->addChild({className=>'WebGUI::Asset::Wobject::Calendar'});
$versionTag->commit();
@ -71,11 +78,9 @@ isa_ok($cal, 'WebGUI::Asset::Wobject::Calendar');
my $event = $cal->addChild({className=>'WebGUI::Asset::Event'});
isa_ok($event, 'WebGUI::Asset::Event','Can add Events as a child to the calendar.');
# Calendars create and autocommit a version tag when a child is added. Lets get the name so we can roll it back.
my $secondVersionTag = WebGUI::VersionTag->new($session, $event->get("tagId"));
my $article = $cal->addChild({className=>"WebGUI::Asset::Wobject::Article"});
isnt(ref $article, 'WebGUI::Asset::Wobject::Article', "Can't add an article as a child to the calendar.");
ok(! defined $article, '... addChild returned undef');
my $dt = WebGUI::DateTime->new($session, mysql => '2001-08-16 8:00:00', time_zone => 'America/Chicago');
@ -107,6 +112,166 @@ cmp_deeply(
'Variables returned by appendTemplateVarsDateTime'
);
######################################################################
#
# getEventsIn
#
######################################################################
my $windowCal = $node->addChild({
className => 'WebGUI::Asset::Wobject::Calendar',
title => 'Calendar for doing event window testing',
});
my $tz = $session->datetime->getTimeZone();
my $bday = WebGUI::DateTime->new($session, WebGUI::Test->webguiBirthday);
my $dt = $bday->clone->truncate(to => 'day');
my $startDt = $dt->cloneToUserTimeZone->subtract(days => 1);
my $endDt = $dt->cloneToUserTimeZone->add(days => 1);
my $inside = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Inside window, no times, same day',
startDate => $bday->toDatabaseDate,
endDate => $bday->toDatabaseDate,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $inside2 = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Inside window, with times',
startDate => $bday->toDatabaseDate,
endDate => $bday->toDatabaseDate,
startTime => $bday->toDatabaseTime,
endTime => $bday->clone->add(hours => 1)->toDatabaseTime,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $outsideHigh = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Outside window, after time',
startDate => $endDt->clone->add(days => 2)->toDatabaseDate,
endDate => $endDt->clone->add(days => 3)->toDatabaseDate,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $outsideLow = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Outside window, before time',
startDate => $startDt->clone->subtract(days => 3)->toDatabaseDate,
endDate => $startDt->clone->subtract(days => 2)->toDatabaseDate,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $straddle = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Straddles the window, inclusive',
startDate => $startDt->clone->subtract(days => 1)->toDatabaseDate,
endDate => $endDt->clone->add(days => 1)->toDatabaseDate,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $straddleLow = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Straddles the window, lower side',
startDate => $startDt->clone->subtract(hours => 12)->toDatabaseDate,
endDate => $startDt->clone->add(hours => 12)->toDatabaseDate,
startTime => $startDt->clone->subtract(hours => 12)->toDatabaseTime,
endTime => $startDt->clone->add(hours => 12)->toDatabaseTime,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $straddleHigh = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Straddles the window, higher side',
startDate => $endDt->clone->subtract(hours => 12)->toDatabaseDate,
endDate => $endDt->clone->add(hours => 12)->toDatabaseDate,
startTime => $endDt->clone->subtract(hours => 12)->toDatabaseTime,
endTime => $endDt->clone->add(hours => 12)->toDatabaseTime,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $justBefore = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Just before the window. Ending time coincident with window start',
startDate => $startDt->clone->subtract(hours => 1)->toDatabaseDate,
endDate => $startDt->toDatabaseDate,
startTime => $startDt->clone->subtract(hours => 1)->toDatabaseTime,
endTime => $startDt->toDatabaseTime,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $justAfter = $windowCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'Just after the window. Start time coincident with window end',
startDate => $endDt->toDatabaseDate,
endDate => $endDt->clone->add(hours => 1)->toDatabaseDate,
startTime => $endDt->toDatabaseTime,
endTime => $endDt->clone->add(hours => 1)->toDatabaseTime,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $tag2 = WebGUI::VersionTag->getWorking($session);
$tag2->commit;
WebGUI::Test->tagsToRollback($tag2);
is(scalar @{ $windowCal->getLineage(['children'])}, 9, 'added events to the window calendar');
my @window = $windowCal->getEventsIn($startDt->toDatabase, $endDt->toDatabase);
#diag $startDt->toDatabase;
#diag join "\n", map { join ' ', $_->get('title'), $_->get('startDate'), $_->get('startTime')} @window;
#diag $endDt->toDatabase;
is(scalar @window, 4, 'getEventsIn returned 4 events');
cmp_bag(
[ map { $_->get('title') } @window ],
[ map { $_->get('title') } ($inside, $inside2, $straddle, $straddleHigh)],
'..returns correct 4 events'
);
######################################################################
#
# viewWeek
#
######################################################################
my $weekCal = $node->addChild({
className => 'WebGUI::Asset::Wobject::Calendar',
title => 'Calendar for doing event span testing, week',
});
my $allDayDt = $bday->cloneToUserTimeZone;
my $allDay = $weekCal->addChild({
className => 'WebGUI::Asset::Event',
title => 'An event with explicit times that lasts all day',
startDate => $allDayDt->toDatabaseDate,
endDate => $allDayDt->clone->add(days => 1)->toDatabaseDate,
startTime => $allDayDt->clone->truncate(to => 'day')->toDatabaseTime,
endTime => $allDayDt->clone->add(days => 1)->truncate(to => 'day')->toDatabaseTime,
timeZone => $tz,
}, undef, undef, {skipAutoCommitWorkflows => 1});
my $tag3 = WebGUI::VersionTag->getWorking($session);
$tag3->commit;
WebGUI::Test->tagsToRollback($tag3);
my $allVars = $weekCal->viewWeek({ start => $bday });
my @eventBins = ();
foreach my $day (@{ $allVars->{days} }) {
if (exists $day->{events} and scalar @{ $day->{events} } > 0) {
push @eventBins, $day->{dayOfWeek};
}
}
cmp_deeply(
\@eventBins,
[ 4 ],
'viewWeek: all day event is only in 1 day when time zones line up correctly'
);
################################################################
#
# wrapIcal
@ -125,10 +290,3 @@ TODO: {
local $TODO = "Tests to make later";
ok(0, 'Lots more to test');
}
END {
# Clean up after thy self
$versionTag->rollback();
$secondVersionTag->rollback();
}