--- loncom/interface/lonpreferences.pm 2009/10/09 01:44:26 1.125.4.7
+++ loncom/interface/lonpreferences.pm 2025/03/05 02:27:00 1.246
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Preferences
#
-# $Id: lonpreferences.pm,v 1.125.4.7 2009/10/09 01:44:26 raeburn Exp $
+# $Id: lonpreferences.pm,v 1.246 2025/03/05 02:27:00 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -27,67 +27,19 @@
#
# This package uses the "londes.js" javascript code.
#
-# TODOs that have to be completed:
-# interface with lonnet to change the password
package Apache::lonpreferences;
use strict;
-use LONCAPA;
use Apache::Constants qw(:common);
use Apache::File;
-use Crypt::DES;
-use DynaLoader; # for Crypt::DES version
use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::lonlocal;
use Apache::lonnet;
use LONCAPA::lonauthcgi();
use LONCAPA();
-
-#
-# Write lonnet::passwd to do the call below.
-# Use:
-# my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
-#
-##################################################
-# password associated functions #
-##################################################
-sub des_keys {
- # Make a new key for DES encryption.
- # Each key has two parts which are returned separately.
- # Please note: Each key must be passed through the &hex function
- # before it is output to the web browser. The hex versions cannot
- # be used to decrypt.
- my @hexstr=('0','1','2','3','4','5','6','7',
- '8','9','a','b','c','d','e','f');
- my $lkey='';
- for (0..7) {
- $lkey.=$hexstr[rand(15)];
- }
- my $ukey='';
- for (0..7) {
- $ukey.=$hexstr[rand(15)];
- }
- return ($lkey,$ukey);
-}
-
-sub des_decrypt {
- my ($key,$cyphertext) = @_;
- my $keybin=pack("H16",$key);
- my $cypher;
- if ($Crypt::DES::VERSION>=2.03) {
- $cypher=new Crypt::DES $keybin;
- } else {
- $cypher=new DES $keybin;
- }
- my $plaintext=
- $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));
- $plaintext.=
- $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));
- $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );
- return $plaintext;
-}
+use DateTime::TimeZone();
################################################################
# Handler subroutines #
@@ -99,6 +51,12 @@ sub des_decrypt {
sub wysiwygchanger {
my $r = shift;
+ Apache::lonhtmlcommon::add_breadcrumb(
+ { href => '/adm/preferences?action=changewysiwyg',
+ text => 'Change WYSIWYG Preferences'});
+ $r->print(Apache::loncommon::start_page('Content Display Settings'));
+ $r->print(Apache::lonhtmlcommon::breadcrumbs('Change WYSIWYG Preferences'));
+
my %userenv = &Apache::lonnet::get
('environment',['wysiwygeditor']);
my $onselect='checked="checked"';
@@ -111,7 +69,7 @@ sub wysiwygchanger {
my $switchon=&mt('Enable WYSIWYG editor');
my $warning='';
if ($env{'user.adv'}) {
- $warning.="
".&mt("The WYSIWYG editor only supports simple HTML and is in many cases unsuited for advanced authoring. In a number of cases, it may destroy advanced authoring involving LaTeX and script function calls.")."
";
+ $warning.='
'.&mt("The WYSIWYG editor only supports simple HTML and is in many cases unsuited for advanced authoring. In a number of cases, it may destroy advanced authoring involving LaTeX and script function calls.")."
";
}
$r->print(<
@@ -132,9 +90,7 @@ sub verify_and_change_wysiwyg {
&Apache::lonnet::appenv({'environment.wysiwygeditor' => $newsetting});
my $message=&Apache::lonhtmlcommon::confirm_success(&mt('Set [_1] to [_2]',''.&mt('WYSIWYG Editor').'',''.&mt($newsetting).''));
$message=&Apache::loncommon::confirmwrapper($message);
- $r->print(< '/adm/preferences?action=changelanguages',
+ text => 'Change Language'});
+ $r->print(Apache::loncommon::start_page('Content Display Settings'));
+ $r->print(Apache::lonhtmlcommon::breadcrumbs('Change Language'));
+ my %userenv = &Apache::lonnet::get('environment',['languages']);
my $language=$userenv{'languages'};
- my $pref=&mt('Preferred language');
- my %langchoices=('' => 'No language preference');
- foreach (&Apache::loncommon::languageids()) {
- if (&Apache::loncommon::supportedlanguagecode($_)) {
- $langchoices{&Apache::loncommon::supportedlanguagecode($_)}
- = &Apache::loncommon::plainlanguagedescription($_);
- }
- }
- my $selectionbox=&Apache::loncommon::select_form($language,'language',
- %langchoices);
- $r->print(<
-
- $pref: $selectionbox
-ENDLSCREEN
- $r->print(' ');
+ $r->print(
+ ''
+ );
}
@@ -178,7 +128,12 @@ sub verify_and_change_languages {
if ($newlanguage) {
&Apache::lonnet::put('environment',{'languages' => $newlanguage});
&Apache::lonnet::appenv({'environment.languages' => $newlanguage});
- $message=&Apache::lonhtmlcommon::confirm_success(&mt('Set [_1] to [_2]',''.&mt('Preferred language').'','"'.$newlanguage.'".'));
+ $message=&Apache::lonhtmlcommon::confirm_success(
+ &mt('Set [_1] to [_2]',
+ ''.&mt('Preferred language').'',
+ '"'.$newlanguage.'".'))
+ .' '
+ .&mt('The change will become active on the next page.');
} else {
&Apache::lonnet::del('environment',['languages']);
&Apache::lonnet::delenv('environment.languages');
@@ -186,9 +141,7 @@ sub verify_and_change_languages {
}
$message=&Apache::loncommon::confirmwrapper($message);
&Apache::loncommon::flush_langs_cache($user,$domain);
- $r->print(< '/adm/preferences?action=changetexenginepref',
+ text => 'Math display settings'});
+ $r->print(Apache::loncommon::start_page('Content Display Settings'));
+ $r->print(Apache::lonhtmlcommon::breadcrumbs('Math display settings'));
my $user = $env{'user.name'};
my $domain = $env{'user.domain'};
my %userenv = &Apache::lonnet::get('environment',['texengine']);
my $texengine=$userenv{'texengine'};
+ if (lc($texengine) eq 'jsmath') {
+ $texengine = 'MathJax';
+ }
my %mathchoices=('' => 'Default',
'tth' => 'tth (TeX to HTML)',
#'ttm' => 'TeX to MathML',
- 'jsMath' => 'jsMath',
+ 'MathJax' => 'MathJax',
'mimetex' => 'mimetex (Convert to Images)',
'raw' => 'Raw (Screen Reader)'
);
- my $selectionbox=&Apache::loncommon::select_form($texengine,'texengine',
- %mathchoices);
- my $jsMath_start=&Apache::lontexconvert::jsMath_header();
+ %mathchoices = &Apache::lonlocal::texthash(%mathchoices);
+ my $selectionbox=
+ &Apache::loncommon::select_form(
+ $texengine,
+ 'texengine',
+ \%mathchoices);
+ my $MathJax_start=&Apache::lontexconvert::MathJax_header();
my %lt=&Apache::lonlocal::texthash(
- 'headline' => 'Change Math Preferences',
- 'preftxt' => 'Preferred method to display Math',
+ 'headline' => 'Change how math is displayed',
+ 'preftxt' => 'Preferred method to display math',
'change' => 'Save',
'exmpl' => 'Examples',
- 'jsmath' => 'jsMath:',
+ 'mathjax' => 'MathJax:',
+ '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):',
);
- my $jsMathWarning='
'
- .'
'
- .&mt("It looks like you don't have the TeX math fonts installed.")
- .'
'
- .'
'
- .&mt('The jsMath example on this page may not look right without them. '
- .'The [_1]jsMath Home Page[_2] has information on how to download the '
- .'needed fonts. In the meantime, jsMath will do the best it can '
- .'with the fonts you have, but it may not be pretty and some equations '
- .'may not be rendered correctly.'
- ,''
- ,'')
- .'
'
- .'';
-
$r->print(<$lt{'headline'}
+ENDSCREEN
+ }
+ }
+}
+
+sub change_authoring_settings {
+ my $r = shift;
+ my $user = $env{'user.name'};
+ 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);
+ &Apache::lonnet::appenv({'environment.nocodemirror' => $ausettings{'environment.nocodemirror'}});
+ my $status='';
+ if ($ausettings{'environment.nocodemirror'} eq 'yes') {
+ $status=&mt('on');
+ } else {
+ $status=&mt('off');
+ }
+ $message=&Apache::lonhtmlcommon::confirm_success(&mt('Set [_1] to [_2]',''.&mt('Deactivate CodeMirror in Authoring Space').'',''.$status.''));
+ $message=&Apache::loncommon::confirmwrapper($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:').'
';
+ $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 {
+ 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;
+ my %userenv = &Apache::lonnet::get('environment',['lockedname']);
+ my $lockedname='';
+ my $ended;
+ if (&can_toggle_namelocking()) {
+ if ($userenv{'lockedname'}) {
+ $lockedname = ' checked="checked"';
+ }
+ my %updateable;
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['autoupdate'],$env{'user.domain'});
+ if (ref($domconfig{'autoupdate'}) eq 'HASH') {
+ if ($domconfig{'autoupdate'}{'run'}) {
+ my @inststatuses = split(':',$env{'environment.inststatus'});
+ unless (@inststatuses) {
+ @inststatuses = ('default');
+ }
+ %updateable = &updateable_userinfo($domconfig{'autoupdate'},\@inststatuses);
+ }
+ }
+ 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',
+ lastname => 'Last Name',
+ );
+ my $text=&mt('By default, based on your institutional affiliation, your LON-CAPA account can be automatically updated nightly based on directory information from your institution.').' '.&mt('The following may be updated, unless you disallow updates:').
+ '
';
+ foreach my $item ('firstname','middlename','lastname') {
+ if ($updateable{$item}) {
+ $text .= '
'.$longnames{$item}.'
';
+ }
+ }
+ $text .= '
';
+ my $locking=&mt('Disallow automatic updates to name information for your LON-CAPA account');
+ my $change=&mt('Save');
+ $r->print(<
+
+$text
+
+
+
+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 {
+ my $r = shift;
+ my $message;
+ if (&can_toggle_namelocking()) {
+ my $newlockedname = $env{'form.lockednames'};
+ $newlockedname =~ s/\D//g;
+ my $currlockedname = $env{'environment.lockedname'};
+ if ($newlockedname ne $currlockedname) {
+ if ($newlockedname) {
+ if (&Apache::lonnet::put('environment',{lockedname => $newlockedname}) eq 'ok') {
+ &Apache::lonnet::appenv({'environment.lockedname' => $newlockedname});
+ }
+ } elsif (&Apache::lonnet::del('environment',['lockedname']) eq 'ok') {
+ &Apache::lonnet::delenv('environment.lockedname');
+ }
+ }
+ my $status='';
+ if ($newlockedname) {
+ $status=&mt('disallowed');
+ } else {
+ $status=&mt('allowed');
+ }
+ $message=&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.&mt('Automatic update of first, middle and last names if institutional directory information indicates changes').'',''.$status.''));
+ $message=&Apache::loncommon::confirmwrapper($message);
+ }
+ &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");
+