|
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 1999-2003, Fred Steinberg, Brown Bear Software
# Create a New Event
package EventNew;
use strict;
use CGI;
use Calendar::Date;
use Calendar::GetHTML;
use Calendar::ValidateDate;
use vars ('@ISA');
@ISA = ('Operation');
sub perform {
my $self = shift;
my ($date, $eventText, $popupText, $export,
$border, $bgColor, $fgColor, $category,
$mailTo, $mailCC, $mailBCC, $mailText,
$reminderTime, $reminderTime2, $reminderAddress,
$ignoreConflict, $ignoreFuture, $editedEventID, $copying,
$singleInstanceOfRepeater,
$displayCal, $viewCal, $displayDate) =
$self->getParams (qw (Date EventText PopupText
ExportPopup BorderCheckbox
BackgroundColor ForegroundColor
Category
MailTo MailCC MailBCC
MailComments MailReminder
MailReminder2 ReminderAddress
IgnoreTimeConflict
IgnoreFutureLimit
OldEventID CopyEvent
SingleRepeatingInstance
DisplayCal ViewCal DisplayDate));
my $cgi = CGI->new;
my @whichCals = $cgi->param ('WhichCalendars');
push @whichCals, $self->calendarName unless @whichCals;
if ($cgi->param ('Cancel')) {
$self->{audit_formcancelled}++;
my $theUrl = $cgi->param ('NextOp');
print $self->redir ($theUrl);
return;
}
my $action = $editedEventID ? 'Replacing' : 'Adding New';
if ($copying) {
$action = 'Copying';
undef $editedEventID;
}
# If multi-cal enabled, ensure at least 1 calendar selected
if ($self->getParams ('MultiCalDisplayed') and
!$cgi->param ('WhichCalendars')) {
my $errorMessage = $self->I18N->get ('You must select at least ' .
'one calendar') . '<br>';
$self->_errorPage ($action, $errorMessage);
$self->{audit_error} = 'no calendar specified';
return;
}
my ($eventDate, $startTime, $endTime, $timePeriod, $endDate, $dateChange,
$errorMessage) = ValidateDate->getAndValidateDateAndTimes ($self);
my $localDate = $eventDate - $dateChange;
# Check for event in the past
if ($self->prefs->NoPastEditing and $localDate < Date->new) {
$self->_errorPage ($action,
$self->I18N->get ('Cannot add past event!') .
'<br><br>' .
$self->I18N->get ('This calendar does not allow ' .
'creating or editing events ' .
"before today's date.") .
'<br>');
$self->{audit_error} = 'past event';
return;
}
# Strip leading/trailing spaces from strings coming from text fields
foreach ($eventText, $popupText, $bgColor, $fgColor,
$mailTo, $mailCC, $mailBCC, $mailText) {
next unless defined;
s/^\s+//;
s/\s+$//;
}
unless ($eventText) {
$self->_errorPage ($action,
$self->I18N->get ('You cannot create a blank event')
. '<br>');
$self->{audit_error} = 'blank event';
return;
}
if ($errorMessage) {
$self->_errorPage ($action, $errorMessage);
$self->{audit_error} = 'bad date or time';
return;
}
# if reminders specified, must have email address
if (($reminderTime or $reminderTime2) and !$reminderAddress) {
$self->_errorPage ($action,
$self->I18N->get ('You must specify an email ' .
'address if Email Reminders ' .
'are specified.')
. '<br>');
$self->{audit_error} = 'reminder w/no address';
return;
}
my ($link, $popup);
# If the popup looks like a URL, we call it a link. Otherwise, a popup!
# Note that this is not a very good test. But probably good enough.
# (Basically, anything that is www.x.x, or starts http:, mailto:, ftp:,
# etc.)
($popup, $link) = Event->textToPopupOrLink ($popupText);
foreach ($bgColor, $fgColor) {
next unless defined;
s/\s*default\s*//i; # If colors are 'Default', get rid of 'em
s/\W//g; # And ensure there's nothing silly going on
$_ = ('#' . $_) if /^\d+$/; # And prepend numerics with the #
}
$category = undef if ($category and $category eq '-');
my ($repeatObject);
my ($repeatType) = $self->getParams ('RepeatRadio');
# Handle repeat stuff, maybe
if (!$repeatType || $repeatType =~ /none/i || $repeatType eq '') {
$repeatObject = undef;
} else {
my ($frequency, $period, $monthWeek, $monthMonth,
$untilRadio, $untilYear, $untilMonth, $untilDay, $skipWeekends) =
$self->getParams (qw (Frequency Period MonthWeek MonthMonth
RepeatUntilRadio UntilYearPopup
UntilMonthPopup UntilDayPopup
SkipWeekends));
if ($repeatType =~ /ByWeek/i) {
$period = $frequency = undef;
} else { # it must be Repeat Every Third Day type
$monthWeek = $monthMonth = undef;
}
$repeatObject = RepeatInfo->new ($eventDate, $endDate,
$period, $frequency,
$monthWeek, $monthMonth,
$skipWeekends);
# If we got here from modifing a repeating event, check for exclusions
my ($exclusionString) = $self->getParams ('ExcludedDates');
if ($exclusionString) {
my @excludedDates;
my @excludedStrings = split /\s/, $exclusionString;
foreach my $excludedDate (@excludedStrings) {
push @excludedDates, Date->new ($excludedDate);
}
$repeatObject->exclusionList (\@excludedDates);
}
# if date was changed by timezone offset, and we're repeating by
# particular days of the week, adjust the days. Yow!
if ($dateChange and ref ($repeatObject->period)) {
foreach my $day (@{$repeatObject->period}) {
$day += $dateChange; # 1-7
if ($day < 1 or $day > 7) {
$day = $day % 7;
$day ||= 7;
}
}
}
}
my $reminders = ($reminderTime || '') . ' ' . ($reminderTime2 || '');
$reminders =~ s/^\s//;
$reminders =~ s/\s$//;
$reminderAddress = undef unless $reminders; # since it has a default
# make the new event
my $newEvent = Event->new ('text' => $eventText,
'link' => $link,
'popup' => $popup,
'export' => $export,
'startTime' => $startTime,
'endTime' => $endTime,
'timePeriod' => $timePeriod,
'repeatInfo' => $repeatObject,
'drawBorder' => $border,
'owner' => $self->getUsername,
'bgColor' => $bgColor,
'fgColor' => $fgColor,
'category' => $category,
'mailTo' => $mailTo,
'mailCC' => $mailCC,
'mailBCC' => $mailBCC,
'mailText' => $mailText,
'reminderTo' => $reminderAddress,
'reminderTimes' => $reminders);
# if modifying or copying, copy subscribers
my ($subscribers) = $self->getParams ('Subscribers');
$newEvent->subscriptions ($subscribers) if ($subscribers);
if (@whichCals > 1) {
my @badFuture;
foreach my $thisCal (@whichCals) {
my $prefs = Preferences->new ($thisCal);
my $vd = ValidateDate->futureCheck ($prefs, $eventDate,
$endDate, $ignoreFuture);
push @badFuture, $thisCal if $vd->isBad;
}
if (@badFuture) {
$self->_errorPage ($action, "Sorry, the event is too far in the
future for these calendars: " .
join (', ', @badFuture));
$self->{audit_error} = 'future limit';
return;
}
} else {
my $thisCal = $whichCals[0];
my $prefs = Preferences->new ($thisCal);
my $vd = ValidateDate->futureCheck ($prefs, $eventDate,
$endDate, $ignoreFuture);
if ($vd->isBad) {
$self->_errorPage ($action, $vd->futureMessage ($self, $thisCal,
$self->I18N),
$vd->isWarning);
$self->{audit_error} = 'future limit';
return;
}
}
# Make sure repeating stuff actually makes sense
if ($repeatObject) {
my $instances = $repeatObject->nextNOccurrences ($newEvent, 1,
$eventDate,
$self->prefs);
unless (keys %$instances) {
$self->_errorPage ($action,
$self->I18N->get ('The specified repeat ' .
'options don\'t define ' .
'any actual instances.'));
$self->{audit_error} = 'repeating w/no instances';
return;
}
}
# If we're checking Time Conflicts and adding a repeating event, we
# have to check on every occurrence. Ugh! Don't do "forever", though;
# only check max of 5 years into the future.
my $prefs = $self->prefs;
if ($repeatObject and defined $startTime and
$prefs->TimeConflicts !~ /allow/i) {
my $occurences = {};
my $endDate = $repeatObject->endDate;
if ($repeatObject->startDate->deltaDays ($endDate) > 365*5) {
$endDate = $repeatObject->startDate + 365*5;
}
$newEvent->addToDateHash ($occurences, $repeatObject->startDate,
$endDate, $self->prefs);
my (%prefs, %dbs);
foreach my $thisCal (@whichCals) {
$prefs{$thisCal} = Preferences->new ($thisCal);
$dbs{$thisCal} = Database->new ($thisCal);
}
foreach my $date (sort {Date->new($a) <=> Date->new($b)}
keys %$occurences) {
my $dobj = Date->new ($date);
foreach my $thisCal (@whichCals) {
my $tc = ValidateDate->timeConflict ($dbs{$thisCal},
$prefs{$thisCal},
$dobj, $startTime,
$endTime, $editedEventID,
$ignoreConflict);
if ($tc->isBad) {
$errorMessage = $tc->conflictMessage ($self,
@whichCals == 1
? undef
: $thisCal);
$self->_errorPage ($action, $errorMessage, $tc->isWarning);
$self->{audit_error} = 'time conflict';
return;
}
}
}
} else {
foreach my $thisCal (@whichCals) {
my $db = Database->new ($thisCal);
my $prefs = Preferences->new ($thisCal);
my $tc = ValidateDate->timeConflict ($db, $prefs, $eventDate,
$startTime, $endTime,
$editedEventID,
$ignoreConflict);
if ($tc->isBad) {
$errorMessage = $tc->conflictMessage ($self,
@whichCals == 1
? undef
: $thisCal);
$self->_errorPage ($action, $errorMessage, $tc->isWarning);
$self->{audit_error} = 'time conflict';
return;
}
}
}
# keep track of things in case we're auditing
$self->{audit_calendars} = [sort {lc($a) cmp lc($b)} @whichCals];
$self->{audit_event} = $newEvent;
$self->{audit_eventDate} = $eventDate;
# Stick it in the database(s)
foreach my $thisCal (@whichCals) {
my $db = Database->new ($thisCal);
# Set "tentative" flag
if (Preferences->new ($thisCal)->TentativeSubmit and
!Permissions->new ($db)->permitted ($self->getUsername, 'Edit')) {
$newEvent->isTentative (1);
$self->{audit_tentative} = $thisCal;
} else {
$newEvent->isTentative (0);
$self->{audit_tentative} = undef;
}
if (defined $editedEventID and !$copying
and !$singleInstanceOfRepeater) {
$newEvent->id ($editedEventID);
# (already deleted in EventReplace.pm)
$db->replaceEvent ($newEvent, $eventDate, 'noDelete');
} else {
$db->insertEvent ($newEvent, $eventDate);
}
# Do auditing for `other' calendars
if ($thisCal ne $self->calendarName) {
my @auditTypes = $db->getAuditing ('Add');
foreach (@auditTypes) {
AuditFactory->create ($_)->perform ($self, $db);
}
}
}
# maybe send email notifications
if ($mailTo or $mailCC or $mailBCC) {
require Calendar::Mail::MailNotifier;
MailNotifier->send ($self, $newEvent, $eventDate, $editedEventID);
}
# maybe remember to remind
if (Defines->mailEnabled and $reminders) {
require Calendar::Mail::MailReminder;
MailReminder->add ($newEvent, $self->calendarName, $eventDate);
}
my $showDate;
if (defined ($editedEventID)) {
$showDate = $displayDate ? Date->new ($displayDate) : $eventDate;
} else {
$showDate = $newEvent->getDisplayDate ($eventDate,
$self->prefs->Timezone);
}
# And redirect to the page to display.
my $theURL;
my $nextOp = $cgi->param ('NextOp');
if ($nextOp ne 'ShowDay') {
$theURL = $nextOp;
} else {
$theURL = $self->makeURL ({Op => 'ShowDay',
Date => $showDate,
CalendarName => $displayCal,
ViewCal => $viewCal,
Splunge => time}); # needed as workaround
}
print $self->redir ($theURL);
}
sub _errorPage {
my ($self, $action, $message, $isWarning) = @_;
my $title = ($isWarning ? "Warning while $action Event"
: "Error $action Event");
GetHTML->errorPage ($self->I18N,
header => $self->I18N->get ($title),
message => $message,
isWarning => $isWarning);
return;
}
# Override audit, since we need to handle special AddTentative case
sub auditType {
my $self = shift;
my $type = $self->{audit_tentative} ? 'AddTentative' : 'Add';
return $type;
}
sub auditString {
my ($self, $short) = @_;
return if $self->{audit_formcancelled};
my $line = $self->SUPER::auditString ($short);
return ($line . ' ERROR - ' . $self->{audit_error})
if $self->{audit_error};
my $event = $self->{audit_event};
if ($short) {
my $text;
if ($event) {
$text = $event->text;
$text =~ s/\n/\\n/g;
$text = $self->{audit_eventDate} . ' ' . $text;
$text .= ' [tentative]' if $self->{audit_tentative};
} else {
$text = 'ERROR - ' . $self->{audit_error};
}
return $line . ' ' . $text;
}
my ($text, $extra);
($text = $event->text) =~ s/
//g;
($extra = $event->popup || $event->link || '') =~ s/
//g;
$extra = "Popup text: $extra" if ($event->popup);
$extra = "URL:\t$extra" if ($event->link);
# make a string
my $message;
if ($self->{audit_calendars} and @{$self->{audit_calendars}} > 1) {
$message = "Calendar Names:\t" .
join (', ', @{$self->{audit_calendars}}) . "\n";
} else {
$message = "Calendar Name:\t" . $self->calendarName . "\n";
}
$message .= "Date:\t$self->{audit_eventDate}\n";
if (defined $event->startTime) {
$message .= "Time:\t" . $event->getTimeString ('both', $self->prefs)
. "\n";
}
$message .= "Type:\t" . $event->export . "\n\n";
$message .= "Text:\t$text\n" . $extra . "\n\n";
$message .= "Category: \t" . $event->category . "\n"
if defined $event->category;
$message .= "Border: \t" . ($event->drawBorder ? 'yes' : 'no') . "\n";
$message .= "Foreground:\t" . ($event->fgColor || 'Default') . "\n" .
"Background:\t" . ($event->bgColor || 'Default') . "\n";
if ($event->isRepeating) {
my $rep = $event->repeatInfo;
$message .= "\nThis is a Repeating Event\n";
$message .= "Start Date:\t" . $rep->startDate . "\n";
$message .= "End Date: \t" . ($rep->endDate == Date->openFuture ?
'None' : $rep->endDate);
$message .= "\n";
if ($rep->period) {
$message .= 'Every ';
# period is either single amount, or ref to list of days of week
if (!ref ($rep->period)) {
my $period = $rep->period;
$period = 'day' if ($period eq 'dayBanner');
if ($rep->frequency == 1) {
$message .= $period . "\n";
} else {
$message .= $rep->frequency . ' ' . $period . "s\n";
}
}
else {
my @days = map {Date->dayName ($_)} @{$rep->period};
my @nth = (' ', 'st', 'nd', 'rd', 'th');
my $nth = ' ';
if ($rep->frequency > 1) {
$nth = $nth[$rep->frequency];
$nth = 'th' unless defined ($nth);
$nth = $rep->frequency . $nth . ' ';
}
$message .= $nth . (join ', ', @days) . "\n";
}
} else {
my %text = (1 => '1st',
2 => '2nd',
3 => '3rd',
4 => '4th',
5 => 'last',
6 => 'fifth (if there is a fifth)');
my $mw = join ', ', map {$text{$_}} @{$rep->monthWeek};
my $day = Date->dayName ($rep->monthDay);
my $mm = ($rep->monthMonth || 1) != 1 ? ' ' . $rep->monthMonth
: '';
$message .= "$mw $day of every$mm month\n";
}
$message .= " (Skip Weekends)\n" if $rep->skipWeekends;
}
my $tent = '';
if ($self->{audit_tentative}) {
my $owner = $event->owner || 'an anonymous user';
$tent .= "A Event requiring approval was added by $owner.\n";
$tent .= "Calendar: " . $self->{audit_tentative} . "\n\n";
my $url = $self->makeURL ({FullURL => 1,
CalendarName => $self->{audit_tentative},
Op => 'ApproveEvents'});
$tent .= "Follow this link for the approval form:\n $url\n\n\n";
}
return $tent . $message . "\n\n$line";
}
1;