--- loncom/interface/slotrequest.pm 2008/12/21 04:14:39 1.85 +++ loncom/interface/slotrequest.pm 2018/07/02 20:34:52 1.139 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler for requesting to have slots added to a students record # -# $Id: slotrequest.pm,v 1.85 2008/12/21 04:14:39 raeburn Exp $ +# $Id: slotrequest.pm,v 1.139 2018/07/02 20:34:52 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,7 +37,7 @@ use Apache::lonnet; use Apache::lonnavmaps(); use Date::Manip; use lib '/home/httpd/lib/perl/'; -use LONCAPA; +use LONCAPA qw(:DEFAULT :match); sub fail { my ($r,$code)=@_; @@ -56,8 +56,22 @@ sub fail { } sub start_page { - my ($r,$title)=@_; - $r->print(&Apache::loncommon::start_page($title)); + 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 { @@ -65,6 +79,291 @@ sub end_page { $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 @@ -117,7 +416,6 @@ 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)); @@ -133,22 +431,20 @@ sub check_for_reservation { return 'error: Unable to determine current status'; } my @got; - foreach my $slot_name (sort { - if (ref($slots{$a}) && ref($slots{$b})) { - return $slots{$a}{'starttime'} <=> $slots{$b}{'starttime'} - } - if (ref($slots{$a})) { return -1;} - if (ref($slots{$b})) { return 1;} - return 0; - } @slots) { + 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'}); - if ($slots{$slot_name}->{'endtime'} > time && - $slots{$slot_name}->{'startreserve'} < time) { - # between start of reservation times and end of slot + $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 { @@ -169,7 +465,7 @@ sub get_consumed_uniqueperiods { return 'error: Unable to determine current status'; } my @problems = $navmap->retrieveResources(undef, - sub { $_[0]->is_problem() },1,0); + sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0); my %used_slots; foreach my $problem (@problems) { my $symb = $problem->symb(); @@ -216,16 +512,19 @@ sub check_for_conflict { if (!defined($new_slot->{'uniqueperiod'})) { return undef; } if (!ref($consumed_uniqueperiods)) { - $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'; - } + if ($consumed_uniqueperiods =~ /^error: /) { + return $consumed_uniqueperiods; } else { - return 'error: Unable to determine current status'; + $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}}; @@ -239,9 +538,7 @@ sub check_for_conflict { } sub make_reservation { - my ($slot_name,$slot,$symb)=@_; - - my ($cnum,$cdom)=&get_course(); + my ($slot_name,$slot,$symb,$cnum,$cdom)=@_; my $value=&Apache::lonnet::EXT("resource.0.availablestudent",$symb, $env{'user.domain'},$env{'user.name'}); @@ -315,13 +612,7 @@ sub make_reservation { if ($value) { $new_value=$value.':'.$new_value; } - my $result=&Apache::lonparmset::storeparm_by_symb($symb, - '0_availablestudent', - $parm_level, $new_value, - 'string', - $env{'user.name'}, - $env{'user.domain'}); - &Apache::lonxml::debug("hrrm $result"); + &store_slot_parm($symb,$slot_name,$parm_level,$new_value,$cnum,$cdom); return $wanted; } @@ -329,6 +620,32 @@ sub make_reservation { return undef; } +sub store_slot_parm { + my ($symb,$slot_name,$parm_level,$new_value,$cnum,$cdom) = @_; + my $result=&Apache::lonparmset::storeparm_by_symb($symb, + '0_availablestudent', + $parm_level, $new_value, + 'string', + $env{'user.name'}, + $env{'user.domain'}); + &Apache::lonxml::debug("hrrm $result"); + my %storehash = ( + symb => $symb, + slot => $slot_name, + action => 'reserve', + context => $env{'form.context'}, + ); + + &Apache::lonnet::write_log('course','slotreservationslog',\%storehash, + '',$env{'user.name'},$env{'user.domain'}, + $cnum,$cdom); + &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash, + 1,$env{'user.name'},$env{'user.domain'}, + $env{'user.name'},$env{'user.domain'}); + + return; +} + sub remove_registration { my ($r) = @_; if ($env{'form.entry'} ne 'remove all') { @@ -345,8 +662,8 @@ sub remove_registration { return; } if (!%consumed) { - $r->print("

".&mt('Slot [_1] has no reservations.', - $slot_name)."

"); + $r->print('

'.&mt('Slot [_1] has no reservations.', + ''.$slot_name.'').'

'); return; } @@ -354,7 +671,7 @@ sub remove_registration { my $names = join(' ',@names); my $msg = &mt('Remove all of [_1] from slot [_2]?',$names,$slot_name); - &remove_registration_confirmation($r,$msg,['entry','slotname']); + &remove_registration_confirmation($r,$msg,['entry','slotname','context']); } sub remove_registration_user { @@ -371,7 +688,7 @@ sub remove_registration_user { $name,$slot_name,$title); &remove_registration_confirmation($r,$msg,['uname','udom','slotname', - 'entry','symb']); + 'entry','symb','context']); } sub remove_registration_confirmation { @@ -383,8 +700,10 @@ sub remove_registration_confirmation { '&\'').'" />'."\n"; } - my %lt = &Apache::lonlocal::texthash('yes' => 'Yes', - 'no' => 'No',); + my %lt = &Apache::lonlocal::texthash( + 'yes' => 'Yes', + 'no' => 'No', + ); $r->print(<<"END_CONFIRM");

$msg

@@ -482,14 +801,20 @@ sub release_reservation { return (0,'error: Unable to determine current status'); } my $passed_resource = $navmap->getBySymb($symb); - if ($passed_resource->is_map()) { - my ($a_resource) = - $navmap->retrieveResources($passed_resource, - sub {$_[0]->is_problem()},0,1); - $symb = $a_resource->symb(); + if (ref($passed_resource)) { + if ($passed_resource->is_map()) { + my ($a_resource) = + $navmap->retrieveResources($passed_resource, + sub {$_[0]->is_problem() || $_[0]->is_tool() },0,1); + $symb = $a_resource->symb(); + } + } else { + unless ($mgr eq 'F') { + return (0,'error: Unable to determine current status'); + } } - # get parameter string, check for existance, rebuild string with the slot + # 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); @@ -510,6 +835,16 @@ sub release_reservation { 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('course','slotreservationslog', + \%storehash,1,$uname,$udom,$cnum,$cdom); + &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog', + \%storehash,1,$uname,$udom,$uname,$udom); } } @@ -530,12 +865,15 @@ sub release_reservation { '0_availablestudent', $parm_level, $new_param, 'string', $uname, $udom); - my $msg; if ($mgr eq 'F') { $msg = &mt('Released Reservation for user: [_1]',"$uname:$udom"); } else { - $msg = &mt('Released Reservation: [_1]',$description); + $msg = ''.&mt('Released reservation: [_1]',$description).'

'; + my $person = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'}); + my $subject = &mt('Reservation change: [_1]',$description); + my $msgbody = &mt('Reservation released by [_1] for [_2].',$person,$description); + $msg .= &slot_change_messaging($slot{'reservationmsg'},$subject,$msgbody,'release'); } return (1,$msg); } @@ -557,15 +895,15 @@ sub delete_slot { my $ret = &Apache::lonnet::cput('slots', {$slot_name => \%slot}, $cdom, $cnum); if ($ret eq 'ok') { - $r->print("

Slot $slot_name marked as deleted.

"); + $r->print('

'.&mt('Slot [_1] marked as deleted.',''.$slot_name.'').'

'); } else { - $r->print("

An error ($ret) occurse when attempting to delete Slot $slot_name.

"); + $r->print('

'.&mt('An error occurred when attempting to delete slot: [_1]',''.$slot_name.'')." ($ret)

"); } } else { if (%consumed) { - $r->print("

Slot $slot_name has active reservations.

"); + $r->print('

'.&mt('Slot [_1] has active reservations.',''.$slot_name.'').'

'); } else { - $r->print("

Slot $slot_name does not exist.

"); + $r->print('

'.&mt('Slot [_1] does not exist.',''.$slot_name.'').'

'); } } $r->print('

'. @@ -575,8 +913,13 @@ sub delete_slot { sub return_link { my ($r) = @_; - $r->print('

'. - &mt('Return to last resource').'

'); + 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').'

'); + } } sub get_slot { @@ -595,10 +938,15 @@ sub get_slot { if ($slot_name && $slot_name ne $conflictable_slot) { my %slot=&Apache::lonnet::get_slot($slot_name); my $description1=&get_description($slot_name,\%slot); + my $slottype1=$slot{'type'}; %slot=&Apache::lonnet::get_slot($env{'form.slotname'}); my $description2=&get_description($env{'form.slotname'},\%slot); - $r->print("

Already have a reservation: $description1

"); - if ($slot_name ne $env{'form.slotname'}) { + if ($slottype1 eq 'preassigned') { + $r->print('

'.&mt('You already have a reservation: "[_1]", assigned by your instructor.', + $description1).'

'. + '

'.&mt('Your instructor must unassign it before you can make a new reservation.'). + '

'); + } elsif ($slot_name ne $env{'form.slotname'}) { $r->print(< @@ -606,25 +954,32 @@ sub get_slot { STUFF - $r->print("

You can either "); - $r->print(< -STUFF - $r->print(' your reservation from '.$description1.' to '. - $description2. - '
or

'); - &return_link($r); + $r->print('

'.&mt('Reservation currently unchanged').'

'); + if ($slot_name ne '') { + $r->print('

'.&mt('To complete the transaction you [_1]must confirm[_2] you want to [_3]process the change[_4] to [_5].' + ,'','','','',''.$description2.'') + .'
' + .&mt('Or you can choose to [_1]make no change[_2] and continue[_2] with the reservation you already had: [_3].' + ,'','',''.$description1.'') + .'

' + .'' + .(' 'x3) + .'' + .'

'); + } $r->print(< STUFF } else { + $r->print('

'.&mt('Already have a reservation: [_1].',$description1).'

'); &return_link($r); } return 0; } + my ($cnum,$cdom)=&get_course(); my $reserved=&make_reservation($env{'form.slotname'}, - \%slot,$symb); + \%slot,$symb,$cnum,$cdom); my $description=&get_description($env{'form.slotname'},\%slot); if (defined($reserved)) { my $retvalue = 0; @@ -633,26 +988,35 @@ STUFF .&mt('An error occurred while attempting to make a reservation. ([_1])',$1) .'

'); } elsif ($reserved > -1) { - $r->print("

Success: $description

"); + $r->print('

'.&mt('Successfully signed up: [_1]',$description).'

'); $retvalue = 1; + my $person = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'}); + my $subject = &mt('Reservation change: [_1]',$description); + my $msgbody = &mt('Successful reservation by [_1] for [_2].',$person,$description); + my $msg = &slot_change_messaging($slot{'reservationmsg'},$subject,$msgbody,'reserve'); + if ($msg) { + $r->print($msg); + } } elsif ($reserved < 0) { - $r->print("

Already reserved: $description

"); + $r->print('

'.&mt('Already reserved: [_1]',$description).'

'); } if (!$inhibit_return_link) { &return_link($r); } return 1; } - my %lt=('request'=>"Availibility list", - 'try' =>'Try again'); - %lt=&Apache::lonlocal::texthash(%lt); + my %lt = &Apache::lonlocal::texthash( + 'request' => 'Availability list', + 'try' => 'Try again?', + 'or' => 'or', + ); my $extra_input; if ($conflictable_slot) { $extra_input=''; } + $r->print('

'.&mt('[_1]Failed[_2] to reserve a slot for [_3].','','',$description).'

'); $r->print(< Failed to reserve a spot for $description.

@@ -661,24 +1025,26 @@ STUFF $extra_input

-?

-or +$lt{'or'}

-

-or STUFF - if (!$inhibit_return_link) { &return_link($r); } + 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)=@_; + my ($slot_name,$slot,$symb,$slots,$consumed_uniqueperiods,$toskip)=@_; #already started if ($slot->{'starttime'} < time) { @@ -703,6 +1069,11 @@ sub allowed_slot { 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; @@ -747,16 +1118,40 @@ sub allowed_slot { return 0 if (!$userallowed); # not allowed for this resource - if (defined($slot->{'symb'}) - && $slot->{'symb'} ne $symb) { - return 0; + if (defined($slot->{'symb'})) { + my $exclude = 1; + my @symbs; + if ($slot->{'symb'} =~ /,/) { + @symbs = split(/\s*,\s*/,$slot->{'symb'}); + } else { + @symbs = ($slot->{'symb'}); + } + my ($map,$id,$url) = &Apache::lonnet::decode_symb($symb); + foreach my $reqsymb (@symbs) { + next if ($reqsymb eq ''); + my ($slotmap,$slotid,$sloturl) = &Apache::lonnet::decode_symb($reqsymb); + if ($sloturl=~/\.(page|sequence)$/) { + if (($map ne '') && ($map eq $sloturl)) { + $exclude = 0; + last; + } + } elsif ($reqsymb eq $symb) { + $exclude = 0; + last; + } + } + if ($exclude) { + 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; - } else { + } elsif ($conflict ne '') { if ($slots->{$conflict}{'starttime'} < time) { return 0; } @@ -777,63 +1172,119 @@ sub get_description { } sub show_choices { - my ($r,$symb)=@_; - - my ($cnum,$cdom)=&get_course(); - my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum); - my $consumed_uniqueperiods = &get_consumed_uniqueperiods(\%slots); - if (ref($consumed_uniqueperiods) eq 'HASH') { - if (&Apache::lonnet::error(%$consumed_uniqueperiods)) { - $r->print(''. - &mt('An error occurred determining slot availability'). - ''); - return; - } - } elsif ($consumed_uniqueperiods =~ /^error: /) { - $r->print(''. - &mt('An error occurred determining slot availability'). - ''); - return; - } - my $available; + my ($symb,$formname,$num,$class,$slots,$consumed_uniqueperiods,$available,$got_slots)=@_; + my $output; &Apache::lonxml::debug("Checking Slots"); - my @got_slots=&check_for_reservation($symb,'allslots'); - if ($got_slots[0] =~ /^error: /) { - $r->print(''. - &mt('An error occurred determining slot availability'). - ''); + if (!ref($available) eq 'ARRAY') { return; } - $r->print(''); - foreach my $slot (sort - { return $slots{$a}->{'starttime'} <=> $slots{$b}->{'starttime'} } - (keys(%slots))) { - - &Apache::lonxml::debug("Checking Slot $slot"); - next if (!&allowed_slot($slot,$slots{$slot},undef,\%slots, - $consumed_uniqueperiods)); - - $available++; - - my $description=&get_description($slot,$slots{$slot}); + if (!@{$available}) { + $output = ''.&mt('No available times.').''; + if ($env{'form.command'} ne 'manageresv') { + $output .= ' '. + &mt('Return to last resource').''; + } + if ($class) { + return '
'.$output.'
'; + } else { + return $output; + } + } + 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 .= '
'.&mt('Actions').''."\n". + '
'; + my @options = ('all','filter'); + if ($numreserved) { + unshift(@options,'show'); + } + my %resmenu = &Apache::lonlocal::texthash ( + show => 'Show current reservation', + all => 'Show all', + filter => 'Search by date', + ); + foreach my $option (@options) { + my $onclick = "toggleSlotDisplay(this.form,'$num');"; + if (($option eq 'show') && ($env{'form.command'} eq 'manageresv')) { + $onclick .= "currSlotDisplay$num(this.form,'$num');"; + } + $output .= ''.(' ' x3)."\n"; + } + $output .= ''; + my $chooserform = 'reservationchooser_'.$num; + my $starttime = $slots->{$available->[0]}->{'starttime'}; + my $endtime = $slots->{$available->[-1]}->{'starttime'}; + if ($env{'form.command'} eq 'manageresv') { + $output .= <<"ENDSCRIPT"; + + - my $form=&mt('Unavailable'); - if ((grep(/^\Q$slot\E$/,@got_slots)) || - &space_available($slot,$slots{$slot},$symb)) { +ENDSCRIPT + } + $output .= + '
'. + '
'. + '
'.&mt('Open after').''. + &Apache::lonhtmlcommon::date_setter($chooserform,'start',$starttime,'','','','','','','',1,1). + '
'.&mt('Closed before').''. + &Apache::lonhtmlcommon::date_setter($chooserform,'end',$endtime,'','','','','','','',1,1). + '

'. + ''. + ''; + } + if ($class) { + return '
'.$output.'
'; + } else { + return $output; } - $r->print(''); } sub to_show { @@ -946,7 +1424,7 @@ sub remove_link { $symb = &escape($symb); return <<"END_LINK"; - ($remove) END_LINK @@ -956,6 +1434,7 @@ 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); @@ -963,7 +1442,8 @@ sub show_table { my $available; if ($mgr eq 'F') { # FIXME: This line should be deleted once Slots uses breadcrumbs - $r->print(&Apache::loncommon::help_open_topic('Slot About', 'Help on slots')); + $r->print('
'.&Apache::loncommon::help_open_topic( + 'Slot About', &mt('Help on slots'))); $r->print('
'); $r->print('
@@ -977,6 +1457,15 @@ sub show_table { $r->print(&Apache::loncommon::help_open_topic('Slot AddInterface')); $r->print('
'); } + + if (!keys(%slots)) { + $r->print( + '

' + .&mt('No slots have been created in this '.lc($crstype).'.') + .'

' + ); + return; + } my %Saveable_Parameters = ('show' => 'array', 'when' => 'scalar', @@ -1001,18 +1490,26 @@ sub show_table { '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.', + 'symb' => 'Resource(s)/Map(s) 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'); + 'proctor' => 'List of proctors', + 'iptied' => 'Unique IP each student',); + 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','secret','space','ip','symb', - 'allowedsections','allowedusers','uniqueperiod', + 'startreserve','endreserve','reservationmsg','secret','space', + 'ip','iptied','symb','allowedsections','allowedusers','uniqueperiod', 'scheduled','proctor'); my @show = (exists($env{'form.show'})) ? &Apache::loncommon::get_env_multiple('form.show') @@ -1078,31 +1575,31 @@ sub show_table { '.&mt('Slot Name Filter').' '.&mt('Options').' - '.&Apache::loncommon::multiple_select_form('show',\@show,6,\%show_fields,\@show_order). + '.&Apache::loncommon::multiple_select_form('show',\@show,6,\%show_fields,\@show_order). ' - + '.&Apache::loncommon::multiple_select_form('studisplay',\@stu_display, 6,\%stu_display_fields, \@stu_display_order).' - '.&Apache::loncommon::select_form($when,'when',%when_fields). + '.&Apache::loncommon::select_form($when,'when',\%when_fields). ' - '.&Apache::loncommon::select_form($name_filter_type, + '.&Apache::loncommon::select_form($name_filter_type, 'name_filter_type', - %name_filter_type_fields). + \%name_filter_type_fields). '
'. &Apache::lonhtmlcommon::textbox('name_filter_value', $env{'form.name_filter_value'}, 15). ' - + - - + + - +
Deleted slots:'.&mt('Deleted slots:').'
@@ -1111,19 +1608,20 @@ sub show_table { $r->print(''); $r->print('

'); my $linkstart=''.$show_fields{$which}.''); + $tableheader .= ''.$linkstart.$which.'">'.$show_fields{$which}.''; } } - $r->print(&Apache::loncommon::end_data_table_header_row()); + $tableheader .= &Apache::loncommon::end_data_table_header_row(); + my $shownheader = 0; my %name_cache; my $slotsort = sub { - if ($env{'form.order'}=~/^(type|description|endtime|startreserve|ip|symb|allowedsections|allowedusers)$/) { + if ($env{'form.order'}=~/^(type|description|endtime|startreserve|endreserve|ip|symb|allowedsections|allowedusers|reservationmsg)$/) { if (lc($slots{$a}->{$env{'form.order'}}) ne lc($slots{$b}->{$env{'form.order'}})) { return (lc($slots{$a}->{$env{'form.order'}}) @@ -1160,12 +1658,15 @@ sub show_table { if ($tmp =~ /^error: /) { undef(%consumed); } } + my %msgops = &slot_reservationmsg_options(); + foreach my $slot (sort $slotsort (keys(%slots))) { if (!&to_show($slot,$slots{$slot},$when, $env{'form.deleted'},$name_filter)) { next; } + my $reservemsg; if (defined($slots{$slot}->{'type'}) - && $slots{$slot}->{'type'} ne 'schedulable_student') { - #next; + && $slots{$slot}->{'type'} eq 'schedulable_student') { + $reservemsg = $msgops{$slots{$slot}->{'reservationmsg'}}; } my $description=&get_description($slot,$slots{$slot}); my ($id_count,$ids); @@ -1202,6 +1703,8 @@ sub show_table { &Apache::lonlocal::locallocaltime($slots{$slot}->{'endtime'}):''); my $start_reserve=($slots{$slot}->{'startreserve'}? &Apache::lonlocal::locallocaltime($slots{$slot}->{'startreserve'}):''); + my $end_reserve=($slots{$slot}->{'endreserve'}? + &Apache::lonlocal::locallocaltime($slots{$slot}->{'endreserve'}):''); my $unique; if (ref($slots{$slot}{'uniqueperiod'})) { @@ -1209,13 +1712,21 @@ sub show_table { localtime($slots{$slot}{'uniqueperiod'}[1]); } - my $title; + my @titles; if (exists($slots{$slot}{'symb'})) { - my (undef,undef,$res)= - &Apache::lonnet::decode_symb($slots{$slot}{'symb'}); - $res = &Apache::lonnet::clutter($res); - $title = &Apache::lonnet::gettitle($slots{$slot}{'symb'}); - $title=''.$title.''; + my @symbs; + if ($slots{$slot}{'symb'} =~ /,/) { + @symbs = split(/\s*,\s*/,$slots{$slot}{'symb'}); + } else { + @symbs = ($slots{$slot}{'symb'}); + } + foreach my $reqsymb (@symbs) { + my (undef,undef,$res) = + &Apache::lonnet::decode_symb($reqsymb); + $res = &Apache::lonnet::clutter($res); + my $title = &Apache::lonnet::gettitle($reqsymb); + push(@titles,''.$title.''); + } } my $allowedsections; @@ -1258,26 +1769,48 @@ sub show_table { } my $proctors=join(', ',@proctors); - my $edit=(<<"EDITLINK"); -Edit + my %lt = &Apache::lonlocal::texthash ( + edit => 'Edit', + delete => 'Delete', + slotlog => 'History', + ); + my ($edit,$delete,$showlog,$remove_all); + if ($mgr) { + $edit=(<<"EDITLINK"); +$lt{'edit'} EDITLINK - my $delete=(<<"DELETELINK"); -Delete + $delete=(<<"DELETELINK"); +$lt{'delete'} DELETELINK - my $remove_all=&remove_link($slot,'remove all').'
'; + $remove_all=&remove_link($slot,'remove all').'
'; + + if ($ids eq '') { + undef($remove_all); + } else { + undef($delete); + } + } + + $showlog=(<<"LOGLINK"); +$lt{'slotlog'} +LOGLINK - if ($ids ne '') { undef($delete); } - if ($slots{$slot}{'type'} ne 'schedulable_student' - || $ids eq '') { + if ($slots{$slot}{'type'} ne 'schedulable_student') { + undef($showlog); undef($remove_all); } + unless ($shownheader) { + $r->print($tableheader); + $shownheader = 1; + } + my $row_start=&Apache::loncommon::start_data_table_row(); my $row_end=&Apache::loncommon::end_data_table_row(); $r->print($row_start. - "\n$edit $delete\n"); + "\n$edit $delete $showlog\n"); if (exists($show{'name'})) { $colspan++;$r->print("$slot"); } @@ -1296,6 +1829,12 @@ DELETELINK if (exists($show{'startreserve'})) { $colspan++;$r->print("$start_reserve\n"); } + if (exists($show{'endreserve'})) { + $colspan++;$r->print("$end_reserve\n"); + } + if (exists($show{'reservationmsg'})) { + $colspan++;$r->print("$reservemsg\n"); + } if (exists($show{'secret'})) { $colspan++;$r->print("$slots{$slot}{'secret'}\n"); } @@ -1312,8 +1851,18 @@ DELETELINK if (exists($show{'ip'})) { $colspan++;$r->print("$slots{$slot}{'ip'}\n"); } + if (exists($show{'iptied'})) { + $colspan++; + if ($slots{$slot}{'iptied'} eq 'yes') { + $r->print(''.&mt('Yes')."\n"); + } elsif ($slots{$slot}{'iptied'} eq 'answer') { + $r->print(''.&mt('Yes, including post-answer date')."\n"); + } else { + $r->print(''.&mt('No')."\n"); + } + } if (exists($show{'symb'})) { - $colspan++;$r->print("$title\n"); + $colspan++;$r->print("".join('
',@titles)."\n"); } if (exists($show{'allowedsections'})) { $colspan++;$r->print("$allowedsections\n"); @@ -1336,30 +1885,905 @@ $row_end STUFF } } - $r->print(''); + if ($shownheader) { + $r->print(&Apache::loncommon::end_data_table()); + } else { + $r->print('

'.&mt('No slots meet the criteria for display').'

'); + } + $r->print(''); + return; +} + +sub manage_reservations { + my ($r,$crstype,$slots,$consumed_uniqueperiods,$allavailable) = @_; + my ($cnum,$cdom)=&get_course(); + 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.') + .'

' + ); + if (!defined($navmap)) { + $r->print('
'); + if ($crstype eq 'Community') { + $r->print(&mt('Unable to retrieve information about community contents')); + } else { + $r->print(&mt('Unable to retrieve information about course contents')); + } + $r->print('
'); + &Apache::lonnet::logthis('Manage Reservations - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'}); + return; + } + if (ref($consumed_uniqueperiods) eq 'HASH') { + if (&Apache::lonnet::error(%$consumed_uniqueperiods)) { + $r->print(''. + &mt('An error occurred determining slot availability.'). + ''); + return; + } + } elsif ($consumed_uniqueperiods =~ /^error: /) { + $r->print(''. + &mt('An error occurred determining slot availability.'). + ''); + return; + } + my (%output,%slotinfo,%statusbymap,%repsymbs,%shownmaps); + my @possibles = $navmap->retrieveResources(undef, + sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0); + + foreach my $resource (@possibles) { + my ($useslots) = $resource->slot_control(); + next if (($useslots eq '') || ($useslots =~ /^\s*no\s*$/i)); + my $symb = $resource->symb(); + my ($slot_status,$date,$slot_name) = $resource->check_for_slot('0'); + my ($msg,$get_choices,$slotdescription); + my $status = $resource->simpleStatus('0'); + my ($msg,$get_choices,$slotdescription); + if ($slot_name ne '') { + my %slot=&Apache::lonnet::get_slot($slot_name); + $slotdescription=&get_description($slot_name,\%slot); + } + if ($slot_status == $resource->NOT_IN_A_SLOT) { + $msg=&mt('No current reservation.'); + $get_choices = 1; + } elsif ($slot_status == $resource->NEEDS_CHECKIN) { + $msg=''.&mt('Reserved:'). + ' '.$slotdescription.'
'. + &mt('Access requires proctor validation.'); + } elsif ($slot_status == $resource->WAITING_FOR_GRADE) { + $msg=&mt('Submitted and currently in grading queue.'); + } elsif ($slot_status == $resource->CORRECT) { + $msg=&mt('Problem is unavailable.'); + } elsif ($slot_status == $resource->RESERVED) { + $msg=''.&mt('Reserved:'). + ' '.$slotdescription.'
'. + &mt('Problem is currently available.'); + } elsif ($slot_status == $resource->RESERVED_LOCATION) { + $msg=''.&mt('Reserved:'). + ' '.$slotdescription.'
'. + &mt('Problem is available at a different location.'); + $get_choices = 1; + } elsif ($slot_status == $resource->RESERVED_LATER) { + $msg=''.&mt('Reserved:'). + ' '.$slotdescription.'
'. + &mt('Problem will be available later.'); + $get_choices = 1; + } elsif ($slot_status == $resource->RESERVABLE) { + $msg=&mt('Reservation needed'); + $get_choices = 1; + } elsif ($slot_status == $resource->RESERVABLE_LATER) { + $msg=&mt('Reservation needed: will be reservable later.'); + } elsif ($slot_status == $resource->NOTRESERVABLE) { + $msg=&mt('Reservation needed: none available.'); + } elsif ($slot_status == $resource->UNKNOWN) { + $msg=&mt('Unable to determine status due to network problems.'); + } else { + if ($status != $resource->OPEN) { + $msg = &Apache::lonnavmaps::getDescription($resource,'0'); + } + } + $output{$symb}{'msg'} = $msg; + if (($status == $resource->OPEN) && ($get_choices)) { + $output{$symb}{'hasaction'} = 1; + } + my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb); + $mapurl = &Apache::lonnet::clutter($mapurl); + unless ($mapurl =~ /default\.sequence$/) { + $shownmaps{$mapurl} = 1; + my $map = $navmap->getResourceByUrl($mapurl); + if (ref($map)) { + my @pcs = split(/,/,$map->map_hierarchy()); + shift(@pcs); + shift(@pcs); + if (@pcs) { + map { $shownmaps{$navmap->getByMapPc($_)->src()} = 1; } reverse(@pcs); + } + } + } + if (($useslots eq 'map_map') || ($useslots eq 'map')) { + if ($slot_status ne '') { + if (ref($statusbymap{$mapurl}{$slot_status}) eq 'ARRAY') { + push(@{$statusbymap{$mapurl}{$slot_status}},$symb); + } else { + $statusbymap{$mapurl}{$slot_status} = [$symb]; + } + } + } + } + + foreach my $mapurl (keys(%statusbymap)) { + if (ref($statusbymap{$mapurl}) eq 'HASH') { + if (keys(%{$statusbymap{$mapurl}}) == 1) { + my @values = values(%{$statusbymap{$mapurl}}); + my $repsymb = $values[0][0]; + if (ref($output{$repsymb}) eq 'HASH') { + $output{$mapurl}{'msg'} = $output{$repsymb}{'msg'}; + $output{$mapurl}{'hasaction'} = $output{$repsymb}{'hasaction'}; + } + $repsymbs{$mapurl} = $repsymb; + } + } + } + + my (%parent,%container,%container_title); + my ($depth,$count,$reservable,$currcontainer,$rownum,$mapnum,$shown) = (0,0,0,0,0,0,0); + my @backgrounds = ("LC_even_row","LC_odd_row"); + my $numcolors = scalar(@backgrounds); + my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons/whitespace_21.gif"); + my $slotheader = '

'. + &mt('Your reservation status for any such assignments is listed below:'). + '

'. + ''."\n"; + my $shownheader = 0; + my $currmap; + my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef); + while (my $resource = $it->next()) { + if ($resource == $it->BEGIN_MAP()) { + $depth++; + $parent{$depth} = $currcontainer; + if (ref($container{$currcontainer})) { + my $currmapres = $container{$currcontainer}; + my $currmaptitle = $container_title{$currcontainer}; + $currmap = $currmapres->src(); + my $currmaptype = 'sequence'; + if ($currmapres->is_page()) { + $currmaptype = 'page'; + } + if ($shownmaps{$currmap}) { + $mapnum ++; + $rownum ++; + $shown ++; + if (!$shownheader) { + $r->print($slotheader); + $shownheader = 1; + } + my $bgcolor = $backgrounds[$shown % $numcolors]; + my ($spacers,$icon); + my $row = ''; + if (ref($statusbymap{$currmap}) eq 'HASH') { + my ($spacers,$icon) = &show_map_row($depth-1,$location,$currmaptype,$currmaptitle); + my $arrowstate = 'open'; + if (keys(%{$statusbymap{$currmap}}) == 1) { + $arrowstate = 'closed'; + } + $row .= ''."\n"; + if (ref($output{$currmap}) eq 'HASH') { + my $formnum = $mapnum.'_'.$reservable+1; + my $class = 'LC_slotmaptext_'.$mapnum; + if ($output{$currmap}{'hasaction'}) { + $row .= ''; + } else { + $row .= ''; + } + $row .= ''."\n"; + } else { + $row .= ''."\n"; + } + } else { + my ($spacers,$icon) = &show_map_row($depth,$location,$currmaptype,$currmaptitle); + $row .= ''."\n"; + } + $r->print($row); + } + } + } elsif ($resource == $it->END_MAP()) { + $depth--; + $currcontainer = $parent{$depth}; + } elsif (ref($resource)) { + my $symb = $resource->symb(); + next if (!$resource->is_problem() && !$resource->is_tool() && + !$resource->is_sequence() && !$resource->is_page()); + $count ++; + if (($resource->is_sequence()) || ($resource->is_page())) { + $currcontainer = $count; + $container{$currcontainer} = $resource; + $container_title{$currcontainer} = $resource->compTitle(); + } + if (($resource->is_problem() || $resource->is_tool)) { + next unless (exists($output{$symb})); + $reservable ++; + $rownum ++; + if (!$shownheader) { + $r->print($slotheader); + $shownheader = 1; + } + my $style; + if (exists($output{$currmap})) { + $style = 'none'; + } else { + $style = 'table-row'; + $shown ++; + } + my $title = $resource->compTitle(); + my $bgcolor = $backgrounds[$shown % $numcolors]; + $r->print(''. + ''); + my $class = 'LC_slottext_'.$mapnum; + if ($output{$symb}{'hasaction'}) { + $r->print(''. + ''); + } else { + $r->print(''); + } + $r->print(''."\n"); + } + } + } + if ($shownheader) { + $r->print('
'.$spacers.''. + $icon.(' ' x6).''. + $output{$currmap}{'msg'}. + ''. + &slot_chooser($repsymbs{$currmap},$class,$formnum, + $allavailable,$slots,$consumed_uniqueperiods). + ''. + $output{$currmap}{'msg'}. + '
 
'.$spacers.$icon.(' ' x6).' 
'); + for (my $i=0; $i<$depth; $i++) { + $r->print(''); + } + $r->print(''. + ''.&mt('Task'));
+                } elsif ($resource->is_tool()) {
+                    $r->print('unknown.gif'.$title.''.(' ' x6).''.$output{$symb}{'msg'}.''. + &slot_chooser($symb,$class,$reservable,$allavailable,$slots, + $consumed_uniqueperiods).''. + ''.$output{$symb}{'msg'}.''. + '
'); + } + if (!$reservable) { + $r->print(''); + if ($crstype eq 'Community') { + $r->print(&mt('No community items currently require a reservation to gain access.')); + } else { + $r->print(&mt('No course items currently require a reservation to gain access.')); + } + $r->print(''); + } + $r->print('

'. + &mt('Reservation History').'

'); +} + +sub show_map_row { + my ($depth,$location,$type,$title) = @_; + my $spacers; + for (my $i=0; $i<$depth-1; $i++) { + $spacers .= ''; + } + my $icon; + if ($type eq 'page') { + $icon = ' '."\n"; + } else { + $icon = ' '."\n"; + } + $icon .= $title; + return ($spacers,$icon); +} + +sub slot_chooser { + my ($symb,$class,$formnum,$allavailable,$slots,$consumed_uniqueperiods) = @_; + my $output; + my @got_slots=&check_for_reservation($symb,'allslots'); + if ($got_slots[0] =~ /^error: /) { + $output = ''. + &mt('An error occurred determining slot availability.'). + ''; + } else { + my $formname = 'manageres_'.$formnum; + 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 ($slots->{$slot}->{'symb'} ne '') { + my ($map,$id,$url) = &Apache::lonnet::decode_symb($symb); + my $exclude = 1; + my @reqsymbs = split(/\s*,\s*/,$slots->{$slot}->{'symb'}); + if (@reqsymbs) { + if (grep(/^\Q$symb\E$/,@reqsymbs)) { + $exclude = 0; + } else { + foreach my $reqsymb (@reqsymbs) { + my (undef,undef,$sloturl) = &Apache::lonnet::decode_symb($reqsymb); + if ($sloturl=~/\.(page|sequence)$/) { + if (($map ne '') && ($map eq $sloturl)) { + $exclude = 0; + last; + } + } + } + } + next if ($exclude); + } + } + } + push(@available,$slot); + } + } + $output .= &show_choices($symb,$formname,$formnum,$class, + $slots,$consumed_uniqueperiods, + \@available,\@got_slots); + } + } + return $output; +} + +sub show_reservations { + my ($r,$uname,$udom) = @_; + if (!defined($uname)) { + $uname = $env{'user.name'}; + } + if (!defined($udom)) { + $udom = $env{'user.domain'}; + } + my $formname = 'slotlog'; + my ($cnum,$cdom)=&get_course(); + my $crstype = &Apache::loncommon::course_type(); + my %log=&Apache::lonnet::dump('nohist_'.$cdom.'_'.$cnum.'_slotlog',$udom,$uname); + if ($env{'form.origin'} eq 'aboutme') { + $r->print('
'); + my $name = &Apache::loncommon::plainname($env{'form.uname'},$env{'form.udom'}, + 'firstname'); + if ($crstype eq 'Community') { + $r->print(&mt('History of member-reservable slots for: [_1]', + $name)); + } else { + $r->print(&mt('History of student-reservable slots for: [_1]', + $name)); + + } + $r->print('
'); + } + $r->print('
'); + # set defaults + my $now = time(); + my $defstart = $now - (7*24*3600); #7 days ago + my %defaults = ( + page => '1', + show => '10', + action => 'any', + log_start_date => $defstart, + log_end_date => $now, + ); + my $more_records = 0; + + # set current + my %curr; + foreach my $item ('show','page','action') { + $curr{$item} = $env{'form.'.$item}; + } + my ($startdate,$enddate) = + &Apache::lonuserutils::get_dates_from_form('log_start_date', + 'log_end_date'); + $curr{'log_start_date'} = $startdate; + $curr{'log_end_date'} = $enddate; + foreach my $key (keys(%defaults)) { + if ($curr{$key} eq '') { + $curr{$key} = $defaults{$key}; + } + } + my ($version) = ($r->dir_config('lonVersion') =~ /^([\d\.]+)\-/); + $r->print(&display_filter($formname,$cdom,$cnum,\%curr,$version)); + my $showntablehdr = 0; + my $tablehdr = &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ' '.&mt('When').''.&mt('Action').''. + ''.&mt('Description').''.&mt('Start time').''. + ''.&mt('End time').''.&mt('Resource').''. + &Apache::loncommon::end_data_table_header_row(); + my ($minshown,$maxshown); + $minshown = 1; + my $count = 0; + if ($curr{'show'} ne &mt('all')) { + $maxshown = $curr{'page'} * $curr{'show'}; + if ($curr{'page'} > 1) { + $minshown = 1 + ($curr{'page'} - 1) * $curr{'show'}; + } + } + my (%titles,%maptitles); + my %lt = &reservationlog_contexts($crstype); + foreach my $id (sort { $log{$b}{'exe_time'}<=>$log{$a}{'exe_time'} } (keys(%log))) { + next if (($log{$id}{'exe_time'} < $curr{'log_start_date'}) || + ($log{$id}{'exe_time'} > $curr{'log_end_date'})); + if ($curr{'show'} ne &mt('all')) { + if ($count >= $curr{'page'} * $curr{'show'}) { + $more_records = 1; + last; + } + } + if ($curr{'action'} ne 'any') { + next if ($log{$id}{'logentry'}{'action'} ne $curr{'action'}); + } + $count ++; + next if ($count < $minshown); + if (!$showntablehdr) { + $r->print($tablehdr); + $showntablehdr = 1; + } + my $symb = $log{$id}{'logentry'}{'symb'}; + my $slot_name = $log{$id}{'logentry'}{'slot'}; + my %slot=&Apache::lonnet::get_slot($slot_name); + my $description = $slot{'description'}; + my $start = ($slot{'starttime'}? + &Apache::lonlocal::locallocaltime($slot{'starttime'}):''); + my $end = ($slot{'endtime'}? + &Apache::lonlocal::locallocaltime($slot{'endtime'}):''); + my $title = &get_resource_title($symb,\%titles,\%maptitles); + my $chgaction = $log{$id}{'logentry'}{'action'}; + if ($chgaction ne '' && $lt{$chgaction} ne '') { + $chgaction = $lt{$chgaction}; + } + $r->print(&Apache::loncommon::start_data_table_row().''.$count.''.&Apache::lonlocal::locallocaltime($log{$id}{'exe_time'}).''.$chgaction.''.$description.''.$start.''.$end.''.$title.''.&Apache::loncommon::end_data_table_row()."\n"); + } + if ($showntablehdr) { + $r->print(&Apache::loncommon::end_data_table().'
'); + if (($curr{'page'} > 1) || ($more_records)) { + $r->print('

'); + if ($curr{'page'} > 1) { + $r->print(''); + } + if ($more_records) { + $r->print(''); + } + $r->print('

'); + $r->print(<<"ENDSCRIPT"); + +ENDSCRIPT + } + } else { + $r->print('' + .&mt('There are no transactions to display.') + .'' + ); + } + $r->print(''."\n". + ''."\n"); + if ($env{'form.origin'} eq 'aboutme') { + $r->print(''."\n". + ''."\n". + ''."\n"); + } + $r->print('
'); + return; +} + +sub show_reservations_log { + my ($r) = @_; + my $badslot; + my $crstype = &Apache::loncommon::course_type(); + if ($env{'form.slotname'} eq '') { + $r->print('
'.&mt('No slot name provided').'
'); + $badslot = 1; + } else { + my %slot=&Apache::lonnet::get_slot($env{'form.slotname'}); + if (keys(%slot) == 0) { + $r->print('
'.&mt('Invalid slot name: [_1]',$env{'form.slotname'}).'
'); + $badslot = 1; + } elsif ($slot{type} ne 'schedulable_student') { + my $description = &get_description($env{'form.slotname'},\%slot); + $r->print('
'); + if ($crstype eq 'Community') { + $r->print(&mt('Reservation history unavailable for non-member-reservable slot: [_1].',$description)); + } else { + $r->print(&mt('Reservation history unavailable for non-student-reservable slot: [_1].',$description)); + } + $r->print('
'); + $badslot = 1; + } + } + if ($badslot) { + $r->print('

'. + &mt('Return to slot list').'

'); + return; + } + my $formname = 'reservationslog'; + my ($cnum,$cdom)=&get_course(); + 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('
'); + my %saveable_parameters = ('show' => 'scalar',); + &Apache::loncommon::store_course_settings('reservationslog', + \%saveable_parameters); + &Apache::loncommon::restore_course_settings('reservationslog', + \%saveable_parameters); + # set defaults + my $now = time(); + my $defstart = $now - (7*24*3600); #7 days ago + my %defaults = ( + page => '1', + show => '10', + chgcontext => 'any', + action => 'any', + symb => 'any', + log_start_date => $defstart, + log_end_date => $now, + ); + my $more_records = 0; + + # set current + my %curr; + foreach my $item ('show','page','chgcontext','action','symb') { + $curr{$item} = $env{'form.'.$item}; + } + my ($startdate,$enddate) = + &Apache::lonuserutils::get_dates_from_form('log_start_date', + 'log_end_date'); + $curr{'log_start_date'} = $startdate; + $curr{'log_end_date'} = $enddate; + foreach my $key (keys(%defaults)) { + if ($curr{$key} eq '') { + $curr{$key} = $defaults{$key}; + } + } + my (%whodunit,%changed,$version); + ($version) = ($r->dir_config('lonVersion') =~ /^([\d\.]+)\-/); + + my %slot=&Apache::lonnet::get_slot($env{'form.slotname'}); + my $description = $slot{'description'}; + $r->print(''); + if ($crstype eq 'Community') { + $r->print(&mt('Reservation changes for member-reservable slot: [_1]',$description)); + } else { + $r->print(&mt('Reservation changes for student-reservable slot: [_1]',$description)); + } + $r->print('
'); + $r->print(&display_filter($formname,$cdom,$cnum,\%curr,$version,\@allsymbs)); + my $showntablehdr = 0; + my $tablehdr = &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ' '.&mt('When').''.&mt('Who made the change'). + ''.&mt('Affected User').''.&mt('Action').''. + ''.&mt('Resource').''.&mt('Context').''. + &Apache::loncommon::end_data_table_header_row(); + my ($minshown,$maxshown); + $minshown = 1; + my $count = 0; + if ($curr{'show'} ne &mt('all')) { + $maxshown = $curr{'page'} * $curr{'show'}; + if ($curr{'page'} > 1) { + $minshown = 1 + ($curr{'page'} - 1) * $curr{'show'}; + } + } + my %lt = &reservationlog_contexts($crstype); + my (%titles,%maptitles); + foreach my $id (sort { $log{$b}{'exe_time'}<=>$log{$a}{'exe_time'} } (keys(%log))) { + next if (($log{$id}{'exe_time'} < $curr{'log_start_date'}) || + ($log{$id}{'exe_time'} > $curr{'log_end_date'})); + if ($curr{'show'} ne &mt('all')) { + if ($count >= $curr{'page'} * $curr{'show'}) { + $more_records = 1; + last; + } + } + if ($curr{'chgcontext'} ne 'any') { + if ($curr{'chgcontext'} eq 'user') { + next if (($log{$id}{'logentry'}{'context'} ne 'user') && + ($log{$id}{'logentry'}{'context'} ne 'usermanage')); + } else { + next if ($log{$id}{'logentry'}{'context'} ne $curr{'chgcontext'}); + } + } + if ($curr{'action'} ne 'any') { + next if ($log{$id}{'logentry'}{'action'} ne $curr{'action'}); + } + if ($curr{'symb'} ne 'any') { + next if ($log{$id}{'logentry'}{'symb'} ne $curr{'symb'}); + } + $count ++; + next if ($count < $minshown); + if (!$showntablehdr) { + $r->print($tablehdr); + $showntablehdr = 1; + } + if ($whodunit{$log{$id}{'exe_uname'}.':'.$log{$id}{'exe_udom'}} eq '') { + $whodunit{$log{$id}{'exe_uname'}.':'.$log{$id}{'exe_udom'}} = + &Apache::loncommon::plainname($log{$id}{'exe_uname'},$log{$id}{'exe_udom'}); + } + if ($changed{$log{$id}{'uname'}.':'.$log{$id}{'udom'}} eq '') { + $changed{$log{$id}{'uname'}.':'.$log{$id}{'udom'}} = + &Apache::loncommon::plainname($log{$id}{'uname'},$log{$id}{'udom'}); + } + my $symb = $log{$id}{'logentry'}{'symb'}; + my $title = &get_resource_title($symb,\%titles,\%maptitles); + my $chgcontext = $log{$id}{'logentry'}{'context'}; + if ($chgcontext ne '' && $lt{$chgcontext} ne '') { + $chgcontext = $lt{$chgcontext}; + } + my $chgaction = $log{$id}{'logentry'}{'action'}; + if ($chgaction ne '' && $lt{$chgaction} ne '') { + $chgaction = $lt{$chgaction}; + } + $r->print(&Apache::loncommon::start_data_table_row().''.$count.''.&Apache::lonlocal::locallocaltime($log{$id}{'exe_time'}).''.$whodunit{$log{$id}{'exe_uname'}.':'.$log{$id}{'exe_udom'}}.''.$changed{$log{$id}{'uname'}.':'.$log{$id}{'udom'}}.''.$chgaction.''.$title.''.$chgcontext.''.&Apache::loncommon::end_data_table_row()."\n"); + } + if ($showntablehdr) { + $r->print(&Apache::loncommon::end_data_table().'
'); + if (($curr{'page'} > 1) || ($more_records)) { + $r->print('

'); + if ($curr{'page'} > 1) { + $r->print(''); + } + if ($more_records) { + $r->print(''); + } + $r->print('

'); + $r->print(<<"ENDSCRIPT"); + +ENDSCRIPT + } + } else { + $r->print(&mt('There are no records to display.')); + } + $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 = '
'; + 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 .= ''; + if (ref($allsymbs) eq 'ARRAY') { + $output .= ''; + } else { + $output .= ''; + } + $output .= '
'. + ''.&mt('Changes/page:').'
'. + &Apache::lonmeta::selectbox('show',$curr->{'show'},undef, + (&mt('all'),5,10,20,50,100,1000,10000)). + '
  '.&mt('Window during which changes occurred:'). + '
'.&mt('After:'). + ''.$startform.'
'.&mt('Before:').''. + $endform.'
  '.&mt('Resource').'
'. + '
  '. + &mt('Context:').'
'.&mt('Action').'
'. + '
  
'. + '

'. + '

'. + &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 .= '



'; + return $output; +} + +sub slot_change_messaging { + my ($setting,$subject,$msg,$action) = @_; + my $user = $env{'user.name'}; + my $domain = $env{'user.domain'}; + my ($message_status,$comment_status); + if ($setting eq 'only_student' + || $setting eq 'student_and_user_notes_screen') { + $message_status = + &Apache::lonmsg::user_normal_msg($user,$domain,$subject,$msg); + $message_status = '
  • '.&mt('Sent to you: [_1]', + $message_status).'
  • '; + } + if ($setting eq 'student_and_user_notes_screen') { + $comment_status = + &Apache::lonmsg::store_instructor_comment($subject.'
    '. + $msg,$user,$domain); + $comment_status = '
  • '.&mt('Entry added to course record (viewable by instructor): [_1]', + $comment_status).'
  • '; + } + if ($message_status || $comment_status) { + my $msgtitle; + if ($action eq 'reserve') { + $msgtitle = &mt('Status of messages about saved reservation'); + } elsif ($action eq 'release') { + $msgtitle = &mt('Status of messages about dropped reservation'); + } elsif ($action eq 'nochange') { + $msgtitle = &mt('Status of messages about unchanged existing reservation'); + } + return ''.$msgtitle.'' + .'
      ' + .$message_status + .$comment_status + .'

    '; + } } sub upload_start { my ($r)=@_; - $r->print(&Apache::grades::checkforfile_js()); - my $result.=''."\n"; - $result.='
    '."\n"; - $result.=' '. - &mt('Specify a file containing the slot definitions.'). - '
    '."\n"; - my $upfile_select=&Apache::loncommon::upfile_select_html(); - my $ignore=&mt('Ignore First Line'); - $result.=< - -$upfile_select -
    - - -ENDUPFORM - $result.='
    '."\n"; - $result.=''."\n"; - $r->print($result); + $r->print( + &Apache::grades::checkforfile_js() + .'

    '.&mt('Upload a file containing the slot definitions').'

    ' + .'
    ' + .'' + .&Apache::lonhtmlcommon::start_pick_box() + .&Apache::lonhtmlcommon::row_title(&mt('File')) + .&Apache::loncommon::upfile_select_html() + .&Apache::lonhtmlcommon::row_closure() + .&Apache::lonhtmlcommon::row_title( + '') + .'' + .&Apache::lonhtmlcommon::row_closure(1) + .&Apache::lonhtmlcommon::end_pick_box() + .'

    ' + .'' + .'

    ' + .'
    ' + ); } sub csvuploadmap_header { @@ -1373,16 +2797,40 @@ sub csvuploadmap_header { my $checked=(($env{'form.noFirstLine'})?' checked="checked"':''); my $ignore=&mt('Ignore First Line'); - my $help_field = &Apache::loncommon::help_open_topic('Slot SelectingField'); + my $buttontext = &mt('Reverse Association'); + + $r->print( + '
    ' + .'

    '.&mt('Identify fields in uploaded list').'

    ' + .'
    ' + .&Apache::loncommon::help_open_topic( + 'Slot About',&mt('Help on slots')) + .' '.&Apache::loncommon::help_open_topic( + 'Slot SelectingField',&mt('Help on selecting Fields')) + ."
    \n" + .'

    ' + .&mt('Total number of records found in file: [_1]',''.$distotal.'') + ."

    \n" + ); + if ($distotal == 0) { + $r->print('

    '.&mt('None found').'

    '); + } + $r->print( + '

    ' + .&mt('Enter as many fields as you can.').'
    ' + .&mt('The system will inform you and bring you back to this page,[_1]if the data selected is insufficient to create the slots.','
    ') + .'

    ' + ); + $r->print( + '
    ' + .'
    '.&mt('Functions').'' + .'' + .' ' + .'

    ' + ); $r->print(< -

    Identify fields $help_field

    -Total number of records found in file: $distotal
    -Enter as many fields as you can. The system will inform you and bring you back -to this page if the data selected is insufficient to create the slots.
    - - @@ -1390,9 +2838,10 @@ to this page if the data selected is ins -
    ENDPICK return ''; @@ -1401,17 +2850,17 @@ ENDPICK sub csvuploadmap_footer { my ($request,$i,$keyfields) =@_; + my $buttontext = &mt('Create Slots'); $request->print(< -
    +
    ENDPICK } sub csvupload_javascript_reverse_associate { - my $error1=&mt('You need to specify the name, starttime, endtime and a type'); + my $error1=&mt('You need to specify the name, start time, end time and a type.'); return(<print('

    Creating Slots

    '); + $r->print('

    '.&mt('Creating Slots').'

    '); my $cname=$env{'course.'.$env{'request.course.id'}.'.num'}; my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; my $countdone=0; @@ -1576,8 +3033,12 @@ sub csv_upload_assign { } if ($entries{$fields{'startreserve'}}) { - $slot{'startreserve'}= - &UnixDate($entries{$fields{'startreserve'}},"%s"); + my $date = &UnixDate($entries{$fields{'startreserve'}},"%s"); + if ($date eq '') { + push(@errors,"$name -- No reservation start time set for slot -- value provided had invalid format"); + } else { + $slot{'startreserve'} = $date; + } } if (defined($slot{'startreserve'}) && $slot{'startreserve'} > $slot{'starttime'}) { @@ -1585,20 +3046,85 @@ sub csv_upload_assign { next; } + if ($entries{$fields{'endreserve'}}) { + my $date = &UnixDate($entries{$fields{'endreserve'}},"%s"); + if ($date eq '') { + push(@errors,"$name -- No reservation end time set for slot -- value provided had invalid format"); + } else { + $slot{'endreserve'} = $date; + } + } + if (defined($slot{'endreserve'}) + && $slot{'endreserve'} > $slot{'starttime'}) { + push(@errors,"$name not created -- Slot's reservation end time is after the slot's start time."); + next; + } + + if ($slot{'type'} eq 'schedulable_student') { + if ($entries{$fields{'reservationmsg'}}) { + if (($entries{$fields{'reservationmsg'}} eq 'only_student') || + ($entries{$fields{'reservationmsg'}} eq 'student_and_user_notes_screen')) { + $slot{'reservationmsg'}=$entries{$fields{'reservationmsg'}}; + } else { + unless (($entries{$fields{'reservationmsg'}} eq 'none') || + ($entries{$fields{'reservationmsg'}} eq '')) { + push(@errors,"$name -- Slot's reservationmsg setting ignored - not one of: 'only_student', 'student_and_user_notes_screen', 'none' or ''"); + } + } + } + } + foreach my $key ('ip','proctor','description','maxspace', 'secret','symb') { if ($entries{$fields{$key}}) { $slot{$key}=$entries{$fields{$key}}; } } - + if ($entries{$fields{'iptied'}} =~ /^\s*(yes|1)\s*$/i) { + $slot{'iptied'}='yes'; + } elsif ($entries{$fields{'iptied'}} =~ /^\s*answer\s*$/i) { + $slot{'iptied'}='answer'; + } + if ($entries{$fields{'allowedusers'}}) { + $entries{$fields{'allowedusers'}} =~ s/^\s+//; + $entries{$fields{'allowedusers'}} =~ s/\s+$//; + my @allowedusers; + foreach my $poss (split(/\s*,\s*/,$entries{$fields{'allowedusers'}})) { + my ($possuname,$possudom) = split(/:/,$poss); + if (($possuname =~ /^$match_username$/) && ($possudom =~ /^$match_domain$/)) { + unless (grep(/^\Q$poss\E$/,@allowedusers)) { + push(@allowedusers,$poss); + } + } + } + if (@allowedusers > 0) { + $slot{'allowedusers'} = join(',',@allowedusers); + } + } + if ($entries{$fields{'allowedsections'}}) { + $entries{$fields{'allowedsections'}} =~ s/^\s+//; + $entries{$fields{'allowedsections'}} =~ s/\s+$//; + my @allowedsections; + foreach my $poss (split(/\s*,\s*/,$entries{$fields{'allowedsections'}})) { + if (($poss !~ /\W/) && ($poss ne 'none')) { + unless (grep(/^\Q$poss\E$/,@allowedsections)) { + push(@allowedsections,$poss); + } + } + } + if (@allowedsections > 0) { + $slot{'allowedsections'} = join(',',@allowedsections); + } + } if ($entries{$fields{'uniqueperiod'}}) { - my ($start,$end)=split(',',$entries{$fields{'uniqueperiod'}}); - my @times=(&UnixDate($start,"%s"), - &UnixDate($end,"%s")); - $slot{'uniqueperiod'}=\@times; + my ($start,$end)= map { &UnixDate($_,"%s"); } split(',',$entries{$fields{'uniqueperiod'}}); + if (($start ne '') && ($end ne '')) { + $slot{'uniqueperiod'}=[$start,$end]; + } else { + push(@errors,"$name -- Slot's unique period ignored -- one or both of the comma separated values for start and end had an invalid format"); + } } - if (defined($slot{'uniqueperiod'}) + if (ref($slot{'uniqueperiod'}) eq 'ARRAY' && $slot{'uniqueperiod'}[0] > $slot{'uniqueperiod'}[1]) { push(@errors,"$name not created -- Slot's unique period start time is later than the unique period's end time."); next; @@ -1609,14 +3135,43 @@ sub csv_upload_assign { $r->rflush(); $countdone++; } - $r->print("

    Created $countdone slots\n

    "); + if ($countdone) { + &Apache::lonnet::devalidate_slots_cache($cname,$cdom); + } + $r->print('

    '.&mt('Created [quant,_1,slot]',$countdone)."\n".'

    '); foreach my $error (@errors) { - $r->print("

    $error

    \n"); + $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; @@ -1628,16 +3183,84 @@ sub handler { } &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'} =~ /^(showslots|uploadstart|csvuploadmap|csvuploadassign)$/ && $vgr eq 'F') { - $title = 'Managing Slots'; + 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 =[]; } - &start_page($r,$title); - - if ($env{'form.command'} eq 'showslots' && $vgr eq 'F') { + 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); @@ -1664,6 +3287,8 @@ sub handler { } &csv_upload_map($r); } + } elsif (($env{'form.command'} eq 'slotlog') && ($vgr eq 'F')) { + &show_reservations_log($r); } else { my $symb=&unescape($env{'form.symb'}); if (!defined($symb)) { @@ -1684,22 +3309,44 @@ sub handler { my ($status) = &Apache::lonhomework::check_slot_access('0',$type); if ($status eq 'CAN_ANSWER' || $status eq 'NEEDS_CHECKIN' || - $status eq 'WAITING_FOR_GRADE') { + $status eq 'WAITING_FOR_GRADE' || + $status eq 'NEED_DIFFERENT_IP') { &fail($r,'not_allowed'); return OK; } if ($env{'form.requestattempt'}) { - &show_choices($r,$symb); + $r->print('
    '); + $r->print(&show_choices($symb,undef,undef,undef,\%slots,$consumed_uniqueperiods,$available,$got_slots)); + $r->print('
    '); } elsif ($env{'form.command'} eq 'release') { &release_slot($r,$symb); } elsif ($env{'form.command'} eq 'get') { &get_slot($r,$symb); } elsif ($env{'form.command'} eq 'change') { - if (&get_slot($r,$symb,$env{'form.releaseslot'},1)) { + if ($env{'form.nochange'}) { + my $slot_name = $env{'form.releaseslot'}; + my @slots = &check_for_reservation($symb,'allslots'); + my $msg; + if (($slot_name ne '') && (grep(/^\Q$slot_name\E/,@slots))) { + my %slot=&Apache::lonnet::get_slot($env{'form.releaseslot'}); + my $description=&get_description($slot_name,\%slot); + $msg = ''. + &mt('Unchanged reservation: [_1]',$description).'

    '; + my $person = + &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'}); + my $subject = &mt('Reservation unchanged: [_1]',$description); + my $msgbody = &mt('No change to existing registration by [_1] for [_2].',$person,$description); + $msg .= &slot_change_messaging($slot{'reservationmsg'},$subject,$msgbody,'nochange'); + } else { + $msg = ''.&mt('Reservation no longer reported as available.').''; + } + $r->print($msg); + &return_link($r); + } elsif (&get_slot($r,$symb,$env{'form.releaseslot'},1)) { &release_slot($r,$symb,$env{'form.releaseslot'}); } } else { - $r->print("

    Unknown command: ".$env{'form.command'}."

    "); + $r->print('

    '.&mt('Unknown command: [_1]',$env{'form.command'}).'

    '); } } &end_page($r); 500 Internal Server Error

    Internal Server Error

    The server encountered an internal error or misconfiguration and was unable to complete your request.

    Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

    More information about this error may be available in the server error log.