--- loncom/interface/slotrequest.pm 2012/08/27 14:33:15 1.116
+++ loncom/interface/slotrequest.pm 2018/01/31 15:28:47 1.137
@@ -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.116 2012/08/27 14:33:15 raeburn Exp $
+# $Id: slotrequest.pm,v 1.137 2018/01/31 15:28:47 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,22 @@ sub fail {
}
sub start_page {
- my ($r,$title,$brcrum)=@_;
+ my ($r,$title,$brcrum,$js)=@_;
my $args;
if (ref($brcrum) eq 'ARRAY') {
$args = {bread_crumbs => $brcrum};
}
- $r->print(&Apache::loncommon::start_page($title,undef,$args));
+ if (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) {
+ my %loaditems = (
+ onload => 'javascript:uncheckSlotRadio();',
+ );
+ if (ref($args) eq 'HASH') {
+ $args->{'add_entries'} = \%loaditems;
+ } else {
+ $args = { 'add_entries' => \%loaditems };
+ }
+ }
+ $r->print(&Apache::loncommon::start_page($title,$js,$args));
}
sub end_page {
@@ -69,6 +79,291 @@ sub end_page {
$r->print(&Apache::loncommon::end_page());
}
+sub reservation_js {
+ my ($slots,$consumed_uniqueperiods,$available,$got_slots,$symb) = @_;
+ return unless ((ref($slots) eq 'HASH') && (ref($available) eq 'ARRAY'));
+ my $toskip;
+ if ($symb eq '') {
+ $toskip = { symb => 1, };
+ }
+ my ($i,$j) = (0,0);
+ my $js;
+ foreach my $slot (sort
+ { return $slots->{$a}->{'starttime'} <=> $slots->{$b}->{'starttime'} }
+ (keys(%{$slots}))) {
+
+ next if (!&allowed_slot($slot,$slots->{$slot},$symb,$slots,
+ $consumed_uniqueperiods,$toskip));
+ $js .= " slotstart[$i]='$slots->{$slot}->{'starttime'}';\n".
+ " slotend[$i]='$slots->{$slot}->{'endtime'}';\n".
+ " slotname[$i]='$slot';\n";
+ if (($symb) && (ref($got_slots) eq 'ARRAY')) {
+ if (grep(/^\Q$slot\E$/,@{$got_slots})) {
+ $js .= " currslot[$j]='$slot';\n";
+ $j++;
+ }
+ }
+ $i++;
+ push(@{$available},$slot);
+ }
+ if ($j) {
+ $js = " var currslot = new Array($j);\n\n$js";
+ }
+ my %alerts = &Apache::lonlocal::texthash (
+ none => 'No reservable time slots found',
+ invalid => 'Invalid date format',
+ );
+ return <<"ENDSCRIPT";
+
+ENDSCRIPT
+
+}
+
+
=pod
slot_reservations db
@@ -121,7 +416,6 @@ sub check_for_reservation {
my ($symb,$mode)=@_;
my $student = &Apache::lonnet::EXT("resource.0.availablestudent", $symb,
$env{'user.domain'}, $env{'user.name'});
-
my $course = &Apache::lonnet::EXT("resource.0.available", $symb,
$env{'user.domain'}, $env{'user.name'});
my @slots = (split(/:/,$student), split(/:/, $course));
@@ -171,7 +465,7 @@ sub get_consumed_uniqueperiods {
return 'error: Unable to determine current status';
}
my @problems = $navmap->retrieveResources(undef,
- sub { $_[0]->is_problem() },1,0);
+ sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0);
my %used_slots;
foreach my $problem (@problems) {
my $symb = $problem->symb();
@@ -218,16 +512,19 @@ sub check_for_conflict {
if (!defined($new_slot->{'uniqueperiod'})) { return undef; }
if (!ref($consumed_uniqueperiods)) {
- $consumed_uniqueperiods = &get_consumed_uniqueperiods($slots);
- if (ref($consumed_uniqueperiods) eq 'HASH') {
- if (&Apache::lonnet::error(%$consumed_uniqueperiods)) {
- return 'error: Unable to determine current status';
- }
+ if ($consumed_uniqueperiods =~ /^error: /) {
+ return $consumed_uniqueperiods;
} else {
- return 'error: Unable to determine current status';
+ $consumed_uniqueperiods = &get_consumed_uniqueperiods($slots);
+ if (ref($consumed_uniqueperiods) eq 'HASH') {
+ if (&Apache::lonnet::error(%$consumed_uniqueperiods)) {
+ return 'error: Unable to determine current status';
+ }
+ } else {
+ return 'error: Unable to determine current status';
+ }
}
- }
-
+ }
my ($new_uniq_start,$new_uniq_end) = @{$new_slot->{'uniqueperiod'}};
foreach my $slot_name (keys(%$consumed_uniqueperiods)) {
my ($start,$end)=@{$consumed_uniqueperiods->{$slot_name}};
@@ -504,14 +801,20 @@ sub release_reservation {
return (0,'error: Unable to determine current status');
}
my $passed_resource = $navmap->getBySymb($symb);
- if ($passed_resource->is_map()) {
- my ($a_resource) =
- $navmap->retrieveResources($passed_resource,
- sub {$_[0]->is_problem()},0,1);
- $symb = $a_resource->symb();
+ if (ref($passed_resource)) {
+ if ($passed_resource->is_map()) {
+ my ($a_resource) =
+ $navmap->retrieveResources($passed_resource,
+ sub {$_[0]->is_problem() || $_[0]->is_tool() },0,1);
+ $symb = $a_resource->symb();
+ }
+ } else {
+ unless ($mgr eq 'F') {
+ return (0,'error: Unable to determine current status');
+ }
}
- # get parameter string, check for existance, rebuild string with the slot
+ # get parameter string, check for existence, rebuild string with the slot
my $student = &Apache::lonnet::EXT("resource.0.availablestudent",
$symb,$udom,$uname);
my @slots = split(/:/,$student);
@@ -696,7 +999,7 @@ STUFF
}
my %lt = &Apache::lonlocal::texthash(
- 'request' => 'Availibility list',
+ 'request' => 'Availability list',
'try' => 'Try again?',
'or' => 'or',
);
@@ -735,7 +1038,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) {
@@ -809,9 +1112,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,
@@ -839,77 +1166,119 @@ sub get_description {
}
sub show_choices {
- my ($r,$symb,$formname)=@_;
-
- my ($cnum,$cdom)=&get_course();
- my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
- 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},$symb,\%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 .= '
'.
&mt('Return to last resource').' ';
}
- $output .= '
';
- $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 $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 .=
+ '';
}
if ($env{'form.command'} eq 'manageresv') {
- $output = '
';
+ $output .= '';
} else {
- $output = &Apache::loncommon::start_data_table();
+ $output .= &Apache::loncommon::start_data_table();
}
- foreach my $slot (@available) {
- my $description=&get_description($slot,$slots{$slot});
+ foreach my $slot (@{$available}) {
+ my $description=&get_description($slot,$slots->{$slot});
my $form;
- if ((grep(/^\Q$slot\E$/,@got_slots)) ||
- &space_available($slot,$slots{$slot},$symb)) {
+ if ((grep(/^\Q$slot\E$/,@{$got_slots})) ||
+ &space_available($slot,$slots->{$slot},$symb)) {
my $text=&mt('Select');
my $command='get';
- if (grep(/^\Q$slot\E$/,@got_slots)) {
+ if (grep(/^\Q$slot\E$/,@{$got_slots})) {
$text=&mt('Drop Reservation');
$command='release';
} else {
- my $conflict = &check_for_conflict($symb,$slot,$slots{$slot},
- \%slots,
- $consumed_uniqueperiods);
+ my $conflict = &check_for_conflict($symb,$slot,$slots->{$slot},
+ $slots,$consumed_uniqueperiods);
if ($conflict) {
if ($conflict =~ /^error: /) {
$form = ''.
- &mt('Slot: [_1] has unknown status.',$description).
- ' ';
+ &mt('Slot: [_1] has unknown status.',$description).
+ '';
} else {
$text=&mt('Change Reservation');
$command='get';
@@ -918,15 +1287,16 @@ sub show_choices {
}
my $escsymb=&escape($symb);
if (!$form) {
+ my $name;
if ($formname) {
- $formname = 'name="'.$formname.'" ';
+ $name = 'name="'.$formname.'"';
}
my $context = 'user';
if ($env{'form.command'} eq 'manageresv') {
$context = 'usermanage';
}
$form=<
+
';
} else {
- $output .= &Apache::loncommon::end_data_table();
+ $output .= &Apache::loncommon::end_data_table();
+ }
+ if (@{$available} > 1) {
+ $output .= '';
+ }
+ if ($class) {
+ return ''.$output.'
';
+ } else {
+ return $output;
}
- $r->print($output);
}
sub to_show {
@@ -1059,7 +1436,8 @@ sub show_table {
my $available;
if ($mgr eq 'F') {
# FIXME: This line should be deleted once Slots uses breadcrumbs
- $r->print(&Apache::loncommon::help_open_topic('Slot About', 'Help on slots'));
+ $r->print(' '.&Apache::loncommon::help_open_topic(
+ 'Slot About', &mt('Help on slots')));
$r->print('');
$r->print('
');
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 {
@@ -1326,13 +1706,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;
@@ -1380,30 +1768,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.
@@ -1448,8 +1845,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");
@@ -1472,12 +1879,18 @@ $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,$crstype) = @_;
+ 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.')
@@ -1496,156 +1909,246 @@ sub manage_reservations {
&Apache::lonnet::logthis('Manage Reservations - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
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");
+ if (ref($consumed_uniqueperiods) eq 'HASH') {
+ if (&Apache::lonnet::error(%$consumed_uniqueperiods)) {
+ $r->print(''.
+ &mt('An error occurred determining slot availability.').
+ ' ');
+ return;
+ }
+ } elsif ($consumed_uniqueperiods =~ /^error: /) {
+ $r->print(''.
+ &mt('An error occurred determining slot availability.').
+ ' ');
+ return;
+ }
+ my (%output,%slotinfo,%statusbymap,%repsymbs,%shownmaps);
+ my @possibles = $navmap->retrieveResources(undef,
+ sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0);
+
+ foreach my $resource (@possibles) {
+ my ($useslots) = $resource->slot_control();
+ next if (($useslots eq '') || ($useslots =~ /^\s*no\s*$/i));
+ my $symb = $resource->symb();
+ my ($slot_status,$date,$slot_name) = $resource->check_for_slot('0');
+ my ($msg,$get_choices,$slotdescription);
+ my $status = $resource->simpleStatus('0');
+ my ($msg,$get_choices,$slotdescription);
+ if ($slot_name ne '') {
+ my %slot=&Apache::lonnet::get_slot($slot_name);
+ $slotdescription=&get_description($slot_name,\%slot);
+ }
+ if ($slot_status == $resource->NOT_IN_A_SLOT) {
+ $msg=&mt('No current reservation.');
+ $get_choices = 1;
+ } elsif ($slot_status == $resource->NEEDS_CHECKIN) {
+ $msg=''.&mt('Reserved:').
+ ' '.$slotdescription.' '.
+ &mt('Access requires proctor validation.');
+ } elsif ($slot_status == $resource->WAITING_FOR_GRADE) {
+ $msg=&mt('Submitted and currently in grading queue.');
+ } elsif ($slot_status == $resource->CORRECT) {
+ $msg=&mt('Problem is unavailable.');
+ } elsif ($slot_status == $resource->RESERVED) {
+ $msg=''.&mt('Reserved:').
+ ' '.$slotdescription.' '.
+ &mt('Problem is currently available.');
+ } elsif ($slot_status == $resource->RESERVED_LOCATION) {
+ $msg=''.&mt('Reserved:').
+ ' '.$slotdescription.' '.
+ &mt('Problem is available at a different location.');
+ $get_choices = 1;
+ } elsif ($slot_status == $resource->RESERVED_LATER) {
+ $msg=''.&mt('Reserved:').
+ ' '.$slotdescription.' '.
+ &mt('Problem will be available later.');
+ $get_choices = 1;
+ } elsif ($slot_status == $resource->RESERVABLE) {
+ $msg=&mt('Reservation needed');
+ $get_choices = 1;
+ } elsif ($slot_status == $resource->RESERVABLE_LATER) {
+ $msg=&mt('Reservation needed: will be reservable later.');
+ } elsif ($slot_status == $resource->NOTRESERVABLE) {
+ $msg=&mt('Reservation needed: none available.');
+ } elsif ($slot_status == $resource->UNKNOWN) {
+ $msg=&mt('Unable to determine status due to network problems.');
+ } else {
+ if ($status != $resource->OPEN) {
+ $msg = &Apache::lonnavmaps::getDescription($resource,'0');
+ }
+ }
+ $output{$symb}{'msg'} = $msg;
+ if (($status == $resource->OPEN) && ($get_choices)) {
+ $output{$symb}{'hasaction'} = 1;
+ }
+ my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
+ $mapurl = &Apache::lonnet::clutter($mapurl);
+ unless ($mapurl =~ /default\.sequence$/) {
+ $shownmaps{$mapurl} = 1;
+ my $map = $navmap->getResourceByUrl($mapurl);
+ if (ref($map)) {
+ my @pcs = split(/,/,$map->map_hierarchy());
+ shift(@pcs);
+ shift(@pcs);
+ if (@pcs) {
+ map { $shownmaps{$navmap->getByMapPc($_)->src()} = 1; } reverse(@pcs);
+ }
+ }
+ }
+ if (($useslots eq 'map_map') || ($useslots eq 'map')) {
+ if ($slot_status ne '') {
+ if (ref($statusbymap{$mapurl}{$slot_status}) eq 'ARRAY') {
+ push(@{$statusbymap{$mapurl}{$slot_status}},$symb);
+ } else {
+ $statusbymap{$mapurl}{$slot_status} = [$symb];
+ }
+ }
+ }
+ }
+
+ foreach my $mapurl (keys(%statusbymap)) {
+ if (ref($statusbymap{$mapurl}) eq 'HASH') {
+ if (keys(%{$statusbymap{$mapurl}}) == 1) {
+ my @values = values(%{$statusbymap{$mapurl}});
+ my $repsymb = $values[0][0];
+ if (ref($output{$repsymb}) eq 'HASH') {
+ $output{$mapurl}{'msg'} = $output{$repsymb}{'msg'};
+ $output{$mapurl}{'hasaction'} = $output{$repsymb}{'hasaction'};
+ }
+ $repsymbs{$mapurl} = $repsymb;
+ }
+ }
+ }
+
+ my (%parent,%container,%container_title);
+ my ($depth,$count,$reservable,$currcontainer,$rownum,$mapnum,$shown) = (0,0,0,0,0,0,0);
+ my @backgrounds = ("LC_even_row","LC_odd_row");
my $numcolors = scalar(@backgrounds);
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons/whitespace_21.gif");
my $slotheader = '
'.
&mt('Your reservation status for any such assignments is listed below:').
'
'.
- ''."\n";
+ ''."\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->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');
- }
+ $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';
- }
- &show_map_row($treelevel,$location,$type,$maptitle,
- \@maprows);
- $shownparent{$higherup} = 1;
- }
- $treelevel --;
- $higherup = $parent{$treelevel};
+ if ($shownmaps{$currmap}) {
+ $mapnum ++;
+ $rownum ++;
+ $shown ++;
+ if (!$shownheader) {
+ $r->print($slotheader);
+ $shownheader = 1;
}
- foreach my $item (@maprows) {
- $rownum ++;
- my $bgcolor = $backgrounds[$rownum % $numcolors];
- 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';
}
- $r->print(' '.$item.' '."\n");
+ $row .= ''.$spacers.' '.
+ $icon.(' ' x6).' '."\n";
+ if (ref($output{$currmap}) eq 'HASH') {
+ my $formnum = $mapnum.'_'.$reservable+1;
+ my $class = 'LC_slotmaptext_'.$mapnum;
+ if ($output{$currmap}{'hasaction'}) {
+ $row .= ''.
+ $output{$currmap}{'msg'}.
+ ' '.
+ &slot_chooser($repsymbs{$currmap},$class,$formnum,
+ $allavailable,$slots,$consumed_uniqueperiods).
+ ' ';
+ } else {
+ $row .= ''.
+ $output{$currmap}{'msg'}.
+ ' ';
+ }
+ $row .= ''."\n";
+ } else {
+ $row .= ' '."\n";
+ }
+ } else {
+ my ($spacers,$icon) = &show_map_row($depth,$location,$currmaptype,$currmaptitle);
+ $row .= ''.$spacers.$icon.(' ' x6).' '."\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];
if (!$shownheader) {
$r->print($slotheader);
$shownheader = 1;
}
- $r->print(''."\n");
+ 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.'">'.
+ ''.$title.' '.(' ' x6).' ';
- my $hasaction;
- if ($status == $resource->OPEN) {
- if ($get_choices) {
- $hasaction = 1;
- }
+ $r->print('problem.gif" alt="'.&mt('Problem'));
}
- if ($hasaction) {
- $result .= ''.$msg.' '.
- ''.(' ' x6);
+ $r->print('" />'.$title.' '.(' ' x6).' ');
+ my $class = 'LC_slottext_'.$mapnum;
+ if ($output{$symb}{'hasaction'}) {
+ $r->print(''.$output{$symb}{'msg'}.' '.
+ ''.
+ &slot_chooser($symb,$class,$reservable,$allavailable,$slots,
+ $consumed_uniqueperiods).' ');
} else {
- $result .= ''.$msg.' ';
+ $r->print(''.
+ ''.$output{$symb}{'msg'}.' '.
+ ' ');
}
- $r->print($result);
- if ($hasaction) {
- my $formname = 'manageres_'.$reservable;
- &show_choices($r,$symb,$formname);
- $r->print('');
- }
- $r->print(' ');
+ $r->print(''."\n");
}
}
}
@@ -1666,19 +2169,68 @@ sub manage_reservations {
}
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 {
@@ -1690,8 +2242,7 @@ 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') {
@@ -1792,16 +2343,19 @@ sub show_reservations {
if ($showntablehdr) {
$r->print(&Apache::loncommon::end_data_table().' ');
if (($curr{'page'} > 1) || ($more_records)) {
- $r->print('');
+ $r->print('');
$r->print(<<"ENDSCRIPT");
ENDSCRIPT
}
@@ -1862,8 +2417,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); }
@@ -2001,14 +2555,16 @@ sub show_reservations_log {
if ($showntablehdr) {
$r->print(&Apache::loncommon::end_data_table().' ');
if (($curr{'page'} > 1) || ($more_records)) {
- $r->print('');
+ $r->print('');
$r->print(<<"ENDSCRIPT");
ENDPICK
return '';
@@ -2264,7 +2846,6 @@ sub csvuploadmap_footer {
my ($request,$i,$keyfields) =@_;
my $buttontext = &mt('Create Slots');
$request->print(<
@@ -2273,7 +2854,7 @@ 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'}) {
@@ -2450,8 +3041,12 @@ sub csv_upload_assign {
}
if ($entries{$fields{'endreserve'}}) {
- $slot{'endreserve'}=
- &UnixDate($entries{$fields{'endreserve'}},"%s");
+ 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'}) {
@@ -2479,14 +3074,51 @@ sub csv_upload_assign {
$slot{$key}=$entries{$fields{$key}};
}
}
-
+ if ($entries{$fields{'iptied'}} =~ /^\s*(yes|1)\s*$/i) {
+ $slot{'iptied'}='yes';
+ } elsif ($entries{$fields{'iptied'}} =~ /^\s*answer\s*$/i) {
+ $slot{'iptied'}='answer';
+ }
+ if ($entries{$fields{'allowedusers'}}) {
+ $entries{$fields{'allowedusers'}} =~ s/^\s+//;
+ $entries{$fields{'allowedusers'}} =~ s/\s+$//;
+ my @allowedusers;
+ foreach my $poss (split(/\s*,\s*/,$entries{$fields{'allowedusers'}})) {
+ my ($possuname,$possudom) = split(/:/,$poss);
+ if (($possuname =~ /^$match_username$/) && ($possudom =~ /^$match_domain$/)) {
+ unless (grep(/^\Q$poss\E$/,@allowedusers)) {
+ push(@allowedusers,$poss);
+ }
+ }
+ }
+ if (@allowedusers > 0) {
+ $slot{'allowedusers'} = join(',',@allowedusers);
+ }
+ }
+ if ($entries{$fields{'allowedsections'}}) {
+ $entries{$fields{'allowedsections'}} =~ s/^\s+//;
+ $entries{$fields{'allowedsections'}} =~ s/\s+$//;
+ my @allowedsections;
+ foreach my $poss (split(/\s*,\s*/,$entries{$fields{'allowedsections'}})) {
+ if (($poss !~ /\W/) && ($poss ne 'none')) {
+ unless (grep(/^\Q$poss\E$/,@allowedsections)) {
+ push(@allowedsections,$poss);
+ }
+ }
+ }
+ if (@allowedsections > 0) {
+ $slot{'allowedsections'} = join(',',@allowedsections);
+ }
+ }
if ($entries{$fields{'uniqueperiod'}}) {
- my ($start,$end)=split(',',$entries{$fields{'uniqueperiod'}});
- my @times=(&UnixDate($start,"%s"),
- &UnixDate($end,"%s"));
- $slot{'uniqueperiod'}=\@times;
+ my ($start,$end)= map { &UnixDate($_,"%s"); } split(',',$entries{$fields{'uniqueperiod'}});
+ if (($start ne '') && ($end ne '')) {
+ $slot{'uniqueperiod'}=[$start,$end];
+ } else {
+ push(@errors,"$name -- Slot's unique period ignored -- one or both of the comma separated values for start and end had an invalid format");
+ }
}
- if (defined($slot{'uniqueperiod'})
+ if (ref($slot{'uniqueperiod'}) eq 'ARRAY'
&& $slot{'uniqueperiod'}[0] > $slot{'uniqueperiod'}[1]) {
push(@errors,"$name not created -- Slot's unique period start time is later than the unique period's end time.");
next;
@@ -2551,6 +3183,7 @@ sub handler {
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';
@@ -2571,9 +3204,14 @@ 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",
@@ -2597,11 +3235,23 @@ sub handler {
} else {
$brcrum =[];
}
- &start_page($r,$title,$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');
+ }
+ if (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) {
+ $js = &reservation_js(\%slots,$consumed_uniqueperiods,$available,$got_slots,$symb);
+ }
+ &start_page($r,$title,$brcrum,$js);
if ($env{'form.command'} eq 'manageresv') {
+ $allavailable = $available;
+ undef($available);
+ undef($got_slots);
my $crstype = &Apache::loncommon::course_type();
- &manage_reservations($r,$crstype);
+ &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') {
@@ -2631,7 +3281,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'});
@@ -2653,12 +3303,15 @@ 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') {