# The LearningOnline Network with CAPA # Handler for requesting to have slots added to a students record # # $Id: slotrequest.pm,v 1.125 2015/09/23 20:09:07 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # ### package Apache::slotrequest; use strict; use Apache::Constants qw(:common :http :methods); use Apache::loncommon(); use Apache::lonlocal; use Apache::lonnet; use Apache::lonnavmaps(); use Date::Manip; use lib '/home/httpd/lib/perl/'; use LONCAPA qw(:DEFAULT :match); sub fail { my ($r,$code)=@_; if ($code eq 'not_valid') { $r->print('
'.&mt('Unable to understand what resource you wanted to sign up for.').'
'); } elsif ($code eq 'not_available') { $r->print(''.&mt('No slots are available.').'
'); } elsif ($code eq 'not_allowed') { $r->print(''.&mt('Not allowed to sign up or change reservations at this time.').'
'); } else { $r->print(''.&mt('Failed.').'
'); } &return_link($r); &end_page($r); } sub start_page { my ($r,$title,$brcrum,$js)=@_; my $args; if (ref($brcrum) eq 'ARRAY') { $args = {bread_crumbs => $brcrum}; } if (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) { my %loaditems = ( onload => 'javascript:uncheckSlotRadio();', ); if (ref($args) eq 'HASH') { $args->{'add_entries'} = \%loaditems; } else { $args = { 'add_entries' => \%loaditems }; } } $r->print(&Apache::loncommon::start_page($title,$js,$args)); } sub end_page { my ($r)=@_; $r->print(&Apache::loncommon::end_page()); } sub reservation_js { my ($slots,$consumed_uniqueperiods,$available,$got_slots,$symb) = @_; return unless ((ref($slots) eq 'HASH') && (ref($available) eq 'ARRAY')); my $toskip; if ($symb eq '') { $toskip = { symb => 1, }; } my ($i,$j) = (0,0); my $js; foreach my $slot (sort { return $slots->{$a}->{'starttime'} <=> $slots->{$b}->{'starttime'} } (keys(%{$slots}))) { next if (!&allowed_slot($slot,$slots->{$slot},$symb,$slots, $consumed_uniqueperiods,$toskip)); $js .= " slotstart[$i]='$slots->{$slot}->{'starttime'}';\n". " slotend[$i]='$slots->{$slot}->{'endtime'}';\n". " slotname[$i]='$slot';\n"; if (($symb) && (ref($got_slots) eq 'ARRAY')) { if (grep(/^\Q$slot\E$/,@{$got_slots})) { $js .= " currslot[$j]='$slot';\n"; $j++; } } $i++; push(@{$available},$slot); } if ($j) { $js = " var currslot = new Array($j);\n\n$js"; } my %alerts = &Apache::lonlocal::texthash ( none => 'No reservable time slots found', invalid => 'Invalid date format', ); return <<"ENDSCRIPT"; ENDSCRIPT } =pod slot_reservations db - keys are - slotname\0id -> value is an hashref of name -> user@domain of holder timestamp -> timestamp of reservation symb -> symb of resource that it is reserved for =cut sub get_course { (undef,my $courseid)=&Apache::lonnet::whichuser(); my $cdom=$env{'course.'.$courseid.'.domain'}; my $cnum=$env{'course.'.$courseid.'.num'}; return ($cnum,$cdom); } sub get_reservation_ids { my ($slot_name)=@_; my ($cnum,$cdom)=&get_course(); my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, "^$slot_name\0"); if (&Apache::lonnet::error(%consumed)) { return 'error: Unable to determine current status'; } my ($tmp)=%consumed; if ($tmp=~/^error: 2 / ) { return 0; } return keys(%consumed); } sub space_available { my ($slot_name,$slot)=@_; my $max=$slot->{'maxspace'}; if (!defined($max)) { return 1; } my $consumed=scalar(&get_reservation_ids($slot_name)); if ($consumed < $max) { return 1 } return 0; } sub check_for_reservation { my ($symb,$mode)=@_; my $student = &Apache::lonnet::EXT("resource.0.availablestudent", $symb, $env{'user.domain'}, $env{'user.name'}); my $course = &Apache::lonnet::EXT("resource.0.available", $symb, $env{'user.domain'}, $env{'user.name'}); my @slots = (split(/:/,$student), split(/:/, $course)); &Apache::lonxml::debug(" slot list is ".join(':',@slots)); my ($cnum,$cdom)=&get_course(); my %slots=&Apache::lonnet::get('slots', [@slots], $cdom, $cnum); if (&Apache::lonnet::error($student) || &Apache::lonnet::error($course) || &Apache::lonnet::error(%slots)) { return 'error: Unable to determine current status'; } my @got; my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime'); foreach my $slot_name (@sorted_slots) { next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name})); &Apache::lonxml::debug(time." $slot_name ". $slots{$slot_name}->{'starttime'}." -- ". $slots{$slot_name}->{'startreserve'}." -- ". $slots{$slot_name}->{'endreserve'}); if (($slots{$slot_name}->{'endtime'} > time) && ($slots{$slot_name}->{'startreserve'} < time) && ((!$slots{$slot_name}->{'endreserve'}) || ($slots{$slot_name}->{'endreserve'} > time))) { # between start of reservation time and end of reservation time # and before end of slot if ($mode eq 'allslots') { push(@got,$slot_name); } else { return($slot_name, $slots{$slot_name}); } } } if ($mode eq 'allslots' && @got) { return @got; } return (undef,undef); } sub get_consumed_uniqueperiods { my ($slots) = @_; my $navmap=Apache::lonnavmaps::navmap->new; if (!defined($navmap)) { return 'error: Unable to determine current status'; } my @problems = $navmap->retrieveResources(undef, sub { $_[0]->is_problem() },1,0); my %used_slots; foreach my $problem (@problems) { my $symb = $problem->symb(); my $student = &Apache::lonnet::EXT("resource.0.availablestudent", $symb, $env{'user.domain'}, $env{'user.name'}); my $course = &Apache::lonnet::EXT("resource.0.available", $symb, $env{'user.domain'}, $env{'user.name'}); if (&Apache::lonnet::error($student) || &Apache::lonnet::error($course)) { return 'error: Unable to determine current status'; } foreach my $slot (split(/:/,$student), split(/:/, $course)) { $used_slots{$slot}=1; } } if (!ref($slots)) { my ($cnum,$cdom)=&get_course(); my %slots=&Apache::lonnet::get('slots', [keys(%used_slots)], $cdom, $cnum); if (&Apache::lonnet::error(%slots)) { return 'error: Unable to determine current status'; } $slots = \%slots; } my %consumed_uniqueperiods; foreach my $slot_name (keys(%used_slots)) { next if (!defined($slots->{$slot_name}) || !ref($slots->{$slot_name})); next if (!defined($slots->{$slot_name}{'uniqueperiod'}) || !ref($slots->{$slot_name}{'uniqueperiod'})); $consumed_uniqueperiods{$slot_name} = $slots->{$slot_name}{'uniqueperiod'}; } return \%consumed_uniqueperiods; } sub check_for_conflict { my ($symb,$new_slot_name,$new_slot,$slots,$consumed_uniqueperiods)=@_; if (!defined($new_slot->{'uniqueperiod'})) { return undef; } if (!ref($consumed_uniqueperiods)) { if ($consumed_uniqueperiods =~ /^error: /) { return $consumed_uniqueperiods; } else { $consumed_uniqueperiods = &get_consumed_uniqueperiods($slots); if (ref($consumed_uniqueperiods) eq 'HASH') { if (&Apache::lonnet::error(%$consumed_uniqueperiods)) { return 'error: Unable to determine current status'; } } else { return 'error: Unable to determine current status'; } } } my ($new_uniq_start,$new_uniq_end) = @{$new_slot->{'uniqueperiod'}}; foreach my $slot_name (keys(%$consumed_uniqueperiods)) { my ($start,$end)=@{$consumed_uniqueperiods->{$slot_name}}; if (! ($start < $new_uniq_start && $end < $new_uniq_start) || ($start > $new_uniq_end && $end > $new_uniq_end )) { return $slot_name; } } return undef; } sub make_reservation { my ($slot_name,$slot,$symb,$cnum,$cdom)=@_; my $value=&Apache::lonnet::EXT("resource.0.availablestudent",$symb, $env{'user.domain'},$env{'user.name'}); &Apache::lonxml::debug("value is $value".&mt('A network error has occurred.').'
'); return; } if (!%consumed) { $r->print(''.&mt('Slot [_1] has no reservations.', ''.$slot_name.'').'
'); return; } my @names = map { $consumed{$_}{'name'} } (sort(keys(%consumed))); my $names = join(' ',@names); my $msg = &mt('Remove all of [_1] from slot [_2]?',$names,$slot_name); &remove_registration_confirmation($r,$msg,['entry','slotname','context']); } sub remove_registration_user { my ($r) = @_; my $slot_name = $env{'form.slotname'}; my $name = &Apache::loncommon::plainname($env{'form.uname'}, $env{'form.udom'}); my $title = &Apache::lonnet::gettitle($env{'form.symb'}); my $msg = &mt('Remove [_1] from slot [_2] for [_3]', $name,$slot_name,$title); &remove_registration_confirmation($r,$msg,['uname','udom','slotname', 'entry','symb','context']); } sub remove_registration_confirmation { my ($r,$msg,$inputs) =@_; my $hidden_input; foreach my $parm (@{$inputs}) { $hidden_input .= '&\'').'" />'."\n"; } my %lt = &Apache::lonlocal::texthash( 'yes' => 'Yes', 'no' => 'No', ); $r->print(<<"END_CONFIRM");$msg
END_CONFIRM } sub release_all_slot { my ($r,$mgr)=@_; my $slot_name = $env{'form.slotname'}; my ($cnum,$cdom)=&get_course(); my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, "^$slot_name\0"); $r->print(''.&mt('Releasing reservations').'
'); foreach my $entry (sort { $consumed{$a}{'name'} cmp $consumed{$b}{'name'} } (keys(%consumed))) { my ($uname,$udom) = split(':',$consumed{$entry}{'name'}); my ($result,$msg) = &release_reservation($slot_name,$uname,$udom, $consumed{$entry}{'symb'},$mgr); if (!$result) { $r->print(''.&mt($msg).'
'); } else { $r->print("$msg
"); } $r->rflush(); } $r->print(''. &mt('Return to slot list').'
'); &return_link($r); } sub release_slot { my ($r,$symb,$slot_name,$inhibit_return_link,$mgr)=@_; if ($slot_name eq '') { $slot_name=$env{'form.slotname'}; } my ($uname,$udom) = ($env{'user.name'}, $env{'user.domain'}); if ($mgr eq 'F' && defined($env{'form.uname'}) && defined($env{'form.udom'})) { ($uname,$udom) = ($env{'form.uname'}, $env{'form.udom'}); } if ($mgr eq 'F' && defined($env{'form.symb'})) { $symb = &unescape($env{'form.symb'}); } my ($result,$msg) = &release_reservation($slot_name,$uname,$udom,$symb,$mgr); if (!$result) { $r->print(''.&mt($msg).'
'); } else { $r->print("$msg
"); } if ($mgr eq 'F') { $r->print(''. &mt('Return to slot list').'
'); } if (!$inhibit_return_link) { &return_link($r); } return $result; } sub release_reservation { my ($slot_name,$uname,$udom,$symb,$mgr) = @_; my %slot=&Apache::lonnet::get_slot($slot_name); my $description=&get_description($slot_name,\%slot); if ($mgr ne 'F') { if ($slot{'starttime'} < time) { return (0,&mt('Not allowed to release Reservation: [_1], as it has already ended.',$description)); } } # if the reservation symb is for a map get a resource in that map # to check slot parameters on my $navmap=Apache::lonnavmaps::navmap->new; if (!defined($navmap)) { return (0,'error: Unable to determine current status'); } my $passed_resource = $navmap->getBySymb($symb); if (ref($passed_resource)) { if ($passed_resource->is_map()) { my ($a_resource) = $navmap->retrieveResources($passed_resource, sub {$_[0]->is_problem()},0,1); $symb = $a_resource->symb(); } } else { unless ($mgr eq 'F') { return (0,'error: Unable to determine current status'); } } # get parameter string, check for existence, rebuild string with the slot my $student = &Apache::lonnet::EXT("resource.0.availablestudent", $symb,$udom,$uname); my @slots = split(/:/,$student); my @new_slots; foreach my $exist_slot (@slots) { if ($exist_slot eq $slot_name) { next; } push(@new_slots,$exist_slot); } my $new_param = join(':',@new_slots); my ($cnum,$cdom)=&get_course(); # get slot reservations, check if user has one, if so remove reservation my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, "^$slot_name\0"); foreach my $entry (keys(%consumed)) { if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) { &Apache::lonnet::del('slot_reservations',[$entry], $cdom,$cnum); my %storehash = ( symb => $symb, slot => $slot_name, action => 'release', context => $env{'form.context'}, ); &Apache::lonnet::write_log('slotreservationslog',\%storehash, 1,$uname,$udom,$cnum,$cdom); &Apache::lonnet::write_log($cdom.'_'.$cnum.'_slotlog',\%storehash, 1,$uname,$udom,$uname,$udom); } } my $use_slots = &Apache::lonnet::EXT("resource.0.useslots", $symb,$udom,$uname); &Apache::lonxml::debug("use_slots is $use_slots'.&mt('Slot [_1] marked as deleted.',''.$slot_name.'').'
'); } else { $r->print(''.&mt('An error occurred when attempting to delete slot: [_1]',''.$slot_name.'')." ($ret)
"); } } else { if (%consumed) { $r->print(''.&mt('Slot [_1] has active reservations.',''.$slot_name.'').'
'); } else { $r->print(''.&mt('Slot [_1] does not exist.',''.$slot_name.'').'
'); } } $r->print(''. &mt('Return to slot list').'
'); &return_link($r); } sub return_link { my ($r) = @_; if (($env{'form.command'} eq 'manageresv') || ($env{'form.context'} eq 'usermanage')) { $r->print(''.
&mt('Return to reservations'));
} else {
$r->print(' '.
&mt('Return to last resource').' '
.&mt('An error occurred while attempting to make a reservation. ([_1])',$1)
.' '.&mt('Reservation currently unchanged').' '.&mt('To complete the transaction you [_1]must confirm[_2] you want to [_3]process the change[_4] to [_5].'
,'','','','',''.$description2.'')
.' '
.''
.(' 'x3)
.''
.' '.&mt('Already have a reservation: [_1].',$description1).' '
.&mt('An error occurred while attempting to make a reservation. ([_1])',$1)
.' '.&mt('Successfully signed up: [_1]',$description).' '.&mt('Already reserved: [_1]',$description).' '.&mt('[_1]Failed[_2] to reserve a slot for [_3].','','',$description).'
'
.&mt('Or you can choose to [_1]make no change[_2] and continue[_2] with the reservation you already had: [_3].'
,'','',''.$description1.'')
.'
$lt{'or'}
STUFF if (!$inhibit_return_link) { $r->print(&mt('or').''); &return_link($r); } else { $r->print(''); } return 0; } sub allowed_slot { my ($slot_name,$slot,$symb,$slots,$consumed_uniqueperiods,$toskip)=@_; #already started if ($slot->{'starttime'} < time) { return 0; } &Apache::lonxml::debug("$slot_name starttime good"); #already ended if ($slot->{'endtime'} < time) { return 0; } &Apache::lonxml::debug("$slot_name endtime good"); # not allowed to pick this one if (defined($slot->{'type'}) && $slot->{'type'} ne 'schedulable_student') { return 0; } &Apache::lonxml::debug("$slot_name type good"); # reserve time not yet started if ($slot->{'startreserve'} > time) { return 0; } # reserve time ended if (($slot->{'endreserve'}) && ($slot->{'endreserve'} < time)) { return 0; } &Apache::lonxml::debug("$slot_name reserve good"); my $userallowed=0; # its for a different set of users if (defined($slot->{'allowedsections'})) { if (!defined($env{'request.role.sec'}) && grep(/^No section assigned$/, split(',',$slot->{'allowedsections'}))) { $userallowed=1; } if (defined($env{'request.role.sec'}) && grep(/^\Q$env{'request.role.sec'}\E$/, split(',',$slot->{'allowedsections'}))) { $userallowed=1; } if (defined($env{'request.course.groups'})) { my @groups = split(/:/,$env{'request.course.groups'}); my @allowed_sec = split(',',$slot->{'allowedsections'}); foreach my $group (@groups) { if (grep {$_ eq $group} (@allowed_sec)) { $userallowed=1; last; } } } } &Apache::lonxml::debug("$slot_name sections is $userallowed"); # its for a different set of users if (defined($slot->{'allowedusers'}) && grep(/^\Q$env{'user.name'}:$env{'user.domain'}\E$/, split(',',$slot->{'allowedusers'}))) { $userallowed=1; } if (!defined($slot->{'allowedusers'}) && !defined($slot->{'allowedsections'})) { $userallowed=1; } &Apache::lonxml::debug("$slot_name user is $userallowed"); return 0 if (!$userallowed); # not allowed for this resource if (defined($slot->{'symb'}) && $slot->{'symb'} ne $symb) { unless ((ref($toskip) eq 'HASH') && ($toskip->{'symb'})) { return 0; } } my $conflict = &check_for_conflict($symb,$slot_name,$slot,$slots, $consumed_uniqueperiods); if ($conflict =~ /^error: /) { return 0; } elsif ($conflict ne '') { if ($slots->{$conflict}{'starttime'} < time) { return 0; } } &Apache::lonxml::debug("$slot_name symb good"); return 1; } sub get_description { my ($slot_name,$slot)=@_; my $description=$slot->{'description'}; if (!defined($description)) { $description=&mt('[_1] From [_2] to [_3]',$slot_name, &Apache::lonlocal::locallocaltime($slot->{'starttime'}), &Apache::lonlocal::locallocaltime($slot->{'endtime'})); } return $description; } sub show_choices { my ($r,$symb,$formname,$num,$slots,$consumed_uniqueperiods,$available,$got_slots)=@_; my $output; &Apache::lonxml::debug("Checking Slots"); if (!ref($available) eq 'ARRAY') { return; } if (!@{$available}) { $output = ''.&mt('No available times.').''; if ($env{'form.command'} ne 'manageresv') { $output .= ' '. &mt('Return to last resource').''; } $r->print($output); return; } if (@{$available} > 1) { my $numavailable = scalar(@{$available}); my $numreserved = 0; my $js; my $j = 0; foreach my $got (@{$got_slots}) { unless (($got eq '') || (!defined($got))) { $numreserved ++; if ($env{'form.command'} eq 'manageresv') { $js .= " currslot[$j]='$got';\n"; $j++; } } } my $showfilter = 'none'; $output .= ''; } $r->print($output); return; } sub to_show { my ($slotname,$slot,$when,$deleted,$name) = @_; my $time=time; my $week=60*60*24*7; if ($deleted eq 'hide' && $slot->{'type'} eq 'deleted') { return 0; } if ($name && $name->{'value'} =~ /\w/) { if ($name->{'type'} eq 'substring') { if ($slotname !~ /\Q$name->{'value'}\E/) { return 0; } } if ($name->{'type'} eq 'exact') { if ($slotname eq $name->{'value'}) { return 0; } } } if ($when eq 'any') { return 1; } elsif ($when eq 'now') { if ($time > $slot->{'starttime'} && $time < $slot->{'endtime'}) { return 1; } return 0; } elsif ($when eq 'nextweek') { if ( ($time < $slot->{'starttime'} && ($time+$week) > $slot->{'starttime'}) || ($time < $slot->{'endtime'} && ($time+$week) > $slot->{'endtime'}) ) { return 1; } return 0; } elsif ($when eq 'lastweek') { if ( ($time > $slot->{'starttime'} && ($time-$week) < $slot->{'starttime'}) || ($time > $slot->{'endtime'} && ($time-$week) < $slot->{'endtime'}) ) { return 1; } return 0; } elsif ($when eq 'willopen') { if ($time < $slot->{'starttime'}) { return 1; } return 0; } elsif ($when eq 'wereopen') { if ($time > $slot->{'endtime'}) { return 1; } return 0; } return 1; } sub remove_link { my ($slotname,$entry,$uname,$udom,$symb) = @_; my $remove = &mt('Remove'); if ($entry eq 'remove all') { $remove = &mt('Remove All'); undef($uname); undef($udom); } $slotname = &escape($slotname); $entry = &escape($entry); $uname = &escape($uname); $udom = &escape($udom); $symb = &escape($symb); return <<"END_LINK"; ($remove) END_LINK } sub show_table { my ($r,$mgr)=@_; my ($cnum,$cdom)=&get_course(); my $crstype=&Apache::loncommon::course_type($cdom.'_'.$cnum); my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum); if ( (keys(%slots))[0] =~ /^error: 2 /) { undef(%slots); } my $available; if ($mgr eq 'F') { # FIXME: This line should be deleted once Slots uses breadcrumbs $r->print('' .&mt('No slots have been created in this '.lc($crstype).'.') .'
' ); return; } my %Saveable_Parameters = ('show' => 'array', 'when' => 'scalar', 'order' => 'scalar', 'deleted' => 'scalar', 'name_filter_type' => 'scalar', 'name_filter_value' => 'scalar', ); &Apache::loncommon::store_course_settings('slotrequest', \%Saveable_Parameters); &Apache::loncommon::restore_course_settings('slotrequest', \%Saveable_Parameters); &Apache::grades::init_perm(); my ($classlist,$section,$fullname)=&Apache::grades::getclasslist('all'); &Apache::grades::reset_perm(); # what to display filtering my %show_fields=&Apache::lonlocal::texthash( 'name' => 'Slot Name', 'description' => 'Description', 'type' => 'Type', 'starttime' => 'Start time', 'endtime' => 'End Time', 'startreserve' => 'Time students can start reserving', 'endreserve' => 'Time students can no longer reserve', 'reservationmsg' => 'Message triggered by reservation', 'secret' => 'Secret Word', 'space' => '# of students/max', 'ip' => 'IP or DNS restrictions', 'symb' => 'Resource slot is restricted to.', 'allowedsections' => 'Sections slot is restricted to.', 'allowedusers' => 'Users slot is restricted to.', 'uniqueperiod' => 'Period of time slot is unique', 'scheduled' => 'Scheduled Students', 'proctor' => 'List of proctors'); if ($crstype eq 'Community') { $show_fields{'startreserve'} = &mt('Time members can start reserving'); $show_fields{'endreserve'} = &mt('Time members can no longer reserve'); $show_fields{'scheduled'} = &mt('Scheduled Members'); } my @show_order=('name','description','type','starttime','endtime', 'startreserve','endreserve','reservationmsg','secret','space', 'ip','symb','allowedsections','allowedusers','uniqueperiod', 'scheduled','proctor'); my @show = (exists($env{'form.show'})) ? &Apache::loncommon::get_env_multiple('form.show') : keys(%show_fields); my %show = map { $_ => 1 } (@show); #when filtering setup my %when_fields=&Apache::lonlocal::texthash( 'now' => 'Open now', 'nextweek' => 'Open within the next week', 'lastweek' => 'Were open last week', 'willopen' => 'Will open later', 'wereopen' => 'Were open', 'any' => 'Anytime', ); my @when_order=('any','now','nextweek','lastweek','willopen','wereopen'); $when_fields{'select_form_order'} = \@when_order; my $when = (exists($env{'form.when'})) ? $env{'form.when'} : 'now'; #display of students setup my %stu_display_fields= &Apache::lonlocal::texthash('username' => 'User name', 'fullname' => 'Full name', ); my @stu_display_order=('fullname','username'); my @stu_display = (exists($env{'form.studisplay'})) ? &Apache::loncommon::get_env_multiple('form.studisplay') : keys(%stu_display_fields); my %stu_display = map { $_ => 1 } (@stu_display); #name filtering setup my %name_filter_type_fields= &Apache::lonlocal::texthash('substring' => 'Substring', 'exact' => 'Exact', #'reg' => 'Regular Expression', ); my @name_filter_type_order=('substring','exact'); $name_filter_type_fields{'select_form_order'} = \@name_filter_type_order; my $name_filter_type = (exists($env{'form.name_filter_type'})) ? $env{'form.name_filter_type'} : 'substring'; my $name_filter = {'type' => $name_filter_type, 'value' => $env{'form.name_filter_value'},}; #deleted slot filtering #default to hide if no value $env{'form.deleted'} ||= 'hide'; my $hide_radio = &Apache::lonhtmlcommon::radio('deleted',$env{'form.deleted'},'hide'); my $show_radio = &Apache::lonhtmlcommon::radio('deleted',$env{'form.deleted'},'show'); $r->print(''); return; } sub manage_reservations { my ($r,$crstype,$slots,$consumed_uniqueperiods,$allavailable) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); $r->print(''
.&mt('Instructors may use a reservation system to place restrictions on when and where assignments can be worked on.')
.'
'
.&mt('One example is for management of laboratory space, which is only available at certain times, and has a limited number of seats.')
.'
'. &mt('Your reservation status for any such assignments is listed below:'). '
'. ''."\n"); for (my $i=0; $i<$depth; $i++) { $r->print(''); } my $result = ''. ''.$title.''.(' ' x6).' | '; my $hasaction; if ($status == $resource->OPEN) { if ($get_choices) { $hasaction = 1; } } if ($hasaction) { $result .= ''.$msg.' | '. ''; } else { $result .= ' | '.$msg.' | '; } $r->print($result); if ($hasaction) { my @got_slots=&check_for_reservation($symb,'allslots'); if ($got_slots[0] =~ /^error: /) { $r->print(''. &mt('An error occurred determining slot availability.'). ''); } else { my $formname = 'manageres_'.$reservable; if (ref($allavailable) eq 'ARRAY') { my @available; if (ref($slots) eq 'HASH') { foreach my $slot (@{$allavailable}) { # not allowed for this resource if (ref($slots->{$slot}) eq 'HASH') { if ((defined($slots->{$slot}->{'symb'})) && ($slots->{$slot}->{'symb'} ne $symb)) { next; } } push(@available,$slot); } } &show_choices($r,$symb,$formname,$reservable,$slots,$consumed_uniqueperiods, \@available,\@got_slots); } } $r->print(''); } $r->print('
'. &mt('Reservation History').'
'); } sub show_map_row { my ($depth,$location,$type,$title,$maprows) = @_; my $output = ''. &mt('Return to slot list').'
'); return; } my $formname = 'reservationslog'; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my %slotlog=&Apache::lonnet::dump('nohist_slotreservationslog',$cdom,$cnum); if ((keys(%slotlog))[0]=~/^error\:/) { undef(%slotlog); } my (%log,@allsymbs); if (keys(%slotlog)) { foreach my $key (keys(%slotlog)) { if (ref($slotlog{$key}) eq 'HASH') { if (ref($slotlog{$key}{'logentry'}) eq 'HASH') { if ($slotlog{$key}{'logentry'}{'slot'} eq $env{'form.slotname'}) { $log{$key} = $slotlog{$key}; if ($slotlog{$key}{'logentry'}{'symb'} ne '') { push(@allsymbs,$slotlog{$key}{'logentry'}{'symb'}); } } } } } } $r->print(''. ''. &mt('Return to slot list').'
'); return; } sub get_resource_title { my ($symb,$titles,$maptitles) = @_; my $title; if ((ref($titles) eq 'HASH') && (ref($maptitles) eq 'HASH')) { if (defined($titles->{$symb})) { $title = $titles->{$symb}; } else { $title = &Apache::lonnet::gettitle($symb); my $maptitle; my ($mapurl) = &Apache::lonnet::decode_symb($symb); if (defined($maptitles->{$mapurl})) { $maptitle = $maptitles->{$mapurl}; } else { if ($mapurl eq $env{'course.'.$env{'request.course.id'}.'.url'}) { $maptitle=&mt('Main Content'); } else { $maptitle=&Apache::lonnet::gettitle($mapurl); } $maptitles->{$mapurl} = $maptitle; } if ($maptitle ne '') { $title .= ' '.&mt('(in [_1])',$maptitle); } $titles->{$symb} = $title; } } else { $title = $symb; } return $title; } sub reservationlog_contexts { my ($crstype) = @_; my %lt = &Apache::lonlocal::texthash ( any => 'Any', user => 'By student', manage => 'Via Slot Manager', parameter => 'Via Parameter Manager', reserve => 'Made reservation', release => 'Dropped reservation', usermanage => 'By student', ); if ($crstype eq 'Community') { $lt{'user'} = &mt('By member'); $lt{'usermanage'} = $lt{'user'}; } return %lt; } sub display_filter { my ($formname,$cdom,$cnum,$curr,$version,$allsymbs) = @_; my $nolink = 1; my (%titles,%maptitles); my $output = ''.
''.&mt('Changes/page:').' '. &Apache::lonmeta::selectbox('show',$curr->{'show'},undef, (&mt('all'),5,10,20,50,100,1000,10000)). ' | '; my $startform = &Apache::lonhtmlcommon::date_setter($formname,'log_start_date', $curr->{'log_start_date'},undef, undef,undef,undef,undef,undef,undef,$nolink); my $endform = &Apache::lonhtmlcommon::date_setter($formname,'log_end_date', $curr->{'log_end_date'},undef, undef,undef,undef,undef,undef,undef,$nolink); my $crstype = &Apache::loncommon::course_type(); my %lt = &reservationlog_contexts($crstype); $output .= ' | '.&mt('Window during which changes occurred:').
'
| '; if (ref($allsymbs) eq 'ARRAY') { $output .= ' | '.&mt('Resource').' '. ' | '.
&mt('Context:').' | ';
} else {
$output .= ''.&mt('Action').' '. ' | ';
}
$output .= '
'. &mt('Only changes made from servers running LON-CAPA [_1] or later are displayed.' ,'2.9.0'); if ($version) { $output .= ' '.&mt('This LON-CAPA server is version [_1]',$version); } $output .= '
'.&mt('Created [quant,_1,slot]',$countdone)."\n".'
'); foreach my $error (@errors) { $r->print(''.$error.'
'."\n"); } &show_table($r,$mgr); return ''; } sub slot_command_titles { my %titles = ( slotlog => 'Reservation Logs', showslots => 'Manage Slots', showresv => 'Reservation History', manageresv => 'Manage Reservations', uploadstart => 'Upload Slots File', csvuploadmap => 'Upload Slots File', csvuploadassign => 'Upload Slots File', delete => 'Slot Deletion', release => 'Reservation Result', remove_reservation => 'Remove Registration', get_reservation => 'Request Reservation', ); return %titles; } sub slot_reservationmsg_options { my %options = &Apache::lonlocal::texthash ( only_student => 'Sent to student', student_and_user_notes_screen => 'Sent to student and added to user notes', none => 'None sent and no record in user notes', ); return %options; } sub handler { my $r=shift; &Apache::loncommon::content_type($r,'text/html'); &Apache::loncommon::no_cache($r); if ($r->header_only()) { $r->send_http_header(); return OK; } &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}); my %crumb_titles = &slot_command_titles(); my $brcrum; my $vgr=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}); my $mgr=&Apache::lonnet::allowed('mgr',$env{'request.course.id'}); my (%slots,$consumed_uniqueperiods); if ($env{'form.command'} eq 'showslots') { if (($vgr ne 'F') && ($mgr ne 'F')) { $env{'form.command'} = 'manageresv'; } } elsif ($env{'form.command'} eq 'manageresv') { if (($vgr eq 'F') || ($mgr eq 'F')) { $env{'form.command'} = 'showslots'; } } my $title='Requesting Another Worktime'; if ($env{'form.command'} eq 'showresv') { $title = 'Reservation History'; if ($env{'form.origin'} eq 'aboutme') { $brcrum =[{href=>"/adm/$env{'form.udom'}/$env{'form.uname'}/aboutme",text=>'Personal Information Page'}]; } else { $brcrum =[{href=>"/adm/slotrequest?command=manageresv",text=>'Manage Reservations'}]; } if (ref($brcrum) eq 'ARRAY') { push(@{$brcrum},{href=>"/adm/slotrequest?command=showresv",text=>$title}); } } elsif (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) { if ($env{'form.command'} eq 'manageresv') { $title = 'Manage Reservations'; $brcrum =[{href=>"/adm/slotrequest?command=manageresv",text=>$title}]; } my ($cnum,$cdom)=&get_course(); %slots = &Apache::lonnet::get_course_slots($cnum,$cdom); $consumed_uniqueperiods = &get_consumed_uniqueperiods(\%slots); } elsif ($vgr eq 'F') { if ($env{'form.command'} =~ /^(slotlog|showslots|uploadstart|csvuploadmap|csvuploadassign|delete|release|remove_registration)$/) { $brcrum =[{href=>"/adm/slotrequest?command=showslots", text=>$crumb_titles{'showslots'}}]; $title = 'Managing Slots'; unless ($env{'form.command'} eq 'showslots') { if (ref($brcrum) eq 'ARRAY') { push(@{$brcrum},{href=>"/adm/slotrequest?command=$env{'form.command'}",text=>$crumb_titles{$env{'form.command'}}}); } } } } elsif ($env{'form.command'} eq 'release') { if ($env{'form.context'} eq 'usermanage') { $brcrum =[{href=>"/adm/slotrequest?command=manageresv", text=>$crumb_titles{'showslots'}}]; $title = 'Manage Reservations'; if (ref($brcrum) eq 'ARRAY') { push(@{$brcrum},{href=>"/adm/slotrequest?command=$env{'form.command'}",text=>$crumb_titles{$env{'form.command'}}}); } } } else { $brcrum =[]; } my ($symb,$js,$available,$allavailable,$got_slots); $available = []; if ($env{'form.requestattempt'}) { $symb=&unescape($env{'form.symb'}); @{$got_slots}=&check_for_reservation($symb,'allslots'); } if (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) { $js = &reservation_js(\%slots,$consumed_uniqueperiods,$available,$got_slots,$symb); } &start_page($r,$title,$brcrum,$js); if ($env{'form.command'} eq 'manageresv') { $allavailable = $available; undef($available); undef($got_slots); my $crstype = &Apache::loncommon::course_type(); &manage_reservations($r,$crstype,\%slots,$consumed_uniqueperiods,$allavailable); } elsif ($env{'form.command'} eq 'showresv') { &show_reservations($r,$env{'form.uname'},$env{'form.udom'}); } elsif ($env{'form.command'} eq 'showslots' && $vgr eq 'F') { &show_table($r,$mgr); } elsif ($env{'form.command'} eq 'remove_registration' && $mgr eq 'F') { &remove_registration($r); } elsif ($env{'form.command'} eq 'release' && $mgr eq 'F') { if ($env{'form.entry'} eq 'remove all') { &release_all_slot($r,$mgr); } else { &release_slot($r,undef,undef,undef,$mgr); } } elsif ($env{'form.command'} eq 'delete' && $mgr eq 'F') { &delete_slot($r); } elsif ($env{'form.command'} eq 'uploadstart' && $mgr eq 'F') { &upload_start($r); } elsif ($env{'form.command'} eq 'csvuploadmap' && $mgr eq 'F') { &csv_upload_map($r); } elsif ($env{'form.command'} eq 'csvuploadassign' && $mgr eq 'F') { if ($env{'form.associate'} ne 'Reverse Association') { &csv_upload_assign($r,$mgr); } else { if ( $env{'form.upfile_associate'} ne 'reverse' ) { $env{'form.upfile_associate'} = 'reverse'; } else { $env{'form.upfile_associate'} = 'forward'; } &csv_upload_map($r); } } elsif ($env{'form.command'} eq 'slotlog' && $mgr eq 'F') { &show_reservations_log($r); } else { my $symb=&unescape($env{'form.symb'}); if (!defined($symb)) { &fail($r,'not_valid'); return OK; } my (undef,undef,$res)=&Apache::lonnet::decode_symb($symb); my $useslots = &Apache::lonnet::EXT("resource.0.useslots",$symb); if ($useslots ne 'resource' && $useslots ne 'map' && $useslots ne 'map_map') { &fail($r,'not_available'); return OK; } $env{'request.symb'}=$symb; my $type = ($res =~ /\.task$/) ? 'Task' : 'problem'; my ($status) = &Apache::lonhomework::check_slot_access('0',$type); if ($status eq 'CAN_ANSWER' || $status eq 'NEEDS_CHECKIN' || $status eq 'WAITING_FOR_GRADE') { &fail($r,'not_allowed'); return OK; } if ($env{'form.requestattempt'}) { $r->print(''.&mt('Unknown command: [_1]',$env{'form.command'}).'
'); } } &end_page($r); return OK; } 1; __END__