--- loncom/interface/lonpreferences.pm 2019/08/22 00:00:03 1.196.4.25
+++ loncom/interface/lonpreferences.pm 2022/09/08 01:41:13 1.241
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Preferences
#
-# $Id: lonpreferences.pm,v 1.196.4.25 2019/08/22 00:00:03 raeburn Exp $
+# $Id: lonpreferences.pm,v 1.241 2022/09/08 01:41:13 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -31,7 +31,6 @@
package Apache::lonpreferences;
use strict;
-use LONCAPA;
use Apache::Constants qw(:common);
use Apache::File;
use Apache::loncommon();
@@ -40,6 +39,7 @@ use Apache::lonlocal;
use Apache::lonnet;
use LONCAPA::lonauthcgi();
use LONCAPA();
+use DateTime::TimeZone();
################################################################
# Handler subroutines #
@@ -165,7 +165,7 @@ sub texenginechanger {
my %mathchoices=('' => 'Default',
'tth' => 'tth (TeX to HTML)',
#'ttm' => 'TeX to MathML',
- 'MathJax' => 'MathJax',
+ 'MathJax' => 'MathJax',
'mimetex' => 'mimetex (Convert to Images)',
'raw' => 'Raw (Screen Reader)'
);
@@ -182,7 +182,7 @@ sub texenginechanger {
'change' => 'Save',
'exmpl' => 'Examples',
'mathjax' => 'MathJax:',
- 'mathjaxinfo' => 'MathJax provides rendered equations whose source code can be extracted in TeX and MathML formats by right clicking the equation.',
+ 'mathjaxinfo' => 'MathJax provides rendered equations whose source code can be extracted in TeX and MathML formats by right clicking the equation.',
'tth' => 'tth (TeX to HTML):',
'mimetex' => 'mimetex (Convert to Images):',
);
@@ -280,7 +280,7 @@ sub rolesprefchanger {
my $hotlist_n=$userenv{'recentrolesn'};
my ($checkedon,$checkedoff);
if ($hotlist_flag) {
- $checkedon = 'checked="checked"';
+ $checkedon = 'checked="checked"';
} else {
$checkedoff = 'checked="checked"';
}
@@ -627,7 +627,7 @@ sub icon_options {
}
sub icon_previews {
- my %icon_text = (
+ my %icon_text = &Apache::lonlocal::texthash (
annotate => 'Notes',
wishlist => 'Stored Links',
catalog => 'Info',
@@ -636,12 +636,12 @@ sub icon_previews {
printout => 'Print',
);
my %inlinetools = (
- printout => "s&8&3&prt.png&$icon_text{'printout'}&printout[_1]&gopost('/adm/printout',currentURL)&Prepare a printable document",
- wishlist => "s&9&1&wishlist-link.png&$icon_text{'wishlist'}&wishlistlink[_2]&set_wishlistlink()&Save a link for this resource in your personal Stored Links repository",
- evaluate => "s&8&1&eval.png&$icon_text{'evaluate'}&this[_1]&gopost('/adm/evaluate',currentURL,1)&Provide my evaluation of this resource",
- feedback => "s&8&2&fdbk.png&$icon_text{'feedback'}&discuss[_1]&gopost('/adm/feedback',currentURL,1)&Provide feedback messages or contribute to the course discussion about this resource",
- annotate => "s&9&3&anot.png&$icon_text{'annotate'}&tations[_1]&annotate()&Make notes and annotations about this resource",
- catalog => "s&6&3&catalog.png&$icon_text{'catalog'}&info[_1]&catalog_info()&Show Metadata",
+ printout => "s&8&3&prt.png&$icon_text{'printout'}&printout[_1]&gopost('/adm/printout',currentURL)&".&mt('Prepare a printable document'),
+ wishlist => "s&9&1&wishlist-link.png&$icon_text{'wishlist'}&wishlistlink[_2]&set_wishlistlink()&".&mt('Save a link for this resource in your personal Stored Links repository'),
+ evaluate => "s&8&1&eval.png&$icon_text{'evaluate'}&this[_1]&gopost('/adm/evaluate',currentURL,1)&".&mt('Provide my evaluation of this resource'),
+ feedback => "s&8&2&fdbk.png&$icon_text{'feedback'}&discuss[_1]&gopost('/adm/feedback',currentURL,1)&".&mt('Provide feedback messages or contribute to the course discussion about this resource'),
+ annotate => "s&9&3&anot.png&$icon_text{'annotate'}&tations[_1]&annotate()&".&mt('Make notes and annotations about this resource'),
+ catalog => "s&6&3&catalog.png&$icon_text{'catalog'}&info[_1]&catalog_info()&".&mt('Show Metadata'),
);
my @toolsorder = qw(annotate wishlist evaluate feedback printout catalog);
return (\%inlinetools,\@toolsorder);
@@ -683,16 +683,51 @@ sub verify_and_change_clicker {
my $r = shift;
my $user = $env{'user.name'};
my $domain = $env{'user.domain'};
+ my $uhome = $env{'user.home'};
my $newclickers = $env{'form.clickers'};
+ my $message;
$newclickers=~s/[^\w\:\-]+/\,/gs;
$newclickers=~tr/a-z/A-Z/;
$newclickers=~s/[\:\-]+/\-/g;
$newclickers=~s/\,+/\,/g;
$newclickers=~s/^\,//;
$newclickers=~s/\,$//;
- &Apache::lonnet::put('environment',{'clickers' => $newclickers});
- &Apache::lonnet::appenv({'environment.clickers' => $newclickers});
- my $message=&Apache::lonhtmlcommon::confirm_success(&mt('Registering clickers: [_1]',$newclickers));
+ my @oldclickers = split(/,/,$env{'environment.clickers'});
+ my @newclickers = split(/,/,$newclickers);
+ my %newuniq;
+ map { $newuniq{$_} = 1; } @newclickers;
+ @newclickers = sort(keys(%newuniq));
+ my @differences = &Apache::loncommon::compare_arrays(\@oldclickers,\@newclickers);
+ if (@differences) {
+ my $putres = &Apache::lonnet::put('environment',{'clickers' => $newclickers});
+ if ($putres eq 'ok') {
+ my @adds = ();
+ my @dels = ();
+ foreach my $item (@differences) {
+ if (grep(/^\Q$item\E$/,@newclickers)) {
+ push(@adds,$item);
+ } else {
+ push(@dels,$item);
+ }
+ }
+ if (@dels) {
+ my %delclicker;
+ map { $delclicker{$_} = $user; } @dels;
+ my $putresult = &Apache::lonnet::iddel($domain,\%delclicker,$uhome,'clickers');
+ }
+ if (@adds) {
+ my %addclicker;
+ map { $addclicker{$_} = $user; } @adds;
+ my $putresult = &Apache::lonnet::updateclickers($domain,'add',\%addclicker,$uhome,1);
+ }
+ &Apache::lonnet::appenv({'environment.clickers' => $newclickers});
+ $message=&Apache::lonhtmlcommon::confirm_success(&mt('Registering clickers: [_1]',$newclickers));
+ } else {
+ $message=&Apache::lonhtmlcommon::confirm_success(&mt('Error saving clicker ID').1);
+ }
+ } else {
+ $message=''.&mt('Clicker information unchanged').'';
+ }
$message=&Apache::loncommon::confirmwrapper($message);
&print_main_menu($r, $message);
}
@@ -1142,10 +1177,10 @@ sub colorschanger {
foreach my $item (sort(keys(%colortypes))) {
my $curcol=&Apache::loncommon::designparm($function.'.'.$item,$domain);
$chtable.=&Apache::loncommon::start_data_table_row().
- '
'.$colortypes{$item}.' | | '.
- &Apache::loncommon::end_data_table_row()."\n";
+ ''.$colortypes{$item}.' | | '.
+ &Apache::loncommon::end_data_table_row()."\n";
}
my $end_data_table = &Apache::loncommon::end_data_table();
my $pjump_def = &Apache::lonhtmlcommon::pjump_javascript_definition();
@@ -1197,9 +1232,9 @@ sub verify_and_change_colors {
my $message='';
foreach my $item (keys(%colortypes)) {
my $color=$env{'form.'.$item};
- if (!($color =~ /^#/)) {
- $color = '#' . $color;
- }
+ if (!($color =~ /^#/)) {
+ $color = '#' . $color;
+ }
my $entry='color.'.$function.'.'.$item;
if (($color=~/^\#[0-9A-Fa-f]{6}$/) && (!$env{'form.resetall'})) {
&Apache::lonnet::put('environment',{$entry => $color});
@@ -1230,7 +1265,8 @@ sub passwordchanger {
# This function is a bit of a mess....
# Passwords are encrypted using londes.js (DES encryption)
$errormessage = ($errormessage || '');
- my ($user,$domain,$currentpass);
+ my ($user,$domain,$currentpass,$clientip);
+ $clientip = &Apache::lonnet::get_requestor_ip($r);
&Apache::lonhtmlcommon::add_breadcrumb(
{ href => '/adm/preferences?action=changepass',
text => 'Change Password'});
@@ -1238,18 +1274,18 @@ sub passwordchanger {
$r->print(Apache::loncommon::start_page('Personal Data'));
$r->print(Apache::lonhtmlcommon::breadcrumbs('Change Password'));
}
- my ($blocked,$blocktext) =
- &Apache::loncommon::blocking_status('passwd');
- if ($blocked) {
- $r->print(''.$blocktext.'
');
- return;
- }
if ((!defined($caller)) || ($caller eq 'preferences')) {
$user = $env{'user.name'};
$domain = $env{'user.domain'};
if (!defined($caller)) {
$caller = 'preferences';
}
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('passwd',$clientip);
+ if ($blocked) {
+ $r->print(''.$blocktext.'
');
+ return;
+ }
} elsif ($caller eq 'reset_by_email') {
my %data = &Apache::lonnet::tmpget($mailtoken);
if (keys(%data) == 0) {
@@ -1266,6 +1302,12 @@ sub passwordchanger {
$user = $data{'username'};
$domain = $data{'domain'};
$currentpass = $data{'temppasswd'};
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('passwd',$clientip,$user,$domain);
+ if ($blocked) {
+ $r->print(''.$blocktext.'
');
+ return;
+ }
} else {
$r->print(
''
@@ -1278,9 +1320,9 @@ sub passwordchanger {
} else {
$r->print(
'
'
- .&mt('Sorry, the URL generated when you requested reset of'
- .' your password contained incomplete information.')
- .'
'
+ .&mt('Sorry, the URL generated when you requested reset of'
+ .' your password contained incomplete information.')
+ .''
);
return;
}
@@ -1325,7 +1367,7 @@ sub passwordchanger {
my $jsh=Apache::File->new($include."/londes.js");
$r->print(<$jsh>);
}
- $r->print(&jscript_send($caller,$extrafields));
+ $r->print(&jscript_send($caller,$domain,$currentauth,$extrafields));
$r->print(< 'New password needs at least one upper case letter',
+ lc => 'New password needs at least one lower case letter',
+ num => 'New password needs at least one number',
+ spec => 'New password needs at least one non-alphanumeric',
+ blank1 => 'Empty Password field',
+ blank2 => 'Empty Confirm Password field',
+ mismatch => 'Contents of Password and Confirm Password fields must match',
+ fail => 'Please fix the following:',
+ );
+ &js_escape(\%js_lt);
+ if ($currentauth eq 'internal:') {
+ if ($domain ne '') {
+ my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
+ if (keys(%passwdconf)) {
+ if ($passwdconf{min}) {
+ $min = $passwdconf{min};
+ }
+ if ($passwdconf{max}) {
+ $max = $passwdconf{max};
+ $js_lt{'long'} = &js_escape(&mt('Maximum password length: [_1]',$max));
+ }
+ if (ref($passwdconf{chars}) eq 'ARRAY') {
+ if (@{$passwdconf{chars}}) {
+ $rulestr = join('","',@{$passwdconf{chars}});
+ $numrules = scalar(@{$passwdconf{chars}});
+ }
+ }
+ }
+ }
+ }
+ $js_lt{'short'} = &js_escape(&mt('Minimum password length: [_1]',$min));
+
+ my $passwdcheck = <<"ENDJS";
+ var errors = new Array();
+ var min = parseInt("$min") || 0;
+ var currauth = "$currentauth";
+ if (this.document.client.elements.newpass_1.value == '') {
+ errors.push("$js_lt{'blank1'}");
+ }
+ if (this.document.client.elements.newpass_2.value == '') {
+ errors.push("$js_lt{'blank2'}");
+ }
+ if (errors.length == 0) {
+ if (this.document.client.elements.newpass_1.value != this.document.client.elements.newpass_2.value) {
+ errors.push("$js_lt{'mismatch'}");
+ }
+ var posspass = this.document.client.elements.newpass_1.value;
+ if (min > 0) {
+ if (posspass.length < min) {
+ errors.push("$js_lt{'short'}");
+ }
+ }
+ if (currauth == 'internal:') {
+ var max = parseInt("$max") || 0;
+ if (max > 0) {
+ if (posspass.length > max) {
+ errors.push("$js_lt{'long'}");
+ }
+ }
+ var numrules = parseInt("$numrules") || 0;
+ if (numrules > 0) {
+ var rules = new Array("$rulestr");
+ for (var i=0; i\\/?]/;
+ if (!posspass.match(pattern)) {
+ errors.push("$js_lt{'spec'}");
+ }
+ }
+ }
+ }
+ }
+ }
+ if (errors.length > 0) {
+ alert("$js_lt{'fail'}"+"\\n\\n"+errors.join("\\n"));
+ return;
+ }
+ENDJS
my $output = qq|
+ENDSCRIPT
+ my %loaditems = (
+ onload => 'javascript:toggleTZdisplay(document.prefs);',
+ );
+ my $args = { 'add_entries' => \%loaditems };
+ &Apache::lonhtmlcommon::add_breadcrumb(
+ { href => '/adm/preferences?action=',
+ text => 'Set Your Time Zone'});
+ $r->print(Apache::loncommon::start_page('Set Your Time Zone',$js,$args));
+ $r->print(Apache::lonhtmlcommon::breadcrumbs('Set Your Time Zone'));
+ my %userenv = &Apache::lonnet::get('environment',['timezone']);
+ my $timezone = $userenv{'timezone'};
+ my %lt = &Apache::lonlocal::texthash(
+ lctz => 'Use Time Zone set by LON-CAPA',
+ owntz => 'Use Time Zone set by you',
+ save => 'Save',
+ );
+ my (%checked,$tzsty);
+ if ($userenv{'timezone'} ne '') {
+ $checked{'owntz'} = ' checked="checked"';
+ $tzsty = 'inline-block';
+ } else {
+ $checked{'lctz'} = ' checked="checked"';
+ $tzsty = 'none';
+ }
+ my $onclick = ' onclick="javascript:toggleTZdisplay(this.form);"';
+ my $selector = &Apache::loncommon::select_timezone('timezone',$timezone,undef,1);
+ $r->print(<<"END");
+
+END
+ }
+ return;
+}
+
+sub verify_and_change_timezone {
+ my $r = shift;
+ my $currtimezone = $env{'environment.timezone'};
+ my $newtimezone;
+ if ($env{'form.settimezone'}) {
+ $newtimezone = $env{'form.timezone'};
+ if (DateTime::TimeZone->is_valid_name($env{'form.timezone'})) {
+ $newtimezone = $env{'form.timezone'};
+ }
+ }
+ my $message='';
+ if ($newtimezone) {
+ if ($newtimezone eq $currtimezone) {
+ $message = &mt('Time Zone settings unchanged');
+ } else {
+ &Apache::lonnet::put('environment',{'timezone' => $newtimezone});
+ &Apache::lonnet::appenv({'environment.timezone' => $newtimezone});
+ $message=&Apache::lonhtmlcommon::confirm_success(
+ &mt('Set [_1] to [_2]',
+ ''.&mt('Your Time Zone').'',
+ '"'.$newtimezone.'".')).
+ '
';
+ }
+ } elsif ($currtimezone) {
+ &Apache::lonnet::del('environment',['timezone']);
+ &Apache::lonnet::delenv('environment.timezone');
+ $message=&Apache::lonhtmlcommon::confirm_success(&mt('Time Zone now set by LON-CAPA'));
+ } else {
+ $message = &mt('Time Zone settings unchanged');
+ }
+ $message=&Apache::loncommon::confirmwrapper($message);
+ &print_main_menu($r,$message);
+ return;
+}
+
sub print_main_menu {
my ($r, $message) = @_;
# Determine current authentication method
@@ -2063,6 +2346,9 @@ my %permissions;
if (&Apache::lonnet::usertools_access($user,$domain,'aboutme')) {
$permissions{'aboutme'} = 'F';
}
+if (&Apache::lonnet::usertools_access($user,$domain,'timezone')) {
+ $permissions{'timezone'} = 'F';
+}
my @menu=
({ categorytitle=>'Personal Data',
items =>[
@@ -2105,6 +2391,14 @@ my @menu=
icon => 'dismath.png',
linktitle => 'Change how math is displayed.'
},
+ {
+ linktext => 'Time Zone',
+ url => '/adm/preferences?action=changetimezone',
+ permission => $permissions{'timezone'},
+ #help => '',
+ icon => 'timezone.png',
+ linktitle => 'Set your time zone.',
+ }
]
},
{ categorytitle=>'Page Display Settings',
@@ -2166,25 +2460,6 @@ push(@{ $menu[0]->{items} }, {
linktitle => 'Change your password.',
});
}
- if ($env{'environment.remote'} eq 'off') {
-push(@{ $menu[1]->{items} }, {
- linktext => 'Launch Remote Control',
- url => '/adm/remote?url=/adm/preferences&action=launch',
- permission => 'F',
- #help => '',
- icon => 'remotecontrol.png',
- linktitle => 'Launch the remote control for LON-CAPA.',
- });
- }else{
-push(@{ $menu[1]->{items} }, {
- linktext => 'Collapse Remote Control',
- url => '/adm/remote?url=/adm/preferences&action=collapse',
- permission => 'F',
- #help => '',
- icon => 'remotecontrol.png',
- linktitle => 'Collapse the remote control for LON-CAPA.',
- });
- }
if (&can_toggle_namelocking()) {
push(@{ $menu[0]->{items} }, {
@@ -2297,12 +2572,12 @@ sub handler {
text => $brtxt,
help => $brhelp,});
if(!exists $env{'form.action'}) {
- &print_main_menu($r);
- $ended = 1;
+ &print_main_menu($r);
+ $ended = 1;
}elsif($env{'form.action'} eq 'changepass'){
&passwordchanger($r);
}elsif($env{'form.action'} eq 'verify_and_change_pass'){
- &verify_and_change_password($r,'preferences','',\$ended);
+ &verify_and_change_password($r,'preferences','','','',\$ended);
}elsif($env{'form.action'} eq 'changescreenname'){
&screennamechanger($r);
}elsif($env{'form.action'} eq 'verify_and_change_screenname'){
@@ -2378,10 +2653,14 @@ sub handler {
&print_main_menu($r);
$ended = 1;
} elsif ($env{'form.action'} eq 'changelockednames') {
- &lockednameschanger($r);
+ $ended = &lockednameschanger($r);
} elsif ($env{'form.action'} eq 'verify_and_change_lockednames') {
&verify_and_change_lockednames($r);
$ended = 1;
+ } elsif ($env{'form.action'} eq 'changetimezone') {
+ &timezonechanger($r);
+ } elsif ($env{'form.action'} eq 'verify_and_change_timezone') {
+ &verify_and_change_timezone($r);
}
# Properly end the HTML page of all preference pages