--- loncom/interface/slotrequest.pm 2010/10/31 15:32:10 1.109
+++ loncom/interface/slotrequest.pm 2025/04/02 23:44:01 1.152
@@ -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.109 2010/10/31 15:32:10 raeburn Exp $
+# $Id: slotrequest.pm,v 1.152 2025/04/02 23:44:01 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)=@_;
@@ -50,25 +50,355 @@ sub fail {
} else {
$r->print('
'.&mt('Failed.').'
');
}
-
+
&return_link($r);
&end_page($r);
}
sub start_page {
- my ($r,$title,$brcrum)=@_;
+ my ($r,$title,$brcrum,$bread_crumbs_component,$js,$mgr)=@_;
my $args;
if (ref($brcrum) eq 'ARRAY') {
$args = {bread_crumbs => $brcrum};
+ if ($bread_crumbs_component) {
+ $args->{bread_crumbs_component} = $bread_crumbs_component;
+ }
+ if ((($env{'form.requestattempt'}) || ($env{'form.context'} eq 'user')) &&
+ ($env{'form.symb'})) {
+ $args->{'bread_crumbs_nomenu'} = 1;
+ }
+ }
+ 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,undef,$args));
+ unless (($env{'form.context'} eq 'usermanage') || (($mgr eq 'F') &&
+ (($env{'form.command'} eq 'release') ||
+ ($env{'form.command'} eq 'remove_registration')))) {
+ if ($env{'form.symb'}) {
+ my $symb=&unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
+ my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
+ if ($resurl =~ /ext\.tool$/) {
+ my $target;
+ my ($marker,$exttool) = (split(m{/},$resurl))[3,4];
+ $marker=~s/\D//g;
+ if (($marker) && ($exttool) && ($env{'request.course.id'})) {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my ($idx,$crstool,$is_tool,%toolhash,%toolsettings);
+ if ($resurl eq "adm/$cdom/$cnum/$marker/$exttool") {
+ my %toolsettings=&Apache::lonnet::dump('exttool_'.$marker,$cdom,$cnum);
+ $target = $toolsettings{'target'};
+ }
+ }
+ if ($target eq 'iframe') {
+ $args->{'only_body'} = 1;
+ }
+ }
+ }
+ }
+ $r->print(&Apache::loncommon::start_page($title,$js,$args));
}
sub end_page {
my ($r)=@_;
- $r->print(&Apache::loncommon::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
@@ -89,7 +419,7 @@ sub get_course {
sub get_reservation_ids {
my ($slot_name)=@_;
-
+
my ($cnum,$cdom)=&get_course();
my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
@@ -121,7 +451,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));
@@ -135,18 +464,22 @@ sub check_for_reservation {
|| &Apache::lonnet::error($course)
|| &Apache::lonnet::error(%slots)) {
return 'error: Unable to determine current status';
- }
+ }
my @got;
- my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots);
+ my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime');
foreach my $slot_name (@sorted_slots) {
next if (!defined($slots{$slot_name}) ||
!ref($slots{$slot_name}));
&Apache::lonxml::debug(time." $slot_name ".
$slots{$slot_name}->{'starttime'}." -- ".
- $slots{$slot_name}->{'startreserve'});
- if ($slots{$slot_name}->{'endtime'} > time &&
- $slots{$slot_name}->{'startreserve'} < time) {
- # between start of reservation times and end of slot
+ $slots{$slot_name}->{'startreserve'}." -- ".
+ $slots{$slot_name}->{'endreserve'});
+ if (($slots{$slot_name}->{'endtime'} > time) &&
+ ($slots{$slot_name}->{'startreserve'} < time) &&
+ ((!$slots{$slot_name}->{'endreserve'}) ||
+ ($slots{$slot_name}->{'endreserve'} > time))) {
+ # between start of reservation time and end of reservation time
+ # and before end of slot
if ($mode eq 'allslots') {
push(@got,$slot_name);
} else {
@@ -167,7 +500,7 @@ sub get_consumed_uniqueperiods {
return 'error: Unable to determine current status';
}
my @problems = $navmap->retrieveResources(undef,
- sub { $_[0]->is_problem() },1,0);
+ sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0);
my %used_slots;
foreach my $problem (@problems) {
my $symb = $problem->symb();
@@ -214,16 +547,19 @@ sub check_for_conflict {
if (!defined($new_slot->{'uniqueperiod'})) { return undef; }
if (!ref($consumed_uniqueperiods)) {
- $consumed_uniqueperiods = &get_consumed_uniqueperiods($slots);
- if (ref($consumed_uniqueperiods) eq 'HASH') {
- if (&Apache::lonnet::error(%$consumed_uniqueperiods)) {
- return 'error: Unable to determine current status';
- }
+ if ($consumed_uniqueperiods =~ /^error: /) {
+ return $consumed_uniqueperiods;
} else {
- return 'error: Unable to determine current status';
+ $consumed_uniqueperiods = &get_consumed_uniqueperiods($slots);
+ if (ref($consumed_uniqueperiods) eq 'HASH') {
+ if (&Apache::lonnet::error(%$consumed_uniqueperiods)) {
+ return 'error: Unable to determine current status';
+ }
+ } else {
+ return 'error: Unable to determine current status';
+ }
}
- }
-
+ }
my ($new_uniq_start,$new_uniq_end) = @{$new_slot->{'uniqueperiod'}};
foreach my $slot_name (keys(%$consumed_uniqueperiods)) {
my ($start,$end)=@{$consumed_uniqueperiods->{$slot_name}};
@@ -252,18 +588,18 @@ sub make_reservation {
return 'error: Unable to determine current status';
}
- my $parm_symb = $symb;
+ my $symb_for_db = $symb;
my $parm_level = 1;
if ($use_slots eq 'map' || $use_slots eq 'map_map') {
my ($map) = &Apache::lonnet::decode_symb($symb);
- $parm_symb = &Apache::lonnet::symbread($map);
+ $symb_for_db = &Apache::lonnet::symbread($map);
$parm_level = 2;
}
foreach my $other_slot (split(/:/, $value)) {
if ($other_slot eq $slot_name) {
my %consumed=&Apache::lonnet::dump('slot_reservations', $cdom,
- $cnum, "^$slot_name\0");
+ $cnum, "^$slot_name\0");
if (&Apache::lonnet::error($value)) {
return 'error: Unable to determine current status';
}
@@ -289,17 +625,17 @@ sub make_reservation {
my $num=(split('\0',$id))[1];
if ($num > $last) { $last=$num; }
}
-
+
my $wanted=$last+1;
&Apache::lonxml::debug("wanted $wanted ");
if (scalar(@ids) >= $max) {
# full up
return undef;
}
-
+
my %reservation=('name' => $env{'user.name'}.':'.$env{'user.domain'},
'timestamp' => time,
- 'symb' => $parm_symb);
+ 'symb' => $symb_for_db);
my $success=&Apache::lonnet::newput('slot_reservations',
{"$slot_name\0$wanted" =>
@@ -311,7 +647,9 @@ sub make_reservation {
if ($value) {
$new_value=$value.':'.$new_value;
}
- &store_slot_parm($symb,$slot_name,$parm_level,$new_value,$cnum,$cdom);
+ my $result = &store_slot_parm($symb,$symb_for_db,$slot_name,$parm_level,
+ $new_value,$cnum,$cdom,$env{'user.name'},
+ $env{'user.domain'},'reserve',$env{'form.context'});
return $wanted;
}
@@ -320,29 +658,27 @@ sub make_reservation {
}
sub store_slot_parm {
- my ($symb,$slot_name,$parm_level,$new_value,$cnum,$cdom) = @_;
- my $result=&Apache::lonparmset::storeparm_by_symb($symb,
- '0_availablestudent',
- $parm_level, $new_value,
- 'string',
- $env{'user.name'},
- $env{'user.domain'});
+ my ($symb_for_parm,$symb_for_db,$slot_name,$parm_level,$new_value,
+ $cnum,$cdom,$uname,$udom,$action,$context,$delflag) = @_;
+
+ # store new parameter string
+ my $result=&Apache::lonparmset::storeparm_by_symb($symb_for_parm,
+ '0_availablestudent',
+ $parm_level,$new_value,
+ 'string',$uname,$udom);
&Apache::lonxml::debug("hrrm $result");
my %storehash = (
- symb => $symb,
+ symb => $symb_for_db,
slot => $slot_name,
- action => 'reserve',
- context => $env{'form.context'},
+ action => $action,
+ context => $context,
);
- &Apache::lonnet::instructor_log('slotreservationslog',\%storehash,
- '',$env{'user.name'},$env{'user.domain'},
- $cnum,$cdom);
- &Apache::lonnet::instructor_log($cdom.'_'.$cnum.'_slotlog',\%storehash,
- 1,$env{'user.name'},$env{'user.domain'},
- $env{'user.name'},$env{'user.domain'});
-
- return;
+ &Apache::lonnet::write_log('course','slotreservationslog',\%storehash,
+ $delflag,$uname,$udom,$cnum,$cdom);
+ &Apache::lonnet::write_log('course',$cdom.'_'.$cnum.'_slotlog',\%storehash,
+ $delflag,$uname,$udom,$uname,$udom);
+ return $result;
}
sub remove_registration {
@@ -375,17 +711,21 @@ sub remove_registration {
sub remove_registration_user {
my ($r) = @_;
-
+
my $slot_name = $env{'form.slotname'};
my $name = &Apache::loncommon::plainname($env{'form.uname'},
$env{'form.udom'});
- my $title = &Apache::lonnet::gettitle($env{'form.symb'});
+ my $symb = &unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
+ my $title = &Apache::lonnet::gettitle($symb);
my $msg = &mt('Remove [_1] from slot [_2] for [_3]',
$name,$slot_name,$title);
-
+
&remove_registration_confirmation($r,$msg,['uname','udom','slotname',
'entry','symb','context']);
}
@@ -421,14 +761,14 @@ END_CONFIRM
sub release_all_slot {
my ($r,$mgr)=@_;
-
+
my $slot_name = $env{'form.slotname'};
my ($cnum,$cdom)=&get_course();
my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
"^$slot_name\0");
-
+
$r->print(''.&mt('Releasing reservations').'
');
foreach my $entry (sort { $consumed{$a}{'name'} cmp
@@ -438,9 +778,9 @@ sub release_all_slot {
&release_reservation($slot_name,$uname,$udom,
$consumed{$entry}{'symb'},$mgr);
if (!$result) {
- $r->print(''.&mt($msg).'
');
+ $r->print(''.&mt($msg).'
');
} else {
- $r->print("$msg
");
+ $r->print($msg);
}
$r->rflush();
}
@@ -463,16 +803,19 @@ sub release_slot {
if ($mgr eq 'F'
&& defined($env{'form.symb'})) {
$symb = &unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
}
my ($result,$msg) =
&release_reservation($slot_name,$uname,$udom,$symb,$mgr);
if (!$result) {
- $r->print(''.&mt($msg).'
');
+ $r->print(''.&mt($msg).'
');
} else {
$r->print("$msg
");
}
-
+
if ($mgr eq 'F') {
$r->print(''.
&mt('Return to slot list').'
');
@@ -486,89 +829,318 @@ sub release_reservation {
my ($slot_name,$uname,$udom,$symb,$mgr) = @_;
my %slot=&Apache::lonnet::get_slot($slot_name);
my $description=&get_description($slot_name,\%slot);
+ my $msg;
if ($mgr ne 'F') {
if ($slot{'starttime'} < time) {
- return (0,&mt('Not allowed to release Reservation: [_1], as it has already ended.',$description));
+ return (0,&mt('Not allowed to release Reservation: [_1], as it has already started.',$description));
}
}
+ my $context = $env{'form.context'};
- # if the reservation symb is for a map get a resource in that map
- # to check slot parameters on
+ # get navmap object
my $navmap=Apache::lonnavmaps::navmap->new;
if (!defined($navmap)) {
return (0,'error: Unable to determine current status');
}
- my $passed_resource = $navmap->getBySymb($symb);
- if ($passed_resource->is_map()) {
- my ($a_resource) =
- $navmap->retrieveResources($passed_resource,
- sub {$_[0]->is_problem()},0,1);
- $symb = $a_resource->symb();
+
+ my ($cnum,$cdom)=&get_course();
+
+ # get slot reservations, check if user has reservation
+ my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
+ "^$slot_name\0");
+
+ #
+ # If release is because of a reservation *change*, symb(s) associated with reservation
+ # being dropped may differ from the current symb.
+ #
+ # We need to get symb(s) from slot_reservations.db, and for each symb, update
+ # the value of the availablestudent parameter, at the appropriate level
+ # (as dictated by the value of the useslots parameter for the symb and user).
+ #
+ # We also delete all entries for the slot being released, for the specific user.
+ #
+
+ my $conflict;
+
+ if (($env{'form.command'} eq 'change') && ($slot_name eq $env{'form.releaseslot'}) &&
+ ($env{'form.slotname'} ne $slot_name)) {
+ my %changedto = &Apache::lonnet::get_slot($env{'form.slotname'});
+
+ # check for conflicts
+ my ($to_uniq_start,$to_uniq_end,$from_uniq_start,$from_uniq_end);
+ if (ref($changedto{'uniqueperiod'}) eq 'ARRAY') {
+ ($to_uniq_start,$to_uniq_end) = @{$changedto{'uniqueperiod'}};
+ }
+ if (ref($slot{'uniqueperiod'}) eq 'ARRAY') {
+ ($from_uniq_start,$from_uniq_end) = @{$slot{'uniqueperiod'}};
+ }
+ my $to_start = $changedto{'starttime'};
+ my $to_end = $changedto{'endtime'};
+ my $from_start = $slot{'starttime'};
+ my $from_end = $slot{'endtime'};
+
+ if (!
+ ($from_start < $to_uniq_start && $from_end < $to_uniq_start) ||
+ ($from_start > $to_uniq_end && $from_end > $to_uniq_end )) {
+ $conflict = 1;
+ }
+ if (!
+ ($to_start < $from_uniq_start && $to_end < $from_uniq_start) ||
+ ($to_start > $from_uniq_end && $to_end > $from_uniq_end )) {
+ $conflict = 1;
+ }
+
+ if ($conflict) {
+ my %symbs_for_slot;
+ my (%to_delete,%failed,%released);
+ foreach my $entry (keys(%consumed)) {
+ if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) {
+ $symbs_for_slot{$consumed{$entry}->{'symb'}} = 1;
+ $to_delete{$entry} = 1;
+ }
+ }
+ if (keys(%to_delete)) {
+ my @removals = keys(%to_delete);
+ if (&Apache::lonnet::del('slot_reservations',\@removals,
+ $cdom,$cnum) eq 'ok') {
+ foreach my $item (keys(%symbs_for_slot)) {
+ my $result = &update_selectable($navmap,$slot_name,$item,$cdom,
+ $cnum,$udom,$uname,$context);
+ if ($result =~ /^error/) {
+ $failed{$item} = 1;
+ } else {
+ $released{$item} = 1;
+ }
+ }
+ }
+ }
+ if (keys(%released)) {
+ $msg = ''.
+ &mt('Released Reservation: [_1]',$description).' '.
+ &mt('The following items had their reservation status change').':';
+ my (%folders,%pages,%container,%titles);
+ foreach my $item (keys(%released)) {
+ my $res = $navmap->getBySymb($item);
+ if (ref($res)) {
+ $titles{$item} = $res->title();
+ if ($res->is_map()) {
+ $folders{$item}{'title'} = $titles{$item};
+ if ($res->is_page()) {
+ $pages{$item}{'title'} = $titles{$item};
+ } else {
+ $folders{$item}{'title'} = $titles{$item};
+ }
+ } else {
+ my $mapsrc = $res->enclosing_map_src();
+ my $map = $navmap->getResourceByUrl($mapsrc);
+ if (ref($map)) {
+ if ($map->id() eq '0.0') {
+ $container{$mapsrc}{'title'} &mt('Top level of course');
+ } else {
+ $container{$mapsrc}{'title'} = $map->title();
+ if ($map->is_page()) {
+ $container{$mapsrc}{'page'} = 1;
+ }
+ }
+ }
+ $container{$mapsrc}{'resources'}{$item} = 1;
+ }
+ }
+ }
+ $msg .= '';
+ if (keys(%folders)) {
+ $msg .= ''.&mt('Folders').': '.
+ join(', ', map { $folders{$_}{'title'} } (sort { $folders{$b}{'title'} cmp $folders{$a}{'title'} } (keys(%folders)))).
+ ' ';
+ }
+ if (keys(%pages)) {
+ $msg .= ''.&mt('Composite Pages').': '.
+ join(', ', map { $pages{$_}{'title'} } (sort { $pages{$b}{'title'} cmp $pages{$a}{'title'} } (keys(%pages)))).
+ ' ';
+ }
+ if (keys(%container)) {
+ $msg .= ''.&mt('Resources').':';
+ foreach my $key (sort { $container{$b}{'title'} cmp $container{$a}{'title'} } (keys(%container))) {
+ if (ref($container{$key}{'resources'}) eq 'HASH') {
+ $msg .= ''.
+ join(', ', map { $titles{$_} } (sort(keys(%{$container{$key}{'resources'}}))));
+ if ($container{$key}{'page'}) {
+ $msg .= ' '.&mt('(in composite page [_1])',$container{$key}{'title'}).' ';
+ } else {
+ $msg .= ' '.&mt('(in folder [_1])',$container{$key}{'title'}).' ';
+ }
+ }
+ }
+ $msg .= ' ';
+ }
+ $msg .= '';
+ my $person = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'});
+ my $subject = &mt('Reservation change: [_1]',$description);
+ my $msgbody = &mt('Reservation released by [_1] for [_2].',$person,$description);
+ $msg .= &slot_change_messaging($slot{'reservationmsg'},$subject,$msgbody,'release');
+ return (1,$msg);
+ } else {
+ if (keys(%to_delete)) {
+ $msg = &mt('Reservation release partially complete for [_1]',$description);
+ } else {
+ $msg = &mt('No entries found for this user to release for [_1].',$description);
+ }
+ return (0,$msg);
+ }
+ } else {
+ $msg = &mt('No conflict found; not releasing: [_1].',$description);
+ return (0,$msg);
+ }
}
- # get parameter string, check for existance, rebuild string with the slot
- my $student = &Apache::lonnet::EXT("resource.0.availablestudent",
- $symb,$udom,$uname);
- my @slots = split(/:/,$student);
+ my $map_symb;
+ my $parm_symb = $symb;
+ my $passed_resource = $navmap->getBySymb($symb);
- my @new_slots;
- foreach my $exist_slot (@slots) {
- if ($exist_slot eq $slot_name) { next; }
- push(@new_slots,$exist_slot);
+ # if the reservation symb is for a map get a resource in that map
+ # to check slot parameters on
+ my $parm_level = 1;
+ if (ref($passed_resource)) {
+ if ($passed_resource->is_map()) {
+ my ($a_resource) =
+ $navmap->retrieveResources($passed_resource,
+ sub {$_[0]->is_problem() || $_[0]->is_tool() },0,1);
+ $parm_symb = $a_resource->symb();
+ }
+ } else {
+ unless ($mgr eq 'F') {
+ return (0,'error: Unable to determine current status');
+ }
}
- my $new_param = join(':',@new_slots);
- my ($cnum,$cdom)=&get_course();
+ # Get value of useslots parameter in effect for this user.
+ # If value is map or map_map, then the parm level is 2 (i.e.,
+ # non-recursive enclosing map/folder level for specific user)
+ # and the symb for this reservation in slot_reservations.db
+ # will be the symb of the map itself.
- # get slot reservations, check if user has one, if so remove reservation
- my %consumed=&Apache::lonnet::dump('slot_reservations',$cdom,$cnum,
- "^$slot_name\0");
+ my $use_slots = &Apache::lonnet::EXT('resource.0.useslots',
+ $parm_symb,$udom,$uname);
+ if (&Apache::lonnet::error($use_slots)) {
+ return (0,'error: Unable to determine current status');
+ }
+ if ($use_slots eq 'map' || $use_slots eq 'map_map') {
+ $parm_level = 2;
+ if ($passed_resource->is_map()) {
+ $map_symb = $passed_resource->symb();
+ } else {
+ my ($map) = &Apache::lonnet::decode_symb($symb);
+ $map_symb = &Apache::lonnet::symbread($map);
+ }
+ }
+
+ #
+ # If release is *not* because of a reservation change, i.e., this is a "drop"
+ # by a student, or a removal for a single student by an instructor then
+ # only remove one entry from slot_reservations.db, where both the user
+ # and the symb match the current context. If useslots was set to map or
+ # map_map, then the symb to match in slot_reservations.db is the symb of
+ # the enclosing map/folder, not the symb of the resource.
+ #
+
+ my ($match,$symb_to_check);
+ if ($parm_level == 2) {
+ $symb_to_check = $map_symb;
+ } else {
+ $symb_to_check = $parm_symb;
+ }
foreach my $entry (keys(%consumed)) {
- if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) {
- &Apache::lonnet::del('slot_reservations',[$entry],
- $cdom,$cnum);
- my %storehash = (
- symb => $symb,
- slot => $slot_name,
- action => 'release',
- context => $env{'form.context'},
- );
- &Apache::lonnet::instructor_log('slotreservationslog',\%storehash,
- 1,$uname,$udom,$cnum,$cdom);
- &Apache::lonnet::instructor_log($cdom.'_'.$cnum.'_slotlog',\%storehash,
- 1,$uname,$udom,$uname,$udom);
- }
+ if ( $consumed{$entry}->{'name'} eq ($uname.':'.$udom) ) {
+ if ($consumed{$entry}->{'symb'} eq $symb_to_check) {
+ if (&Apache::lonnet::del('slot_reservations',[$entry],
+ $cdom,$cnum) eq 'ok') {
+ $match = $symb_to_check;
+ }
+ last;
+ }
+ }
+ }
+ if ($match) {
+ if (&update_selectable($navmap,$slot_name,$symb,$cdom,
+ $cnum,$udom,$uname,$context) =~ /^error/) {
+ if ($mgr eq 'F') {
+ $msg = &mt('Reservation release partially complete for: [_1]',"$uname:$udom").' '.
+ &mt('Update of availablestudent parameter for [_1] was not completed.',"$uname:$udom");
+ } else {
+ $msg = &mt('Release partially complete for: [_1]',$description);
+ }
+ return (0,$msg);
+ } else {
+ if ($mgr eq 'F') {
+ $msg = &mt('Released Reservation for user: [_1]',"$uname:$udom");
+ } else {
+ $msg = ''.
+ &mt('Released reservation: [_1]',$description).'
';
+ my $person = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'});
+ my $subject = &mt('Reservation change: [_1]',$description);
+ my $msgbody = &mt('Reservation released by [_1] for [_2].',$person,$description);
+ $msg .= &slot_change_messaging($slot{'reservationmsg'},$subject,$msgbody,'release');
+ }
+ return (1,$msg);
+ }
+ } else {
+ $msg = &mt('Release failed for: [_1]',$description);
+ return (0,$msg);
}
+}
+
+sub update_selectable {
+ my ($navmap,$slot_name,$symb,$cdom,$cnum,$udom,$uname,$context) = @_;
+ return 'error: ' unless (ref($navmap));
+ my $symb_for_parm = $symb;
+ my $passed_resource = $navmap->getBySymb($symb);
+ return 'error: invalid symb' unless (ref($passed_resource));
+
+ # if the reservation symb is for a map get a resource in that map
+ # to check slot parameters on
+ if ($passed_resource->is_map()) {
+ my ($a_resource) =
+ $navmap->retrieveResources($passed_resource,
+ sub {$_[0]->is_problem() || $_[0]->is_tool() },0,1);
+ $symb_for_parm = $a_resource->symb();
+ }
+ # get parameter string, check for existence, rebuild string with the slot
+ my $student = &Apache::lonnet::EXT('resource.0.availablestudent',
+ $symb_for_parm,$udom,$uname);
+
+ # Get value of useslots parameter in effect for this user.
+ # If value is map or map_map, then the parm level is 2 (i.e.,
+ # non-recursive enclosing map/folder level for specific user)
+ # and the symb for this reservation in slot_reservations.db
+ # will be the symb of the map itself.
- my $use_slots = &Apache::lonnet::EXT("resource.0.useslots",
- $symb,$udom,$uname);
+ my $use_slots = &Apache::lonnet::EXT('resource.0.useslots',
+ $symb_for_parm,$udom,$uname);
&Apache::lonxml::debug("use_slots is $use_slots ");
- if (&Apache::lonnet::error($use_slots)) {
- return (0,'error: Unable to determine current status');
+ if (&Apache::lonnet::error($use_slots)) {
+ return 'error: Unable to determine current status';
}
my $parm_level = 1;
if ($use_slots eq 'map' || $use_slots eq 'map_map') {
- $parm_level = 2;
+ $parm_level = 2;
}
- # store new parameter string
- my $result=&Apache::lonparmset::storeparm_by_symb($symb,
- '0_availablestudent',
- $parm_level, $new_param,
- 'string', $uname, $udom);
- my $msg;
- if ($mgr eq 'F') {
- $msg = &mt('Released Reservation for user: [_1]',"$uname:$udom");
- } else {
- $msg = ''.&mt('Released reservation: [_1]',$description).' ';
- my $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 @slots = split(/:/,$student);
+
+ my @new_slots;
+ foreach my $exist_slot (@slots) {
+ next if ($exist_slot eq $slot_name);
+ push(@new_slots,$exist_slot);
}
- return (1,$msg);
+ my $new_value = join(':',@new_slots);
+
+ my $result = &store_slot_parm($symb_for_parm,$symb,$slot_name,$parm_level,
+ $new_value,$cnum,$cdom,$uname,$udom,'release',
+ $context,1);
+ return $result;
}
sub delete_slot {
@@ -590,7 +1162,7 @@ sub delete_slot {
if ($ret eq 'ok') {
$r->print(''.&mt('Slot [_1] marked as deleted.',''.$slot_name.' ').'
');
} else {
- $r->print(''.&mt('An error occurred when attempting to delete slot: [_1]',''.$slot_name.' ')." ($ret)
");
+ $r->print(''.&mt('An error occurred when attempting to delete slot: [_1]',''.$slot_name.' ')." ($ret)
");
}
} else {
if (%consumed) {
@@ -606,15 +1178,32 @@ sub delete_slot {
sub return_link {
my ($r) = @_;
+ my $target = &return_target();
if (($env{'form.command'} eq 'manageresv') || ($env{'form.context'} eq 'usermanage')) {
- $r->print(''.
- &mt('Return to reservations'));
+ $r->print(''.
+ &mt('Return to reservations').'
');
} else {
- $r->print(''.
+ $r->print(''.
&mt('Return to last resource').'
');
}
}
+sub return_target {
+ my ($target,$ltitarget,$deeplinktarget);
+ if ($env{'request.lti.login'}) {
+ $ltitarget = $env{'request.lti.target'};
+ }
+ if ($env{'request.deeplink.login'}) {
+ $deeplinktarget = $env{'request.deeplink.target'};
+ }
+ if (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) {
+ $target = '_self';
+ } else {
+ $target = '_top';
+ }
+ return $target;
+}
+
sub get_slot {
my ($r,$symb,$conflictable_slot,$inhibit_return_link)=@_;
@@ -622,18 +1211,24 @@ sub get_slot {
my $slot_name=&check_for_conflict($symb,$env{'form.slotname'},\%slot);
if ($slot_name =~ /^error: (.*)/) {
- $r->print(''
+ $r->print(''
.&mt('An error occurred while attempting to make a reservation. ([_1])',$1)
- .'
');
+ .'
');
&return_link($r);
return 0;
}
if ($slot_name && $slot_name ne $conflictable_slot) {
my %slot=&Apache::lonnet::get_slot($slot_name);
my $description1=&get_description($slot_name,\%slot);
+ my $slottype1=$slot{'type'};
%slot=&Apache::lonnet::get_slot($env{'form.slotname'});
my $description2=&get_description($env{'form.slotname'},\%slot);
- if ($slot_name ne $env{'form.slotname'}) {
+ if ($slottype1 eq 'preassigned') {
+ $r->print(''.&mt('You already have a reservation: "[_1]", assigned by your instructor.',
+ $description1).'
'.
+ ''.&mt('Your instructor must unassign it before you can make a new reservation.').
+ '
');
+ } elsif ($slot_name ne $env{'form.slotname'}) {
$r->print(<
@@ -641,16 +1236,19 @@ sub get_slot {
STUFF
- $r->print(''.&mt('Reservation currently unchanged').'
'.
- '');
+ $r->print('
'.&mt('Reservation currently unchanged').'
');
if ($slot_name ne '') {
- $r->print(&mt('To complete the transaction you [_1]must[_2] confirm you want the change to [_3] to be processed.'
- ,'',' ',''.$description2.' ').' '
- .'
'
- .&mt('or').''.&mt('you will continue with the reservation you already had: [_1]'
- ,''.$description1.' ').'
');
+ $r->print(''.&mt('To complete the transaction you [_1]must confirm[_2] you want to [_3]process the change[_4] to [_5].'
+ ,'',' ','',' ',''.$description2.' ')
+ .' '
+ .&mt('Or you can choose to [_1]make no change[_2] and continue[_2] with the reservation you already had: [_3].'
+ ,'',' ',''.$description1.' ')
+ .'
'
+ .' '
+ .(' 'x3)
+ .' '
+ .'
');
}
- &return_link($r);
$r->print(<
STUFF
@@ -668,9 +1266,9 @@ STUFF
if (defined($reserved)) {
my $retvalue = 0;
if ($slot_name =~ /^error: (.*)/) {
- $r->print(''
+ $r->print(''
.&mt('An error occurred while attempting to make a reservation. ([_1])',$1)
- .'
');
+ .'');
} elsif ($reserved > -1) {
$r->print(''.&mt('Successfully signed up: [_1]',$description).'
');
$retvalue = 1;
@@ -689,7 +1287,7 @@ STUFF
}
my %lt = &Apache::lonlocal::texthash(
- 'request' => 'Availibility list',
+ 'request' => 'Availability list',
'try' => 'Try again?',
'or' => 'or',
);
@@ -728,7 +1326,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) {
@@ -753,6 +1351,11 @@ sub allowed_slot {
if ($slot->{'startreserve'} > time) {
return 0;
}
+ # reserve time ended
+ if (($slot->{'endreserve'}) &&
+ ($slot->{'endreserve'} < time)) {
+ return 0;
+ }
&Apache::lonxml::debug("$slot_name reserve good");
my $userallowed=0;
@@ -797,9 +1400,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,
@@ -827,95 +1454,156 @@ sub get_description {
}
sub show_choices {
- my ($r,$symb,$formname)=@_;
-
- my ($cnum,$cdom)=&get_course();
- my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum);
- my $consumed_uniqueperiods = &get_consumed_uniqueperiods(\%slots);
- if (ref($consumed_uniqueperiods) eq 'HASH') {
- if (&Apache::lonnet::error(%$consumed_uniqueperiods)) {
- $r->print(''.
- &mt('An error occurred determining slot availability').
- ' ');
- return;
- }
- } elsif ($consumed_uniqueperiods =~ /^error: /) {
- $r->print(''.
- &mt('An error occurred determining slot availability').
- ' ');
- return;
- }
- my (@available,$output);
+ my ($symb,$formname,$num,$class,$slots,$consumed_uniqueperiods,$available,$got_slots)=@_;
+ my $output;
&Apache::lonxml::debug("Checking Slots");
- my @got_slots=&check_for_reservation($symb,'allslots');
- if ($got_slots[0] =~ /^error: /) {
- $r->print(''.
- &mt('An error occurred determining slot availability').
- ' ');
+ if (!ref($available) eq 'ARRAY') {
return;
}
- foreach my $slot (sort
- { return $slots{$a}->{'starttime'} <=> $slots{$b}->{'starttime'} }
- (keys(%slots))) {
-
- &Apache::lonxml::debug("Checking Slot $slot");
- next if (!&allowed_slot($slot,$slots{$slot},$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 .= ' '.
+ my $target = &return_target();
+ $output .= ' '.
&mt('Return to last resource').' ';
}
- $r->print($output);
- return;
+ if ($class) {
+ return ''.$output.'
';
+ } else {
+ return $output;
+ }
+ } elsif ($env{'form.command'} ne 'manageresv') {
+ my $title = &Apache::lonnet::gettitle($symb);
+ my $headertext = &mt('Manage Reservation(s) for [_1]',$title);
+ $output .= ''.$headertext.' ';
+ }
+ 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 .= ''.
+ ''.&mt('Action').' '.&mt('Name').' ';
} else {
- $output = &Apache::loncommon::start_data_table();
+ $output .= &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ''.&mt('Action').' '.&mt('Name').' '.
+ &Apache::loncommon::end_data_table_header_row();
}
- foreach my $slot (@available) {
- my $description=&get_description($slot,$slots{$slot});
+ my $shownsymb;
+ if ($env{'request.role.adv'}) {
+ $shownsymb = $symb;
+ } elsif (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i) {
+ $shownsymb = &Apache::lonenc::encrypted($symb);
+ } else {
+ $shownsymb = $symb;
+ }
+ $shownsymb = &escape($shownsymb);
+ 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';
}
}
}
- 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 {
@@ -1006,7 +1701,7 @@ sub to_show {
}
return 0;
}
-
+
return 1;
}
@@ -1021,11 +1716,20 @@ sub remove_link {
undef($udom);
}
+ my $shownsymb;
+ if ($env{'request.role.adv'}) {
+ $shownsymb = $symb;
+ } elsif (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i) {
+ $shownsymb = &Apache::lonenc::encrypted($symb);
+ } else {
+ $shownsymb = $symb;
+ }
+
$slotname = &escape($slotname);
$entry = &escape($entry);
$uname = &escape($uname);
$udom = &escape($udom);
- $symb = &escape($symb);
+ $symb = &escape($shownsymb);
return <<"END_LINK";
print(&Apache::loncommon::help_open_topic('Slot About', 'Help on slots'));
-
$r->print('');
$r->print('');
- $r->print(&Apache::loncommon::help_open_topic('Slot AddInterface'));
+ $r->print(&Apache::loncommon::help_open_topic('Slot About'));
$r->print('
');
}
if (!keys(%slots)) {
- if ($crstype eq 'Community') {
- $r->print(''.&mt('No slots have been created in this community.').'
');
- } else {
- $r->print(''.&mt('No slots have been created in this course.').'
');
- }
+ $r->print(
+ ''
+ .&mt('No slots have been created in this '.lc($crstype).'.')
+ .'
'
+ );
return;
}
-
+
my %Saveable_Parameters = ('show' => 'array',
'when' => 'scalar',
'order' => 'scalar',
@@ -1093,23 +1794,26 @@ sub show_table {
'starttime' => 'Start time',
'endtime' => 'End Time',
'startreserve' => 'Time students can start reserving',
+ 'endreserve' => 'Time students can no longer reserve',
'reservationmsg' => 'Message triggered by reservation',
'secret' => 'Secret Word',
'space' => '# of students/max',
'ip' => 'IP or DNS restrictions',
- 'symb' => 'Resource slot is restricted to.',
+ 'symb' => 'Resource(s)/Map(s) slot is restricted to.',
'allowedsections' => 'Sections slot is restricted to.',
'allowedusers' => 'Users slot is restricted to.',
'uniqueperiod' => 'Period of time slot is unique',
'scheduled' => 'Scheduled Students',
- 'proctor' => 'List of proctors');
+ 'proctor' => 'List of proctors',
+ 'iptied' => 'Unique IP each student',);
if ($crstype eq 'Community') {
$show_fields{'startreserve'} = &mt('Time members can start reserving');
+ $show_fields{'endreserve'} = &mt('Time members can no longer reserve');
$show_fields{'scheduled'} = &mt('Scheduled Members');
}
my @show_order=('name','description','type','starttime','endtime',
- 'startreserve','reservationmsg','secret','space','ip','symb',
- 'allowedsections','allowedusers','uniqueperiod',
+ 'startreserve','endreserve','reservationmsg','secret','space',
+ 'ip','iptied','symb','allowedsections','allowedusers','uniqueperiod',
'scheduled','proctor');
my @show =
(exists($env{'form.show'})) ? &Apache::loncommon::get_env_multiple('form.show')
@@ -1156,7 +1860,7 @@ sub show_table {
my $name_filter = {'type' => $name_filter_type,
'value' => $env{'form.name_filter_value'},};
-
+
#deleted slot filtering
#default to hide if no value
$env{'form.deleted'} ||= 'hide';
@@ -1169,58 +1873,55 @@ sub show_table {
');
$r->print('');
$r->print('
- '.&mt('Show').'
- '.&mt('Student Display').'
- '.&mt('Open').'
- '.&mt('Slot Name Filter').'
+ '.&mt('Show').'
+ '.&mt('Student Display').'
+ '.&mt('Open').'
+ '.&mt('Slot Name Filter').'
'.&mt('Options').'
- '.&Apache::loncommon::multiple_select_form('show',\@show,6,\%show_fields,\@show_order).
+ '.&Apache::loncommon::multiple_select_form('show',\@show,6,\%show_fields,\@show_order,'show').
'
'.&Apache::loncommon::multiple_select_form('studisplay',\@stu_display,
6,\%stu_display_fields,
- \@stu_display_order).'
+ \@stu_display_order,'studisplay').'
- '.&Apache::loncommon::select_form($when,'when',\%when_fields).
+ '.&Apache::loncommon::select_form($when,'when',\%when_fields,'','','when').
'
- '.&Apache::loncommon::select_form($name_filter_type,
+ '.&Apache::loncommon::select_form($name_filter_type,
'name_filter_type',
- \%name_filter_type_fields).
- ' '.
+ \%name_filter_type_fields,'','','name_filter_type').
+ ' '.
&Apache::lonhtmlcommon::textbox('name_filter_value',
$env{'form.name_filter_value'},
- 15).
- '
+ 15,'aria-label="'.&mt('Name filter').'"').
+ '
-
-
- Deleted slots:
- '.$show_radio.'Show
-
-
- '.$hide_radio.'Hide
-
-
-
+
+ '.&mt('Deleted slots').'
+ '.$show_radio.&mt('Show').'
+ '.$hide_radio.&mt('Hide').'
+
+
');
$r->print('
');
$r->print('
');
my $linkstart=' '.&mt('Action').'';
foreach my $which (@show_order) {
if ($which ne 'proctor' && exists($show{$which})) {
- $r->print(' '.$linkstart.$which.'">'.$show_fields{$which}.' ');
+ $tableheader .= ''.$linkstart.$which.'">'.$show_fields{$which}.' ';
}
}
- $r->print(&Apache::loncommon::end_data_table_header_row());
+ $tableheader .= &Apache::loncommon::end_data_table_header_row();
+ my $shownheader = 0;
my %name_cache;
my $slotsort = sub {
- if ($env{'form.order'}=~/^(type|description|endtime|startreserve|ip|symb|allowedsections|allowedusers|reservationmsg)$/) {
+ if ($env{'form.order'}=~/^(type|description|endtime|startreserve|endreserve|ip|symb|allowedsections|allowedusers|reservationmsg)$/) {
if (lc($slots{$a}->{$env{'form.order'}})
ne lc($slots{$b}->{$env{'form.order'}})) {
return (lc($slots{$a}->{$env{'form.order'}})
@@ -1235,7 +1936,7 @@ sub show_table {
return lc($a) cmp lc($b);
}
} elsif ($env{'form.order'} eq 'uniqueperiod') {
-
+
if ($slots{$a}->{'uniqueperiod'}[0]
ne $slots{$b}->{'uniqueperiod'}[0]) {
return ($slots{$a}->{'uniqueperiod'}[0]
@@ -1269,7 +1970,7 @@ sub show_table {
}
my $description=&get_description($slot,$slots{$slot});
my ($id_count,$ids);
-
+
if (exists($show{'scheduled'}) || exists($show{'space'}) ) {
my $re_str = "$slot\0";
my @this_slot = grep(/^\Q$re_str\E/,keys(%consumed));
@@ -1302,6 +2003,8 @@ sub show_table {
&Apache::lonlocal::locallocaltime($slots{$slot}->{'endtime'}):'');
my $start_reserve=($slots{$slot}->{'startreserve'}?
&Apache::lonlocal::locallocaltime($slots{$slot}->{'startreserve'}):'');
+ my $end_reserve=($slots{$slot}->{'endreserve'}?
+ &Apache::lonlocal::locallocaltime($slots{$slot}->{'endreserve'}):'');
my $unique;
if (ref($slots{$slot}{'uniqueperiod'})) {
@@ -1309,13 +2012,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;
@@ -1363,30 +2074,39 @@ sub show_table {
delete => 'Delete',
slotlog => 'History',
);
- my $edit=(<<"EDITLINK");
-$lt{'edit'}
+ my ($edit,$delete,$showlog,$remove_all);
+ if ($mgr) {
+ $edit=(<<"EDITLINK");
+$lt{'edit'}
EDITLINK
- my $delete=(<<"DELETELINK");
-$lt{'delete'}
+ $delete=(<<"DELETELINK");
+$lt{'delete'}
DELETELINK
- my $showlog=(<<"LOGLINK");
-$lt{'slotlog'}
-LOGLINK
-
- my $remove_all=&remove_link($slot,'remove all').' ';
+ $remove_all=&remove_link($slot,'remove all').' ';
- if ($ids eq '') {
- undef($remove_all);
- } else {
- undef($delete);
+ if ($ids eq '') {
+ undef($remove_all);
+ } else {
+ undef($delete);
+ }
}
+
+ $showlog=(<<"LOGLINK");
+$lt{'slotlog'}
+LOGLINK
+
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.
@@ -1409,6 +2129,9 @@ LOGLINK
if (exists($show{'startreserve'})) {
$colspan++;$r->print("$start_reserve \n");
}
+ if (exists($show{'endreserve'})) {
+ $colspan++;$r->print("$end_reserve \n");
+ }
if (exists($show{'reservationmsg'})) {
$colspan++;$r->print("$reservemsg \n");
}
@@ -1428,8 +2151,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");
@@ -1452,12 +2185,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.')
@@ -1476,154 +2215,257 @@ 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".
+ ''.
+ ''.&mt('Resource or Folder').' '.
+ ''.&mt('Reservation Status').' '."\n";
my $shownheader = 0;
+ my $currmap;
my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef);
while (my $resource = $it->next()) {
if ($resource == $it->BEGIN_MAP()) {
$depth++;
- $parent{$depth} = $lastcontainer;
- }
- if ($resource == $it->END_MAP()) {
- $depth--;
- $lastcontainer = $parent{$depth};
- }
- if (ref($resource)) {
- my $symb = $resource->symb();
- my $ressymb = $symb;
- $contents{$lastcontainer} ++;
- next if (!$resource->is_problem() && !$resource->is_sequence() &&
- !$resource->is_page());
- $count ++;
- if (($resource->is_sequence()) || ($resource->is_page())) {
- $lastcontainer = $count;
- $container{$lastcontainer} = $resource;
- $container_title{$lastcontainer} = $resource->compTitle();
- }
- if ($resource->is_problem()) {
- my ($useslots) = $resource->slot_control();
- next if (($useslots eq '') || ($useslots =~ /^\s*no\s*$/i));
- my ($msg,$get_choices,$slotdescription);
- my $title = $resource->compTitle();
- my $status = $resource->simpleStatus('0');
- my ($slot_status,$date,$slot_name) = $resource->check_for_slot('0');
- if ($slot_name ne '') {
- my %slot=&Apache::lonnet::get_slot($slot_name);
- $slotdescription=&get_description($slot_name,\%slot);
- }
- if ($slot_status == $resource->NOT_IN_A_SLOT) {
- $msg=&mt('No current reservation.');
- $get_choices = 1;
- } elsif ($slot_status == $resource->NEEDS_CHECKIN) {
- $msg=''.&mt('Reserved:').
- ' '.$slotdescription.' '.
- &mt('Access requires proctor validation.');
- } elsif ($slot_status == $resource->WAITING_FOR_GRADE) {
- $msg=&mt('Submitted and currently in grading queue.');
- } elsif ($slot_status == $resource->CORRECT) {
- $msg=&mt('Problem is unavailable.');
- } elsif ($slot_status == $resource->RESERVED) {
- $msg=''.&mt('Reserved:').
- ' '.$slotdescription.' '.
- &mt('Problem is currently available.');
- } elsif ($slot_status == $resource->RESERVED_LOCATION) {
- $msg=''.&mt('Reserved:').
- ' '.$slotdescription.' '.
- &mt('Problem is available at a different location.');
- $get_choices = 1;
- } elsif ($slot_status == $resource->RESERVED_LATER) {
- $msg=''.&mt('Reserved:').
- ' '.$slotdescription.' '.
- &mt('Problem will be available later.');
- $get_choices = 1;
- } elsif ($slot_status == $resource->RESERVABLE) {
- $msg=&mt('Reservation needed');
- $get_choices = 1;
- } elsif ($slot_status == $resource->NOTRESERVABLE) {
- $msg=&mt('Reservation needed: none available.');
- } elsif ($slot_status == $resource->UNKNOWN) {
- $msg=&mt('Unable to determine status due to network problems.');
- } else {
- if ($status != $resource->OPEN) {
- $msg = &Apache::lonnavmaps::getDescription($resource,'0');
- }
+ $parent{$depth} = $currcontainer;
+ if (ref($container{$currcontainer})) {
+ my $currmapres = $container{$currcontainer};
+ my $currmaptitle = $container_title{$currcontainer};
+ $currmap = $currmapres->src();
+ my $currmaptype = 'sequence';
+ if ($currmapres->is_page()) {
+ $currmaptype = 'page';
}
- $reservable ++;
- my $treelevel = $depth;
- my $higherup = $lastcontainer;
- if ($depth > 1) {
- my @maprows;
- while ($treelevel > 1) {
- if (ref($container{$higherup})) {
- my $res = $container{$higherup};
- last if (defined($shownparent{$higherup}));
- my $maptitle = $res->compTitle();
- my $type = 'sequence';
- if ($res->is_page()) {
- $type = 'page';
- }
- &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();
+ my $src = $resource->src();
+ my ($shownsymb,$shownsrc);
+ $shownsymb = $resource->shown_symb();
+ if ($resource->encrypted()) {
+ $shownsrc = &Apache::lonenc::encrypted($src);
+ } else {
+ $shownsrc = $src;
+ }
+ 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 = ''.
- ' '.
+ ''.$title.' '.(' ' x6).' ';
- my $hasaction;
- if ($status == $resource->OPEN) {
- if ($get_choices) {
- $hasaction = 1;
- }
- }
- 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($result);
- if ($hasaction) {
- my $formname = 'manageres_'.$reservable;
- &show_choices($r,$symb,$formname);
- $r->print('');
+ $r->print(''.
+ ''.$output{$symb}{'msg'}.' '.
+ ' ');
}
- $r->print(' ');
+ $r->print(''."\n");
}
}
}
@@ -1644,19 +2486,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 {
@@ -1668,8 +2559,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') {
@@ -1770,16 +2660,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
}
@@ -1840,8 +2734,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); }
@@ -1979,14 +2872,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 '';
@@ -2240,7 +3170,6 @@ sub csvuploadmap_footer {
my ($request,$i,$keyfields) =@_;
my $buttontext = &mt('Create Slots');
$request->print(<
@@ -2249,7 +3178,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'}) {
@@ -2424,6 +3364,20 @@ sub csv_upload_assign {
next;
}
+ if ($entries{$fields{'endreserve'}}) {
+ my $date = &UnixDate($entries{$fields{'endreserve'}},"%s");
+ if ($date eq '') {
+ push(@errors,"$name -- No reservation end time set for slot -- value provided had invalid format");
+ } else {
+ $slot{'endreserve'} = $date;
+ }
+ }
+ if (defined($slot{'endreserve'})
+ && $slot{'endreserve'} > $slot{'starttime'}) {
+ push(@errors,"$name not created -- Slot's reservation end time is after the slot's start time.");
+ next;
+ }
+
if ($slot{'type'} eq 'schedulable_student') {
if ($entries{$fields{'reservationmsg'}}) {
if (($entries{$fields{'reservationmsg'}} eq 'only_student') ||
@@ -2442,16 +3396,56 @@ 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{'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;
@@ -2462,6 +3456,9 @@ sub csv_upload_assign {
$r->rflush();
$countdone++;
}
+ if ($countdone) {
+ &Apache::lonnet::devalidate_slots_cache($cname,$cdom);
+ }
$r->print(''.&mt('Created [quant,_1,slot]',$countdone)."\n".'
');
foreach my $error (@errors) {
$r->print(''.$error.'
'."\n");
@@ -2496,6 +3493,61 @@ sub slot_reservationmsg_options {
return %options;
}
+sub get_user_breadcrumbs {
+ my ($symb) = @_;
+ my ($mapurl, $rid, $resurl) = &Apache::lonnet::decode_symb($symb);
+ return [] unless (&Apache::lonnet::symbverify($symb,$resurl));
+ my $coursetitle = $env{'course.'.$env{'request.course.id'}.'.description'};
+ my $maptitle = &Apache::lonnet::gettitle($mapurl);
+ my $restitle = &Apache::lonnet::gettitle($symb);
+ my $crstype = &Apache::loncommon::course_type();
+ my ($ltiscope,$ltiuri);
+ my (@crumbs,@mapcrumbs);
+ if (($env{'request.course.id'}) && ($env{'request.lti.login'})) {
+ ($ltiscope,$ltiuri) =
+ &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'},
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+ }
+ if (($resurl ne '/adm/navmaps') && ($mapurl ne '') &&
+ (!(($crstype eq 'Placement') && !$env{'request.role.adv'}))) {
+ unless ($ltiscope eq 'resource') {
+ if (($mapurl ne $env{'course.'.$env{'request.course.id'}.'.url'}) &&
+ !(($ltiscope eq 'map') && (&Apache::lonnet::clutter($resurl) eq $ltiuri))) {
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (ref($navmap)) {
+ @mapcrumbs = $navmap->recursed_crumbs($mapurl,$restitle);
+ }
+ }
+ }
+ }
+ unless ((($crstype eq 'Placement') && (!$env{'request.role.adv'})) ||
+ ($ltiscope eq 'map') || ($ltiscope eq 'resource')) {
+ @crumbs = ({text => $crstype.' Contents',
+ href => "javascript:gopost('/adm/navmaps','')"});
+ }
+ if ($mapurl ne $env{'course.'.$env{'request.course.id'}.'.url'}) {
+ if (@mapcrumbs) {
+ push(@crumbs,@mapcrumbs);
+ } elsif (!(($crstype eq 'Placement') && (!$env{'request.role.adv'})) &&
+ ($ltiscope ne 'map') && ($ltiscope ne 'resource')) {
+ push(@crumbs, {text => '...',
+ no_mt => 1});
+ }
+ }
+ unless ((($crstype eq 'Placement') && (!$env{'request.role.adv'})) || (@mapcrumbs) ||
+ (!$maptitle) || ($maptitle eq 'default.sequence') ||
+ ($mapurl eq $env{'course.'.$env{'request.course.id'}.'.url'}) ||
+ ($ltiscope eq 'resource')) {
+ push(@crumbs, {text => $maptitle, no_mt => 1,
+ href => &Apache::lonnet::clutter($mapurl).'?navmap=1'});
+ }
+ if ($restitle && !@mapcrumbs) {
+ push(@crumbs,{text => $restitle, no_mt => 1});
+ }
+ return \@crumbs;
+}
+
sub handler {
my $r=shift;
@@ -2509,10 +3561,11 @@ sub handler {
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
my %crumb_titles = &slot_command_titles();
- my $brcrum;
+ my ($symb,$brcrum,$bread_crumbs_component);
my $vgr=&Apache::lonnet::allowed('vgr',$env{'request.course.id'});
my $mgr=&Apache::lonnet::allowed('mgr',$env{'request.course.id'});
+ my (%slots,$consumed_uniqueperiods);
if ($env{'form.command'} eq 'showslots') {
if (($vgr ne 'F') && ($mgr ne 'F')) {
$env{'form.command'} = 'manageresv';
@@ -2533,14 +3586,30 @@ 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}];
+ }
+ if ($env{'form.requestattempt'}) {
+ $symb=&unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
+ if ($symb) {
+ $brcrum = &get_user_breadcrumbs($symb);
+ }
+ }
+ my ($cnum,$cdom)=&get_course();
+ %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
+ $consumed_uniqueperiods = &get_consumed_uniqueperiods(\%slots);
} elsif ($vgr eq 'F') {
if ($env{'form.command'} =~ /^(slotlog|showslots|uploadstart|csvuploadmap|csvuploadassign|delete|release|remove_registration)$/) {
$brcrum =[{href=>"/adm/slotrequest?command=showslots",
- text=>$crumb_titles{'showslots'}}];
+ text=>$crumb_titles{'showslots'},
+ help=>'Slot_Use'}];
$title = 'Managing Slots';
+ $bread_crumbs_component = 'Slots';
unless ($env{'form.command'} eq 'showslots') {
if (ref($brcrum) eq 'ARRAY') {
push(@{$brcrum},{href=>"/adm/slotrequest?command=$env{'form.command'}",text=>$crumb_titles{$env{'form.command'}}});
@@ -2550,19 +3619,52 @@ sub handler {
} elsif ($env{'form.command'} eq 'release') {
if ($env{'form.context'} eq 'usermanage') {
$brcrum =[{href=>"/adm/slotrequest?command=manageresv",
- text=>$crumb_titles{'showslots'}}];
+ text=>$crumb_titles{'manageresv'}}];
$title = 'Manage Reservations';
if (ref($brcrum) eq 'ARRAY') {
push(@{$brcrum},{href=>"/adm/slotrequest?command=$env{'form.command'}",text=>$crumb_titles{$env{'form.command'}}});
}
-
+ } elsif ($env{'form.context'} eq 'user') {
+ if ($env{'form.symb'}) {
+ $symb = &unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
+ $brcrum = &get_user_breadcrumbs($symb);
+ } else {
+ $brcrum =[];
+ }
}
+ } elsif (($env{'form.command'} eq 'get') && ($env{'form.context'} eq 'user')) {
+ if ($env{'form.symb'}) {
+ $symb=&unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
+ $brcrum = &get_user_breadcrumbs($symb);
+ } else {
+ $brcrum =[];
+ }
+ } else {
+ $brcrum =[];
+ }
+ my ($js,$available,$allavailable,$got_slots);
+ $available = [];
+ if ($env{'form.requestattempt'}) {
+ @{$got_slots}=&check_for_reservation($symb,'allslots');
}
- &start_page($r,$title,$brcrum);
+ if (($env{'form.requestattempt'}) || ($env{'form.command'} eq 'manageresv')) {
+ $js = &reservation_js(\%slots,$consumed_uniqueperiods,$available,$got_slots,$symb);
+ }
+ &start_page($r,$title,$brcrum,$bread_crumbs_component,$js,$mgr);
+ $r->print(''."\n");
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') {
@@ -2592,10 +3694,13 @@ 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'});
+ $symb = &unescape($env{'form.symb'});
+ if ($symb =~ m{^/enc/}) {
+ $symb = &Apache::lonenc::unencrypted($symb);
+ }
if (!defined($symb)) {
&fail($r,'not_valid');
return OK;
@@ -2614,18 +3719,40 @@ sub handler {
my ($status) = &Apache::lonhomework::check_slot_access('0',$type);
if ($status eq 'CAN_ANSWER' ||
$status eq 'NEEDS_CHECKIN' ||
- $status eq 'WAITING_FOR_GRADE') {
+ $status eq 'WAITING_FOR_GRADE' ||
+ $status eq 'NEED_DIFFERENT_IP') {
&fail($r,'not_allowed');
return OK;
}
if ($env{'form.requestattempt'}) {
- &show_choices($r,$symb);
+ $r->print('
'.
+ &show_choices($symb,undef,0,undef,\%slots,$consumed_uniqueperiods,$available,$got_slots).
+ '
');
} elsif ($env{'form.command'} eq 'release') {
&release_slot($r,$symb);
} elsif ($env{'form.command'} eq 'get') {
&get_slot($r,$symb);
} elsif ($env{'form.command'} eq 'change') {
- if (&get_slot($r,$symb,$env{'form.releaseslot'},1)) {
+ if ($env{'form.nochange'}) {
+ my $slot_name = $env{'form.releaseslot'};
+ my @slots = &check_for_reservation($symb,'allslots');
+ my $msg;
+ if (($slot_name ne '') && (grep(/^\Q$slot_name\E/,@slots))) {
+ my %slot=&Apache::lonnet::get_slot($env{'form.releaseslot'});
+ my $description=&get_description($slot_name,\%slot);
+ $msg = '
'.
+ &mt('Unchanged reservation: [_1]',$description).' ';
+ my $person =
+ &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'});
+ my $subject = &mt('Reservation unchanged: [_1]',$description);
+ my $msgbody = &mt('No change to existing registration by [_1] for [_2].',$person,$description);
+ $msg .= &slot_change_messaging($slot{'reservationmsg'},$subject,$msgbody,'nochange');
+ } else {
+ $msg = '
'.&mt('Reservation no longer reported as available.').' ';
+ }
+ $r->print($msg);
+ &return_link($r);
+ } elsif (&get_slot($r,$symb,$env{'form.releaseslot'},1)) {
&release_slot($r,$symb,$env{'form.releaseslot'});
}
} else {