');
+ }
+ $r->print('');
+ return;
+}
+
+sub manage_reservations {
+ 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.')
+ .' '
+ .&mt('One example is for management of laboratory space, which is only available at certain times, and has a limited number of seats.')
+ .'
'
+ );
+ if (!defined($navmap)) {
+ $r->print('
');
+ if ($crstype eq 'Community') {
+ $r->print(&mt('Unable to retrieve information about community contents'));
+ } else {
+ $r->print(&mt('Unable to retrieve information about course contents'));
+ }
+ $r->print('
');
+ &Apache::lonnet::logthis('Manage Reservations - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
+ return;
+ }
+ 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".
+ '
'.
+ '
'.&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} = $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';
+ }
+ if ($shownmaps{$currmap}) {
+ $mapnum ++;
+ $rownum ++;
+ $shown ++;
+ 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';
+ }
+ $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 .= '
');
+ }
+ if (!$reservable) {
+ $r->print('');
+ if ($crstype eq 'Community') {
+ $r->print(&mt('No community items currently require a reservation to gain access.'));
+ } else {
+ $r->print(&mt('No course items currently require a reservation to gain access.'));
+ }
+ $r->print('');
+ }
+ $r->print('
'.
+ &mt('Only changes made from servers running LON-CAPA [_1] or later are displayed.'
+ ,'2.9.0');
+ if ($version) {
+ $output .= ' '.&mt('This LON-CAPA server is version [_1]',$version);
+ }
+ $output .= '
';
+ return $output;
+}
+
+sub slot_change_messaging {
+ my ($setting,$subject,$msg,$action) = @_;
+ my $user = $env{'user.name'};
+ my $domain = $env{'user.domain'};
+ my ($message_status,$comment_status);
+ if ($setting eq 'only_student'
+ || $setting eq 'student_and_user_notes_screen') {
+ $message_status =
+ &Apache::lonmsg::user_normal_msg($user,$domain,$subject,$msg);
+ $message_status = '
'
+ );
}
sub csvuploadmap_header {
@@ -1400,16 +3067,40 @@ sub csvuploadmap_header {
my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
my $ignore=&mt('Ignore First Line');
- my $help_field = &Apache::loncommon::help_open_topic('Slot SelectingField');
+ my $buttontext = &mt('Reverse Association');
+
+ $r->print(
+ '
'
+ .'
'.&mt('Identify fields in uploaded list').'
'
+ .'
'
+ .&Apache::loncommon::help_open_topic(
+ 'Slot About',&mt('Help on slots'))
+ .' '.&Apache::loncommon::help_open_topic(
+ 'Slot SelectingField',&mt('Help on selecting Fields'))
+ ."
\n"
+ .'
'
+ .&mt('Total number of records found in file: [_1]',''.$distotal.'')
+ ."
\n"
+ );
+ if ($distotal == 0) {
+ $r->print('
'.&mt('None found').'
');
+ }
+ $r->print(
+ '
'
+ .&mt('Enter as many fields as you can.').' '
+ .&mt('The system will inform you and bring you back to this page,[_1]if the data selected is insufficient to create the slots.',' ')
+ .'
'
+ );
+ $r->print(
+ '
'
+ .'
'
+ );
$r->print(<
-
Identify fields $help_field
-Total number of records found in file: $distotal
-Enter as many fields as you can. The system will inform you and bring you back
-to this page if the data selected is insufficient to create the slots.
-
-
@@ -1417,9 +3108,10 @@ to this page if the data selected is ins
-
ENDPICK
return '';
@@ -1430,16 +3122,15 @@ sub csvuploadmap_footer {
my ($request,$i,$keyfields) =@_;
my $buttontext = &mt('Create Slots');
$request->print(<
-
+
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'}) {
@@ -1613,20 +3316,88 @@ 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') ||
+ ($entries{$fields{'reservationmsg'}} eq 'student_and_user_notes_screen')) {
+ $slot{'reservationmsg'}=$entries{$fields{'reservationmsg'}};
+ } else {
+ unless (($entries{$fields{'reservationmsg'}} eq 'none') ||
+ ($entries{$fields{'reservationmsg'}} eq '')) {
+ push(@errors,"$name -- Slot's reservationmsg setting ignored - not one of: 'only_student', 'student_and_user_notes_screen', 'none' or ''");
+ }
+ }
+ }
+ }
+
foreach my $key ('ip','proctor','description','maxspace',
'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;
@@ -1637,6 +3408,9 @@ sub csv_upload_assign {
$r->rflush();
$countdone++;
}
+ if ($countdone) {
+ &Apache::lonnet::devalidate_slots_cache($cname,$cdom);
+ }
$r->print('