--- loncom/interface/lonmenu.pm 2018/04/14 17:52:43 1.486
+++ loncom/interface/lonmenu.pm 2022/05/28 16:25:45 1.520
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines to control the menu
#
-# $Id: lonmenu.pm,v 1.486 2018/04/14 17:52:43 raeburn Exp $
+# $Id: lonmenu.pm,v 1.520 2022/05/28 16:25:45 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -99,7 +99,7 @@ It gets filled in the BEGIN block of thi
=over
-=item prep_menuitems(\@menuitem,$ltitarget)
+=item prep_menuitems(\@menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr)
This routine wraps a menuitem in proper HTML. It is used by primary_menu() and
secondary_menu().
@@ -220,7 +220,7 @@ use vars qw(@desklines %category_names %
my @inlineremote;
sub prep_menuitem {
- my ($menuitem,$ltitarget) = @_;
+ my ($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr) = @_;
return '' unless(ref($menuitem) eq 'ARRAY');
my $link;
if ($$menuitem[1]) { # graphical Link
@@ -233,11 +233,13 @@ sub prep_menuitem {
my $target = ' target="_top"';
if ($ltitarget eq 'iframe') {
$target ='';
+ } elsif ($deeplinktarget eq '_self') {
+ $target = ' target="'.$deeplinktarget.'"';
}
- return '
':'').'$link|;
+ . qq| href="$$menuitem[0]"$target $linkattr>$link|;
}
# primary_menu() evaluates @primary_menu and returns a two item array,
@@ -247,8 +249,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) = @_;
- my (%menu);
+ 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;
@@ -265,9 +267,23 @@ sub primary_menu {
my %roles_in_env;
$rolecount = &Apache::lonroles::roles_from_env(\%roles_in_env,$update);
}
- my $ltitarget;
+ my ($lti,$ltitarget,$deeplinktarget);
if ($env{'request.lti.login'}) {
+ $lti = 1;
$ltitarget = $env{'request.lti.target'};
+ if (ref($ltimenu) eq 'HASH') {
+ foreach my $item ('fullname','logout') {
+ unless ($ltimenu->{$item}) {
+ $ltiexc{$item} = 1;
+ }
+ }
+ }
+ }
+ if ($env{'request.deeplink.login'}) {
+ $deeplinktarget = $env{'request.deeplink.target'};
+ }
+ if (($menucoll) && (ref($menuref) eq 'HASH')) {
+ %menuopts = %{$menuref};
}
foreach my $menuitem (@primary_menu) {
# evaluate conditions
@@ -283,9 +299,15 @@ sub primary_menu {
&& !$public; # only visible to public
# users
next if $$menuitem[4] eq 'roles' ##show links depending on
- && &Apache::loncommon::show_course(); ##term 'Courses' or
- next if $$menuitem[4] eq 'courses' ##'Roles' wanted
- && !&Apache::loncommon::show_course(); ##
+ && (&Apache::loncommon::show_course() ##term 'Courses' or
+ || $lti); ##'Roles' wanted
+ next if $$menuitem[4] eq 'courses' ##and not LTI access
+ && (!&Apache::loncommon::show_course()
+ || $lti);
+ next if $$menuitem[4] eq 'notlti'
+ && $lti;
+ next if $$menuitem[4] eq 'ltiexc'
+ && exists($ltiexc{lc($menuitem->[3])});
my $title = $menuitem->[3];
if (($crstype eq 'Placement') && (!$env{'request.role.adv'})) {
if ($menuitem->[4] eq 'courses') {
@@ -298,11 +320,33 @@ 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} .= ''.
+ &Apache::loncommon::plainname($env{'user.name'},
+ $env{'user.domain'}).'';
+ 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 '') {
$link = $menuitem->[0];
- unless ($ltitarget eq 'iframe') {
+ unless (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) {
$target = '_top';
}
} else {
@@ -317,17 +361,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'} ) {
- $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} .= ''.$title.'';
+ $menu{$position} .= ($listclass?'':'').
+ ''.$title.'';
}
}
} elsif ($$menuitem[3] eq 'Help') { # special treatment for helplink
@@ -339,13 +396,22 @@ sub primary_menu {
'helpdeskmail',
$defdom,$origmail);
if ($to ne '') {
- $menu{$position} .= &prep_menuitem($menuitem,$ltitarget);
+ $menu{$position} .= &prep_menuitem($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr);
}
} else {
- $menu{$position} .= ''.&Apache::loncommon::top_nav_help('Help').'';
+ $menu{$position} .= ($listclass?'':'').
+ &Apache::loncommon::top_nav_help('Help',$linkattr).
+ '';
}
+ } elsif ($$menuitem[3] eq 'Log In') {
+ if ($public) {
+ if (&Apache::lonnet::get_saml_landing()) {
+ $$menuitem[0] = '/adm/login';
+ }
+ }
+ $menu{$position} .= prep_menuitem($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr);
} else {
- $menu{$position} .= prep_menuitem($menuitem,$ltitarget);
+ $menu{$position} .= prep_menuitem($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr);
}
}
my @output = ('','');
@@ -384,7 +450,7 @@ sub getauthor{
}
sub secondary_menu {
- my ($httphost) = @_;
+ my ($httphost,$ltiscope,$ltimenu,$noprimary,$menucoll,$menuref,$links_disabled) = @_;
my $menu;
my $crstype = &Apache::loncommon::course_type();
@@ -405,9 +471,11 @@ sub secondary_menu {
my $canmodpara = &Apache::lonnet::allowed('opa', $crs_sec);
my $canvgr = &Apache::lonnet::allowed('vgr', $crs_sec);
my $canmgr = &Apache::lonnet::allowed('mgr', $crs_sec);
+ my $canplc = &Apache::lonnet::allowed('plc', $crs_sec);
my $author = &getauthor();
- my ($cdom,$cnum,$showsyllabus,$showfeeds,$showresv,$grouptools);
+ 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'};
@@ -431,10 +499,9 @@ sub secondary_menu {
$showresv = 1;
}
}
- my %groups = &Apache::lonnet::get_active_groups(
- $env{'user.domain'}, $env{'user.name'},$cdom,$cnum);
- if (%groups) {
- foreach my $group (keys(%groups)) {
+ if ($env{'request.course.groups'} ne '') {
+ foreach my $group (split(/:/,$env{'request.course.groups'})) {
+ next unless ($group =~ /^\w+$/);
my @privs = split(/:/,$env{"user.priv.$env{'request.role'}./$cdom/$cnum/$group"});
shift(@privs);
if (@privs) {
@@ -442,6 +509,28 @@ sub secondary_menu {
}
}
}
+ if ($env{'request.lti.login'}) {
+ $lti = 1;
+ if (ref($ltimenu) eq 'HASH') {
+ foreach my $item ('fullname','coursetitle','role','logout','grades') {
+ unless ($ltimenu->{$item}) {
+ $ltiexc{$item} = 1;
+ }
+ }
+ }
+ if (($ltiscope eq 'map') || ($ltiscope eq 'resource')) {
+ $ltimapres = 1;
+ }
+ }
+ }
+ if (($menucoll) && (ref($menuref) eq 'HASH')) {
+ %menuopts = %{$menuref};
+ }
+
+ my ($listclass,$linkattr);
+ if ($links_disabled) {
+ $listclass = 'LCisDisabled';
+ $linkattr = 'aria-disabled="true"';
}
my ($canmodifycoauthor);
@@ -452,10 +541,14 @@ sub secondary_menu {
$canmodifycoauthor = 1;
}
}
- my ($roleswitcher_js,$roleswitcher_form,$ltitarget);
+
+ my ($roleswitcher_js,$roleswitcher_form,$ltitarget,$deeplinktarget);
if ($env{'request.lti.login'}) {
$ltitarget = $env{'request.lti.target'};
}
+ if ($env{'request.deeplink.login'}) {
+ $deeplinktarget = $env{'request.deeplink.target'};
+ }
foreach my $menuitem (@secondary_menu) {
# evaluate conditions
@@ -467,7 +560,7 @@ sub secondary_menu {
next if $$menuitem[4] =~ /^crsedit/
&& (!$canedit && !$canvieweditor);
next if $$menuitem[4] eq 'nvgr'
- && $canvgr;
+ && ($canvgr || $ltiexc{'grades'});
next if $$menuitem[4] eq 'vgr'
&& !$canvgr;
next if $$menuitem[4] eq 'viewusers'
@@ -488,17 +581,32 @@ sub secondary_menu {
&& !$showsyllabus;
next if $$menuitem[4] eq 'showfeeds'
&& !$showfeeds;
+ next if $$menuitem[4] eq 'plc'
+ && !$canplc;
next if $$menuitem[4] eq 'author'
&& !$author;
next if $$menuitem[4] eq 'cca'
&& !$canmodifycoauthor;
+ next if $$menuitem[4] eq 'notltimapres'
+ && $ltimapres;
+ next if $$menuitem[4] eq 'notlti'
+ && $lti;
+ next if $$menuitem[4] eq 'lti'
+ && (!$lti || !$noprimary);
+ next if $$menuitem[3] eq 'Logout'
+ && $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') || ($deeplinktarget eq '_self')) {
$target = '_top';
}
} else {
@@ -518,24 +626,46 @@ sub secondary_menu {
next if ($item->[2] eq 'params' && !$canmodpara && !$canviewpara);
next if ($item->[2] eq 'author' && !$author);
next if ($item->[2] eq 'cca' && !$canmodifycoauthor);
+ next if ($item->[2] eq 'lti' && !$lti);
+ if ($item->[2] =~ /^lti(portfolio|wishlist|blog)$/) {
+ my $tool = $1;
+ next if !$lti;
+ next if (!&Apache::lonnet::usertools_access('','',$tool,
+ undef,'tools'));
+ }
push(@scndsub,$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 (@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 .= ''.&mt($title).'';
+ $menu .= ($listclass?'':'').
+ ''.
+ &mt($title).'';
}
}
} 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
+ $env{'course.' . $env{'request.course.id'} . '.domain'},
+ $env{'course.' . $env{'request.course.id'} . '.num'},
+ $httphost,$menucoll,$menuref
);
+ 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');
+ $menu .= ''.&Apache::loncommon::top_nav_help('Help').'';
} else {
if ($$menuitem[3] eq 'Syllabus' && $env{'request.course.id'}) {
my $url = $$menuitem[0];
@@ -549,17 +679,19 @@ 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 ($$menuitem[0] =~ m{^https?://}) {
- $$menuitem[0] = 'http://'.$ENV{'SERVER_NAME'}.$$menuitem[0];
- }
- unless ($$menuitem[0] =~ /(\&|\?)usehttp=1/) {
- $$menuitem[0] .= (($$menuitem[0]=~/\?/) ? '&' : '?').'usehttp=1';
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl())) {
+ unless ($$menuitem[0] =~ m{^https?://}) {
+ $$menuitem[0] = 'http://'.$ENV{'SERVER_NAME'}.$$menuitem[0];
+ }
+ unless ($$menuitem[0] =~ /(\&|\?)usehttp=1/) {
+ $$menuitem[0] .= (($$menuitem[0]=~/\?/) ? '&' : '?').'usehttp=1';
+ }
}
}
}
$$menuitem[0] = &HTML::Entities::encode($$menuitem[0],'&<>"');
}
- $menu .= &prep_menuitem(\@$menuitem,$ltitarget);
+ $menu .= &prep_menuitem(\@$menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr);
}
}
if ($menu =~ /\[url\].*\[symb\]/) {
@@ -582,6 +714,7 @@ sub secondary_menu {
}
$menu =~ s/\[uname\]/$$author{user}/g;
$menu =~ s/\[udom\]/$$author{dom}/g;
+ $menu =~ s/\[javascript\]/javascript:/g;
if ($env{'request.course.id'}) {
$menu =~ s/\[cnum\]/$cnum/g;
$menu =~ s/\[cdom\]/$cdom/g;
@@ -596,7 +729,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 '') {
@@ -611,7 +744,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 .= '';
return $menu;
@@ -621,7 +754,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 '';
}
@@ -665,6 +798,20 @@ sub build_submenu {
next unless (($env{'user.name'} ne '') && ($env{'user.domain'} ne ''));
$href =~ s/\[domain\]/$env{'user.domain'}/g;
$href =~ s/\[user\]/$env{'user.name'}/g;
+ } elsif (($href =~ m{^/adm/preferences\?}) && ($href =~ /\[returnurl\]/)) {
+ my $returnurl = $ENV{'REQUEST_URI'};
+ if ($ENV{'REQUEST_URI'} =~ m{/adm/preferences\?action=(?:changedomcoord|authorsettings)\&returnurl=([^\&]+)$}) {
+ $returnurl = $1;
+ }
+ if (($returnurl =~ m{^/adm/createuser($|\?action=)}) ||
+ ($returnurl =~ m{^/priv/$match_domain/$match_username}) ||
+ ($returnurl =~ m{^/res(/?$|/$match_domain/$match_username)})) {
+ $returnurl =~ s{\?.*$}{};
+ $returnurl = '&returnurl='.&HTML::Entities::encode($returnurl,'"<>&\'');
+ } else {
+ undef($returnurl);
+ }
+ $href =~ s/\[returnurl\]/$returnurl/;
}
unless (($href eq '') || ($href =~ /^\#/)) {
if ($target eq '_top') {
@@ -672,8 +819,10 @@ sub build_submenu {
}
}
- $menu .= '';
- $menu .= '' . $title . '';
+ $menu .= '';
+ $menu .= '' . $title . '';
$menu .= '';
}
}
@@ -682,7 +831,7 @@ sub build_submenu {
}
sub innerregister {
- my ($forcereg,$bread_crumbs,$group,$pagebuttonshide,$hostname) = @_;
+ my ($forcereg,$bread_crumbs,$group,$pagebuttonshide,$hostname,$ltiscope,$ltiuri) = @_;
my $const_space = ($env{'request.state'} eq 'construct');
my $is_const_dir = 0;
@@ -692,18 +841,13 @@ sub innerregister {
undef(@inlineremote);
- my ($mapurl,$resurl,$crstype,$navmap,$ltiscope,$ltiuri);
+ my ($mapurl,$resurl,$crstype,$navmap);
if ($env{'request.course.id'}) {
#
#course_type: Course, Community, or Placement
#
$crstype = &Apache::loncommon::course_type();
- if (($env{'request.lti.login'}) && ($env{'request.lti.uri'})) {
- my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
- my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
- ($ltiscope,$ltiuri) = &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'},$cdom,$cnum);
- }
if ($env{'request.symb'}) {
my $ignorenull;
unless ($env{'request.noversionuri'} eq '/adm/navmaps') {
@@ -920,6 +1064,13 @@ sub innerregister {
$currdir =~ s|[^/]+$||;
my $cleandisfn = &Apache::loncommon::escape_single($thisdisfn);
my $esc_currdir = &Apache::loncommon::escape_single($currdir);
+ my $pubfile = "/res/$udom/$uname/$thisdisfn";
+ my $candelete = 1;
+ if (-e $londocroot.$pubfile) {
+ unless (&Apache::lonnet::metadata($pubfile,'obsolete')) {
+ undef($candelete);
+ }
+ }
#
# Probably should be in mydesk.tab
#
@@ -927,7 +1078,18 @@ sub innerregister {
s&6&1&list.png&Directory&dir[_1]&golist('$esc_currdir')&List current directory
s&6&2&rtrv.png&Retrieve&version[_1]&gocstr('/adm/retrieve','/priv/$udom/$uname/$cleandisfn')&Retrieve old version
s&6&3&pub.png&Publish&resource[_3]&gocstr('/adm/publish','/priv/$udom/$uname/$cleandisfn')&Publish this resource
+s&7&3©.png&Copy&resource[_4]&gocstr('/adm/cfile?action=copy','/priv/$udom/$uname/$cleandisfn')&Copy this resource
+ENDMENUITEMS
+#
+# Rename and Delete only available if obsolete or unpublished
+#
+ if ($candelete) {
+ $menuitems .= (<