--- loncom/interface/lonparmset.pm 2016/07/12 20:30:20 1.560 +++ loncom/interface/lonparmset.pm 2020/02/10 19:48:56 1.595 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set parameters for assessments # -# $Id: lonparmset.pm,v 1.560 2016/07/12 20:30:20 damieng Exp $ +# $Id: lonparmset.pm,v 1.595 2020/02/10 19:48:56 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,7 +36,8 @@ lonparmset - Handler to set parameters f =head1 SYNOPSIS -lonparmset provides an interface to setting course parameters. +lonparmset provides an interface to setting content parameters in a +course. It contains all the code for the "Content and Problem Settings" UI, except for the helpers parameter.helper and resettimes.helper, and lonhelper.pm, @@ -137,7 +138,7 @@ javascript function 'pjump'. =item print_td() -=item print_usergroups() +=item check_other_groups() =item parm_control_group() @@ -336,6 +337,10 @@ use LONCAPA qw(:DEFAULT :match); ################################################## # Page header +# +# @param {Apache2::RequestRec} $r - Apache request object +# @param {string} $mode - selected tab, 'parmset' for course and problem settings, or 'coursepref' for course settings +# @param {string} $crstype - course type ('Community' for community settings) sub startSettingsScreen { my ($r,$mode,$crstype)=@_; @@ -363,22 +368,47 @@ sub endSettingsScreen { ################################################## -# TABLE MODE +# (mostly) TABLE MODE # (parmval is also used for the log of parameter changes) ################################################## +# Calls parmval_by_symb, getting the symb from $id with &symbcache. +# +# @param {string} $what - part info and parameter name separated by a dot, e.g. '0.weight' +# @param {string} $id - resource id or map pc +# @param {string} $def - the resource's default value for this parameter +# @param {string} $uname - user name +# @param {string} $udom - user domain +# @param {string} $csec - section name +# @param {string} $cgroup - group name +# @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db) +# @returns {Array} sub parmval { my ($what,$id,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_; return &parmval_by_symb($what,&symbcache($id),$def,$uname,$udom,$csec, $cgroup,$courseopt); } +# Returns an array containing +# - the most specific level that is defined for that parameter (integer) +# - an array with the level as index and the parameter value as value (when defined) +# (level 1 is the most specific and will have precedence) +# +# @param {string} $what - part info and parameter name separated by a dot, e.g. '0.weight' +# @param {string} $symb - resource symb or map src +# @param {string} $def - the resource's default value for this parameter +# @param {string} $uname - user name +# @param {string} $udom - user domain +# @param {string} $csec - section name +# @param {string} $cgroup - group name +# @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db) +# @returns {Array} sub parmval_by_symb { my ($what,$symb,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_; my $useropt; if ($uname ne '' && $udom ne '') { - $useropt = &Apache::lonnet::get_userresdata($uname,$udom); + $useropt = &Apache::lonnet::get_userresdata($uname,$udom); } my $result=''; @@ -386,7 +416,10 @@ sub parmval_by_symb { # ----------------------------------------------------- Cascading lookup scheme my $map=(&Apache::lonnet::decode_symb($symb))[0]; $map = &Apache::lonnet::deversion($map); - + + # NOTE: some of that code looks redondant with code in lonnavmaps::parmval_real, + # any change should be reflected there. + my $symbparm=$symb.'.'.$what; my $recurseparm=$map.'___(rec).'.$what; my $mapparm=$map.'___(all).'.$what; @@ -409,16 +442,19 @@ sub parmval_by_symb { # --------------------------------------------------------- first, check course +# 18 - General Course if (defined($$courseopt{$courselevel})) { $outpar[18]=$$courseopt{$courselevel}; $result=18; } +# 17 - Map or Folder level in course (recursive) if (defined($$courseopt{$courseleveli})) { $outpar[17]=$$courseopt{$courseleveli}; $result=17; } +# 16 - Map or Folder level in course (non-recursive) if (defined($$courseopt{$courselevelm})) { $outpar[16]=$$courseopt{$courselevelm}; $result=16; @@ -426,14 +462,17 @@ sub parmval_by_symb { # ------------------------------------------------------- second, check default +# 15 - resource default if (defined($def)) { $outpar[15]=$def; $result=15; } # ------------------------------------------------------ third, check map parms +# 14 - map default my $thisparm=&parmhash($symbparm); if (defined($thisparm)) { $outpar[14]=$thisparm; $result=14; } +# 13 - resource level in course if (defined($$courseopt{$courselevelr})) { $outpar[13]=$$courseopt{$courselevelr}; $result=13; @@ -441,18 +480,22 @@ sub parmval_by_symb { # ------------------------------------------------------ fourth, back to course if ($csec ne '') { +# 12 - General for section if (defined($$courseopt{$seclevel})) { $outpar[12]=$$courseopt{$seclevel}; $result=12; } +# 11 - Map or Folder level for section (recursive) if (defined($$courseopt{$secleveli})) { $outpar[11]=$$courseopt{$secleveli}; $result=11; } +# 10 - Map or Folder level for section (non-recursive) if (defined($$courseopt{$seclevelm})) { $outpar[10]=$$courseopt{$seclevelm}; $result=10; } +# 9 - resource level in section if (defined($$courseopt{$seclevelr})) { $outpar[9]=$$courseopt{$seclevelr}; $result=9; @@ -460,18 +503,22 @@ sub parmval_by_symb { } # ------------------------------------------------------ fifth, check course group if ($cgroup ne '') { +# 8 - General for group if (defined($$courseopt{$grplevel})) { $outpar[8]=$$courseopt{$grplevel}; $result=8; } +# 7 - Map or Folder level for group (recursive) if (defined($$courseopt{$grpleveli})) { $outpar[7]=$$courseopt{$grpleveli}; $result=7; } +# 6 - Map or Folder level for group (non-recursive) if (defined($$courseopt{$grplevelm})) { $outpar[6]=$$courseopt{$grplevelm}; $result=6; } +# 5 - resource level in group if (defined($$courseopt{$grplevelr})) { $outpar[5]=$$courseopt{$grplevelr}; $result=5; @@ -481,25 +528,29 @@ sub parmval_by_symb { # ---------------------------------------------------------- sixth, check user if ($uname ne '') { - if (defined($$useropt{$courselevel})) { - $outpar[4]=$$useropt{$courselevel}; - $result=4; - } +# 4 - General for specific student + if (defined($$useropt{$courselevel})) { + $outpar[4]=$$useropt{$courselevel}; + $result=4; + } - if (defined($$useropt{$courseleveli})) { - $outpar[3]=$$useropt{$courseleveli}; - $result=3; - } +# 3 - Map or Folder level for specific student (recursive) + if (defined($$useropt{$courseleveli})) { + $outpar[3]=$$useropt{$courseleveli}; + $result=3; + } - if (defined($$useropt{$courselevelm})) { - $outpar[2]=$$useropt{$courselevelm}; - $result=2; - } +# 2 - Map or Folder level for specific student (non-recursive) + if (defined($$useropt{$courselevelm})) { + $outpar[2]=$$useropt{$courselevelm}; + $result=2; + } - if (defined($$useropt{$courselevelr})) { - $outpar[1]=$$useropt{$courselevelr}; - $result=1; - } +# 1 - resource level for specific student + if (defined($$useropt{$courselevelr})) { + $outpar[1]=$$useropt{$courselevelr}; + $result=1; + } } return ($result,@outpar); } @@ -509,20 +560,25 @@ sub parmval_by_symb { # --- Caches local to lonparmset +# Reset lonparmset caches (called at the beginning and end of the handler). sub reset_caches { &resetparmhash(); &resetsymbcache(); &resetrulescache(); } +# cache for map parameters, stored temporarily in $env{'request.course.fn'}_parms.db +# (these parameters come from param elements in .sequence files created with the advanced RAT) { - my $parmhashid; - my %parmhash; + my $parmhashid; # course identifier, to initialize the cache only once for a course + my %parmhash; # the parameter cache + # reset map parameter hash sub resetparmhash { undef($parmhashid); undef(%parmhash); } + # dump the _parms.db database into %parmhash sub cacheparmhash { if ($parmhashid eq $env{'request.course.fn'}) { return; } my %parmhashfile; @@ -534,6 +590,7 @@ sub reset_caches { } } + # returns a parameter value for an identifier symb.parts.parameter, using the map parameter cache sub parmhash { my ($id) = @_; &cacheparmhash(); @@ -541,14 +598,18 @@ sub reset_caches { } } +# cache resource id or map pc -> resource symb or map src, using lonnavmaps to find association { - my $symbsid; - my %symbs; + my $symbsid; # course identifier, to initialize the cache only once for a course + my %symbs; # hash id->symb + # reset the id->symb cache sub resetsymbcache { undef($symbsid); undef(%symbs); } + # returns the resource symb or map src corresponding to a resource id or map pc + # (using lonnavmaps and a cache) sub symbcache { my $id=shift; if ($symbsid ne $env{'request.course.id'}) { @@ -569,14 +630,16 @@ sub reset_caches { } } +# cache for parameter default actions (stored in parmdefactions.db) { - my $rulesid; - my %rules; + my $rulesid; # course identifier, to initialize the cache only once for a course + my %rules; # parameter default actions hash sub resetrulescache { undef($rulesid); undef(%rules); } + # returns the value for a given key in the parameter default action hash sub rulescache { my $id=shift; if ($rulesid ne $env{'request.course.id'} @@ -591,7 +654,12 @@ sub reset_caches { } - +# Returns the values of the parameter type default action +# "default value when manually setting". +# If none is defined, ('','','','','') is returned. +# +# @param {string} $type - parameter type +# @returns {Array} - (hours, min, sec, value) sub preset_defaults { my $type=shift; if (&rulescache($type.'_action') eq 'default') { @@ -607,8 +675,13 @@ sub preset_defaults { } - - +# Checks that a date is after enrollment start date and before +# enrollment end date. +# Returns HTML with a warning if it is not, or the empty string otherwise. +# This is used by both overview and table modes. +# +# @param {integer} $checkdate - the date to check. +# @returns {string} - HTML possibly containing a localized warning message. sub date_sanity_info { my $checkdate=shift; unless ($checkdate) { return ''; } @@ -643,26 +716,39 @@ sub date_sanity_info { # } return $result; } -################################################## -################################################## -# -# Store a parameter by ID -# -# Takes -# - resource id -# - name of parameter -# - level -# - new value -# - new type -# - username -# - userdomain + +# Store a parameter value and type by ID, also triggering more parameter changes based on parameter default actions. +# +# @param {string} $sresid - resource id or map pc +# @param {string} $spnam - part info and parameter name separated by a dot or underscore, e.g. '0.weight' +# @param {integer} $snum - level +# @param {string} $nval - new value +# @param {string} $ntype - new type +# @param {string} $uname - username +# @param {string} $udom - userdomain +# @param {string} $csec - section name +# @param {string} $cgroup - group name sub storeparm { my ($sresid,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup)=@_; &storeparm_by_symb(&symbcache($sresid),$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,'',$cgroup); } -my %recstack; +my %recstack; # hash parameter name -> 1 when a parameter was used before in a recursive call to storeparm_by_symb + +# Store a parameter value and type by symb, also triggering more parameter changes based on parameter default actions. +# Uses storeparm_by_symb_inner to actually store the parameter, ignoring any returned error. +# +# @param {string} $symb - resource symb or map src +# @param {string} $spnam - part info and parameter name separated by a dot or underscore, e.g. '0.weight' +# @param {integer} $snum - level +# @param {string} $nval - new value +# @param {string} $ntype - new type +# @param {string} $uname - username +# @param {string} $udom - userdomain +# @param {string} $csec - section name +# @param {boolean} $recflag - should be true for recursive calls to storeparm_by_symb, false otherwise +# @param {string} $cgroup - group name sub storeparm_by_symb { my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$recflag,$cgroup)=@_; unless ($recflag) { @@ -692,8 +778,7 @@ sub storeparm_by_symb { # are there restrictions? if (&rulescache($triggered.'_triggervalue')=~/\w/) { $active=0; - foreach my $possiblevalue (split(/\s*\, - \s*/,&rulescache($triggered.'_triggervalue'))) { + foreach my $possiblevalue (split(/\s*\,\s*/,&rulescache($triggered.'_triggervalue'))) { if (lc($possiblevalue) eq lc($nval)) { $active=1; } } } @@ -715,10 +800,25 @@ sub storeparm_by_symb { return ''; } +# Adds all given arguments to the course parameter log. +# @returns {string} - the answer to the lonnet query. sub log_parmset { return &Apache::lonnet::write_log('course','parameterlog',@_); } +# Store a parameter value and type by symb, without using the parameter default actions. +# Expire related sheets. +# +# @param {string} $symb - resource symb or map src +# @param {string} $spnam - part info and parameter name separated by a dot, e.g. '0.weight' +# @param {integer} $snum - level +# @param {string} $nval - new value +# @param {string} $ntype - new type +# @param {string} $uname - username +# @param {string} $udom - userdomain +# @param {string} $csec - section name +# @param {string} $cgroup - group name +# @returns {string} - HTML code with an error message if the parameter could not be stored. sub storeparm_by_symb_inner { # ---------------------------------------------------------- Get symb, map, etc my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$cgroup)=@_; @@ -747,17 +847,36 @@ sub storeparm_by_symb_inner { my $courselevelm=$env{'request.course.id'}.'.'.$mapparm; my $storeunder=''; + my $possreplace=''; if (($snum==18) || ($snum==4)) { $storeunder=$courselevel; } - if (($snum==17) || ($snum==3)) { $storeunder=$courseleveli; } - if (($snum==16) || ($snum==2)) { $storeunder=$courselevelm; } + if (($snum==17) || ($snum==3)) { + $storeunder=$courseleveli; + $possreplace=$courselevelm; + } + if (($snum==16) || ($snum==2)) { + $storeunder=$courselevelm; + $possreplace=$courseleveli; + } if (($snum==13) || ($snum==1)) { $storeunder=$courselevelr; } if ($snum==12) { $storeunder=$seclevel; } - if ($snum==11) { $storeunder=$secleveli; } - if ($snum==10) { $storeunder=$seclevelm; } + if ($snum==11) { + $storeunder=$secleveli; + $possreplace=$seclevelm; + } + if ($snum==10) { + $storeunder=$seclevelm; + $possreplace=$secleveli; + } if ($snum==9) { $storeunder=$seclevelr; } if ($snum==8) { $storeunder=$grplevel; } - if ($snum==7) { $storeunder=$grpleveli; } - if ($snum==6) { $storeunder=$grplevelm; } + if ($snum==7) { + $storeunder=$grpleveli; + $possreplace=$grplevelm; + } + if ($snum==6) { + $storeunder=$grplevelm; + $possreplace=$grpleveli; + } if ($snum==5) { $storeunder=$grplevelr; } @@ -776,7 +895,7 @@ sub storeparm_by_symb_inner { &Apache::lonnet::expirespread('','','studentcalc'); if (($snum==13) || ($snum==9) || ($snum==5)) { &Apache::lonnet::expirespread('','','assesscalc',$symb); - } elsif (($snum==14) || ($snum==10) || ($snum==6)) { + } elsif (($snum==17) || ($snum==16) || ($snum==11) || ($snum==10) || ($snum==7) || ($snum==6)) { &Apache::lonnet::expirespread('','','assesscalc',$map); } else { &Apache::lonnet::expirespread('','','assesscalc'); @@ -790,6 +909,17 @@ sub storeparm_by_symb_inner { $reply=&Apache::lonnet::cput ('resourcedata',\%storecontent,$cdom,$cnum); &log_parmset(\%storecontent); + if ($possreplace) { + my $resdata = &Apache::lonnet::get_courseresdata($cnum,$cdom); + if (ref($resdata) eq 'HASH') { + if (exists($resdata->{$possreplace})) { + if (&Apache::lonnet::del + ('resourcedata',[$possreplace,$possreplace.'.type'],$cdom,$cnum) eq 'ok') { + &log_parmset({$possreplace => '', $possreplace.'.type' => $ntype},1); + } + } + } + } } &Apache::lonnet::devalidatecourseresdata($cnum,$cdom); } else { @@ -800,7 +930,7 @@ sub storeparm_by_symb_inner { if ($snum==1) { &Apache::lonnet::expirespread ($uname,$udom,'assesscalc',$symb); - } elsif ($snum==2) { + } elsif (($snum==2) || ($snum==3)) { &Apache::lonnet::expirespread ($uname,$udom,'assesscalc',$map); } else { @@ -815,6 +945,18 @@ sub storeparm_by_symb_inner { $reply=&Apache::lonnet::cput ('resourcedata',\%storecontent,$udom,$uname); &log_parmset(\%storecontent,0,$uname,$udom); + if ($possreplace) { + my $resdata = &Apache::lonnet::get_userresdata($uname,$udom); + if (ref($resdata) eq 'HASH') { + if (exists($resdata->{$possreplace})) { + if (&Apache::lonnet::del + ('resourcedata',[$possreplace,$possreplace.'.type'],$udom,$uname) eq 'ok') { + &log_parmset({$possreplace => '',$possreplace.'.type' => $ntype},1, + $uname,$udom); + } + } + } + } } &Apache::lonnet::devalidateuserresdata($uname,$udom); } @@ -826,6 +968,15 @@ sub storeparm_by_symb_inner { } +# Returns HTML with the value of the given parameter, +# using a readable format for dates, and +# a warning if there is a problem with a date. +# Used by table mode. +# Returns HTML for the editmap.png image if no value is defined and $editable is true. +# +# @param {string} $value - the parameter value +# @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 $result = ''; @@ -904,12 +1055,27 @@ sub valout { } +# Returns HTML containing a link on a parameter value, for table mode. +# The link uses the javascript function 'pjump'. +# +# @param {string} $type - parameter type +# @param {string} $dis - dialog title for editing the parameter value and type +# @param {string} $value - parameter value +# @param {string} $marker - identifier for the parameter, "resource id&part_parameter name&level", will be passed as pres_marker when the user submits a change. +# @param {string} $return - prefix for the name of the form and field names that will be used to submit the form ('parmform.pres') +# @param {string} $call - javascript function to call to submit the form ('psub') +# @param {boolean} $recursive - true if link is for a map/folder where parameter is currently set to be recursive. +# @param {string} $extra - optional additional information to send as tenth arg in call to javascript pjump function. sub plink { - my ($type,$dis,$value,$marker,$return,$call)=@_; + my ($type,$dis,$value,$marker,$return,$call,$recursive,$extra)=@_; my $winvalue=$value; unless ($winvalue) { - if (&isdateparm($type)) { + if (&isdateparm($type) || (&is_specialstring($type))) { $winvalue=$env{'form.recent_'.$type}; + } elsif ($type eq 'string_yesno') { + if ($env{'form.recent_string'} =~ /^(yes|no)$/i) { + $winvalue=$env{'form.recent_string'}; + } } else { $winvalue=$env{'form.recent_'.(split(/\_/,$type))[0]}; } @@ -917,19 +1083,22 @@ sub plink { my ($parmname)=((split(/\&/,$marker))[1]=~/\_([^\_]+)$/); my ($hour,$min,$sec,$val)=&preset_defaults($parmname); unless (defined($winvalue)) { $winvalue=$val; } - my $valout = &valout($value,$type,$parmname,1); + my $valout = &valout($value,$type,1); my $unencmarker = $marker; foreach my $item (\$type, \$dis, \$winvalue, \$marker, \$return, \$call, - \$hour, \$min, \$sec) { + \$hour, \$min, \$sec, \$extra) { $$item = &HTML::Entities::encode($$item,'"<>&'); $$item =~ s/\'/\\\'/g; } return '
'. ''. - $valout.'
'; + .$marker."','".$return."','".$call."','".$hour."','".$min."','".$sec."','".$extra."'".');">'. + $valout.''.($recursive?''. + &mt('recursive').'' : '').''; + } +# Javascript for table mode. sub page_js { my $selscript=&Apache::loncommon::studentbrowser_javascript(); @@ -942,20 +1111,22 @@ sub page_js { $pjump_def function psub() { + var specstring = /^string_!(yesno|any)/i; if (document.parmform.pres_marker.value!='') { document.parmform.action+='#'+document.parmform.pres_marker.value; var typedef=new Array(); typedef=document.parmform.pres_type.value.split('_'); - if (document.parmform.pres_type.value!='') { - if (typedef[0]=='date') { - eval('document.parmform.recent_'+ - document.parmform.pres_type.value+ - '.value=document.parmform.pres_value.value;'); - } else { - eval('document.parmform.recent_'+typedef[0]+ - '.value=document.parmform.pres_value.value;'); + if (document.parmform.pres_type.value!='') { + if ((typedef[0]=='date') || + (specstring.test(document.parmform.pres_type.value))) { + eval('document.parmform.recent_'+ + document.parmform.pres_type.value+ + '.value=document.parmform.pres_value.value;'); + } else { + eval('document.parmform.recent_'+typedef[0]+ + '.value=document.parmform.pres_value.value;'); + } } - } document.parmform.submit(); } else { document.parmform.pres_value.value=''; @@ -979,6 +1150,8 @@ ENDJS } +# Javascript to show or hide the map selection (function showHide_courseContent), +# for table and overview modes. sub showhide_js { return <<"COURSECONTENTSCRIPT"; @@ -999,6 +1172,7 @@ function showHide_courseContent() { COURSECONTENTSCRIPT } +# Javascript functions showHideLenient and toggleParmTextbox, for overview mode sub toggleparmtextbox_js { return <<"ENDSCRIPT"; @@ -1058,6 +1232,7 @@ function toggleParmTextbox(form,key) { ENDSCRIPT } +# Javascript function validateParms, for overview mode sub validateparms_js { return <<'ENDSCRIPT'; @@ -1068,12 +1243,16 @@ function validateParms() { var patternLenientStd = /^(yes|no|default)$/; var ipallowRegExp = /^setipallow_/; var ipdenyRegExp = /^setipdeny_/; + var deeplinkRegExp = /^deeplink_(listing|scope)_/; + var deeplinkUrlsRegExp = /^deeplink_urls_/; + var deeplinkltiRegExp = /^deeplink_lti_/; + var deeplinkkeyRegExp = /^deeplink_key_/; var patternIP = /[\[\]\*\.a-zA-Z\d\-]+/; if ((document.parmform.elements.length != 'undefined') && (document.parmform.elements.length) != 'null') { if (document.parmform.elements.length) { for (i=0; i parameter part (can be problem part.'_'.response id for response parameters) +# @param {hash reference} $name - parameter key -> parameter name +# @param {hash reference} $symbp - map pc or resource/map id -> map src.'___(all)' or resource symb +# @param {string} $rid - resource id +# @param {hash reference} $default - parameter key -> resource parameter default value +# @param {hash reference} $defaulttype - parameter key -> resource parameter default type +# @param {hash reference} $display - parameter key -> full title for the parameter +# @param {string} $defbgone - user level and other levels background color +# @param {string} $defbgtwo - section level background color, also used for part number +# @param {string} $defbgthree - group level background color +# @param {string} $parmlev - parameter level (Resource:'full', Map:'map', Course:'general') +# @param {string} $uname - user name +# @param {string} $udom - user domain +# @param {string} $csec - section name +# @param {string} $cgroup - group name +# @param {array reference} $usersgroups - list of groups the user belongs to, if any +# @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters +# @param {boolean} $readonly - true if no editing allowed. +# @param {array reference} - $recurseup - list of maps containing current one, ending at top-level. +# @param {hash reference} - $maptitles - - hash map id or src -> map title +# @param {hash reference} - $allmaps_inverted - hash map src -> map pc +# @param {scalar reference} - $reclinks - number of "parameter in effect" cells with link to map where recursive param was set sub print_row { my ($r,$which,$part,$name,$symbp,$rid,$default,$defaulttype,$display,$defbgone, - $defbgtwo,$defbgthree,$parmlev,$uname,$udom,$csec,$cgroup,$usersgroups,$noeditgrp)=@_; + $defbgtwo,$defbgthree,$parmlev,$uname,$udom,$csec,$cgroup,$usersgroups,$noeditgrp, + $readonly,$recurseup,$maptitles,$allmaps_inverted,$reclinks)=@_; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom); + my $numlinks = 0; # get the values for the parameter in cascading order # empty levels will remain empty @@ -1270,85 +1554,182 @@ sub print_row { my $thismarker=$which; $thismarker=~s/^parameter\_//; my $mprefix=$rid.'&'.$thismarker.'&'; - my $effective_parm = &valout($outpar[$result],$typeoutpar[$result],$thismarker); - my ($othergrp,$grp_parm,$controlgrp); - + my ($parmname)=($thismarker=~/\_([^\_]+)$/); + my ($othergrp,$grp_parm,$controlgrp,$effective_parm,$effparm_rec,$effparm_level, + $eff_groupparm,$recurse_check,$recursinfo,$extra); + if ((ref($recurseup) eq 'ARRAY') && (@{$recurseup} > 0)) { + if ($result eq '') { + $recurse_check = 1; + } elsif (($uname ne '') && ($result > 3)) { + $recurse_check = 1; + } elsif (($cgroup ne '') && ($result > 7)) { + $recurse_check = 1; + } elsif (($csec ne '') && ($result > 11)) { + $recurse_check = 1; + } elsif ($result > 17) { + $recurse_check = 1; + } + if ($recurse_check) { + my $what = $$part{$which}.'.'.$$name{$which}; + my $prefix; + if (($uname ne '') && ($udom ne '')) { + my $useropt = &Apache::lonnet::get_userresdata($uname,$udom); + $prefix = $env{'request.course.id'}; + $recursinfo = &get_recursive($recurseup,$useropt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + $effparm_level = &mt('user: [_1]',$uname); + } + } + if (($cgroup ne '') && (!$effparm_rec)) { + $prefix = $env{'request.course.id'}.'.['.$cgroup.']'; + $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + $effparm_level = &mt('group: [_1]',$cgroup); + } + } + if (($csec ne '') && (!$effparm_rec)) { + $prefix = $env{'request.course.id'}.'.['.$csec.']'; + $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + $effparm_level = &mt('section: [_1]',$csec); + } + } + if (!$effparm_rec) { + $prefix = $env{'request.course.id'}; + $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + } + } + } + } + if ((!$effparm_rec) && ($result == 17 || $result == 11 || $result == 7 || $result == 3)) { + $effparm_rec = 1; + } + if ((!$effparm_rec) && + (($$name{$which} eq 'encrypturl') || ($$name{$which} eq 'hiddenresource')) && + ($result == 16 || $result == 10 || $result == 6 || $result == 2)) { + $effparm_rec = 1; + } + if ($parmname eq 'deeplink') { + my %posslti; + my %lti = + &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'}, + 'provider'); + foreach my $item (keys(%lti)) { + if (ref($lti{$item}) eq 'HASH') { + unless ($lti{$item}{'requser'}) { + $posslti{$item} = $lti{$item}{'consumer'}; + } + } + } + if (keys(%posslti)) { + $extra = 'lti_'; + foreach my $lti (sort { $a <=> $b } keys(%posslti)) { + $extra .= $lti.':'.&js_escape($posslti{$lti}).','; + } + $extra =~ s/,$//; + } + } if ($parmlev eq 'general') { if ($uname) { - &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } elsif ($cgroup) { - &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); + &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra); } elsif ($csec) { - &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } else { - &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } } elsif ($parmlev eq 'map') { if ($uname) { - &print_td($r,3,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); } elsif ($cgroup) { - &print_td($r,7,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); - &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); + &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra); } elsif ($csec) { - &print_td($r,11,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); } else { - &print_td($r,17,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); } } else { if ($uname) { if (@{$usersgroups} > 1) { - my ($coursereply,$grp_parm,$controlgrp); - ($coursereply,$othergrp,$grp_parm,$controlgrp) = - &print_usergroups($r,$$part{$which}.'.'.$$name{$which}, + (my $coursereply,$othergrp,$grp_parm,$controlgrp,my $grp_is_rec) = + &check_other_groups($$part{$which}.'.'.$$name{$which}, $rid,$cgroup,$defbgone,$usersgroups,$result,$courseopt); - if ($coursereply && $result > 4) { + if (($coursereply) && ($result > 4)) { if (defined($controlgrp)) { if ($cgroup ne $controlgrp) { - $effective_parm = $grp_parm; - $result = 0; + $eff_groupparm = $grp_parm; + undef($result); + undef($effparm_rec); + if ($grp_is_rec) { + $effparm_rec = 1; + } } } } } } - &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,17,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); + &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); if ($csec) { - &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,11,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); + &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } if ($cgroup) { - &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); - &print_td($r,7,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); - &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); - &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp); + &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra); + &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra); + &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp.$readonly,'',$extra); } if ($uname) { if ($othergrp) { $r->print($othergrp); } - &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,3,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); - &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display); + &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); + &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } - } # end of $parmlev if/else - $r->print(''.$effective_parm.''); - + if (ref($recursinfo) eq 'ARRAY') { + my $rectitle = &mt('recursive'); + if ((ref($maptitles) eq 'HASH') && (exists($maptitles->{$recursinfo->[2]}))) { + if ((ref($allmaps_inverted) eq 'HASH') && (exists($allmaps_inverted->{$recursinfo->[2]}))) { + $rectitle = &mt('set in: [_1]','"'. + '{$recursinfo->[2]}."',". + "'$parmname','$$part{$which}'".');">'. + $maptitles->{$recursinfo->[2]}.'"'); + + $numlinks ++; + } + } + my ($parmname)=($thismarker=~/\_([^\_]+)$/); + $effective_parm = &valout($recursinfo->[0],$recursinfo->[1]); + $r->print(''.$effective_parm. + '
'.$rectitle.' '. + $effparm_level.''); + } else { + if ($result) { + $effective_parm = &valout($outpar[$result],$typeoutpar[$result]); + } + if ($eff_groupparm) { + $effective_parm = $eff_groupparm; + } + $r->print(''.$effective_parm. + ($effparm_rec?'
'.&mt('recursive'). + '':'').''); + } if ($parmlev eq 'full') { my $sessionval=&Apache::lonnet::EXT('resource.'.$$part{$which}. '.'.$$name{$which},$$symbp{$rid}); @@ -1357,47 +1738,110 @@ sub print_row { $sessionvaltype=$$defaulttype{$which}; } $r->print(''. - &valout($sessionval,$sessionvaltype,$$name{$which}).' '. + &valout($sessionval,$sessionvaltype).' '. ''); } $r->print(''); $r->print("\n"); + if (($numlinks) && (ref($reclinks))) { + $$reclinks = $numlinks; + } } +# Prints a cell for table mode. +# +# FIXME: some of these parameter names are uninspired ($which and $value) +# Also, it would make more sense to pass the display for this cell rather +# than the full display hash and the key to use. +# +# @param {Apache2::RequestRec} $r - the Apache request +# @param {integer} $which - level +# @param {string} $defbg - cell background color +# @param {integer} $result - the most specific level that is defined for that parameter +# @param {array reference} $outpar - array level -> parameter value (when defined) +# @param {string} $mprefix - resource id.'&'.part.'_'.parameter name.'&' +# @param {string} $value - parameter key ('parameter_'.part.'_'.name) +# @param {array reference} $typeoutpar - array level -> parameter type (when defined) +# @param {hash reference} $display - parameter key -> full title for the parameter +# @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters +# @param {boolean} $readonly -true if editing not allowed. +# @param {boolean} $ismaplevel - true if level is for a map. +# @param {strring} $extra - extra informatio to pass to plink. sub print_td { - my ($r,$which,$defbg,$result,$outpar,$mprefix,$value,$typeoutpar,$display,$noeditgrp)=@_; - $r->print(''); my $nolink = 0; - if ($which == 14 || $which == 15) { - $nolink = 1; - } elsif (($env{'request.course.sec'} ne '') && ($which > 12)) { + if ($readonly) { $nolink = 1; - } elsif ($which == 5 || $which == 6 || $which == 7 || $which == 8) { - if ($noeditgrp) { + } else { + if ($which == 14 || $which == 15 || $mprefix =~ /mapalias\&$/) { $nolink = 1; - } - } elsif ($mprefix =~ /availablestudent\&$/) { - if ($which > 4) { - $nolink = 1; - } - } elsif ($mprefix =~ /examcode\&$/) { - unless ($which == 2) { + } elsif (($env{'request.course.sec'} ne '') && ($which > 12)) { $nolink = 1; + } elsif ($which == 5 || $which == 6 || $which == 7 || $which == 8) { + if ($noeditgrp) { + $nolink = 1; + } + } elsif ($mprefix =~ /availablestudent\&$/) { + if ($which > 4) { + $nolink = 1; + } + } elsif ($mprefix =~ /examcode\&$/) { + unless ($which == 2) { + $nolink = 1; + } } } if ($nolink) { - $r->print(&valout($$outpar[$which],$$typeoutpar[$which],$mprefix)); + my ($parmname)=((split(/\&/,$mprefix))[1]=~/\_([^\_]+)$/); + $r->print(&valout($currval,$currtype)); } else { - $r->print(&plink($$typeoutpar[$which], - $$display{$value},$$outpar[$which], - $mprefix."$which",'parmform.pres','psub')); + $r->print(&plink($currtype, + $$display{$value},$currval, + $mprefix.$currlevel,'parmform.pres','psub',$recursive, + $extra)); } $r->print(''."\n"); } -sub print_usergroups { - my ($r,$what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_; +# Returns HTML and other info for the cell added when a user is selected +# and that user is in several groups. This is the cell with the title "Control by other group". +# +# @param {string} $what - parameter part.'.'.parameter name +# @param {string} $rid - resource id +# @param {string} $cgroup - group name +# @param {string} $defbg - cell background color +# @param {array reference} $usersgroups - list of groups the user belongs to, if any +# @param {integer} $result - level +# @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db) +# @returns {Array} - array (parameter value for the other group, HTML for the cell, HTML with the value, name of the other group, true if recursive) +sub check_other_groups { + my ($what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_; my $courseid = $env{'request.course.id'}; my $output; my $symb = &symbcache($rid); @@ -1409,16 +1853,22 @@ sub print_usergroups { &parm_control_group($courseid,$usersgroups,$symbparm,$mapparm, $recurseparm,$what,$courseopt); my $bgcolor = $defbg; - my $grp_parm; + my ($grp_parm,$grp_is_rec); if (($coursereply) && ($cgroup ne $resultgroup)) { + my ($parmname) = ($what =~ /\.([^.]+)$/); if ($result > 3) { $bgcolor = '#AAFFAA'; - $grp_parm = &valout($coursereply,$resulttype,$what); } - $grp_parm = &valout($coursereply,$resulttype,$what); + $grp_parm = &valout($coursereply,$resulttype); $output = ''; if ($resultgroup && $resultlevel) { - $output .= ''.$resultgroup.' ('.$resultlevel.'): '.$grp_parm; + if ($resultlevel eq 'recursive') { + $resultlevel = 'map/folder'; + $grp_is_rec = 1; + } + $output .= ''.$resultgroup.' ('.$resultlevel.'): '.$grp_parm. + ($grp_is_rec?''.&mt('recursive').'':''); + } else { $output .= ' '; } @@ -1426,9 +1876,20 @@ sub print_usergroups { } else { $output .= ' '; } - return ($coursereply,$output,$grp_parm,$resultgroup); + return ($coursereply,$output,$grp_parm,$resultgroup,$grp_is_rec); } +# Looks for a group with a defined parameter for given user and parameter. +# Used by check_other_groups. +# +# @param {string} $courseid - the course id +# @param {array reference} $usersgroups - list of groups the user belongs to, if any +# @param {string} $symbparm - end of the course parameter hash key for the group resource level +# @param {string} $mapparm - end of the course parameter hash key for the group map/folder level +# @param {string} $recurseparm - end of the course parameter hash key for the group recursive level +# @param {string} $what - parameter part.'.'.parameter name +# @param {hash reference} $courseopt - course parameters hash +# @returns {Array} - (parameter value for the group, course parameter hash key for the parameter, name of the group, level name, parameter type) sub parm_control_group { my ($courseid,$usersgroups,$symbparm,$mapparm,$recurseparm,$what,$courseopt) = @_; my ($coursereply,$resultitem,$resultgroup,$resultlevel,$resulttype); @@ -1455,6 +1916,21 @@ sub parm_control_group { +# Extracts lots of information about all of the the course's resources into a variety of hashes, using lonnavmaps and lonnet::metadata. +# All the parameters are references and are filled by the sub. +# +# @param {array reference} $ids - resource and map ids +# @param {hash reference} $typep - hash resource/map id -> resource type (file extension) +# @param {hash reference} $keyp - hash resource/map id -> comma-separated list of parameter keys from lonnet::metadata +# @param {hash reference} $allparms - hash parameter name -> parameter title +# @param {hash reference} $allparts - hash parameter part -> part title (a parameter part can be problem part.'_'.response id for response parameters) +# @param {hash reference} $allmaps - hash map pc -> map src +# @param {hash reference} $mapp - hash map pc or resource/map id -> enclosing map src +# @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' for a map or resource symb for a resource +# @param {hash reference} $maptitles - hash map pc or src -> map title (this should really be two separate hashes) +# @param {hash reference} $uris - hash resource/map id -> resource src +# @param {hash reference} $keyorder - hash parameter key -> appearance rank for this parameter when looking through every resource and every parameter, starting at 100 (integer) +# @param {hash reference} $defkeytype - hash parameter name -> parameter type sub extractResourceInformation { my $ids = shift; my $typep = shift; @@ -1481,23 +1957,27 @@ sub extractResourceInformation { my $srcf=$resource->src(); $srcf=~/\.(\w+)$/; $$typep{$id}=$1; + my $toolsymb; + if ($srcf =~ /ext\.tool$/) { + $toolsymb = $resource->symb(); + } $$keyp{$id}=''; $$uris{$id}=$srcf; - foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys'))) { + foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys',$toolsymb))) { next if ($key!~/^parameter_/); # Hidden parameters - next if (&Apache::lonnet::metadata($srcf,$key.'.hidden') eq 'parm'); + next if (&Apache::lonnet::metadata($srcf,$key.'.hidden',$toolsymb) eq 'parm'); # # allparms is a hash of parameter names # - my $name=&Apache::lonnet::metadata($srcf,$key.'.name'); + my $name=&Apache::lonnet::metadata($srcf,$key.'.name',$toolsymb); if (!exists($$allparms{$name}) || $$allparms{$name} =~ m/^\s*$/ ) { my ($display,$parmdis); $display = &standard_parameter_names($name); if ($display eq '') { - $display= &Apache::lonnet::metadata($srcf,$key.'.display'); + $display= &Apache::lonnet::metadata($srcf,$key.'.display',$toolsymb); $parmdis = $display; $parmdis =~ s/\s*\[Part.*$//g; } else { @@ -1506,14 +1986,14 @@ sub extractResourceInformation { $$allparms{$name}=$parmdis; if (ref($defkeytype)) { $$defkeytype{$name}= - &Apache::lonnet::metadata($srcf,$key.'.type'); + &Apache::lonnet::metadata($srcf,$key.'.type',$toolsymb); } } # # allparts is a hash of all parts # - my $part= &Apache::lonnet::metadata($srcf,$key.'.part'); + my $part= &Apache::lonnet::metadata($srcf,$key.'.part',$toolsymb); $$allparts{$part} = &mt('Part: [_1]',$part); # # Remember all keys going with this resource @@ -1554,21 +2034,52 @@ sub extractResourceInformation { } } +sub get_recursive { + my ($recurseup,$resdata,$what,$prefix) = @_; + if ((ref($resdata) eq 'HASH') && (ref($recurseup) eq 'ARRAY')) { + foreach my $item (@{$recurseup}) { + my $norecursechk=$prefix.'.'.$item.'___(all).'.$what; + if (defined($resdata->{$norecursechk})) { + if ($what =~ /\.(encrypturl|hiddenresource)$/) { + my $type = $resdata->{$norecursechk.'.type'}; + return [$resdata->{$norecursechk},$type,$item]; + } else { + last; + } + } + my $recursechk=$prefix.'.'.$item.'___(rec).'.$what; + if (defined($resdata->{$recursechk})) { + my $type = $resdata->{$recursechk.'.type'}; + return [$resdata->{$recursechk},$type,$item]; + } + } + } + return; +} +# Tells if a parameter type is a date. +# +# @param {string} type - parameter type +# @returns{boolean} - true if it is a date sub isdateparm { my $type=shift; return (($type=~/^date/) && (!($type eq 'date_interval'))); } +# Determine if parameter type is specialized string type (i.e., +# not just string or string_yesno. + +sub is_specialstring { + my $type=shift; + return (($type=~/^string_/) && (($type ne 'string_yesno'))); +} + +# Prints the HTML and Javascript to select parameters, with various shortcuts. # -# parmmenu displays a list of the selected parameters. -# It also offers a link to show/hide the complete parameter list -# from which you can select all desired parameters. -# +# @param {Apache2::RequestRec} $r - the Apache request sub parmmenu { - my ($r,$allparms,$pscat,$keyorder)=@_; - my $tempkey; + my ($r)=@_; $r->print(< // @@ -1647,10 +2156,13 @@ sub parmmenu { ENDSCRIPT $r->print('
'); - &shortCuts($r,$allparms,$pscat,$keyorder); + &shortCuts($r); $r->print('
'); } -# return a hash + +# Returns parameter categories. +# +# @returns {hash} - category name -> title in English sub categories { return ('time_settings' => 'Time Settings', 'grading' => 'Grading', @@ -1664,7 +2176,9 @@ sub categories { 'misc' => 'Miscellaneous' ); } -# return a hash. Like a look-up table +# Returns the category for each parameter. +# +# @returns {hash} - parameter name -> category name sub lookUpTableParameter { return ( @@ -1696,6 +2210,7 @@ sub lookUpTableParameter { 'buttonshide' => 'hiding', 'turnoffeditor' => 'hiding', 'encrypturl' => 'hiding', + 'deeplink' => 'hiding', 'randomorder' => 'high_level_randomization', 'randompick' => 'high_level_randomization', 'available' => 'slots', @@ -1711,10 +2226,14 @@ sub lookUpTableParameter { 'lenient' => 'grading', 'retrypartial' => 'tries', 'discussvote' => 'misc', - 'examcode' => 'high_level_randomization', - ); + 'examcode' => 'high_level_randomization', + ); } +# Adds the given parameter name to an array of arrays listing all parameters for each category. +# +# @param {string} $name - parameter name +# @param {array reference} $catList - array reference category name -> array reference of parameter names sub whatIsMyCategory { my $name = shift; my $catList = shift; @@ -1738,6 +2257,11 @@ sub whatIsMyCategory { } } +# Sorts parameter names based on appearance order. +# +# @param {array reference} name - array reference of parameter names +# @param {hash reference} $keyorder - hash parameter key -> appearance rank +# @returns {Array} - array of parameter names sub keysindisplayorderCategory { my ($name,$keyorder)=@_; return sort { @@ -1745,6 +2269,9 @@ sub keysindisplayorderCategory { } ( @{$name}); } +# Returns a hash category name -> order, starting at 1 (integer) +# +# @returns {hash} sub category_order { return ( 'time_settings' => 1, @@ -1761,6 +2288,12 @@ sub category_order { } +# Prints HTML to let the user select parameters, from a list of all parameters organized by category. +# +# @param {Apache2::RequestRec} $r - the Apache request +# @param {hash reference} $allparms - hash parameter name -> parameter title +# @param {array reference} $pscat - list of selected parameter names +# @param {hash reference} $keyorder - hash parameter key -> appearance rank sub parmboxes { my ($r,$allparms,$pscat,$keyorder)=@_; my %categories = &categories(); @@ -1788,6 +2321,7 @@ sub parmboxes { $r->print('
' .'

'.&mt($categories{$key}).'

'."\n"); foreach my $tempkey (&keysindisplayorderCategory($categoryList{$key},$keyorder)) { + next if ($tempkey eq ''); $r->print('' .'
'. ''.&mt('Button text').': '. - '&').'" />'; + '&').'"'.$disabled.' />'; } } unless ($readonly) { @@ -4121,6 +5310,16 @@ sub date_interval_selector { return $result; } +# Returns HTML with a warning if a parameter requires a more recent version of LON-CAPA. +# +# @param {string} $name - parameter name +# @param {string} $namematch - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel) +# @param {string} $value - parameter value +# @param {string} $chostname - course server name +# @param {integer} $cmajor - major version number +# @param {integer} $cminor - minor version number +# @param {string} $needsrelease - release version needed (major.minor) +# @returns {string} sub oldversion_warning { my ($name,$namematch,$value,$chostname,$cmajor,$cminor,$needsrelease) = @_; my $standard_name = &standard_parameter_names($name); @@ -4196,14 +5395,28 @@ sub oldversion_warning { } # end of block using some constants related to parameter types -# -# Shift all start and end dates by $shift -# +# Shifts all start and end dates in the current course by $shift. +# +# @param {integer} $shift - time to shift, in seconds +# @returns {string} - error name or 'ok' sub dateshift { - my ($shift)=@_; + my ($shift,$numchanges)=@_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $sec = $env{'request.course.sec'}; + my $secgrpregex; + if ($sec ne '') { + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + } + if (@groups) { + $secgrpregex = '(?:'.join('|',($sec,@groups)).')'; + } else { + $secgrpregex = $sec; + } + } my %data=&Apache::lonnet::dump('resourcedata',$dom,$crs); # ugly retro fix for broken version of types foreach my $key (keys(%data)) { @@ -4218,7 +5431,11 @@ sub dateshift { # go through all parameters and look for dates foreach my $key (keys(%data)) { if ($data{$key.'.type'}=~/^date_(start|end)$/) { + if ($sec ne '') { + next unless ($key =~ /^$env{'request.course.id'}\.\[$secgrpregex\]\./); + } my $newdate=$data{$key}+$shift; + $$numchanges ++; $storecontent{$key}=$newdate; } } @@ -4231,12 +5448,19 @@ sub dateshift { return $reply; } +# Overview mode UI to edit course parameters. +# +# @param {Apache2::RequestRec} $r - the Apache request sub newoverview { - my ($r) = @_; + my ($r,$parm_permission) = @_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; + my $readonly = 1; + if ($parm_permission->{'edit'}) { + undef($readonly); + } &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview', text=>"Overview Mode"}); @@ -4253,6 +5477,7 @@ sub newoverview { &validateparms_js()."\n". &ipacc_boxes_js()."\n". &done_proctor_js()."\n". + &deeplink_js()."\n". '// ]]> '; @@ -4395,15 +5620,31 @@ ENDOVER # List data - &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview'); + &listdata($r,$resourcedata,$listdata,$sortorder,'newoverview',undef,$readonly); } - $r->print(&tableend(). - ((($env{'form.store'}) || ($env{'form.dis'}))?'

':''). - ''); + $r->print(&tableend()); + unless ($readonly) { + $r->print( ((($env{'form.store'}) || ($env{'form.dis'}))?'

':'') ); + } + $r->print(''); &endSettingsScreen($r); $r->print(&Apache::loncommon::end_page()); } +# Fills $listdata with parameter information. +# Keys use the format course id.[section id].part.name and course id.[section id].part.name.type. +# The non-type value is always 1. +# +# @param {string} $cat - parameter name +# @param {string} $pschp - selected map pc, or 'all' +# @param {string} $parmlev - selected level value (full|map|general), or '' +# @param {hash reference} $listdata - the parameter data that will be modified +# @param {array reference} $psprt - selected parts +# @param {array reference} $selections - selected sections +# @param {hash reference} $defkeytype - hash parameter name -> parameter type +# @param {hash reference} $allmaps - hash map pc -> map src +# @param {array reference} $ids - resource and map ids +# @param {hash reference} $symbp - hash map pc or resource/map id -> map src.'___(all)' or resource symb sub secgroup_lister { my ($cat,$pschp,$parmlev,$listdata,$psprt,$selections,$defkeytype,$allmaps,$ids,$symbp) = @_; foreach my $item (@{$selections}) { @@ -4424,9 +5665,6 @@ sub secgroup_lister { my $newparmkey=$rootparmkey.'.'.$$allmaps{$mapid}.'___(all).'.$part.'.'.$cat; $$listdata{$newparmkey}=1; $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat}; - $newparmkey=$rootparmkey.'.'.$$allmaps{$mapid}.'___(rec).'.$part.'.'.$cat; - $$listdata{$newparmkey}=1; - $$listdata{$newparmkey.'.type'}=$$defkeytype{$cat}; } } else { # resource-level parameter @@ -4442,18 +5680,26 @@ sub secgroup_lister { } } -# Display all existing parameter settings. +# UI to edit parameter settings starting with a list of all existing parameters. +# (called by setoverview action) +# +# @param {Apache2::RequestRec} $r - the Apache request sub overview { - my ($r) = @_; + my ($r,$parm_permission) = @_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; + my $readonly = 1; + if ($parm_permission->{'edit'}) { + undef($readonly); + } my $js = ''."\n"; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview', @@ -4470,7 +5716,9 @@ sub overview { # Store modified - &storedata($r,$crs,$dom); + unless ($readonly) { + &storedata($r,$crs,$dom); + } # Read modified data @@ -4481,15 +5729,29 @@ sub overview { unless ($sortorder) { $sortorder='realmstudent'; } &sortmenu($r,$sortorder); + my $submitbutton = ''; + + if ($readonly) { + $r->print('

'.$submitbutton.'

'); + } + # List data - my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder,'overview',$classlist); - $r->print(&tableend().'

'. - ($foundkeys?'':''.&mt('There are no parameters.').'').'

'. - &Apache::loncommon::end_page()); + my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder,'overview',$classlist,$readonly); + $r->print(&tableend().'

'); + if ($foundkeys) { + unless ($readonly) { + $r->print('

'.$submitbutton.'

'); + } + } else { + $r->print('

'.&mt('There are no parameters.').'

'); + } + $r->print(''.&Apache::loncommon::end_page()); } # Unused sub. +# +# @param {Apache2::RequestRec} $r - the Apache request sub clean_parameters { my ($r) = @_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; @@ -4549,10 +5811,8 @@ ENDOVER $r->print(&mt('All users')); } elsif ($data{'scope_type'} eq 'user') { $r->print(&mt('User: [_1]',join(':',@{$data{'scope'}}))); - } elsif ($data{'scope_type'} eq 'section') { - $r->print(&mt('Section: [_1]',$data{'scope'})); - } elsif ($data{'scope_type'} eq 'group') { - $r->print(&mt('Group: [_1]',$data{'scope'})); + } elsif ($data{'scope_type'} eq 'secgroup') { + $r->print(&mt('Group/Section: [_1]',$data{'scope'})); } $r->print('
'); if ($data{'realm_type'} eq 'all') { @@ -4578,15 +5838,30 @@ ENDOVER $r->print(&Apache::loncommon::end_page()); } -# Overview mode, UI to shift all dates. +# UI to shift all dates (called by dateshift1 action). +# Used by overview mode. +# +# @param {Apache2::RequestRec} $r - the Apache request sub date_shift_one { my ($r) = @_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; - + my $sec = $env{'request.course.sec'}; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'}, text=>"Shifting Dates"}); + my $submit_text = &mt('Shift all dates accordingly'); + if ($sec ne '') { + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + } + if (@groups) { + $submit_text = &mt("Shift dates set just for your section/group(s), accordingly"); + } else { + $submit_text = &mt("Shift dates set just for your section, accordingly"); + } + } my $start_page=&Apache::loncommon::start_page('Shift Dates'); my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift'); $r->print($start_page.$breadcrumbs); @@ -4602,16 +5877,19 @@ sub date_shift_one { ''. ''. ''. - ''); + ''); &endSettingsScreen($r); $r->print(&Apache::loncommon::end_page()); } -# Overview mode, UI to shift all dates (second form). +# UI to shift all dates (second form). +# +# @param {Apache2::RequestRec} $r - the Apache request sub date_shift_two { my ($r) = @_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $sec = $env{'request.course.sec'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'}, text=>"Shifting Dates"}); @@ -4620,14 +5898,47 @@ sub date_shift_two { $r->print($start_page.$breadcrumbs); &startSettingsScreen($r,'parmset',$crstype); my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted'); - $r->print('

'.&mt('Shift Dates').'

'. - '

'.&mt('Shifting all dates such that [_1] becomes [_2]', - &Apache::lonlocal::locallocaltime($env{'form.timebase'}), - &Apache::lonlocal::locallocaltime($timeshifted)).'

'); + $r->print('

'.&mt('Shift Dates').'

'); + if ($sec ne '') { + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + } + if (@groups) { + $r->print('

'. + &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]", + &Apache::lonlocal::locallocaltime($env{'form.timebase'}), + &Apache::lonlocal::locallocaltime($timeshifted)). + '

'); + } else { + $r->print('

'. + &mt("Shift dates set just for your section, such that [_1] becomes [_2]", + &Apache::lonlocal::locallocaltime($env{'form.timebase'}), + &Apache::lonlocal::locallocaltime($timeshifted)). + '

'); + } + } else { + $r->print('

'.&mt('Shifting all dates such that [_1] becomes [_2]', + &Apache::lonlocal::locallocaltime($env{'form.timebase'}), + &Apache::lonlocal::locallocaltime($timeshifted)). + '

'); + } my $delta=$timeshifted-$env{'form.timebase'}; - &dateshift($delta); + my $numchanges = 0; + my $result = &dateshift($delta,\$numchanges); + if ($result eq 'ok') { + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]', + $numchanges))); + } elsif ($result eq 'con_delayed') { + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]', + $numchanges))); + } else { + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1)); + } $r->print( - &Apache::lonhtmlcommon::confirm_success(&mt('Done')). '

'. &Apache::lonhtmlcommon::actionbox( [''.&mt('Content and Problem Settings').''])); @@ -4635,11 +5946,18 @@ sub date_shift_two { $r->print(&Apache::loncommon::end_page()); } +# Returns the different components of a resourcedata key. +# Keys: scope_type, scope, realm_type, realm, realm_title, +# realm_exists, parameter_part, parameter_name. +# Was used by clean_parameters (which is unused). +# +# @param {string} $key - the parameter key +# @returns {hash} sub parse_key { my ($key) = @_; my %data; my ($middle,$part,$name)= - ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s]+)\.(\w+)$/); + ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/); $data{'scope_type'} = 'all'; if ($middle=~/^\[(.*)\]/) { $data{'scope'} = $1; @@ -4647,8 +5965,7 @@ sub parse_key { $data{'scope_type'} = 'user'; $data{'scope'} = [$1,$2]; } else { - #FIXME check for group scope - $data{'scope_type'} = 'section'; + $data{'scope_type'} = 'secgroup'; } $middle=~s/^\[(.*)\]//; } @@ -4675,6 +5992,7 @@ sub parse_key { } +# Calls loncommon::start_page with the "Settings" title. sub header { return &Apache::loncommon::start_page('Settings'); } @@ -4685,6 +6003,10 @@ sub header { # MAIN MENU ################################################## +# Content and problem settings main menu. +# +# @param {Apache2::RequestRec} $r - the Apache request +# @param {boolean} $parm_permission - true if the user has permission to edit the current course or section sub print_main_menu { my ($r,$parm_permission)=@_; # @@ -4704,35 +6026,73 @@ ENDMAINFORMHEAD my $vgr = &Apache::lonnet::allowed('vgr',$env{'request.course.id'}); my $mgr = &Apache::lonnet::allowed('mgr',$env{'request.course.id'}); my $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'}); + my $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'}); + my $vpa = &Apache::lonnet::allowed('vpa',$env{'request.course.id'}); if ((!$dcm) && ($env{'request.course.sec'} ne '')) { $dcm = &Apache::lonnet::allowed('dcm',$env{'request.course.id'}. '/'.$env{'request.course.sec'}); } - + if ((!$vcb) && ($env{'request.course.sec'} ne '')) { + $vcb = &Apache::lonnet::allowed('vcb',$env{'request.course.id'}. + '/'.$env{'request.course.sec'}); + } + my (%linktext,%linktitle,%url); + if ($parm_permission->{'edit'}) { + %linktext = ( + newoverview => 'Edit Resource Parameters - Overview Mode', + settable => 'Edit Resource Parameters - Table Mode', + setoverview => 'Modify Resource Parameters - Overview Mode', + ); + %linktitle = ( + newoverview => 'Set/Modify resource parameters in overview mode.', + settable => 'Set/Modify resource parameters in table mode.', + setoverview => 'Set/Modify existing resource parameters in overview mode.', + ); + } else { + %linktext = ( + newoverview => 'View Resource Parameters - Overview Mode', + settable => 'View Resource Parameters - Table Mode', + setoverview => 'View Resource Parameters - Overview Mode', + ); + %linktitle = ( + newoverview => 'Display resource parameters in overview mode.', + settable => 'Display resource parameters in table mode.', + setoverview => 'Display existing resource parameters in overview mode.', + ); + } + if ($mgr) { + $linktext{'resettimes'} = 'Reset Student Access Times'; + $linktitle{'resettimes'} = "Reset access times for folders/maps, resources or the $lc_crstype."; + $url{'resettimes'} = '/adm/helper/resettimes.helper'; + } elsif ($vgr) { + $linktext{'resettimes'} = 'Display Student Access Times', + $linktitle{'resettimes'} = "Display access times for folders/maps, resources or the $lc_crstype.", + $url{'resettimes'} = '/adm/accesstimes'; + } my @menu = ( { categorytitle=>"Content Settings for this $crstype", items => [ { linktext => 'Portfolio Metadata', url => '/adm/parmset?action=setrestrictmeta', - permission => $parm_permission, + permission => $parm_permission->{'setrestrictmeta'}, linktitle => "Restrict metadata for this $lc_crstype." , icon =>'contact-new.png' , }, - { linktext => 'Reset Student Access Times', - url => '/adm/helper/resettimes.helper', - permission => $mgr, - linktitle => "Reset access times for folders/maps, resources or the $lc_crstype." , - icon => 'start-here.png' , + { linktext => $linktext{'resettimes'}, + url => $url{'resettimes'}, + permission => ($vgr || $mgr), + linktitle => $linktitle{'resettimes'}, + icon => 'start-here.png', }, { linktext => 'Blocking Communication/Resource Access', url => '/adm/setblock', - permission => $dcm, + permission => ($vcb || $dcm), linktitle => 'Configure blocking of communication/collaboration and access to resources during an exam', icon => 'comblock.png', }, { linktext => 'Set Parameter Setting Default Actions', url => '/adm/parmset?action=setdefaults', - permission => $parm_permission, + permission => $parm_permission->{'setdefaults'}, linktitle =>'Set default actions for parameters.' , icon => 'folder-new.png' , }]}, @@ -4740,37 +6100,37 @@ ENDMAINFORMHEAD items => [ { linktext => 'Edit Resource Parameters - Helper Mode', url => '/adm/helper/parameter.helper', - permission => $parm_permission, + permission => $parm_permission->{'helper'}, linktitle =>'Set/Modify resource parameters in helper mode.' , icon => 'dialog-information.png' , #help => 'Parameter_Helper', }, - { linktext => 'Edit Resource Parameters - Overview Mode', + { linktext => $linktext{'newoverview'}, url => '/adm/parmset?action=newoverview', - permission => $parm_permission, - linktitle =>'Set/Modify resource parameters in overview mode.' , - icon => 'edit-find.png' , + permission => $parm_permission->{'newoverview'}, + linktitle => $linktitle{'newoverview'}, + icon => 'edit-find.png', #help => 'Parameter_Overview', }, - { linktext => 'Edit Resource Parameters - Table Mode', + { linktext => $linktext{'settable'}, url => '/adm/parmset?action=settable', - permission => $parm_permission, - linktitle =>'Set/Modify resource parameters in table mode.' , - icon => 'edit-copy.png' , + permission => $parm_permission->{'settable'}, + linktitle => $linktitle{'settable'}, + icon => 'edit-copy.png', #help => 'Table_Mode', }]}, { categorytitle => 'Existing Parameter Settings for Resources', items => [ - { linktext => 'Modify Resource Parameters - Overview Mode', + { linktext => $linktext{'setoverview'}, url => '/adm/parmset?action=setoverview', - permission => $parm_permission, - linktitle =>'Set/Modify existing resource parameters in overview mode.' , - icon => 'preferences-desktop-wallpaper.png' , + permission => $parm_permission->{'setoverview'}, + linktitle => $linktitle{'setoverview'}, + icon => 'preferences-desktop-wallpaper.png', #help => 'Parameter_Overview', }, { linktext => 'Change Log', url => '/adm/parmset?action=parameterchangelog', - permission => $parm_permission, + permission => $parm_permission->{'parameterchangelog'}, linktitle =>"View parameter and $lc_crstype blog posting/user notification change log." , icon => 'document-properties.png', }]} @@ -4788,6 +6148,13 @@ ENDMAINFORMHEAD # PORTFOLIO METADATA ################################################## +# Prints HTML to edit an item of portfolio metadata. The HTML contains several td elements (no tr). +# It looks like field titles are not localized. +# +# @param {Apache2::RequestRec} $r - the Apache request +# @param {string} $field_name - metadata field name +# @param {string} $field_text - metadata field title, in English unless manually added +# @param {boolean} $added_flag - true if the field was manually added sub output_row { my ($r, $field_name, $field_text, $added_flag) = @_; my $output; @@ -4845,6 +6212,9 @@ sub output_row { # UI to order portfolio metadata fields. +# Currently useless because addmetafield does not work. +# +# @param {Apache2::RequestRec} $r - the Apache request sub order_meta_fields { my ($r)=@_; my $idx = 1; @@ -4935,15 +6305,21 @@ sub order_meta_fields { } +# Returns HTML with a Continue button redirecting to the initial portfolio metadata screen. +# @returns {string} sub continue { my $output; $output .= '
'; $output .= ''; - $output .= ''; + $output .= ''; return ($output); } +# UI to add a metadata field. +# Currenly does not work because of an HTML error (the field is not visible). +# +# @param {Apache2::RequestRec} $r - the Apache request sub addmetafield { my ($r)=@_; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=addmetadata', @@ -4963,7 +6339,10 @@ sub addmetafield { my $put_result = &Apache::lonnet::put('environment', {'metadata.'.$meta_field.'.options'=>$options},$dom,$crs); - $r->print('Undeleted Metadata Field '.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}." with result ".$put_result.'
'); + $r->print(&mt('Undeleted Metadata Field [_1] with result [_2]', + ''.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}. + '',$put_result). + '
'); } $r->print(&continue()); } elsif (exists($env{'form.fieldname'})) { @@ -4975,30 +6354,40 @@ sub addmetafield { {'metadata.'.$meta_field.'.values'=>"", 'metadata.'.$meta_field.'.added'=>"$display_field", 'metadata.'.$meta_field.'.options'=>""},$dom,$crs); - $r->print('Added new Metadata Field '.$env{'form.fieldname'}." with result ".$put_result.'
'); + $r->print(&mt('Added new Metadata Field [_1] with result [_2]', + ''.$env{'form.fieldname'}.'',$put_result). + '
'); $r->print(&continue()); } else { my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'}); if ($fields) { - $r->print('You may undelete previously deleted fields.
Check those you wish to undelete and click Undelete.
'); + $r->print(&mt('You may undelete previously deleted fields.'). + '
'. + &mt('Check those you wish to undelete and click Undelete.'). + '
'); $r->print(''); foreach my $key(keys(%$fields)) { - $r->print(''.$$fields{$key}.'
print('
print(''); + $r->print(''); $r->print('
'); } - $r->print('
Or you may enter a new metadata field name.
print('
'. + &mt('[_1]Or[_2] you may enter a new metadata field name.', + '',''). + ''); $r->print('
'); - $r->print(''); + $r->print(''); + $r->print('
'); } - $r->print(''); &endSettingsScreen($r); } # Display or save portfolio metadata. +# +# @param {Apache2::RequestRec} $r - the Apache request sub setrestrictmeta { my ($r)=@_; my $next_meta; @@ -5015,6 +6404,11 @@ sub setrestrictmeta { &startSettingsScreen($r,'parmset',$crstype); my $key_base = $env{'course.'.$env{'request.course.id'}.'.'}; my $save_field = ''; + my %lt = &Apache::lonlocal::texthash( + addm => 'Add Metadata Field', + ordm => 'Order Metadata Fields', + save => 'Save', + ); if ($env{'form.restrictmeta'}) { foreach my $field (sort(keys(%env))) { if ($field=~m/^form.(.+)_(.+)$/) { @@ -5053,28 +6447,25 @@ sub setrestrictmeta { my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio'); # Now get possible added metadata fields my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'}); - my $row_alt = 1; $output .= &Apache::loncommon::start_data_table(); foreach my $field (sort(keys(%metadata_fields))) { if ($field ne 'courserestricted') { - $row_alt = $row_alt ? 0 : 1; - $output.= &output_row($r, $field, $metadata_fields{$field}); + $output.= &output_row($r,$field,$metadata_fields{$field}); } } my $buttons = (< +
- +

- + ENDButtons my $added_flag = 1; foreach my $field (sort(keys(%$added_metadata_fields))) { - $row_alt = $row_alt ? 0 : 1; - $output.= &output_row($r, $field, $$added_metadata_fields{$field},$added_flag, $row_alt); + $output.= &output_row($r,$field,$$added_metadata_fields{$field},$added_flag); } $output .= &Apache::loncommon::end_data_table(); $r->print(< field title (not localized) sub get_added_meta_fieldnames { my ($cid) = @_; my %fields; @@ -5103,6 +6498,10 @@ sub get_added_meta_fieldnames { } +# Returns metadata fields that have been manually added and deleted. +# +# @param {string} $cid - course id +# @returns {hash reference} - hash field name -> field title (not localized) sub get_deleted_meta_fieldnames { my ($cid) = @_; my %fields; @@ -5124,6 +6523,8 @@ sub get_deleted_meta_fieldnames { ################################################## # UI to change parameter setting default actions +# +# @param {Apache2::RequestRec} $r - the Apache request sub defaultsetter { my ($r) = @_; @@ -5217,8 +6618,8 @@ sub defaultsetter { push @datedisplay,&mt('Automatically set earlier than ').$tempkey; } } -$r->print(&mt('Manual setting rules apply to all interfaces.').'
'. - &mt('Automatic setting rules apply to table mode interfaces only.')); + $r->print(&mt('Manual setting rules apply to all interfaces.').'
'. + &mt('Automatic setting rules apply to table mode interfaces only.')); $r->print("\n".&Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). "".&mt('Rule for parameter').''. @@ -5262,7 +6663,7 @@ $r->print(&mt('Manual setting rules appl $lt{'hours'}
$lt{'min'}
$lt{'sec'} - ENDINPUTDATE +ENDINPUTDATE } elsif ($defkeytype{$tempkey} eq 'string_yesno') { my $yeschecked=''; my $nochecked=''; @@ -5272,7 +6673,7 @@ $r->print(&mt('Manual setting rules appl $r->print(< $lt{'yes'}
- ENDYESNO +ENDYESNO } else { $r->print(''); } @@ -5290,15 +6691,33 @@ $r->print(&mt('Manual setting rules appl # PARAMETER CHANGES LOG ################################################## +# Returns some info for a parameter log entry. +# Returned entries: +# $realm - HTML title for the parameter level and resource +# $section - parameter section +# $name - parameter name +# $part - parameter part +# $what - $part.'.'.$name +# $middle - resource symb ? +# $uname - user name (same as given) +# $udom - user domain (same as given) +# $issection - section or group name +# $realmdescription - title for the parameter level and resource (without using HTML) +# +# @param {string} $key - parameter log key +# @param {string} $uname - user name +# @param {string} $udom - user domain +# @param {boolean} $typeflag - .type log entry +# @returns {Array} sub components { - my ($key,$uname,$udom,$exeuser,$exedomain,$typeflag)=@_; + my ($key,$uname,$udom,$typeflag)=@_; if ($typeflag) { $key=~s/\.type$//; } my ($middle,$part,$name)= - ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s]+)\.(\w+)$/); + ($key=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/); my $issection; my $section=&mt('All Students'); @@ -5338,11 +6757,12 @@ sub components { $what,$middle,$uname,$udom,$issection,$realmdescription); } -my %standard_parms; -my %standard_parms_types; +my %standard_parms; # hash parameter name -> parameter title (not localized) +my %standard_parms_types; # hash parameter name -> parameter type +# Reads parameter info from packages.tab into %standard_parms. sub load_parameter_names { - open(my $config,"<$Apache::lonnet::perlvar{'lonTabDir'}/packages.tab"); + open(my $config,"<","$Apache::lonnet::perlvar{'lonTabDir'}/packages.tab"); while (my $configline=<$config>) { if ($configline !~ /\S/ || $configline=~/^\#/) { next; } chomp($configline); @@ -5357,8 +6777,13 @@ sub load_parameter_names { close($config); $standard_parms{'int_pos'} = 'Positive Integer'; $standard_parms{'int_zero_pos'} = 'Positive Integer or Zero'; + $standard_parms{'scoreformat'} = 'Format for display of score'; } +# Returns a parameter title for standard parameters, the name for others. +# +# @param {string} $name - parameter name +# @returns {string} sub standard_parameter_names { my ($name)=@_; if (!%standard_parms) { @@ -5371,6 +6796,10 @@ sub standard_parameter_names { } } +# Returns a parameter type for standard parameters, undef for others. +# +# @param {string} $name - parameter name +# @returns {string} sub standard_parameter_types { my ($name)=@_; if (!%standard_parms_types) { @@ -5382,6 +6811,10 @@ sub standard_parameter_types { return; } +# Returns a parameter level title (not localized) from the parameter level name. +# +# @param {string} $name - parameter level name (recognized: resourcelevel|maplevel|maplevelrecurse|courselevel) +# @returns {string} sub standard_parameter_levels { my ($name)=@_; my %levels = ( @@ -5397,11 +6830,13 @@ sub standard_parameter_levels { } # Display log for parameter changes, blog postings, user notification changes. +# +# @param {Apache2::RequestRec} $r - the Apache request sub parm_change_log { - my ($r)=@_; + my ($r,$parm_permission)=@_; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'} + my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=settable', text=>"Parameter Change Log"}); my $js = '