--- loncom/interface/lonpreferences.pm 2019/08/21 22:41:13 1.235 +++ loncom/interface/lonpreferences.pm 2025/03/05 05:24:42 1.247 @@ -1,7 +1,7 @@ # The LearningOnline Network # Preferences # -# $Id: lonpreferences.pm,v 1.235 2019/08/21 22:41:13 raeburn Exp $ +# $Id: lonpreferences.pm,v 1.247 2025/03/05 05:24:42 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 # @@ -491,24 +491,24 @@ sub screennamechanger { text => 'Change Screen Name'}); $r->print(Apache::loncommon::start_page('Personal Data')); $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Screen Name')); - $r->print('

' + $r->print('

' .&mt('Change the name that is displayed in your posts.') .'

' ); $r->print('
' .'' .&Apache::lonhtmlcommon::start_pick_box() - .&Apache::lonhtmlcommon::row_title(&mt('Screenname').' '.&mt('(shown if you post anonymously)')) - .'' + .&Apache::lonhtmlcommon::row_title(' '.&mt('(shown if you post anonymously)')) + .'' .&Apache::lonhtmlcommon::row_closure() - .&Apache::lonhtmlcommon::row_title(&mt('Nickname').' '.&mt('(shown if you post non-anonymously)')) - .'' + .&Apache::lonhtmlcommon::row_title(' '.&mt('(shown if you post non-anonymously)')) + .'' .&Apache::lonhtmlcommon::row_closure() - .&Apache::lonhtmlcommon::row_title() + .&Apache::lonhtmlcommon::row_title(''.&mt('Submit').':','','','',1) .'' .&Apache::lonhtmlcommon::row_closure(1) .&Apache::lonhtmlcommon::end_pick_box() - .'
' + .'
' ); } @@ -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); @@ -864,6 +864,7 @@ sub msgforwardchanger { my $validatescript = &Apache::lonhtmlcommon::javascript_valid_email(); my $jscript = qq| |; $r->print(<print(' '); $r->print(< '/adm/preferences?action=changepass', text => 'Change Password'}); unless ($caller eq 'reset_by_email') { $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; + $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Password'). + '
'); } if ((!defined($caller)) || ($caller eq 'preferences')) { $user = $env{'user.name'}; @@ -1285,6 +1285,12 @@ sub passwordchanger { 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) { @@ -1301,6 +1307,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( '

' @@ -1360,11 +1372,11 @@ 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(< +

@@ -1377,11 +1389,105 @@ ENDFORM } sub jscript_send { - my ($caller,$extrafields) = @_; + my ($caller,$domain,$currentauth,$extrafields) = @_; + my ($min,$max,$rulestr,$numrules); + $min = $Apache::lonnet::passwdmin; + my %js_lt = &Apache::lonlocal::texthash( + uc => '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| |; } @@ -1456,16 +1563,16 @@ sub client_form { } else { $output .= &Apache::lonhtmlcommon::row_title( '') - .'' + .'' .&Apache::lonhtmlcommon::row_closure(); } $output .= &Apache::lonhtmlcommon::row_title( '') - .'' + .'' .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title( '') - .'' + .'' .&Apache::lonhtmlcommon::row_closure(1) .&Apache::lonhtmlcommon::end_pick_box(); if ($caller eq 'reset_by_email') { @@ -1480,7 +1587,6 @@ sub client_form { -

|; return $output; } @@ -1522,14 +1628,8 @@ sub server_form { } sub verify_and_change_password { - my ($r,$caller,$mailtoken,$ended) = @_; - my ($user,$domain,$homeserver); - my ($blocked,$blocktext) = - &Apache::loncommon::blocking_status('passwd'); - if ($blocked) { - $r->print('

'.$blocktext.'

'); - return; - } + my ($r,$caller,$mailtoken,$timelimit,$extrafields,$ended) = @_; + my ($user,$domain,$homeserver,$clientip); if ($caller eq 'reset_by_email') { $user = $env{'form.uname'}; $domain = $env{'form.udom'}; @@ -1538,20 +1638,31 @@ sub verify_and_change_password { if ($homeserver eq 'no_host') { &passwordchanger($r,"

\n". &mt("Invalid username and/or domain")."\n

", - $caller,$mailtoken); - return 1; + $caller,$mailtoken,$timelimit,$extrafields); + return 'no_host'; } } else { &passwordchanger($r,"

\n". &mt("Username and domain were blank")."\n

", - $caller,$mailtoken); - return 1; + $caller,$mailtoken,$timelimit,$extrafields); + return 'missingdata'; } } else { $user = $env{'user.name'}; $domain = $env{'user.domain'}; $homeserver = $env{'user.home'}; } + $clientip = &Apache::lonnet::get_requestor_ip($r); + my ($blocked,$blocktext) = + &Apache::loncommon::blocking_status('passwd',$clientip,$user,$domain); + if ($blocked) { + $r->print('

'.$blocktext.'

'); + if ($caller eq 'reset_by_email') { + return 'blocked'; + } else { + return; + } + } my $currentauth=&Apache::lonnet::queryauthenticate($user,$domain); # Check for authentication types that allow changing of the password. if ($currentauth !~ /^(unix|internal):/) { @@ -1559,8 +1670,8 @@ sub verify_and_change_password { &passwordchanger($r,"

\n". &mt("Authentication type for this user can not be changed by this mechanism"). "\n

", - $caller,$mailtoken); - return 1; + $caller,$mailtoken,$timelimit,$extrafields); + return 'otherauth'; } else { return; } @@ -1576,8 +1687,12 @@ sub verify_and_change_password { defined($newpass2) ){ &passwordchanger($r,"

\n". &mt("One or more password fields were blank"). - "\n

",$caller,$mailtoken); - return; + "\n

",$caller,$mailtoken,$timelimit,$extrafields); + if ($caller eq 'reset_by_email') { + return 'missingdata'; + } else { + return; + } } # Get the keys my $lonhost = $r->dir_config('lonHostID'); @@ -1595,7 +1710,11 @@ sub verify_and_change_password {

ENDERROR # Probably should log an error here - return 1; + if ($caller eq 'reset_by_email') { + return 'internalerror'; + } else { + return; + } } my ($ckey,$n1key,$n2key)=split(/&/,$tmpinfo); # @@ -1609,31 +1728,39 @@ ENDERROR &passwordchanger($r, ''. &mt('Could not verify current authentication.').' '. - &mt('Please try again.').'',$caller,$mailtoken); - return 1; + &mt('Please try again.').'',$caller,$mailtoken,$timelimit,$extrafields); + return 'emptydata'; } if ($currentpass ne $data{'temppasswd'}) { &passwordchanger($r, ''. &mt('Could not verify current authentication.').' '. - &mt('Please try again.').'',$caller,$mailtoken); - return 1; + &mt('Please try again.').'',$caller,$mailtoken,$timelimit,$extrafields); + return 'missingtemp'; } } if ($newpass1 ne $newpass2) { &passwordchanger($r, ''. &mt('The new passwords you entered do not match.').' '. - &mt('Please try again.').'',$caller,$mailtoken); - return 1; + &mt('Please try again.').'',$caller,$mailtoken,$timelimit,$extrafields); + if ($caller eq 'reset_by_email') { + return 'mismatch'; + } else { + return; + } } if ($currentauth eq 'unix:') { if (length($newpass1) < 7) { &passwordchanger($r, ''. &mt('Passwords must be a minimum of 7 characters long.').' '. - &mt('Please try again.').'',$caller,$mailtoken); - return 1; + &mt('Please try again.').'',$caller,$mailtoken,$timelimit,$extrafields); + if ($caller eq 'reset_by_email') { + return 'length'; + } else { + return; + } } } else { my $warning = &Apache::loncommon::check_passwd_rules($domain,$newpass1); @@ -1641,8 +1768,12 @@ ENDERROR &passwordchanger($r,''. $warning. &mt('Please try again.').'', - $caller,$mailtoken); - return 1; + $caller,$mailtoken,$timelimit,$extrafields); + if ($caller eq 'reset_by_email') { + return 'rules'; + } else { + return; + } } } # @@ -1662,8 +1793,12 @@ ENDERROR ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\`abcdefghijklmnopqrstuvwxyz{|}~ ENDERROR - &passwordchanger($r,$errormessage,$caller,$mailtoken); - return 1; + &passwordchanger($r,$errormessage,$caller,$mailtoken,$timelimit,$extrafields); + if ($caller eq 'reset_by_email') { + return 'badchars'; + } else { + return; + } } # # Change the password (finally) @@ -1686,7 +1821,7 @@ ENDERROR # error error: run in circles, scream and shout if ($caller eq 'reset_by_email') { if (!$result) { - return 1; + return 'error'; } else { return $result; } @@ -1948,9 +2083,117 @@ sub author_space_settings { my $domain = $env{'user.domain'}; my %author_roles = &Apache::lonnet::get_my_roles($user,$domain,'userroles','',['au','ca','aa']); if (keys(%author_roles) > 0) { - $r->print(Apache::loncommon::start_page('Authoring Space Settings')); - $r->print(Apache::lonhtmlcommon::breadcrumbs('Authoring Space Settings')); - my %userenv = &Apache::lonnet::get('environment',['nocodemirror']); + my ($showdomdefs,$js,$args,@items); + my $returnurl = &HTML::Entities::encode($env{'form.returnurl'},'"<>&\''); + if (&expanded_authoring_settings()) { + @items = ('nocodemirror'); + if (&daxe_permitted(\%author_roles)) { + push(@items,'daxecollapse'); + } + push(@items,('copyright','sourceavail')); + $showdomdefs = 1; + $js = &toggle_options_js(); + my $onload; + foreach my $item (@items) { + $onload .= "javascript:toggleOptions(document.prefs,'$item','user_$item');" + } + $args = { 'add_entries' => { 'onload' => $onload } }; + } + $r->print(Apache::loncommon::start_page('Authoring Space Settings',$js,$args)); + $r->print(Apache::lonhtmlcommon::breadcrumbs('Authoring Space Settings')); + if ($showdomdefs) { + my %userenv = &Apache::lonnet::get('environment',\@items); + my %domdefs = &Apache::lonnet::get_domain_defaults($domain); + my %staticdefaults = ( + 'nocodemirror' => '0', + 'daxecollapse' => '0', + 'copyright' => 'default', + 'sourceavail' => 'closed', + ); + my %lt = &authoring_settings_text(); + my %titles = &authoring_settings_titles(); + $r->print("

$lt{'auss'}

". + '
'."\n". + '

'."\n". + ''."\n". + ''."\n"); + foreach my $item (@items) { + my ($domdef,$checkeddom,$checkeduser,$domdefdisplay,$divsty,$userelem); + $checkeddom = ' checked="checked"'; + $divsty = 'display:none'; + if (exists($domdefs{$item})) { + $domdef = $domdefs{$item}; + } else { + $domdef = $staticdefaults{$item}; + } + if ($item eq 'copyright') { + $domdefdisplay = &Apache::loncommon::copyrightdescription($domdef); + $userelem = &selectbox('userchoice_'.$item,$userenv{$item},'', + \&Apache::loncommon::copyrightdescription, + (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))); + } elsif ($item eq 'sourceavail') { + $domdefdisplay = &Apache::loncommon::source_copyrightdescription($domdef); + $userelem = &selectbox('userchoice_'.$item,$userenv{$item},'', + \&Apache::loncommon::source_copyrightdescription, + (&Apache::loncommon::source_copyrightids)); + } elsif (($item eq 'nocodemirror') || ($item eq 'daxecollapse')) { + if ($domdef) { + if ($item eq 'daxecollapse') { + $domdefdisplay = $lt{'coll'}; + } else { + $domdefdisplay = $lt{'yes'}; + } + } else { + if ($item eq 'daxecollapse') { + $domdefdisplay = $lt{'expa'}; + } else { + $domdefdisplay = $lt{'no'}; + } + } + my (%checked,%text); + $checked{'no'} = ' checked="checked"'; + if ($userenv{$item} eq 'yes') { + $checked{'yes'} = $checked{'no'}; + $checked{'no'} = ''; + } + if ($item eq 'daxecollapse') { + %text = ( + yes => $lt{'coll'}, + no => $lt{'expa'}, + ); + } else { + %text = ( + yes => $lt{'yes'}, + no => $lt{'no'}, + ); + } + $userelem = ''; + foreach my $choice ('yes','no') { + $userelem .= '   '; + } + $userelem .= ''; + } + if ($userenv{$item} ne '') { + $checkeduser = $checkeddom; + $checkeddom = ''; + $divsty = 'display:inline-block'; + } + $r->print(<<"END"); +

$titles{$item}

+

$lt{'curd'}: $domdefdisplay

+

+    +

+
+$lt{'ousv'} +$userelem +


+END + } + $r->print(''. + '
'."\n"); + } else { my $constchecked=''; if ($env{'environment.nocodemirror'}) { $constchecked=' checked="checked"'; @@ -1958,7 +2201,6 @@ sub author_space_settings { my $text=&mt('By default, CodeMirror an editor with advanced functionality for editing code is activated for authors.'); my $cmoff=&mt('Deactivate CodeMirror. This can improve performance on slow computers and accessibility.'); my $change=&mt('Save'); - my $returnurl = &HTML::Entities::encode($env{'form.returnurl'},'"<>&\''); $r->print(< @@ -1968,6 +2210,7 @@ sub author_space_settings { ENDSCREEN + } } } @@ -1977,6 +2220,8 @@ sub change_authoring_settings { my $domain = $env{'user.domain'}; my %author_roles = &Apache::lonnet::get_my_roles($user,$domain,'userroles','',['au','ca','aa']); if (keys(%author_roles) > 0) { + my $message; + if (!&expanded_authoring_settings()) { my %ausettings=('environment.nocodemirror' => ''); if ($env{'form.cmoff'}) { $ausettings{'environment.nocodemirror'}='yes'; } &Apache::lonnet::put('environment',\%ausettings); @@ -1987,25 +2232,195 @@ sub change_authoring_settings { } else { $status=&mt('off'); } - my $message=&Apache::lonhtmlcommon::confirm_success(&mt('Set [_1] to [_2]',''.&mt('Deactivate CodeMirror in Authoring Space').'',''.$status.'')); + $message=&Apache::lonhtmlcommon::confirm_success(&mt('Set [_1] to [_2]',''.&mt('Deactivate CodeMirror in Authoring Space').'',''.$status.'')); $message=&Apache::loncommon::confirmwrapper($message); - if ($env{'form.returnurl'}) { - &do_redirect($r,$env{'form.returnurl'},$message); + } else { + my @items = ('nocodemirror'); + if (&daxe_permitted(\%author_roles)) { + push(@items,'daxecollapse'); + } + push(@items,('copyright','sourceavail')); + my %oldsettings = &Apache::lonnet::get('environment',\@items); + my %domdefs = &Apache::lonnet::get_domain_defaults($domain); + my %lt = &authoring_settings_text(); + my %titles = &authoring_settings_titles(); + my ($result,%newsettings,%changes,@delete,@unchanged,@delerrors,@adderrors); + foreach my $item (@items) { + if ($env{'form.'.$item} eq 'dom') { + if ($oldsettings{$item} eq '') { + push(@unchanged,$item); + } else { + push(@delete,$item); + } + } elsif ($env{'form.'.$item} eq 'user') { + my $newval = $env{'form.userchoice_'.$item}; + my @possibles; + if (($item eq 'nocodemirror') || ($item eq 'daxecollapse')) { + if ($newval =~ /^yes|no$/) { + $newsettings{$item} = $newval; + } + } elsif ($item eq 'copyright') { + @possibles = (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids)); + if (grep(/^\Q$newval\E$/,@possibles)) { + $newsettings{$item} = $newval; + } + } elsif ($item eq 'sourceavail') { + @possibles = (&Apache::loncommon::source_copyrightids); + if (grep(/^\Q$newval\E$/,@possibles)) { + $newsettings{$item} = $newval; + } + } + if ($oldsettings{$item} eq $newsettings{$item}) { + push(@unchanged,$item); + } else { + $changes{$item} = $newsettings{$item}; + } + } + } + if (@delete) { + if (&Apache::lonnet::del('environment',\@delete) eq 'ok') { + foreach my $key (@delete) { + &Apache::lonnet::delenv('environment.'.$key); + } + } else { + @delerrors = @delete; + } + } + if (keys(%changes)) { + if (&Apache::lonnet::put('environment',\%changes) eq 'ok') { + my %newenvhash; + map {$newenvhash{'environment.'.$_} = $changes{$_}; } (keys(%changes)); + &Apache::lonnet::appenv(\%newenvhash); + } else { + foreach my $item (@items) { + if (exists($changes{$item})) { + push(@adderrors,$item); + } + } + } + } + if (@adderrors) { + $result = &mt('An error occurred when saving user-specific settings for').': '. + join(', ', map { $titles{$_} } @adderrors); + $message = &Apache::loncommon::confirmwrapper(&Apache::lonhtmlcommon::confirm_success($result,1)); + } elsif (keys(%changes)) { + $result = &mt('User-specific settings saved:').'
    '; + foreach my $item (@items) { + next unless (exists($changes{$item})); + my $value = $changes{$item}; + if ($item eq 'nocodemirror') { + $value = $lt{$changes{$item}}; + } elsif ($item eq 'daxecollapse') { + if ($value eq 'yes') { + $value = $lt{'coll'}; + } else { + $value = $lt{'expa'}; + } + } elsif ($item eq 'copyright') { + $value = &Apache::loncommon::copyrightdescription($changes{$item}); + } elsif ($item eq 'sourceavail') { + $value = &Apache::loncommon::source_copyrightdescription($changes{$item}); + } + $result .= '
  • '. + &mt('[_1] set to [_2]', + $titles{$item}, + ''.$value.''). + '
  • '; + } + $result .= '
'; + $message = &Apache::loncommon::confirmwrapper(&Apache::lonhtmlcommon::confirm_success($result)); + } + if (@delerrors) { + $result = &mt('An error occurred when deleting user-specific settings for').':
  • '. + join('
  • ', map { $titles{$_} } @delerrors).'
'; + $message .= &Apache::loncommon::confirmwrapper(&Apache::lonhtmlcommon::confirm_success($result,1)); + } elsif (@delete) { + $result = &mt('Set use of domain default for').':
  • '. + join('
  • ', map { $titles{$_} } @delete).'
'; + $message .= &Apache::loncommon::confirmwrapper(&Apache::lonhtmlcommon::confirm_success($result)); + } + if (@unchanged) { + $result = &mt('No changes made for').':
  • '. + join('
  • ', map { $titles{$_} } @unchanged).'
'; + $message .= &Apache::loncommon::confirmwrapper(&Apache::lonhtmlcommon::confirm_success($result)); + } + } + if ($env{'form.returnurl'}) { + &do_redirect($r,$env{'form.returnurl'},$message); + } else { + &print_main_menu($r,$message); + } + } +} + +sub authoring_settings_text { + return &Apache::lonlocal::texthash( + 'auss' => 'Authoring Space Settings', + 'used' => 'Use domain default', + 'usyo' => 'Use your own user-specific setting', + 'curd' => 'Current domain default is', + 'ousv' => 'Own user-specific value', + 'save' => 'Save', + 'yes' => 'Deactivated', + 'no' => 'Activated', + 'expa' => 'Start Expanded', + 'coll' => 'Start Collapsed', + ); +} + +sub authoring_settings_titles { + return &Apache::lonlocal::texthash( + 'nocodemirror' => 'CodeMirror for EditXML editor', + 'daxecollapse' => 'Daxe editor: collapsible standard LON-CAPA menus', + 'copyright' => 'Default Copyright/Distribution in new metadata file', + 'sourceavail' => 'Default Source Available in new metadata file', + ); +} + +sub expanded_authoring_settings { + my $reqdmajor = 2; + my $reqdminor = 12; + my $loncaparev = &Apache::lonnet::get_server_loncaparev($env{'user.domain'},$env{'user.home'}); + my ($major,$minor) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); + unless (($major eq '' && $minor eq '') || + ($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor))) { + return 1; + } + return; +} + +sub daxe_permitted { + my ($aurolesref) = @_; + my $hasdaxe; + if (ref($aurolesref) eq 'HASH') { + my %editors; + foreach my $key (keys(%{$aurolesref})) { + if ($key =~ /^:$LONCAPA::match_domain:au$/) { + if (exists($env{'environment.editors'})) { + if (grep(/^daxe$/,split(/,/,$env{'environment.editors'}))) { + $hasdaxe = 1; + last; + } + } } else { - &print_main_menu($r,$message); + my ($auname,$audom) = ($key =~ /^($LONCAPA::match_username):($LONCAPA::match_domain):(ca|aa)$/); + if (exists($env{"environment.internal.editors./$audom/$auname"})) { + if (grep(/^daxe$/,split(/,/,$env{"environment.internal.editors./$audom/$auname"}))) { + $hasdaxe = 1; + last; + } + } } + } } + return $hasdaxe; } sub lockednameschanger { my $r = shift; - &Apache::lonhtmlcommon::add_breadcrumb( - { href => '/adm/preferences?action=changelockednames', - text => 'Automatic name changes'}); - $r->print(Apache::loncommon::start_page('Automatic name changes')); - $r->print(Apache::lonhtmlcommon::breadcrumbs('Allow/disallow name updates')); my %userenv = &Apache::lonnet::get('environment',['lockedname']); my $lockedname=''; + my $ended; if (&can_toggle_namelocking()) { if ($userenv{'lockedname'}) { $lockedname = ' checked="checked"'; @@ -2023,6 +2438,11 @@ sub lockednameschanger { } } if (keys(%updateable)) { + &Apache::lonhtmlcommon::add_breadcrumb( + { href => '/adm/preferences?action=changelockednames', + text => 'Automatic name changes'}); + $r->print(Apache::loncommon::start_page('Automatic name changes')); + $r->print(Apache::lonhtmlcommon::breadcrumbs('Allow/disallow name updates')); my %longnames = &Apache::lonlocal::texthash ( firstname => 'First Name', middlename => 'Middle Name', @@ -2049,11 +2469,14 @@ ENDSCREEN } else { my $message = &mt('Based on your institutional affiliation no name information is automatically updated for your LON-CAPA account.'); &print_main_menu($r,$message); + $ended = 1; } } else { my $message = &mt('You are not permitted to set a user preference for automatic name updates for your LON-CAPA account.'); &print_main_menu($r,$message); + $ended = 1; } + return $ended; } sub verify_and_change_lockednames { @@ -2084,6 +2507,90 @@ sub verify_and_change_lockednames { &print_main_menu($r,$message); } +sub timezonechanger { + my $r = shift; + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + if (&Apache::lonnet::usertools_access($uname,$udom,'timezone')) { + my $js = &toggle_options_js(); + my %loaditems = ( + onload => "javascript:toggleOptions(document.prefs,'settimezone','LC_timezone_selector');", + ); + 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:toggleOptions(this.form,'."'settimezone','LC_timezone_selector'".');"'; + my $selector = &Apache::loncommon::select_timezone('timezone',$timezone,undef,1); + $r->print(<<"END"); +
+ + +     +
  +$selector +


+ +
+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 @@ -2098,6 +2605,11 @@ 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 %author_roles = &Apache::lonnet::get_my_roles($user,$domain,'userroles','',['au']); +my %author_coauthor_roles = &Apache::lonnet::get_my_roles($user,$domain,'userroles','',['au','ca','aa']); my @menu= ({ categorytitle=>'Personal Data', items =>[ @@ -2106,6 +2618,7 @@ my @menu= permission => $permissions{'aboutme'}, #help => 'Prefs_About_Me', icon => 'system-users.png', + alttext => 'About Me Icon', linktitle => 'Edit information about yourself that should be displayed on your public profile.' }, { linktext => 'Screen Name', @@ -2113,6 +2626,7 @@ my @menu= permission => 'F', #help => 'Prefs_Screen_Name_Nickname', icon => 'preferences-desktop-font.png', + alttext => 'Nickname Icon', linktitle => 'Change the name that is displayed in your posts.' }, ] @@ -2124,6 +2638,7 @@ my @menu= permission => 'F', #help => 'Prefs_Language', icon => 'preferences-desktop-locale.png', + alttext => 'Language Icon', linktitle => 'Choose the default language for this user.' }, { linktext => $role.' Page', @@ -2131,6 +2646,7 @@ my @menu= permission => 'F', #help => '', icon => 'role_hotlist.png', + alttext => 'Switch Role Icon', linktitle => 'Configure the roles hotlist.' }, { linktext => 'Math display settings', @@ -2138,8 +2654,18 @@ my @menu= permission => 'F', #help => '', icon => 'dismath.png', + alttext => 'Math Icon', linktitle => 'Change how math is displayed.' }, + { + linktext => 'Time Zone', + url => '/adm/preferences?action=changetimezone', + permission => $permissions{'timezone'}, + #help => '', + icon => 'timezone.png', + alttext => 'Clock Icon', + linktitle => 'Set your time zone.', + } ] }, { categorytitle=>'Page Display Settings', @@ -2149,6 +2675,7 @@ my @menu= permission => 'F', #help => 'Change_Colors', icon => 'preferences-desktop-theme.png', + alttext => 'Colors Icon', linktitle => 'Change LON-CAPA default colors.' }, { linktext => 'Menu Display', @@ -2156,6 +2683,7 @@ my @menu= permission => 'F', #help => '', icon => 'preferences-system-windows.png', + alttext => 'Menus Icon', linktitle => 'Change whether the menus are displayed with icons or icons and text.' } ] @@ -2167,6 +2695,7 @@ my @menu= permission => 'F', #help => 'Prefs_Messages', icon => 'mail-reply-all.png', + alttext => 'Notifications Icon', linktitle => 'Change messageforwarding or notifications settings.' }, { linktext => 'Discussion Display', @@ -2174,10 +2703,40 @@ my @menu= permission => 'F', #help => 'Change_Discussion_Display', icon => 'chat.png', + alttext => 'Discussions Icon', linktitle => 'Set display preferences for discussion posts for both discussion boards and individual resources in all your courses.' }, ] }, + ); +if (keys(%author_coauthor_roles) > 0) { + push(@menu, + { categorytitle=>'Authoring Settings', + items => [ + { + linktext => 'Authoring Space Configuration', + url => '/adm/preferences?action=authorsettings', + permission => 'F', + icon => 'codemirror.png', + alttext => 'Coding Icon', + linktitle => 'Settings for your authoring space.', + }, + ] + }, + ); + if (keys(%author_roles) > 0) { + push(@{ $menu[4]->{items} }, { + linktext => 'Restrict Domain Coordinator Access', + url => '/adm/preferences?action=changedomcoord', + permission => 'F', + #help => '', + icon => 'system-lock-screen.png', + alttext => 'Lock Icon', + linktitle => 'Restrict domain coordinator access.', + }); + } +} +push(@menu, { categorytitle=>'Other', items =>[ { linktext => 'Register Response Devices ("Clickers")', @@ -2185,19 +2744,21 @@ my @menu= permission => 'F', #help => '', icon => 'network-workgroup.png', + alttext => 'Clicker Icon', linktitle => 'Register your clicker.' }, ] }, - ); +); if ($currentauth =~ /^(unix|internal):/) { -push(@{ $menu[0]->{items} }, { + push(@{ $menu[0]->{items} }, { linktext => 'Password', url => '/adm/preferences?action=changepass', permission => 'F', #help => 'Change_Password', icon => 'emblem-readonly.png', + alttext => 'Secure Icon', linktitle => 'Change your password.', }); } @@ -2209,62 +2770,42 @@ push(@{ $menu[0]->{items} }, { permission => 'F', #help => '', icon => 'system-lock-screen.png', + alttext => 'Screen Lock Icon', linktitle => 'Allow/disallow propagation of name changes from institutional directory service', }); } - my %author_roles = &Apache::lonnet::get_my_roles($user,$domain,'userroles','',['au']); - if (keys(%author_roles) > 0) { -push(@{ $menu[4]->{items} }, { - linktext => 'Restrict Domain Coordinator Access', - url => '/adm/preferences?action=changedomcoord', - permission => 'F', - #help => '', - icon => 'system-lock-screen.png', - linktitle => 'Restrict domain coordinator access.', - }); - } - if (&Apache::lonnet::allowed('whn',$env{'request.course.id'}) || &Apache::lonnet::allowed('whn',$env{'request.course.id'}.'/' .$env{'request.course.sec'})) { -push(@{ $menu[4]->{items} }, { +push(@{ $menu[-1]->{items} }, { linktext => 'Course Initialization', url => '/adm/preferences?action=changecourseinit', permission => 'F', #help => '', icon => 'course_ini.png', + alttext => 'Course Launch Icon', linktitle => 'Set the default page to be displayed when you select a course role.', }); } - my %author_coauthor_roles = &Apache::lonnet::get_my_roles($user,$domain,'userroles','',['au','ca','aa']); - if (keys(%author_coauthor_roles) > 0) { - push(@{ $menu[4]->{items} }, { - linktext => 'Authoring Space Configuration', - url => '/adm/preferences?action=authorsettings', - permission => 'F', - icon => 'codemirror.png', - linktitle => 'Settings for your authoring space.', - }); - } - if (&can_toggle_debug()) { -push(@{ $menu[4]->{items} }, { +push(@{ $menu[-1]->{items} }, { linktext => 'Toggle Debug Messages (Currently '.($env{'user.debug'} ? 'on)' : 'off)'), url => '/adm/preferences?action=debugtoggle', permission => 'F', #help => '', icon => 'blog.png', + alttext => 'Debugging Icon', linktitle => 'Toggle Debug Messages.', }); } $r->print(&Apache::loncommon::start_page('My Space')); $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Preferences')); - $r->print($message); - $r->print(Apache::lonhtmlcommon::generate_menu(@menu)); + $r->print('
'."\n".$message); + $r->print(Apache::lonhtmlcommon::generate_menu(@menu)."\n".'
'); $r->print(Apache::loncommon::end_page()); } @@ -2317,8 +2858,9 @@ sub handler { $ended = 1; }elsif($env{'form.action'} eq 'changepass'){ &passwordchanger($r); + $r->print('
'); }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'){ @@ -2394,10 +2936,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 @@ -2479,13 +3025,66 @@ sub updateable_userinfo { sub do_redirect { my ($r,$url,$msg) = @_; $r->print( - &Apache::loncommon::start_page('Switching Server ...',undef, - {'redirect' => [0.5,$url]}). + &Apache::loncommon::start_page('Loading ...',undef, + {'redirect' => [2,$url]}). '
'."\n". "$msg\n". &Apache::loncommon::end_page()); return; } +sub toggle_options_js { + return <<"ENDSCRIPT"; + +ENDSCRIPT +} + +sub selectbox { + my ($name,$value,$readonly,$functionref,@idlist)=@_; + my $selout = ''; + return $selout; +} + 1; __END__