--- loncom/interface/portfolio.pm	2021/12/14 03:34:43	1.254.2.6
+++ loncom/interface/portfolio.pm	2024/09/07 19:13:00	1.271
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # portfolio browser
 #
-# $Id: portfolio.pm,v 1.254.2.6 2021/12/14 03:34:43 raeburn Exp $
+# $Id: portfolio.pm,v 1.271 2024/09/07 19:13:00 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -237,7 +237,7 @@ sub display_directory_line {
 	if ($lock_info) {
 	    my %anchor_fields = ('lockinfo' => $fullpath);
 	    if ($versions) { # hold the folder open
-	        my ($fname,$version,$extension) = &Apache::grades::file_name_version_ext($fullpath);
+	        my ($fname,$version,$extension) = &Apache::lonnet::file_name_version_ext($fullpath);
 	        $fname =~ s|^/||;
 	        $anchor_fields{'showversions'} = $fname.'.'.$extension;
 	    }
@@ -267,13 +267,16 @@ sub display_directory_line {
 
 sub display_directory {
     my ($r,$url,$current_path,$is_empty,$dir_list,$group,$can_upload,
-        $can_modify,$can_delete,$can_setacl)=@_;
+        $can_modify,$can_delete,$can_setacl,$can_viewacl,$caller)=@_;
     my $iconpath= $r->dir_config('lonIconsURL') . "/";
     my $select_mode;
     my $checked_files;
     my $port_path = &get_port_path();
     my ($uname,$udom) = &get_name_dom($group);
-    my $access_admin_text = &mt('View Status');
+    my $access_admin_text;
+    if ($can_viewacl) {
+        $access_admin_text = &mt('View Status');
+    }
     if ($can_setacl) {
         $access_admin_text = &mt('View/Change Status');
     }
@@ -311,6 +314,18 @@ sub display_directory {
                 &mt('Using the portfolio file list'))
            .'</p>'
         );
+        my ($acl_helpfile,$acl_helplink);
+        if ($caller eq 'coursegrp_portfolio') {
+            $acl_helpfile = 'Portfolio ShareFile Group';
+        } elsif ($can_setacl) {
+            $acl_helpfile = 'Portfolio ShareFile';
+        }
+        unless ($can_setacl || $can_viewacl) {
+            $acl_helpfile = 'Portfolio ShareFile Off';
+        }
+        if ($acl_helpfile) {
+            $acl_helplink = &Apache::loncommon::help_open_topic($acl_helpfile);
+        }
         $r->print(&Apache::loncommon::start_data_table()
                  .&Apache::loncommon::start_data_table_header_row()
                  .'<th colspan="2">'.&mt('Actions'). &Apache::loncommon::help_open_topic('Portfolio FileAction').'</th>'
@@ -320,7 +335,7 @@ sub display_directory {
                  .'<th>'.&mt('Size').'</th>'
                  .'<th>'.&mt('Last Modified').'</th>'
                  .'<th>&nbsp;</th>'
-                 .'<th>'.&mt('Current Access Status').&Apache::loncommon::help_open_topic('Portfolio ShareFile').'</th>'
+                 .'<th>'.&mt('Current Access Status').$acl_helplink.'</th>'
                  .&Apache::loncommon::end_data_table_header_row());
     }
 
@@ -370,7 +385,7 @@ sub display_directory {
 		          } (@{$dir_list})) {
     	    my ($filename,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef)=split(/\&/,$dir_line,16); 
     	    $filename =~ s/\s+$//;
-    	    my ($fname,$version,$extension) = &Apache::grades::file_name_version_ext($filename);
+    	    my ($fname,$version,$extension) = &Apache::lonnet::file_name_version_ext($filename);
     	    if ($version) {
 	        my $fullpath = &prepend_group($current_path.$fname.'.'.$extension);
     	        push(@{ $versioned{$fullpath} },
@@ -383,7 +398,7 @@ sub display_directory {
     my $zerobyte;
     foreach my $dir_line (@dir_lines) {
         my ($filename,$dom,$testdir,$size,$mtime,$obs) = @$dir_line;
-        my ($fname,$version,$extension) = &Apache::grades::file_name_version_ext($filename);
+        my ($fname,$version,$extension) = &Apache::lonnet::file_name_version_ext($filename);
     	if (($filename ne '.') && ($filename ne '..') && ($filename !~ /\.meta$/ ) && ($filename !~ /(.*)\.(\d+)\.([^\.]*)$/)) {
     	    my $version_flag;
     	    my $show_versions;
@@ -487,6 +502,7 @@ sub display_directory {
 		    my $cond_access = 0;
 		    foreach my $key (sort(keys(%{$access_controls{$fullpath}}))) {
 			my ($num,$scope,$end,$start) = &unpack_acc_key($key);
+                        next if ($scope eq 'ip');   
 			if (($now > $start) && (!$end || $end > $now)) {
 			    if ($scope eq 'public')  {
 				$pub_access = 1;
@@ -514,7 +530,7 @@ sub display_directory {
 		    }
 		}
                 &display_directory_line($r,$select_mode, $filename, $mtime, $size, $css_class, $line, 
-                                        \%access_controls, $curr_access,$now, $version_flag, $href_location, 
+                                        \%access_controls, $curr_access, $now, $version_flag, $href_location, 
                                         $url, $current_path, $access_admin_text);
 		if ($show_versions) {
 		    foreach my $dir_line (@{ $versioned{$fullpath} }) {
@@ -887,7 +903,7 @@ sub access_for_renamed {
 }
 
 sub display_access {
-    my ($r,$url,$group,$can_setacl,$port_path,$action) = @_;
+    my ($r,$url,$group,$can_setacl,$can_viewacl,$port_path,$action) = @_;
     my ($uname,$udom) = &get_name_dom($group);
     my $file_name = $env{'form.currentpath'}.$env{'form.access'};
     $file_name = &prepend_group($file_name);
@@ -897,6 +913,8 @@ sub display_access {
     my $aclcount = keys(%access_controls);
     my ($header,$info);
     if ($action eq 'chgaccess') {
+        my $uhome = &Apache::lonnet::homeserver($uname,$udom);
+        my $prefix = &Apache::lonnet::url_prefix($r,$udom,$uhome,'web');
         $header =
             '<h2>'
             .&mt('Allowing others to retrieve file: [_1]'
@@ -909,13 +927,13 @@ sub display_access {
         $info .= '</li><li>'.&mt('Passphrase-protected files do not require log-in, but will require the viewer to enter the passphrase you set.');
         $info .= '</li><li>'.&explain_conditionals();
         $info .= '</li></ul>'.
-                  &mt('A listing of files viewable without log-in is available at: ')."<a href=\"/adm/$udom/$uname/aboutme/portfolio\">".&Apache::lonnet::absolute_url()."/adm/$udom/$uname/aboutme/portfolio</a>.<br />";
+                  &mt('A listing of files viewable without log-in is available at: ')."<a href=\"$prefix/adm/$udom/$uname/aboutme/portfolio\">$prefix/adm/$udom/$uname/aboutme/portfolio</a>.<br />";
         if ($group eq '') {
             $info .= &mt("For logged in users a 'Display file listing' link will also appear (when there are viewable files) on your personal information page:");
         } else {
             $info .= &mt("For logged in users a 'Display file listing' link will also appear (when there are viewable files) on the course information page:");
         }
-        $info .= "<br /><a href=\"/adm/$udom/$uname/aboutme\">".&Apache::lonnet::absolute_url()."/adm/$udom/$uname/aboutme</a><br />";
+        $info .= "<br /><a href=\"$prefix/adm/$udom/$uname/aboutme\">$prefix/adm/$udom/$uname/aboutme</a><br />";
         if ($group ne '') {
             $info .= &mt("Users with course editing rights may add a 'Group Portfolio' item using the Course Editor (Collaboration tab), to provide access to viewable group portfolio files.").'<br />';
         }
@@ -936,13 +954,21 @@ sub display_access {
                         'cancel' => &mt('Return to directory'),
                       };
         &close_form($r,$url,$button_text);
-    } else {
+    } elsif ($can_viewacl) {
         $r->print($header);
         if ($aclcount) {  
             $r->print($info);
         }
         &view_access_settings($r,$url,$access_controls{$file_name},$aclcount);
+    } else {
+        $r->print($header);
+        $r->print(&mt('You do not have sufficient privileges to view access controls').'<br />');
     }
+    my %anchor_fields = (
+        'currentpath' => $env{'form.currentpath'}
+    );
+    $r->print('<br />'.&make_anchor($url, \%anchor_fields, &mt('Return to directory')));
+    return;
 }
 
 sub explain_conditionals {
@@ -992,9 +1018,9 @@ sub build_access_summary {
                       domains => 'Conditional: domain-based',
                       users => 'Conditional: user-based',
                       course => 'Conditional: course/community-based',
-                      ip     => 'Conditional: IP-based',
+                      userip => 'Conditional: IP-based',
                      );
-    my @allscopes = ('public','guest','domains','users','course','ip');
+    my @allscopes = ('public','guest','domains','users','course','userip');
     foreach my $scope (@allscopes) {
         if ((!(exists($todisplay{$scope}))) || (ref($todisplay{$scope}) ne 'HASH')) {
             next;
@@ -1071,8 +1097,8 @@ sub build_access_summary {
                 } elsif ($scope eq 'users') {
                     my $curr_user_list = &sort_users($content->{'users'});
                     $r->print(&mt('Users: ').$curr_user_list);
-                } elsif ($scope eq 'ip') {
-                    my $curr_ips_list = &sort_ips($content->{'ip'});
+                } elsif ($scope eq 'userip') {
+                    my $curr_ips_list = &sort_ips($content->{'userip'});
                     $r->print(&mt('IP(s):').' '.$curr_ips_list);
                 } else {
                     $r->print('&nbsp;');
@@ -1182,7 +1208,7 @@ sub update_access {
     my $totalnew = 0;
     my $status = 'new';
     my ($firstitem,$lastitem);
-    my @types = ('course','domains','users','ip');
+    my @types = ('course','domains','users','userip');
     foreach my $newitem (@types) {
         $allnew += $env{'form.new'.$newitem};
     }
@@ -1194,7 +1220,7 @@ sub update_access {
            course  => 'course/community',
            domains => 'domain',
            users   => 'user',
-           ip      => 'IP',
+           userip  => 'IP',
         );
         foreach my $newitem (@types) {
             next if ($env{'form.new'.$newitem} <= 0);
@@ -1298,7 +1324,7 @@ sub build_access_record {
 		'udom'  => $udom
 		});
 	}
-    } elsif ($scope eq 'ip') {
+    } elsif ($scope eq 'userip') {
         my $ipslist = $env{'form.ips_'.$num};
         $ipslist =~ s/\s+//sg;
         my %ipshash = map { ($_,1) } (split(/,/,$ipslist));
@@ -1369,7 +1395,7 @@ sub access_setting_table {
                 push(@domains,$key);
             } elsif ($scope eq 'users') {
                 push(@users,$key);
-            } elsif ($scope eq 'ip') {
+            } elsif ($scope eq 'userip') {
                 push(@ips,$key);
             }
         }
@@ -1431,7 +1457,7 @@ sub standard_settings {
     my $numconditionals = 0;
     my $conditionstext;
     my %cond_status;
-    foreach my $scope ('domains','users','course','ip') {
+    foreach my $scope ('domains','users','course','userip') {
         $numconditionals += $acl_count->{$scope}; 
         if ($acl_count->{$scope} > 0) {
             if ($conditionstext ne 'Active') {
@@ -1478,7 +1504,7 @@ sub condition_setting {
     $r->print('</td></tr><tr><td colspan="3"></td></tr><tr><td valign="top">');
     &access_element($r,'course',$acl_count,$courses,$access_controls,$now,$then);
     $r->print('</td><td>&nbsp;</td><td valign="top">');
-    &access_element($r,'ip',$acl_count,$ips,$access_controls,$now,$then);
+    &access_element($r,'userip',$acl_count,$ips,$access_controls,$now,$then);
     $r->print('</td></tr></table>');
 }
 
@@ -1499,7 +1525,7 @@ sub access_element {
         domains => 'Domain',
         users   => 'User',
         course  => 'Course/Community',
-        ip      => 'IP',
+        userip  => 'IP',
     );
     $r->print('<h3>'.&mt($typetext{$type}.'-based conditional access:').' ');
     if ($$acl_count{$type}) {
@@ -1524,7 +1550,7 @@ sub display_access_row {
     } elsif ($type eq 'users') {
         $showtype = &mt('Users');
         $infotype = 'User';
-    } elsif ($type eq 'ip') {
+    } elsif ($type eq 'userip') {
         $showtype = &mt('IP-based');
         $infotype = 'IP';  
     }
@@ -1552,7 +1578,7 @@ sub display_access_row {
                             $then);
             } elsif ($type eq 'users') {
                 &users_row($r,$status,$key,$access_controls,$now,$then);
-            } elsif ($type eq 'ip') {
+            } elsif ($type eq 'userip') {
                 &ips_row($r,$status,$key,$access_controls,$now,$then);
             }
 	    $r->print(&Apache::loncommon::end_data_table_row());
@@ -1735,11 +1761,11 @@ sub users_row {
 sub ips_row {
     my ($r,$status,$item,$access_controls,$now,$then) = @_;
     my ($num,$scope,$end,$start) = &set_identifiers($status,$item,$now,$then,
-                                                    'ip');
+                                                    'userip');
     my $curr_ips_list;
     if ($status eq 'old') {
         my $content = $$access_controls{$item};
-        $curr_ips_list = &sort_ips($content->{'ip'});
+        $curr_ips_list = &sort_ips($content->{'userip'});
     }
     $r->print('<td>'.&actionbox($status,$num,$scope).'</td><td>'.&mt('Format for IP controls').'<br />'.
               &mt('[_1] or [_2] or [_3] or [_4] or [_5]','<tt>35.8.*</tt>','<tt>35.8.3.[34-56]</tt>',
@@ -1758,7 +1784,7 @@ sub additional_item {
         $showtype = 'domain';
     } elsif ($type eq 'users') {
         $showtype = 'user';
-    } elsif ($type eq 'ip') {
+    } elsif ($type eq 'userip') {
         $showtype = 'IP';
     }
     return
@@ -1772,7 +1798,7 @@ sub actionbox {
     my $output = '<span class="LC_nobreak"><label>';
     if ($status eq 'new') {
         my $checkstate;
-        if ($scope eq 'domains' || $scope eq 'users' || $scope eq 'course' || $scope eq 'ip') {
+        if ($scope eq 'domains' || $scope eq 'users' || $scope eq 'course' || $scope eq 'userip') {
             $checkstate = 'checked="checked"';
         }
         $output .= '<input type="checkbox" name="activate" value="'.$num.'" '.
@@ -2513,6 +2539,7 @@ sub missing_priv {
                       delete => 'delete files',
                       rename => 'rename files',
                       setacl => 'set access controls for files',
+                      viewacl => 'view access controls for files',
     );
     my $escpath = &HTML::Entities::encode($env{'form.currentpath'},'&<>"');
     my $rtnlink = '<a href="'.$url;
@@ -2668,7 +2695,7 @@ sub handler {
         $url = $1.$2;
         $caller = $2;
     }
-    my ($can_modify,$can_delete,$can_upload,$can_setacl);
+    my ($can_modify,$can_delete,$can_upload,$can_setacl,$can_viewacl);
     if ($caller eq 'coursegrp_portfolio') {
     #  Needs to be in a course
         if (! ($env{'request.course.fn'})) {
@@ -2712,6 +2739,7 @@ sub handler {
             $can_delete = 1;
             $can_upload = 1;
             $can_setacl = 1;
+            $can_viewacl = 1;
         } else {
             if (&Apache::lonnet::allowed('agf',$env{'request.course.id'}.'/'.$group)) {
                 $can_setacl = 1;
@@ -2725,6 +2753,9 @@ sub handler {
             if (&Apache::lonnet::allowed('dgf',$env{'request.course.id'}.'/'.$group)) {
                 $can_delete = 1;
             }
+            if (&Apache::lonnet::allowed('rgf',$env{'request.course.id'}.'/'.$group)) {
+                $can_viewacl = 1;
+            }
         }
     } else {
         ($uname,$udom) = &get_name_dom();
@@ -2733,7 +2764,11 @@ sub handler {
         $can_modify = 1;
         $can_delete = 1;
         $can_upload = 1;
-        $can_setacl = 1;
+        if (&Apache::lonnet::usertools_access($uname,$udom,'portaccess',
+                                              undef,'tools')) {
+            $can_viewacl = 1;
+            $can_setacl = 1;
+        }
     }
 
     my $port_path = &get_port_path();
@@ -2745,7 +2780,7 @@ sub handler {
 
     my $js = '<script type="text/javascript"
                 src="/res/adm/includes/file_upload.js"></script>';
-
+    
     if ($env{"form.mode"} eq 'selectfile'){
         $r->print(&Apache::loncommon::start_page($title, $js,
 						 {'only_body' => 1}));
@@ -2914,10 +2949,14 @@ sub handler {
         }
     } elsif ($env{'form.access'}) {
         $env{'form.selectfile'} = $env{'form.access'};
-        if (!defined($env{'form.action'})) { 
+        if (!defined($env{'form.action'})) {
             $env{'form.action'} = 'chgaccess';
         }
-        &display_access($r,$url,$group,$can_setacl,$port_path,$env{'form.action'});
+        if (($can_viewacl) || ($can_setacl)) {
+            &display_access($r,$url,$group,$can_setacl,$can_viewacl,$port_path,$env{'form.action'});
+        } else {
+            &missing_priv($r,$url,'viewacl');
+        }
     } elsif (($env{'form.action'} eq 'chgaccess') || 
              ($env{'form.action'} eq 'chgconditions')) {
         if ($can_setacl) {
@@ -2991,7 +3030,8 @@ sub handler {
 	&display_common($r,$url,$current_path,$is_empty,$dirlistref,
 			$can_upload,$group);
         &display_directory($r,$url,$current_path,$is_empty,$dirlistref,$group,
-                           $can_upload,$can_modify,$can_delete,$can_setacl);
+                           $can_upload,$can_modify,$can_delete,$can_setacl,
+                           $can_viewacl,$caller);
     }
     $r->print(&Apache::loncommon::end_page());
     return OK;