--- loncom/interface/domainprefs.pm 2019/06/04 03:16:19 1.362 +++ loncom/interface/domainprefs.pm 2020/02/05 23:46:01 1.369 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.362 2019/06/04 03:16:19 raeburn Exp $ +# $Id: domainprefs.pm,v 1.369 2020/02/05 23:46:01 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -831,6 +831,7 @@ sub print_config_box { if ($numheaders > 1) { my $colspan = ''; my $rightcolspan = ''; + my $leftnobr = ''; if (($action eq 'rolecolors') || ($action eq 'defaults') || ($action eq 'directorysrch') || (($action eq 'login') && ($numheaders < 4))) { @@ -839,12 +840,15 @@ sub print_config_box { if ($action eq 'usersessions') { $rightcolspan = ' colspan="3"'; } + if ($action eq 'passwords') { + $leftnobr = ' LC_nobreak'; + } $output .= ' - + '; $rowtotal ++; @@ -889,6 +893,7 @@ sub print_config_box { ($action eq 'usersessions') || ($action eq 'coursecategories') || ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'passwords')) { + my $leftnobr = ' LC_nobreak'; if ($action eq 'coursecategories') { $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal); $colspan = ' colspan="2"'; @@ -956,7 +961,7 @@ sub print_config_box {
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col1'}).' '.&mt($item->{'header'}->[0]->{'col2'}).'
- + '."\n"; if ($action eq 'passwords') { $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal); @@ -2905,7 +2910,7 @@ function toggleLTI(form,setting,item) { } } } - } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback')) { + } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) { var radioname = ''; var divid = ''; if (setting == 'user') { @@ -2914,6 +2919,9 @@ function toggleLTI(form,setting,item) { } else if (setting == 'crs') { radioname = 'lti_mapcrs_'+item; divid = 'lti_crsfield_'+item; + } else if (setting == 'callback') { + radioname = 'lti_callback_'+item; + divid = 'lti_callbackfield_'+item; } else { radioname = 'lti_passback_'+item; divid = 'lti_passback_'+item; @@ -2923,7 +2931,7 @@ function toggleLTI(form,setting,item) { var setvis = ''; for (var i=0; i{'callback'} ne '') { + $callback = $current->{'callback'}; + $checked{'callback'}{'Y'} = ' checked="checked"'; + $callbacksty = 'inline-block'; + } else { + $checked{'callback'}{'N'} = ' checked="checked"'; + } if ($current->{'topmenu'}) { $checked{'topmenu'}{'Y'} = ' checked="checked"'; } else { @@ -5079,6 +5095,7 @@ sub lti_options { } else { $checked{'makecrs'}{'N'} = ' checked="checked"'; $checked{'crssec'}{'N'} = ' checked="checked"'; + $checked{'callback'}{'N'} = ' checked="checked"'; $checked{'topmenu'}{'N'} = ' checked="checked"'; $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; $checked{'menuitem'}{'grades'} = ' checked="checked"'; @@ -5107,6 +5124,7 @@ sub lti_options { my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"'; my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"'; my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"'; + my $onclickcallback = ' onclick="toggleLTI(this.form,'."'callback','$num'".');"'; my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"'; my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"'; my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"'; @@ -5256,7 +5274,17 @@ sub lti_options { ''.(' 'x2). ''. + &mt('Outcomes Extension (1.0)').''. + '
'. + '
'.&mt('Callback on logout').': '. + ''.(' 'x2). + '
'. + '
'. + ''.&mt('Parameter').': '. + ''. + '
'. '
'.&mt('Course defaults (Course Coordinator can override)').''. '
'.$lt{'topmenu'}.': '. ''. - '   '; + '   '; } } my $checkedcase; @@ -6137,7 +6165,7 @@ sub print_passwords { &mt('(If you use the same account ... reset a password from this page.)').'

'. &mt('Include custom text:'); if ($customurl) { - my $link = &Apache::loncommon::modal_link($customurl,&mt('Custom text file'),600,500, + my $link = &Apache::loncommon::modal_link($customurl,&mt('custom text'),600,500, undef,undef,undef,undef,'background-color:#ffffff'); $datatable .= ' '.$link. '
'. ''; $itemcount ++; $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''. ''; $itemcount ++; @@ -6308,14 +6337,16 @@ sub print_passwords { $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''. ''; $itemcount ++; $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''. ''; } else { @@ -6361,7 +6392,7 @@ sub print_passwords { $datatable .= ''. - '   '; + '   '; } } my $checked; @@ -9272,16 +9303,22 @@ ENDSCRIPT } sub passwords_javascript { - my $intauthcheck = &mt('Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.'); - my $intauthcost = &mt('Warning: bcrypt encryption cost for internal authentication must be an integer.'); - &js_escape(\$intauthcheck); - &js_escape(\$intauthcost); + my %intalert = &Apache::lonlocal::texthash ( + authcheck => 'Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.', + authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.', + passmin => 'Warning: minimum password length must be a positive integer greater than 6.', + passmax => 'Warning: maximum password length must be a positive integer (or blank).', + passexp => 'Warning: days before password expiration must be a positive integer (or blank).', + passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).', + ); + &js_escape(\%intalert); + my $defmin = $Apache::lonnet::passwdmin; my $intauthjs = <<"ENDSCRIPT"; function warnIntAuth(field) { if (field.name == 'intauth_check') { if (field.value == '2') { - alert('$intauthcheck'); + alert('$intalert{authcheck}'); } } if (field.name == 'intauth_cost') { @@ -9289,7 +9326,60 @@ function warnIntAuth(field) { if (field.value != '') { var regexdigit=/^\\d+\$/; if (!regexdigit.test(field.value)) { - alert('$intauthcost'); + alert('$intalert{authcost}'); + } + } + } + return; +} + +function warnIntPass(field) { + field.value.replace(/^\s+/,''); + field.value.replace(/\s+\$/,''); + var regexdigit=/^\\d+\$/; + if (field.name == 'passwords_min') { + if (field.value == '') { + alert('$intalert{passmin}'); + field.value = '$defmin'; + } else { + if (!regexdigit.test(field.value)) { + alert('$intalert{passmin}'); + field.value = '$defmin'; + } + var minval = parseInt(field.value,10); + if (minval < $defmin) { + alert('$intalert{passmin}'); + field.value = '$defmin'; + } + } + } else { + if (field.value == '0') { + field.value = ''; + } + if (field.value != '') { + if (field.name == 'passwords_expire') { + var regexpposnum=/^\\d+(|\\.\\d*)\$/; + if (!regexpposnum.test(field.value)) { + alert('$intalert{passexp}'); + field.value = ''; + } else { + var expval = parseFloat(field.value); + if (expval == 0) { + alert('$intalert{passexp}'); + field.value = ''; + } + } + } else { + if (!regexdigit.test(field.value)) { + if (field.name == 'passwords_max') { + alert('$intalert{passmax}'); + } else { + if (field.name == 'passwords_numsaved') { + alert('$intalert{passnum}'); + } + } + } + field.value = ''; } } } @@ -12675,6 +12765,13 @@ sub modify_lti { } } } + if ($env{'form.lti_callback_'.$idx}) { + if ($env{'form.lti_callbackparam_'.$idx}) { + my $callback = $env{'form.lti_callbackparam_'.$idx}; + $callback =~ s/^\s+|\s+$//g; + $confhash{$itemid}{'callback'} = $callback; + } + } foreach my $field ('passback','roster','topmenu','inlinemenu') { if ($env{'form.lti_'.$field.'_'.$idx}) { $confhash{$itemid}{$field} = 1; @@ -12700,7 +12797,7 @@ sub modify_lti { } } unless (($idx eq 'add') || ($changes{$itemid})) { - foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu') { + foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu','callback') { if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) { $changes{$itemid} = 1; } @@ -12926,6 +13023,11 @@ sub modify_lti { } else { $resulttext .= '
  • '.&mt('No section assignment').'
  • '; } + if ($confhash{$itemid}{'callback'}) { + $resulttext .= '
  • '.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'
  • '; + } else { + $resulttext .= '
  • '.&mt('No callback to logout LON-CAPA session when user logs out of Comsumer'); + } foreach my $item ('passback','roster','topmenu','inlinemenu') { $resulttext .= '
  • '.$lt{$item}.': '; if ($confhash{$itemid}{$item}) { @@ -14455,8 +14557,8 @@ sub modify_passwords { 'intauth_cost' => 10, 'intauth_check' => 0, 'intauth_switch' => 0, - 'min' => 7, ); + $staticdefaults{'min'} = $Apache::lonnet::passwdmin; foreach my $type (@oktypes) { $staticdefaults{'resetpostlink'}{$type} = ['email','username']; } @@ -14468,7 +14570,7 @@ sub modify_passwords { if ($current{'resetlink'} ne $linklife) { $changes{'reset'} = 1; } - } elsif (!exists($domconfig{passwords})) { + } elsif (!ref($domconfig{passwords}) eq 'HASH') { if ($staticdefaults{'resetlink'} ne $linklife) { $changes{'reset'} = 1; } @@ -14489,7 +14591,7 @@ sub modify_passwords { if (@diffs > 0) { $changes{'reset'} = 1; } - } elsif (!exists($domconfig{passwords})) { + } elsif (!ref($domconfig{passwords}) eq 'HASH') { my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens); if (@diffs > 0) { $changes{'reset'} = 1; @@ -14501,7 +14603,7 @@ sub modify_passwords { if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) { $changes{'reset'} = 1; } - } elsif (!exists($domconfig{passwords})) { + } elsif (!ref($domconfig{passwords}) eq 'HASH') { if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) { $changes{'reset'} = 1; } @@ -14528,7 +14630,7 @@ sub modify_passwords { } else { $changes{'reset'} = 1; } - } elsif (!exists($domconfig{passwords})) { + } elsif (!ref($domconfig{passwords}) eq 'HASH') { my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink); if (@diffs > 0) { $changes{'reset'} = 1; @@ -14550,7 +14652,7 @@ sub modify_passwords { if (@diffs > 0) { $changes{'reset'} = 1; } - } elsif (!exists($domconfig{passwords})) { + } elsif (!ref($domconfig{passwords}) eq 'HASH') { my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail); if (@diffs > 0) { $changes{'reset'} = 1; @@ -14637,10 +14739,18 @@ sub modify_passwords { $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g; my $ruleok; if ($rule eq 'expire') { - if ($env{'form.passwords_'.$rule} =~ /^\d+(|\.\d*)$/) { + if (($env{'form.passwords_'.$rule} =~ /^\d+(|\.\d*)$/) && + ($env{'form.passwords_'.$rule} ne '0')) { $ruleok = 1; } - } elsif ($env{'form.passwords_'.$rule} =~ /^\d+$/) { + } elsif ($rule eq 'min') { + if ($env{'form.passwords_'.$rule} =~ /^\d+$/) { + if ($env{'form.passwords_'.$rule} >= $Apache::lonnet::passwdmin) { + $ruleok = 1; + } + } + } elsif (($env{'form.passwords_'.$rule} =~ /^\d+$/) && + ($env{'form.passwords_'.$rule} ne '0')) { $ruleok = 1; } if ($ruleok) { @@ -14701,7 +14811,7 @@ sub modify_passwords { } } } - } elsif (!exists($domconfig{passwords})) { + } elsif (!(ref($domconfig{passwords}) eq 'HASH')) { foreach my $item ('by','for') { if (@{$crsownerchg{$item}} > 0) { $changes{'crsownerchg'} = 1; @@ -14731,9 +14841,11 @@ sub modify_passwords { $resulttext .= '
  • '.&mt('CAPTCHA validation set to use: original CAPTCHA').'
  • '; } elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') { $resulttext .= '
  • '.&mt('CAPTCHA validation set to use: reCAPTCHA').' '. - &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'
    '. - &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchapub'}).'
    '. - &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchapriv'}).'
  • '; + &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'
    '; + if (ref($confighash{'passwords'}{'recaptchakeys'}) eq 'HASH') { + $resulttext .= &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'public'}).'
    '. + &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'private'}).''; + } } else { $resulttext .= '
  • '.&mt('No CAPTCHA validation').'
  • '; } @@ -14812,8 +14924,9 @@ sub modify_passwords { } if ($confighash{'passwords'}{'resetcustom'}) { my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'}, - $titles{custom},600,500); - $resulttext .= '
  • '.&mt('Preamble to "Forgot Password" form includes [_1]',$customlink).'
  • '; + &mt('custom text'),600,500,undef,undef, + undef,undef,'background-color:#ffffff'); + $resulttext .= '
  • '.&mt('Preamble to "Forgot Password" form includes: [_1]',$customlink).'
  • '; } else { $resulttext .= '
  • '.&mt('No custom text included in preamble to "Forgot Password" form').'
  • '; } @@ -14850,7 +14963,8 @@ sub modify_passwords { if ($confighash{'passwords'}{$rule} eq '') { if ($rule eq 'min') { $resulttext .= '
  • '.&mt('[_1] not set.',$titles{$rule}); - ' '.&mt('Default of 7 will be used').'
  • '; + ' '.&mt('Default of [_1] will be used', + $Apache::lonnet::passwdmin).''; } else { $resulttext .= '
  • '.&mt('[_1] set to none',$titles{$rule}).'
  • '; } @@ -15997,19 +16111,25 @@ sub modify_selfcreation { } sub process_captcha { - my ($container,$changes,$newsettings,$current) = @_; - return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH') || (ref($current) eq 'HASH')); + my ($container,$changes,$newsettings,$currsettings) = @_; + return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH')); $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'}; unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') { $newsettings->{'captcha'} = 'original'; } - if ($current->{'captcha'} ne $newsettings->{'captcha'}) { + my %current; + if (ref($currsettings) eq 'HASH') { + %current = %{$currsettings}; + } + if ($current{'captcha'} ne $newsettings->{'captcha'}) { if ($container eq 'cancreate') { if (ref($changes->{'cancreate'}) eq 'ARRAY') { push(@{$changes->{'cancreate'}},'captcha'); } elsif (!defined($changes->{'cancreate'})) { $changes->{'cancreate'} = ['captcha']; } + } elsif ($container eq 'passwords') { + $changes->{'reset'} = 1; } else { $changes->{'captcha'} = 1; } @@ -16031,9 +16151,9 @@ sub process_captcha { } $newsettings->{'recaptchaversion'} = $newversion; } - if (ref($current->{'recaptchakeys'}) eq 'HASH') { - $currpub = $current->{'recaptchakeys'}{'public'}; - $currpriv = $current->{'recaptchakeys'}{'private'}; + if (ref($current{'recaptchakeys'}) eq 'HASH') { + $currpub = $current{'recaptchakeys'}{'public'}; + $currpriv = $current{'recaptchakeys'}{'private'}; unless ($newsettings->{'captcha'} eq 'recaptcha') { $newsettings->{'recaptchakeys'} = { public => '', @@ -16041,8 +16161,8 @@ sub process_captcha { } } } - if ($current->{'captcha'} eq 'recaptcha') { - $currversion = $current->{'recaptchaversion'}; + if ($current{'captcha'} eq 'recaptcha') { + $currversion = $current{'recaptchaversion'}; if ($currversion ne '2') { $currversion = 1; } @@ -16054,6 +16174,8 @@ sub process_captcha { } elsif (!defined($changes->{'cancreate'})) { $changes->{'cancreate'} = ['recaptchaversion']; } + } elsif ($container eq 'passwords') { + $changes->{'reset'} = 1; } else { $changes->{'recaptchaversion'} = 1; } @@ -16065,6 +16187,8 @@ sub process_captcha { } elsif (!defined($changes->{'cancreate'})) { $changes->{'cancreate'} = ['recaptchakeys']; } + } elsif ($container eq 'passwords') { + $changes->{'reset'} = 1; } else { $changes->{'recaptchakeys'} = 1; } @@ -16860,6 +16984,10 @@ sub modify_coursecategories { } $resulttext .= ''; } + &Apache::lonnet::do_cache_new('cats',$dom,$cathash,3600); + if (ref($lastactref) eq 'HASH') { + $lastactref->{'cats'} = 1; + } } $resulttext .= ''; if ($changes{'unauth'} || $changes{'auth'}) { @@ -19640,7 +19768,7 @@ sub devalidate_remote_domconfs { my %thismachine; map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); my @posscached = ('domainconfig','domdefaults','ltitools','usersessions', - 'directorysrch','passwdconf'); + 'directorysrch','passwdconf','cats'); if (keys(%servers)) { foreach my $server (keys(%servers)) { next if ($thismachine{$server});
    '.&mt($item->{'header'}->[3]->{'col1'}).''.&mt($item->{'header'}->[3]->{'col1'}).' '.&mt($item->{'header'}->[3]->{'col2'}).'
    '.$titles{'min'}.''. - ''. - ' '.&mt('(Leave blank for no minimum)').''. + ''. + ' '.&mt('(Enter an integer: 7 or larger)').''. '
    '.$titles{'max'}.''. - ''. + ''. ' '.&mt('(Leave blank for no maximum)').''. '
    '.$titles{'expire'}.''. - ''. + ''. ' '.&mt('(Leave blank for no expiration)').''. '
    '.$titles{'numsaved'}.''. - ''. + ''. ' '.&mt('(Leave blank to not save previous passwords)').''. '