--- loncom/interface/lonhelper.pm 2010/09/02 00:19:17 1.180.2.2 +++ loncom/interface/lonhelper.pm 2018/08/29 20:21:30 1.201 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # .helper XML handler to implement the LON-CAPA helper # -# $Id: lonhelper.pm,v 1.180.2.2 2010/09/02 00:19:17 raeburn Exp $ +# $Id: lonhelper.pm,v 1.201 2018/08/29 20:21:30 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -64,9 +64,11 @@ messages, resource selections, or date q The helper tag is required to have one attribute, "title", which is the name of the helper itself, such as "Parameter helper". The helper tag may optionally -have a "requiredpriv" attribute, specifying the priviledge a user must have +have a "requiredpriv" attribute, specifying the privilege a user must have to use the helper, or get denied access. See loncom/auth/rolesplain.tab for -useful privs. Default is full access, which is often wrong! +useful privs. You may add the modifier &S at the end of the three letter priv +if you want to grant access to users for whom the corresponding privilege is +section-specific. The default is full access, which is often wrong! =head2 State tags @@ -261,7 +263,7 @@ sub real_handler { my $uri = shift; if (!defined($uri)) { $uri = $r->uri(); } $env{'request.uri'} = $uri; - my $filename = '/home/httpd/html' . $uri; + my $filename = $r->dir_config('lonDocRoot').$uri; my $fh = Apache::File->new($filename); my $file; read $fh, $file, 100000000; @@ -283,7 +285,8 @@ sub real_handler { my $allowed = $helper->allowedCheck(); if (!$allowed) { - $env{'user.error.msg'} = $env{'request.uri'}.':'.$helper->{REQUIRED_PRIV}. + my ($priv,$modifier) = split(/\&/,$helper->{REQUIRED_PRIV}); + $env{'user.error.msg'} = $env{'request.uri'}.':'.$priv. ":0:0:Permission denied to access this helper."; return HTTP_NOT_ACCEPTABLE; } @@ -508,8 +511,13 @@ sub allowedCheck { if (!defined($self->{REQUIRED_PRIV})) { return 1; } - - return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $env{'request.course.id'}); + my ($priv,$modifier) = split(/\&/,$self->{REQUIRED_PRIV}); + my $allowed = &Apache::lonnet::allowed($priv,$env{'request.course.id'}); + if ((!$allowed) && ($modifier eq 'S') && ($env{'request.course.sec'} ne '')) { + $allowed = &Apache::lonnet::allowed($priv,$env{'request.course.id'}.'/'. + $env{'request.course.sec'}); + } + return $allowed; } sub changeState { @@ -651,7 +659,7 @@ sub display { $result .= $buttons; - #foreach my $key (keys %{$self->{VARS}}) { + #foreach my $key (keys(%{$self->{VARS}})) { # $result .= "|$key| -> " . $self->{VARS}->{$key} . "
"; #} @@ -1476,9 +1484,9 @@ BUTTONS HTML::Entities::encode($choice->[1],"<>&\"'") . "'"; if ($checkedChoices{$choice->[1]}) { - $result .= " checked='checked' "; + $result .= " checked='checked'"; } - $result .= qq{id="id$id"}; + $result .= qq{ id="id$id"}; my $choiceLabel = $choice->[0]; if ($choice->[3]) { # if we need to evaluate this choice $choiceLabel = "sub { my $helper = shift; my $state = shift;" . @@ -1486,7 +1494,7 @@ BUTTONS $choiceLabel = eval($choiceLabel); $choiceLabel = &$choiceLabel($helper, $self); } - $result .= "/> ".qq{' } return $result; @@ -2033,7 +2047,9 @@ be filtered out. The 'addstatus' attribu and long status display columns to the display. The 'addparts' attribute will add in a part selector beside problems that have more than 1 part. The 'includecourse' attribute if true, will include -the toplevel default.sequence in the results. +the toplevel default.sequence in the results. The 'modalLink' attribute, +if true, will cause links to be launched as modal pop-ups, instead of +replacing the resource selection listing, currently being displayed. =head3 SUB-TAGS @@ -2145,6 +2161,7 @@ sub start_resource { $paramHash->{'toponly'} = $token->[2]{'toponly'}; $paramHash->{'addstatus'} = $token->[2]{'addstatus'}; $paramHash->{'addparts'} = $token->[2]{'addparts'}; + $paramHash->{'modalLink'} = $token->[2]{'modallink'}; if ($paramHash->{'addparts'}) { $helper->declareVar($paramHash->{'variable'}.'_part'); } @@ -2351,6 +2368,7 @@ BUTTONS my $option_texts = $self->{OPTION_TEXTS}; my $option_types = $self->{OPTION_TYPES}; my $addparts = $self->{'addparts'}; + my $modalLink = $self->{'modalLink'}; my $headings_done = 0; # Evaluate the map url as needed @@ -2390,7 +2408,7 @@ BUTTONS $result .= "$text"; } } - $result .= "Select"; + $result .= ''.&Apache::lonlocal::mt('Select').''; $result .= ""; # Close off the extra row and start a new one. $headings_done = 1; } @@ -2450,7 +2468,7 @@ BUTTONS $resource_name . "'/> "; } else { $col .= - " "; } @@ -2487,9 +2505,9 @@ BUTTONS &HTML::Entities::encode(&$valueFunc($resource),"<>&\"'"); if ($addparts && (scalar(@{$resource->parts}) > 1)) { $col .= ""; } @@ -2534,7 +2552,9 @@ RADIO 'closeAllPages' => $self->{'closeallpages'}, 'suppressEmptySequences' => $self->{'suppressEmptySequences'}, 'include_top_level_map' => $self->{'include_top_level_map'}, - 'iterator_map' => $mapUrl } + 'iterator_map' => $mapUrl, + 'map_no_edit_link' => 1, + 'modalLink' => $modalLink, } ); $result .= $buttons; @@ -2606,6 +2626,12 @@ selection. Defaults to false. If true, only active students and course personnel will be shown. Defaults to false. +=item * B: + +If true, and user's role is in a specific section, only course personnel +will be shown if they also have a section-specific role in the same section. +Defaults to false. + =item * B: If true, the selection of no users is allowed. Defaults to false. @@ -2641,6 +2667,7 @@ sub start_student { $helper->declareVar($paramHash->{'variable'}); $paramHash->{'multichoice'} = $token->[2]{'multichoice'}; $paramHash->{'coursepersonnel'} = $token->[2]{'coursepersonnel'}; + $paramHash->{'sectiononly'} = $token->[2]{'sectiononly'}; $paramHash->{'activeonly'} = $token->[2]{'activeonly'}; if (defined($token->[2]{'nextstate'})) { $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'}; @@ -2682,14 +2709,17 @@ sub render { delete($defaultUsers{''}); } + my $personnel_section; + if ($self->{'sectiononly'}) { + $personnel_section = $env{'request.course.sec'}; + } my ($course_personnel, $current_members, $expired_members, $future_members) = - &Apache::lonselstudent::get_people_in_class($env{'request.course.sec'}); - - + &Apache::lonselstudent::get_people_in_class($env{'request.course.sec'}, + $personnel_section); # Load up the non-students, if necessary @@ -2697,26 +2727,44 @@ sub render { unshift @$current_members, (@$course_personnel); } + my %titles = &Apache::lonlocal::texthash( + 'active' => 'Select Currently Enrolled Students and Active Course Personnel', + 'future' => 'Select Future Enrolled Students', + 'expired' => 'Select Previously Enrolled Students', + ); + + if ($env{'request.course.sec'}) { + if ($self->{'sectiononly'}) { + $titles{'active'} = &mt('Select Currently Enrolled Students and Active Course Personnel in Section: [_1]', + $env{'request.course.sec'}); + } else { + $titles{'active'} = &mt('Select Currently Enrolled Students in Section: [_1], and Active Course Personnel', + $env{'request.course.sec'}); + } + $titles{'future'} = &mt('Select Future Enrolled Students in Section: [_1]', + $env{'request.course.sec'}); + $titles{'expired'} = &mt('Select Previously Enrolled Students in Section: [_1]', + $env{'request.course.sec'}); + } - # Current personel + # Current personnel - $result .= '

'.&mt('Select Currently Enrolled Students and Active Course Personnel').'

'; + $result .= '

'.$titles{'active'}.'

'; $result .= &Apache::lonselstudent::render_student_list( $current_members, "helpform", - "current", + "current", \%defaultUsers, $self->{'multichoice'}, $self->{'variable'}, 1); - # If activeonly is not set then we can also give the expired students: # if (!$self->{'activeonly'} && ((scalar(@$future_members)) > 0)) { # And future. - $result .= '

'.&mt('Select Future Enrolled Students and Future Course Personnel').'

'; + $result .= '

'.$titles{'future'}.'

'; $result .= &Apache::lonselstudent::render_student_list( $future_members, "helpform", @@ -2729,7 +2777,7 @@ sub render { if (!$self->{'activeonly'} && ((scalar(@$expired_members)) > 0)) { # Past - $result .= '

'.&mt('Select Previously Enrolled Students and Inactive Course Personnel').'

'; + $result .= '

'.$titles{'expired'}.'

'; $result .= &Apache::lonselstudent::render_student_list($expired_members, "helpform", "past", @@ -2971,30 +3019,31 @@ BUTTONS } # Get the list of files in this directory. - my @fileList; + my (@fileList,$listref,$listerror); # If the subdirectory is in local CSTR space my $metadir; - if ($subdir =~ m|/home/([^/]+)/public_html/(.*)|) { - my ($user,$domain)= - &Apache::loncacc::constructaccess($subdir, - $Apache::lonnet::perlvar{'lonDefDomain'}); - $metadir='/res/'.$domain.'/'.$user.'/'.$2; - @fileList = &Apache::lonnet::dirlist($subdir,$domain,$user,undef,undef,'/'); - } elsif ($subdir =~ m|^~([^/]+)/(.*)$|) { - $subdir='/home/'.$1.'/public_html/'.$2; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + if ($subdir =~ m{^(?:\Q$londocroot\E)*/priv/[^/]+/[^/]+/(.*)$}) { + my $innerpath=$1; + unless ($subdir=~m{^\Q$londocroot\E}) { + $subdir=$londocroot.$subdir; + } my ($user,$domain)= - &Apache::loncacc::constructaccess($subdir, - $Apache::lonnet::perlvar{'lonDefDomain'}); - $metadir='/res/'.$domain.'/'.$user.'/'.$2; - @fileList = &Apache::lonnet::dirlist($subdir,$domain,$user,undef,undef,'/'); + &Apache::lonnet::constructaccess($subdir); + $metadir='/res/'.$domain.'/'.$user.'/'.$innerpath; + ($listref,$listerror) = + &Apache::lonnet::dirlist($subdir,$domain,$user,undef,undef,'/'); } else { # local library server resource space - @fileList = &Apache::lonnet::dirlist($subdir,$env{'user.domain'},$env{'user.name'},undef,undef,'/'); + ($listref,$listerror) = + &Apache::lonnet::dirlist($subdir,$env{'user.domain'},$env{'user.name'},undef,undef,'/'); } # Sort the fileList into order - @fileList = sort {lc($a) cmp lc($b)} @fileList; + if (ref($listref) eq 'ARRAY') { + @fileList = sort {lc($a) cmp lc($b)} @{$listref}; + } $result .= $buttons; @@ -3089,7 +3138,7 @@ sub fileState { } my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'}; my $subdirpart = $constructionSpaceDir; - $subdirpart =~ s/^\/home\/$uname\/public_html//; + $subdirpart =~ s{^\Q$docroot/priv/$udom/$uname\E}{}; my $resdir = $docroot . '/res/' . $udom . '/' . $uname . $subdirpart; @@ -3139,7 +3188,7 @@ It takes the standard attributes "variab "allowempty" and "nextstate", meaning what they do for most other elements. -also takes a boolean 'onlysections' whcih will restrict this to only +also takes a boolean 'onlysections' which will restrict this to only have sections and not include groups =cut @@ -3177,22 +3226,27 @@ sub start_section { # Populate the CHOICES element my %choices; + my $usersec = $Apache::lonnet::env{'request.course.sec'}; - my $section = Apache::loncoursedata::CL_SECTION(); - my $classlist = Apache::loncoursedata::get_classlist(); - foreach my $user (keys(%$classlist)) { - my $section_name = $classlist->{$user}[$section]; - if (!$section_name) { - $choices{"No section assigned"} = ""; - } else { - $choices{$section_name} = $section_name; + if ($usersec ne '') { + $choices{$usersec} = $usersec; + } else { + my $section = Apache::loncoursedata::CL_SECTION(); + my $classlist = Apache::loncoursedata::get_classlist(); + foreach my $user (keys(%$classlist)) { + my $section_name = $classlist->{$user}[$section]; + if (!$section_name) { + $choices{"No section assigned"} = ""; + } else { + $choices{$section_name} = $section_name; + } + } + + if (exists($choices{"No section assigned"})) { + push(@{$paramHash->{CHOICES}}, + ['No section assigned','No section assigned']); + delete($choices{"No section assigned"}); } - } - - if (exists($choices{"No section assigned"})) { - push(@{$paramHash->{CHOICES}}, - ['No section assigned','No section assigned']); - delete($choices{"No section assigned"}); } for my $section_name (sort {lc($a) cmp lc($b) } (keys(%choices))) { push @{$paramHash->{CHOICES}}, [$section_name, $section_name]; @@ -3228,6 +3282,10 @@ It takes the standard attributes "variab "allowempty" and "nextstate", meaning what they do for most other elements. +also takes a boolean grouponly, which if true, will restrict choice to +groups in which user is a member, unless user has the mdg priv in the course, +in which case all groups will be possible choices. Defaults to false. + =cut no strict; @@ -3257,6 +3315,7 @@ sub start_group { $helper->declareVar($paramHash->{'variable'}); $paramHash->{'multichoice'} = $token->[2]{'multichoice'}; $paramHash->{'allowempty'} = $token->[2]{'allowempty'}; + $paramHash->{'grouponly'} = $token->[2]{'grouponly'}; if (defined($token->[2]{'nextstate'})) { $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'}; } @@ -3264,7 +3323,12 @@ sub start_group { # Populate the CHOICES element my %choices; - my %curr_groups = &Apache::longroup::coursegroups(); + my %curr_groups; + if ((!$paramHash->{'grouponly'}) || (&Apache::lonnet::allowed('mdg',$Apache::lonnet::env{'request.course.id'}))) { + %curr_groups = &Apache::longroup::coursegroups(); + } elsif ($Apache::lonnet::env{'request.course.groups'} ne '') { + map { $curr_groups{$_} = 1; } split(/,/,$Apache::lonnet::env{'request.course.groups'}); + } foreach my $group_name (sort {lc($a) cmp lc($b)} (keys(%curr_groups))) { push(@{$paramHash->{CHOICES}}, [$group_name, $group_name]); } @@ -3364,7 +3428,7 @@ sub render { $result .= '

' . $self->{ERROR_MSG} . '

'; } - $result .= '{'variable'} . '_forminput"'; if (defined($self->{'size'})) { $result .= ' size="' . $self->{'size'} . '"'; @@ -3626,7 +3690,7 @@ sub render { my @results; # Collect all the results - for my $stateName (keys %{$helper->{STATES}}) { + for my $stateName (keys(%{$helper->{STATES}})) { my $state = $helper->{STATES}->{$stateName}; for my $element (@{$state->{ELEMENTS}}) { @@ -3679,10 +3743,8 @@ sub render { } my $previous = HTML::Entities::encode(&mt("Back"), '<>&"'); my $next = HTML::Entities::encode(&mt("Next"), '<>&"'); - my $target = " target='loncapaclient'"; - if ($env{'environment.remote'} eq 'off') { $target=''; } $result .= "

\n" . - "

\n" . + "\n" . "" . "" . "\n" . @@ -3769,38 +3831,54 @@ sub render { if ($vars->{GRANULARITY} eq 'whole_course') { $resourceString .= '
  • '.&mt('for [_1]all resources in the course[_2]','','').'
  • '; if ($vars->{TARGETS} eq 'course') { - $level = 14; # general course, see lonparmset.pm perldoc + $level = 18; # general course, see lonparmset.pm perldoc } elsif ($vars->{TARGETS} eq 'section') { - $level = 9; + $level = 12; } elsif ($vars->{TARGETS} eq 'group') { - $level = 6; + $level = 8; } else { - $level = 3; + $level = 4; } $affectedResourceId = "0.0"; $symb = 'a'; $paramlevel = 'general'; - } elsif ($vars->{GRANULARITY} eq 'map') { + } elsif (($vars->{GRANULARITY} eq 'map') || ($vars->{GRANULARITY} eq 'maprecurse')) { my $navmap = Apache::lonnavmaps::navmap->new(); if (defined($navmap)) { my $res = $navmap->getByMapPc($vars->{RESOURCE_ID}); my $title = $res->compTitle(); $symb = $res->symb(); - $resourceString .= '
  • '.&mt('for the map named [_1]',"$title").'
  • '; + if ($vars->{GRANULARITY} eq 'map') { + $resourceString .= '
  • '.&mt('for the map named [_1]',"$title").'
  • '; + } else { + $resourceString .= '
  • '.&mt('for the map named [_1] (applies recursively to sub-folders)',"$title").'
  • '; + } } else { $resourceString .= '
  • '.&mt('for the map ID [_1] (name unavailable)',''.$vars->{RESOURCE_ID}.'').'
  • '; &Apache::lonnet::logthis('Retrieval of map title failed in lonhelper.pm - could not create navmap object for course.'); } - if ($vars->{TARGETS} eq 'course') { - $level = 13; # general course, see lonparmset.pm perldoc - } elsif ($vars->{TARGETS} eq 'section') { - $level = 8; - } elsif ($vars->{TARGETS} eq 'group') { - $level = 5; - } else { - $level = 2; - } + if ($vars->{GRANULARITY} eq 'maprecurse') { + if ($vars->{TARGETS} eq 'course') { + $level = 17; # general course, see lonparmset.pm perldoc + } elsif ($vars->{TARGETS} eq 'section') { + $level = 11; + } elsif ($vars->{TARGETS} eq 'group') { + $level = 7; + } else { + $level = 3; + } + } else { + if ($vars->{TARGETS} eq 'course') { + $level = 16; # general course, see lonparmset.pm perldoc + } elsif ($vars->{TARGETS} eq 'section') { + $level = 10; + } elsif ($vars->{TARGETS} eq 'group') { + $level = 6; + } else { + $level = 2; + } + } $affectedResourceId = $vars->{RESOURCE_ID}; $paramlevel = 'map'; } else { @@ -3817,11 +3895,11 @@ sub render { &Apache::lonnet::logthis('Retrieval of resource title failed in lonhelper.pm - could not create navmap object for course.'); } if ($vars->{TARGETS} eq 'course') { - $level = 10; # general course, see lonparmset.pm perldoc + $level = 13; # general course, see lonparmset.pm perldoc } elsif ($vars->{TARGETS} eq 'section') { - $level = 7; + $level = 9; } elsif ($vars->{TARGETS} eq 'group') { - $level = 4; + $level = 5; } else { $level = 1; } @@ -3837,7 +3915,7 @@ sub render { if ($vars->{GRANULARITY} eq 'resource') { $result .= "&\"") . "' />\n"; - } elsif ($vars->{GRANULARITY} eq 'map') { + } elsif (($vars->{GRANULARITY} eq 'map') || ($vars->{GRANULARITY} eq 'maprecurse')) { $result .= "\n"; }