![]() ![]() | ![]() |
- can now change a reservation or freee one
# The LearningOnline Network with CAPA # Handler for requesting to have slots added to a students record # # $Id: slotrequest.pm,v 1.6 2005/08/09 15:04:50 albertel Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # ### package Apache::slotrequest; use strict; use Apache::Constants qw(:common :http :methods); use Apache::loncommon(); use Apache::lonlocal; use Apache::lonnet; sub fail { my ($r,$code)=@_; if ($code eq 'not_valid') { $r->print('<p>'.&mt('Unable to understand what resource you wanted to sign up for.').'</p>'.$env{'form.symb'}); } $r->print('<p><a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></p>'); &end_page($r); } sub start_page { my ($r)=@_; my $html=&Apache::lonxml::xmlbegin(); $r->print($html.'<head><title>'. &mt('Request another Worktime').'</title></head>'); $r->print(&Apache::loncommon::bodytag('Requesting another Worktime')); } sub end_page { my ($r)=@_; $r->print(&Apache::loncommon::endbodytag().'</html>'); } =pod slot_reservations db - keys are - slotname\0id -> value is an hashref of name -> user@domain of holder timestamp -> timestamp of reservation symb -> symb of resource that it is reserved for =cut sub get_course { (undef,my $courseid)=&Apache::lonxml::whichuser(); my $cdom=$env{'course.'.$courseid.'.domain'}; my $cnum=$env{'course.'.$courseid.'.num'}; return ($cnum,$cdom); } sub get_reservation_ids { my ($slot_name)=@_; my ($cnum,$cdom)=&get_course(); my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, "^$slot_name\0"); my ($tmp)=%consumed; if ($tmp=~/^error: 2 / ) { return 0; } return keys(%consumed); } sub space_available { my ($slot_name,$slot)=@_; my $max=$slot->{'maxspace'}; if (!defined($max)) { return 1; } my $consumed=scalar(&get_reservation_ids($slot_name)); if ($consumed < $max) { return 1 } return 0; } sub check_for_reservation { my ($symb)=@_; my $student = &Apache::lonnet::EXT("resource.0.availablestudent", $symb, $env{'user.domain'}, $env{'user.name'}); my $course = &Apache::lonnet::EXT("resource.0.available", $symb, $env{'user.domain'}, $env{'user.name'}); my @slots = (split(/:/,$student), split(/:/, $course)); &Apache::lonxml::debug(" slot list is ".join(':',@slots)); my ($cnum,$cdom)=&get_course(); my %slots=&Apache::lonnet::get('slots', [@slots], $cdom, $cnum); foreach my $slot_name (@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}->{'starttime'} > time && $slots{$slot_name}->{'startreserve'} < time) { # between start of reservation times and start of slot return($slot_name, $slots{$slot_name}); } } return (undef,undef); } sub check_for_conflict { my ($symb,$new_slot_name)=@_; 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)); my ($cnum,$cdom)=&get_course(); my %slots=&Apache::lonnet::get('slots', [@slots], $cdom, $cnum); foreach my $slot_name (@slots) { next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name})); next if (!defined($slots{$slot_name}->{'uniqueperiod'}) || !ref($slots{$slot_name}->{'uniqueperiod'})); my ($start,$end)=@{$slots{$slot_name}->{'uniqueperiod'}}; if ($start<time && time < $end) { return $slot_name; } } return undef; } # FIXME - depends on the parameter for the resource to be correct # to prevent multiple reservations sub make_reservation { my ($slot_name,$slot,$symb)=@_; my ($cnum,$cdom)=&get_course(); my $value=&Apache::lonnet::EXT("resource.0.availablestudent",$symb, $env{'user.domain'},$env{'user.name'}); &Apache::lonxml::debug("value is $value<br />"); foreach my $other_slot (split(/:/, $value)) { if ($other_slot eq $slot_name) { my %consumed=&Apache::lonnet::dump('slot_reservations', $cdom, $cnum, "^$slot_name\0"); my $me=$env{'user.name'}.'@'.$env{'user.domain'}; foreach my $key (keys(%consumed)) { if ($consumed{$key}->{'name'} eq $me) { my $num=(split('\0',$key))[1]; return -$num; } } } } my $max=$slot->{'maxspace'}; if (!defined($max)) { $max=99999; } my (@ids)=&get_reservation_ids($slot_name); # FIXME we could end up having holes... my $last=0; foreach my $id (@ids) { my $num=(split('\0',$id))[1]; if ($num > $last) { $last=$num; } } my $wanted=$last+1; &Apache::lonxml::debug("wanted $wanted<br />"); if ($wanted >= $max) { # full up return -1; } my %reservation=('name' => $env{'user.name'}.'@'.$env{'user.domain'}, 'timestamp' => time, 'symb' => $symb); my $success=&Apache::lonnet::newput('slot_reservations', {"$slot_name\0$wanted" => \%reservation}, $cdom, $cnum); if ($success eq 'ok') { #FIXME need to set the parm my $new_value=$slot_name; if ($value) { $new_value=$value.':'.$new_value; } my $result=&Apache::lonparmset::storeparm_by_symb($symb, '0_availablestudent', 1, $new_value, 'string', $env{'user.name'}, $env{'user.domain'}); &Apache::lonxml::debug("hrrm $result"); return $wanted; } # someone else got it return undef; } sub release_slot { my ($r,$symb,$slot_name,$inhibit_return_link)=@_; if ($slot_name eq '') { $slot_name=$env{'form.slotname'}; } my ($cnum,$cdom)=&get_course(); # get parameter string, check for existance, rebuild string with the slot my @slots = split(/:/,&Apache::lonnet::EXT("resource.0.availablestudent", $symb,$env{'user.domain'}, $env{'user.name'})); 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); # 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 ($env{'user.name'}.'@'.$env{'user.domain'}) ) { &Apache::lonnet::del('slot_reservations',[$entry], $cdom,$cnum); } } # store new parameter string my $result=&Apache::lonparmset::storeparm_by_symb($symb, '0_availablestudent', 1, $new_param, 'string', $env{'user.name'}, $env{'user.domain'}); my %slot=&Apache::lonnet::get_slot($slot_name); my $description=&get_description($env{'form.slotname'},\%slot); $r->print("<p>Released Reservation: $description</p>"); if ($inhibit_return_link) { $r->print('<p><a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></p>'); } return 1; } sub get_slot { my ($r,$symb)=@_; my $slot_name=&check_for_conflict($symb,$env{'form.slotname'}); if ($slot_name) { my %slot=&Apache::lonnet::get_slot($slot_name); my $description1=&get_description($slot_name,\%slot); %slot=&Apache::lonnet::get_slot($env{'form.slotname'}); my $description2=&get_description($env{'form.slotname'},\%slot); $r->print("<p>Already have a reservation: $description1</p>"); $r->print(<<STUFF); <form method="POST" action="/adm/slotrequest"> <input type="hidden" name="symb" value="$env{'form.symb'}" /> <input type="hidden" name="slotname" value="$env{'form.slotname'}" /> <input type="hidden" name="releaseslot" value="$slot_name" /> <input type="hidden" name="command" value="change" /> STUFF $r->print("<p>You can either "); $r->print(<<STUFF); <input type="submit" name="change" value="Change" /> STUFF $r->print(' your reservation from <b>'.$description1.'</b> to <b>'. $description2. '</b> <br />or <a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></p>'); $r->print(<<STUFF); </form> STUFF # FIXME add button to free current reservation and get new one return; } my %slot=&Apache::lonnet::get_slot($env{'form.slotname'}); my $reserved=&make_reservation($env{'form.slotname'}, \%slot,$symb); my $description=&get_description($env{'form.slotname'},\%slot); if ($reserved > -1) { $r->print("<p>Success: $description</p>"); $r->print('<p><a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></p>'); return; } elsif ($reserved < 0) { $r->print("<p>Already reserved: $description</p>"); $r->print('<p><a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></p>'); return; } my %lt=('request'=>"Request another attempt", 'try' =>'Try again'); %lt=&Apache::lonlocal::texthash(%lt); $r->print(<<STUFF); <p> <font color="red">Failed</font> to reserve a spot for $description. </p> <p> <form method="POST" action="/adm/slotrequest"> <input type="submit" name="Try Again" value="$lt{'try'}" /> <input type="hidden" name="symb" value="$env{'form.symb'}" /> <input type="hidden" name="slotname" value="$env{'form.slotname'}" /> <input type="hidden" name="command" value="get" /> </form> ? </p> <p> or <form method="POST" action="/adm/slotrequest"> <input type="hidden" name="symb" value="$env{'form.symb'}" /> <input type="submit" name="requestattempt" value="$lt{'request'}" /> </form> </p> or STUFF $r->print('<p><a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></p>'); return; } sub allowed_slot { my ($slot_name,$slot,$symb)=@_; #already started if ($slot->{'starttime'} < time) { # all open slot to be schedulable #return 0; } &Apache::lonxml::debug("$slot_name starttime good"); #already ended if ($slot->{'endtime'} < time) { return 0; } &Apache::lonxml::debug("$slot_name endtime good"); # not allowed to pick this one if (defined($slot->{'type'}) && $slot->{'type'} ne 'schedulable_student') { return 0; } &Apache::lonxml::debug("$slot_name type good"); # not allowed for this resource if (defined($slot->{'symb'}) && $slot->{'symb'} ne $symb) { return 0; } &Apache::lonxml::debug("$slot_name symb good"); return 1; } sub get_description { my ($slot_name,$slot)=@_; my $description=$slot->{'description'}; if (!defined($description)) { $description=&mt('[_1] From [_2] to [_3]',$slot_name, &Apache::lonlocal::locallocaltime($slot->{'starttime'}), &Apache::lonlocal::locallocaltime($slot->{'endtime'})); } return $description; } sub show_choices { my ($r,$symb)=@_; my ($cnum,$cdom)=&get_course(); my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum); my $available; $r->print('<table border="1">'); &Apache::lonxml::debug("Checking Slots"); my ($got_slot)=&check_for_reservation($symb); 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})); $available++; my $description=&get_description($slot,$slots{$slot}); my $form=&mt('Unavailable'); if (&space_available($slot,$slots{$slot},$symb)) { my $text=&mt('Select'); my $command='get'; if ($slot eq $got_slot) { $text=&mt('Free Reservation'); $command='release'; } my $escsymb=&Apache::lonnet::escape($symb); $form=<<STUFF; <form method="POST" action="/adm/slotrequest"> <input type="submit" name="Select" value="$text" /> <input type="hidden" name="symb" value="$escsymb" /> <input type="hidden" name="slotname" value="$slot" /> <input type="hidden" name="command" value="$command" /> </form> STUFF } $r->print(<<STUFF); <tr> <td>$form</td> <td>$description</td> </tr> STUFF } if (!$available) { $r->print('<tr><td>No available times. <a href="/adm/flip?postdata=return:">'. &mt('Return to last resource').'</a></td></tr>'); } $r->print('</table>'); } sub show_table { my ($r,$symb)=@_; my ($cnum,$cdom)=&get_course(); my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum); my $available; $r->print('<table border="1">'); foreach my $slot (sort { return $slots{$a}->{'starttime'} <=> $slots{$b}->{'starttime'} } (keys(%slots))) { if (defined($slots{$slot}->{'type'}) && $slots{$slot}->{'type'} ne 'schedulable_student') { next; } my $description=&get_description($slot,$slots{$slot}); my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum, "^$slot\0"); my $ids; foreach my $entry (sort(keys(%consumed))) { my (undef,$id)=split("\0",$entry); $ids.= $id.'-> '.$consumed{$entry}->{'name'}.'<br />'; } my $start=localtime($slots{$slot}->{'starttime'}); my $end=localtime($slots{$slot}->{'endtime'}); $r->print(<<STUFF); <tr> <td>$slot</td> <td>$description</td> <td>$start</td> <td>$end</td> <td>$slots{$slot}->{'maxspace'}</td> <td>$ids</td> </tr> STUFF } $r->print('</table>'); } sub handler { my $r=shift; &start_page($r); my $symb=&Apache::lonnet::unescape($env{'form.symb'}); my (undef,undef,$res)=&Apache::lonnet::decode_symb($symb); if ($res !~ /\.task$/) { &fail($r,'not_valid'); return OK; } if ($env{'form.command'} eq 'showslots') { &show_table($r,$symb); } elsif ($env{'form.requestattempt'}) { &show_choices($r,$symb); } 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') { &release_slot($r,$symb,$env{'form.releaseslot'},1); &get_slot($r,$symb); } &end_page($r); return OK; } 1; __END__