--- loncom/interface/lonparmset.pm 2020/12/24 00:37:30 1.598 +++ loncom/interface/lonparmset.pm 2022/04/28 15:30:34 1.607 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set parameters for assessments # -# $Id: lonparmset.pm,v 1.598 2020/12/24 00:37:30 raeburn Exp $ +# $Id: lonparmset.pm,v 1.607 2022/04/28 15:30:34 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -978,7 +978,7 @@ sub storeparm_by_symb_inner { # @param {string} $type - the parameter type # @param {boolean} $editable - Set to true to get an icon when no value is defined. sub valout { - my ($value,$type,$name,$editable)=@_; + my ($value,$type,$editable)=@_; my $result = ''; # Values of zero are valid. if (! $value && $value ne '0') { @@ -1245,9 +1245,10 @@ function validateParms() { var ipallowRegExp = /^setipallow_/; var ipdenyRegExp = /^setipdeny_/; var deeplinkRegExp = /^deeplink_/; - var dlListScopeRegExp = /^deeplink_(listing|scope)_/; - var dlLinkUrlsRegExp = /^deeplink_urls_/; - var dlLtiRegExp = /^deeplink_lti_/; + var dlListScopeRegExp = /^deeplink_(state|others|listing|scope)_/; + var dlLinkProtectRegExp = /^deeplink_protect_/; + var dlLtidRegExp = /^deeplink_ltid_/; + var dlLticRegExp = /^deeplink_ltic_/; var dlKeyRegExp = /^deeplink_key_/; var dlMenusRegExp = /^deeplink_menus_/; var dlCollsRegExp = /^deeplink_colls_/; @@ -1314,9 +1315,9 @@ function validateParms() { } document.parmform.elements['set_'+identifier].value += possdeeplink; } - } else if (dlLinkUrlsRegExp.test(name)) { + } else if (dlLinkProtectRegExp.test(name)) { if (document.parmform.elements[i].checked) { - var identifier = name.replace(dlLinkUrlsRegExp,''); + var identifier = name.replace(dlLinkProtectRegExp,''); var posslinkurl = document.parmform.elements[i].value; posslinkurl = posslinkurl.replace(/^\s+|\s+$/g,''); if (document.parmform.elements['set_'+identifier].value) { @@ -1324,25 +1325,41 @@ function validateParms() { } document.parmform.elements['set_'+identifier].value += posslinkurl; } - } else if (dlLtiRegExp.test(name)) { - var identifier = name.replace(dlLtiRegExp,''); - if (isRadioSet('deeplink_urls_'+identifier,'lti')) { - var posslti = document.parmform.elements[i].value; - posslti = posslti.replace(/\D+/g,''); - if (posslti.length) { + } else if (dlLtidRegExp.test(name)) { + var identifier = name.replace(dlLtidRegExp,''); + if (isRadioSet('deeplink_protect_'+identifier,'ltid')) { + var possltid = document.parmform.elements[i].value; + possltid = possltid.replace(/\D+/g,''); + if (possltid.length) { if (document.parmform.elements['set_'+identifier].value) { - posslti = ':'+posslti; + possltid = ':'+possltid; } - document.parmform.elements['set_'+identifier].value += posslti; + document.parmform.elements['set_'+identifier].value += possltid; } else { document.parmform.elements['set_'+identifier].value = ''; - alert("A link type of 'deep with LTI launch' was selected but no LTI launcher was selected.\nPlease select one, or choose a different supported link type."); + alert("A link type of 'domain LTI launch' was selected but no domain LTI launcher was selected.\nPlease select one, or choose a different supported link type."); return false; } } + } else if (dlLticRegExp.test(name)) { + var identifier = name.replace(dlLticRegExp,''); + if (isRadioSet('deeplink_protect_'+identifier,'ltic')) { + var possltic = document.parmform.elements[i].value; + possltic = possltic.replace(/\D+/g,''); + if (possltic.length) { + if (document.parmform.elements['set_'+identifier].value) { + possltic = ':'+possltic; + } + document.parmform.elements['set_'+identifier].value += possltic; + } else { + document.parmform.elements['set_'+identifier].value = ''; + alert("A link type of 'course LTI launch' was selected but no course LTI launcher was selected.\nPlease select one, or choose a different supported link type."); + return false; + } + } } else if (dlKeyRegExp.test(name)) { var identifier = name.replace(dlKeyRegExp,''); - if (isRadioSet('deeplink_urls_'+identifier,'key')) { + if (isRadioSet('deeplink_protect_'+identifier,'key')) { var posskey = document.parmform.elements[i].value; posskey = posskey.replace(/^\s+|\s+$/g,''); var origlength = posskey.length; @@ -1478,32 +1495,44 @@ function toggleDeepLink(form,item,key) { if (document.getElementById('deeplink_key_'+item+'_'+key)) { keybox = document.getElementById('deeplink_key_'+item+'_'+key); } - var divoption; - if (item == 'urls') { - divoption = 'lti' + var divoptions = new Array(); + if (item == 'protect') { + divoptions = ['ltic','ltid']; } else { if (item == 'menus') { - divoption = 'colls'; + divoptions = ['colls']; } } - var seldiv; - if (document.getElementById('deeplinkdiv_'+divoption+'_'+item+'_'+key)) { - seldiv = document.getElementById('deeplinkdiv_'+divoption+'_'+item+'_'+key); + var seldivs = new Array(); + if ((item == 'protect') || (item == 'menus')) { + for (var i=0; i $b } (keys(%lti))) { + if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) { + $domltistr .= $item.':'.&escape(&escape($lti{$item}{'name'})).','; } } + $domltistr =~ s/,$//; + if ($domltistr) { + $extra = 'ltid_'.$domltistr; + } } - if (keys(%posslti)) { - $extra = 'lti_'; - foreach my $lti (sort { $a <=> $b } keys(%posslti)) { - $extra .= $lti.':'.&escape(&escape($posslti{$lti})).','; + my %courselti = &Apache::lonnet::get_course_lti($cnum,$cdom); + if (keys(%courselti)) { + foreach my $item (sort { $a <=> $b } keys(%courselti)) { + if (($item =~ /^\d+$/) && (ref($courselti{$item}) eq 'HASH')) { + $crsltistr .= $item.':'.&escape(&escape($courselti{$item}{'name'})).','; + } + } + $crsltistr =~ s/,$//; + if ($crsltistr) { + if ($extra) { + $extra .= '&'; + } + $extra .= 'ltic_'.$crsltistr; } - $extra =~ s/,$//; } if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) { my @colls; @@ -1912,9 +1953,7 @@ sub print_td { $nolink = 1; } } elsif ($mprefix =~ /availablestudent\&$/) { - if ($which > 4) { - $nolink = 1; - } + $nolink = 1; } elsif ($mprefix =~ /examcode\&$/) { unless ($which == 2) { $nolink = 1; @@ -2048,11 +2087,22 @@ sub extractResourceInformation { my $uris=shift; my $keyorder=shift; my $defkeytype=shift; + my $pssymb=shift; my $keyordercnt=100; my $navmap = Apache::lonnavmaps::navmap->new(); - my @allres=$navmap->retrieveResources(undef,undef,1,undef,1); + return unless(ref($navmap)); + my @allres; + if ($pssymb ne '') { + my $res = $navmap->getBySymb($pssymb); + if (ref($res)) { + @allres = ($res); + } + } + if (!@allres) { + @allres=$navmap->retrieveResources(undef,undef,1,undef,1); + } foreach my $resource (@allres) { my $id=$resource->id(); my ($mapid,$resid)=split(/\./,$id); @@ -2176,7 +2226,7 @@ sub isdateparm { sub is_specialstring { my $type=shift; - return (($type=~/^string_/) && (($type ne 'string_yesno'))); + return (($type=~/^string_/) && ($type ne 'string_yesno')); } # Prints the HTML and Javascript to select parameters, with various shortcuts. @@ -3325,7 +3375,7 @@ sub assessparms { # --------------------------------------------------------- Get all assessments &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps, \%mapp, \%symbp,\%maptitles,\%uris, - \%keyorder); + \%keyorder,undef,$pssymb); %allmaps_inverted = reverse(%allmaps); @@ -3342,6 +3392,7 @@ sub assessparms { my $chome = $env{'course.'.$env{'request.course.id'}.'.home'}; my ($got_chostname,$chostname,$cmajor,$cminor); my $totalstored = 0; + my $totalskippeduser = 0; my $now = time; for (my $i=0;$i<=$#markers;$i++) { my ($needsrelease,$needsnewer,$name,$namematch); @@ -3350,6 +3401,11 @@ sub assessparms { } if ($markers[$i] =~ /\&(8|7|6|5)$/) { next if ($noeditgrp); + } elsif ($markers[$i] =~ /\&(4|3|2|1)$/) { + if ($uname eq '') { + $totalskippeduser ++; + next; + } } if ($markers[$i] =~ /\&(17|11|7|3)$/) { $namematch = 'maplevelrecurse'; @@ -3488,9 +3544,27 @@ sub assessparms { # ---------------------------------------------------------------- Done storing if ($totalstored) { $message.='

' + .&mt('Changes for [quant,_1,parameter] saved.',$totalstored) + .'
' .&mt('Changes can take up to 10 minutes before being active for all students.') .&Apache::loncommon::help_open_topic('Caching') .'

'; + } else { + $message.='

'.&mt('No parameter changes saved.').'

'; + } + if ($totalskippeduser) { + $message .= '

'; + if ($uhome eq 'no_host') { + $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the username or ID was invalid.', + $totalskippeduser); + } elsif ($env{'form.userroles'} eq 'any') { + $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user does not have a course role.', + $totalskippeduser); + } else { + $message .= &mt('Changes for [quant,_1,user-specific parameter] not saved because the user is not a student.', + $totalskippeduser); + } + $message .= '

'; } } @@ -3521,13 +3595,20 @@ sub assessparms { # ----- Start Parameter Selection - # Hide parm selection? + # Hide parm selection and possibly table? + my ($tablejs,$tabledivsty); + if (((($env{'form.uname'} ne '') || ($env{'form.id'} ne '')) && ($uname eq '')) && + ($env{'form.dis'}) && ($pssymb eq '')) { + $tablejs = 'document.getElementById('."'parmtable'".').style.display = "";'; + $tabledivsty = ' style="display:none"'; + } $r->print(< // @@ -3634,6 +3715,7 @@ ENDPARMSELSCRIPT if ($parm_permission->{'edit'}) { undef($readonly); } + $r->print('
'); if ($parmlev eq 'full') { # @@ -3850,7 +3932,7 @@ ENDTABLEHEADFOUR #-------------------------------------------- for each map, gather information my $mapid; - foreach $mapid (sort {$maplist{$a} cmp $maplist{$b}} keys(%maplist)) { + foreach $mapid (sort { $a <=> $b } keys(%maplist)) { my $maptitle = $maplist{$mapid}; #----------------------- loop through ids and get all parameter types for map @@ -4067,6 +4149,7 @@ ENDMAPONE .'' ); } # end of $parmlev eq general + $r->print('
'); } $r->print(''); if ($numreclinks) { @@ -4680,6 +4763,7 @@ sub listdata { ($thiskey=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/); my $section=&mt('All Students'); $readonly = $readonlyall; + my $userscope; my $showval = $$resourcedata{$thiskey}; if ($middle=~/^\[(.*)\]/) { my $issection=$1; @@ -4693,6 +4777,7 @@ sub listdata { } } $section=&mt('User').": ".&Apache::loncommon::plainname($stuname,$studom); + $userscope = 1; } else { if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) { if (exists($grouphash{$issection})) { @@ -4790,8 +4875,13 @@ sub listdata { ''.&mt($parmitem). ''); unless ($readonly) { + my $disabled; + if (($name eq 'availablestudent') && + (($showval eq '') || ($userscope))) { + $disabled = ' disabled="disabled"'; + } $r->print(''); + $thiskey.'"'.$disabled.' />'); } $r->print(''); $foundkeys++; @@ -4819,6 +4909,9 @@ sub listdata { $r->print(&date_interval_selector($thiskey,$name, $showval,$readonly)); } elsif ($thistype =~ m/^string/) { + if ($name eq 'availablestudent') { + $readonly = 1; + } $r->print(&string_selector($thistype,$thiskey, $showval,$name,$readonly)); } else { @@ -4974,21 +5067,30 @@ sub string_ip_selector { sub string_deeplink_selector { my ($thiskey, $showval, $readonly) = @_; my (@components,%values,@current,%titles,%options,%optiontext,%defaults, - %selectnull,%posslti,@possmenus); - @components = ('listing','scope','urls','menus'); + %selectnull,%domlti,%crslti,@possmenus); + @components = ('state','others','listing','scope','protect','menus'); %titles = &Apache::lonlocal::texthash ( + state => 'Access status', + others => 'Hide other resources', listing => 'In Contents and/or Gradebook', scope => 'Access scope for link', - urls => 'Supported link types', + protect => 'Link protection', menus => 'Menu Items Displayed', ); %options = ( + state => ['only','off','both'], + others => ['hide','unhide'], listing => ['full','absent','grades','details','datestatus'], scope => ['res','map','rec'], - urls => ['any','only','key','lti'], + protect => ['none','key','ltid','ltic'], menus => ['std','colls'], ); %optiontext = &Apache::lonlocal::texthash ( + only => 'deep only', + off => 'deeplink off', + both => 'regular + deep', + hide => 'Hidden', + unhide => 'Unhidden', full => 'Listed (linked) in both', absent => 'Not listed', grades => 'Listed in grades only', @@ -4997,42 +5099,53 @@ sub string_deeplink_selector { res => 'resource only', map => 'enclosing map/folder', rec => 'recursive map/folder', - any => 'regular + deep', - only => 'deep only', - key => 'deep with key', - lti => 'deep with LTI launch', + none => 'not in use', + key => 'key access', + ltic => 'LTI access (course)', + ltid => 'LTI access (domain)' , std => 'Standard (all menus)', colls => 'Numbered collection', ); %selectnull = &Apache::lonlocal::texthash ( - lti => 'Select Provider', + ltic => 'Select Launcher', + ltid => 'Select Launcher', colls => 'Select', ); if ($showval =~ /,/) { %values=(); @current = split(/,/,$showval); - ($values{'listing'}) = ($current[0] =~ /^(full|absent|grades|details|datestatus)$/); - ($values{'scope'}) = ($current[1] =~ /^(res|map|rec)$/); - ($values{'urls'}) = ($current[2] =~ /^(any|only|key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|lti:\d+)$/); - ($values{'menus'}) = ($current[3] =~ /^(\d+)$/); + ($values{'state'}) = ($current[0] =~ /^(only|off|both)$/); + ($values{'others'}) = ($current[1] =~ /^(hide|unhide)$/); + ($values{'listing'}) = ($current[2] =~ /^(full|absent|grades|details|datestatus)$/); + ($values{'scope'}) = ($current[3] =~ /^(res|map|rec)$/); + ($values{'protect'}) = ($current[4] =~ /^(key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|ltic:\d+|ltid:\d+)$/); + ($values{'menus'}) = ($current[5] =~ /^(\d+)$/); } else { + $defaults{'state'} = 'off', + $defaults{'others'} = 'unhide', $defaults{'listing'} = 'full'; $defaults{'scope'} = 'res'; - $defaults{'urls'} = 'any'; + $defaults{'protect'} = 'none'; $defaults{'menus'} = '0'; } my $disabled; if ($readonly) { $disabled=' disabled="disabled"'; } - my %lti = + my %courselti = + &Apache::lonnet::get_course_lti($env{'course.'.$env{'request.course.id'}.'.num'}, + $env{'course.'.$env{'request.course.id'}.'.domain'}); + foreach my $item (keys(%courselti)) { + if (ref($courselti{$item}) eq 'HASH') { + $crslti{$item} = $courselti{$item}{'name'}; + } + } + my %lti = &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'}, - 'provider'); + 'linkprot'); foreach my $item (keys(%lti)) { - if (ref($lti{$item}) eq 'HASH') { - unless ($lti{$item}{'requser'}) { - $posslti{$item} = $lti{$item}{'consumer'}; - } + if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) { + $domlti{$item} = $lti{$item}{'name'}; } } if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) { @@ -5051,11 +5164,15 @@ sub string_deeplink_selector { $output .= ''; foreach my $item (@components) { $output .= ''; - if (($item eq 'urls') || ($item eq 'menus')) { + if (($item eq 'protect') || ($item eq 'menus')) { my $selected = $values{$item}; foreach my $option (@{$options{$item}}) { - if (($item eq 'urls') && ($option eq 'lti')) { - next unless (keys(%posslti)); + if ($item eq 'protect') { + if ($option eq 'ltid') { + next unless (keys(%domlti)); + } elsif ($option eq 'ltic') { + next unless (keys(%crslti)); + } } elsif (($item eq 'menus') && ($option eq 'colls')) { next unless (@possmenus); } @@ -5080,7 +5197,7 @@ sub string_deeplink_selector { $output .= ''; - if (($item eq 'urls') && ($option eq 'key')) { + if (($item eq 'protect') && ($option eq 'key')) { my $visibility="hidden"; my $currkey; if ($checked) { @@ -5089,12 +5206,12 @@ sub string_deeplink_selector { } $output .= ' '. ''; - } elsif (($option eq 'lti') || ($option eq 'colls')) { + } elsif (($option eq 'ltic') || ($option eq 'ltid') || ($option eq 'colls')) { my $display="none"; my ($current,$blankcheck,@possibles); if ($checked) { $display = 'inline-block'; - if ($option eq 'lti') { + if (($option eq 'ltic') || ($option eq 'ltid')) { $current = (split(/\:/,$selected))[1]; } else { $current = $selected; @@ -5102,8 +5219,10 @@ sub string_deeplink_selector { } else { $blankcheck = ' selected="selected"'; } - if ($option eq 'lti') { - @possibles = keys(%posslti); + if ($option eq 'ltid') { + @possibles = keys(%domlti); + } elsif ($option eq 'ltic') { + @possibles = keys(%crslti); } else { @possibles = @possmenus; } @@ -5120,8 +5239,10 @@ sub string_deeplink_selector { $selected = ' selected="selected"'; } my $shown = $poss; - if ($option eq 'lti') { - $shown = $posslti{$poss}; + if ($option eq 'ltid') { + $shown = $domlti{$poss}; + } elsif ($option eq 'ltic') { + $shown = $crslti{$poss}; } $output .= ''; } @@ -5198,7 +5319,7 @@ my %stringmatches = ( => [['_allowfrom_','[^\!]+'], ['_denyfrom_','\!']], 'string_deeplink' - => [['on','^(full|absent|grades|details|datestatus)\,(res|map|rec)\,(any|only|key\:\w+|lti\:\d+)\,(\d+|)$']], + => [['on','^(only|off|both)\,(hide|unhide)\,(full|absent|grades|details|datestatus)\,(res|map|rec)\,(none|key\:\w+|ltic\:\d+|ltid\:\d+)\,(\d+|)$']], ); my %stringtypes = ( @@ -5805,7 +5926,7 @@ ENDOVER &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps, \%mapp, \%symbp,\%maptitles,\%uris, - \%keyorder,\%defkeytype); + \%keyorder,\%defkeytype,$pssymb); if (grep {$_ eq 'all'} (@psprt)) { @psprt = keys(%allparts);