--- loncom/interface/slotrequest.pm 2021/01/18 21:58:57 1.125.2.10 +++ loncom/interface/slotrequest.pm 2015/09/25 16:13:00 1.128 @@ -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.125.2.10 2021/01/18 21:58:57 raeburn Exp $ +# $Id: slotrequest.pm,v 1.128 2015/09/25 16:13:00 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -56,13 +56,10 @@ sub fail { } sub start_page { - my ($r,$title,$brcrum,$bread_crumbs_component,$js)=@_; + my ($r,$title,$brcrum,$js)=@_; 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 = ( @@ -263,6 +260,42 @@ function uncheckSlotRadio() { } } } + +function toggleSlotMap(maprownum) { + if (document.getElementById('arrow'+maprownum)) { + var img = document.getElementById('arrow'+maprownum); + var rowdisplay; + var celldisplay = ''; + if (img.src.indexOf('arrow.open.gif')!=-1) { + img.src = '/adm/lonIcons/arrow.closed.gif'; + rowdisplay = 'none'; + } + else { + img.src = '/adm/lonIcons/arrow.open.gif'; + rowdisplay = 'table-row'; + celldisplay = 'none'; + } + var resrows; + var maptext; + if (document.getElementsByClassName) { + resrows = document.getElementsByClassName('LC_slotmaprow_'+maprownum); + maptext = document.getElementsByClassName('LC_slotmaptext_'+maprownum); + } else { + resrows = getElementsByClassName(document.body,'LC_slotmaprow_'+maprownum); + maptext = getElementsByClassName(document.body,'LC_slotmaptext_'+maprownum); + } + if (resrows.length) { + for (var i=0; i<resrows.length; i++) { + resrows[i].style.display = rowdisplay; + } + } + if (maptext.length) { + for (var i=0; i<maptext.length; i++) { + maptext[i].style.display = celldisplay; + } + } + } +} // ]]> </script> ENDSCRIPT @@ -459,11 +492,11 @@ sub make_reservation { return 'error: Unable to determine current status'; } - my $symb_for_db = $symb; + my $parm_symb = $symb; my $parm_level = 1; if ($use_slots eq 'map' || $use_slots eq 'map_map') { my ($map) = &Apache::lonnet::decode_symb($symb); - $symb_for_db = &Apache::lonnet::symbread($map); + $parm_symb = &Apache::lonnet::symbread($map); $parm_level = 2; } @@ -506,7 +539,7 @@ sub make_reservation { my %reservation=('name' => $env{'user.name'}.':'.$env{'user.domain'}, 'timestamp' => time, - 'symb' => $symb_for_db); + 'symb' => $parm_symb); my $success=&Apache::lonnet::newput('slot_reservations', {"$slot_name\0$wanted" => @@ -518,9 +551,7 @@ sub make_reservation { if ($value) { $new_value=$value.':'.$new_value; } - 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'}); + &store_slot_parm($symb,$slot_name,$parm_level,$new_value,$cnum,$cdom); return $wanted; } @@ -529,27 +560,29 @@ sub make_reservation { } sub store_slot_parm { - 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); + 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_for_db, + symb => $symb, slot => $slot_name, - action => $action, - context => $context, + action => 'reserve', + context => $env{'form.context'}, ); &Apache::lonnet::write_log('course','slotreservationslog',\%storehash, - $delflag,$uname,$udom,$cnum,$cdom); + '',$env{'user.name'},$env{'user.domain'}, + $cnum,$cdom); &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash, - $delflag,$uname,$udom,$uname,$udom); - return $result; + 1,$env{'user.name'},$env{'user.domain'}, + $env{'user.name'},$env{'user.domain'}); + + return; } sub remove_registration { @@ -645,7 +678,7 @@ sub release_all_slot { &release_reservation($slot_name,$uname,$udom, $consumed{$entry}{'symb'},$mgr); if (!$result) { - $r->print('<p class="LC_error">'.&mt($msg).'</p>'); + $r->print('<p><span class="LC_error">'.&mt($msg).'</span></p>'); } else { $r->print("<p>$msg</p>"); } @@ -675,7 +708,7 @@ sub release_slot { my ($result,$msg) = &release_reservation($slot_name,$uname,$udom,$symb,$mgr); if (!$result) { - $r->print('<p class="LC_error">'.&mt($msg).'</p>'); + $r->print('<p><span class="LC_error">'.&mt($msg).'</span></p>'); } else { $r->print("<p>$msg</p>"); } @@ -693,184 +726,26 @@ 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 started.',$description)); + return (0,&mt('Not allowed to release Reservation: [_1], as it has already ended.',$description)); } } - my $context = $env{'form.context'}; - # get navmap object + # if the reservation symb is for a map get a resource in that map + # to check slot parameters on my $navmap=Apache::lonnavmaps::navmap->new; if (!defined($navmap)) { return (0,'error: Unable to determine current status'); } - - my ($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 = '<span style="font-weight: bold;">'. - &mt('Released Reservation: [_1]',$description).'</span> '. - &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 .= '<ul>'; - if (keys(%folders)) { - $msg .= '<li>'.&mt('Folders').': '. - join(', ', map { $folders{$_}{'title'} } (sort { $folders{$b}{'title'} cmp $folders{$a}{'title'} } (keys(%folders)))). - '</li>'; - } - if (keys(%pages)) { - $msg .= '<li>'.&mt('Composite Pages').': '. - join(', ', map { $pages{$_}{'title'} } (sort { $pages{$b}{'title'} cmp $pages{$a}{'title'} } (keys(%pages)))). - '</li>'; - } - if (keys(%container)) { - $msg .= '<li>'.&mt('Resources').':<ul>'; - foreach my $key (sort { $container{$b}{'title'} cmp $container{$a}{'title'} } (keys(%container))) { - if (ref($container{$key}{'resources'}) eq 'HASH') { - $msg .= '<li>'. - join(', ', map { $titles{$_} } (sort(keys(%{$container{$key}{'resources'}})))); - if ($container{$key}{'page'}) { - $msg .= ' '.&mt('(in composite page [_1])',$container{$key}{'title'}).'</li>'; - } else { - $msg .= ' '.&mt('(in folder [_1])',$container{$key}{'title'}).'</li>'; - } - } - } - $msg .= '</ul></li>'; - } - $msg .= '</ul>'; - 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); - } - } - - my $map_symb; - my $parm_symb = $symb; my $passed_resource = $navmap->getBySymb($symb); - - # 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,1); - $parm_symb = $a_resource->symb(); + $symb = $a_resource->symb(); } } else { unless ($mgr eq 'F') { @@ -878,132 +753,68 @@ sub release_reservation { } } - # 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', - $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. - # + # get parameter string, check for existence, rebuild string with the slot + my $student = &Apache::lonnet::EXT("resource.0.availablestudent", + $symb,$udom,$uname); + my @slots = split(/:/,$student); - my ($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) ) { - 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").'<br />'. - &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 = '<span style="font-weight: bold;">'.&mt('Released reservation: [_1]',$description).'</span><br /><br />'; - 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); + my @new_slots; + foreach my $exist_slot (@slots) { + if ($exist_slot eq $slot_name) { next; } + push(@new_slots,$exist_slot); } -} + my $new_param = join(':',@new_slots); -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 ($cnum,$cdom)=&get_course(); - # 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,1); - $symb_for_parm = $a_resource->symb(); + # get slot reservations, check if user has one, if so remove reservation + my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, + "^$slot_name\0"); + foreach my $entry (keys(%consumed)) { + if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) { + &Apache::lonnet::del('slot_reservations',[$entry], + $cdom,$cnum); + my %storehash = ( + symb => $symb, + slot => $slot_name, + action => 'release', + context => $env{'form.context'}, + ); + &Apache::lonnet::write_log('slotreservationslog',\%storehash, + 1,$uname,$udom,$cnum,$cdom); + &Apache::lonnet::write_log($cdom.'_'.$cnum.'_slotlog',\%storehash, + 1,$uname,$udom,$uname,$udom); + } } - # 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); + my $use_slots = &Apache::lonnet::EXT("resource.0.useslots", + $symb,$udom,$uname); &Apache::lonxml::debug("use_slots is $use_slots<br />"); - if (&Apache::lonnet::error($use_slots)) { - return 'error: Unable to determine current status'; + if (&Apache::lonnet::error($use_slots)) { + return (0,'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; } - - my @slots = split(/:/,$student); - - my @new_slots; - foreach my $exist_slot (@slots) { - next if ($exist_slot eq $slot_name); - push(@new_slots,$exist_slot); + # 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 = '<span style="font-weight: bold;">'.&mt('Released reservation: [_1]',$description).'</span><br /><br />'; + 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'); } - 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; + return (1,$msg); } sub delete_slot { @@ -1025,7 +836,7 @@ sub delete_slot { if ($ret eq 'ok') { $r->print('<p>'.&mt('Slot [_1] marked as deleted.','<tt>'.$slot_name.'</tt>').'</p>'); } else { - $r->print('<p class="LC_error">'.&mt('An error occurred when attempting to delete slot: [_1]','<tt>'.$slot_name.'</tt>')." ($ret)</p>"); + $r->print('<p><span class="LC_error">'.&mt('An error occurred when attempting to delete slot: [_1]','<tt>'.$slot_name.'</tt>')." ($ret)</span></p>"); } } else { if (%consumed) { @@ -1057,24 +868,18 @@ sub get_slot { my $slot_name=&check_for_conflict($symb,$env{'form.slotname'},\%slot); if ($slot_name =~ /^error: (.*)/) { - $r->print('<p class="LC_error">' + $r->print('<p><span class="LC_error">' .&mt('An error occurred while attempting to make a reservation. ([_1])',$1) - .'</p>'); + .'</span></p>'); &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); - if ($slottype1 eq 'preassigned') { - $r->print('<p>'.&mt('You already have a reservation: "[_1]", assigned by your instructor.', - $description1).'</p>'. - '<p>'.&mt('Your instructor must unassign it before you can make a new reservation.'). - '</p>'); - } elsif ($slot_name ne $env{'form.slotname'}) { + if ($slot_name ne $env{'form.slotname'}) { $r->print(<<STUFF); <form method="post" action="/adm/slotrequest"> <input type="hidden" name="symb" value="$env{'form.symb'}" /> @@ -1112,9 +917,9 @@ STUFF if (defined($reserved)) { my $retvalue = 0; if ($slot_name =~ /^error: (.*)/) { - $r->print('<p class="LC_error">' + $r->print('<p><span class="LC_error">' .&mt('An error occurred while attempting to make a reservation. ([_1])',$1) - .'</p>'); + .'</span></p>'); } elsif ($reserved > -1) { $r->print('<p style="font-weight: bold;">'.&mt('Successfully signed up: [_1]',$description).'</p>'); $retvalue = 1; @@ -1246,10 +1051,21 @@ sub allowed_slot { return 0 if (!$userallowed); # not allowed for this resource - if (defined($slot->{'symb'}) - && $slot->{'symb'} ne $symb) { - unless ((ref($toskip) eq 'HASH') && ($toskip->{'symb'})) { - return 0; + if (defined($slot->{'symb'})) { + my $exclude = 1; + my ($slotmap,$slotid,$sloturl) = &Apache::lonnet::decode_symb($slot->{'symb'}); + if ($sloturl=~/\.(page|sequence)$/) { + my ($map,$id,$url) = &Apache::lonnet::decode_symb($symb); + if (($map ne '') && ($map eq $slotmap)) { + $exclude = 0; + } + } elsif ($slot->{'symb'} eq $symb) { + $exclude = 0; + } + if ($exclude) { + unless ((ref($toskip) eq 'HASH') && ($toskip->{'symb'})) { + return 0; + } } } @@ -1278,7 +1094,7 @@ sub get_description { } sub show_choices { - my ($r,$symb,$formname,$num,$slots,$consumed_uniqueperiods,$available,$got_slots)=@_; + my ($symb,$formname,$num,$class,$slots,$consumed_uniqueperiods,$available,$got_slots)=@_; my $output; &Apache::lonxml::debug("Checking Slots"); if (!ref($available) eq 'ARRAY') { @@ -1290,8 +1106,11 @@ sub show_choices { $output .= ' <a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a>'; } - $r->print($output); - return; + if ($class) { + return '<div class="'.$class.'">'.$output.'</div>'; + } else { + return $output; + } } if (@{$available} > 1) { my $numavailable = scalar(@{$available}); @@ -1439,8 +1258,11 @@ STUFF if (@{$available} > 1) { $output .= '</div></fieldset>'; } - $r->print($output); - return; + if ($class) { + return '<div class="'.$class.'">'.$output.'</div>'; + } else { + return $output; + } } sub to_show { @@ -1541,6 +1363,10 @@ sub show_table { } my $available; if ($mgr eq 'F') { + # FIXME: This line should be deleted once Slots uses breadcrumbs + $r->print('<br />'.&Apache::loncommon::help_open_topic( + 'Slot About', &mt('Help on slots'))); + $r->print('<div>'); $r->print('<form method="post" action="/adm/slotrequest"> <input type="hidden" name="command" value="uploadstart" /> @@ -1550,7 +1376,7 @@ sub show_table { $r->print('<form method="post" action="/adm/helper/newslot.helper"> <input type="submit" name="newslot" value="'.&mt('Create a New Slot').'" /> </form>'); - $r->print(&Apache::loncommon::help_open_topic('Slot About')); + $r->print(&Apache::loncommon::help_open_topic('Slot AddInterface')); $r->print('</div>'); } @@ -1591,7 +1417,7 @@ sub show_table { 'secret' => 'Secret Word', 'space' => '# of students/max', 'ip' => 'IP or DNS restrictions', - 'symb' => 'Resource slot is restricted to.', + 'symb' => 'Resource/Map slot is restricted to.', 'allowedsections' => 'Sections slot is restricted to.', 'allowedusers' => 'Users slot is restricted to.', 'uniqueperiod' => 'Period of time slot is unique', @@ -1703,16 +1529,15 @@ sub show_table { $r->print('</div>'); $r->print('<p><input type="submit" name="start" value="'.&mt('Update Display').'" /></p>'); my $linkstart='<a href="/adm/slotrequest?command=showslots&order='; - my $tableheader = &Apache::loncommon::start_data_table(). - &Apache::loncommon::start_data_table_header_row().' - <th></th>'; + $r->print(&Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row().' + <th></th>'); foreach my $which (@show_order) { if ($which ne 'proctor' && exists($show{$which})) { - $tableheader .= '<th>'.$linkstart.$which.'">'.$show_fields{$which}.'</a></th>'; + $r->print('<th>'.$linkstart.$which.'">'.$show_fields{$which}.'</a></th>'); } } - $tableheader .= &Apache::loncommon::end_data_table_header_row(); - my $shownheader = 0; + $r->print(&Apache::loncommon::end_data_table_header_row()); my %name_cache; my $slotsort = sub { @@ -1861,39 +1686,30 @@ sub show_table { delete => 'Delete', slotlog => 'History', ); - my ($edit,$delete,$showlog,$remove_all); - if ($mgr) { - $edit=(<<"EDITLINK"); + my $edit=(<<"EDITLINK"); <a href="/adm/helper/newslot.helper?name=$slot">$lt{'edit'}</a> EDITLINK - $delete=(<<"DELETELINK"); + my $delete=(<<"DELETELINK"); <a href="/adm/slotrequest?command=delete&slotname=$slot">$lt{'delete'}</a> DELETELINK - $remove_all=&remove_link($slot,'remove all').'<br />'; - - if ($ids eq '') { - undef($remove_all); - } else { - undef($delete); - } - } - - $showlog=(<<"LOGLINK"); + my $showlog=(<<"LOGLINK"); <a href="/adm/slotrequest?command=slotlog&slotname=$slot">$lt{'slotlog'}</a> LOGLINK + my $remove_all=&remove_link($slot,'remove all').'<br />'; + + 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. @@ -1962,12 +1778,7 @@ $row_end STUFF } } - if ($shownheader) { - $r->print(&Apache::loncommon::end_data_table()); - } else { - $r->print('<p>'.&mt('No slots meet the criteria for display').'</p>'); - } - $r->print('</form>'); + $r->print(&Apache::loncommon::end_data_table().'</form>'); return; } @@ -2015,18 +1826,93 @@ sub manage_reservations { '<table class="LC_data_table LC_tableOfContent">'."\n"; my $shownheader = 0; my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef); + my (@ordered,%output,$mapitem,$got_map_slot,$currmapoutput,$mapnum); + $mapnum = 0; while (my $resource = $it->next()) { if ($resource == $it->BEGIN_MAP()) { + @ordered=(); + undef(%output); + $currmapoutput = ''; + $got_map_slot = ''; + $mapitem = ''; $depth++; $parent{$depth} = $lastcontainer; } if ($resource == $it->END_MAP()) { $depth--; $lastcontainer = $parent{$depth}; + my %allstatuses; + foreach my $symb (@ordered) { + if (ref($output{$symb}) eq 'HASH') { + if (($output{$symb}{'type'} eq 'map_map') || ($output{$symb}{'type'} eq 'map')) { + if ($output{$symb}{'slotstatus'} ne '') { + if (ref($allstatuses{$output{$symb}{'slotstatus'}}) eq 'ARRAY') { + push(@{$allstatuses{$output{$symb}{'slotstatus'}}},$symb); + } else { + $allstatuses{$output{$symb}{'slotstatus'}} = [$symb]; + } + } + } + } + } + if (keys(%allstatuses) == 1) { + $got_map_slot = 1; + my $repsymb; + my @values = values(%allstatuses); + if (ref($values[0]) eq 'ARRAY') { + if (ref($output{$values[0][0]}) eq 'HASH') { + $repsymb = $values[0][0]; + } + } + if (($mapitem) && ($repsymb)) { + my $formnum = $mapnum.'_'.$output{$repsymb}{'reservable'}; + my $class = 'LC_slotmaptext_'.$mapnum; + if ($output{$repsymb}{'hasaction'}) { + $mapitem .= '<td valign="top"><span class="'.$class.'">'. + $output{$repsymb}{'msg'}. + '</span></td><td valign="top">'. + &slot_chooser($repsymb,$class,$formnum,$allavailable,$slots, + $consumed_uniqueperiods). + '</td>'; + + } else { + $mapitem .= '<td colspan="2" valign="middle"><span class="'.$class.'">'. + $output{$repsymb}{'msg'}. + '</span></td>'; + } + } + foreach my $symb (@ordered) { + if (ref($output{$symb}) eq 'HASH') { + my $bgcolor = $backgrounds[$output{$symb}{'rownum'} % $numcolors]; + $currmapoutput .= $output{$symb}{'header'}. + '<tr class="'.$bgcolor.' LC_slotmaprow_'.$output{$symb}{'mapnum'}.'"'. + ' style="display:none">'.$output{$symb}{'info'}. + $output{$symb}{'data'}.'</tr>'."\n"; + } + } + } else { + foreach my $symb (@ordered) { + if (ref($output{$symb}) eq 'HASH') { + my $bgcolor = $backgrounds[$output{$symb}{'rownum'} % $numcolors]; + $currmapoutput .= $output{$symb}{'header'}. + '<tr class="'.$bgcolor.' LC_slotmaprow_'.$output{$symb}{'mapnum'}.'"'. + ' style="display:table-row">'.$output{$symb}{'info'}. + $output{$symb}{'data'}.'</tr>'."\n"; + } + } + } + if ($mapitem) { + if ($got_map_slot) { + $mapitem =~ s{(<img src=\"/adm/lonIcons/arrow\.)open(\.gif\")}{$1closed$2}; + $mapitem .= '</tr>'."\n"; + } else { + $mapitem .= '<td colspan="2"> </td></tr>'."\n"; + } + } + $r->print($mapitem.$currmapoutput); } if (ref($resource)) { my $symb = $resource->symb(); - my $ressymb = $symb; $contents{$lastcontainer} ++; next if (!$resource->is_problem() && !$resource->is_sequence() && !$resource->is_page()); @@ -2039,10 +1925,15 @@ sub manage_reservations { if ($resource->is_problem()) { my ($useslots) = $resource->slot_control(); next if (($useslots eq '') || ($useslots =~ /^\s*no\s*$/i)); + push(@ordered,$symb); + $output{$symb}{type} = $useslots; 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'); + + $output{$symb}{'slotstatus'} = $slot_status; + $output{$symb}{'slotname'} = $slot_name; if ($slot_name ne '') { my %slot=&Apache::lonnet::get_slot($slot_name); $slotdescription=&get_description($slot_name,\%slot); @@ -2086,7 +1977,9 @@ sub manage_reservations { $msg = &Apache::lonnavmaps::getDescription($resource,'0'); } } + $output{$symb}{'msg'} = $msg; $reservable ++; + $output{$symb}{'reservable'} = $reservable; my $treelevel = $depth; my $higherup = $lastcontainer; if ($depth > 1) { @@ -2107,76 +2000,67 @@ sub manage_reservations { $treelevel --; $higherup = $parent{$treelevel}; } - foreach my $item (@maprows) { + for (my $i=0; $i<@maprows; $i++) { + $mapnum ++; $rownum ++; my $bgcolor = $backgrounds[$rownum % $numcolors]; if (!$shownheader) { - $r->print($slotheader); + $mapitem .= $slotheader; $shownheader = 1; } - $r->print('<tr class="'.$bgcolor.'">'.$item.'</tr>'."\n"); + if (ref($maprows[$i]) eq 'ARRAY') { + if ($i < scalar(@maprows)-1) { + $mapitem .= '<tr class="'.$bgcolor.'"><td>'.join('',@{$maprows[$i]}).'</td>'. + '<td colspan="2"> </td></tr>'."\n"; + } else { + $mapitem .= + '<tr class="'.$bgcolor.'"><td>'.$maprows[$i][0]. + '<img src="/adm/lonIcons/arrow.open.gif" id="arrow'.$mapnum.'" '. + 'alt="arrow" onmouseover="this.style.cursor=\'pointer\'" '. + 'onclick="'."toggleSlotMap('$mapnum');".'" />'. + $maprows[$i][1].(' ' x6).'</td>'."\n"; + } + } } + $output{$symb}{'mapnum'} = $mapnum; } $rownum ++; - my $bgcolor = $backgrounds[$rownum % $numcolors]; + $output{$symb}{'rownum'} = $rownum; if (!$shownheader) { - $r->print($slotheader); + $output{$symb}{'header'} = $slotheader; $shownheader = 1; } - $r->print('<tr class="'.$bgcolor.'"><td>'."\n"); + $output{$symb}{'info'} = '<td>'; for (my $i=0; $i<$depth; $i++) { - $r->print('<img src="'.$location.'" alt="" />'); + $output{$symb}{'info'} .= '<img src="'.$location.'" alt="" />'; } - my $result = '<a href="'.$resource->src().'?symb='.$symb.'">'. - '<img class="LC_contentImage" src="/adm/lonIcons/'; + $output{$symb}{'info'} .= '<a href="'.$resource->src().'?symb='.$symb.'">'. + '<img class="LC_contentImage" src="/adm/lonIcons/'; if ($resource->is_task()) { - $result .= 'task.gif" alt="'.&mt('Task'); + $output{$symb}{'info'} .= 'task.gif" alt="'.&mt('Task'); } else { - $result .= 'problem.gif" alt="'.&mt('Problem'); + $output{$symb}{'info'} .= 'problem.gif" alt="'.&mt('Problem'); } - $result .= '" /><b>'.$title.'</b></a>'.(' ' x6).'</td>'; + $output{$symb}{'info'} .= '" /><b>'.$title.'</b></a>'.(' ' x6).'</td>'; + my $hasaction; if ($status == $resource->OPEN) { if ($get_choices) { $hasaction = 1; + $output{$symb}{'hasaction'} = $hasaction; } } + my $class = 'LC_slottext_'.$mapnum; if ($hasaction) { - $result .= '<td valign="top">'.$msg.'</td>'. - '<td valign="top">'; + $output{$symb}{'data'} = '<td valign="top"><span class="'.$class.'">'.$msg.'</span></td>'. + '<td valign="top">'. + &slot_chooser($symb,$class,$reservable,$allavailable,$slots, + $consumed_uniqueperiods).'</td>'; } else { - $result .= '<td colspan="2" valign="middle">'.$msg.'</td>'; - } - $r->print($result); - if ($hasaction) { - my @got_slots=&check_for_reservation($symb,'allslots'); - if ($got_slots[0] =~ /^error: /) { - $r->print('<span class="LC_error">'. - &mt('An error occurred determining slot availability.'). - '</span>'); - } else { - my $formname = 'manageres_'.$reservable; - if (ref($allavailable) eq 'ARRAY') { - my @available; - if (ref($slots) eq 'HASH') { - foreach my $slot (@{$allavailable}) { - # not allowed for this resource - if (ref($slots->{$slot}) eq 'HASH') { - if ((defined($slots->{$slot}->{'symb'})) && - ($slots->{$slot}->{'symb'} ne $symb)) { - next; - } - } - push(@available,$slot); - } - } - &show_choices($r,$symb,$formname,$reservable,$slots,$consumed_uniqueperiods, - \@available,\@got_slots); - } - } - $r->print('</td>'); + $output{$symb}{'data'} = '<td colspan="2" valign="middle">'. + '<span class="'.$class.'">'.$msg.'</span>'. + '</td>'; } - $r->print('</tr>'); } } } @@ -2198,20 +2082,53 @@ sub manage_reservations { sub show_map_row { my ($depth,$location,$type,$title,$maprows) = @_; - my $output = '<td>'; - for (my $i=0; $i<$depth-1; $i++) { - $output .= '<img src="'.$location.'" alt="" />'; + my $spacers; + for (my $i=0; $i<$depth-2; $i++) { + $spacers .= '<img src="'.$location.'" alt="" />'; } + my $icon; if ($type eq 'page') { - $output .= '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" /> '."\n"; + $icon = '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" /> '."\n"; } else { - $output .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n"; + $icon = '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n"; } - $output .= $title.'</td><td colspan="2"> </td>'."\n"; - unshift (@{$maprows},$output); + $icon .= $title; + unshift (@{$maprows},[$spacers,$icon]); return; } +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 = '<span class="'.$class.'"><span class="LC_error">'. + &mt('An error occurred determining slot availability.'). + '</span></span>'; + } 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 ((defined($slots->{$slot}->{'symb'})) && + ($slots->{$slot}->{'symb'} ne $symb)) { + next; + } + } + 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)) { @@ -2323,16 +2240,14 @@ sub show_reservations { if ($showntablehdr) { $r->print(&Apache::loncommon::end_data_table().'<br />'); if (($curr{'page'} > 1) || ($more_records)) { - $r->print('<p>'); + $r->print('<table><tr>'); if ($curr{'page'} > 1) { - $r->print('<input type="button" onclick="javascript:chgPage('."'previous'".');" value="'. - &mt('Previous [_1] changes',$curr{'show'}).'" />'); + $r->print('<td><a href="javascript:chgPage('."'previous'".');">'.&mt('Previous [_1] changes',$curr{'show'}).'</a></td>'); } if ($more_records) { - $r->print('<input type="button" onclick="javascript:chgPage('."'next'".');" value="'. - &mt('Next [_1] changes',$curr{'show'}).'" />'); + $r->print('<td><a href="javascript:chgPage('."'next'".');">'.&mt('Next [_1] changes',$curr{'show'}).'</a></td>'); } - $r->print('</p>'); + $r->print('</tr></table>'); $r->print(<<"ENDSCRIPT"); <script type="text/javascript"> // <![CDATA[ @@ -2536,16 +2451,14 @@ sub show_reservations_log { if ($showntablehdr) { $r->print(&Apache::loncommon::end_data_table().'<br />'); if (($curr{'page'} > 1) || ($more_records)) { - $r->print('<p>'); + $r->print('<table><tr>'); if ($curr{'page'} > 1) { - $r->print('<input type="button" onclick="javascript:chgPage('."'previous'".');" value="'. - &mt('Previous [_1] changes',$curr{'show'}).'" />'); + $r->print('<td><a href="javascript:chgPage('."'previous'".');">'.&mt('Previous [_1] changes',$curr{'show'}).'</a></td>'); } if ($more_records) { - $r->print('<input type="button" onclick="javascript:chgPage('."'next'".');" value="'. - &mt('Next [_1] changes',$curr{'show'}).'" />'); + $r->print('<td><a href="javascript:chgPage('."'next'".');">'.&mt('Next [_1] changes',$curr{'show'}).'</a></td>'); } - $r->print('</p>'); + $r->print('</tr></table>'); $r->print(<<"ENDSCRIPT"); <script type="text/javascript"> function chgPage(caller) { @@ -2685,9 +2598,8 @@ sub display_filter { } $output .= '</select></td>'; } - $output .= '<td> </td></tr></table>'. - '<p><input type="submit" value="'. - &mt('Update Display').'" /></p>'. + $output .= '<td> </td><td valign="middle"><input type="submit" value="'. + &mt('Update Display').'" /></tr></table>'. '<p class="LC_info">'. &mt('Only changes made from servers running LON-CAPA [_1] or later are displayed.' ,'2.9.0'); @@ -2893,10 +2805,8 @@ sub csv_upload_map { if (!$env{'form.datatoken'}) { $datatoken=&Apache::loncommon::upfile_store($r); } else { - $datatoken=&Apache::loncommon::valid_datatoken($env{'form.datatoken'}); - if ($datatoken ne '') { - &Apache::loncommon::load_tmp_file($r,$datatoken); - } + $datatoken=$env{'form.datatoken'}; + &Apache::loncommon::load_tmp_file($r); } my @records=&Apache::loncommon::upfile_record_sep(); if ($env{'form.noFirstLine'}) { shift(@records); } @@ -2936,7 +2846,7 @@ sub csvupload_fields { ['proctor','List of proctor ids'], ['description','Slot Description'], ['maxspace','Maximum number of reservations'], - ['symb','Resource Restriction'], + ['symb','Resource/Map Restriction'], ['uniqueperiod','Date range of slot exclusion'], ['secret','Secret word proctor uses to validate'], ['allowedsections','Sections slot is restricted to'], @@ -2946,10 +2856,7 @@ sub csvupload_fields { sub csv_upload_assign { my ($r,$mgr)= @_; - my $datatoken = &Apache::loncommon::valid_datatoken($env{'form.datatoken'}); - if ($datatoken ne '') { - &Apache::loncommon::load_tmp_file($r,$datatoken); - } + &Apache::loncommon::load_tmp_file($r); my @slotdata = &Apache::loncommon::upfile_record_sep(); if ($env{'form.noFirstLine'}) { shift(@slotdata); } my %fields=&Apache::grades::get_fields(); @@ -3007,12 +2914,8 @@ sub csv_upload_assign { } if ($entries{$fields{'startreserve'}}) { - 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; - } + $slot{'startreserve'}= + &UnixDate($entries{$fields{'startreserve'}},"%s"); } if (defined($slot{'startreserve'}) && $slot{'startreserve'} > $slot{'starttime'}) { @@ -3021,12 +2924,8 @@ sub csv_upload_assign { } 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; - } + $slot{'endreserve'}= + &UnixDate($entries{$fields{'endreserve'}},"%s"); } if (defined($slot{'endreserve'}) && $slot{'endreserve'} > $slot{'starttime'}) { @@ -3052,9 +2951,6 @@ sub csv_upload_assign { 'secret','symb') { if ($entries{$fields{$key}}) { $slot{$key}=$entries{$fields{$key}}; - if ($key eq 'maxspace') { - $slot{$key} =~ s/\D+//g; - } } } if ($entries{$fields{'allowedusers'}}) { @@ -3089,14 +2985,12 @@ sub csv_upload_assign { } } if ($entries{$fields{'uniqueperiod'}}) { - 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"); - } + my ($start,$end)=split(',',$entries{$fields{'uniqueperiod'}}); + my @times=(&UnixDate($start,"%s"), + &UnixDate($end,"%s")); + $slot{'uniqueperiod'}=\@times; } - if (ref($slot{'uniqueperiod'}) eq 'ARRAY' + if (defined($slot{'uniqueperiod'}) && $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; @@ -3157,7 +3051,7 @@ sub handler { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}); my %crumb_titles = &slot_command_titles(); - my ($brcrum,$bread_crumbs_component); + my $brcrum; my $vgr=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}); my $mgr=&Apache::lonnet::allowed('mgr',$env{'request.course.id'}); @@ -3193,10 +3087,8 @@ sub handler { } 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'}, - help=>'Slot_Use'}]; + text=>$crumb_titles{'showslots'}}]; $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'}}}); @@ -3224,7 +3116,7 @@ sub handler { 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); + &start_page($r,$title,$brcrum,$js); if ($env{'form.command'} eq 'manageresv') { $allavailable = $available; @@ -3261,7 +3153,7 @@ sub handler { } &csv_upload_map($r); } - } elsif (($env{'form.command'} eq 'slotlog') && ($vgr eq 'F')) { + } elsif ($env{'form.command'} eq 'slotlog' && $mgr eq 'F') { &show_reservations_log($r); } else { my $symb=&unescape($env{'form.symb'}); @@ -3289,7 +3181,7 @@ sub handler { } if ($env{'form.requestattempt'}) { $r->print('<div class="LC_left_float">'); - &show_choices($r,$symb,undef,undef,\%slots,$consumed_uniqueperiods,$available,$got_slots); + $r->print(&show_choices($symb,undef,undef,undef,\%slots,$consumed_uniqueperiods,$available,$got_slots)); $r->print('</div><div style="padding:0;clear:both;margin:0;border:0"></div>'); } elsif ($env{'form.command'} eq 'release') { &release_slot($r,$symb);