use sane dump=>1; our $white = "white" our $header_color = "#eeeeee" our $sep_color = "gray" our $textcolor = "black" our $textcolor_disabled = "#444444" our $bgcolor_today = "beige" our $bgcolor_other_days = "white" our $bgcolor_holiday = "#ffefef" our $admin_warning_color = "red" our $static_warning_color = "purple" #our $color_mine_static = "#00ff00" our $color_mine_static = "#ffafff" our $color_mine_booked = "aaffaa" #our $color_other_static = "#999999" our $color_other_static = "#ffcfff" our $color_other_booked = "cccccc" our $color_mine_cancelled = "#eeee99" our $color_other_cancelled = "#dddddd" our $body_bgcolor = "#ffeedd" our $cell_count = 0 use IO::File use CGI ':standard' use CGI::Carp 'fatalsToBrowser' require "lib_pl" require "lib_bookings_pl" use Date use File::Copy # session variables our $session_data = {} our ($uid, $password, $token, $session_code, $authenticated, $ou_allowed) our ($short_uid_type) # descriptive, for messages # other vars from lib_pl our ($program, $submit_i, $file_i, $password_i, @month, @weekday) our ($common_conf) our %N # config our @week_desc = ("this week", "next week", "fortnight") our @periods_all = ("Period 1", "Period 2", "Recess", "Period 3", "Period 4", "Lunch", "Period 5", "Period 6", "After School") our $week_min = 0 our $week_max = 2 our $n_weeks = $week_max - $week_min + 1 # appearence config our $cellwidth_major = 120 # classes our $cellwidth_minor = 100 # recess, etc our $cellpadding = 2 our $sep_h = qq{} our $sep_h1 = qq{} our $sep_v = qq{\n\n\n\n} # globals (I would use OO but perl's sucks too bad) our ($conf, $dir, $lock_file, $booked_file, $static_file, $cancelled_file, $holidays_file, $info_file, $static_info_file) our ($users) our ($booked, $static, $cancelled, $booked_x, $static_x, $cancelled_x, $holidays, $info, $info_x, $static_info, $static_info_x) our ($max_bookings, $n_bookings, $my_bookings, $too_many_bookings) our ($category, $week, $today_wday, $monday1, $monday, $resources, $n_resources, $classes_only, @periods, $n_periods) our ($date, $wday, $ymd2, $past, $today, $holiday, $weekday, $month_day) our ($resource, $resource_full, $resource_info) our ($period, $class) our ($booked_by, $static_booker, $cancelled_by, $booker, $is_static, $mine, $cancellable, $info_editable, $available, $my_cancelled, $cell_name) our ($changed_cancelled, $changed_booked, $changed_static, $new_booker, $changed_info, $changed_static_info) our ($mode_normal, $mode_admin, $mode_static, $mode_admin_any) our ($bgcolor, $fgcolor, $day_bgcolor) our ($reset) our ($info_missing_msg) our ($user) our ($teacher_names, $teacher_ids) our ($id) # short_uid our ($editable_day) our ($n_bookings_unlimited, $n_bookings_left) our ($description_of) $my_bookings = [] #my $teacher_names = read_data("teachers.conf") #delete $teacher_names->{__order} $conf = read_data("bookings.conf") $ou_allowed = $conf->{"ou.allowed"} load_session() $user = auth() $id = uc_or_lc_id($user->{short_uid}) if !defined $id or $id eq "" msg("your short uid ($short_uid_type) is not defined in the directory - please contact $conf->{administrator}") ftr(); exit # hdr("Booking Resources", $body_bgcolor) ($teacher_names, $teacher_ids) = lookup_staff_etc() #msg(Dumper($teacher_names)) mode_vars() if (param("category") && !(param("back"))) calendar() else hdr("Booking Resources", $body_bgcolor) category_chooser() ftr() sub calendar_hdr my $title = param("category")." Bookings" if exists $conf->{unlimited}{param("category")} $title .= " (unlimited)" $title .= " - ".week_desc($week) hdr($title, $body_bgcolor) # hidden variable/s print hidden("category") # print hidden("week") # now this is with the bit that displays the current week, because in admin mode it's a dropdown sub calendar check_mode_buttons() my $lock = get_lock($lock_file) daily_backup() calendar_init() calendar_hdr() # print "
" save_changes() if param("save") print qq{
} calendar_status() nl() calendar_controller() print qq{} calendar_legend() print "
" calendar_main() nl() list_all_bookings() # print "
" unlock($lock) sub daily_backup # make a daily backup if ! $conf->{no_daily_backups} my $date = Date->today->yyyymmdd if ! -d "backups" or ! -d "backups/$date" mkdir "backups"; mkdir "backups/$date" for my $filename glob("*.conf"), glob("*.data") my $backup = "backups/$date/$filename" copy($filename, $backup) || die "can't make backup file $backup" sub check_mode_buttons if $user->{is_admin} if param("admin") sd_set("mode", "admin") $reset = 1 if param("timetable") sd_set("mode", "static") $reset = 1 if param("normal") sd_set("mode", "normal") $reset = 1 mode_vars() #sub auth # return 1 if check_token_ok() # $uid = lc $uid # param("uid", $uid) # my $user = ldap_auth({keep_ldap_open=>1}, $uid, $password) # unless($user) { ldap_close(); return 0 } # my $dn = $user->dn() # my @ou # while ($dn =~ /ou=(.*?)(?:,|$)/gi) # unshift @ou, lc $1 # # my $_ou = $ou_allowed # for @ou # if exists $_ou->{$_} # $_ou = $_ou->{$_} # else # ldap_close(); return 0 # # # sd_set("user is admin", grep(/admin/i, @ou) || $uid eq "ssw" || 0) # $authenticated = $user && 1 # if sd("user is admin") # my $users = lookup_staff_etc() # sd_set("users", $users) # # ldap_close() # return $user # sub category_chooser my $dropdown = dropdown({autosubmit=>1}, "category", $conf->{resources}{__order}) my $b = buttons("select", "logout") print tbl_tsv(qq What type of resource? $dropdown $b ) sub calendar_init load_calendar_data() # load and validate parameters $category = param("category") exists $conf->{resources}{$category} or die "no such category: $category\n" $week = param("week") || 0 if param("<<") -- $week if param(">>") ++ $week if !$mode_admin_any if $week < 0 $week = 0 if $week > $week_max $week = $week_max param("week", $week) # date my $d = Date->today $today_wday = $d->{wday}-2 # counting sunday == -1, monday == 0 $monday1 = $d->dup $monday1->back_days($today_wday) # go to monday (day 2, counting from 1->sun) # set $monday to monday of the selected week $monday = $monday1->dup for my $i 0..$week-1 $monday->forward_days(7) # set $resources ary $resources = $conf->{resources}{$category} if ref $resources $description_of = $resources $resources = $resources->{__order} else $description_of = $conf->{resources} $resources = [$category] undef $category $n_resources = 0+@$resources # display just classes, or recess, lunchtime, after school? $classes_only = 1 # XXX conf per resource? TODO conf. overnight separately? @periods = @periods_all if $classes_only @periods = grep /Period/, @periods $n_periods = 0+@periods $max_bookings = $conf->{"max bookings"}{normal} if $conf->{"max bookings"}{exceptions}{$id} $max_bookings = $conf->{"max bookings"}{exceptions}{$id} check_bookings($booked) sub week_desc return $week_desc[$week] || "week ".$week+1 sub calendar_main # start table print qq{\n\n # table - corner (week) and buttons print qq{ print $sep_h # top header (periods) display_periods_header() # table - main my @weekdays $date = $monday->dup for 0..4 $weekdays[$_] = $date->dup $date->tomorrow for $wday 0..4 $date = $weekdays[$wday] date_vars() print $sep_h, $sep_v # local periods_header # print qq{ # print $sep_h # display_periods_header() table_day_row() print "\n
date_browser() print qq{
\n" nl() sub table_day_row if !$mode_static && $holiday # it's a holiday! yay # print row header (date) print qq{ print "" if $today print $weekday; print "
"; print $month_day print "
" if $today print "" print $sep_h my $colspan = $conf->{flip_table} ? "rowspan" : "colspan" print qq{ print $holiday print "" print "\n\n" else # print row header (date) print qq{ print "" if $today print $weekday; if (!$mode_static) { print "
"; print $month_day print "
" if $today print "" # a row for each resource ... for $resource @$resources resource_vars() print $sep_h; # a cell for each period ... for $period @periods period_vars() booking_vars() if param("reload") param($cell_name, $booker) # display the cell display_cell() # resource column, optional resource_column() print "\n\n" sub display_periods_header for $period @periods period_vars() if $class print qq{} else print qq{} print $period if $class print qq{} else print qq{} if defined $category print $sep_h1 print qq{} print $category print qq{} print $sep_v sub resource_column # XXX change to a variable, $multiple_resources ? if defined $category print $sep_h1 my $r = $resource my $tt = "$description_of->{$resource}" $r = nbspify($r) $tt = nbspify("$r $tt") print qq{}.with_popup($r, $tt, "overlay_left").qq{} # print qq{$resource} sub date_browser if $mode_static space(1) elsif $mode_admin_any # allow to book up to 52 weeks ahead, for now ... # XXX maybe should allow to view the past too? # highlight current week? my $options = [] my $day = $monday1 for my $i 0..52 push @$options, $i if $week_desc[$i] push @$options, $week_desc[$i] $day->forward_days(7) else my $week_desc = $day->mon_day() $day->forward_days(4) $week_desc .= " - ".$day->mon_day() push @$options, $week_desc $day->forward_days(3) print left_right( dropdown({no_prompt=>1, abbrev=>1, autosubmit=>1, selected=>$week}, 'week', $options), # submit({name=>"go"}) ) else # mode_normal print left_mid_right( submit({name=>"<<", (($week <= $week_min) ? (disabled => 1) : ())}), week_desc($week), submit({name=>">>", (($week >= $week_max) ? (disabled => 1) : ())}), ) if !$mode_admin_any print hidden("week") # in admin mode, this is a dropdown, see above sub selector print qq{} if $fgcolor ne "black" if $mode_normal user_selector() else admin_selector() print qq{} if $fgcolor ne "black" sub info_selector if $mode_normal && $my_cancelled # a cancelled booking of mine show_static_info_greyed() elsif ($available || $info_editable) # normal selector my $ix = $mode_static ? $static_info_x->{$weekday} : $info_x->{$ymd2 my @o for my $type @{$resource_info->{__order}} my $info = $ix->{$period}{$resource_full}{$type my @selected = defined $info ? (selected => $info) : () my $name = "$cell_name : $type" # XXX if exists $conf->{types}{$type} my $range = $conf->{types}{$type}{__order push @o, dropdown({prompt=>"$type", @selected}, $name, $range) else push @o, qq{ print join " ", @o elsif ($booker) my $ix = $is_static ? $static_info_x->{$weekday} : $info_x->{$ymd2 show_info($ix) sub show_static_info_greyed print q{ show_info($static_info_x->{$weekday}) print q{ sub show_info my ($ix) = @_ my @o for my $type @{$resource_info->{__order}} my $info = $ix->{$period}{$resource_full}{$type if defined $info push @o, $info print join "  ", @o sub user_selector checkbox_selector() sub checkbox_selector if $booker if $cancellable print checkbox($cell_name, 1, $booker, '') # print qq{ print " "; #   doesn't work. html should have a container or CSS property else param($cell_name, $booker) print hidden($cell_name) display_booker($booker) elsif ($available) print checkbox($cell_name, 0, $id, '') # print qq{ else if $editable_day die "logic problem!" sub admin_selector if $available # if $mode_admin_any # print "" # XXX my $options = ['', @$teacher_ids] if $static_booker unshift @$options, $static_booker if !$mine && $id ne $static_booker unshift @$options, $id my $abbrev @$options = map $_, $_ eq "" ? "" : "$_   $teacher_names->{$_}" @$options $abbrev = 1 # @$options = map $_, $_ eq "" ? "" : $teacher_names->{$_} || $_ @$options $abbrev = 1 my $tiny = $booker eq "" my $dropdown_opts = no_prompt=>1, abbrev=>$abbrev, selected=>$booker||'', clip=>1, # dynamic_expand=>1, # print qq{
}.dropdown($dropdown_opts, $cell_name, $options).qq{
} print dropdown($dropdown_opts, $cell_name, $options)."
" else checkbox_selector() sub display_booker my $booker_name = $teacher_names->{$booker # print with_popup($booker, "$booker_name  $booker", "overlay_right") print with_popup($booker, "$booker_name", "overlay_left") sub display_resource_name print qq{} if $fgcolor ne "black" my $r = nbspify(encode_entities($resource)) if defined $description_of->{$resource} my $tt = encode_entities($description_of->{$resource}) my $popup $popup = with_tooltip($r, "$r  $tt") # if $mode_admin_any # $popup = with_popup($r, "$r  $tt", "overlay_left") ## $popup =~ s/(onMouseover=")/$1hide_if_exists('hideme_$cell_count'); /; # XXX HACK to hide the dropdown next to it ## $popup =~ s/(onMouseout=")/$1show_if_exists('hideme_$cell_count'); / # else # $popup = with_popup($r, "$r  $tt", "overlay_left") # print $popup else print $r print qq{} if $fgcolor ne "black" # TODO make these generic? sub clean_table my ($rows, $ymd2_week_start) = @_ my $out = [] for @$rows my ($ymd, $period, $resource, $who) = @$_ if $ymd ge $ymd2_week_start push @$out, $_ return $out sub is_holiday my ($ymd2) = @_ # !inefficient! # need binary lookup for my $h @$holidays my ($start, $end, $desc) = @$h if $ymd2 ge $start and $ymd2 le $end return $desc return 0 #sub calendar_header # # heading: category and resources # print "
" # print qq{
# print "

" # if $category ## print "$category: " . join", ",@$resources # print "$category" # if exists $conf->{unlimited}{$category} # print " (unlimited)" # # else # print "@$resources"; # just one I hope! # if exists $conf->{unlimited}{"@$resources"} # print " (unlimited)" # # # ## print " — " ## ## # week selector ## my $d = $monday1->dup ## print qq{\n\n" ## print qq{\n # # print "

\n" # print qq{
# # calendar_legend() # print "
" # sub calendar_status print qq{ my $firstname = $id if $teacher_names->{$id} $firstname = $teacher_names->{$id $firstname =~ s/ .*// print "$firstname," space(1) if $mode_admin print qq{you have admin powers. elsif ($mode_static) print qq{this is the timetable. else my $plural = $n_bookings == 0 ? "no bookings" : $n_bookings == 1 ? "one booking" : "$N{$n_bookings} bookings" my $bookings_link = $n_bookings ? a({href=>"#my"}, $plural) : $plural my $bookings_left = $n_bookings_left == 0 ? "none" : $N{$n_bookings_left if $too_many_bookings print "you have requested $plural." else print qq{you have made $bookings_link – $bookings_left left{ print qq{
} if $too_many_bookings nl() msg("You are limited to $N{$max_bookings} bookings in any $N{$n_weeks} week period.") msg("Please contact $conf->{administrator} if you need a higher limit.") my $unlimited = $conf->{unlimited}{__order if @$unlimited my $x = join ", ", @$unlimited msg("There is no limit for $x.") sub calendar_controller # save button print q{  }; #save  };