--- loncom/interface/slotrequest.pm 2005/05/31 21:13:01 1.2 +++ loncom/interface/slotrequest.pm 2005/08/09 15:38:13 1.7 @@ -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.2 2005/05/31 21:13:01 albertel Exp $ +# $Id: slotrequest.pm,v 1.7 2005/08/09 15:38:13 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -104,16 +104,88 @@ sub space_available { } 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}->{'endtime'} > time && + $slots{$slot_name}->{'startreserve'} < time) { + # between start of reservation times and end 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; + +} + sub make_reservation { my ($slot_name,$slot,$symb)=@_; - my $max=$slot->{'maxspace'}; - if (!defined($max)) { return 1; } + 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]; @@ -121,50 +193,240 @@ sub make_reservation { } my $wanted=$last+1; - if ($wanted >= $max) { + &Apache::lonxml::debug("wanted $wanted<br />"); + if (scalar(@ids) >= $max) { # full up - return -1; + return undef; } my %reservation=('name' => $env{'user.name'}.'@'.$env{'user.domain'}, 'timestamp' => time, 'symb' => $symb); - my ($cnum,$cdom)=&get_course(); my $success=&Apache::lonnet::newput('slot_reservations', {"$slot_name\0$wanted" => \%reservation}, - $cdom,$cnum); + $cdom, $cnum); + if ($success eq 'ok') { + 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 -1; + 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>"); + 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'}" /> + <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 + } else { + $r->print('<p><a href="/adm/flip?postdata=return:">'. + &mt('Return to last resource').'</a></p>'); + } + 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 (defined($reserved)) { + 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'=>"Availibility list", + '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))) { - my $description=$slots{$slot}->{'description'}; - if (!defined($description)) { - $description=&mt('[_1] From [_2] to [_3]',$slot, - &Apache::lonlocal::locallocaltime($slots{$slot}->{'starttime'}), - &Apache::lonlocal::locallocaltime($slots{$slot}->{'endtime'})); - } + + &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})) { + if (($slot eq $got_slot) || + &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> - <input type="submit" name="Select" value="Select" /> - <!-- FIXME needs to send data --> + <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 } @@ -175,6 +437,49 @@ STUFF </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>'); } @@ -188,11 +493,22 @@ sub handler { &fail($r,'not_valid'); return OK; } - - if ($env{'form.requestattempt'}) { + + 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__