--- rat/lonpage.pm	2015/07/17 19:48:51	1.112
+++ rat/lonpage.pm	2020/01/18 01:09:11	1.129
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Page Handler
 #
-# $Id: lonpage.pm,v 1.112 2015/07/17 19:48:51 raeburn Exp $
+# $Id: lonpage.pm,v 1.129 2020/01/18 01:09:11 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -42,6 +42,7 @@ use Apache::lonlocal;
 use Apache::lonmenu;
 use Apache::lonhomework;
 use Apache::lonparmset;
+use Apache::lonenc();
 use HTML::TokeParser;
 use GDBM_File;
 use Apache::lonsequence;
@@ -184,6 +185,8 @@ sub handler {
   if (($env{'request.course.fn'}) && (!$env{'form.forceselect'})) {
       my $fn=$env{'request.course.fn'};
       if (-e "$fn.db") {
+          my %buttonshide;
+          my $hostname = $r->hostname();
           if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640)) {
 # ------------------------------------------------------------------- Hash tied
               my $firstres=$hash{'map_start_'.$requrl};
@@ -192,9 +195,12 @@ sub handler {
 # ------------------------------------------------------------- Countdown Timer
                   my $now = time;
                   my ($pagefirstaccess,%hastimeleft,%countdowndisp,%donebutton,
-                      $donetime,$symbtosetdone);
+                      %donebtnextra,%buttonbytime,$donetime,$symbtosetdone);
                   my ($pagesymb,$courseid,$domain,$name)=&Apache::lonnet::whichuser();
-                  if (($pagesymb && ($courseid ne '') && ($domain ne '') && ($name ne '')) {
+                  unless ($pagesymb) {
+                      $pagesymb=&Apache::lonnet::symbread($requrl);
+                  }
+                  if ($pagesymb && ($courseid ne '') && ($domain ne '') && ($name ne '')) {
                       my %times=&Apache::lonnet::get('firstaccesstimes',
                                                      [$courseid."\0".$pagesymb],
                                                      $domain,$name);
@@ -233,9 +239,12 @@ sub handler {
                                 if ($src =~ /$LONCAPA::assess_re/) {
                                     my @interval=&Apache::lonnet::EXT("resource.0.interval",$symb);
                                     if (@interval > 1) {
-                                        if ($interval[1] eq 'map') {
-                                            if ($pagefirstaccess + $interval[0] > $now) {
-                                                $symbtosetdone = $symb;
+                                        if (($interval[1] eq 'map') && ($pagefirstaccess)) {
+                                            my ($timelimit) = ($interval[0] =~ /^(\d+)/);
+                                            if ($timelimit) {
+                                                if ($pagefirstaccess + $timelimit > $now) {
+                                                    $symbtosetdone = $symb;
+                                                }
                                             }
                                         }
                                     }
@@ -294,11 +303,17 @@ sub handler {
                       $lcm*=($#colcont+1)/euclid($lcm,($#colcont+1));
                       foreach (@colcont) {
                           my $src=$hash{'src_'.$_};
+                          my $plainsrc = $src;
                           my ($extension)=($src=~/\.(\w+)$/);
 			  $cellexternal{$_}=($hash{'ext_'.$_} eq 'true:');
 			  if ($hash{'encrypted_'.$_}) {
 			      $src=&Apache::lonenc::encrypted($src);
 			  }
+                          my ($mapid,$resid)=split(/\./,$_);
+                          my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$src);
+                          unless ($env{'request.role.adv'}) {
+                              $buttonshide{$symb} = &Apache::lonnet::EXT("resource.0.buttonshide",$symb);
+                          }
                           $cellemb{$_}=
 			      &Apache::loncommon::fileembstyle($extension);
                           if ($cellexternal{$_}) {
@@ -309,11 +324,8 @@ ENDEXT
                               }
                           } elsif ($cellemb{$_} eq 'ssi') {
 # --------------------------------------------------------- This is an SSI cell
-			      my ($mapid,$resid)=split(/\./,$_);
-			      my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$src);
-			      
-			      my $prefix=$_.'_';
-                              my $idprefix= join('_',($mapid,$resid,''));
+			      my $prefix='p_'.$_.'_';
+                              my $idprefix= 'p_'.join('_',($mapid,$resid,''));
                               my %posthash=('request.prefix' => $prefix,
 					    'LONCAPA_INTERNAL_no_discussion' => 'true',
 					    'symb' => $symb);
@@ -326,31 +338,36 @@ ENDEXT
 				  $posthash{'rndseed'}=$env{'form.rndseed'};
                                   $posthash{'answer_output_mode'} = $env{'form.answer_output_mode'};
 			      }
-			      my $submitted=exists($env{'form.all_submit'});
+			      my $submitted=$env{'form.all_submit_pressed'};
 			      if (!$submitted) {
 				  foreach my $key (keys(%env)) {
-				      if ($key=~/^form.\Q$prefix\Esubmit_/) {
-					  $submitted=1;last;
+				      if ($key=~/^\Qform.$prefix\Esubmit_(.+)_pressed$/) {
+                                          if ($env{$key}) {
+                                              $submitted=1;
+                                              last;
+                                          }
 				      }
-				  }
+                                  }
 			      }
                               if ($submitted) {
 				  foreach my $key (keys(%env)) {
-				      if ($key=~/^form.\Q$prefix\E/) {
+				      if ($key=~/^\Qform.$prefix\E/) {
 					  my $name=$key;
-					  $name=~s/^form.\Q$prefix\E//;
+					  $name=~s/^\Qform.$prefix\E//;
 					  $posthash{$name}=$env{$key};
-				      }
+                                      }
 				  }
-				  if (exists($env{'form.all_submit'})) {
+				  if ($env{'form.all_submit_pressed'}) {
 				      $posthash{'all_submit'}='yes';
 				  }
-			      }
+			      } elsif ($env{'form.'.$prefix.'markaccess'} eq 'yes') {
+		                  $posthash{'markaccess'} = $env{'form.'.$prefix.'markaccess'};
+		              }
                               my $output=Apache::lonnet::ssi($src,%posthash);
 			      $output=~s|//(\s*<!--)? BEGIN LON-CAPA Internal.+?// END LON-CAPA Internal\s*(-->)?\s||gs;
                               if (($target eq 'tex') || ($target eq 'tex_answer')) {
-				  $output =~ s/^([^&]+)\\begin{document}//;
-				  $output =~ s/\\end{document}//;
+				  $output =~ s/^([^&]+)\\begin\{document}//;
+				  $output =~ s/\\end\{document}//;
 #				  $output = '\parbox{\minipagewidth}{ '.$output.' }';
                                   #some additional cleanup necessary for LateX (due to limitations of table environment 
 				  $output =~ s/(\\vskip\s*\d+mm)\s*(\\\\)+/$1/g;
@@ -432,6 +449,8 @@ ENDEXT
 				      s/\<((?:input|select|button|textarea)[^\>]+)name\s*\=\s*[\'\"]*([^\'\"]+)[\'\"]*([^\>]*)\>/\<$1 name="$prefix$2" $3\>/gsi;
                                   $output=~
                                       s/\<((?:input|select|button|textarea)[^\>]+)id\s*\=\s*[\'\"]*([^\'\"]+)[\'\"]*([^\>]*)\>/\<$1 id="$idprefix$2" $3\>/gsi;
+                                  $output=~
+                                      s/(\Qthis.form.elements['\E)(HW(?:VAL|CHK)_[^']+\'\]\.(?:value=\'|checked))/$1$prefix$2/gsi;
                                   if ($hastimer) {
                                       $output=~
                                           s/\<(input[^\>]+name=\Q"$prefix\Eaccessbutton"[^\>]+)(?:\Qdocument.markaccess.submit();\E)([^\>]*)\>/\<$1pageTimer(this.form,'$prefix')$2\>/gsi;
@@ -451,8 +470,6 @@ ENDEXT
                                   $output=~
                                       s/(\Q<td class="LC_status_\E)(\Qsubmit_\E)([^\"]*)(\s*[^\"]*"\>)/$1$idprefix$2$3$4/g;
                                   if ($nuploads) {
-                                      $output=~
-                                          s/\<(input[^\>]+name=\"\Q$prefix\EHWFILE[^\>]+)\s*id\s*\=\s*[\'\"]*([^\'\"]+)[\'\"]*([^\)]*)\>/\<$1 id="$prefix$2" $3\>/gsi;
                                        ($turninpaths{$prefix},$multiresps{$prefix}) = 
                                            &Apache::loncommon::get_turnedin_filepath($symb,$env{'user.name'},$env{'user.domain'});
                                        if ($turninparent eq '') {
@@ -465,11 +482,11 @@ ENDEXT
                                   $output=~
                                       s/\<(input[^\>]+\Qonfocus=\"javascript:disableAutoComplete\E)\(\'([^\']+)\'\)(;\")/\<$1('$idprefix$2')$3/gsi;
                                   unless ($hastimer) {
-                                      if ($src =~ /$LONCAPA::assess_re/) {
+                                      if ($plainsrc =~ /$LONCAPA::assess_re/) {
                                           %Apache::lonhomework::history =
                                               &Apache::lonnet::restore($symb,$courseid,$domain,$name);
                                           my $type = 'problem';
-                                          if ($src =~ /\.task$/) {
+                                          if ($extension eq 'task') {
                                               $type = 'Task';
                                           }
                                           my ($status,$accessmsg,$slot_name,$slot) =
@@ -477,7 +494,8 @@ ENDEXT
                                           undef(%Apache::lonhomework::history);
                                           my $probstatus = &Apache::lonnet::EXT("resource.0.problemstatus",$symb);
                                           if (($status eq 'CAN_ANSWER') || (($status eq 'CANNOT_ANSWER') && 
-                                              (($probstatus eq 'no') || ($probstatus eq 'no_feedback_ever')))) {
+                                              (($probstatus eq 'no') || ($probstatus eq 'no_feedback_ever'))) ||
+                                              (($status eq 'NOT_YET_VIEWED') && ($posthash{'markaccess'} eq 'yes'))) {
                                               my ($slothastime,$timerhastime);
                                               if ($slot_name ne '') {
                                                   if (ref($slot) eq 'HASH') {
@@ -490,11 +508,26 @@ ENDEXT
                                               my $duedate = &Apache::lonnet::EXT("resource.0.duedate",$symb);
                                               my @interval=&Apache::lonnet::EXT("resource.0.interval",$symb);
                                               if (@interval > 1) {
-                                                  my $first_access=&Apache::lonnet::get_first_access($interval[1],$symb);
+                                                  my $first_access;
+                                                  if ($interval[1] eq 'map') {
+                                                      my $ignorecache;
+                                                      if ($env{'form.'.$prefix.'markaccess'} eq 'yes') {
+                                                          $ignorecache = 1;
+                                                      }
+                                                      $first_access=&Apache::lonnet::get_first_access($interval[1],undef,$pagesymb,$ignorecache);
+                                                      if (($first_access) && (!$pagefirstaccess)) {
+                                                          $pagefirstaccess = $first_access;
+                                                      }
+                                                  } else {
+                                                      $first_access=&Apache::lonnet::get_first_access($interval[1],$symb);
+                                                  }
                                                   if ($first_access > 0) {
-                                                      my $timeremains = $first_access+$interval[0] - $now;
-                                                      if ($timeremains > 0) {
-                                                          $timerhastime = $timeremains;
+                                                      my ($timelimit) = ($interval[0] =~ /^(\d+)/);
+                                                      if ($timelimit) {
+                                                          my $timeremains = $timelimit + $first_access - $now;
+                                                          if ($timeremains > 0) {
+                                                              $timerhastime = $timeremains;
+                                                          }
                                                       }
                                                   }
                                               }
@@ -507,7 +540,26 @@ ENDEXT
                                                       if ((@interval > 1) && ($timerhastime)) {
                                                           $hastimeleft{$symb} = $timerhastime;
                                                           if ($pagefirstaccess) {
-                                                              $donebutton{$symb} = $interval[1];
+                                                              my ($timelimit,$usesdone,$donebuttontext,$proctor,$secret);
+                                                              ($timelimit,my $donesuffix) = split(/_/,$interval[0],2);
+                                                              if ($donesuffix =~ /^done\:([^\:]+)\:(.*)$/) {
+                                                                  $usesdone = 'done';
+                                                                  $donebuttontext = $1;
+                                                                  (undef,$proctor,$secret) = split(/_/,$2);
+                                                              } elsif ($donesuffix =~ /^done(|_.+)$/) {
+                                                                  $donebuttontext = &mt('Done');
+                                                                  ($usesdone,$proctor,$secret) = split(/_/,$donesuffix);
+                                                              }
+                                                              if ($usesdone eq 'done') {
+                                                                  $donebutton{$symb} = $timelimit;
+                                                                  push(@{$buttonbytime{$timelimit}},$symb);
+                                                                  $donebtnextra{$symb} = {
+                                                                                              text    => $donebuttontext,
+                                                                                              proctor => $proctor,
+                                                                                              secret  => $secret,
+                                                                                              type    => $interval[1],
+                                                                                         };
+                                                              }
                                                           }
                                                       } else {
                                                           $hastimeleft{$symb} = $slothastime;
@@ -517,7 +569,7 @@ ENDEXT
                                                       $countdowndisp{$symb} = 'none';
                                                   }
                                                   unless ($donebutton{$symb}) {
-                                                     $donebutton{$symb} = 0;
+                                                      $donebutton{$symb} = 0;
                                                   }
                                               }
                                           }
@@ -571,7 +623,9 @@ ENDEXT
 				  "\n</script>\n";
 			  }
                           if (($nforms) && ($nuploads)) {
-                              $allscript .= &Apache::lonhtmlcommon::file_submissionchk_js(\%turninpaths,\%multiresps);
+                              $allscript .= &Apache::lonhtmlcommon::file_submissionchk_js(\%turninpaths,\%multiresps).
+                                            '<script type="text/javascript" '.
+                                            'src="/res/adm/includes/file_upload.js"></script>';
                           }
                           if (($nforms) && (&Apache::lonhtmlcommon::htmlareabrowser())) {
                               my %textarea_args = (
@@ -598,8 +652,9 @@ ENDEXT
                                       $uniquetimes{$item} = 1;
                                   }
                               }
-                              if (keys(%uniquetimes) == 1) {
-                                  my (%uniquedisplays,%uniquedones,$currdisp,$donebuttontime);
+                              if (scalar(keys(%uniquetimes)) == 1) {
+                                  my (%uniquedisplays,%uniquedones,$currdisp,$donebuttontime,
+                                      $donebuttonextras);
                                   if (keys(%countdowndisp)) {
                                       foreach my $item (values(%countdowndisp)) {
                                           if (exists($uniquedisplays{$item})) {
@@ -625,16 +680,36 @@ ENDEXT
                                       if (scalar(@donebuttons) == 1) {
                                           if ($donebuttons[0]) {
                                               $donebuttontime = $donebuttons[0];
+                                              if (ref($buttonbytime{$donebuttontime}) eq 'ARRAY') {
+                                                  $donebuttonextras = $donebtnextra{$buttonbytime{$donebuttontime}->[0]};
+                                              }
                                           }
                                       }
                                   }
-                                  &add_countdown_timer($currdisp,$donebuttontime);
+                                  &add_countdown_timer($currdisp,$donebuttontime,$donebuttonextras);
+                              }
+                          }
+                          my $pagebuttonshide;
+                          if (keys(%buttonshide)) {
+                              my %uniquebuttonhide;
+                              foreach my $item (values(%buttonshide)) {
+                                  if (exists($uniquebuttonhide{$item})) {
+                                      $uniquebuttonhide{$item} ++;
+                                  } else {
+                                      $uniquebuttonhide{$item} = 1;
+                                  }
+                              }
+                              if (keys(%uniquebuttonhide) == 1) {
+                                  if (lc((keys(%uniquebuttonhide))[0]) eq 'yes') {
+                                      $pagebuttonshide = 'yes';
+                                  }
                               }
                           }
 # ------------------------------------------------------------------ Start body
 			  $r->print(&Apache::loncommon::start_page(undef,$allscript,
 								   {'force_register' => 1,
-								    'bgcolor'        => '#ffffff',}));
+								    'bgcolor'        => '#ffffff',
+								    'hide_buttons'   => $pagebuttonshide}));
 # ------------------------------------------------------------------ Start form
 			  if ($nforms) {
 			      my $fmtag = '<form name="lonhomework" method="post"  enctype="multipart/form-data"';
@@ -680,7 +755,7 @@ ENDEXT
                           my $avespan=$lcm/($#colcont+1);
                           for ($j=0;$j<=$#colcont;$j++) {
                               my $rid=$colcont[$j];
-			      my $metainfo =&get_buttons(\%hash,$rid).'<br />';
+			      my $metainfo =&get_buttons(\%hash,$rid,\%buttonshide,$hostname).'<br />';
 			    unless (($target eq 'tex') || ($target eq 'tex_answer')) {
 				$r->print('<td colspan="'.$avespan.'"');
 			    }
@@ -770,6 +845,8 @@ ENDEXT
                           $r->print(
 	                  '<input name="all_submit" value="'.&mt('Submit All').'" type="'.
 			  (($nforms>1)?'submit':'hidden').'"'.$class.' id="all_submit" />'.
+                          '<input type="hidden" name="all_submit_pressed" '.
+                          'id="all_submit_pressed" value="" />'.
                           '<div id="msg_all_submit" style="display:none">'.
                           &mt('Processing your submission ...').'</div></form>');
                       }
@@ -808,7 +885,7 @@ ENDEXT
 }
 
 sub get_buttons {
-    my ($hash,$rid) = @_;
+    my ($hash,$rid,$buttonshide,$hostname) = @_;
 
     my $metainfo = '';
     my $esrc=&Apache::lonnet::declutter($hash->{'src_'.$rid});
@@ -817,7 +894,7 @@ sub get_buttons {
 					  $resid,
 					  $hash->{'src_'.$rid});
     unless ($env{'request.role.adv'}) {
-        if (&Apache::lonnet::EXT('resource.0.buttonshide',$symb)) {
+        if ($buttonshide->{$symb} eq 'yes') {
             return;
         }
     }
@@ -878,23 +955,61 @@ sub get_buttons {
 		'</a>';
 	}
     }
-    if (($env{'request.course.id'}) && (&Apache::lonnet::allowed('mdc',$env{'request.course.id'}))) {
+    if ($env{'request.course.id'}) {
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
         my $file=&Apache::lonnet::declutter($hash->{'src_'.$rid});
-        my ($cfile,$home,$switchserver,$forceedit,$forceview) =
-            &Apache::lonnet::can_edit_resource($file,$cnum,$cdom,$hash->{'src_'.$rid},$symb);
-        if ($cfile ne '') {
-            my $jscall = &Apache::lonhtmlcommon::jump_to_editres($cfile,$home,$switchserver,
-                                                                 $forceedit,1,$symb,undef,
-                                                                 &escape($env{'form.title'}));
-            if ($jscall) {
+        my $editbutton = '';
+        if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) {
+            my ($cfile,$home,$switchserver,$forceedit,$forceview) =
+                &Apache::lonnet::can_edit_resource($file,$cnum,$cdom,$hash->{'src_'.$rid},$symb);
+            if ($cfile ne '') {
+                my $jscall = &Apache::lonhtmlcommon::jump_to_editres($cfile,$home,$switchserver,
+                                                                     $forceedit,1,$symb,undef,
+                                                                     &escape($env{'form.title'}),
+                                                                     $hostname);
+                if ($jscall) {
+                    $editbutton = 1;
+                    my $icon = 'pcstr.png';
+                    my $label = &mt('Edit');
+                    my $title = &mt('Edit this resource');
+                    my $pic = '<img src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/'.$icon).'"'.
+                              ' class="LC_icon" alt="'.$label.'" title="'.$title.'" />';
+                    $metainfo .= '&nbsp;<a href="javascript:'.$jscall.';">'.$pic.'</a>';
+                }
+            }
+        }
+        if ((!$editbutton) && ($file=~/$LONCAPA::assess_re/)) {
+            my $url = &Apache::lonnet::clutter($file);
+            my $viewsrcbutton;
+            if ((&Apache::lonnet::allowed('cre','/')) &&
+                (&Apache::lonnet::metadata($url,'sourceavail') eq 'open')) {
+                $viewsrcbutton = 1;
+            } elsif (&Apache::lonnet::allowed('vxc',$env{'request.course.id'})) {
+                if ($url =~ m{^\Q/res/$cdom/\E($LONCAPA::match_username)/}) {
+                    my $auname = $1;
+                    if (($env{'request.course.adhocsrcaccess'} ne '') &&
+                        (grep(/^\Q$auname\E$/,split(/,/,$env{'request.course.adhocsrcaccess'})))) {
+                        $viewsrcbutton = 1;
+                    }
+                }
+            }
+            if ($viewsrcbutton) {
                 my $icon = 'pcstr.png';
-                my $label = &mt('Edit');
-                my $title = &mt('Edit this resource');
+                my $label = &mt('View Source');
+                my $title = &mt('View source code');
+                my $jsrid = $rid;
+                $jsrid =~ s/\./_/g;
+                my $showurl = &escape(&Apache::lonenc::check_encrypt($url));
                 my $pic = '<img src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/'.$icon).'"'.
                           ' class="LC_icon" alt="'.$label.'" title="'.$title.'" />';
-                $metainfo .= '&nbsp;<a href="javascript:'.$jscall.';">'.$pic.'</a>';
+                $metainfo .= '&nbsp;<a href="javascript:open_source_'.$jsrid.'();">'.$pic.'</a>'."\n".
+                             '<script type="text/javascript">'."\n".
+                             "function open_source_$jsrid() {\n".
+                             "  sourcewin=window.open('/adm/source?inhibitmenu=yes&viewonly=1&filename=$showurl','LONsource',".
+                             "'height=500,width=600,resizable=yes,location=no,menubar=no,toolbar=no,scrollbars=yes');\n".
+                             "}\n".
+                             "</script>\n";
             }
         }
     }
@@ -902,7 +1017,7 @@ sub get_buttons {
 }
 
 sub add_countdown_timer {
-    my ($currdisp,$donebuttontime) = @_;
+    my ($currdisp,$donebuttontime,$donebuttonextras) = @_;
     my ($collapse,$expand,$alttxt,$title,$donebutton);
     if ($currdisp eq 'inline') {
         $collapse = '&#9658;&nbsp;';
@@ -910,7 +1025,17 @@ sub add_countdown_timer {
         $expand = '&#9668;&nbsp;';
     }
     if ($donebuttontime) {
-        $donebutton = &Apache::lonmenu::done_button_js($donebuttontime);
+        my ($type,$proctor,$donebuttontext);
+        if (ref($donebuttonextras) eq 'HASH') {
+            $proctor = $donebuttonextras->{'proctor'};
+            $donebuttontext = $donebuttonextras->{'text'};
+            $type = $donebuttonextras->{'type'};
+        } else {
+            $donebuttontext = &mt('Done');
+            $type = 'map';
+        }
+        $donebutton = 
+            &Apache::lonmenu::done_button_js($type,'','',$proctor,$donebuttontext);
     }
     unless ($env{'environment.icons'} eq 'iconsonly') {
         $alttxt = &mt('Timer');