--- loncom/interface/slotrequest.pm 2009/04/23 17:33:54 1.95 +++ loncom/interface/slotrequest.pm 2023/07/07 03:52:40 1.145 @@ -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.95 2009/04/23 17:33:54 bisitz Exp $ +# $Id: slotrequest.pm,v 1.145 2023/07/07 03:52:40 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,12 +56,50 @@ sub fail { } sub start_page { - my ($r,$title,$brcrum)=@_; + my ($r,$title,$brcrum,$bread_crumbs_component,$js,$mgr)=@_; my $args; if (ref($brcrum) eq 'ARRAY') { $args = {bread_crumbs => $brcrum}; + if ($bread_crumbs_component) { + $args->{bread_crumbs_component} = $bread_crumbs_component; + } + } + 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 }; + } + } + unless (($env{'form.context'} eq 'usermanage') || (($mgr eq 'F') && + (($env{'form.command'} eq 'release') || + ($env{'form.command'} eq 'remove_registration')))) { + if ($env{'form.symb'}) { + my $symb=&unescape($env{'form.symb'}); + my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb); + if ($resurl =~ /ext\.tool$/) { + my $target; + my ($marker,$exttool) = (split(m{/},$resurl))[3,4]; + $marker=~s/\D//g; + if (($marker) && ($exttool) && ($env{'request.course.id'})) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my ($idx,$crstool,$is_tool,%toolhash,%toolsettings); + if ($resurl eq "adm/$cdom/$cnum/$marker/$exttool") { + my %toolsettings=&Apache::lonnet::dump('exttool_'.$marker,$cdom,$cnum); + $target = $toolsettings{'target'}; + } + } + if ($target eq 'iframe') { + $args->{'only_body'} = 1; + } + } + } } - $r->print(&Apache::loncommon::start_page($title,undef,$args)); + $r->print(&Apache::loncommon::start_page($title,$js,$args)); } sub end_page { @@ -69,6 +107,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 @@ -121,7 +444,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)); @@ -137,16 +459,20 @@ sub check_for_reservation { return 'error: Unable to determine current status'; } my @got; - my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%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 { @@ -167,7 +493,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(); @@ -214,16 +540,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}}; @@ -252,11 +581,11 @@ sub make_reservation { return 'error: Unable to determine current status'; } - my $parm_symb = $symb; + my $symb_for_db = $symb; my $parm_level = 1; if ($use_slots eq 'map' || $use_slots eq 'map_map') { my ($map) = &Apache::lonnet::decode_symb($symb); - $parm_symb = &Apache::lonnet::symbread($map); + $symb_for_db = &Apache::lonnet::symbread($map); $parm_level = 2; } @@ -299,7 +628,7 @@ sub make_reservation { my %reservation=('name' => $env{'user.name'}.':'.$env{'user.domain'}, 'timestamp' => time, - 'symb' => $parm_symb); + 'symb' => $symb_for_db); my $success=&Apache::lonnet::newput('slot_reservations', {"$slot_name\0$wanted" => @@ -311,7 +640,9 @@ sub make_reservation { if ($value) { $new_value=$value.':'.$new_value; } - &store_slot_parm($symb,$slot_name,$parm_level,$new_value,$cnum,$cdom); + my $result = &store_slot_parm($symb,$symb_for_db,$slot_name,$parm_level, + $new_value,$cnum,$cdom,$env{'user.name'}, + $env{'user.domain'},'reserve',$env{'form.context'}); return $wanted; } @@ -320,29 +651,27 @@ sub make_reservation { } 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'}); + my ($symb_for_parm,$symb_for_db,$slot_name,$parm_level,$new_value, + $cnum,$cdom,$uname,$udom,$action,$context,$delflag) = @_; + + # store new parameter string + my $result=&Apache::lonparmset::storeparm_by_symb($symb_for_parm, + '0_availablestudent', + $parm_level,$new_value, + 'string',$uname,$udom); &Apache::lonxml::debug("hrrm $result"); my %storehash = ( - symb => $symb, + symb => $symb_for_db, slot => $slot_name, - action => 'reserve', - context => $env{'form.context'}, + action => $action, + context => $context, ); - &Apache::lonnet::instructor_log('slotreservationslog',\%storehash, - '',$env{'user.name'},$env{'user.domain'}, - $cnum,$cdom); - &Apache::lonnet::instructor_log($cdom.'_'.$cnum.'_slotlog',\%storehash, - 1,$env{'user.name'},$env{'user.domain'}, - $env{'user.name'},$env{'user.domain'}); - - return; + &Apache::lonnet::write_log('course','slotreservationslog',\%storehash, + $delflag,$uname,$udom,$cnum,$cdom); + &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash, + $delflag,$uname,$udom,$uname,$udom); + return $result; } sub remove_registration { @@ -438,7 +767,7 @@ sub release_all_slot { &release_reservation($slot_name,$uname,$udom, $consumed{$entry}{'symb'},$mgr); if (!$result) { - $r->print('

'.&mt($msg).'

'); + $r->print('

'.&mt($msg).'

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

$msg

"); } @@ -468,7 +797,7 @@ sub release_slot { my ($result,$msg) = &release_reservation($slot_name,$uname,$udom,$symb,$mgr); if (!$result) { - $r->print('

'.&mt($msg).'

'); + $r->print('

'.&mt($msg).'

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

$msg

"); } @@ -486,85 +815,317 @@ 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); + my $msg; if ($mgr ne 'F') { if ($slot{'starttime'} < time) { - return (0,&mt('Not allowed to release Reservation: [_1], as it has already ended.',$description)); + return (0,&mt('Not allowed to release Reservation: [_1], as it has already started.',$description)); } } + my $context = $env{'form.context'}; - # if the reservation symb is for a map get a resource in that map - # to check slot parameters on + # get navmap object my $navmap=Apache::lonnavmaps::navmap->new; if (!defined($navmap)) { 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(); + + my ($cnum,$cdom)=&get_course(); + + # get slot reservations, check if user has reservation + my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, + "^$slot_name\0"); + + # + # If release is because of a reservation *change*, symb(s) associated with reservation + # being dropped may differ from the current symb. + # + # We need to get symb(s) from slot_reservations.db, and for each symb, update + # the value of the availablestudent parameter, at the appropriate level + # (as dictated by the value of the useslots parameter for the symb and user). + # + # We also delete all entries for the slot being released, for the specific user. + # + + my $conflict; + + if (($env{'form.command'} eq 'change') && ($slot_name eq $env{'form.releaseslot'}) && + ($env{'form.slotname'} ne $slot_name)) { + my %changedto = &Apache::lonnet::get_slot($env{'form.slotname'}); + + # check for conflicts + my ($to_uniq_start,$to_uniq_end,$from_uniq_start,$from_uniq_end); + if (ref($changedto{'uniqueperiod'}) eq 'ARRAY') { + ($to_uniq_start,$to_uniq_end) = @{$changedto{'uniqueperiod'}}; + } + if (ref($slot{'uniqueperiod'}) eq 'ARRAY') { + ($from_uniq_start,$from_uniq_end) = @{$slot{'uniqueperiod'}}; + } + my $to_start = $changedto{'starttime'}; + my $to_end = $changedto{'endtime'}; + my $from_start = $slot{'starttime'}; + my $from_end = $slot{'endtime'}; + + if (! + ($from_start < $to_uniq_start && $from_end < $to_uniq_start) || + ($from_start > $to_uniq_end && $from_end > $to_uniq_end )) { + $conflict = 1; + } + if (! + ($to_start < $from_uniq_start && $to_end < $from_uniq_start) || + ($to_start > $from_uniq_end && $to_end > $from_uniq_end )) { + $conflict = 1; + } + + if ($conflict) { + my %symbs_for_slot; + my (%to_delete,%failed,%released); + foreach my $entry (keys(%consumed)) { + if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) { + $symbs_for_slot{$consumed{$entry}->{'symb'}} = 1; + $to_delete{$entry} = 1; + } + } + if (keys(%to_delete)) { + my @removals = keys(%to_delete); + if (&Apache::lonnet::del('slot_reservations',\@removals, + $cdom,$cnum) eq 'ok') { + foreach my $item (keys(%symbs_for_slot)) { + my $result = &update_selectable($navmap,$slot_name,$item,$cdom, + $cnum,$udom,$uname,$context); + if ($result =~ /^error/) { + $failed{$item} = 1; + } else { + $released{$item} = 1; + } + } + } + } + if (keys(%released)) { + $msg = ''. + &mt('Released Reservation: [_1]',$description).'  '. + &mt('The following items had their reservation status change').':'; + my (%folders,%pages,%container,%titles); + foreach my $item (keys(%released)) { + my $res = $navmap->getBySymb($item); + if (ref($res)) { + $titles{$item} = $res->title(); + if ($res->is_map()) { + $folders{$item}{'title'} = $titles{$item}; + if ($res->is_page()) { + $pages{$item}{'title'} = $titles{$item}; + } else { + $folders{$item}{'title'} = $titles{$item}; + } + } else { + my $mapsrc = $res->enclosing_map_src(); + my $map = $navmap->getResourceByUrl($mapsrc); + if (ref($map)) { + if ($map->id() eq '0.0') { + $container{$mapsrc}{'title'} &mt('Top level of course'); + } else { + $container{$mapsrc}{'title'} = $map->title(); + if ($map->is_page()) { + $container{$mapsrc}{'page'} = 1; + } + } + } + $container{$mapsrc}{'resources'}{$item} = 1; + } + } + } + $msg .= ''; + 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); + } else { + if (keys(%to_delete)) { + $msg = &mt('Reservation release partially complete for [_1]',$description); + } else { + $msg = &mt('No entries found for this user to release for [_1].',$description); + } + return (0,$msg); + } + } else { + $msg = &mt('No conflict found; not releasing: [_1].',$description); + return (0,$msg); + } } - # get parameter string, check for existance, rebuild string with the slot - my $student = &Apache::lonnet::EXT("resource.0.availablestudent", - $symb,$udom,$uname); - my @slots = split(/:/,$student); + my $map_symb; + my $parm_symb = $symb; + my $passed_resource = $navmap->getBySymb($symb); - my @new_slots; - foreach my $exist_slot (@slots) { - if ($exist_slot eq $slot_name) { next; } - push(@new_slots,$exist_slot); + # if the reservation symb is for a map get a resource in that map + # to check slot parameters on + my $parm_level = 1; + 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); + $parm_symb = $a_resource->symb(); + } + } else { + unless ($mgr eq 'F') { + return (0,'error: Unable to determine current status'); + } } - my $new_param = join(':',@new_slots); - my ($cnum,$cdom)=&get_course(); + # Get value of useslots parameter in effect for this user. + # If value is map or map_map, then the parm level is 2 (i.e., + # non-recursive enclosing map/folder level for specific user) + # and the symb for this reservation in slot_reservations.db + # will be the symb of the map itself. - # get slot reservations, check if user has one, if so remove reservation - my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, - "^$slot_name\0"); + my $use_slots = &Apache::lonnet::EXT('resource.0.useslots', + $parm_symb,$udom,$uname); + if (&Apache::lonnet::error($use_slots)) { + return (0,'error: Unable to determine current status'); + } + if ($use_slots eq 'map' || $use_slots eq 'map_map') { + $parm_level = 2; + if ($passed_resource->is_map()) { + $map_symb = $passed_resource->symb(); + } else { + my ($map) = &Apache::lonnet::decode_symb($symb); + $map_symb = &Apache::lonnet::symbread($map); + } + } + + # + # If release is *not* because of a reservation change, i.e., this is a "drop" + # by a student, or a removal for a single student by an instructor then + # only remove one entry from slot_reservations.db, where both the user + # and the symb match the current context. If useslots was set to map or + # map_map, then the symb to match in slot_reservations.db is the symb of + # the enclosing map/folder, not the symb of the resource. + # + + my ($match,$symb_to_check); + if ($parm_level == 2) { + $symb_to_check = $map_symb; + } else { + $symb_to_check = $parm_symb; + } 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::instructor_log('slotreservationslog',\%storehash, - 1,$uname,$udom,$cnum,$cdom); - &Apache::lonnet::instructor_log($cdom.'_'.$cnum.'_slotlog',\%storehash, - 1,$uname,$udom,$uname,$udom); - } + if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) { + if ($consumed{$entry}->{'symb'} eq $symb_to_check) { + if (&Apache::lonnet::del('slot_reservations',[$entry], + $cdom,$cnum) eq 'ok') { + $match = $symb_to_check; + } + last; + } + } + } + if ($match) { + if (&update_selectable($navmap,$slot_name,$symb,$cdom, + $cnum,$udom,$uname,$context) =~ /^error/) { + if ($mgr eq 'F') { + $msg = &mt('Reservation release partially complete for: [_1]',"$uname:$udom").'
'. + &mt('Update of availablestudent parameter for [_1] was not completed.',"$uname:$udom"); + } else { + $msg = &mt('Release partially complete for: [_1]',$description); + } + return (0,$msg); + } else { + if ($mgr eq 'F') { + $msg = &mt('Released Reservation for user: [_1]',"$uname:$udom"); + } else { + $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); + } + } else { + $msg = &mt('Release failed for: [_1]',$description); + return (0,$msg); } +} + +sub update_selectable { + my ($navmap,$slot_name,$symb,$cdom,$cnum,$udom,$uname,$context) = @_; + return 'error: ' unless (ref($navmap)); + my $symb_for_parm = $symb; + my $passed_resource = $navmap->getBySymb($symb); + return 'error: invalid symb' unless (ref($passed_resource)); - my $use_slots = &Apache::lonnet::EXT("resource.0.useslots", - $symb,$udom,$uname); + # if the reservation symb is for a map get a resource in that map + # to check slot parameters on + if ($passed_resource->is_map()) { + my ($a_resource) = + $navmap->retrieveResources($passed_resource, + sub {$_[0]->is_problem() || $_[0]->is_tool() },0,1); + $symb_for_parm = $a_resource->symb(); + } + # get parameter string, check for existence, rebuild string with the slot + my $student = &Apache::lonnet::EXT('resource.0.availablestudent', + $symb_for_parm,$udom,$uname); + + # Get value of useslots parameter in effect for this user. + # If value is map or map_map, then the parm level is 2 (i.e., + # non-recursive enclosing map/folder level for specific user) + # and the symb for this reservation in slot_reservations.db + # will be the symb of the map itself. + + my $use_slots = &Apache::lonnet::EXT('resource.0.useslots', + $symb_for_parm,$udom,$uname); &Apache::lonxml::debug("use_slots is $use_slots
"); - if (&Apache::lonnet::error($use_slots)) { - return (0,'error: Unable to determine current status'); + if (&Apache::lonnet::error($use_slots)) { + return 'error: Unable to determine current status'; } my $parm_level = 1; if ($use_slots eq 'map' || $use_slots eq 'map_map') { - $parm_level = 2; + $parm_level = 2; } - # store new parameter string - my $result=&Apache::lonparmset::storeparm_by_symb($symb, - '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); + + my @slots = split(/:/,$student); + + my @new_slots; + foreach my $exist_slot (@slots) { + next if ($exist_slot eq $slot_name); + push(@new_slots,$exist_slot); } - return (1,$msg); + my $new_value = join(':',@new_slots); + + my $result = &store_slot_parm($symb_for_parm,$symb,$slot_name,$parm_level, + $new_value,$cnum,$cdom,$uname,$udom,'release', + $context,1); + return $result; } sub delete_slot { @@ -586,7 +1147,7 @@ sub delete_slot { if ($ret eq 'ok') { $r->print('

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

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

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

"); + $r->print('

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

"); } } else { if (%consumed) { @@ -602,15 +1163,32 @@ sub delete_slot { sub return_link { my ($r) = @_; + my $target = &return_target(); if (($env{'form.command'} eq 'manageresv') || ($env{'form.context'} eq 'usermanage')) { - $r->print('

'. - &mt('Return to reservations')); + $r->print('

'. + &mt('Return to reservations').'

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

'. + $r->print('

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

'); } } +sub return_target { + my ($target,$ltitarget,$deeplinktarget); + if ($env{'request.lti.login'}) { + $ltitarget = $env{'request.lti.target'}; + } + if ($env{'request.deeplink.login'}) { + $deeplinktarget = $env{'request.deeplink.target'}; + } + if (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) { + $target = '_self'; + } else { + $target = '_top'; + } + return $target; +} + sub get_slot { my ($r,$symb,$conflictable_slot,$inhibit_return_link)=@_; @@ -618,19 +1196,24 @@ sub get_slot { my $slot_name=&check_for_conflict($symb,$env{'form.slotname'},\%slot); if ($slot_name =~ /^error: (.*)/) { - $r->print('

' + $r->print('

' .&mt('An error occurred while attempting to make a reservation. ([_1])',$1) - .'

'); + .'

'); &return_link($r); return 0; } 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('

'.&mt('Already have a reservation: [_1].',$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(< @@ -638,19 +1221,24 @@ sub get_slot { STUFF - $r->print('

' - .&mt('You can either [_1]Change[_2] your reservation from [_3] to [_4] or' - ,'' - ,''.$description1.'' - ,''.$description2.'') - .'

' - ); - &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; @@ -663,12 +1251,19 @@ STUFF if (defined($reserved)) { my $retvalue = 0; if ($slot_name =~ /^error: (.*)/) { - $r->print('

' + $r->print('

' .&mt('An error occurred while attempting to make a reservation. ([_1])',$1) - .'

'); + .'

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

'.&mt('Success: [_1]',$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('

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

'); } @@ -677,7 +1272,7 @@ STUFF } my %lt = &Apache::lonlocal::texthash( - 'request' => 'Availibility list', + 'request' => 'Availability list', 'try' => 'Try again?', 'or' => 'or', ); @@ -707,7 +1302,8 @@ $lt{'or'} STUFF if (!$inhibit_return_link) { - $r->print(&mt('or').'

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

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

'); } @@ -715,7 +1311,7 @@ STUFF } 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) { @@ -740,6 +1336,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; @@ -784,9 +1385,33 @@ 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, @@ -814,76 +1439,120 @@ sub get_description { } sub show_choices { - my ($r,$symb,$formname)=@_; - - 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,$output); + 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; } - 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)); - - push(@available,$slot); - } - if (!@available) { - $output = &mt('No available times.'); + if (!@{$available}) { + $output = ''.&mt('No available times.').''; if ($env{'form.command'} ne 'manageresv') { - $output .= ' '. + my $target = &return_target(); + $output .= ' '. &mt('Return to last resource').''; } - $r->print($output); - return; + 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"; + + + +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($output); } sub to_show { @@ -1025,15 +1702,13 @@ 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(&Apache::loncommon::help_open_topic('Slot About', 'Help on slots')); - $r->print('
'); $r->print(' @@ -1043,12 +1718,16 @@ sub show_table { $r->print(' '); - $r->print(&Apache::loncommon::help_open_topic('Slot AddInterface')); + $r->print(&Apache::loncommon::help_open_topic('Slot About')); $r->print('
'); } if (!keys(%slots)) { - $r->print('
'.&mt('No slots have been created in this course.').'
'); + $r->print( + '

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

' + ); return; } @@ -1075,18 +1754,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') @@ -1159,11 +1846,11 @@ sub show_table { 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, 'name_filter_type', - %name_filter_type_fields). + \%name_filter_type_fields). '
'. &Apache::lonhtmlcommon::textbox('name_filter_value', $env{'form.name_filter_value'}, @@ -1172,11 +1859,11 @@ sub show_table { - - + + - +
Deleted slots:'.&mt('Deleted slots:').'
@@ -1185,19 +1872,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'}}) @@ -1234,12 +1922,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); @@ -1276,6 +1967,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'})) { @@ -1283,13 +1976,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; @@ -1337,30 +2038,39 @@ sub show_table { delete => 'Delete', slotlog => 'History', ); - my $edit=(<<"EDITLINK"); + my ($edit,$delete,$showlog,$remove_all); + if ($mgr) { + $edit=(<<"EDITLINK"); $lt{'edit'} EDITLINK - my $delete=(<<"DELETELINK"); + $delete=(<<"DELETELINK"); $lt{'delete'} DELETELINK - my $showlog=(<<"LOGLINK"); + $remove_all=&remove_link($slot,'remove all').'
'; + + if ($ids eq '') { + undef($remove_all); + } else { + undef($delete); + } + } + + $showlog=(<<"LOGLINK"); $lt{'slotlog'} LOGLINK - my $remove_all=&remove_link($slot,'remove all').'
'; - - if ($ids eq '') { - undef($remove_all); - } else { - undef($delete); - } 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. @@ -1383,6 +2093,12 @@ LOGLINK 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"); } @@ -1399,8 +2115,18 @@ LOGLINK 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"); @@ -1423,189 +2149,358 @@ $row_end STUFF } } - $r->print(&Apache::loncommon::end_data_table().''); + 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,$type) = @_; + 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.') - .'

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

' ); if (!defined($navmap)) { - $r->print('
'. - &mt('Unable to retrieve information about course contents'). - '
'); - &Apache::lonnet::logthis('Manage Reservations - could not create navmap object in '.lc($type).':'.$env{'request.course.id'}); + $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 (%parent,%shownparent,%container,%container_title,%contents); - my ($depth,$count,$reservable,$lastcontainer,$rownum) = (0,0,0,0,0); - my @backgrounds = ("LC_odd_row","LC_even_row"); + 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"); - $r->print(''."\n"); + 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} = $lastcontainer; - } - if ($resource == $it->END_MAP()) { - $depth--; - $lastcontainer = $parent{$depth}; - } - if (ref($resource)) { - my $symb = $resource->symb(); - my $ressymb = $symb; - $contents{$lastcontainer} ++; - next if (!$resource->is_problem() && !$resource->is_sequence() && - !$resource->is_page()); - $count ++; - if (($resource->is_sequence()) || ($resource->is_page())) { - $lastcontainer = $count; - $container{$lastcontainer} = $resource; - $container_title{$lastcontainer} = $resource->compTitle(); - } - if ($resource->is_problem()) { - my ($useslots) = $resource->slot_control(); - next if (($useslots eq '') || ($useslots =~ /^\s*no\s*$/i)); - my ($msg,$get_choices,$slotdescription); - my $title = $resource->compTitle(); - my $status = $resource->simpleStatus('0'); - my ($slot_status,$date,$slot_name) = $resource->check_for_slot('0'); - 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->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'); - } + $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'; } - $reservable ++; - my $treelevel = $depth; - my $higherup = $lastcontainer; - if ($depth > 1) { - my @maprows; - while ($treelevel > 1) { - if (ref($container{$higherup})) { - my $res = $container{$higherup}; - last if (defined($shownparent{$higherup})); - my $maptitle = $res->compTitle(); - my $type = 'sequence'; - if ($res->is_page()) { - $type = '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 .= ''; } - &show_map_row($treelevel,$location,$type,$maptitle, - \@maprows); - $shownparent{$higherup} = 1; + $row .= ''."\n"; + } else { + $row .= ''."\n"; } - $treelevel --; - $higherup = $parent{$treelevel}; - } - foreach my $item (@maprows) { - $rownum ++; - my $bgcolor = $backgrounds[$rownum % $numcolors]; - $r->print(''.$item.''."\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 ++; - my $bgcolor = $backgrounds[$rownum % $numcolors]; - $r->print(''. + ''; - my $hasaction; - if ($status == $resource->OPEN) { - if ($get_choices) { - $hasaction = 1; - } + $r->print('problem.gif" alt="'.&mt('Problem')); } - if ($hasaction) { - $result .= ''. - ''); + my $class = 'LC_slottext_'.$mapnum; + if ($output{$symb}{'hasaction'}) { + $r->print(''. + ''); } else { - $result .= ''; + $r->print(''); } - $r->print($result); - if ($hasaction) { - my $formname = 'manageres_'.$reservable; - &show_choices($r,$symb,$formname); - $r->print(''); - } - $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).' 
'."\n"); + 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('
'); for (my $i=0; $i<$depth; $i++) { $r->print(''); } - my $result = ''. - 'src().'?symb='.$symb.'">'. + ''.&mt('Task');
+                    $r->print('task.gif'.$title.''.(' ' x6).''.$msg.''.(' ' x6); + $r->print('" />'.$title.''.(' ' x6).''.$output{$symb}{'msg'}.''. + &slot_chooser($symb,$class,$reservable,$allavailable,$slots, + $consumed_uniqueperiods).''.$msg.''. + ''.$output{$symb}{'msg'}.''. + '
'); + } if (!$reservable) { - $r->print(''.&mt('No course items currently require a reservation to gain access.').''); + $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(''. - '

'. + $r->print('

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

'); } sub show_map_row { - my ($depth,$location,$type,$title,$maprows) = @_; - my $output = ''; + my ($depth,$location,$type,$title) = @_; + my $spacers; for (my $i=0; $i<$depth-1; $i++) { - $output .= ''; + $spacers .= ''; } + my $icon; if ($type eq 'page') { - $output .= ' '."\n"; + $icon = ' '."\n"; } else { - $output .= ' '."\n"; + $icon = ' '."\n"; } - $output .= $title.' '."\n"; - unshift (@{$maprows},$output); - return; + $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 { @@ -1617,14 +2512,22 @@ sub show_reservations { $udom = $env{'user.domain'}; } my $formname = 'slotlog'; - my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + 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('
'. - &mt('History of student-reservable slots for: [_1]', - &Apache::loncommon::plainname($env{'form.uname'},$env{'form.udom'}, - 'firstname')).'
'); + $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 @@ -1673,7 +2576,7 @@ sub show_reservations { } } my (%titles,%maptitles); - my %lt = &reservationlog_contexts(); + 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'})); @@ -1710,16 +2613,19 @@ sub show_reservations { if ($showntablehdr) { $r->print(&Apache::loncommon::end_data_table().'
'); if (($curr{'page'} > 1) || ($more_records)) { - $r->print(''); + $r->print('

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

'); + $r->print(''); } if ($more_records) { - $r->print(''); + $r->print(''); } - $r->print('
'.&mt('Previous [_1] changes',$curr{'show'}).''.&mt('Next [_1] changes',$curr{'show'}).'
'); + $r->print('

'); $r->print(<<"ENDSCRIPT"); ENDSCRIPT } } else { $r->print('' - .&mt('There are no transactions to display') + .&mt('There are no transactions to display.') .'' ); } @@ -1753,6 +2660,7 @@ ENDSCRIPT 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; @@ -1763,7 +2671,13 @@ sub show_reservations_log { $badslot = 1; } elsif ($slot{type} ne 'schedulable_student') { my $description = &get_description($env{'form.slotname'},\%slot); - $r->print('
'.&mt('Reservation history unavailable for non-student-reservable slot: [_1].',$description).'
'); + $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; } } @@ -1773,8 +2687,7 @@ sub show_reservations_log { return; } my $formname = 'reservationslog'; - my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my ($cnum,$cdom)=&get_course(); my %slotlog=&Apache::lonnet::dump('nohist_slotreservationslog',$cdom,$cnum); if ((keys(%slotlog))[0]=~/^error\:/) { undef(%slotlog); } @@ -1834,9 +2747,13 @@ sub show_reservations_log { my %slot=&Apache::lonnet::get_slot($env{'form.slotname'}); my $description = $slot{'description'}; - $r->print(''. - &mt('Reservation changes for student-reservable slot: [_1]',$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(). @@ -1854,7 +2771,7 @@ sub show_reservations_log { $minshown = 1 + ($curr{'page'} - 1) * $curr{'show'}; } } - my %lt = &reservationlog_contexts(); + 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'}) || @@ -1908,14 +2825,16 @@ sub show_reservations_log { if ($showntablehdr) { $r->print(&Apache::loncommon::end_data_table().'
'); if (($curr{'page'} > 1) || ($more_records)) { - $r->print(''); + $r->print('

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

'); + $r->print(''); } if ($more_records) { - $r->print(''); + $r->print(''); } - $r->print('
'.&mt('Previous [_1] changes',$curr{'show'}).''.&mt('Next [_1] changes',$curr{'show'}).'
'); + $r->print('

'); $r->print(<<"ENDSCRIPT"); ENDPICK return ''; @@ -2124,16 +3116,15 @@ 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(< $slot{'starttime'}) { @@ -2307,20 +3310,88 @@ 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 ($key eq 'maxspace') { + $slot{$key} =~ s/\D+//g; + } } } - + 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; @@ -2331,6 +3402,9 @@ sub csv_upload_assign { $r->rflush(); $countdone++; } + 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"); @@ -2356,6 +3430,15 @@ sub slot_command_titles { 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; @@ -2369,10 +3452,11 @@ sub handler { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}); my %crumb_titles = &slot_command_titles(); - my $brcrum; + my ($brcrum,$bread_crumbs_component); 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'; @@ -2393,14 +3477,21 @@ sub handler { if (ref($brcrum) eq 'ARRAY') { push(@{$brcrum},{href=>"/adm/slotrequest?command=showresv",text=>$title}); } - } elsif ($env{'form.command'} eq 'manageresv') { - $title = 'Manage Reservations'; - $brcrum =[{href=>"/adm/slotrequest?command=manageresv",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'}}]; + text=>$crumb_titles{'showslots'}, + help=>'Slot_Use'}]; $title = 'Managing Slots'; + $bread_crumbs_component = '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'}}}); @@ -2415,14 +3506,27 @@ sub handler { 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'); } - &start_page($r,$title,$brcrum); + if (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) { + $js = &reservation_js(\%slots,$consumed_uniqueperiods,$available,$got_slots,$symb); + } + &start_page($r,$title,$brcrum,$bread_crumbs_component,$js,$mgr); if ($env{'form.command'} eq 'manageresv') { + $allavailable = $available; + undef($available); + undef($got_slots); my $crstype = &Apache::loncommon::course_type(); - &manage_reservations($r,$crstype); + &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') { @@ -2452,7 +3556,7 @@ sub handler { } &csv_upload_map($r); } - } elsif ($env{'form.command'} eq 'slotlog' && $mgr eq 'F') { + } elsif (($env{'form.command'} eq 'slotlog') && ($vgr eq 'F')) { &show_reservations_log($r); } else { my $symb=&unescape($env{'form.symb'}); @@ -2474,18 +3578,40 @@ 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 {