--- loncom/interface/lonmenu.pm 2011/02/15 14:54:51 1.347 +++ loncom/interface/lonmenu.pm 2012/05/23 00:29:22 1.369.2.5 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Routines to control the menu # -# $Id: lonmenu.pm,v 1.347 2011/02/15 14:54:51 wenzelju Exp $ +# $Id: lonmenu.pm,v 1.369.2.5 2012/05/23 00:29:22 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,8 +26,6 @@ # http://www.lon-capa.org/ # # -# There is one parameter controlling the action of this module: -# =head1 NAME @@ -35,7 +33,8 @@ Apache::lonmenu =head1 SYNOPSIS -Coordinates the response to clicking an image. +Loads contents of /home/httpd/lonTabs/mydesk.tab, +used to generate inline menu, and Main Menu page. This is part of the LearningOnline Network with CAPA project described at http://www.lon-capa.org. @@ -74,10 +73,19 @@ It is set to 'done' in the BEGIN block o =item @primary_menu The elements of this array reference arrays that are made up of the components -of those lines of mydesk.tab that start with prim. +of those lines of mydesk.tab that start with prim:. It is used by primary_menu() to generate the corresponding menu. It gets filled in the BEGIN block of this module. +=item %primary_sub_menu + +The keys of this hash reference are the names of items in the primary_menu array +which have sub-menus. For each key, the corresponding value is a reference to +an array containing components extracted from lines in mydesk.tab which begin +with primsub:. +This hash, which is used by primary_menu to generate sub-menus, is populated in +the BEGIN block. + =item @secondary_menu The elements of this array reference arrays that are made up of the components @@ -153,12 +161,12 @@ use Apache::lonhtmlcommon(); use Apache::loncommon(); use Apache::lonenc(); use Apache::lonlocal; +use Apache::lonmsg(); use LONCAPA qw(:DEFAULT :match); use HTML::Entities(); -use Apache::lonwishlist(); use vars qw(@desklines %category_names %category_members %category_positions - $readdesk @primary_menu @secondary_menu); + $readdesk @primary_menu %primary_submenu @secondary_menu %secondary_submenu); my @inlineremote; @@ -181,7 +189,7 @@ sub prep_menuitem { # primary_menu() evaluates @primary_menu and returns XHTML for the menu # that contains following links: -# About, Message, Roles, Help, Logout +# About, Message, Personal, Roles, Help, Logout # @primary_menu is filled within the BEGIN block of this module with # entries from mydesk.tab sub primary_menu { @@ -211,8 +219,54 @@ sub primary_menu { next if $$menuitem[4] eq 'courses' ##'Roles' wanted && !&Apache::loncommon::show_course(); ## - - if ($$menuitem[3] eq 'Help') { # special treatment for helplink + my $title = $menuitem->[3]; + if (defined($primary_submenu{$title})) { + my ($link,$target,$numsub); + if ($menuitem->[0] ne '') { + $link = $menuitem->[0]; + $target = '_top'; + } else { + $link = '#'; + } + if (ref($primary_submenu{$title}) eq 'ARRAY') { + $numsub = @{$primary_submenu{$title}}; + if ($numsub) { + $title = + ''.$title. + ''. + ' ▼'; + } + } + $menu .= '
  • '. + ''.$title.''; + if ($numsub) { + $menu .= ''; + } + $menu .= '
  • '; + } elsif ($$menuitem[3] eq 'Help') { # special treatment for helplink if ($public) { my $origmail = $Apache::lonnet::perlvar{'lonSupportEMail'}; my $defdom = &Apache::lonnet::default_login_domain(); @@ -268,12 +322,13 @@ sub secondary_menu { ? "/$env{'request.course.sec'}" : ''); my $canedit = &Apache::lonnet::allowed('mdc', $env{'request.course.id'}); - my $canviewgrps = &Apache::lonnet::allowed('vcg', $crs_sec); - my $canmodifyuser = &Apache::lonnet::allowed('cst', $crs_sec); - my $canviewwnew = &Apache::lonnet::allowed('whn', $crs_sec); + my $canviewroster = $env{'course.'.$env{'request.course.id'}.'.student_classlist_view'}; + my $canviewgrps = &Apache::lonnet::allowed('vcg', $crs_sec); + my $canmodifyuser = &Apache::lonnet::allowed('cst', $crs_sec); + my $canviewwnew = &Apache::lonnet::allowed('whn', $crs_sec); 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 $canmgr = &Apache::lonnet::allowed('mgr', $crs_sec); my $author = &getauthor(); my %groups = &Apache::lonnet::get_active_groups( @@ -289,6 +344,10 @@ sub secondary_menu { && !$env{'request.course.id'}; next if $$menuitem[4] =~ /^mdc/ && !$canedit; + next if $$menuitem[4] eq 'mdcCourse' + && ($crstype eq 'Community'); + next if $$menuitem[4] eq 'mdcCommunity' + && ($crstype eq 'Course'); next if $$menuitem[4] eq 'nvgr' && $canvgr; next if $$menuitem[4] eq 'vgr' @@ -296,7 +355,7 @@ sub secondary_menu { next if $$menuitem[4] eq 'cst' && !$canmodifyuser; next if $$menuitem[4] eq 'ncst' - && $canmodifyuser; + && ($canmodifyuser || !$canviewroster); next if $$menuitem[4] eq 'mgr' && !$canmgr; next if $$menuitem[4] eq 'nmgr' @@ -305,19 +364,76 @@ sub secondary_menu { && !$canviewwnew; next if $$menuitem[4] eq 'opa' && !$canmodpara; - next if $$menuitem[4] =~ /showgroups$/ - && !$canviewgrps - && !%groups; + next if $$menuitem[4] eq 'nvcg' + && ($canviewgrps || !%groups); next if $$menuitem[4] eq 'author' && !$author; - if ($$menuitem[3] eq 'Roles' && $env{'request.course.id'}) { + my $title = $menuitem->[3]; + if (defined($secondary_submenu{$title})) { + my ($link,$target,$numsub); + if ($menuitem->[0] ne '') { + $link = $menuitem->[0]; + $target = '_top'; + } else { + $link = '#'; + } + + my @scndsub; + if (ref($secondary_submenu{$title}) eq 'ARRAY') { + $numsub = 0; + foreach my $item (@{$secondary_submenu{$title}}) { + if (ref($item) eq 'ARRAY') { + next if ($item->[2] eq 'vgr' && !$canvgr); + next if ($item->[2] eq 'opa' && !$canmodpara); + next if ($item->[2] eq 'cst' && !$canmodifyuser); + next if ($item->[2] eq 'mgr' && !$canmgr); + next if ($item->[2] eq 'vcg' && !$canviewgrps); + push(@scndsub,$item); + $numsub ++; + } + } + if ($numsub) { + $title = + ''.$title. + ''. + ' ▼'; + } + } + $menu .= '
  • '. + ''.$title.''; + if ($numsub) { + $menu .= ''; + } + $menu .= '
  • '; + } elsif ($$menuitem[3] eq 'Roles' && $env{'request.course.id'}) { # special treatment for role selector my $roles_selector = &roles_selector( $env{'course.' . $env{'request.course.id'} . '.domain'}, $env{'course.' . $env{'request.course.id'} . '.num'} ); - $menu .= $roles_selector ? "
  • $roles_selector
  • " + $menu .= $roles_selector ? "
  • $roles_selector
  • " : ''; } else { $menu .= &prep_menuitem(\@$menuitem); @@ -334,9 +450,8 @@ sub secondary_menu { and ( $env{'request.noversionuri'} eq '' || !defined($env{'request.noversionuri'}))) { - ($escurl = $env{'request.filename'}) =~ - s{^/home/([^/]+)/public_html/(.*)$}{/priv/$1/$2}; - + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + ($escurl = $env{'request.filename'}) =~ s{^\Q$londocroot\E}{}; $escurl = &escape($escurl); } $menu =~ s/\[url\]/$escurl/g; @@ -359,9 +474,10 @@ sub innerregister { undef(@inlineremote); + my $resurl; if ( $env{'request.symb'} && $env{'request.course.id'} ) { - my ($mapurl,$rid,$resurl) = &Apache::lonnet::decode_symb(&Apache::lonnet::symbread()); + (my $mapurl, my $rid, $resurl) = &Apache::lonnet::decode_symb(&Apache::lonnet::symbread()); my $coursetitle = $env{'course.'.$env{'request.course.id'}.'.description'}; my $maptitle = &Apache::lonnet::gettitle($mapurl); @@ -410,7 +526,7 @@ sub innerregister { my $hwkadd=''; if ($env{'request.symb'} ne '' && - $env{'request.filename'}=~/\.(problem|exam|quiz|assess|survey|form|task)$/) { + $env{'request.filename'}=~/$LONCAPA::assess_re/) { if (&Apache::lonnet::allowed('mgr',$crs)) { $hwkadd.=&switch('','',7,2,'pgrd.png','Content Grades','grades[_4]', "gocmd('/adm/grades','gradingmenu')", @@ -427,6 +543,12 @@ sub innerregister { "gocmd('/adm/parmset','set')", 'Content Settings'); } + if ($env{'request.symb'}=~/^uploaded/ && + &Apache::lonnet::allowed('mdc',$crs)) { + $hwkadd.=&switch('','',7,4,'docs.png','Folder/Page Content','parms[_2]', + "gocmd('/adm/coursedocs','direct')", + 'Folder/Page Content'); + } # -- End Homework ### ### Determine whether or not to display the 'cstr' button for this @@ -446,7 +568,7 @@ sub innerregister { # # Set defaults for authors my ($top,$bottom) = ('con-','struct'); - my $action = "go('/priv/".$env{'user.name'}."');"; + my $action = "go('/priv/".$env{'user.domain'}.'/'.$env{'user.name'}."');"; my $cadom = $env{'request.role.domain'}; my $caname = $env{'user.name'}; my $desc = "Enter my construction space"; @@ -454,12 +576,12 @@ sub innerregister { if ($env{'request.role'} =~ /^ca/) { ($cadom,$caname)=($env{'request.role'}=~/($match_domain)\/($match_username)$/); ($top,$bottom) = ('co con-','struct'); - $action = "go('/priv/".$caname."');"; + $action = "go('/priv/".$cadom.'/'.$caname."');"; $desc = "Enter construction space as co-author"; } elsif ($env{'request.role'} =~ /^aa/) { ($cadom,$caname)=($env{'request.role'}=~/($match_domain)\/($match_username)$/); ($top,$bottom) = ('co con-','struct'); - $action = "go('/priv/".$caname."');"; + $action = "go('/priv/".$cadom.'/'.$caname."');"; $desc = "Enter construction space as assistant co-author"; } # Check that we are on the correct machine @@ -492,9 +614,13 @@ sub innerregister { $uploaded = &is_course_upload($file,$cnum,$cdom); } if (!$uploaded) { - $file=~s/^($match_domain)\/($match_username)/\/priv\/$2/; + + $file=~s{^(priv/$match_domain/$match_username)}{/$1}; + $file=~s{^($match_domain/$match_username)}{/priv/$1}; + # Check that the user has permission to edit this resource - ($cfuname,$cfudom)=&Apache::loncacc::constructaccess($file,$1); + my $setpriv = 1; + ($cfuname,$cfudom)=&Apache::loncacc::constructaccess($file,$setpriv); if (defined($cfudom)) { $home=&Apache::lonnet::homeserver($cfuname,$cfudom); my $allowed=0; @@ -555,6 +681,18 @@ sub innerregister { } } } + if ($env{'request.course.id'}) { + if ($resurl eq "public/$cdom/$cnum/syllabus") { + if ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ /\w/) { + if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { + $editbutton=&switch('','',6,1,'pcstr.png','Edit', + 'resource[_2]', + "go('/adm/courseprefs?phase=display&actions=courseinfo')", + 'Edit this resource'); + } + } + } + } ### ### # Prepare the rest of the buttons @@ -563,9 +701,11 @@ sub innerregister { # # We are in construction space # - my ($uname,$thisdisfn) = - ($env{'request.filename'}=~m|^/home/([^/]+)/public_html/(.*)|); - my $currdir = '/priv/'.$uname.'/'.$thisdisfn; + + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + my ($udom,$uname,$thisdisfn) = + ($env{'request.filename'}=~m{^\Q$londocroot/priv/\E([^/]+)/([^/]+)/(.*)$}); + my $currdir = '/priv/'.$udom.'/'.$uname.'/'.$thisdisfn; if ($currdir =~ m-/$-) { $is_const_dir = 1; } else { @@ -577,10 +717,10 @@ sub innerregister { # $menuitems=(<'); + } +# +# The Remote actually gets launched! +# + my $configmenu=&rawconfig(); + my $esclowerurl=&escape($lowerurl); + my $message=&mt('"Waiting for Remote Control window to load: "+[_1]','waited'); + return(< +// + +ENDREMOTESTARTUP +} + +sub setflags() { + return(< +// + +ENDSETFLAGS +} + +sub maincall() { + if ($env{'environment.remote'} eq 'off') { return ''; } + return(< +// + +ENDMAINCALL +} + +sub load_remote_msg { + my ($lowerurl)=@_; + + if ($env{'environment.remote'} eq 'off') { return ''; } + + my $esclowerurl=&escape($lowerurl); + my $link=&mt('[_1]Continue[_2] on in Inline Menu mode' + ,'' + ,''); + return(< +
    + +
    +

    +

    $link

    +ENDREMOTEFORM +} + +sub get_menu_name { + my $hostid = $Apache::lonnet::perlvar{'lonHostID'}; + $hostid =~ s/\W//g; + return 'LCmenu'.$hostid; +} + + +sub reopenmenu { + if ($env{'environment.remote'} eq 'off') { return ''; } + my $menuname = &get_menu_name(); + my $nothing = &Apache::lonhtmlcommon::javascript_nothing(); + return('window.open('.$nothing.',"'.$menuname.'","",false);'); +} + + +sub open { + my $returnval=''; + if ($env{'environment.remote'} eq 'off') { + return + ''; + } + my $menuname = &get_menu_name(); + +# unless (shift eq 'unix') { +# resizing does not work on linux because of virtual desktop sizes +# $returnval.=(< +ENDOPEN + return ''; +} + + # ================================================================== Raw Config sub clear { @@ -988,6 +1275,7 @@ sub rawconfig { ($env{'request.role'}=~/($match_domain)\/($match_username)$/); } $act =~ s/\$caname/$caname/g; + $act =~ s/\$cadom/$cadom/g; my $home = &Apache::lonnet::homeserver($caname,$cadom); my $allowed=0; my @ids=&Apache::lonnet::current_machine_ids(); @@ -1050,6 +1338,28 @@ sub check_for_rcrs { return $showreqcrs; } +# ======================================================================= Close + +sub close { + if ($env{'environment.remote'} eq 'off') { return ''; } + my $menuname = &get_menu_name(); + return(< +// + +ENDCLOSE +} + sub dc_popup_js { my %lt = &Apache::lonlocal::texthash( more => '(More ...)', @@ -1061,13 +1371,13 @@ function showCourseID() { document.getElementById('dccid').style.display='block'; document.getElementById('dccid').style.textAlign='left'; document.getElementById('dccid').style.textFace='normal'; - document.getElementById('dccidtext').innerHTML ='$lt{'less'}'; + document.getElementById('dccidtext').innerHTML ='$lt{'less'}'; return; } function hideCourseID() { document.getElementById('dccid').style.display='none'; - document.getElementById('dccidtext').innerHTML ='$lt{'more'}'; + document.getElementById('dccidtext').innerHTML ='$lt{'more'}'; return; } @@ -1103,15 +1413,26 @@ sub utilityfunctions { my $end_page_annotate = &Apache::loncommon::end_page({'js_ready' => 1}); + my $start_page_bookmark = + &Apache::loncommon::start_page('Bookmarks',undef, + {'only_body' => 1, + 'js_ready' => 1, + 'bgcolor' => '#BBBBBB',}); + + my $end_page_bookmark = + &Apache::loncommon::end_page({'js_ready' => 1}); + my $confirm_switch = &mt("Editing requires switching to the resource's home server.").'\n'. &mt('Switch server?'); + my $esc_url=&escape($currenturl); + my $esc_symb=&escape($currentsymb); return (<
    ' + +'
    Link Name:
    ' + +'
    Address:

    ' + +'$end_page_bookmark' ); + bmquery.document.close(); } ENDUTILITY @@ -1301,7 +1640,7 @@ sub roles_selector { my ($cdom,$cnum) = @_; my $crstype = &Apache::loncommon::course_type(); my $now = time; - my (%courseroles,%seccount); + my (%courseroles,%seccount,%courseprivs); my $is_cc; my $role_selector; my $ccrole; @@ -1309,7 +1648,17 @@ sub roles_selector { $ccrole = 'co'; } else { $ccrole = 'cc'; - } + } + my $priv; + my $destinationurl = $ENV{'REQUEST_URI'}; + my $reqprivs = &required_privs(); + if (ref($reqprivs) eq 'HASH') { + my $destination = $destinationurl; + $destination =~ s/(\?.*)$//; + if (exists($reqprivs->{$destination})) { + $priv = $reqprivs->{$destination}; + } + } if ($env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum}) { my ($start,$end) = split(/\./,$env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum}); @@ -1322,7 +1671,7 @@ sub roles_selector { } } if ($is_cc) { - &get_all_courseroles($cdom,$cnum,\%courseroles,\%seccount); + &get_all_courseroles($cdom,$cnum,\%courseroles,\%seccount,\%courseprivs,$priv); } else { my %gotnosection; foreach my $item (keys(%env)) { @@ -1338,6 +1687,18 @@ sub roles_selector { $gotnosection{$role} = 1; } } + if ($priv ne '') { + my $cnumsec = $cnum; + if ($sec ne '') { + $cnumsec .= "/$sec"; + } + $courseprivs{"$role./$cdom/$cnumsec./"} = + $env{"user.priv.$role./$cdom/$cnumsec./"}; + $courseprivs{"$role./$cdom/$cnumsec./$cdom/"} = + $env{"user.priv.$role./$cdom/$cnumsec./$cdom/"}; + $courseprivs{"$role./$cdom/$cnumsec./$cdom/$cnumsec"} = + $env{"user.priv.$role./$cdom/$cnumsec./$cdom/$cnumsec"}; + } if (ref($courseroles{$role}) eq 'ARRAY') { if ($sec ne '') { if (!grep(/^\Q$sec\E$/,@{$courseroles{$role}})) { @@ -1363,7 +1724,7 @@ sub roles_selector { } my @roles_order = ($ccrole,'in','ta','ep','ad','st'); if (keys(%courseroles) > 1) { - $role_selector = &jump_to_role($cdom,$cnum,\%seccount,\%courseroles); + $role_selector = &jump_to_role($cdom,$cnum,\%seccount,\%courseroles,\%courseprivs,$priv); $role_selector .= '
    '."\n". ''."\n". + &HTML::Entities::encode($destinationurl).'" />'."\n". ''."\n". ''."\n". ''."\n". @@ -1389,8 +1750,9 @@ sub roles_selector { } sub get_all_courseroles { - my ($cdom,$cnum,$courseroles,$seccount) = @_; - unless ((ref($courseroles) eq 'HASH') && (ref($seccount) eq 'HASH')) { + my ($cdom,$cnum,$courseroles,$seccount,$courseprivs) = @_; + unless ((ref($courseroles) eq 'HASH') && (ref($seccount) eq 'HASH') && + (ref($courseprivs) eq 'HASH')) { return; } my ($result,$cached) = @@ -1398,9 +1760,11 @@ sub get_all_courseroles { if (defined($cached)) { if (ref($result) eq 'HASH') { if ((ref($result->{'roles'}) eq 'HASH') && - (ref($result->{'seccount'}) eq 'HASH')) { + (ref($result->{'seccount'}) eq 'HASH') && + (ref($result->{'privs'}) eq 'HASH')) { %{$courseroles} = %{$result->{'roles'}}; %{$seccount} = %{$result->{'seccount'}}; + %{$courseprivs} = %{$result->{'privs'}}; return; } } @@ -1428,30 +1792,43 @@ sub get_all_courseroles { push(@{$courseroles->{$urole}},$usec); } } + my $area = '/'.$cdom.'/'.$cnum; + if ($usec ne '') { + $area .= '/'.$usec; + } + if ($role =~ /^cr\//) { + &Apache::lonnet::custom_roleprivs($courseprivs,$urole,$cdom,$cnum,$urole.'.'.$area,$area); + } else { + &Apache::lonnet::standard_roleprivs($courseprivs,$urole,$cdom,$urole.'.'.$area,$cnum,$area); + } } my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum,['st']); @{$courseroles->{'st'}} = (); + &Apache::lonnet::standard_roleprivs($courseprivs,'st',$cdom,"st./$cdom/$cnum",$cnum,"/$cdom/$cnum"); if (keys(%sections_count) > 0) { push(@{$courseroles->{'st'}},keys(%sections_count)); - $seccount->{'st'} = scalar(keys(%sections_count)); + $seccount->{'st'} = scalar(keys(%sections_count)); } my $rolehash = { 'roles' => $courseroles, 'seccount' => $seccount, + 'privs' => $courseprivs, }; &Apache::lonnet::do_cache_new('getcourseroles',$cdom.'_'.$cnum,$rolehash); return; } sub jump_to_role { - my ($cdom,$cnum,$seccount,$courseroles) = @_; + my ($cdom,$cnum,$seccount,$courseroles,$courseprivs,$priv) = @_; my %lt = &Apache::lonlocal::texthash( this => 'This role has section(s) associated with it.', ente => 'Enter a specific section.', orlb => 'Enter a specific section, or leave blank for no section.', avai => 'Available sections are:', youe => 'You entered an invalid section choice:', - plst => 'Please try again', + plst => 'Please try again.', + role => 'The role you selected is not permitted to view the current page.', + swit => 'Switch role, but display Main Menu page instead?', ); my $js; if (ref($courseroles) eq 'HASH') { @@ -1474,6 +1851,37 @@ sub jump_to_role { ' numsec['.$i.'] = "'.$seccount->{$items[$i]}.'";'."\n"; } } + my $checkroles = 0; + if ($priv && ref($courseprivs) eq 'HASH') { + my (%disallowed,%allowed,@disallow); + foreach my $role (sort(keys(%{$courseprivs}))) { + my $trole; + if ($role =~ m{^(.+?)\Q./$cdom/$cnum\E}) { + $trole = $1; + } + if (($trole ne '') && ($trole ne 'cm')) { + if ($courseprivs->{$role} =~ /\Q:$priv\E($|:|\&\w+)/) { + $allowed{$trole} = 1; + } else { + $disallowed{$trole} = 1; + } + } + } + foreach my $trole (keys(%disallowed)) { + unless ($allowed{$trole}) { + push(@disallow,$trole); + } + } + if (@disallow > 0) { + $checkroles = 1; + $js .= " var disallow = new Array('".join("','",@disallow)."');\n". + " var rolecheck = 1;\n"; + } + } + if (!$checkroles) { + $js .= " var disallow = new Array();\n". + " rolecheck = 0;\n"; + } return <<"END";