--- loncom/interface/lonmenu.pm	2020/02/17 23:04:18	1.501
+++ loncom/interface/lonmenu.pm	2021/11/15 23:29:20	1.512
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Routines to control the menu
 #
-# $Id: lonmenu.pm,v 1.501 2020/02/17 23:04:18 raeburn Exp $
+# $Id: lonmenu.pm,v 1.512 2021/11/15 23:29:20 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -220,7 +220,7 @@ use vars qw(@desklines %category_names %
 my @inlineremote;
 
 sub prep_menuitem {
-    my ($menuitem,$ltitarget) = @_;
+    my ($menuitem,$ltitarget,$listclass,$linkattr) = @_;
     return '' unless(ref($menuitem) eq 'ARRAY');
     my $link;
     if ($$menuitem[1]) { # graphical Link
@@ -234,10 +234,10 @@ sub prep_menuitem {
     if ($ltitarget eq 'iframe') {
         $target ='';
     }
-    return '<li><a' 
+    return ($listclass?'<li class="'.$listclass.'">':'<li>').'<a'
            # highlighting for new messages
            . ( $$menuitem[4] eq 'newmsg' ? ' class="LC_new_message"' : '') 
-           . qq| href="$$menuitem[0]"$target>$link</a></li>|;
+           . qq| href="$$menuitem[0]"$target $linkattr>$link</a></li>|;
 }
 
 # primary_menu() evaluates @primary_menu and returns a two item array,
@@ -247,8 +247,8 @@ sub prep_menuitem {
 # @primary_menu is filled within the BEGIN block of this module with 
 # entries from mydesk.tab
 sub primary_menu {
-    my ($crstype,$ltimenu) = @_;
-    my (%menu,%ltiexc);
+    my ($crstype,$ltimenu,$menucoll,$menuref,$links_disabled) = @_;
+    my (%menu,%ltiexc,%menuopts);
     # each element of @primary contains following array:
     # (link url, icon path, alt text, link text, condition, position)
     my $public;
@@ -277,6 +277,9 @@ sub primary_menu {
             }
         }
     }
+    if (($menucoll) && (ref($menuref) eq 'HASH')) {
+        %menuopts = %{$menuref};
+    }
     foreach my $menuitem (@primary_menu) {
         # evaluate conditions 
         next if    ref($menuitem)       ne 'ARRAY';    #
@@ -292,10 +295,10 @@ sub primary_menu {
                                                        # users
         next if    $$menuitem[4]        eq 'roles'     ##show links depending on
                 && (&Apache::loncommon::show_course()  ##term 'Courses' or
-                || $env{'request.lti.login'});         ##'Roles' wanted
+                || $lti);                              ##'Roles' wanted
         next if    $$menuitem[4]        eq 'courses'   ##and not LTI access
                 && (!&Apache::loncommon::show_course()
-                || !$env{'request.lti.login'});
+                || $lti);
         next if    $$menuitem[4]        eq 'notlti'
                 && $lti;
         next if    $$menuitem[4]        eq 'ltiexc'
@@ -312,6 +315,28 @@ sub primary_menu {
         if ($position eq '') {
             $position = 'right';
         }
+        if ($env{'request.course.id'} && $menucoll) {
+            if (($menuitem->[6]) && (!$menuopts{$menuitem->[6]})) {
+                if ($menuitem->[6] eq 'pers') {
+                    if ($menuopts{'name'} && !$ltiexc{'fullname'} &&
+                        $env{'user.name'} && $env{'user.domain'}) {
+                        $menu{$position} .= '<li><a href="#">'.
+                            &Apache::loncommon::plainname($env{'user.name'},
+                                                          $env{'user.domain'}).'</a></li>';
+                        next;
+                    } else {
+                        next;
+                    }
+                } else {
+                    next;
+                }
+            }
+        }
+        my ($listclass,$linkattr);
+        if ($links_disabled) {
+            $listclass = 'LCisDisabled';
+            $linkattr = 'aria-disabled="true"';
+        }
         if (defined($primary_submenu{$title})) {
             my ($link,$target);
             if ($menuitem->[0] ne '') {
@@ -331,19 +356,30 @@ sub primary_menu {
                              ($item->[2] eq 'blog')) &&
                              (!&Apache::lonnet::usertools_access('','',$item->[2],
                                                            undef,'tools')));
+                    if ($env{'request.course.id'} && $menucoll) {
+                        next if ($item->[3]) && (!$menuopts{$item->[3]});
+                    }
                     push(@primsub,$item);
                 }
-                if ($title eq 'Personal' && $env{'user.name'} && $env{'user.domain'} ) {
-                    unless ($ltiexc{'fullname'}) {
-                        $title = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'});
+                if ($title eq 'Personal') {
+                    if ($env{'user.name'} && $env{'user.domain'} && !$ltiexc{'fullname'}) {
+                        unless (($env{'request.course.id'}) && ($menucoll) && (!$menuopts{'name'})) {
+                            $title = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'});
+                        }
+                    }
+                    next if (($env{'request.course.id'}) && ($menucoll) && ($title eq 'Personal') &&
+                             (!@primsub));
+                    if ($title eq 'Personal') {
+                        $title = &mt($title);
                     }
                 } else {
                     $title = &mt($title);
                 }
                 if (@primsub > 0) {
-                    $menu{$position} .= &create_submenu($link,$target,$title,\@primsub,1);
+                    $menu{$position} .= &create_submenu($link,$target,$title,\@primsub,1,undef,$listclass,$linkattr);
                 } elsif ($link) {
-                    $menu{$position} .= '<li><a href="'.$link.'" target="'.$target.'">'.$title.'</a></li>';
+                    $menu{$position} .= ($listclass?'<li class="'.$listclass.'">':'<li>').
+                                        '<a href="'.$link.'" target="'.$target.'" '.$linkattr.'>'.$title.'</a></li>';
                 }
             }
         } elsif ($$menuitem[3] eq 'Help') { # special treatment for helplink
@@ -355,13 +391,22 @@ sub primary_menu {
                                                                   'helpdeskmail',
                                                                   $defdom,$origmail);
                 if ($to ne '') {
-                    $menu{$position} .= &prep_menuitem($menuitem,$ltitarget); 
+                    $menu{$position} .= &prep_menuitem($menuitem,$ltitarget,$listclass,$linkattr); 
                 }
             } else {
-                $menu{$position} .= '<li>'.&Apache::loncommon::top_nav_help('Help').'</li>';
+                $menu{$position} .= ($listclass?'<li class="'.$listclass.'">':'<li>').
+                                    &Apache::loncommon::top_nav_help('Help',$linkattr).
+                                    '</li>';
+            }
+        } elsif ($$menuitem[3] eq 'Log In') {
+            if ($public) {
+                if (&Apache::lonnet::get_saml_landing()) {
+                    $$menuitem[0] = '/adm/login';
+                }
             }
+            $menu{$position} .= prep_menuitem($menuitem,$ltitarget,$listclass,$linkattr);
         } else {
-            $menu{$position} .= prep_menuitem($menuitem,$ltitarget);
+            $menu{$position} .= prep_menuitem($menuitem,$ltitarget,$listclass,$linkattr);
         }
     }
     my @output = ('','');
@@ -400,7 +445,7 @@ sub getauthor{
 }
 
 sub secondary_menu {
-    my ($httphost,$ltiscope,$ltimenu,$noprimary) = @_;
+    my ($httphost,$ltiscope,$ltimenu,$noprimary,$menucoll,$menuref,$links_disabled) = @_;
     my $menu;
 
     my $crstype = &Apache::loncommon::course_type();
@@ -424,7 +469,8 @@ sub secondary_menu {
     my $canplc        = &Apache::lonnet::allowed('plc', $crs_sec);
     my $author        = &getauthor();
 
-    my ($cdom,$cnum,$showsyllabus,$showfeeds,$showresv,$grouptools,$lti,$ltimapres,%ltiexc);
+    my ($cdom,$cnum,$showsyllabus,$showfeeds,$showresv,$grouptools,
+        $lti,$ltimapres,%ltiexc,%menuopts);
     $grouptools = 0;
     if ($env{'request.course.id'}) {
         $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
@@ -472,6 +518,15 @@ sub secondary_menu {
             }
         }
     }
+    if (($menucoll) && (ref($menuref) eq 'HASH')) {
+        %menuopts = %{$menuref};
+    }
+
+    my ($listclass,$linkattr);
+    if ($links_disabled) {
+        $listclass = 'LCisDisabled';
+        $linkattr = 'aria-disabled="true"';
+    }
 
     my ($canmodifycoauthor); 
     if ($env{'request.role'} eq "au./$env{'user.domain'}/") {
@@ -534,11 +589,16 @@ sub secondary_menu {
                 && $ltiexc{'logout'};
 
         my $title = $menuitem->[3];
+        if ($env{'request.course.id'} && $menucoll) {
+            unless ($$menuitem[5] eq 'roles') {
+                next if (($$menuitem[5]) && (!$menuopts{$$menuitem[5]}));
+            }
+        }
         if (defined($secondary_submenu{$title})) {
             my ($link,$target);
             if ($menuitem->[0] ne '') {
                 $link = $menuitem->[0];
-                unless ($ltitarget eq 'iframe') {   
+                unless ($ltitarget eq 'iframe') {
                     $target = '_top';
                 }
             } else {
@@ -568,25 +628,32 @@ sub secondary_menu {
                         push(@scndsub,$item);
                     }
                 }
-                if ($title eq 'Personal' && $env{'user.name'} && $env{'user.domain'} ) {
+                if ($title eq 'Personal' && $env{'user.name'} && $env{'user.domain'}) {
                     unless ($ltiexc{'fullname'}) {
                         $title = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'});
                     }
                 }
                 if (@scndsub > 0) {
-                    $menu .= &create_submenu($link,$target,$title,\@scndsub,1);
+                    $menu .= &create_submenu($link,$target,&mt($title),\@scndsub,1,undef,
+                                             $listclass,$linkattr);
                 } elsif ($link ne '#') {
-                    $menu .= '<li><a href="'.$link.'" target="'.$target.'">'.&mt($title).'</a></li>';
+                    $menu .= ($listclass?'<li class="'.$listclass.'">':'<li>').
+                             '<a href="'.$link.'" target="'.$target.'" '.$linkattr.'>'.
+                             &mt($title).'</a></li>';
                 }
             }
         } elsif ($$menuitem[3] eq 'Roles' && $env{'request.course.id'}) {
             # special treatment for role selector
-            ($roleswitcher_js,$roleswitcher_form,my $switcher) =
+            my ($switcher,$has_opa_priv);
+            ($roleswitcher_js,$roleswitcher_form,$switcher,$has_opa_priv) =
                 &roles_selector(
                     $env{'course.' . $env{'request.course.id'} . '.domain'},
                     $env{'course.' . $env{'request.course.id'} . '.num'},
                     $httphost,$ltitarget
                 );
+            if (($$menuitem[5]) && (!$menuopts{$$menuitem[5]})) {
+                next unless ($has_opa_priv);
+            }
             $menu .= $switcher;
         } elsif ($$menuitem[3] eq 'Help') { # special treatment for helplink
             next if ($crstype eq 'Placement');
@@ -604,7 +671,7 @@ sub secondary_menu {
                 }
                 if ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://}) {
                     if (($ENV{'SERVER_PORT'} == 443) || ($env{'request.use_absolute'} =~ m{^https://})) {
-                        unless (&Apache::lonnet::uses_sts()) {
+                        unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl())) {
                             unless ($$menuitem[0] =~ m{^https?://}) {
                                 $$menuitem[0] = 'http://'.$ENV{'SERVER_NAME'}.$$menuitem[0];
                             }
@@ -616,7 +683,7 @@ sub secondary_menu {
                 }
                 $$menuitem[0] = &HTML::Entities::encode($$menuitem[0],'&<>"');
             }
-            $menu .= &prep_menuitem(\@$menuitem,$ltitarget);
+            $menu .= &prep_menuitem(\@$menuitem,$ltitarget,$listclass,$linkattr);
         }
     }
     if ($menu =~ /\[url\].*\[symb\]/) {
@@ -654,7 +721,7 @@ sub secondary_menu {
 }
 
 sub create_submenu {
-    my ($link,$target,$title,$submenu,$translate,$addclass) = @_;
+    my ($link,$target,$title,$submenu,$translate,$addclass,$listclass,$linkattr) = @_;
     return unless (ref($submenu) eq 'ARRAY');
     my $disptarget;
     if ($target ne '') {
@@ -669,7 +736,7 @@ sub create_submenu {
 
     # $link and $title are only used in the initial string written in $menu
     # as seen above, not needed for nested submenus
-    $menu .= &build_submenu($target, $submenu, $translate, '1');
+    $menu .= &build_submenu($target, $submenu, $translate, '1', $listclass, $linkattr);
     $menu .= '</ul></li>';
 
     return $menu;
@@ -679,7 +746,7 @@ sub create_submenu {
 # build the dropdown (and nested submenus) recursively
 # see perldoc create_submenu documentation for further information
 sub build_submenu {
-    my ($target, $submenu, $translate, $first_level) = @_; 
+    my ($target, $submenu, $translate, $first_level, $listclass, $linkattr) = @_; 
     unless (@{$submenu}) {
         return '';
     }
@@ -744,8 +811,10 @@ sub build_submenu {
                     }
                 }
 
-                $menu .= '<li style="margin:0;padding:0;'. $bordertop . $borderbot .'">';
-                $menu .= '<a href="'.$href.'"'.$target.'>' .  $title . '</a>';
+                $menu .= '<li '.
+                $menu .= ($listclass?'class="'.$listclass.'" ':'');
+                $menu .= 'style="margin:0;padding:0;'. $bordertop . $borderbot .'">';
+                $menu .= '<a href="'.$href.'"'.$target.' '.$linkattr.'>' .  $title . '</a>';
                 $menu .= '</li>';
             }
         }
@@ -1098,12 +1167,14 @@ if ($env{'browser.mobile'}) {
 }
 
             unless ($env{'request.noversionuri'}=~/\/(bulletinboard|smppg|navmaps|syllabus|aboutme|viewclasslist|portfolio)(\?|$)/) {
-		if ((!$env{'request.enc'}) && ($env{'request.noversionuri'} !~ m{^/adm/wrapper/ext/}) && ($env{'request.noversionuri'} !~ m{^/uploaded/$match_domain/$match_courseid/docs/}) && ($env{'request.noversionuri'} !~ m{^/adm/.+/ext\.tool$})) {
+		if ((!$env{'request.enc'}) && ($env{'request.noversionuri'} !~ m{^/adm/wrapper/ext/}) &&
+                    ($env{'request.noversionuri'} !~ m{^/uploaded/$match_domain/$match_courseid/(docs/|default_\d+\.page$)}) &&
+                    ($env{'request.noversionuri'} !~ m{^/adm/.+/ext\.tool$})) {
 		    $menuitems.=(<<ENDREALRES);
 s&6&3&catalog.png&Info&info[_1]&catalog_info(currentURL,'$is_mobile')&Show Metadata
 ENDREALRES
                 }
-                unless (($env{'request.noversionuri'} =~ m{^/uploaded/$match_domain/$match_courseid/docs/}) ||
+                unless (($env{'request.noversionuri'} =~ m{^/uploaded/$match_domain/$match_courseid/(docs/|default_\d+\.page$)}) ||
                         ($env{'request.noversionuri'} =~ m{^\Q/adm/wrapper/\E(ext|uploaded)/}) ||
                         ($env{'request.noversionuri'} =~ m{^/adm/.+/ext\.tool$})) {
                     $menuitems.=(<<ENDREALRES);
@@ -1281,11 +1352,12 @@ sub prepare_functions {
 # Determine whether or not to display 'Edit' or 'View Source' icon/button
 #
     if ($resurl =~ m{^/?adm/($match_domain)/($match_username)/aboutme$}) {
+        my $blocked = &Apache::loncommon::blocking_status('about',$2,$1);
         my $file=&Apache::lonnet::declutter($env{'request.filename'});
         ($cfile,$home,$switchserver,$forceedit,$forceview) =
             &Apache::lonnet::can_edit_resource($file,$cnum,$cdom,
                 &Apache::lonnet::clutter($resurl),$env{'request.symb'},$group);
-        if (($cfile) && ($home ne '') && ($home ne 'no_host')) {
+        if (($cfile) && ($home ne '') && ($home ne 'no_host') && (!$blocked)) {
             $editbutton = &get_editbutton($cfile,$home,$switchserver,
                                           $forceedit,$forceview,$forcereg);
         }
@@ -1398,10 +1470,13 @@ sub prepare_functions {
         if ($resurl =~ m{^/?adm/($match_domain)/($match_username)/aboutme$}) {
             my ($sdom,$sname) = ($1,$2);
             unless (&Apache::lonnet::is_course($sdom,$sname)) {
-                &switch('','',6,4,'mail-message-new-22x22.png','Message to user',
-                        '',
-                        "go('/adm/email?compose=individual&amp;recname=$sname&amp;recdom=$sdom')",
-                            'Send message to specific user');
+                my $blocked = &Apache::loncommon::blocking_status('about',$sname,$sdom);
+                unless ($blocked) {
+                    &switch('','',6,4,'mail-message-new-22x22.png','Message to user',
+                            '',
+                            "go('/adm/email?compose=individual&amp;recname=$sname&amp;recdom=$sdom')",
+                                'Send message to specific user');
+                }
             }
             my $hideprivileged = 1;
             if (&Apache::lonnet::in_course($sdom,$sname,$cdom,$cnum,undef,
@@ -1907,6 +1982,7 @@ sub done_button_js {
                  key      => 'Key:',
                  nokey    => 'A proctor key is required', 
     );
+    my $shownsymb = &HTML::Entities::encode(&Apache::lonenc::check_encrypt($env{'request.symb'}));
     my $navmap = Apache::lonnavmaps::navmap->new(); 
     my ($missing,$tried) = (0,0);
     if (ref($navmap)) {
@@ -1969,6 +2045,7 @@ sub done_button_js {
 <form method="post" name="LCdoneButton" action="">
     <input type="hidden" name="LC_interval_done" value="" />
     <input type="hidden" name="LC_interval_done_proctorpass" value="" />
+    <input type="hidden" name="symb" value="$shownsymb" />
     <button id="LC_done-confirm-opener" type="button">$donebuttontext</button>
 </form>
 
@@ -2050,6 +2127,7 @@ END
 
 <form method="post" name="LCdoneButton" action="">
     <input type="hidden" name="LC_interval_done" value="" />
+    <input type="hidden" name="symb" value="$shownsymb" />
     <button id="LC_done-confirm-opener" type="button">$donebuttontext</button>
 </form>
 
@@ -2385,7 +2463,7 @@ sub roles_selector {
     my $now = time;
     my (%courseroles,%seccount,%courseprivs,%roledesc);
     my $is_cc;
-    my ($js,$form,$switcher);
+    my ($js,$form,$switcher,$has_opa_priv);
     my $ccrole;
     if ($crstype eq 'Community') {
         $ccrole = 'co';
@@ -2506,12 +2584,19 @@ sub roles_selector {
                 if ($env{'request.role'} =~ m{^\Q$role\E}) {
                     if ($seccount{$role} > 1) {
                         $include = 1;
+                    } else {
+                        if ($env{'user.priv.'.$env{'request.role'}."./$cdom/$cnum"} =~/opa\&([^\:]*)/) {
+                            $has_opa_priv = 1;
+                        }
                     }
                 } else {
                     $include = 1;
                 }
             }
             if ($include) {
+                if ($env{"user.priv.$role./$cdom/$cnum./$cdom/$cnum"} =~/opa\&([^\:]*)/) {
+                    $has_opa_priv = 1;
+                }
                 push(@submenu,['javascript:adhocRole('."'$role'".')',
                                &Apache::lonnet::plaintext($role,$crstype)]);
             }
@@ -2536,6 +2621,9 @@ sub roles_selector {
                     } else {
                         $rolename = &Apache::lonnet::plaintext($role);
                     }
+                    if ($env{"user.priv.$role./$cdom/$cnum./$cdom/$cnum"} =~/opa\&([^\:]*)/) {
+                        $has_opa_priv = 1;
+                    }
                     push(@submenu,['javascript:adhocRole('."'$role'".')',
                                    $rolename]);
                 }
@@ -2545,7 +2633,7 @@ sub roles_selector {
             $switcher = &create_submenu('','',&mt('Switch role'),\@submenu,'','',$ltitarget);
         }
     }
-    return ($js,$form,$switcher);
+    return ($js,$form,$switcher,$has_opa_priv);
 }
 
 sub get_all_courseroles {
@@ -2993,13 +3081,13 @@ BEGIN {
                         $category_positions{$entries[2]}=$entries[1];
                         $category_names{$entries[2]}=$entries[3];
                     } elsif ($configline=~/^prim\:/) {
-                        my @entries = (split(/\:/, $configline))[1..6];
+                        my @entries = (split(/\:/, $configline))[1..7];
                         push(@primary_menu,\@entries);
                     } elsif ($configline=~/^primsub\:/) {
-                        my ($parent,@entries) = (split(/\:/, $configline))[1..4];
+                        my ($parent,@entries) = (split(/\:/, $configline))[1..5];
                         push(@{$primary_submenu{$parent}},\@entries);
                     } elsif ($configline=~/^scnd\:/) {
-                        my @entries = (split(/\:/, $configline))[1..5];
+                        my @entries = (split(/\:/, $configline))[1..6];
                         push(@secondary_menu,\@entries);
                     } elsif ($configline=~/^scndsub\:/) {
                         my ($parent,@entries) = (split(/\:/, $configline))[1..4];