#!/usr/bin/perl
#
# shiva.pl -- Shiva scheduling program
#
# (c) Copyright 2007 Software Garden, Inc.
# All Rights Reserved.
# Subject to Software License at the end of this file
#
#
# Access with:
#
# http://www.domain.com/cgi-bin/shiva.pl
#
# This program may create the following files:
#
# shivadata.txt - Non-default string settings. See save_shivadata for format.
# Note: Includes admin password in clear text.
#
# *.set directories, each with:
#
# event.txt - Contains event set data for event set "setname" in dir setname.set.
# See load_set routine below for data format.
#
# person.n.txt - Name and event sign up data for person number "n".
# See load_people routine below for data format.
#
# All files are in text format, so their operation should be easy to discover,
# and problems fixable.
#
#
# Do uses
#
use strict;
use CGI qw(:standard);
#
# Define some variables
#
#
# Here are the program name strings for display when executing.
#
our $programversion = "0.9"; # The version information string
our $programmark = "Shiva"; # This is the main trademark for the product. Change if required by trademark law.
our $programname = "$programmark $programversion"; # Change name if required by trademark usage. This is where the version is indicated.
our $SGIfootertext = <<"EOF";
Shiva Program (c) Copyright 2007 Software Garden, Inc.
All Rights Reserved.
The original version of this program is from Software Garden.
EOF
# Strings
#
# For each string add to @stringinfo:
# [$snum][$stringname] = short name for lookup
# [$snum][$stringfullname] = full name
# [$snum][$stringtype] = type: $stringtypesingleline, $stringtypemultiline
# [$snum][$stringdesc] = description (HTML)
# [$snum][$stringdefault] = default value
#
# The order here is the order listed in edit lists
# Access using String Name Lookup ($snl): $stringinfo[$snl{stringname}][valuetype]
# Stringnames starting with "admin" are only settable on the main admin page, not for each event set
my $stringname = 0;
my $stringfullname = 1;
my $stringtype = 2;
my $stringdesc = 3;
my $stringdefault = 4;
my $stringtypesingleline = 1;
my $stringtypemultiline = 2;
my @stringinfo = (
["adminpassword", "Administrator Password", $stringtypesingleline,
"This is the password for logging into the Administration part of the program.
If you change it here you will have to login again with the new password.
If you forget the password, the person who set up this system may be able
to reset it for you.
The default value is no password,
so you should set it to something not easy for people to guess.",
""
],
["adminpageheading", "Heading at the top of all pages", $stringtypesingleline,
"This is the text that appears at the top of each page in large type and as the page title for the browser.",
'Shiva Signup Program'
],
["admininitialpageinstructions", "Initial page instructions", $stringtypemultiline,
"Instructions above the list of sets of events that a normal user may choose from when no set has been chosen.
May include special markup commands.",
'Select the set of events for which you wish to sign up:'
],
["adminchoosebutton", "Choose buttons on initial page", $stringtypesingleline,
"The text on the Choose buttons on the page with the list of sets of events visible to a normal user.",
'Choose'
],
["adminloginbutton", "Admin Login button on initial page", $stringtypesingleline,
"The text on the Admin Login button on the page with the list of sets of events visible to a normal user.",
'Admin Login'
],
["admininitialpagefooting", "Initial page footer", $stringtypemultiline,
"Text at the bottom of the list of sets of events visible to a normal user.
This may include information about the organization running this website.
May include special markup commands.",
''
],
["adminnosets", "No Sets To List Message", $stringtypesingleline,
"The text displayed when there are no sets listed on the page with the list of sets of events visible to a normal user.",
'*** No events available for signup at this time ***'
],
["adminlogininstructions", "Login page instructions", $stringtypemultiline,
"Instructions on the administration login page. May include special markup commands.",
'Login here to create new events, etc.'
],
["adminmaptext", "Map link text", $stringtypesingleline,
'The text that appears as a link to a map when using the "[map:...]" special markup command.',
'Map'
],
["admintimeoffset", "Time offset", $stringtypesingleline,
'The number of hours to add to the time displayed at the bottom of each page and on backup listings to adjust for
differences in time settings between the web server and local time for users.
(For example, the server is in Eastern Time Zone Atlanta, and users are in Central Time Zone Chicago.)
This is for cosmetic purposes only, and just affects what is displayed.
It must be just a number with an optional plus or minus sign.
(Note: It does not change the time display on the first screen after it is changed, just ones after that.)',
'0'
],
["topinstructionsnew", "Signup top instructions (new signup)", $stringtypemultiline,
"Instructions above the Events section on the normal signup sheet
when normally showing the signup page. May include special markup commands.",
'Select the events you plan to attend below, enter your name and party size in the space below them, and then press the "Save" button below:'
],
["topinstructionsold", "Signup top instructions (editing person)", $stringtypemultiline,
"Instructions above the Events section on the normal signup sheet
when editing an existing person's information. May include special markup commands.",
'Make any changes to the events you plan to attend below, make any changes to your name and party size in the space below them, and then press the "Save" button:'
],
["eventsectiontitle", "Signup Event section title", $stringtypesingleline,
"The main title of the section listing the events.",
"Events"
],
["eventheaderdescattendee", "Signup Event heading: Description/Attendee", $stringtypesingleline,
"The heading on the event description/attendee column.",
"Description / Attendees"
],
["eventheadercount", "Signup Event heading: Counts", $stringtypesingleline,
"The heading on the event column listing the counts of attendees signed up.",
"Counts"
],
["signupattending", "Signup checkbox text", $stringtypesingleline,
"The text that goes next to the checkbox indicating that the person is attending the event.",
"Attending"
],
["signupactiontitlenew", "Signup action title (new signup)", $stringtypesingleline,
"The title below the events on the signup page above the name and count.",
"Attendee to Add:"
],
["signupactiontitleold", "Signup action title (editing person)", $stringtypesingleline,
"The title below the events on the signup page above the name and count.",
"Editing Attendee:"
],
["signupname", "Signup: name", $stringtypesingleline,
"The text to the left of the textbox in which to type the person's name.",
"Name:"
],
["signupnumpeople", "Signup: number of people", $stringtypesingleline,
"The text to the left of the radio buttons for selecting the number of people attending an event.",
"Number of People:"
],
["signupsavemsg", "Signup save message", $stringtypemultiline,
"This is the text above the signup Save button. May include special markup commands.",
"Make sure you have selected the events you are planning to attend before saving!"
],
["signupsavingbuttonnew", "Signup Save button (new signup)", $stringtypesingleline,
"The text on the signup Save button when normally showing the signup page.",
"Save"
],
["signupsavingbuttonold", "Signup Save button (editing person)", $stringtypesingleline,
"The text on the signup Save button for saving an update to an existing person being edited.",
"Save"
],
["signupcancelbutton", "Signup Cancel button", $stringtypesingleline,
"The text on the signup Cancel button.",
"Cancel"
],
["signupbottominstructions", "Signup bottom instructions", $stringtypemultiline,
"Instructions before the People section on the signup page. May include special markup commands.",
"Click on the Edit button next to the entry for which you wish to make changes:"
],
["peoplesectiontitle", "Signup People section title", $stringtypesingleline,
"The title of the section listing people by name with edit buttons.",
"People"
],
["peoplenamecolumn", "Signup People heading: Name", $stringtypesingleline,
"The heading on the column of names of people who have signed up, sorted by name.",
"Name"
],
["peoplepeoplecolumn", "Signup People heading: People", $stringtypesingleline,
"The heading on the column of showing the numbers of persons represented by each name.",
"People"
],
["peopleattendingcolumn", "Signup People heading: Attending", $stringtypesingleline,
"The heading on the column listing the short names of the events for which each person has signed up.",
"Attending"
],
["peopleeditbutton", "Signup People Edit button", $stringtypesingleline,
"The text on the Edit button on each line in the people list.",
"Edit"
],
["adminpagetemplate", "Page HTML template", $stringtypemultiline,
'This advanced feature is the template used to create the HTML that makes up the web page.
It includes all of the text that is static on the page.
The string "{pagecontents}" in this text is replaced by the contents of the page created
dynamically by this program and {pagetitle} is replaced by the "Heading at the top of all pages" value.
The default value includes the CSS classes that may be customized to change the look of the output.
Only change this value if you are familiar with HTML and using templates of this type.
',
<<"EOF"
{pagetitle}
{pagecontents}
EOF
],
);
my %snl; # String Name Lookup -- filled in automatically from @strings
my $maxcountbuttons = 10;
# Program common values
my (@personname, %personnumber, @personevents, @personcount, @personssorted, @eventcount);
my $eventdir;
#
# *** Local serving: For development and debugging only ***
#
# To use this standalone on a computer, not served by a web server on the web,
# uncomment the following lines and make sure shivaserver.pm is in the
# same directory as this program.
#
# use shivaserver;
# shivaserver::local_server(\&process_request);
# exit;
# *** End of local serving ***
#
# * * * * *
#
# Main entry - processes CGI request
#
# Get query parameters
my $query;
if ($ENV{REQUEST_METHOD} eq 'POST') {
read(STDIN, $query, $ENV{CONTENT_LENGTH});
}
else {
$query = $ENV{QUERY_STRING};
}
# Process the request and output the results
my %responsedata = (); # holds results of processing request
process_request($query, \%responsedata);
my $content = $responsedata{content};
my $type = $responsedata{contenttype};
# Output header
$type ||= "text/html; charset=UTF-8"; # default type
my $header = "Content-type: $type\nExpires: Thu, 01 Jan 1970 00:00:00 GMT\n";
print "$header\n"; # print header plus extra line
# Output content
print $content;
#
# * * * * *
#
# process_request($querystring, \%responsedata)
#
# Process the HTTP request
#
# Responds to browser request and does all the work
# Returns data in %responsedata:
# $responsedata{content} - a string with the HTML response
# $responsedata{contenttype} - the HTTP response header content MIME type or null for default text/html UTF-8
# $responsedata{contentexpires} - expire string or null for default (-1d)
#
# The $querystring is the raw query from the browser.
#
sub process_request {
my ($querystring, $responsedata) = @_;
my $response;
# Get CGI object to get parameters:
$querystring ||= ""; # make sure has something
my $q = new CGI($querystring);
my %params = $q->Vars;
# # # # # # # # # #
#
# Load %strings
#
# # # # # # # # # #
my %shivadata;
load_shivadata(\%shivadata);
my %strings;
for (my $snum=0; $snum <= $#stringinfo; $snum++) { # fill in %strings values
my $sname = $stringinfo[$snum][$stringname];
$strings{$sname} = $shivadata{$sname} || $stringinfo[$snum][$stringdefault];
$snl{$sname} = $snum;
}
for (my $snum=0; $snum <= $#stringinfo; $snum++) { # after adminmaptext is copied, expand special chars
my $sname = $stringinfo[$snum][$stringname];
if ($stringinfo[$snum][$stringtype] == $stringtypemultiline) {
$strings{$sname} = wikitext_encode($strings{$sname}, $strings{adminmaptext});
}
else {
$strings{$sname} = special_chars($strings{$sname})
unless $sname eq "adminmaptext"; # map all but the "Map" text (which will get it on encode)
}
}
# Get current time string
my $start_clock_time = scalar localtime(time()+3600*($strings{admintimeoffset} || 0));
# # # # # # # # # #
#
# Check arguments
#
# # # # # # # # # #
my ($newattend, $editnum);
$params{set} = check_setname($params{set});
$params{editset} = check_setname($params{editset});
foreach my $p (keys %params) { # go through all the parameters
if ($p =~ /^showset:(.*)/) { # get set to show
$params{set} = check_setname($1);
last;
}
elsif ($p eq "backtolist") {
if ($params{person}) { # treat as a "Save" if person set
$params{dosave} = "Save";
last;
}
%params = (); # reset back to top
next;
}
elsif ($p =~ /^attend:(\d*)/) { # set attendence
$newattend .= ":" if $newattend;
$newattend .= $1;
}
elsif ($p =~ /^edit:(\d*)/) { # edit existing person
$editnum = $1;
}
elsif ($p =~ /^editset:(.*)/) { # edit existing set
last unless check_adminpassword(\%params, \%strings);
$params{editset} = check_setname($1);
last;
}
elsif ($p =~ /^ssave:([^\:]*):(.*?)$/) { # save string value
last unless check_adminpassword(\%params, \%strings);
$shivadata{$1} = $2 eq "c" ? $params{"snew:$1"} : "";
$strings{$1} = $shivadata{$1} || $stringinfo[$snl{$1}][$stringdefault];
if ($stringinfo[$snl{$1}][$stringtype] == $stringtypemultiline) {
$strings{$1} = wikitext_encode($strings{$1}, $strings{adminmaptext});
}
else {
$strings{$1} = special_chars($strings{$1});
}
save_shivadata(\%shivadata);
$params{admintop} = 1;
last;
}
elsif ($p =~ /^deleteset:(.*)/) { # delete existing set
last unless check_adminpassword(\%params, \%strings);
my $sname = check_setname($1);
my @peoplefiles =
my $pcount = unlink glob("$sname.set/person.*.txt"); # Delete all people
unlink "$sname.set/event.txt"; # Delete event file
rmdir "$sname.set"; # Delete directory
$params{admintop} = 1;
$params{statusmessage} = qq!Deleted "$sname" which included $pcount people signup record(s)!;
last;
}
elsif ($p eq "admincreate") { # create a new set merging text set and info set
last unless check_adminpassword(\%params, \%strings);
my $newname = check_setname($params{createname}); # make legal
if (length($newname)<1) {
$params{admintop} = 1;
$params{statusmessage} = "Name missing or invalid - nothing created";
last;
}
my %setdata1;
if ($params{createtext} ne "[none]") {
load_set(check_setname($params{createtext}) . ".set", \%setdata1);
}
my %setdata2;
if ($params{createinfo} ne "[none]") {
load_set(check_setname($params{createinfo}) . ".set", \%setdata2);
}
my %newsetdata;
$newsetdata{event} = [];
$newsetdata{eventorder} = [];
$newsetdata{strings} = {};
$newsetdata{set} = $newname;
$newsetdata{setname} = $setdata1{setname};
$newsetdata{setdescription} = $setdata1{setdescription};
$newsetdata{countbuttons} = $setdata2{countbuttons} || 1;
if ($setdata2{event}) { # copy events from setdata2
for (my $eline=1; $eline < scalar @{$setdata2{eventorder}}; $eline++) {
my $enum = $setdata2{eventorder}->[$eline];
$newsetdata{event}->[$enum] = {name => $setdata2{event}->[$enum]->{name},
desc => $setdata2{event}->[$enum]->{desc}};
$newsetdata{eventorder}->[$eline] = $enum;
}
$newsetdata{maxevent} = $setdata2{maxevent};
}
if ($setdata1{strings}) { # copy strings from setdata1
foreach my $sname (sort keys %{$setdata1{strings}}) {
$newsetdata{strings}->{$sname} = $setdata1{strings}->{$sname};
}
}
$newsetdata{visible} = "N"; # start out not listed in public list
my $ok = mkdir("$newname.set"); # create the set directory
if ($ok) {
save_set_from_setdata(\%newsetdata); # save the new data file
$params{statusmessage} = "Created $newname from $setdata2{set} (events) and $setdata1{set} (text)";
}
else {
$params{statusmessage} = qq!Unable to create "$newname".!;
}
$params{admintop} = 1;
last;
}
elsif ($p eq "adminbackup") { # display all variable data as text
$response .= <<"EOF";
Shiva Program
Backup of data from: $start_clock_time
EOF
my $somenondefault;
for (my $snum=0; $snum <= $#stringinfo; $snum++) {
my $sname = $stringinfo[$snum][$stringname];
if ($shivadata{$sname}) {
$somenondefault++;
my $stringtext = for_listing($shivadata{$sname}, ($stringinfo[$snum][$stringtype]==$stringtypemultiline));
$response .= <<"EOF";
- - -
$stringinfo[$snum][$stringfullname]:
$stringtext
EOF
}
}
$response .= "- No non-default administration text data - \n" unless $somenondefault;
$response .= <<"EOF";
= = = = = = = = = = = = = = = = =
DATA FOR EACH EVENT SET
= = = = = = = = = = = = = = = = =
EOF
my @sets = glob("*.set");
for (my $snum=0; $snum <= $#sets; $snum++) {
my %setdata;
my $maxeline = load_set($sets[$snum], \%setdata);
$maxeline += 0;
my $setname = for_listing($setdata{setname},0);
my $setdesc = for_listing($setdata{setdescription}, 1);
$response .= <<"EOF";
****************
$setdata{set}: $setname
****************
Short Name: $setdata{set}
Set Display Name: $setname
Maximum number of people: $setdata{countbuttons}
Visible in public list: $setdata{visible}
- - - - - - -
Set Description:
$setdesc
- - - - - - -
$maxeline event(s):
EOF
for (my $eline=1; $eline <= $maxeline; $eline++) {
my $enum = $setdata{eventorder}->[$eline];
my $ename = special_chars($setdata{event}->[$enum]->{name});
my $edesc = special_chars($setdata{event}->[$enum]->{desc});
$response .= "($enum) $ename: $edesc \n";
}
my $maxpnum = load_people($sets[$snum]); # get people information
my $npeople = 0;
for (my $unsortedpnum=1; $unsortedpnum <= $#personname; $unsortedpnum++) {
$npeople ++ if $personname[$personssorted[$unsortedpnum-1]];
}
$response .= <<"EOF";
- - - - - - -
People records: $npeople
EOF
for (my $unsortedpnum=1; $unsortedpnum <= $#personname; $unsortedpnum++) {
my $pnum = $personssorted[$unsortedpnum-1];
next unless $personname[$pnum];
my @pevents = split(/\:/, $personevents[$pnum]);
$response .= "($pnum) " . special_chars($personname[$pnum]) . ", attendees: ";
$response .= "$personcount[$pnum] " . ", events: ";
my $elist;
foreach my $enum (@pevents) {
$elist .= ", " if $elist;
$elist .= special_chars($setdata{event}->[$enum]->{name}) . " ($enum)";
}
$response .= "$elist \n";
}
$response .= <<"EOF";
- - - - - - -
Set specific text data (non-default settings only):
EOF
$response .= "- No set specific text data - \n" unless scalar(keys %{$setdata{strings}});
for (my $snum=0; $snum <= $#stringinfo; $snum++) {
my $sname = $stringinfo[$snum][$stringname];
if (exists $setdata{strings}->{$sname}) {
my $stringtext = for_listing($setdata{strings}->{$sname}, ($stringinfo[$snum][$stringtype]==$stringtypemultiline));
$response .= <<"EOF";
- - -
$stringinfo[$snum][$stringfullname]:
$stringtext
EOF
}
}
}
$response .= <<"EOF";
= = = = = = = = = = = = = = = = =
END OF BACKUP DATA
= = = = = = = = = = = = = = = = =
EOF
$responsedata->{content} = $response;
$responsedata->{contenttype} = "text/HTML; charset=UTF-8";
return;
}
elsif ($p =~ /^editsetsave/) { # save new values for set
last unless check_adminpassword(\%params, \%strings);
my %setdata;
my $maxevent = load_set("$params{editset}.set", \%setdata);
load_set_from_params(\%params, \%setdata);
save_set_from_setdata(\%setdata);
last;
}
elsif ($p =~ /^editsetssave:([^\:]*):(.*?)$/) { # save set specific string value
last unless check_adminpassword(\%params, \%strings);
my %setdata;
my $maxevent = load_set("$params{editset}.set", \%setdata);
$setdata{strings}->{$1} = $2 eq "c" ? $params{"editsetsnew:$1"} : ""; # "c" is change, "d" is default
$setdata{strings}->{$1} =~ s/\n$//; # remove trailing new line so it doesn't keep adding
load_set_from_params(\%params, \%setdata);
save_set_from_setdata(\%setdata);
last;
}
elsif ($p =~ /^editsetreorder:([a-z]*):(\d*)$/) { # reorder set events: up/down/insert/delete
last unless check_adminpassword(\%params, \%strings);
my $cmd = $1;
my $eline = $2;
my %setdata;
my $maxeventline = load_set("$params{editset}.set", \%setdata);
$maxeventline = load_set_from_params(\%params, \%setdata); # get set data, including any new changes here
if ($cmd eq "up") {
if ($eline > 1) {
my $enum = splice(@{$setdata{eventorder}}, $eline, 1);
splice(@{$setdata{eventorder}}, $eline-1, 0, $enum);
}
}
elsif ($cmd eq "down") {
if ($eline < $maxeventline) {
my $enum = splice(@{$setdata{eventorder}}, $eline, 1);
splice(@{$setdata{eventorder}}, $eline+1, 0, $enum);
}
}
elsif ($cmd eq "insert") {
my $newenum;
for ($newenum=1; $newenum <= $maxeventline; $newenum++) {
last unless $setdata{event}->[$newenum]; # find first unused number
}
$params{insertnewevent} = [$eline, $newenum]; # remember to show it in listing
}
elsif ($cmd eq "delete") {
my $delnum = $setdata{eventorder}->[$eline];
splice(@{$setdata{eventorder}}, $eline, 1); # remove event
my $enamesc = special_chars($setdata{event}->[$delnum]->{name});
$params{statusmessage} = qq!Deleted "$enamesc" ($delnum)!;
load_people("$params{editset}.set"); # get people information
my $pnum;
my $pplupdatelist;
for (my $unsortedpnum=1; $unsortedpnum <= $#personname; $unsortedpnum++) {
$pnum = $personssorted[$unsortedpnum-1];
next unless $personname[$pnum];
my %pevents;
@pevents{split(/\:/, $personevents[$pnum])} = 1;
if (exists $pevents{$delnum}) { # this person is signed up for the deleted event
delete $pevents{$delnum};
$personevents[$pnum] = join(":", sort keys %pevents);
$pplupdatelist .= ", " if $pplupdatelist;
$pplupdatelist .= special_chars($personname[$pnum]);
if ($personevents[$pnum]) { # other events left - update file
open (PERSONFILEOUT, ">$params{editset}.set/person.$pnum.txt");
print PERSONFILEOUT "version:1.0\n";
print PERSONFILEOUT "name:$personname[$pnum]\n";
print PERSONFILEOUT "count:$personcount[$pnum]\n";
foreach my $penum (sort {$a <=> $b} split(/\:/, $personevents[$pnum])) {
print PERSONFILEOUT "event:$penum\n";
}
close PERSONFILEOUT;
}
else { # no events left - delete person file
unlink "$params{editset}.set/person.$pnum.txt";
$pplupdatelist .= " (no remaining events)";
}
}
}
$params{statusmessage} .= " Removed from the following people: $pplupdatelist" if $pplupdatelist;
}
save_set_from_setdata(\%setdata);
last;
}
elsif ($p =~ /^editsetcancel/) { # just redisplay
last;
}
elsif ($p =~ /^editsetadmin/) { # go back to admin
last unless check_adminpassword(\%params, \%strings);
$params{editset} = "";
$params{admintop} = 1;
last;
}
}
$response .= <<"EOF";
$strings{adminpageheading}
EOF
if ($params{statusmessage}) { # display status message if necessary
$response .= <<"EOF";
$params{statusmessage}
EOF
$params{statusmessage} = ""; # only show this one once
}
# # # # # # # # # #
#
# See which type of invocation
#
# # # # # # # # # #
#
# ADMIN command
#
if ($params{doinglogin} && !$params{adminlogincancel}) { # IE submits without using button name
$params{admintop} = "Login";
}
if ($params{admintop} || $params{editset}) {
check_adminpassword(\%params, \%strings);
}
if ($params{admintop}) {
my $passwordwarning;
$passwordwarning = <<"EOF" unless $strings{adminpassword};
The administrator password is currently not set.
This allows any user to access this page.
If this is not what you want, you can set the password below.
EOF
$response .= <<"EOF";
EOF
}
#
# EDIT SET command
#
elsif ($params{editset}) {
my %setdata;
my $maxevent = load_set("$params{editset}.set", \%setdata);
my ($insertedeline, $insertedenum);
if ($params{insertnewevent}) {
$maxevent++; # add a blank one in the middle
($insertedeline, $insertedenum) = @{$params{insertnewevent}};
splice(@{$setdata{eventorder}}, $insertedeline, 0, $insertedenum);
$setdata{event}->[$insertedenum] = {name => "", desc => ""};
}
my $maxblank = 3;
my $mindisplayed = 10;
my $setnamesc = special_chars($setdata{setname});
my $descsc = special_chars($setdata{setdescription});
$descsc =~ s/\\n/\n/g;
my %visiblechecked;
$visiblechecked{$setdata{visible}} = " CHECKED";
$response .= <<"EOF";
EOF
}
#
# SHOW ADMIN LOGIN SCREEN
#
elsif ($params{adminlogin}) {
if ($params{statusmessage}) { # display status message if present
$response .= <<"EOF";
$params{statusmessage}
EOF
}
$response .= <<"EOF";
EOF
}
# # # # # # # # # #
#
# Have set, list events, etc. -- main display
#
# # # # # # # # # #
else {
my ($command, $rest, $enum, $eline, $maxevent, $ename, $edesc, $pnum, $ecount, $rowtype, $maxpnum);
my ($changednum, $setname, $setdescription, $countbuttons);
my (%setdata, %countchecked);
$eventdir = "$params{set}.set";
$maxevent = load_set($eventdir, \%setdata);
if (!$setdata{exists} || $setdata{visible} && $setdata{visible} ne "Y") {
$responsedata->{content} = <<"EOF"; # should not get here unless URL with "set" param was given out
Page not found
The page you are looking for might have been removed,
had its name changed, or is temporarily unavailable.
EOF
$responsedata->{contenttype} = "text/plain; charset=UTF-8";
return;
}
foreach my $sname (keys %{$setdata{strings}}) { # override non-default text strings with setdata
if ($stringinfo[$snl{$sname}][$stringtype] == $stringtypemultiline) {
$strings{$sname} = wikitext_encode($setdata{strings}->{$sname}, $strings{adminmaptext});
}
else {
$strings{$sname} = special_chars($setdata{strings}->{$sname});
}
}
my $maxpnum = load_people($eventdir);
if ($params{dosave} && $params{person}) { # update or create person info
if ($newattend) { # attending at least one thing
if ($params{editnum}) { # updating an existing person (will even update their name)
$pnum = $params{editnum};
}
else { # new one - still look up just in case person didn't remember they were coming
$pnum = $personnumber{$params{person}}; # see if already exists
if ($pnum) { # already exists -- add this to their existing events
my %setevents;
@setevents{split(/\:/, $newattend)} = 1;
@setevents{split(/\:/, $personevents[$pnum])} = 1;
$newattend = join(":", sort keys %setevents);
}
else {
$pnum ||= $maxpnum + 1; # add a new one
}
}
my $pname = $params{person};
$pname = substr($pname, 0, 40) if length($pname) > 40; # spam protection of a sort
my $pcount = $params{pcount};
$pcount = $pcount > 10 ? 10 : $pcount; # spam protection of a sort
open (PERSONFILEOUT, ">$eventdir/person.$pnum.txt");
print PERSONFILEOUT "version:1.0\n";
print PERSONFILEOUT "name:$pname\n";
print PERSONFILEOUT "count:$pcount\n";
foreach $enum (sort {$a <=> $b} split(/\:/, $newattend)) {
print PERSONFILEOUT "event:$enum\n";
}
close PERSONFILEOUT;
$changednum = $pnum; # remember to highlight
}
else { # not attending anything - delete if existed
if($personnumber{$params{person}}) {
unlink "$eventdir/person.$personnumber{$params{person}}.txt";
}
}
load_people($eventdir); # reload people information
$editnum = 0; # not editing anymore if were
}
my ($topinstructions, $savingtitle, $namevalue, $savingbutton, $donedisabled);
if ($editnum) {
$topinstructions = $strings{topinstructionsold};
$countchecked{$personcount[$editnum]} = " CHECKED";
$namevalue = special_chars($personname[$editnum]);
$savingtitle = $strings{signupactiontitleold};
$savingbutton = $strings{signupsavingbuttonold};
$donedisabled = " disabled";
}
else {
$topinstructions = $strings{topinstructionsnew};
$countchecked{1} = " CHECKED";
$savingtitle = $strings{signupactiontitlenew};
$savingbutton = $strings{signupsavingbuttonnew};
$donedisabled = "";
}
# # # # # # # # # #
#
# List Events
#
# # # # # # # # # #
$setname = special_chars($setdata{setname});
$setdescription = wikitext_encode($setdata{setdescription}, $strings{adminmaptext});
$response .= <<"EOF";