|
Server : Apache/2.4.62 System : FreeBSD fbsdweb2.web.rcn.net 14.1-RELEASE FreeBSD 14.1-RELEASE releng/14.1-n267679-10e31f0946d8 GENERIC amd64 User : www ( 80) PHP Version : 8.3.8 Disable Function : NONE Directory : /domains/compasssysweb/calendar/CalciumDir39/Operation/ |
Upload File : |
# Copyright 2000-2003 Fred Steinberg, Brown Bear Software
# Export Event data (to an html page)
package AdminExport;
use strict;
use CGI (':standard');
use Calendar::Date;
use Calendar::GetHTML;
use vars ('@ISA');
@ISA = ('Operation');
sub perform {
my $self = shift;
my ($save, $cancel, $isPopup) = $self->getParams (qw (Save Cancel
IsPopup));
my $cgi = new CGI;
my $calName = $self->calendarName;
if ($cancel) {
my $op = $calName ? ($isPopup ? 'AdminPageUser' : 'AdminPage')
: 'SysAdminPage';
print $self->redir ($self->makeURL({Op => $op}));
return;
}
my $prefs = $self->prefs;
my $i18n = $self->I18N;
my @exportedLines;
my @vEvents;
my ($format, $separator, $cookie);
if ($save) {
my ($fromYear, $fromMonth, $fromDay) =
@{$self->{params}}{qw (FromYearPopup
FromMonthPopup
FromDayPopup)};
my ($toYear, $toMonth, $toDay) =
@{$self->{params}}{qw (ToYearPopup
ToMonthPopup
ToDayPopup)};
$separator = @{$self->{params}}{'Separator'};
$format = @{$self->{params}}{'Format'};
my $errorMessage;
if (!Date->valid ($fromYear, $fromMonth, $fromDay)) {
$errorMessage = $i18n->get ('<br>Invalid <b>From</b> Date');
}
if (!Date->valid ($toYear, $toMonth, $toDay)) {
$errorMessage = $i18n->get ('<br>Invalid <b>To</b> Date');
}
if ($errorMessage) {
GetHTML->errorPage ($i18n,
header => $i18n->get ('Error exporting events'),
message => $errorMessage);
return;
}
my $fromDate = Date->new ($fromYear, $fromMonth, $fromDay);
my $toDate = Date->new ($toYear, $toMonth, $toDay);
if ($format =~ /^[iv]cal/) {
my ($regs, $repeats) = $self->db->getEventLists ($prefs, $fromDate,
$toDate);
require Calendar::EventvEvent;
require Calendar::vCalendar::vCalendar;
foreach my $date (_dateSort ([keys %$regs])) {
my $dateObj = Date->new ($date);
# foreach my $event (@{$regs->{$date}}) {
# my $includedFrom = $event->includedFrom;
# next if ($includedFrom and $includedFrom =~ /^ADDIN /);
# my $vEvent = $event->vEvent ($dateObj);
# push @vEvents, $vEvent;
# }
push @vEvents, map {$_->vEvent ($dateObj)} @{$regs->{$date}};
}
# foreach my $event (@$repeats) {
# my $includedFrom = $event->includedFrom;
# next if ($includedFrom and $includedFrom =~ /^ADDIN /);
# my $vEvent = $event->vEvent;
# push @vEvents, $vEvent;
# }
push @vEvents, map {$_->vEvent} @$repeats;
} else {
my $evHash = $self->db->getEventDateHash ($fromDate, $toDate,
$prefs);
my $lines = _getExportedLines ($evHash, $format, $separator);
@exportedLines = @$lines;
}
# Write cookie with prefs
$cookie = $cgi->cookie (-name => 'CalciumExportPrefs',
-value => "$separator-$format",
-expires => '+1y');
$self->{audit_formsaved}++;
$self->{audit_fromdate} = $fromDate;
$self->{audit_todate} = $toDate;
$self->{audit_eventcount} = @exportedLines;
}
# Get cookie vals for prefs
my $prefCookie = $cgi->cookie ('CalciumExportPrefs') || '';
my ($sepDefault, $formatDefault) = split '-', $prefCookie;
if (@vEvents) {
use Time::Local;
my $now = time;
my $utc = timegm (gmtime ($now));
my $local = timegm (localtime ($now));
my $hours = int (($local - $utc) / 3600) - ($prefs->Timezone || 0);
if ($hours) {
foreach (@vEvents) {
$_->convertToUTC ($hours);
}
}
my ($version, $extension) = ('2.0', 'ics');
if ($format =~ /^vcal/) {
($version, $extension) = ('1.0', 'vcs');
}
my $vCal = vCalendar->new (events => \@vEvents,
version => $version);
my $type = 'text/calendar';
my $filename = "CalciumEvents.$extension";
if ($format eq 'vcal_text') {
$type = 'text/x-Calcium-Events';
$filename = 'CalciumEvents.txt';
}
print $cgi->header (-type => $type,
'-Content-disposition' => "filename=$filename",
-cookie => $cookie);
print $vCal->textDump (METHOD => 'PUBLISH');
# print $vCal->textDump;
return;
}
if (@exportedLines) {
print $cgi->header (-type => 'text/x-Calcium-Events',
'-Content-disposition' =>
'filename=CalciumEvents.txt',
-cookie => $cookie);
if ($format =~ /msoutlook/i) {
$separator = "\t" if ($separator eq 'TAB');
print join $separator, ('"Subject"',
'"Start Date"',
'"Start Time"',
'"End Date"',
'"End Time"',
'"All day event"',
'"Description"');
print "\n";
}
print join "\n", @exportedLines;
return;
}
print $cgi->header;
print $cgi->start_html ('-title' =>
$i18n->get ('Export Event Data') .
": $calName",
'-bgcolor' => 'white');
print '<center>';
print GetHTML->AdminHeader (I18N => $i18n,
cal => $calName,
section => 'Export Event Data');
print '<br>';
if ($save and !@exportedLines) {
print $cgi->p ($cgi->font ({color => 'red'},
$i18n->get ("No events were found in the " .
"specified date range!")));
}
print $i18n->get ('Data for Events between the specified dates ' .
'will be exported.');
print '</center>';
my $script = <<' END_JAVASCRIPT';
: <SCRIPT LANGUAGE="JavaScript">
: <!-- start
: // Make sure dates are OK (or cancel pressed)
: function submitCheck (theForm, baseYear) {
: if (theForm.Cancel.pressed) {
: return true;
: }
: fromMonth = theForm.FromMonthPopup.selectedIndex;
: fromDay = theForm.FromDayPopup.selectedIndex + 1;
: fromYear = theForm.FromYearPopup.selectedIndex + baseYear;
: toMonth = theForm.ToMonthPopup.selectedIndex;
: toDay = theForm.ToDayPopup.selectedIndex + 1;
: toYear = theForm.ToYearPopup.selectedIndex + baseYear;
: fromDate = new Date (fromYear, fromMonth, fromDay);
: toDate = new Date (toYear, toMonth, toDay);
: gotMonth = fromDate.getMonth();
: gotDay = fromDate.getDate();
: if (gotMonth != fromMonth || gotDay != fromDay) {
: alert ('From Date is invalid.');
: return false;
: }
: gotMonth = toDate.getMonth();
: gotDay = toDate.getDate();
: if (gotMonth != toMonth || gotDay != toDay) {
: alert ('To Date is invalid.');
: return false;
: }
: if (fromDate.valueOf() > toDate.valueOf()) {
: alert ('To Date cannot be before From Date.');
: return false;
: }
: return true;
: }
: // End -->
: </SCRIPT>
END_JAVASCRIPT
$script =~ s/^\s*:\s*//mg;
print $script;
my ($yearStart, $yearEnd, $earliestDate);
$yearStart = Date->new;
$yearStart->month(1);
$yearStart->day(1);
$yearEnd = Date->new ($yearStart)->addYears (1) - 1;
$earliestDate = Date->new ($yearStart);
$earliestDate->addYears(-10);
my $Format_Help = $i18n->get ('AdminExport_FormatHelp');
if ($Format_Help eq 'AdminExport_FormatHelp') {
($Format_Help =<<' ENDHELP') =~ s/^ +//gm;
This option specifies how the data will be printed.\n\n
'iCalendar' format is used by Mozilla, Apple's iCal, and other\n
calendar systems. 'iCalendar -file' will download as a plain ASCII\n
file, while 'iCalendar' will download as type text/calendar.\n\n\n
'vCalendar' is like iCalendar, but is the older version 1.0, mainly
for Palm Desktop compatibility.\n\n
'Calcium' or 'MS Outlook' specifies the fields and order.\n\n
Calcium:\n
Date Text Link_or_Popup Start_Time End_Time\n
Border? BG_Color FG_Color Export Owner_Name\n
Category Included_From_Calendar\n\n
MS Outlook:\n
Text Date Start_Time Date End_Time All_Day_Event?\n
Link_or_Popup\n\n
'European' prints dates as DD/MM/YYYY (e.g. 31/01/2000),\n
and times in 24-hour format.\n\n
'USA' prints dates as MM/DD/YYYY (e.g. 01/31/2000),\n
and times in 12-hour format, with 'am' or 'pm' in a separate\n
field.
ENDHELP
}
$Format_Help =~ s/'/\\'/g; #"'
my $url = $cgi->url (-absolute => 1, -path_info => 1, -query => 1);
# $url =~ s{\?}{/CalciumEvents?};
print $cgi->startform (-action => $url,
-onSubmit =>
"return submitCheck(this, $earliestDate)");
my $fromPopup = GetHTML->datePopup ($i18n,
{name => 'From',
default => $yearStart,
start => $earliestDate,
numYears => 20});
my $toPopup = GetHTML->datePopup ($i18n,
{name => 'To',
# default => Date->new - 1,
default => $yearEnd,
start => $earliestDate,
numYears => 20});
my ($usa, $euro) = ($i18n->get ('USA'), $i18n->get ('European'));
print $cgi->table ($cgi->Tr ($cgi->td ($cgi->b ($i18n->get ('From:'))),
$cgi->td ({-colspan => 2}, $fromPopup)),
$cgi->Tr ($cgi->td ($cgi->b ($i18n->get ('To:'))),
$cgi->td ({-colspan => 2}, $toPopup)),
$cgi->Tr ($cgi->td ($cgi->b
($i18n->get ('Field Separator:'))),
$cgi->td ($cgi->popup_menu (
-name => 'Separator',
-default => $sepDefault,
-Values => [',', ' ', 'TAB',';'],
-labels => {',' =>
$i18n->get ('Comma'),
' ' =>
$i18n->get ('Space'),
'TAB' =>
$i18n->get ('Tab'),
';' =>
$i18n->get ('Semicolon'),
})),
$cgi->td ($cgi->font ({-size => -1}, '(' .
$i18n->get ('Separators in ' .
'the actual data will be ' .
'preceded by a backslash. ') .
$i18n->get ('Ignored for vCalendar')
. ')'))),
$cgi->Tr ($cgi->td ($cgi->b
($i18n->get ('Format:'))),
$cgi->td ($cgi->popup_menu (
-name => 'Format',
-default => $formatDefault,
-Values => ['usa', 'euro',
'vcal', 'vcal_text',
'ical', 'ical_text',
'msoutlook-usa',
'msoutlook-euro'],
-labels =>
{'usa' => "Calcium - $usa",
'euro' => "Calcium - $euro",
'vcal' => "vCalendar",
'vcal_text' => 'vCalendar - file',
'ical' => "iCalendar",
'ical_text' => 'iCalendar - file',
'msoutlook-usa' => "MS Outlook - $usa",
'msoutlook-euro' => "MS Outlook - $euro",
})),
$cgi->td ($cgi->a ({href =>
"JavaScript:alert (\'$Format_Help\')"},
$i18n->get ('What does this mean?')))));
my $string = $i18n->get ('AdminExport_Instructions');
if ($string eq 'AdminExport_Instructions') {
print '<ul><li>';
print $i18n->get ('Each occurrence of a Repeating Event will be ' .
'exported as a separate line of data.');
print ' ' . $i18n->get ('(Except for vCalendar format.)');
print '</ul>';
} else {
print $string;
}
print '<hr width="50%">';
my $subscribeURL = $self->makeURL ({FullURL => 1,
PlainURL => 1,
Op => 'iCalSubscribe'});
$subscribeURL =~ s/^http/webcal/;
$subscribeURL .= '&x=1'; # Apple might tack on an .ics or some such
print '<center>';
print $i18n->get ("If your browser understands the 'webcal' protocol,") .
'<br>' . $i18n->get ('you can') . ' ';
print $cgi->a ({href => $subscribeURL},
$i18n->get ('"Subscribe" to this calendar'));
print '</center>';
print '<hr>';
print $cgi->submit (-name => 'Save',
-value => $i18n->get ('Download Events'));
print ' ';
print $cgi->submit (-name => 'Cancel',
-value => $i18n->get ('Done'),
-onClick => 'this.pressed = true');
print ' ';
print $cgi->reset (-value => $i18n->get ('Reset Dates'));
print $cgi->hidden (-name => 'Op', -value => 'AdminExport');
print $cgi->hidden (-name => 'CalendarName', -value => $calName);
print $self->hiddenDisplaySpecs;
print $cgi->endform;
print $cgi->end_html;
}
sub _getExportedLines {
my ($evHash, $format, $separator) = @_;
my @lines;
my $escapeIt = 1;
if ($separator eq 'TAB') {
$separator = "\t";
undef $escapeIt;
}
foreach my $date (map {$_->[0]}
sort {$AdminExport::a->[1] <=> $AdminExport::b->[1]}
map {[$_, Date->new ($_)->_toInt]} keys %$evHash) {
foreach (@{$evHash->{$date}}) {
my $includedFrom = $_->includedFrom;
next if ($includedFrom and $includedFrom =~ /^ADDIN /);
my ($y, $m, $d) = split '/', $date;
$m = "0$m" if $m < 10;
$d = "0$d" if $d < 10;
my ($starth, $startm, $endh, $endm);
if (defined $_->startTime) {
$starth = int ($_->startTime / 60);
$startm = $_->startTime % 60;
$startm = "0$startm" if $startm < 10;
}
if (defined $_->endTime) {
$endh = int ($_->endTime / 60);
$endm = $_->endTime % 60;
$endm = "0$endm" if $endm < 10;
}
my ($theDate, $startTime, $endTime,
$start_meridian, $end_meridian);
my $isUSA = ($format =~ /usa/i);
if ($isUSA) {
$theDate = "$m/$d/$y";
if (defined ($starth)) {
$start_meridian = $starth < 12 ? 'am' : 'pm';
$starth = 12 if ($starth == 0);
$starth -= 12 if ($starth > 12);
$startTime = "$starth:$startm";
}
if (defined ($endh)) {
$end_meridian = $endh < 12 ? 'am' : 'pm';
$endh = 12 if ($endh == 0);
$endh -= 12 if ($endh > 12);
$endTime = "$endh:$endm";
}
} else {
if ($separator eq ';') {
$theDate = "$d.$m.$y";
} else {
$theDate = "$d/$m/$y";
}
$startTime = "$starth:$startm" if defined ($starth);
$endTime = "$endh:$endm" if defined ($endh);
}
local $^W = 0; # don't warn about undefs
my @fields;
if ($format =~ /msoutlook/i) {
my ($start, $end);
$start = "$startTime:00 \U$start_meridian" if ($startTime);
$end = "$endTime:00 \U$end_meridian" if ($endTime);
@fields = ($_->escapedText ($escapeIt),
$theDate,
$start,
$theDate,
$end,
$start ? 'False' : 'True',
$_->link || $_->escapedPopup ($escapeIt),
);
map {$_ = "\"$_\"" if defined} @fields;
} else {
my (@start, @end);
push @start, $startTime; # yes, even if undef
push @start, $start_meridian if $isUSA;
push @end, $endTime;
push @end, $end_meridian if $isUSA;
@fields = ($theDate,
$_->escapedText ($escapeIt),
$_->link || $_->escapedPopup ($escapeIt),
@start, # list because might have am or pm
@end,
$_->drawBorder ? '1' : '',
$_->bgColor,
$_->fgColor,
$_->export,
$_->owner,
$_->category,
$_->includedFrom);
foreach (@fields) { # escape things that need escaping
# s/($separator|['"])/\\$1/go; # ' ])
if ($separator ne "\t") {
s/($separator)/\\$1/g;
s/(['"])/\\$1/g; # ' ])
} else {
s/\t/\\t/g;
}
# s/<br>/\\\\n/g; # need \\n in the output file
s/<br>/\\n/g; # just put '\' and 'n' in output file
}
}
push @lines, (join $separator, @fields);
}
}
\@lines;
}
# Return sorted list of dates in hash
sub _dateSort {
my $dates = shift;
return map {$_->[0]}
sort {$AdminExport::a->[1] <=> $AdminExport::b->[1]}
map {[$_, Date->new ($_)->_toInt]}
@$dates;
}
sub auditString {
my ($self, $short) = @_;
return unless $self->{audit_formsaved};
my $line = $self->SUPER::auditString ($short);
return "$line $self->{audit_fromdate}-$self->{audit_todate} " .
"$self->{audit_eventcount} events";
}
1;