File:
[LON-CAPA] /
loncom /
interface /
domainprefs.pm
Revision
1.445:
download - view:
text,
annotated -
select for diffs
Sat Oct 12 01:42:29 2024 UTC (2 months, 2 weeks ago) by
raeburn
Branches:
MAIN
CVS tags:
version_2_12_X,
HEAD
- Remove domain config unused beginning with 2.11.0 (2014)
Headers on main page had used rolecolors->{role}->{'img'}, [role is one of
student, coordinator,author or admin], when Remote Control was in use, prior
to rev. 1.949 (main branch) and rev 1.1075.2.21 (2.11 branch).
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
# $Id: domainprefs.pm,v 1.445 2024/10/12 01:42:29 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
#
###############################################################
###############################################################
=pod
=head1 NAME
Apache::domainprefs.pm
=head1 SYNOPSIS
Handles configuration of a LON-CAPA domain.
This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.
=head1 OVERVIEW
Each institution using LON-CAPA will typically have a single domain designated
for use by individuals affiliated with the institution. Accordingly, each domain
may define a default set of logos and a color scheme which can be used to "brand"
the LON-CAPA instance. In addition, an institution will typically have a language
and timezone which are used for the majority of courses.
LON-CAPA provides a mechanism to display and modify these defaults, as well as a
host of other domain-wide settings which determine the types of functionality
available to users and courses in the domain.
There is also a mechanism to configure cataloging of courses in the domain, and
controls on the operation of automated processes which govern such things as
roster updates, user directory updates and processing of course requests.
The domain coordination manual which is built dynamically on install/update of
LON-CAPA from the relevant help items provides more information about domain
configuration.
Most of the domain settings are stored in the configuration.db GDBM file which is
housed on the primary library server for the domain in /home/httpd/lonUsers/$dom,
where $dom is the domain. The configuration.db stores settings in a number of
frozen hashes of hashes. In a few cases, domain information must be uploaded to
the domain as files (e.g., image files for logos etc., or plain text files for
bubblesheet formats). In this case the domainprefs.pm must be running in a user
session hosted on the primary library server in the domain, as these files are
stored in author space belonging to a special $dom-domainconfig user.
domainprefs.pm in combination with lonconfigsettings.pm will retrieve and display
the current settings, and provides an interface to make modifications.
=head1 SUBROUTINES
=over
=item print_quotas()
Inputs: 4
$dom,$settings,$rowtotal,$action.
$dom is the domain, $settings is a reference to a hash of current settings for
the current context, $rowtotal is a reference to the scalar used to record the
number of rows displayed on the page, and $action is the context (quotas,
requestcourses or requestauthor).
The print_quotas routine was orginally created to display/store information
about default quota sizes for portfolio spaces for the different types of
institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.),
but is now also used to manage availability of user tools:
i.e., blogs, aboutme page, and portfolios, and the course request tool,
used by course owners to request creation of a course.
Outputs: 1
$datatable - HTML containing form elements which allow settings to be changed.
In the case of course requests, radio buttons are displayed for each institutional
affiliate type (and also default, and _LC_adv) for each of the course types
(official, unofficial, community, textbook, placement, and lti).
In each case the radio buttons allow the selection of one of four values:
0, approval, validate, autolimit=N (where N is blank, or a positive integer).
which have the following effects:
0
=over
- course requests are not allowed for this course types/affiliation
=back
approval
=over
- course requests must be approved by a Doman Coordinator in the
course's domain
=back
validate
=over
- an institutional validation (e.g., check requestor is instructor
of record) needs to be passed before the course will be created. The required
validation is in localenroll.pm on the primary library server for the course
domain.
=back
autolimit
=over
- course requests will be processed automatically up to a limit of
N requests for the course type for the particular requestor.
If N is undefined, there is no limit to the number of course requests
which a course owner may submit and have processed automatically.
=back
=item modify_quotas()
=back
=cut
package Apache::domainprefs;
use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::lonlocal;
use Apache::lonmsg();
use Apache::lonconfigsettings;
use Apache::lonuserutils();
use Apache::loncoursequeueadmin();
use Apache::courseprefs();
use LONCAPA qw(:DEFAULT :match);
use LONCAPA::Enrollment;
use LONCAPA::lonauthcgi();
use LONCAPA::SSL;
use File::Copy;
use Locale::Language;
use DateTime::TimeZone;
use DateTime::Locale;
use Time::HiRes qw( sleep );
use Net::CIDR;
use Crypt::CBC;
my $registered_cleanup;
my $modified_urls;
sub handler {
my $r=shift;
if ($r->header_only) {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
return OK;
}
my $context = 'domain';
my $dom = $env{'request.role.domain'};
my $domdesc = &Apache::lonnet::domain($dom,'description');
if (&Apache::lonnet::allowed('mau',$dom)) {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
} else {
$env{'user.error.msg'}=
"/adm/domainprefs:mau:0:0:Cannot modify domain settings";
return HTTP_NOT_ACCEPTABLE;
}
$registered_cleanup=0;
@{$modified_urls}=();
&Apache::lonhtmlcommon::clear_breadcrumbs();
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['phase','actions']);
my $phase = 'pickactions';
if ( exists($env{'form.phase'}) ) {
$phase = $env{'form.phase'};
}
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %domconfig =
&Apache::lonnet::get_dom('configuration',['login','rolecolors',
'quotas','autoenroll','autoupdate','autocreate',
'directorysrch','usercreation','usermodification',
'contacts','defaults','scantron','coursecategories',
'serverstatuses','requestcourses','helpsettings',
'coursedefaults','usersessions','loadbalancing',
'requestauthor','selfenrollment','inststatus',
'ltitools','toolsec','ssl','trust','lti','ltisec',
'privacy','passwords','proctoring','wafproxy',
'ipaccess','authordefaults'],$dom);
my %encconfig =
&Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1);
my ($checked_is_home,$is_home);
if (ref($domconfig{'ltitools'}) eq 'HASH') {
if (ref($encconfig{'ltitools'}) eq 'HASH') {
my $home = &Apache::lonnet::domain($dom,'primary');
unless (($home eq 'no_host') || ($home eq '')) {
my @ids=&Apache::lonnet::current_machine_ids();
if (grep(/^\Q$home\E$/,@ids)) {
$is_home = 1;
}
}
$checked_is_home = 1;
foreach my $id (keys(%{$domconfig{'ltitools'}})) {
if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') &&
(ref($encconfig{'ltitools'}{$id}) eq 'HASH')) {
$domconfig{'ltitools'}{$id}{'key'} = $encconfig{'ltitools'}{$id}{'key'};
if (($is_home) && ($phase eq 'process')) {
$domconfig{'ltitools'}{$id}{'secret'} = $encconfig{'ltitools'}{$id}{'secret'};
}
}
}
}
}
if (ref($domconfig{'lti'}) eq 'HASH') {
if (ref($encconfig{'lti'}) eq 'HASH') {
unless ($checked_is_home) {
my $home = &Apache::lonnet::domain($dom,'primary');
unless (($home eq 'no_host') || ($home eq '')) {
my @ids=&Apache::lonnet::current_machine_ids();
if (grep(/^\Q$home\E$/,@ids)) {
$is_home = 1;
}
}
$checked_is_home = 1;
}
foreach my $id (keys(%{$domconfig{'lti'}})) {
if ((ref($domconfig{'lti'}{$id}) eq 'HASH') &&
(ref($encconfig{'lti'}{$id}) eq 'HASH')) {
$domconfig{'lti'}{$id}{'key'} = $encconfig{'lti'}{$id}{'key'};
if (($is_home) && ($phase eq 'process')) {
$domconfig{'lti'}{$id}{'secret'} = $encconfig{'lti'}{$id}{'secret'};
}
}
}
}
}
if (ref($domconfig{'ltisec'}) eq 'HASH') {
if (ref($domconfig{'ltisec'}{'linkprot'}) eq 'HASH') {
if (ref($encconfig{'linkprot'}) eq 'HASH') {
foreach my $id (keys(%{$domconfig{'ltisec'}{'linkprot'}})) {
unless ($id =~ /^\d+$/) {
delete($domconfig{'ltisec'}{'linkprot'}{$id});
}
if ((ref($domconfig{'ltisec'}{'linkprot'}{$id}) eq 'HASH') &&
(ref($encconfig{'linkprot'}{$id}) eq 'HASH')) {
foreach my $item ('key','secret') {
$domconfig{'ltisec'}{'linkprot'}{$id}{$item} = $encconfig{'linkprot'}{$id}{$item};
}
}
}
}
}
}
if (ref($domconfig{'proctoring'}) eq 'HASH') {
if (ref($encconfig{'proctoring'}) eq 'HASH') {
foreach my $provider (keys(%{$domconfig{'proctoring'}})) {
if ((ref($domconfig{'proctoring'}{$provider}) eq 'HASH') &&
(ref($encconfig{'proctoring'}{$provider}) eq 'HASH')) {
foreach my $item ('key','secret') {
$domconfig{'proctoring'}{$provider}{$item} = $encconfig{'proctoring'}{$provider}{$item};
}
}
}
}
}
my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',
'quotas','autoenroll','autoupdate','autocreate','directorysrch',
'contacts','privacy','usercreation','selfcreation',
'usermodification','scantron','requestcourses','requestauthor',
'coursecategories','serverstatuses','helpsettings','coursedefaults',
'authordefaults','ltitools','proctoring','selfenrollment',
'usersessions','ssl','trust','lti');
my %existing;
if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
%existing = %{$domconfig{'loadbalancing'}};
}
if ((keys(%servers) > 1) || (keys(%existing) > 0)) {
push(@prefs_order,'loadbalancing');
}
my %prefs = (
'rolecolors' =>
{ text => 'Default color schemes',
help => 'Domain_Configuration_Color_Schemes',
header => [{col1 => 'Student Settings',
col2 => '',},
{col1 => 'Coordinator Settings',
col2 => '',},
{col1 => 'Author Settings',
col2 => '',},
{col1 => 'Administrator Settings',
col2 => '',}],
print => \&print_rolecolors,
modify => \&modify_rolecolors,
},
'login' =>
{ text => 'Log-in page options',
help => 'Domain_Configuration_Login_Page',
header => [{col1 => 'Log-in Page Items',
col2 => '',},
{col1 => 'Log-in Help',
col2 => 'Value'},
{col1 => 'Custom HTML in document head',
col2 => 'Value'},
{col1 => 'SSO',
col2 => 'Dual login: SSO and non-SSO options'},
],
print => \&print_login,
modify => \&modify_login,
},
'defaults' =>
{ text => 'Default authentication/language/timezone/portal/types',
help => 'Domain_Configuration_LangTZAuth',
header => [{col1 => 'Setting',
col2 => 'Value'},
{col1 => 'Institutional user types',
col2 => 'Name displayed'},
{col1 => 'Mapping for missing usernames via standard log-in',
col2 => 'Rules in use'}],
print => \&print_defaults,
modify => \&modify_defaults,
},
'wafproxy' =>
{ text => 'Web Application Firewall/Reverse Proxy',
help => 'Domain_Configuration_WAF_Proxy',
header => [{col1 => 'Domain(s)',
col2 => 'Servers and WAF/Reverse Proxy alias(es)',
},
{col1 => 'Domain(s)',
col2 => 'WAF Configuration',}],
print => \&print_wafproxy,
modify => \&modify_wafproxy,
},
'passwords' =>
{ text => 'Passwords (Internal authentication)',
help => 'Domain_Configuration_Passwords',
header => [{col1 => 'Resetting Forgotten Password',
col2 => 'Settings'},
{col1 => 'Encryption of Stored Passwords (Internal Auth)',
col2 => 'Settings'},
{col1 => 'Rules for LON-CAPA Passwords',
col2 => 'Settings'},
{col1 => 'Course Owner Changing Student Passwords',
col2 => 'Settings'}],
print => \&print_passwords,
modify => \&modify_passwords,
},
'quotas' =>
{ text => 'Blogs, personal pages/timezones, portfolio/quotas',
help => 'Domain_Configuration_Quotas',
header => [{col1 => 'User affiliation',
col2 => 'Available tools',
col3 => 'Portfolio quota (MB)',}],
print => \&print_quotas,
modify => \&modify_quotas,
},
'autoenroll' =>
{ text => 'Auto-enrollment settings',
help => 'Domain_Configuration_Auto_Enrollment',
header => [{col1 => 'Configuration setting',
col2 => 'Value(s)'}],
print => \&print_autoenroll,
modify => \&modify_autoenroll,
},
'autoupdate' =>
{ text => 'Auto-update settings',
help => 'Domain_Configuration_Auto_Updates',
header => [{col1 => 'Setting',
col2 => 'Value',},
{col1 => 'Setting',
col2 => 'Affiliation'},
{col1 => 'User population',
col2 => 'Updatable user data'}],
print => \&print_autoupdate,
modify => \&modify_autoupdate,
},
'autocreate' =>
{ text => 'Auto-course creation settings',
help => 'Domain_Configuration_Auto_Creation',
header => [{col1 => 'Configuration Setting',
col2 => 'Value',}],
print => \&print_autocreate,
modify => \&modify_autocreate,
},
'directorysrch' =>
{ text => 'Directory searches',
help => 'Domain_Configuration_InstDirectory_Search',
header => [{col1 => 'Institutional Directory Setting',
col2 => 'Value',},
{col1 => 'LON-CAPA Directory Setting',
col2 => 'Value',}],
print => \&print_directorysrch,
modify => \&modify_directorysrch,
},
'contacts' =>
{ text => 'E-mail addresses and helpform',
help => 'Domain_Configuration_Contact_Info',
header => [{col1 => 'Default e-mail addresses',
col2 => 'Value',},
{col1 => 'Recipient(s) for notifications',
col2 => 'Value',},
{col1 => 'Nightly status check e-mail',
col2 => 'Settings',},
{col1 => 'Ask helpdesk form settings',
col2 => 'Value',},],
print => \&print_contacts,
modify => \&modify_contacts,
},
'usercreation' =>
{ text => 'User creation',
help => 'Domain_Configuration_User_Creation',
header => [{col1 => 'Format rule type',
col2 => 'Format rules in force'},
{col1 => 'User account creation',
col2 => 'Usernames which may be created',},
{col1 => 'Context',
col2 => 'Assignable authentication types'}],
print => \&print_usercreation,
modify => \&modify_usercreation,
},
'selfcreation' =>
{ text => 'Users self-creating accounts',
help => 'Domain_Configuration_Self_Creation',
header => [{col1 => 'Self-creation with institutional username',
col2 => 'Enabled?'},
{col1 => 'Institutional user type (login/SSO self-creation)',
col2 => 'Information user can enter'},
{col1 => 'Self-creation with e-mail verification',
col2 => 'Settings'}],
print => \&print_selfcreation,
modify => \&modify_selfcreation,
},
'usermodification' =>
{ text => 'User modification',
help => 'Domain_Configuration_User_Modification',
header => [{col1 => 'Target user has role',
col2 => 'User information updatable in author context'},
{col1 => 'Target user has role',
col2 => 'User information updatable by co-author manager'},
{col1 => 'Target user has role',
col2 => 'User information updatable in course context'}],
print => \&print_usermodification,
modify => \&modify_usermodification,
},
'scantron' =>
{ text => 'Bubblesheet format',
help => 'Domain_Configuration_Scantron_Format',
header => [ {col1 => 'Bubblesheet format file',
col2 => ''},
{col1 => 'Bubblesheet data upload formats',
col2 => 'Settings'}],
print => \&print_scantron,
modify => \&modify_scantron,
},
'requestcourses' =>
{text => 'Request creation of courses',
help => 'Domain_Configuration_Request_Courses',
header => [{col1 => 'User affiliation',
col2 => 'Availability/Processing of requests',},
{col1 => 'Setting',
col2 => 'Value'},
{col1 => 'Available textbooks',
col2 => ''},
{col1 => 'Available templates',
col2 => ''},
{col1 => 'Validation (not official courses)',
col2 => 'Value'},],
print => \&print_quotas,
modify => \&modify_quotas,
},
'requestauthor' =>
{text => 'Request Authoring Space',
help => 'Domain_Configuration_Request_Author',
header => [{col1 => 'User affiliation',
col2 => 'Availability/Processing of requests',},
{col1 => 'Setting',
col2 => 'Value'}],
print => \&print_quotas,
modify => \&modify_quotas,
},
'coursecategories' =>
{ text => 'Cataloging of courses/communities',
help => 'Domain_Configuration_Cataloging_Courses',
header => [{col1 => 'Catalog type/availability',
col2 => '',},
{col1 => 'Category settings for standard catalog',
col2 => '',},
{col1 => 'Categories',
col2 => '',
}],
print => \&print_coursecategories,
modify => \&modify_coursecategories,
},
'serverstatuses' =>
{text => 'Access to server status pages',
help => 'Domain_Configuration_Server_Status',
header => [{col1 => 'Status Page',
col2 => 'Other named users',
col3 => 'Specific IPs',
}],
print => \&print_serverstatuses,
modify => \&modify_serverstatuses,
},
'helpsettings' =>
{text => 'Support settings',
help => 'Domain_Configuration_Help_Settings',
header => [{col1 => 'Help Page Settings (logged-in users)',
col2 => 'Value'},
{col1 => 'Helpdesk Roles',
col2 => 'Settings'},],
print => \&print_helpsettings,
modify => \&modify_helpsettings,
},
'coursedefaults' =>
{text => 'Course/Community defaults',
help => 'Domain_Configuration_Course_Defaults',
header => [{col1 => 'Defaults which can be overridden in each course by a CC',
col2 => 'Value',},
{col1 => 'Defaults which can be overridden for each course by a DC',
col2 => 'Value',},],
print => \&print_coursedefaults,
modify => \&modify_coursedefaults,
},
'selfenrollment' =>
{text => 'Self-enrollment in Course/Community',
help => 'Domain_Configuration_Selfenrollment',
header => [{col1 => 'Configuration Rights',
col2 => 'Configured by Course Personnel or Domain Coordinator?'},
{col1 => 'Defaults',
col2 => 'Value'},
{col1 => 'Self-enrollment validation (optional)',
col2 => 'Value'},],
print => \&print_selfenrollment,
modify => \&modify_selfenrollment,
},
'privacy' =>
{text => 'Role assignments and user privacy',
help => 'Domain_Configuration_User_Privacy',
header => [{col1 => 'Role assigned in different domain',
col2 => 'Approval options'},
{col1 => 'Role assigned in different domain to user of type',
col2 => 'User information available in that domain'},
{col1 => "Role assigned in user's domain",
col2 => 'Information viewable by privileged user'},
{col1 => "Role assigned in user's domain",
col2 => 'Information viewable by unprivileged user'}],
print => \&print_privacy,
modify => \&modify_privacy,
},
'usersessions' =>
{text => 'User session hosting/offloading',
help => 'Domain_Configuration_User_Sessions',
header => [{col1 => 'Domain server',
col2 => 'Servers to offload sessions to when busy'},
{col1 => 'Hosting of users from other domains',
col2 => 'Rules'},
{col1 => "Hosting domain's own users elsewhere",
col2 => 'Rules'}],
print => \&print_usersessions,
modify => \&modify_usersessions,
},
'loadbalancing' =>
{text => 'Dedicated Load Balancer(s)',
help => 'Domain_Configuration_Load_Balancing',
header => [{col1 => 'Balancers',
col2 => 'Default destinations',
col3 => 'User affiliation',
col4 => 'Overrides'},
],
print => \&print_loadbalancing,
modify => \&modify_loadbalancing,
},
'ltitools' =>
{text => 'External Tools (LTI)',
help => 'Domain_Configuration_LTI_Tools',
header => [{col1 => 'Encryption of shared secrets',
col2 => 'Settings'},
{col1 => 'Rules for shared secrets',
col2 => 'Settings'},
{col1 => 'Providers',
col2 => 'Settings',}],
print => \&print_ltitools,
modify => \&modify_ltitools,
},
'proctoring' =>
{text => 'Remote Proctoring Integration',
help => 'Domain_Configuration_Proctoring',
header => [{col1 => 'Name',
col2 => 'Configuration'}],
print => \&print_proctoring,
modify => \&modify_proctoring,
},
'ssl' =>
{text => 'LON-CAPA Network (SSL)',
help => 'Domain_Configuration_Network_SSL',
header => [{col1 => 'Server',
col2 => 'Certificate Status'},
{col1 => 'Connections to other servers',
col2 => 'Rules'},
{col1 => 'Connections from other servers',
col2 => 'Rules'},
{col1 => "Replicating domain's published content",
col2 => 'Rules'}],
print => \&print_ssl,
modify => \&modify_ssl,
},
'trust' =>
{text => 'Trust Settings',
help => 'Domain_Configuration_Trust',
header => [{col1 => "Access to this domain's content by others",
col2 => 'Rules'},
{col1 => "Access to other domain's content by this domain",
col2 => 'Rules'},
{col1 => "Enrollment in this domain's courses by others",
col2 => 'Rules',},
{col1 => "Co-author roles in this domain for others",
col2 => 'Rules',},
{col1 => "Co-author roles for this domain's users elsewhere",
col2 => 'Rules',},
{col1 => "Domain roles in this domain assignable to others",
col2 => 'Rules'},
{col1 => "Course catalog for this domain displayed elsewhere",
col2 => 'Rules'},
{col1 => "Requests for creation of courses in this domain by others",
col2 => 'Rules'},
{col1 => "Users in other domains can send messages to this domain",
col2 => 'Rules'},],
print => \&print_trust,
modify => \&modify_trust,
},
'lti' =>
{text => 'LTI Link Protection and LTI Consumers',
help => 'Domain_Configuration_LTI_Provider',
header => [{col1 => 'Encryption of shared secrets',
col2 => 'Settings'},
{col1 => 'Rules for shared secrets',
col2 => 'Settings'},
{col1 => 'Link Protectors in Courses',
col2 => 'Values'},
{col1 => 'Link Protectors',
col2 => 'Settings'},
{col1 => 'Consumers',
col2 => 'Settings'},],
print => \&print_lti,
modify => \&modify_lti,
},
'ipaccess' =>
{text => 'IP-based access control',
help => 'Domain_Configuration_IP_Access',
header => [{col1 => 'Setting',
col2 => 'Value'},],
print => \&print_ipaccess,
modify => \&modify_ipaccess,
},
'authordefaults' =>
{text => 'Authoring Space defaults',
help => 'Domain_Configuration_Author_Defaults',
header => [{col1 => 'Defaults which can be overridden by Author',
col2 => 'Settings',},
{col1 => 'Defaults which can be overridden by a Dom. Coord.',
col2 => 'Settings',},],
print => \&print_authordefaults,
modify => \&modify_authordefaults,
},
);
if (keys(%servers) > 1) {
$prefs{'login'} = { text => 'Log-in page options',
help => 'Domain_Configuration_Login_Page',
header => [{col1 => 'Log-in Service',
col2 => 'Server Setting',},
{col1 => 'Log-in Page Items',
col2 => 'Settings'},
{col1 => 'Log-in Help',
col2 => 'Value'},
{col1 => 'Custom HTML in document head',
col2 => 'Value'},
{col1 => 'SSO',
col2 => 'Dual login: SSO and non-SSO options'},
],
print => \&print_login,
modify => \&modify_login,
};
}
my @roles = ('student','coordinator','author','admin');
my @actions = &Apache::loncommon::get_env_multiple('form.actions');
&Apache::lonhtmlcommon::add_breadcrumb
({href=>"javascript:changePage(document.$phase,'pickactions')",
text=>"Settings to display/modify"});
my $confname = $dom.'-domainconfig';
if ($phase eq 'process') {
my $result = &Apache::lonconfigsettings::make_changes($r,$dom,$phase,$context,\@prefs_order,
\%prefs,\%domconfig,$confname,\@roles);
if ((ref($result) eq 'HASH') && (keys(%{$result}))) {
$r->rflush();
&devalidate_remote_domconfs($dom,$result);
}
} elsif ($phase eq 'display') {
my $js = &recaptcha_js().
&toggle_display_js();
if ((keys(%servers) > 1) || (keys(%existing) > 0)) {
my ($othertitle,$usertypes,$types) =
&Apache::loncommon::sorted_inst_types($dom);
$js .= &lonbalance_targets_js($dom,$types,\%servers,
$domconfig{'loadbalancing'}).
&new_spares_js().
&common_domprefs_js().
&Apache::loncommon::javascript_array_indexof();
}
if (grep(/^requestcourses$/,@actions)) {
my $javascript_validations;
my $coursebrowserjs=&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'});
$js .= <<END;
<script type="text/javascript">
$javascript_validations
</script>
$coursebrowserjs
END
} elsif (grep(/^ipaccess$/,@actions)) {
$js .= &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'});
}
if (grep(/^selfcreation$/,@actions)) {
$js .= &selfcreate_javascript();
}
if (grep(/^contacts$/,@actions)) {
$js .= &contacts_javascript();
}
if (grep(/^scantron$/,@actions)) {
$js .= &scantron_javascript();
}
&Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);
} else {
# check if domconfig user exists for the domain.
my $servadm = $r->dir_config('lonAdmEMail');
my ($configuserok,$author_ok,$switchserver) =
&config_check($dom,$confname,$servadm);
unless ($configuserok eq 'ok') {
&Apache::lonconfigsettings::print_header($r,$phase,$context);
$r->print(&mt('The domain configuration user "[_1]" has yet to be created.',
$confname).
'<br />'
);
if ($switchserver) {
$r->print(&mt('Ordinarily, that domain configuration user is created when the ./UPDATE script is run to install LON-CAPA for the first time.').
'<br />'.
&mt('However, that does not apply when new domains are added to a multi-domain server, and ./UPDATE has not been run recently.').
'<br />'.
&mt('The "[_1]" user can be created automatically when a Domain Coordinator visits the web-based "Set domain configuration" screen, in a session hosted on the primary library server.',$confname).
'<br />'.
&mt('To do that now, use the following link: [_1]',$switchserver)
);
} else {
$r->print(&mt('To create that user from the command line run the ./UPDATE script found in the top level directory of the extracted LON-CAPA tarball.').
'<br />'.
&mt('Once that is done, you will be able to use the web-based "Set domain configuration" to configure the domain')
);
}
$r->print(&Apache::loncommon::end_page());
return OK;
}
if (keys(%domconfig) == 0) {
my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
my @ids=&Apache::lonnet::current_machine_ids();
if (!grep(/^\Q$primarylibserv\E$/,@ids)) {
my %designhash = &Apache::loncommon::get_domainconf($dom);
my @loginimages = ('img','logo','domlogo','login');
my $custom_img_count = 0;
foreach my $img (@loginimages) {
if ($designhash{$dom.'.login.'.$img} ne '') {
$custom_img_count ++;
}
}
foreach my $role (@roles) {
if ($designhash{$dom.'.'.$role.'.img'} ne '') {
$custom_img_count ++;
}
}
if ($custom_img_count > 0) {
&Apache::lonconfigsettings::print_header($r,$phase,$context);
my $switch_server = &check_switchserver($dom,$confname);
$r->print(
&mt('Domain configuration settings have yet to be saved for this domain via the web-based domain preferences interface.').'<br />'.
&mt("While this remains so, you must switch to the domain's primary library server in order to update settings.").'<br /><br />'.
&mt("Thereafter, (with a Domain Coordinator role selected in the domain) you will be able to update settings when logged in to any server in the LON-CAPA network.").'<br />'.
&mt("However, you will still need to switch to the domain's primary library server to upload new images or logos.").'<br /><br />');
if ($switch_server) {
$r->print($switch_server.' '.&mt('to primary library server for domain: [_1]',$dom));
}
$r->print(&Apache::loncommon::end_page());
return OK;
}
}
}
&Apache::lonconfigsettings::display_choices($r,$phase,$context,\@prefs_order,\%prefs);
}
return OK;
}
sub process_changes {
my ($r,$dom,$confname,$action,$roles,$values,$lastactref) = @_;
my %domconfig;
if (ref($values) eq 'HASH') {
%domconfig = %{$values};
}
my $output;
if ($action eq 'login') {
$output = &modify_login($r,$dom,$confname,$lastactref,%domconfig);
} elsif ($action eq 'rolecolors') {
$output = &modify_rolecolors($r,$dom,$confname,$roles,
$lastactref,%domconfig);
} elsif ($action eq 'quotas') {
$output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'autoenroll') {
$output = &modify_autoenroll($dom,$lastactref,%domconfig);
} elsif ($action eq 'autoupdate') {
$output = &modify_autoupdate($dom,%domconfig);
} elsif ($action eq 'autocreate') {
$output = &modify_autocreate($dom,%domconfig);
} elsif ($action eq 'directorysrch') {
$output = &modify_directorysrch($dom,$lastactref,%domconfig);
} elsif ($action eq 'usercreation') {
$output = &modify_usercreation($dom,%domconfig);
} elsif ($action eq 'selfcreation') {
$output = &modify_selfcreation($dom,$lastactref,%domconfig);
} elsif ($action eq 'usermodification') {
$output = &modify_usermodification($dom,%domconfig);
} elsif ($action eq 'contacts') {
$output = &modify_contacts($dom,$lastactref,%domconfig);
} elsif ($action eq 'defaults') {
$output = &modify_defaults($dom,$lastactref,%domconfig);
} elsif ($action eq 'scantron') {
$output = &modify_scantron($r,$dom,$confname,$lastactref,%domconfig);
} elsif ($action eq 'coursecategories') {
$output = &modify_coursecategories($dom,$lastactref,%domconfig);
} elsif ($action eq 'serverstatuses') {
$output = &modify_serverstatuses($dom,%domconfig);
} elsif ($action eq 'requestcourses') {
$output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'requestauthor') {
$output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'helpsettings') {
$output = &modify_helpsettings($r,$dom,$confname,$lastactref,%domconfig);
} elsif ($action eq 'coursedefaults') {
$output = &modify_coursedefaults($dom,$lastactref,%domconfig);
} elsif ($action eq 'selfenrollment') {
$output = &modify_selfenrollment($dom,$lastactref,%domconfig)
} elsif ($action eq 'usersessions') {
$output = &modify_usersessions($dom,$lastactref,%domconfig);
} elsif ($action eq 'loadbalancing') {
$output = &modify_loadbalancing($dom,%domconfig);
} elsif ($action eq 'ltitools') {
$output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'proctoring') {
$output = &modify_proctoring($r,$dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'ssl') {
$output = &modify_ssl($dom,$lastactref,%domconfig);
} elsif ($action eq 'trust') {
$output = &modify_trust($dom,$lastactref,%domconfig);
} elsif ($action eq 'lti') {
$output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'privacy') {
$output = &modify_privacy($dom,$lastactref,%domconfig);
} elsif ($action eq 'passwords') {
$output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
} elsif ($action eq 'wafproxy') {
$output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);
} elsif ($action eq 'ipaccess') {
$output = &modify_ipaccess($dom,$lastactref,%domconfig);
} elsif ($action eq 'authordefaults') {
$output = &modify_authordefaults($dom,$lastactref,%domconfig);
}
return $output;
}
sub print_config_box {
my ($r,$dom,$confname,$phase,$action,$item,$settings) = @_;
my $rowtotal = 0;
my $output;
if ($action eq 'coursecategories') {
$output = &coursecategories_javascript($settings);
} elsif ($action eq 'defaults') {
$output = &defaults_javascript($settings);
} elsif ($action eq 'passwords') {
$output = &passwords_javascript($action);
} elsif ($action eq 'helpsettings') {
my (%privs,%levelscurrent);
my %full=();
my %levels=(
course => {},
domain => {},
system => {},
);
my $context = 'domain';
my $crstype = 'Course';
my $formname = 'display';
&Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
$output =
&Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full,
\@templateroles);
} elsif ($action eq 'ltitools') {
$output .= &Apache::lonconfigsettings::ltitools_javascript($settings);
} elsif ($action eq 'lti') {
$output .= &passwords_javascript('ltisecrets')."\n".
<i_javascript($dom,$settings);
} elsif ($action eq 'proctoring') {
$output .= &proctoring_javascript($settings);
} elsif ($action eq 'wafproxy') {
$output .= &wafproxy_javascript($dom);
} elsif ($action eq 'autoupdate') {
$output .= &autoupdate_javascript();
} elsif ($action eq 'autoenroll') {
$output .= &autoenroll_javascript();
} elsif ($action eq 'login') {
$output .= &saml_javascript();
} elsif ($action eq 'ipaccess') {
$output .= &ipaccess_javascript($settings);
} elsif ($action eq 'authordefaults') {
$output .= &authordefaults_javascript();
}
$output .=
'<table class="LC_nested_outer">
<tr>
<th class="LC_left_item LC_middle"><span class="LC_nobreak">'.
&mt($item->{text}).' '.
&Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n".
'</tr>';
$rowtotal ++;
my $numheaders = 1;
if (ref($item->{'header'}) eq 'ARRAY') {
$numheaders = scalar(@{$item->{'header'}});
}
if ($numheaders > 1) {
my $colspan = '';
my $rightcolspan = '';
my $leftnobr = '';
if (($action eq 'rolecolors') || ($action eq 'defaults') ||
($action eq 'directorysrch') ||
(($action eq 'login') && ($numheaders < 5))) {
$colspan = ' colspan="2"';
}
if ($action eq 'usersessions') {
$rightcolspan = ' colspan="3"';
}
if ($action eq 'passwords') {
$leftnobr = ' LC_nobreak';
}
$output .= '
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td>
<td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
</tr>';
$rowtotal ++;
if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||
($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy') ||
($action eq 'lti') || ($action eq 'ltitools') || ($action eq 'authordefaults')) {
$output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
} elsif ($action eq 'passwords') {
$output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'coursecategories') {
$output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);
} elsif ($action eq 'scantron') {
$output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'login') {
if ($numheaders == 5) {
$colspan = ' colspan="2"';
$output .= &print_login('service',$dom,$confname,$phase,$settings,\$rowtotal);
} else {
$output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal);
}
} elsif (($action eq 'requestcourses') || ($action eq 'requestauthor')) {
$output .= &print_quotas($dom,$settings,\$rowtotal,$action);
} elsif ($action eq 'rolecolors') {
$output .= &print_rolecolors($phase,'student',$dom,$confname,$settings,\$rowtotal);
}
$output .= '
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[1]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[1]->{'col2'}).'</td>
</tr>';
$rowtotal ++;
if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
($action eq 'usersessions') || ($action eq 'coursecategories') ||
($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') ||
($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti') ||
($action eq 'ltitools') || ($action eq 'usermodification')) {
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
$colspan = ' colspan="2"';
} elsif ($action eq 'trust') {
$output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
} elsif ($action eq 'passwords') {
$output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'lti') {
$output .= $item->{'print'}->('upper',$dom,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
<td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
</tr>'."\n".
$item->{'print'}->('middle',$dom,$settings,\$rowtotal);
} else {
$output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
}
if ($action eq 'trust') {
$output .= '
</table>
</td>
</tr>';
my @trusthdrs = qw(2 3 4 5 6 7);
my @prefixes = qw(enroll othcoau coaurem domroles catalog reqcrs);
for (my $i=0; $i<@trusthdrs; $i++) {
$output .= '
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col2'}).'</td></tr>'.
$item->{'print'}->($prefixes[$i],$dom,$settings,\$rowtotal).'
</table>
</td>
</tr>';
}
$output .= '
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
$item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
} else {
my $hdridx = 2;
if ($action eq 'lti') {
$hdridx = 3;
}
$output .= '
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>
<td class="LC_right_item">'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td>
</tr>'."\n";
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
} elsif (($action eq 'contacts') || ($action eq 'privacy') ||
($action eq 'passwords') || ($action eq 'lti')) {
if ($action eq 'passwords') {
$output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);
} else {
$output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);
}
$hdridx ++;
$output .= '
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td></tr>'."\n";
if ($action eq 'passwords') {
$output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);
} else {
$output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
}
$output .= '
</table>
</td>
</tr>
<tr>';
} else {
$output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
}
}
$rowtotal ++;
} elsif (($action eq 'coursedefaults') || ($action eq 'authordefaults') ||
($action eq 'directorysrch') || ($action eq 'helpsettings') ||
($action eq 'wafproxy')) {
$output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
} elsif ($action eq 'scantron') {
$output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'ssl') {
$output .= $item->{'print'}->('connto',$dom,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'.
$item->{'print'}->('connfrom',$dom,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
$item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
} elsif ($action eq 'login') {
if ($numheaders == 5) {
$output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'.
&print_login('help',$dom,$confname,$phase,$settings,\$rowtotal);
$rowtotal ++;
} else {
$output .= &print_login('help',$dom,$confname,$phase,$settings,\$rowtotal);
}
$output .= '
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">';
if ($numheaders == 5) {
$output .= '
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td>
</tr>';
} else {
$output .= '
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
</tr>';
}
$rowtotal ++;
$output .= &print_login('headtag',$dom,$confname,$phase,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">';
if ($numheaders == 5) {
$output .= '
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
</tr>';
} else {
$output .= '
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td>
</tr>';
}
$rowtotal ++;
$output .= &print_login('saml',$dom,$confname,$phase,$settings,\$rowtotal);
} elsif ($action eq 'requestcourses') {
$output .= &print_requestmail($dom,$action,$settings,\$rowtotal);
$rowtotal ++;
$output .= &print_studentcode($settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
<td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td> </tr>'.
&textbookcourses_javascript($settings).
&print_textbookcourses($dom,'textbooks',$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
<td class="LC_right_item">'.&mt($item->{'header'}->[3]->{'col2'}).'</td> </tr>'.
&print_textbookcourses($dom,'templates',$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
<td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
</tr>'.
&print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);
} elsif ($action eq 'requestauthor') {
$output .= &print_requestmail($dom,$action,$settings,\$rowtotal);
$rowtotal ++;
} elsif ($action eq 'rolecolors') {
$output .= &print_rolecolors($phase,'coordinator',$dom,$confname,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.
&mt($item->{'header'}->[2]->{'col1'}).'</td>
<td class="LC_right_item" style="vertical-align: top">'.
&mt($item->{'header'}->[2]->{'col2'}).'</td>
</tr>'.
&print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'
</table>
</td>
</tr>
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
<td class="LC_right_item">'.&mt($item->{'header'}->[3]->{'col2'}).'</td>
</tr>'.
&print_rolecolors($phase,'admin',$dom,$confname,$settings,\$rowtotal);
$rowtotal += 2;
}
} else {
$output .= '
<tr>
<td>
<table class="LC_nested">
<tr class="LC_info_row">';
if ($action eq 'login') {
$output .= '
<td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
} elsif ($action eq 'serverstatuses') {
$output .= '
<td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).
'<br />('.&mt('Automatic access for Dom. Coords.').')</td>';
} else {
$output .= '
<td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
}
if (defined($item->{'header'}->[0]->{'col3'})) {
$output .= '<td class="LC_left_item" style="vertical-align: top">'.
&mt($item->{'header'}->[0]->{'col2'});
if ($action eq 'serverstatuses') {
$output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';
}
} else {
$output .= '<td class="LC_right_item" style="vertical-align: top">'.
&mt($item->{'header'}->[0]->{'col2'});
}
$output .= '</td>';
if ($item->{'header'}->[0]->{'col3'}) {
if (defined($item->{'header'}->[0]->{'col4'})) {
$output .= '<td class="LC_left_item" style="vertical-align: top">'.
&mt($item->{'header'}->[0]->{'col3'});
} else {
$output .= '<td class="LC_right_item" style="vertical-align: top">'.
&mt($item->{'header'}->[0]->{'col3'});
}
if ($action eq 'serverstatuses') {
$output .= '<br />(<tt>'.&mt('IP1,IP2 etc.').'</tt>)';
}
$output .= '</td>';
}
if ($item->{'header'}->[0]->{'col4'}) {
$output .= '<td class="LC_right_item" style="vertical-align: top">'.
&mt($item->{'header'}->[0]->{'col4'});
}
$output .= '</tr>';
$rowtotal ++;
if ($action eq 'quotas') {
$output .= &print_quotas($dom,$settings,\$rowtotal,$action);
} elsif (($action eq 'autoenroll') || ($action eq 'autocreate') ||
($action eq 'serverstatuses') || ($action eq 'loadbalancing') ||
($action eq 'proctoring') || ($action eq 'ipaccess')) {
$output .= $item->{'print'}->($dom,$settings,\$rowtotal);
}
}
$output .= '
</table>
</td>
</tr>
</table><br />';
return ($output,$rowtotal);
}
sub print_login {
my ($caller,$dom,$confname,$phase,$settings,$rowtotal) = @_;
my ($css_class,$datatable,$switchserver,%lt);
my %choices = &login_choices();
if (($caller eq 'help') || ($caller eq 'headtag') || ($caller eq 'saml')) {
%lt = &login_file_options();
$switchserver = &check_switchserver($dom,$confname);
}
if ($caller eq 'service') {
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my $choice = $choices{'disallowlogin'};
$css_class = ' class="LC_odd_row"';
$datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.
'<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'.
'<th>'.$choices{'server'}.'</th>'.
'<th>'.$choices{'serverpath'}.'</th>'.
'<th>'.$choices{'custompath'}.'</th>'.
'<th><span class="LC_nobreak">'.$choices{'exempt'}.'</span></th></tr>'."\n";
my %disallowed;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'loginvia'}) eq 'HASH') {
%disallowed = %{$settings->{'loginvia'}};
}
}
foreach my $lonhost (sort(keys(%servers))) {
my $direct = 'selected="selected"';
if (ref($disallowed{$lonhost}) eq 'HASH') {
if ($disallowed{$lonhost}{'server'} ne '') {
$direct = '';
}
}
$datatable .= '<tr><td>'.$servers{$lonhost}.'</td>'.
'<td><select name="'.$lonhost.'_server">'.
'<option value=""'.$direct.'>'.$choices{'directlogin'}.
'</option>';
foreach my $hostid (sort(keys(%servers))) {
next if ($servers{$hostid} eq $servers{$lonhost});
my $selected = '';
if (ref($disallowed{$lonhost}) eq 'HASH') {
if ($hostid eq $disallowed{$lonhost}{'server'}) {
$selected = 'selected="selected"';
}
}
$datatable .= '<option value="'.$hostid.'"'.$selected.'>'.
$servers{$hostid}.'</option>';
}
$datatable .= '</select></td>'.
'<td><select name="'.$lonhost.'_serverpath">';
foreach my $path ('','/','/adm/login','/adm/roles','custom') {
my $pathname = $path;
if ($path eq 'custom') {
$pathname = &mt('Custom Path').' ->';
}
my $selected = '';
if (ref($disallowed{$lonhost}) eq 'HASH') {
if ($path eq $disallowed{$lonhost}{'serverpath'}) {
$selected = 'selected="selected"';
}
} elsif ($path eq '') {
$selected = 'selected="selected"';
}
$datatable .= '<option value="'.$path.'"'.$selected.'>'.$pathname.'</option>';
}
$datatable .= '</select></td>';
my ($custom,$exempt);
if (ref($disallowed{$lonhost}) eq 'HASH') {
$custom = $disallowed{$lonhost}{'custompath'};
$exempt = $disallowed{$lonhost}{'exempt'};
}
$datatable .= '<td><input type="text" name="'.$lonhost.'_custompath" size="6" value="'.$custom.'" /></td>'.
'<td><input type="text" name="'.$lonhost.'_exempt" size="8" value="'.$exempt.'" /></td>'.
'</tr>';
}
$datatable .= '</table></td></tr>';
return $datatable;
} elsif ($caller eq 'page') {
my %defaultchecked = (
'coursecatalog' => 'on',
'helpdesk' => 'on',
'adminmail' => 'off',
'newuser' => 'off',
);
my @toggles = ('coursecatalog','adminmail','helpdesk','newuser');
my (%checkedon,%checkedoff);
foreach my $item (@toggles) {
if ($defaultchecked{$item} eq 'on') {
$checkedon{$item} = ' checked="checked" ';
$checkedoff{$item} = ' ';
} elsif ($defaultchecked{$item} eq 'off') {
$checkedoff{$item} = ' checked="checked" ';
$checkedon{$item} = ' ';
}
}
my @images = ('img','logo','domlogo','login');
my @alttext = ('img','logo','domlogo');
my @logintext = ('textcol','bgcol');
my @bgs = ('pgbg','mainbg','sidebg');
my @links = ('link','alink','vlink');
my %designhash = &Apache::loncommon::get_domainconf($dom);
my %defaultdesign = %Apache::loncommon::defaultdesign;
my (%is_custom,%designs);
my %defaults = (
font => $defaultdesign{'login.font'},
);
foreach my $item (@images) {
$defaults{$item} = $defaultdesign{'login.'.$item};
$defaults{'showlogo'}{$item} = 1;
}
foreach my $item (@bgs) {
$defaults{'bgs'}{$item} = $defaultdesign{'login.'.$item};
}
foreach my $item (@logintext) {
$defaults{'logintext'}{$item} = $defaultdesign{'login.'.$item};
}
foreach my $item (@links) {
$defaults{'links'}{$item} = $defaultdesign{'login.'.$item};
}
if (ref($settings) eq 'HASH') {
foreach my $item (@toggles) {
if ($settings->{$item} eq '1') {
$checkedon{$item} = ' checked="checked" ';
$checkedoff{$item} = ' ';
} elsif ($settings->{$item} eq '0') {
$checkedoff{$item} = ' checked="checked" ';
$checkedon{$item} = ' ';
}
}
foreach my $item (@images) {
if (defined($settings->{$item})) {
$designs{$item} = $settings->{$item};
$is_custom{$item} = 1;
}
if (defined($settings->{'showlogo'}{$item})) {
$designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item};
}
}
foreach my $item (@alttext) {
if (ref($settings->{'alttext'}) eq 'HASH') {
if ($settings->{'alttext'}->{$item} ne '') {
$designs{'alttext'}{$item} = $settings->{'alttext'}{$item};
}
}
}
foreach my $item (@logintext) {
if ($settings->{$item} ne '') {
$designs{'logintext'}{$item} = $settings->{$item};
$is_custom{$item} = 1;
}
}
if ($settings->{'font'} ne '') {
$designs{'font'} = $settings->{'font'};
$is_custom{'font'} = 1;
}
foreach my $item (@bgs) {
if ($settings->{$item} ne '') {
$designs{'bgs'}{$item} = $settings->{$item};
$is_custom{$item} = 1;
}
}
foreach my $item (@links) {
if ($settings->{$item} ne '') {
$designs{'links'}{$item} = $settings->{$item};
$is_custom{$item} = 1;
}
}
} else {
if ($designhash{$dom.'.login.font'} ne '') {
$designs{'font'} = $designhash{$dom.'.login.font'};
$is_custom{'font'} = 1;
}
foreach my $item (@images) {
if ($designhash{$dom.'.login.'.$item} ne '') {
$designs{$item} = $designhash{$dom.'.login.'.$item};
$is_custom{$item} = 1;
}
}
foreach my $item (@bgs) {
if ($designhash{$dom.'.login.'.$item} ne '') {
$designs{'bgs'}{$item} = $designhash{$dom.'.login.'.$item};
$is_custom{$item} = 1;
}
}
foreach my $item (@links) {
if ($designhash{$dom.'.login.'.$item} ne '') {
$designs{'links'}{$item} = $designhash{$dom.'.login.'.$item};
$is_custom{$item} = 1;
}
}
}
my %alt_text = &Apache::lonlocal::texthash ( img => 'Log-in banner',
logo => 'Institution Logo',
domlogo => 'Domain Logo',
login => 'Login box');
my $itemcount = 1;
foreach my $item (@toggles) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .=
'<tr'.$css_class.'><td colspan="2">'.$choices{$item}.
'</td><td>'.
'<span class="LC_nobreak"><label><input type="radio" name="'.
$item.'"'.$checkedon{$item}.' value="1" />'.&mt('Yes').
'</label> <label><input type="radio" name="'.$item.'"'.
$checkedoff{$item}.' value="0" />'.&mt('No').'</label></span></td>'.
'</tr>';
$itemcount ++;
}
$datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext);
$datatable .= '</tr></table></td></tr>';
} elsif ($caller eq 'help') {
my ($defaulturl,$defaulttype,%url,%type,%langchoices);
my $itemcount = 1;
$defaulturl = '/adm/loginproblems.html';
$defaulttype = 'default';
%langchoices = &Apache::lonlocal::texthash(&get_languages_hash());
my @currlangs;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'helpurl'}) eq 'HASH') {
foreach my $key (sort(keys(%{$settings->{'helpurl'}}))) {
next if ($settings->{'helpurl'}{$key} eq '');
$url{$key} = $settings->{'helpurl'}{$key}.'?inhibitmenu=yes';
$type{$key} = 'custom';
unless ($key eq 'nolang') {
push(@currlangs,$key);
}
}
} elsif ($settings->{'helpurl'} ne '') {
$type{'nolang'} = 'custom';
$url{'nolang'} = $settings->{'helpurl'}.'?inhibitmenu=yes';
}
}
foreach my $lang ('nolang',sort(@currlangs)) {
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'>';
if ($url{$lang} eq '') {
$url{$lang} = $defaulturl;
}
if ($type{$lang} eq '') {
$type{$lang} = $defaulttype;
}
$datatable .= '<td colspan="2"><span class="LC_nobreak">';
if ($lang eq 'nolang') {
$datatable .= &mt('Log-in help page if no specific language file: [_1]',
&Apache::loncommon::modal_link($url{$lang},$lt{$type{$lang}},600,500));
} else {
$datatable .= &mt('Log-in help page for language: [_1] is [_2]',
$langchoices{$lang},
&Apache::loncommon::modal_link($url{$lang},$lt{$type{$lang}},600,500));
}
$datatable .= '</span></td>'."\n".
'<td class="LC_left_item">';
if ($type{$lang} eq 'custom') {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="loginhelpurl_del" value="'.$lang.'" />'.
$lt{'del'}.'</label> '.$lt{'rep'}.'</span>';
} else {
$datatable .= $lt{'upl'};
}
$datatable .='<br />';
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="loginhelpurl_'.$lang.'" />';
}
$datatable .= '</td></tr>';
$itemcount ++;
}
my @addlangs;
foreach my $lang (sort(keys(%langchoices))) {
next if ((grep(/^\Q$lang\E$/,@currlangs)) || ($lang eq 'x_chef'));
push(@addlangs,$lang);
}
if (@addlangs > 0) {
my %toadd;
map { $toadd{$_} = $langchoices{$_} ; } @addlangs;
$toadd{''} = &mt('Select');
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td class="LC_left_item" colspan="2">'.
&mt('Add log-in help page for a specific language:').' '.
&Apache::loncommon::select_form('','loginhelpurl_add_lang',\%toadd).
'</td><td class="LC_left_item">'.$lt{'upl'}.'<br />';
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="loginhelpurl_add_file" />';
}
$datatable .= '</td></tr>';
$itemcount ++;
}
$datatable .= &captcha_choice('login',$settings,$itemcount);
} elsif ($caller eq 'headtag') {
my %domservers = &Apache::lonnet::get_servers($dom);
my $choice = $choices{'headtag'};
$css_class = ' class="LC_odd_row"';
$datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.
'<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'.
'<th>'.$choices{'current'}.'</th>'.
'<th>'.$choices{'action'}.'</th>'.
'<th>'.$choices{'exempt'}.'</th></tr>'."\n";
my (%currurls,%currexempt);
if (ref($settings) eq 'HASH') {
if (ref($settings->{'headtag'}) eq 'HASH') {
foreach my $lonhost (keys(%{$settings->{'headtag'}})) {
if (ref($settings->{'headtag'}{$lonhost}) eq 'HASH') {
$currurls{$lonhost} = $settings->{'headtag'}{$lonhost}{'url'};
$currexempt{$lonhost} = $settings->{'headtag'}{$lonhost}{'exempt'};
}
}
}
}
foreach my $lonhost (sort(keys(%domservers))) {
my $exempt = &check_exempt_addresses($currexempt{$lonhost});
$datatable .= '<tr><td>'.$domservers{$lonhost}.'</td>';
if ($currurls{$lonhost}) {
$datatable .= '<td class="LC_right_item"><a href="'.
"javascript:void(open('$currurls{$lonhost}?inhibitmenu=yes','Custom_HeadTag',
'menubar=0,toolbar=1,scrollbars=1,width=600,height=500,resizable=yes'))".
'">'.$lt{'curr'}.'</a></td>'.
'<td><span class="LC_nobreak"><label>'.
'<input type="checkbox" name="loginheadtag_del" value="'.$lonhost.'" />'.
$lt{'del'}.'</label> '.$lt{'rep'}.'</span>';
} else {
$datatable .= '<td class="LC_right_item">'.$lt{'none'}.'</td><td>'.$lt{'upl'};
}
$datatable .='<br />';
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />';
}
$datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';
}
$datatable .= '</table></td></tr>';
} elsif ($caller eq 'saml') {
my %domservers = &Apache::lonnet::get_servers($dom);
$datatable .= '<tr><td colspan="3" style="text-align: left">'.
'<table><tr><th>'.$choices{'hostid'}.'</th>'.
'<th>'.$choices{'samllanding'}.'</th>'.
'<th>'.$choices{'samloptions'}.'</th></tr>'."\n";
my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso,%styleon,%styleoff);
foreach my $lonhost (keys(%domservers)) {
$samlurl{$lonhost} = '/adm/sso';
$styleon{$lonhost} = 'display:none';
$styleoff{$lonhost} = '';
}
if ((ref($settings) eq 'HASH') && (ref($settings->{'saml'}) eq 'HASH')) {
foreach my $lonhost (keys(%{$settings->{'saml'}})) {
if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') {
$saml{$lonhost} = 1;
$samltext{$lonhost} = $settings->{'saml'}{$lonhost}{'text'};
$samlimg{$lonhost} = $settings->{'saml'}{$lonhost}{'img'};
$samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'};
$samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'};
$samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'};
$samlwindow{$lonhost} = $settings->{'saml'}{$lonhost}{'window'};
$samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'};
$styleon{$lonhost} = '';
$styleoff{$lonhost} = 'display:none';
} else {
$styleon{$lonhost} = 'display:none';
$styleoff{$lonhost} = '';
}
}
}
my $itemcount = 1;
foreach my $lonhost (sort(keys(%domservers))) {
my $samlon = ' ';
my $samloff = ' checked="checked" ';
if ($saml{$lonhost}) {
$samlon = $samloff;
$samloff = ' ';
}
my $samlwinon = '';
my $samlwinoff = ' checked="checked"';
if ($samlwindow{$lonhost}) {
$samlwinon = $samlwinoff;
$samlwinoff = '';
}
my $css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'.
'<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff.
'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="0" />'.
&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="saml_'.$lonhost.'"'.$samlon.
'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'.
&mt('Yes').'</label></span></td>'.
'<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'.
'<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th></tr>'.
'<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'.
'<th>'.&mt('Alt Text').'</th></tr>'.
'<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="20" value="'.
$samltext{$lonhost}.'" /></td><td>';
if ($samlimg{$lonhost}) {
$datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="saml_img_del" value="'.$lonhost.'" />'.
$lt{'del'}.'</label> '.$lt{'rep'}.'</span>';
} else {
$datatable .= $lt{'upl'};
}
$datatable .='<br />';
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />';
}
$datatable .= '</td>'.
'<td><input type="text" name="saml_alt_'.$lonhost.'" size="25" '.
'value="'.$samlalt{$lonhost}.'" /></td></tr></table><br />'.
'<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th><th align="center">'.
'<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'.
'<tr><th>'.&mt('URL').'</th><th>'.&mt('Tool Tip').'</th>'.
'<th>'.&mt('Pop-up if iframe').'</th><th>'.&mt('Text').'</th></tr>'.
'<tr'.$css_class.'>'.
'<td><input type="text" name="saml_url_'.$lonhost.'" size="30" '.
'value="'.$samlurl{$lonhost}.'" /></td>'.
'<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="20">'.
$samltitle{$lonhost}.'</textarea></td>'.
'<td><label><input type="radio" name="saml_window_'.$lonhost.'" value=""'.$samlwinoff.'>'.
&mt('No').'</label>'.(' 'x2).'<label><input type="radio" '.
'name="saml_window_'.$lonhost.'" value="1"'.$samlwinon.'>'.&mt('Yes').'</label></td>'.
'<td><input type="text" name="saml_notsso_'.$lonhost.'" size="12" '.
'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'.
'</table></td>'.
'<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%"> </td></tr>';
$itemcount ++;
}
$datatable .= '</table></td></tr>';
}
return $datatable;
}
sub login_choices {
my %choices =
&Apache::lonlocal::texthash (
coursecatalog => 'Display Course/Community Catalog link?',
adminmail => "Display Administrator's E-mail Address?",
helpdesk => 'Display "Contact Helpdesk" link',
disallowlogin => "Login page requests redirected",
hostid => "Server",
server => "Redirect to:",
serverpath => "Path",
custompath => "Custom",
exempt => "Exempt IP(s)",
directlogin => "No redirect",
newuser => "Link to create a user account",
img => "Header",
logo => "Main Logo",
domlogo => "Domain Logo",
login => "Log-in Header",
textcol => "Text color",
bgcol => "Box color",
bgs => "Background colors",
links => "Link colors",
font => "Font color",
pgbg => "Header",
mainbg => "Page",
sidebg => "Login box",
link => "Link",
alink => "Active link",
vlink => "Visited link",
headtag => "Custom markup",
action => "Action",
current => "Current",
samllanding => "Dual login?",
samloptions => "Options",
alttext => "Alt text",
);
return %choices;
}
sub login_file_options {
return &Apache::lonlocal::texthash(
del => 'Delete?',
rep => 'Replace:',
upl => 'Upload:',
curr => 'View contents',
default => 'Default',
custom => 'Custom',
none => 'None',
);
}
sub print_ipaccess {
my ($dom,$settings,$rowtotal) = @_;
my $css_class;
my $itemcount = 0;
my $datatable;
my %ordered;
if (ref($settings) eq 'HASH') {
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
if ($num eq '') {
$num = scalar(keys(%{$settings}));
}
$ordered{$num} = $item;
}
}
}
my $maxnum = scalar(keys(%ordered));
if (keys(%ordered)) {
my @items = sort { $a <=> $b } keys(%ordered);
for (my $i=0; $i<@items; $i++) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $item = $ordered{$items[$i]};
my ($name,$ipranges,%commblocks,%courses);
if (ref($settings->{$item}) eq 'HASH') {
$name = $settings->{$item}->{'name'};
$ipranges = $settings->{$item}->{'ip'};
if (ref($settings->{$item}->{'commblocks'}) eq 'HASH') {
%commblocks = %{$settings->{$item}->{'commblocks'}};
}
if (ref($settings->{$item}->{'courses'}) eq 'HASH') {
%courses = %{$settings->{$item}->{'courses'}};
}
}
my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_".$item."'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="ipaccess_pos_'.$item.'"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $i) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select>'.(' 'x2).
'<label><input type="checkbox" name="ipaccess_del" value="'.$item.'" />'.
&mt('Delete?').'</label></span></td>'.
'<td colspan="2"><input type="hidden" name="ipaccess_id_'.$i.'" value="'.$item.'" />'.
&ipaccess_options($i,$itemcount,$dom,$name,$ipranges,\%commblocks,\%courses).
'</td></tr>';
$itemcount ++;
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_add'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
'<input type="hidden" name="ipaccess_maxnum" value="'.$maxnum.'" />'."\n".
'<select name="ipaccess_pos_add"'.$chgstr.'>';
for (my $k=0; $k<$maxnum+1; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $maxnum) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select> '."\n".
'<input type="checkbox" name="ipaccess_add" value="1" />'.&mt('Add').'</span></td>'."\n".
'<td colspan="2">'.
&ipaccess_options('add',$itemcount,$dom).
'</td>'."\n".
'</tr>'."\n";
$$rowtotal ++;
return $datatable;
}
sub ipaccess_options {
my ($num,$itemcount,$dom,$name,$ipranges,$blocksref,$coursesref) = @_;
my (%currblocks,%currcourses,$output);
if (ref($blocksref) eq 'HASH') {
%currblocks = %{$blocksref};
}
if (ref($coursesref) eq 'HASH') {
%currcourses = %{$coursesref};
}
$output = '<fieldset><legend>'.&mt('Location(s)').'</legend>'.
'<span class="LC_nobreak">'.&mt('Name').': '.
'<input type="text" name="ipaccess_name_'.$num.'" value="'.$name.'" />'.
'</span></fieldset>'.
'<fieldset><legend>'.&mt('IP Range(s)').'</legend>'.
&mt('Format for each IP range').': '.&mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.
&mt('Range(s) will be stored as IP netblock(s) in CIDR notation (comma separated)').'<br />'.
'<textarea name="ipaccess_range_'.$num.'" rows="3" cols="80">'.
$ipranges.'</textarea></fieldset>'.
'<fieldset><legend>'.&mt('Functionality Blocked?').'</legend>'.
&blocker_checkboxes($num,$blocksref).'</fieldset>'.
'<fieldset><legend>'.&mt('Courses/Communities allowed').'</legend>'.
'<table>';
foreach my $cid (sort(keys(%currcourses))) {
my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});
$output .= '<tr><td><span class="LC_nobreak">'.
'<label><input type="checkbox" name="ipaccess_course_delete_'.$num.'" value="'.$cid.'" />'.
&mt('Delete?').' <span class="LC_cusr_emph">'.$courseinfo{'description'}.'</span></label></span>'.
' <span class="LC_fontsize_medium">('.$cid.')</span></td></tr>';
}
$output .= '<tr><td><span class="LC_nobreak">'.&mt('Add').': '.
'<input type="text" name="ipaccess_cdesc_'.$num.'" value="" onfocus="this.blur();opencrsbrowser('."'display','ipaccess_cnum_$num','ipaccess_cdom_$num','ipaccess_cdesc_$num'".');" />'.
&Apache::loncommon::selectcourse_link('display','ipaccess_cnum_'.$num,'ipaccess_cdom_'.$num,'ipaccess_cdesc_'.$num,$dom,undef,'Course/Community').
'<input type="hidden" name="ipaccess_cnum_'.$num.'" value="" />'.
'<input type="hidden" name="ipaccess_cdom_'.$num.'" value="" />'.
'</span></td></tr></table>'."\n".
'</fieldset>';
return $output;
}
sub blocker_checkboxes {
my ($num,$blocks) = @_;
my ($typeorder,$types) = &commblocktype_text();
my $numinrow = 6;
my $output = '<table>';
for (my $i=0; $i<@{$typeorder}; $i++) {
my $block = $typeorder->[$i];
my $blockstatus;
if (ref($blocks) eq 'HASH') {
if ($blocks->{$block} eq 'on') {
$blockstatus = 'checked="checked"';
}
}
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$output .= '</tr>';
}
$output .= '<tr>';
}
if ($i == scalar(@{$typeorder})-1) {
my $colsleft = $numinrow-$rem;
if ($colsleft > 1) {
$output .= '<td colspan="'.$colsleft.'">';
} else {
$output .= '<td>';
}
} else {
$output .= '<td>';
}
my $item = 'ipaccess_block_'.$num;
if ($blockstatus) {
$blockstatus = ' '.$blockstatus;
}
$output .= '<span class="LC_nobreak"><label>'."\n".
'<input type="checkbox" name="'.$item.'"'.
$blockstatus.' value="'.$block.'"'.' />'.
$types->{$block}.'</label></span>'."\n".
'<br /></td>';
}
$output .= '</tr></table>';
return $output;
}
sub commblocktype_text {
my %types = &Apache::lonlocal::texthash(
'com' => 'Messaging',
'chat' => 'Chat Room',
'boards' => 'Discussion',
'port' => 'Portfolio',
'groups' => 'Groups',
'blogs' => 'Blogs',
'about' => 'User Information',
'printout' => 'Printouts',
'passwd' => 'Change Password',
'grades' => 'Gradebook',
'search' => 'Course search',
'wishlist' => 'Stored links',
'annotate' => 'Annotations',
);
my $typeorder = ['com','chat','boards','port','groups','blogs','about','wishlist','printout','grades','search','annotate','passwd'];
return ($typeorder,\%types);
}
sub print_rolecolors {
my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_;
my %choices = &color_font_choices();
my @bgs = ('pgbg','tabbg','sidebg');
my @links = ('link','alink','vlink');
my @images = ();
my %alt_text = &Apache::lonlocal::texthash(img => "Banner for $role role");
my %designhash = &Apache::loncommon::get_domainconf($dom);
my %defaultdesign = %Apache::loncommon::defaultdesign;
my (%is_custom,%designs);
my %defaults = &role_defaults($role,\@bgs,\@links,\@images);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$role}) eq 'HASH') {
if ($settings->{$role}->{'font'} ne '') {
$designs{'font'} = $settings->{$role}->{'font'};
$is_custom{'font'} = 1;
}
if ($settings->{$role}->{'fontmenu'} ne '') {
$designs{'fontmenu'} = $settings->{$role}->{'fontmenu'};
$is_custom{'fontmenu'} = 1;
}
foreach my $item (@bgs) {
if ($settings->{$role}->{$item} ne '') {
$designs{'bgs'}{$item} = $settings->{$role}->{$item};
$is_custom{$item} = 1;
}
}
foreach my $item (@links) {
if ($settings->{$role}->{$item} ne '') {
$designs{'links'}{$item} = $settings->{$role}->{$item};
$is_custom{$item} = 1;
}
}
}
} else {
if ($designhash{$dom.'.'.$role.'.fontmenu'} ne '') {
$designs{fontmenu} = $designhash{$dom.'.'.$role.'.fontmenu'};
$is_custom{'fontmenu'} = 1;
}
if ($designhash{$dom.'.'.$role.'.font'} ne '') {
$designs{font} = $designhash{$dom.'.'.$role.'.font'};
$is_custom{'font'} = 1;
}
foreach my $item (@bgs) {
if ($designhash{$dom.'.'.$role.'.'.$item} ne '') {
$designs{'bgs'}{$item} = $designhash{$dom.'.'.$role.'.'.$item};
$is_custom{$item} = 1;
}
}
foreach my $item (@links) {
if ($designhash{$dom.'.'.$role.'.'.$item} ne '') {
$designs{'links'}{$item} = $designhash{$dom.'.'.$role.'.'.$item};
$is_custom{$item} = 1;
}
}
}
my $itemcount = 1;
my $datatable = &display_color_options($dom,$confname,$phase,$role,$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal);
$datatable .= '</tr></table></td></tr>';
return $datatable;
}
sub role_defaults {
my ($role,$bgs,$links,$images,$logintext) = @_;
my %defaults;
unless ((ref($bgs) eq 'ARRAY') && (ref($links) eq 'ARRAY') && (ref($images) eq 'ARRAY')) {
return %defaults;
}
my %defaultdesign = %Apache::loncommon::defaultdesign;
if ($role eq 'login') {
%defaults = (
font => $defaultdesign{$role.'.font'},
);
if (ref($logintext) eq 'ARRAY') {
foreach my $item (@{$logintext}) {
$defaults{'logintext'}{$item} = $defaultdesign{$role.'.'.$item};
}
}
foreach my $item (@{$images}) {
$defaults{'showlogo'}{$item} = 1;
}
} else {
%defaults = (
font => $defaultdesign{$role.'.font'},
fontmenu => $defaultdesign{$role.'.fontmenu'},
);
}
foreach my $item (@{$bgs}) {
$defaults{'bgs'}{$item} = $defaultdesign{$role.'.'.$item};
}
foreach my $item (@{$links}) {
$defaults{'links'}{$item} = $defaultdesign{$role.'.'.$item};
}
foreach my $item (@{$images}) {
$defaults{$item} = $defaultdesign{$role.'.'.$item};
}
return %defaults;
}
sub display_color_options {
my ($dom,$confname,$phase,$role,$itemcount,$choices,$is_custom,$defaults,$designs,
$images,$bgs,$links,$alt_text,$rowtotal,$logintext) = @_;
my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
my $css_class = $itemcount%2?' class="LC_odd_row"':'';
my $datatable = '<tr'.$css_class.'>'.
'<td>'.$choices->{'font'}.'</td>';
if (!$is_custom->{'font'}) {
$datatable .= '<td>'.&mt('Default in use:').' <span class="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>';
} else {
$datatable .= '<td> </td>';
}
my $current_color = $designs->{'font'} ? $designs->{'font'} : $defaults->{'font'};
$datatable .= '<td><span class="LC_nobreak">'.
'<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'.
' value="'.$current_color.'" /> '.
' </span></td></tr>';
unless ($role eq 'login') {
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$choices->{'fontmenu'}.'</td>';
if (!$is_custom->{'fontmenu'}) {
$datatable .= '<td>'.&mt('Default in use:').' <span class="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>';
} else {
$datatable .= '<td> </td>';
}
$current_color = $designs->{'fontmenu'} ?
$designs->{'fontmenu'} : $defaults->{'fontmenu'};
$datatable .= '<td><span class="LC_nobreak">'.
'<input class="colorchooser" type="text" size="10" name="'
.$role.'_fontmenu"'.
' value="'.$current_color.'" /> '.
' </span></td></tr>';
}
my $switchserver = &check_switchserver($dom,$confname);
foreach my $img (@{$images}) {
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$choices->{$img};
my ($imgfile,$img_import,$login_hdr_pick,$logincolors,$alttext);
if ($role eq 'login') {
if ($img eq 'login') {
$login_hdr_pick =
&login_header_options($img,$role,$defaults,$is_custom,$choices);
$logincolors =
&login_text_colors($img,$role,$logintext,$phase,$choices,
$designs,$defaults);
} else {
if ($img ne 'domlogo') {
$datatable.= &logo_display_options($img,$defaults,$designs);
}
if (ref($designs->{'alttext'}) eq 'HASH') {
$alttext = $designs->{'alttext'}{$img};
}
}
}
$datatable .= '</td>';
if ($designs->{$img} ne '') {
$imgfile = $designs->{$img};
$img_import = ($imgfile =~ m{^/adm/});
} else {
$imgfile = $defaults->{$img};
}
if ($imgfile) {
my ($showfile,$fullsize);
if ($imgfile =~ m-^(/res/\Q$dom\E/\Q$confname\E/\Q$img\E)/([^/]+)$-) {
my $urldir = $1;
my $filename = $2;
my @info = &Apache::lonnet::stat_file($designs->{$img});
if (@info) {
my $thumbfile = 'tn-'.$filename;
my @thumb=&Apache::lonnet::stat_file($urldir.'/'.$thumbfile);
if (@thumb) {
$showfile = $urldir.'/'.$thumbfile;
} else {
$showfile = $imgfile;
}
} else {
$showfile = '';
}
} elsif ($imgfile =~ m-^/(adm/[^/]+)/([^/]+)$-) {
$showfile = $imgfile;
my $imgdir = $1;
my $filename = $2;
if (-e "$londocroot/$imgdir/tn-".$filename) {
$showfile = "/$imgdir/tn-".$filename;
} else {
my $input = $londocroot.$imgfile;
my $output = "$londocroot/$imgdir/tn-".$filename;
if (!-e $output) {
my ($width,$height) = &thumb_dimensions();
my ($fullwidth,$fullheight) = &check_dimensions($input);
if ($fullwidth ne '' && $fullheight ne '') {
if ($fullwidth > $width && $fullheight > $height) {
my $size = $width.'x'.$height;
my @args = ('convert','-sample',$size,$input,$output);
system({$args[0]} @args);
$showfile = "/$imgdir/tn-".$filename;
}
}
}
}
}
if ($showfile) {
if ($showfile =~ m{^/(adm|res)/}) {
if ($showfile =~ m{^/res/}) {
my $local_showfile =
&Apache::lonnet::filelocation('',$showfile);
&Apache::lonnet::repcopy($local_showfile);
}
$showfile = &Apache::loncommon::lonhttpdurl($showfile);
}
if ($imgfile) {
if ($imgfile =~ m{^/(adm|res)/}) {
if ($imgfile =~ m{^/res/}) {
my $local_imgfile =
&Apache::lonnet::filelocation('',$imgfile);
&Apache::lonnet::repcopy($local_imgfile);
}
$fullsize = &Apache::loncommon::lonhttpdurl($imgfile);
} else {
$fullsize = $imgfile;
}
}
$datatable .= '<td>';
if ($img eq 'login') {
$datatable .= $login_hdr_pick;
}
$datatable .= &image_changes($is_custom->{$img},$alt_text->{$img},$img_import,
$showfile,$fullsize,$role,$img,$imgfile,$logincolors);
} else {
$datatable .= '<td> </td><td class="LC_left_item">'.
&mt('Upload:').'<br />';
}
} else {
$datatable .= '<td> </td><td class="LC_left_item">'.
&mt('Upload:').'<br />';
}
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
if ($img ne 'login') { # suppress file selection for Log-in header
$datatable .=' <input type="file" name="'.$role.'_'.$img.'" />';
}
}
if (($role eq 'login') && ($img ne 'login')) {
$datatable .= (' ' x2).' <span class="LC_nobreak"><label>'.$choices->{'alttext'}.':'.
'<input type="text" name="'.$role.'_alt_'.$img.'" size="10" value="'.$alttext.'" />'.
'</label></span>';
}
$datatable .= '</td></tr>';
}
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$choices->{'bgs'}.'</td>';
my $bgs_def;
foreach my $item (@{$bgs}) {
if (!$is_custom->{$item}) {
$bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span> <span class="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';"> </span><br />'.$defaults->{'bgs'}{$item}.'</td>';
}
}
if ($bgs_def) {
$datatable .= '<td>'.&mt('Default(s) in use:').'<br /><table border="0"><tr>'.$bgs_def.'</tr></table></td>';
} else {
$datatable .= '<td> </td>';
}
$datatable .= '<td class="LC_right_item">'.
'<table border="0"><tr>';
foreach my $item (@{$bgs}) {
$datatable .= '<td style="text-align: center">'.$choices->{$item};
my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};
if ($designs->{'bgs'}{$item}) {
$datatable .= ' ';
}
$datatable .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.
'" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';
}
$datatable .= '</tr></table></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$choices->{'links'}.'</td>';
my $links_def;
foreach my $item (@{$links}) {
if (!$is_custom->{$item}) {
$links_def .= '<td>'.$choices->{$item}.'<br /><span class="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>';
}
}
if ($links_def) {
$datatable .= '<td>'.&mt('Default(s) in use:').'<br /><table border="0"><tr>'.$links_def.'</tr></table></td>';
} else {
$datatable .= '<td> </td>';
}
$datatable .= '<td class="LC_right_item">'.
'<table border="0"><tr>';
foreach my $item (@{$links}) {
my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};
$datatable .= '<td style="text-align: center">'.$choices->{$item}."\n";
if ($designs->{'links'}{$item}) {
$datatable.=' ';
}
$datatable .= '<br /><input type="text" size="8" class="colorchooser" name="'.$role.'_'.$item.'" value="'.$color.
'" /></td>';
}
$$rowtotal += $itemcount;
return $datatable;
}
sub logo_display_options {
my ($img,$defaults,$designs) = @_;
my $checkedon;
if (ref($defaults) eq 'HASH') {
if (ref($defaults->{'showlogo'}) eq 'HASH') {
if ($defaults->{'showlogo'}{$img}) {
$checkedon = 'checked="checked" ';
}
}
}
if (ref($designs) eq 'HASH') {
if (ref($designs->{'showlogo'}) eq 'HASH') {
if (defined($designs->{'showlogo'}{$img})) {
if ($designs->{'showlogo'}{$img} == 0) {
$checkedon = '';
} elsif ($designs->{'showlogo'}{$img} == 1) {
$checkedon = 'checked="checked" ';
}
}
}
}
return '<br /><label> <input type="checkbox" name="'.
'login_showlogo_'.$img.'" value="1" '.$checkedon.'/>'.
&mt('show').'</label>'."\n";
}
sub login_header_options {
my ($img,$role,$defaults,$is_custom,$choices) = @_;
my $output = '';
if ((!$is_custom->{'textcol'}) || (!$is_custom->{'bgcol'})) {
$output .= &mt('Text default(s):').'<br />';
if (!$is_custom->{'textcol'}) {
$output .= $choices->{'textcol'}.': '.$defaults->{'logintext'}{'textcol'}.
' ';
}
if (!$is_custom->{'bgcol'}) {
$output .= $choices->{'bgcol'}.': '.
'<span id="css_'.$role.'_font" style="background-color: '.
$defaults->{'logintext'}{'bgcol'}.';"> </span>';
}
$output .= '<br />';
}
$output .='<br />';
return $output;
}
sub login_text_colors {
my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;
my $color_menu = '<table border="0"><tr>';
foreach my $item (@{$logintext}) {
$color_menu .= '<td style="text-align: center">'.$choices->{$item};
my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};
$color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.
'" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';
}
$color_menu .= '</tr></table><br />';
return $color_menu;
}
sub image_changes {
my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_;
my $output;
if ($img eq 'login') {
$output = '</td><td>'.$logincolors; # suppress image for Log-in header
} elsif (!$is_custom) {
if ($img ne 'domlogo') {
$output = &mt('Default image:').'<br />';
} else {
$output = &mt('Default in use:').'<br />';
}
}
if ($img ne 'login') {
if ($img_import) {
$output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />';
}
$output .= '<a href="'.$fullsize.'" target="_blank"><img src="'.
$showfile.'" alt="'.$alt_text.'" border="0" /></a></td>';
if ($is_custom) {
$output .= '<td>'.$logincolors.'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.
$role.'_del_'.$img.'" value="1" />'.&mt('Delete?').
'</label> '.&mt('Replace:').'</span><br />';
} else {
$output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />';
}
}
return $output;
}
sub print_quotas {
my ($dom,$settings,$rowtotal,$action) = @_;
my $context;
if ($action eq 'quotas') {
$context = 'tools';
} else {
$context = $action;
}
my ($datatable,$defaultquota,@usertools,@options,%validations);
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my $typecount = 0;
my ($css_class,%titles);
if ($context eq 'requestcourses') {
@usertools = ('official','unofficial','community','textbook','placement','lti');
@options =('norequest','approval','validate','autolimit');
%validations = &Apache::lonnet::auto_courserequest_checks($dom);
%titles = &courserequest_titles();
} elsif ($context eq 'requestauthor') {
@usertools = ('author');
@options = ('norequest','approval','automatic');
%titles = &authorrequest_titles();
} else {
@usertools = ('aboutme','blog','portfolio','portaccess','timezone');
%titles = &tool_titles();
}
if (ref($types) eq 'ARRAY') {
foreach my $type (@{$types}) {
my $currdefquota;
unless (($context eq 'requestcourses') ||
($context eq 'requestauthor')) {
if (ref($settings) eq 'HASH') {
if (ref($settings->{defaultquota}) eq 'HASH') {
$currdefquota = $settings->{defaultquota}->{$type};
} else {
$currdefquota = $settings->{$type};
}
}
}
if (defined($usertypes->{$type})) {
$typecount ++;
$css_class = $typecount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$usertypes->{$type}.'</td>'.
'<td class="LC_left_item">';
if ($context eq 'requestcourses') {
$datatable .= '<table><tr>';
}
my %cell;
foreach my $item (@usertools) {
if ($context eq 'requestcourses') {
my ($curroption,$currlimit);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$item}) eq 'HASH') {
$curroption = $settings->{$item}->{$type};
if ($curroption =~ /^autolimit=(\d*)$/) {
$currlimit = $1;
}
}
}
if (!$curroption) {
$curroption = 'norequest';
}
$datatable .= '<th>'.$titles{$item}.'</th>';
foreach my $option (@options) {
my $val = $option;
if ($option eq 'norequest') {
$val = 0;
}
if ($option eq 'validate') {
my $canvalidate = 0;
if (ref($validations{$item}) eq 'HASH') {
if ($validations{$item}{$type}) {
$canvalidate = 1;
}
}
next if (!$canvalidate);
}
my $checked = '';
if ($option eq $curroption) {
$checked = ' checked="checked"';
} elsif ($option eq 'autolimit') {
if ($curroption =~ /^autolimit/) {
$checked = ' checked="checked"';
}
}
$cell{$item} .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="crsreq_'.$item.
'_'.$type.'" value="'.$val.'"'.$checked.' />'.
$titles{$option}.'</label>';
if ($option eq 'autolimit') {
$cell{$item} .= ' <input type="text" name="crsreq_'.
$item.'_limit_'.$type.'" size="1" '.
'value="'.$currlimit.'" />';
}
$cell{$item} .= '</span> ';
if ($option eq 'autolimit') {
$cell{$item} .= $titles{'unlimited'};
}
}
} elsif ($context eq 'requestauthor') {
my $curroption;
if (ref($settings) eq 'HASH') {
$curroption = $settings->{$type};
}
if (!$curroption) {
$curroption = 'norequest';
}
foreach my $option (@options) {
my $val = $option;
if ($option eq 'norequest') {
$val = 0;
}
my $checked = '';
if ($option eq $curroption) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="authorreq_'.$type.
'" value="'.$val.'"'.$checked.' />'.
$titles{$option}.'</label></span> ';
}
} else {
my $checked = 'checked="checked" ';
if ($item eq 'timezone') {
$checked = '';
}
if (ref($settings) eq 'HASH') {
if (ref($settings->{$item}) eq 'HASH') {
if (!$settings->{$item}->{$type}) {
$checked = '';
} elsif ($settings->{$item}->{$type} == 1) {
$checked = 'checked="checked" ';
}
}
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$context.'_'.$item.
'" value="'.$type.'" '.$checked.'/>'.$titles{$item}.
'</label></span> ';
}
}
if ($context eq 'requestcourses') {
$datatable .= '</tr><tr>';
foreach my $item (@usertools) {
$datatable .= '<td style="vertical-align: top">'.$cell{$item}.'</td>';
}
$datatable .= '</tr></table>';
}
$datatable .= '</td>';
unless (($context eq 'requestcourses') ||
($context eq 'requestauthor')) {
$datatable .=
'<td class="LC_right_item">'.
'<span class="LC_nobreak">'.
'<input type="text" name="quota_'.$type.
'" value="'.$currdefquota.
'" size="5" /></span></td>';
}
$datatable .= '</tr>';
}
}
}
unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
$defaultquota = '20';
if (ref($settings) eq 'HASH') {
if (ref($settings->{'defaultquota'}) eq 'HASH') {
$defaultquota = $settings->{'defaultquota'}->{'default'};
} elsif (defined($settings->{'default'})) {
$defaultquota = $settings->{'default'};
}
}
}
$typecount ++;
$css_class = $typecount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$othertitle.'</td>'.
'<td class="LC_left_item">';
if ($context eq 'requestcourses') {
$datatable .= '<table><tr>';
}
my %defcell;
foreach my $item (@usertools) {
if ($context eq 'requestcourses') {
my ($curroption,$currlimit);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$item}) eq 'HASH') {
$curroption = $settings->{$item}->{'default'};
if ($curroption =~ /^autolimit=(\d*)$/) {
$currlimit = $1;
}
}
}
if (!$curroption) {
$curroption = 'norequest';
}
$datatable .= '<th>'.$titles{$item}.'</th>';
foreach my $option (@options) {
my $val = $option;
if ($option eq 'norequest') {
$val = 0;
}
if ($option eq 'validate') {
my $canvalidate = 0;
if (ref($validations{$item}) eq 'HASH') {
if ($validations{$item}{'default'}) {
$canvalidate = 1;
}
}
next if (!$canvalidate);
}
my $checked = '';
if ($option eq $curroption) {
$checked = ' checked="checked"';
} elsif ($option eq 'autolimit') {
if ($curroption =~ /^autolimit/) {
$checked = ' checked="checked"';
}
}
$defcell{$item} .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="crsreq_'.$item.
'_default" value="'.$val.'"'.$checked.' />'.
$titles{$option}.'</label>';
if ($option eq 'autolimit') {
$defcell{$item} .= ' <input type="text" name="crsreq_'.
$item.'_limit_default" size="1" '.
'value="'.$currlimit.'" />';
}
$defcell{$item} .= '</span> ';
if ($option eq 'autolimit') {
$defcell{$item} .= $titles{'unlimited'};
}
}
} elsif ($context eq 'requestauthor') {
my $curroption;
if (ref($settings) eq 'HASH') {
$curroption = $settings->{'default'};
}
if (!$curroption) {
$curroption = 'norequest';
}
foreach my $option (@options) {
my $val = $option;
if ($option eq 'norequest') {
$val = 0;
}
my $checked = '';
if ($option eq $curroption) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="authorreq_default"'.
' value="'.$val.'"'.$checked.' />'.
$titles{$option}.'</label></span> ';
}
} else {
my $checked = 'checked="checked" ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{$item}) eq 'HASH') {
if ($settings->{$item}->{'default'} == 0) {
$checked = '';
} elsif ($settings->{$item}->{'default'} == 1) {
$checked = 'checked="checked" ';
}
}
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$context.'_'.$item.
'" value="default" '.$checked.'/>'.$titles{$item}.
'</label></span> ';
}
}
if ($context eq 'requestcourses') {
$datatable .= '</tr><tr>';
foreach my $item (@usertools) {
$datatable .= '<td style="vertical-align: top">'.$defcell{$item}.'</td>';
}
$datatable .= '</tr></table>';
}
$datatable .= '</td>';
unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
$datatable .= '<td class="LC_right_item">'.
'<span class="LC_nobreak">'.
'<input type="text" name="defaultquota" value="'.
$defaultquota.'" size="5" /></span></td>';
}
$datatable .= '</tr>';
$typecount ++;
$css_class = $typecount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.&mt('LON-CAPA Advanced Users').'<br />';
if ($context eq 'requestcourses') {
$datatable .= &mt('(overrides affiliation, if set)').
'</td>'.
'<td class="LC_left_item">'.
'<table><tr>';
} else {
$datatable .= &mt('(overrides affiliation, if checked)').
'</td>'.
'<td class="LC_left_item" colspan="2">'.
'<br />';
}
my %advcell;
foreach my $item (@usertools) {
if ($context eq 'requestcourses') {
my ($curroption,$currlimit);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$item}) eq 'HASH') {
$curroption = $settings->{$item}->{'_LC_adv'};
if ($curroption =~ /^autolimit=(\d*)$/) {
$currlimit = $1;
}
}
}
$datatable .= '<th>'.$titles{$item}.'</th>';
my $checked = '';
if ($curroption eq '') {
$checked = ' checked="checked"';
}
$advcell{$item} .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="crsreq_'.$item.
'__LC_adv" value=""'.$checked.' />'.
&mt('No override set').'</label></span> ';
foreach my $option (@options) {
my $val = $option;
if ($option eq 'norequest') {
$val = 0;
}
if ($option eq 'validate') {
my $canvalidate = 0;
if (ref($validations{$item}) eq 'HASH') {
if ($validations{$item}{'_LC_adv'}) {
$canvalidate = 1;
}
}
next if (!$canvalidate);
}
my $checked = '';
if ($val eq $curroption) {
$checked = ' checked="checked"';
} elsif ($option eq 'autolimit') {
if ($curroption =~ /^autolimit/) {
$checked = ' checked="checked"';
}
}
$advcell{$item} .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="crsreq_'.$item.
'__LC_adv" value="'.$val.'"'.$checked.' />'.
$titles{$option}.'</label>';
if ($option eq 'autolimit') {
$advcell{$item} .= ' <input type="text" name="crsreq_'.
$item.'_limit__LC_adv" size="1" '.
'value="'.$currlimit.'" />';
}
$advcell{$item} .= '</span> ';
if ($option eq 'autolimit') {
$advcell{$item} .= $titles{'unlimited'};
}
}
} elsif ($context eq 'requestauthor') {
my $curroption;
if (ref($settings) eq 'HASH') {
$curroption = $settings->{'_LC_adv'};
}
my $checked = '';
if ($curroption eq '') {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="authorreq__LC_adv"'.
' value=""'.$checked.' />'.
&mt('No override set').'</label></span> ';
foreach my $option (@options) {
my $val = $option;
if ($option eq 'norequest') {
$val = 0;
}
my $checked = '';
if ($val eq $curroption) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="authorreq__LC_adv"'.
' value="'.$val.'"'.$checked.' />'.
$titles{$option}.'</label></span> ';
}
} else {
my $checked = 'checked="checked" ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{$item}) eq 'HASH') {
if ($settings->{$item}->{'_LC_adv'} == 0) {
$checked = '';
} elsif ($settings->{$item}->{'_LC_adv'} == 1) {
$checked = 'checked="checked" ';
}
}
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$context.'_'.$item.
'" value="_LC_adv" '.$checked.'/>'.$titles{$item}.
'</label></span> ';
}
}
if ($context eq 'requestcourses') {
$datatable .= '</tr><tr>';
foreach my $item (@usertools) {
$datatable .= '<td style="vertical-align: top">'.$advcell{$item}.'</td>';
}
$datatable .= '</tr></table>';
}
$datatable .= '</td></tr>';
$$rowtotal += $typecount;
return $datatable;
}
sub print_requestmail {
my ($dom,$action,$settings,$rowtotal,$customcss,$rowstyle) = @_;
my ($now,$datatable,%currapp);
$now = time;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'notify'}) eq 'HASH') {
if ($settings->{'notify'}{'approval'} ne '') {
map {$currapp{$_}=1;} split(/,/,$settings->{'notify'}{'approval'});
}
}
}
my $numinrow = 2;
my $css_class;
if ($$rowtotal%2) {
$css_class = 'LC_odd_row';
}
if ($customcss) {
$css_class .= " $customcss";
}
$css_class =~ s/^\s+//;
if ($css_class) {
$css_class = ' class="'.$css_class.'"';
}
if ($rowstyle) {
$css_class .= ' style="'.$rowstyle.'"';
}
my $text;
if ($action eq 'requestcourses') {
$text = &mt('Receive notification of course requests requiring approval');
} elsif ($action eq 'requestauthor') {
$text = &mt('Receive notification of Authoring Space requests requiring approval');
} else {
$text = &mt('Receive notification of queued requests for self-created user accounts requiring approval');
}
$datatable = '<tr'.$css_class.'>'.
' <td>'.$text.'</td>'.
' <td class="LC_left_item">';
my ($numdc,$table,$rows) = &active_dc_picker($dom,$numinrow,'checkbox',
$action.'notifyapproval',%currapp);
if ($numdc > 0) {
$datatable .= $table;
} else {
$datatable .= &mt('There are no active Domain Coordinators');
}
$datatable .='</td></tr>';
return $datatable;
}
sub print_studentcode {
my ($settings,$rowtotal) = @_;
my $rownum = 0;
my ($output,%current);
my @crstypes = ('official','unofficial','community','textbook','placement','lti');
if (ref($settings) eq 'HASH') {
if (ref($settings->{'uniquecode'}) eq 'HASH') {
foreach my $type (@crstypes) {
$current{$type} = $settings->{'uniquecode'}{$type};
}
}
}
$output .= '<tr>'.
'<td class="LC_left_item">'.&mt('Generate unique six character code as course identifier?').'</td>'.
'<td class="LC_left_item">';
foreach my $type (@crstypes) {
my $check = ' ';
if ($current{$type}) {
$check = ' checked="checked" ';
}
$output .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="uniquecode" value="'.$type.'"'.$check.'/>'.
&mt($type).'</label></span>'.(' 'x2).' ';
}
$output .= '</td></tr>';
$$rowtotal ++;
return $output;
}
sub print_textbookcourses {
my ($dom,$type,$settings,$rowtotal) = @_;
my $rownum = 0;
my $css_class;
my $itemcount = 1;
my $maxnum = 0;
my $bookshash;
if (ref($settings) eq 'HASH') {
$bookshash = $settings->{$type};
}
my %ordered;
if (ref($bookshash) eq 'HASH') {
foreach my $item (keys(%{$bookshash})) {
if (ref($bookshash->{$item}) eq 'HASH') {
my $num = $bookshash->{$item}{'order'};
$ordered{$num} = $item;
}
}
}
my $confname = $dom.'-domainconfig';
my $switchserver = &check_switchserver($dom,$confname);
my $maxnum = scalar(keys(%ordered));
my $datatable;
if (keys(%ordered)) {
my @items = sort { $a <=> $b } keys(%ordered);
for (my $i=0; $i<@items; $i++) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $key = $ordered{$items[$i]};
my %coursehash=&Apache::lonnet::coursedescription($key);
my $coursetitle = $coursehash{'description'};
my ($subject,$title,$author,$publisher,$image,$imgsrc,$cdom,$cnum);
if (ref($bookshash->{$key}) eq 'HASH') {
$subject = $bookshash->{$key}->{'subject'};
$title = $bookshash->{$key}->{'title'};
if ($type eq 'textbooks') {
$publisher = $bookshash->{$key}->{'publisher'};
$author = $bookshash->{$key}->{'author'};
$image = $bookshash->{$key}->{'image'};
if ($image ne '') {
my ($path,$imagefile) = ($image =~ m{^(.+)/([^/]+)$});
my $imagethumb = "$path/tn-".$imagefile;
$imgsrc = '<img src="'.$imagethumb.'" alt="'.&mt('Textbook image').'" />';
}
}
}
my $chgstr = ' onchange="javascript:reorderBooks(this.form,'."'$type".'_'."$key','$type'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="'.$type.'_'.$key.'"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $i) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select>'.(' 'x2).
'<label><input type="checkbox" name="'.$type.'_del" value="'.$key.'" />'.
&mt('Delete?').'</label></span></td>'.
'<td colspan="2">'.
'<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_subject_'.$i.'" value="'.$subject.'" /></span> '.
(' 'x2).
'<span class="LC_nobreak">'.&mt('Title:').'<input type="text" size="30" name="'.$type.'_title_'.$i.'" value="'.$title.'" /></span> ';
if ($type eq 'textbooks') {
$datatable .= (' 'x2).
'<span class="LC_nobreak">'.&mt('Publisher:').'<input type="text" size="10" name="'.$type.'_publisher_'.$i.'" value="'.$publisher.'" /></span> '.
(' 'x2).
'<span class="LC_nobreak">'.&mt('Author(s):').'<input type="text" size="25" name="'.$type.'_author_'.$i.'" value="'.$author.'" /></span> '.
(' 'x2).
'<span class="LC_nobreak">'.&mt('Thumbnail:');
if ($image) {
$datatable .= $imgsrc.
'<label><input type="checkbox" name="'.$type.'_image_del"'.
' value="'.$key.'" />'.&mt('Delete?').'</label></span> '.
'<span class="LC_nobreak"> '.&mt('Replace:').' ';
}
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="'.$type.'_image_'.$i.'" value="" />';
}
}
$datatable .= '<input type="hidden" name="'.$type.'_id_'.$i.'" value="'.$type.'_'.$key.'" /></span> '.
'<span class="LC_nobreak">'.&mt('LON-CAPA course:').' '.
$coursetitle.'</span></td></tr>'."\n";
$itemcount ++;
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderBooks(this.form,'."'$type"."_addbook_pos','$type'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
'<input type="hidden" name="'.$type.'_maxnum" value="'.$maxnum.'" />'."\n".
'<select name="'.$type.'_addbook_pos"'.$chgstr.'>';
for (my $k=0; $k<$maxnum+1; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $maxnum) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select> '."\n".
'<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</span></td>'."\n".
'<td colspan="2">'.
'<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.&mt('Title:').'<input type="text" size="30" name="'.$type.'_addbook_title" value="" /></span> '."\n".
(' 'x2);
if ($type eq 'textbooks') {
$datatable .= '<span class="LC_nobreak">'.&mt('Publisher:').'<input type="text" size="10" name="'.$type.'_addbook_publisher" value="" /></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.&mt('Author(s):').'<input type="text" size="25" name="'.$type.'_addbook_author" value="" /></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.&mt('Image:').' ';
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />';
}
$datatable .= '</span>'."\n";
}
$datatable .= '<span class="LC_nobreak">'.&mt('LON-CAPA course:').' '.
&Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom').
'<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'.
&Apache::loncommon::selectcourse_link
('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course').
'</span></td>'."\n".
'</tr>'."\n";
$itemcount ++;
return $datatable;
}
sub textbookcourses_javascript {
my ($settings) = @_;
return unless(ref($settings) eq 'HASH');
my (%ordered,%total,%jstext);
foreach my $type ('textbooks','templates') {
$total{$type} = 0;
if (ref($settings->{$type}) eq 'HASH') {
foreach my $item (keys(%{$settings->{$type}})) {
if (ref($settings->{$type}->{$item}) eq 'HASH') {
my $num = $settings->{$type}->{$item}{'order'};
$ordered{$type}{$num} = $item;
}
}
$total{$type} = scalar(keys(%{$settings->{$type}}));
}
my @jsarray = ();
foreach my $item (sort {$a <=> $b } (keys(%{$ordered{$type}}))) {
push(@jsarray,$ordered{$type}{$item});
}
$jstext{$type} = ' var '.$type.' = Array('."'".join("','",@jsarray)."'".');'."\n";
}
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderBooks(form,item,caller) {
var changedVal;
$jstext{'textbooks'};
$jstext{'templates'};
var newpos;
var maxh;
if (caller == 'textbooks') {
newpos = 'textbooks_addbook_pos';
maxh = 1 + $total{'textbooks'};
} else {
newpos = 'templates_addbook_pos';
maxh = 1 + $total{'templates'};
}
var current = new Array;
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
if (item == newpos) {
changedVal = newitemVal;
} else {
changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
current[newitemVal] = newpos;
}
if (caller == 'textbooks') {
for (var i=0; i<textbooks.length; i++) {
var elementName = 'textbooks_'+textbooks[i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
}
if (caller == 'templates') {
for (var i=0; i<templates.length; i++) {
var elementName = 'templates_'+templates[i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub ltitools_javascript {
my ($settings) = @_;
my $togglejs = <itools_toggle_js();
unless (ref($settings) eq 'HASH') {
return $togglejs;
}
my (%ordered,$total,%jstext);
$total = 0;
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
$ordered{$num} = $item;
}
}
$total = scalar(keys(%{$settings}));
my @jsarray = ();
foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
push(@jsarray,$ordered{$item});
}
my $jstext = ' var ltitools = Array('."'".join("','",@jsarray)."'".');'."\n";
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderLTITools(form,item) {
var changedVal;
$jstext
var newpos = 'ltitools_add_pos';
var maxh = 1 + $total;
var current = new Array;
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
if (item == newpos) {
changedVal = newitemVal;
} else {
changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
current[newitemVal] = newpos;
}
for (var i=0; i<ltitools.length; i++) {
var elementName = 'ltitools_'+ltitools[i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
// ]]>
</script>
$togglejs
ENDSCRIPT
}
sub ltitools_toggle_js {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleLTITools(form,setting,item) {
var radioname = '';
var divid = '';
if ((setting == 'passback') || (setting == 'roster')) {
radioname = 'ltitools_'+setting+'_'+item;
divid = 'ltitools_'+setting+'time_'+item;
var num = form.elements[radioname].length;
if (num) {
var setvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if (form.elements[radioname][i].value == '1') {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'inline-block';
}
setvis = 1;
}
break;
}
}
}
if (!setvis) {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'none';
}
}
}
if (setting == 'user') {
divid = 'ltitools_'+setting+'_div_'+item;
var checkid = 'ltitools_'+setting+'_field_'+item;
if (document.getElementById(divid)) {
if (document.getElementById(checkid)) {
if (document.getElementById(checkid).checked) {
document.getElementById(divid).style.display = 'inline-block';
} else {
document.getElementById(divid).style.display = 'none';
}
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub wafproxy_javascript {
my ($dom) = @_;
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function updateWAF() {
if (document.getElementById('wafproxy_remoteip')) {
var wafremote = 0;
if (document.display.wafproxy_remoteip.options[document.display.wafproxy_remoteip.selectedIndex].value == 'h') {
wafremote = 1;
}
var fields = new Array('header','trust');
for (var i=0; i<fields.length; i++) {
if (document.getElementById('wafproxy_'+fields[i])) {
if (wafremote == 1) {
document.getElementById('wafproxy_'+fields[i]).style.display = 'table-row';
}
else {
document.getElementById('wafproxy_'+fields[i]).style.display = 'none';
}
}
}
if (document.getElementById('wafproxyranges_$dom')) {
if (wafremote == 1) {
document.getElementById('wafproxyranges_$dom').style.display = 'inline-block';
} else {
for (var i=0; i<document.display.wafproxy_vpnaccess.length; i++) {
if (document.display.wafproxy_vpnaccess[i].checked) {
if (document.display.wafproxy_vpnaccess[i].value == 0) {
document.getElementById('wafproxyranges_$dom').style.display = 'none';
}
}
}
}
}
}
return;
}
function checkWAF() {
if (document.getElementById('wafproxy_remoteip')) {
var wafvpn = 0;
for (var i=0; i<document.display.wafproxy_vpnaccess.length; i++) {
if (document.display.wafproxy_vpnaccess[i].checked) {
if (document.display.wafproxy_vpnaccess[i].value == 1) {
wafvpn = 1;
}
break;
}
}
var vpn = new Array('vpnint','vpnext');
for (var i=0; i<vpn.length; i++) {
if (document.getElementById('wafproxy_show_'+vpn[i])) {
if (wafvpn == 1) {
document.getElementById('wafproxy_show_'+vpn[i]).style.display = 'table-row';
}
else {
document.getElementById('wafproxy_show_'+vpn[i]).style.display = 'none';
}
}
}
if (document.getElementById('wafproxyranges_$dom')) {
if (wafvpn == 1) {
document.getElementById('wafproxyranges_$dom').style.display = 'inline-block';
}
else if (document.display.wafproxy_remoteip.options[document.display.wafproxy_remoteip.selectedIndex].value != 'h') {
document.getElementById('wafproxyranges_$dom').style.display = 'none';
}
}
}
return;
}
function toggleWAF() {
if (document.getElementById('wafproxy_table')) {
var wafproxy = 0;
for (var i=0; i<document.display.wafproxy_${dom}.length; i++) {
if (document.display.wafproxy_${dom}[i].checked) {
if (document.display.wafproxy_${dom}[i].value == 1) {
wafproxy = 1;
break;
}
}
}
if (wafproxy == 1) {
document.getElementById('wafproxy_table').style.display='inline';
}
else {
document.getElementById('wafproxy_table').style.display='none';
}
if (document.getElementById('wafproxyrow_${dom}')) {
if (wafproxy == 1) {
document.getElementById('wafproxyrow_${dom}').style.display = 'table-row';
}
else {
document.getElementById('wafproxyrow_${dom}').style.display = 'none';
}
}
if (document.getElementById('nowafproxyrow_$dom')) {
if (wafproxy == 1) {
document.getElementById('nowafproxyrow_${dom}').style.display = 'none';
}
else {
document.getElementById('nowafproxyrow_${dom}').style.display = 'table-row';
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub proctoring_javascript {
my ($settings) = @_;
my (%ordered,$total,%jstext);
$total = 0;
if (ref($settings) eq 'HASH') {
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
$ordered{$num} = $item;
}
}
$total = scalar(keys(%{$settings}));
} else {
%ordered = (
0 => 'proctorio',
1 => 'examity',
);
$total = 2;
}
my @jsarray = ();
foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
push(@jsarray,$ordered{$item});
}
my $jstext = ' var proctors = Array('."'".join("','",@jsarray)."'".');'."\n";
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderProctoring(form,item) {
var changedVal;
$jstext
var maxh = $total;
var current = new Array;
var changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
for (var i=0; i<proctors.length; i++) {
var elementName = 'proctoring_pos_'+proctors[i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
function toggleProctoring(form,item) {
var fieldsets = document.getElementsByClassName('proctoring_'+item);
if (fieldsets.length) {
var radioname = 'proctoring_available_'+item;
var num = form.elements[radioname].length;
if (num) {
var setvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if (form.elements[radioname][i].value == '1') {
setvis = 1;
break;
}
}
}
for (var j=0; j<fieldsets.length; j++) {
if (setvis) {
fieldsets[j].style.display = 'block';
} else {
fieldsets[j].style.display = 'none';
}
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub lti_javascript {
my ($dom,$settings) = @_;
my $togglejs = <i_toggle_js($dom);
my $linkprot_js = &Apache::courseprefs::linkprot_javascript();
unless (ref($settings) eq 'HASH') {
return $togglejs.'
<script type="text/javascript">
// <![CDATA[
'.$linkprot_js.'
// ]]>
</script>
';
}
my (%ordered,$total,%jstext);
$total = scalar(keys(%{$settings}));
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
if ($num eq '') {
$num = $total - 1;
}
$ordered{$num} = $item;
}
}
my @jsarray = ();
foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
push(@jsarray,$ordered{$item});
}
my $jstext = ' var lti = Array('."'".join("','",@jsarray)."'".');'."\n";
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderLTI(form,item) {
var changedVal;
$jstext
var newpos = 'lti_pos_add';
var maxh = 1 + $total;
var current = new Array;
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
if (item == newpos) {
changedVal = newitemVal;
} else {
changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
current[newitemVal] = newpos;
}
for (var i=0; i<lti.length; i++) {
var elementName = 'lti_pos_'+lti[i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
$linkprot_js
// ]]>
</script>
$togglejs
ENDSCRIPT
}
sub lti_toggle_js {
my ($dom) = @_;
my %lcauthparmtext = &Apache::lonlocal::texthash (
localauth => 'Local auth argument',
krb => 'Kerberos domain',
);
my $crsincalert = &mt('"User\'s identity sent" needs to be set to "Yes" first,[_1] before setting "Course\'s identity sent" to "Yes"',"\n");
&js_escape(\$crsincalert);
my %servers = &Apache::lonnet::get_servers($dom,'library');
my $primary = &Apache::lonnet::domain($dom,'primary');
my $course_servers = "'".join("','",keys(%servers))."'";
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleLTI(form,setting,item) {
if ((setting == 'requser') || (setting == 'crsinc')) {
var usrfieldsets = document.getElementsByClassName('ltioption_usr_'+item);
var setvis = '';
var radioname = 'lti_requser_'+item;
var num = form.elements[radioname].length;
if (num) {
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if (form.elements[radioname][i].value == '1') {
setvis = 1;
break;
}
}
}
}
if (usrfieldsets.length) {
for (var j=0; j<usrfieldsets.length; j++) {
if (setvis) {
usrfieldsets[j].style.display = 'block';
} else {
usrfieldsets[j].style.display = 'none';
}
}
}
var crsfieldsets = document.getElementsByClassName('ltioption_crs_'+item);
if (crsfieldsets.length) {
radioname = 'lti_crsinc_'+item;
var num = form.elements[radioname].length;
if (num) {
var crsvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if (form.elements[radioname][i].value == '1') {
if (setvis == '') {
if (setting == 'crsinc'){
alert("$crsincalert");
form.elements[radioname][0].checked = true;
}
} else {
crsvis = 1;
}
break;
}
}
}
setvis = crsvis;
}
for (var j=0; j<crsfieldsets.length; j++) {
if (setvis) {
crsfieldsets[j].style.display = 'block';
} else {
crsfieldsets[j].style.display = 'none';
}
}
}
} else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) {
var radioname = '';
var divid = '';
if (setting == 'user') {
radioname = 'lti_mapuser_'+item;
divid = 'lti_userfield_'+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;
}
var num = form.elements[radioname].length;
if (num) {
var setvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if ((setting == 'passback') || (setting == 'callback')) {
if (form.elements[radioname][i].value == '1') {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'inline-block';
}
setvis = 1;
break;
}
} else {
if (form.elements[radioname][i].value == 'other') {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'inline-block';
}
setvis = 1;
break;
}
}
}
}
if (!setvis) {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'none';
}
}
}
} else if ((setting == 'sec') || (setting == 'secsrc')) {
var numsec = form.elements['lti_crssec_'+item].length;
if (numsec) {
var setvis = '';
for (var i=0; i<numsec; i++) {
if (form.elements['lti_crssec_'+item][i].checked) {
if (form.elements['lti_crssec_'+item][i].value == '1') {
if (document.getElementById('lti_crssecfield_'+item)) {
document.getElementById('lti_crssecfield_'+item).style.display = 'inline-block';
setvis = 1;
var numsrcsec = form.elements['lti_crssecsrc_'+item].length;
if (numsrcsec) {
var setsrcvis = '';
for (var j=0; j<numsrcsec; j++) {
if (form.elements['lti_crssecsrc_'+item][j].checked) {
if (form.elements['lti_crssecsrc_'+item][j].value == 'other') {
if (document.getElementById('lti_secsrcfield_'+item)) {
document.getElementById('lti_secsrcfield_'+item).style.display = 'inline-block';
setsrcvis = 1;
}
}
}
}
if (!setsrcvis) {
if (document.getElementById('lti_secsrcfield_'+item)) {
document.getElementById('lti_secsrcfield_'+item).style.display = 'none';
}
}
}
}
}
}
}
if (!setvis) {
if (document.getElementById('lti_crssecfield_'+item)) {
document.getElementById('lti_crssecfield_'+item).style.display = 'none';
}
if (document.getElementById('lti_secsrcfield_'+item)) {
document.getElementById('lti_secsrcfield_'+item).style.display = 'none';
}
}
}
} else if (setting == 'lcauth') {
var numauth = form.elements['lti_lcauth_'+item].length;
if (numauth) {
for (var i=0; i<numauth; i++) {
if (form.elements['lti_lcauth_'+item][i].checked) {
if (document.getElementById('lti_'+setting+'_parmrow_'+item)) {
if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) {
document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none';
} else {
document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row';
if (document.getElementById('lti_'+setting+'_parmtext_'+item)) {
if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') {
document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}";
} else {
document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}";
}
}
}
}
}
}
}
} else if (setting == 'lcmenu') {
var menus = new Array('lti_topmenu_'+item,'lti_inlinemenu_'+item);
var divid = 'lti_menufield_'+item;
var setvis = '';
for (var i=0; i<menus.length; i++) {
var radioname = menus[i];
var num = form.elements[radioname].length;
if (num) {
for (var j=0; j<num; j++) {
if (form.elements[radioname][j].checked) {
if (form.elements[radioname][j].value == '1') {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'inline-block';
}
setvis = 1;
break;
}
}
}
}
if (setvis == 1) {
break;
}
}
if (!setvis) {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'none';
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub autoupdate_javascript {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleLastActiveDays(form) {
var radioname = 'lastactive';
var divid = 'lastactive_div';
var num = form.elements[radioname].length;
if (num) {
var setvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if (form.elements[radioname][i].value == '1') {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'inline-block';
}
setvis = 1;
}
break;
}
}
if (!setvis) {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'none';
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub autoenroll_javascript {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleFailsafe(form) {
var radioname = 'autoenroll_failsafe';
var divid = 'autoenroll_failsafe_div';
var num = form.elements[radioname].length;
if (num) {
var setvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if ((form.elements[radioname][i].value == 'zero') || (form.elements[radioname][i].value == 'any')) {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'inline-block';
}
setvis = 1;
}
break;
}
}
if (!setvis) {
if (document.getElementById(divid)) {
document.getElementById(divid).style.display = 'none';
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub saml_javascript {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleSamlOptions(form,hostid) {
var radioname = 'saml_'+hostid;
var tablecellon = 'samloptionson_'+hostid;
var tablecelloff = 'samloptionsoff_'+hostid;
var num = form.elements[radioname].length;
if (num) {
var setvis = '';
for (var i=0; i<num; i++) {
if (form.elements[radioname][i].checked) {
if (form.elements[radioname][i].value == '1') {
if (document.getElementById(tablecellon)) {
document.getElementById(tablecellon).style.display='';
}
if (document.getElementById(tablecelloff)) {
document.getElementById(tablecelloff).style.display='none';
}
setvis = 1;
}
break;
}
}
if (!setvis) {
if (document.getElementById(tablecellon)) {
document.getElementById(tablecellon).style.display='none';
}
if (document.getElementById(tablecelloff)) {
document.getElementById(tablecelloff).style.display='';
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub ipaccess_javascript {
my ($settings) = @_;
my (%ordered,$total,%jstext);
$total = 0;
if (ref($settings) eq 'HASH') {
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
$ordered{$num} = $item;
}
}
$total = scalar(keys(%{$settings}));
}
my @jsarray = ();
foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
push(@jsarray,$ordered{$item});
}
my $jstext = ' var ipaccess = Array('."'".join("','",@jsarray)."'".');'."\n";
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderIPaccess(form,item) {
var changedVal;
$jstext
var newpos = 'ipaccess_pos_add';
var maxh = 1 + $total;
var current = new Array;
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
if (item == newpos) {
changedVal = newitemVal;
} else {
changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
current[newitemVal] = newpos;
}
for (var i=0; i<ipaccess.length; i++) {
var elementName = 'ipaccess_pos_'+ipaccess[i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub authordefaults_javascript {
my %alert = &Apache::lonlocal::texthash (
reqd => 'Warning: at least one editor needs to be available.',
rest => 'Unchecking this editor disallowed while others unchecked.',
);
&js_escape(\%alert);
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function checkEditors(form,checkbox,current) {
if (form.elements[checkbox].length != undefined) {
var count = 0;
for (var i=0; i<form.elements[checkbox].length; i++) {
if (form.elements[checkbox][i].checked) {
count ++;
}
}
if (count == 0) {
if (current.type =='radio') {
current.checked = true;
alert('$alert{reqd}\\n$alert{rest}');
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub print_autoenroll {
my ($dom,$settings,$rowtotal) = @_;
my $autorun = &Apache::lonnet::auto_run(undef,$dom),
my ($defdom,$runon,$runoff,$coownerson,$coownersoff,
$failsafe,$autofailsafe,$failsafesty,%failsafechecked);
$failsafesty = 'none';
%failsafechecked = (
off => ' checked="checked"',
);
if (ref($settings) eq 'HASH') {
if (exists($settings->{'run'})) {
if ($settings->{'run'} eq '0') {
$runoff = ' checked="checked" ';
$runon = ' ';
} else {
$runon = ' checked="checked" ';
$runoff = ' ';
}
} else {
if ($autorun) {
$runon = ' checked="checked" ';
$runoff = ' ';
} else {
$runoff = ' checked="checked" ';
$runon = ' ';
}
}
if (exists($settings->{'co-owners'})) {
if ($settings->{'co-owners'} eq '0') {
$coownersoff = ' checked="checked" ';
$coownerson = ' ';
} else {
$coownerson = ' checked="checked" ';
$coownersoff = ' ';
}
} else {
$coownersoff = ' checked="checked" ';
$coownerson = ' ';
}
if (exists($settings->{'sender_domain'})) {
$defdom = $settings->{'sender_domain'};
}
if (exists($settings->{'failsafe'})) {
$failsafe = $settings->{'failsafe'};
if ($failsafe eq 'zero') {
$failsafechecked{'zero'} = ' checked="checked"';
$failsafechecked{'off'} = '';
$failsafesty = 'inline-block';
} elsif ($failsafe eq 'any') {
$failsafechecked{'any'} = ' checked="checked"';
$failsafechecked{'off'} = '';
}
$autofailsafe = $settings->{'autofailsafe'};
} elsif (exists($settings->{'autofailsafe'})) {
$autofailsafe = $settings->{'autofailsafe'};
if ($autofailsafe ne '') {
$failsafechecked{'zero'} = ' checked="checked"';
$failsafe = 'zero';
$failsafechecked{'off'} = '';
}
}
} else {
if ($autorun) {
$runon = ' checked="checked" ';
$runoff = ' ';
} else {
$runoff = ' checked="checked" ';
$runon = ' ';
}
}
my $domform = &Apache::loncommon::select_dom_form($defdom,'sender_domain',1);
my $notif_sender;
if (ref($settings) eq 'HASH') {
$notif_sender = $settings->{'sender_uname'};
}
my $datatable='<tr class="LC_odd_row">'.
'<td>'.&mt('Auto-enrollment active?').'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="autoenroll_run"'.
$runon.' value="1" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="autoenroll_run"'.
$runoff.' value="0" />'.&mt('No').'</label></span></td>'.
'</tr><tr>'.
'<td>'.&mt('Notification messages - sender').
'</td><td class="LC_right_item"><span class="LC_nobreak">'.
&mt('username').': '.
'<input type="text" name="sender_uname" value="'.
$notif_sender.'" size="10" /> '.&mt('domain').
': '.$domform.'</span></td></tr>'.
'<tr class="LC_odd_row">'.
'<td>'.&mt('Automatically assign co-ownership').'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="autoassign_coowners"'.
$coownerson.' value="1" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="autoassign_coowners"'.
$coownersoff.' value="0" />'.&mt('No').'</label></span></td>'.
'</tr><tr>'.
'<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
'<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="off" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'off'}.' />'.&mt('Not in use').'</label></span> '.
'<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="zero" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'zero'}.' />'.&mt('Retrieved section enrollment is zero').'</label></span><br />'.
'<span class="LC_nobreak"><label><input type="radio" name="autoenroll_failsafe" value="any" onclick="toggleFailsafe(this.form)"'.$failsafechecked{'any'}.' />'.&mt('Retrieved section enrollment is zero or greater').'</label></span>'.
'<div class="LC_floatleft" style="display:'.$failsafesty.';" id="autoenroll_failsafe_div">'.
'<span class="LC_nobreak">'.
&mt('Threshold for number of students in section to drop: [_1]',
'<input type="text" name="autoenroll_autofailsafe" value="'.$autofailsafe.'" size="4" />').
'</span></div></td></tr>';
$$rowtotal += 4;
return $datatable;
}
sub print_autoupdate {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($enable,$datatable);
if ($position eq 'top') {
my %choices = &Apache::lonlocal::texthash (
run => 'Auto-update active?',
classlists => 'Update information in classlists?',
unexpired => 'Skip updates for users without active or future roles?',
lastactive => 'Skip updates for inactive users?',
);
my $itemcount = 0;
my $updateon = ' ';
my $updateoff = ' checked="checked" ';
if (ref($settings) eq 'HASH') {
if ($settings->{'run'} eq '1') {
$updateon = $updateoff;
$updateoff = ' ';
}
}
$enable = '<tr class="LC_odd_row">'.
'<td>'.$choices{'run'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="autoupdate_run"'.
$updateoff.'value="0" />'.&mt('No').'</label> '.
'<label><input type="radio" name="autoupdate_run"'.
$updateon.'value="1" />'.&mt('Yes').'</label></span></td>'.
'</tr>';
my @toggles = ('classlists','unexpired');
my %defaultchecked = ('classlists' => 'off',
'unexpired' => 'off'
);
$$rowtotal ++;
($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
\%choices,$itemcount,'','','left','no');
$datatable = $enable.$datatable;
$$rowtotal += $itemcount;
my $lastactiveon = ' ';
my $lastactiveoff = ' checked="checked" ';
my $lastactivestyle = 'none';
my $lastactivedays;
my $onclick = ' onclick="javascript:toggleLastActiveDays(this.form);"';
if (ref($settings) eq 'HASH') {
if ($settings->{'lastactive'} =~ /^\d+$/) {
$lastactiveon = $lastactiveoff;
$lastactiveoff = ' ';
$lastactivestyle = 'inline-block';
$lastactivedays = $settings->{'lastactive'};
}
}
my $css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$choices{'lastactive'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="lastactive"'.
$lastactiveoff.'value="0"'.$onclick.' />'.&mt('No').'</label>'.
' <label>'.
'<input type="radio" name="lastactive"'.
$lastactiveon.' value="1"'.$onclick.' />'.&mt('Yes').'</label>'.
'<div id="lastactive_div" style="display:'.$lastactivestyle.';">'.
': '.&mt('inactive = no activity in last [_1] days',
'<input type="text" size="5" name="lastactivedays" value="'.
$lastactivedays.'" />').
'</span></td>'.
'</tr>';
$$rowtotal ++;
} elsif ($position eq 'middle') {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my $numinrow = 3;
my $locknamesettings;
$datatable .= &insttypes_row($settings,$types,$usertypes,
$dom,$numinrow,$othertitle,
'lockablenames',$rowtotal);
$$rowtotal ++;
} else {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my @fields = ('lastname','firstname','middlename','generation',
'permanentemail','id');
my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
my $numrows = 0;
if (ref($types) eq 'ARRAY') {
if (@{$types} > 0) {
$datatable =
&usertype_update_row($settings,$usertypes,\%fieldtitles,
\@fields,$types,\$numrows);
$$rowtotal += @{$types};
}
}
$datatable .=
&usertype_update_row($settings,{'default' => $othertitle},
\%fieldtitles,\@fields,['default'],
\$numrows);
$$rowtotal ++;
}
return $datatable;
}
sub print_autocreate {
my ($dom,$settings,$rowtotal) = @_;
my (%createon,%createoff,%currhash);
my @types = ('xml','req');
if (ref($settings) eq 'HASH') {
foreach my $item (@types) {
$createoff{$item} = ' checked="checked" ';
$createon{$item} = ' ';
if (exists($settings->{$item})) {
if ($settings->{$item}) {
$createon{$item} = ' checked="checked" ';
$createoff{$item} = ' ';
}
}
}
if ($settings->{'xmldc'} ne '') {
$currhash{$settings->{'xmldc'}} = 1;
}
} else {
foreach my $item (@types) {
$createoff{$item} = ' checked="checked" ';
$createon{$item} = ' ';
}
}
$$rowtotal += 2;
my $numinrow = 2;
my $datatable='<tr class="LC_odd_row">'.
'<td>'.&mt('Create pending official courses from XML files').'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="autocreate_xml"'.
$createon{'xml'}.' value="1" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="autocreate_xml"'.
$createoff{'xml'}.' value="0" />'.&mt('No').'</label></span>'.
'</td></tr><tr>'.
'<td>'.&mt('Create pending requests for official courses (if validated)').'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="autocreate_req"'.
$createon{'req'}.' value="1" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="autocreate_req"'.
$createoff{'req'}.' value="0" />'.&mt('No').'</label></span>';
my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio',
'autocreate_xmldc',%currhash);
$datatable .= '</td></tr><tr class="LC_odd_row"><td>';
if ($numdc > 1) {
$datatable .= &mt('Course creation processed as: (choose Dom. Coord.)').
'</td><td class="LC_left_item">';
} else {
$datatable .= &mt('Course creation processed as:').
'</td><td class="LC_right_item">';
}
$datatable .= $dctable.'</td></tr>';
$$rowtotal += $rows;
return $datatable;
}
sub print_directorysrch {
my ($position,$dom,$settings,$rowtotal) = @_;
my $datatable;
if ($position eq 'top') {
my $instsrchon = ' ';
my $instsrchoff = ' checked="checked" ';
my ($exacton,$containson,$beginson);
my $instlocalon = ' ';
my $instlocaloff = ' checked="checked" ';
if (ref($settings) eq 'HASH') {
if ($settings->{'available'} eq '1') {
$instsrchon = $instsrchoff;
$instsrchoff = ' ';
}
if ($settings->{'localonly'} eq '1') {
$instlocalon = $instlocaloff;
$instlocaloff = ' ';
}
if (ref($settings->{'searchtypes'}) eq 'ARRAY') {
foreach my $type (@{$settings->{'searchtypes'}}) {
if ($type eq 'exact') {
$exacton = ' checked="checked" ';
} elsif ($type eq 'contains') {
$containson = ' checked="checked" ';
} elsif ($type eq 'begins') {
$beginson = ' checked="checked" ';
}
}
} else {
if ($settings->{'searchtypes'} eq 'exact') {
$exacton = ' checked="checked" ';
} elsif ($settings->{'searchtypes'} eq 'contains') {
$containson = ' checked="checked" ';
} elsif ($settings->{'searchtypes'} eq 'specify') {
$exacton = ' checked="checked" ';
$containson = ' checked="checked" ';
}
}
}
my ($searchtitles,$titleorder) = &sorted_searchtitles();
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my $numinrow = 4;
my $cansrchrow = 0;
$datatable='<tr class="LC_odd_row">'.
'<td colspan="2"><span class ="LC_nobreak">'.&mt('Institutional directory search available?').'</span></td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="dirsrch_available"'.
$instsrchon.' value="1" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="dirsrch_available"'.
$instsrchoff.' value="0" />'.&mt('No').'</label></span></td>'.
'</tr><tr>'.
'<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search institution?').'</span></td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="dirsrch_instlocalonly"'.
$instlocaloff.' value="0" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="dirsrch_instlocalonly"'.
$instlocalon.' value="1" />'.&mt('No').'</label></span></td>'.
'</tr>';
$$rowtotal += 2;
if (ref($usertypes) eq 'HASH') {
if (keys(%{$usertypes}) > 0) {
$datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
$numinrow,$othertitle,'cansearch',
$rowtotal);
$cansrchrow = 1;
}
}
if ($cansrchrow) {
$$rowtotal ++;
$datatable .= '<tr>';
} else {
$datatable .= '<tr class="LC_odd_row">';
}
$datatable .= '<td><span class ="LC_nobreak">'.&mt('Supported search methods').
'</span></td><td class="LC_left_item" colspan="2"><table><tr>';
foreach my $title (@{$titleorder}) {
if (defined($searchtitles->{$title})) {
my $check = ' ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{'searchby'}) eq 'ARRAY') {
if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) {
$check = ' checked="checked" ';
}
}
}
$datatable .= '<td class="LC_left_item">'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="searchby" '.
'value="'.$title.'"'.$check.'/>'.
$searchtitles->{$title}.'</label></span></td>';
}
}
$datatable .= '</tr></table></td></tr>';
$$rowtotal ++;
if ($cansrchrow) {
$datatable .= '<tr class="LC_odd_row">';
} else {
$datatable .= '<tr>';
}
$datatable .= '<td><span class ="LC_nobreak">'.&mt('Search latitude').'</span></td>'.
'<td class="LC_left_item" colspan="2">'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="searchtypes" '.
$exacton.' value="exact" />'.&mt('Exact match').
'</label> '.
'<label><input type="checkbox" name="searchtypes" '.
$beginson.' value="begins" />'.&mt('Begins with').
'</label> '.
'<label><input type="checkbox" name="searchtypes" '.
$containson.' value="contains" />'.&mt('Contains').
'</label></span></td></tr>';
$$rowtotal ++;
} else {
my $domsrchon = ' checked="checked" ';
my $domsrchoff = ' ';
my $domlocalon = ' ';
my $domlocaloff = ' checked="checked" ';
if (ref($settings) eq 'HASH') {
if ($settings->{'lclocalonly'} eq '1') {
$domlocalon = $domlocaloff;
$domlocaloff = ' ';
}
if ($settings->{'lcavailable'} eq '0') {
$domsrchoff = $domsrchon;
$domsrchon = ' ';
}
}
$datatable='<tr class="LC_odd_row">'.
'<td colspan="2"><span class ="LC_nobreak">'.&mt('LON-CAPA directory search available?').'</span></td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="dirsrch_domavailable"'.
$domsrchon.' value="1" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="dirsrch_domavailable"'.
$domsrchoff.' value="0" />'.&mt('No').'</label></span></td>'.
'</tr><tr>'.
'<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search LON-CAPA domain?').'</span></td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="dirsrch_domlocalonly"'.
$domlocaloff.' value="0" />'.&mt('Yes').'</label> '.
'<label><input type="radio" name="dirsrch_domlocalonly"'.
$domlocalon.' value="1" />'.&mt('No').'</label></span></td>'.
'</tr>';
$$rowtotal += 2;
}
return $datatable;
}
sub print_contacts {
my ($position,$dom,$settings,$rowtotal) = @_;
my $datatable;
my @contacts = ('adminemail','supportemail');
my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield,
$maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus);
if ($position eq 'top') {
if (ref($settings) eq 'HASH') {
foreach my $item (@contacts) {
if (exists($settings->{$item})) {
$to{$item} = $settings->{$item};
}
}
}
} elsif ($position eq 'middle') {
@mailings = ('errormail','packagesmail','lonstatusmail','requestsmail',
'updatesmail','idconflictsmail','hostipmail');
foreach my $type (@mailings) {
$otheremails{$type} = '';
}
} elsif ($position eq 'lower') {
if (ref($settings) eq 'HASH') {
if (ref($settings->{'lonstatus'}) eq 'HASH') {
%lonstatus = %{$settings->{'lonstatus'}};
}
}
} else {
@mailings = ('helpdeskmail','otherdomsmail');
foreach my $type (@mailings) {
$otheremails{$type} = '';
}
$bccemails{'helpdeskmail'} = '';
$bccemails{'otherdomsmail'} = '';
$includestr{'helpdeskmail'} = '';
$includestr{'otherdomsmail'} = '';
($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
}
if (ref($settings) eq 'HASH') {
unless (($position eq 'top') || ($position eq 'lower')) {
foreach my $type (@mailings) {
if (exists($settings->{$type})) {
if (ref($settings->{$type}) eq 'HASH') {
foreach my $item (@contacts) {
if ($settings->{$type}{$item}) {
$checked{$type}{$item} = ' checked="checked" ';
}
}
$otheremails{$type} = $settings->{$type}{'others'};
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
$bccemails{$type} = $settings->{$type}{'bcc'};
if ($settings->{$type}{'include'} ne '') {
($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2);
$includestr{$type} = &unescape($includestr{$type});
}
}
}
} elsif ($type eq 'lonstatusmail') {
$checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';
}
}
}
if ($position eq 'bottom') {
foreach my $type (@mailings) {
$bccemails{$type} = $settings->{$type}{'bcc'};
if ($settings->{$type}{'include'} ne '') {
($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2);
$includestr{$type} = &unescape($includestr{$type});
}
}
if (ref($settings->{'helpform'}) eq 'HASH') {
if (ref($fields) eq 'ARRAY') {
foreach my $field (@{$fields}) {
$currfield{$field} = $settings->{'helpform'}{$field};
}
}
if (exists($settings->{'helpform'}{'maxsize'})) {
$maxsize = $settings->{'helpform'}{'maxsize'};
} else {
$maxsize = '1.0';
}
} else {
if (ref($fields) eq 'ARRAY') {
foreach my $field (@{$fields}) {
$currfield{$field} = 'yes';
}
}
$maxsize = '1.0';
}
}
} else {
if ($position eq 'top') {
$to{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'};
$to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'};
$checked{'errormail'}{'adminemail'} = ' checked="checked" ';
$checked{'packagesmail'}{'adminemail'} = ' checked="checked" ';
$checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" ';
$checked{'requestsmail'}{'adminemail'} = ' checked="checked" ';
$checked{'updatesmail'}{'adminemail'} = ' checked="checked" ';
$checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" ';
$checked{'hostipmail'}{'adminemail'} = ' checked="checked" ';
} elsif ($position eq 'bottom') {
$checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" ';
$checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" ';
if (ref($fields) eq 'ARRAY') {
foreach my $field (@{$fields}) {
$currfield{$field} = 'yes';
}
}
$maxsize = '1.0';
}
}
my ($titles,$short_titles) = &contact_titles();
my $rownum = 0;
my $css_class;
if ($position eq 'top') {
foreach my $item (@contacts) {
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.$titles->{$item}.
'</span></td><td class="LC_right_item">'.
'<input type="text" name="'.$item.'" value="'.
$to{$item}.'" /></td></tr>';
$rownum ++;
}
} elsif ($position eq 'bottom') {
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.&mt('Extra helpdesk form fields:').'<br />'.
&mt('(e-mail, subject, and description always shown)').
'</td><td class="LC_left_item">';
if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') &&
(ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) {
$datatable .= '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Status').'</th></tr>';
foreach my $field (@{$fields}) {
$datatable .= '<tr><td>'.$fieldtitles->{$field};
if (($field eq 'screenshot') || ($field eq 'cc')) {
$datatable .= ' '.&mt('(logged-in users)');
}
$datatable .='</td><td>';
my $clickaction;
if ($field eq 'screenshot') {
$clickaction = ' onclick="screenshotSize(this);"';
}
if (ref($possoptions->{$field}) eq 'ARRAY') {
foreach my $option (@{$possoptions->{$field}}) {
my $checked;
if ($currfield{$field} eq $option) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="helpform_'.$field.'" '.
'value="'.$option.'"'.$checked.$clickaction.' />'.$fieldoptions->{$option}.
'</label></span>'.(' 'x2);
}
}
if ($field eq 'screenshot') {
my $display;
if ($currfield{$field} eq 'no') {
$display = ' style="display:none"';
}
$datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.'>'.
'<td>'.&mt('Maximum size for upload (MB)').'</td><td>'.
'<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />';
}
$datatable .= '</td></tr>';
}
$datatable .= '</table>';
}
$datatable .= '</td></tr>'."\n";
$rownum ++;
}
unless (($position eq 'top') || ($position eq 'lower')) {
foreach my $type (@mailings) {
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.
$titles->{$type}.': </span></td>'.
'<td class="LC_left_item">';
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
$datatable .= '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>';
}
$datatable .= '<span class="LC_nobreak">';
foreach my $item (@contacts) {
$datatable .= '<label>'.
'<input type="checkbox" name="'.$type.'"'.
$checked{$type}{$item}.
' value="'.$item.'" />'.$short_titles->{$item}.
'</label> ';
}
$datatable .= '</span><br />'.&mt('Others').': '.
'<input type="text" name="'.$type.'_others" '.
'value="'.$otheremails{$type}.'" />';
my %locchecked;
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
foreach my $loc ('s','b') {
if ($includeloc{$type} eq $loc) {
$locchecked{$loc} = ' checked="checked"';
last;
}
}
$datatable .= '<br />'.&mt('Bcc:').(' 'x6).
'<input type="text" name="'.$type.'_bcc" '.
'value="'.$bccemails{$type}.'" /></fieldset>'.
'<fieldset><legend>'.&mt('Optional added text').'</legend>'.
&mt('Text automatically added to e-mail:').' '.
'<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br />'.
'<span class="LC_nobreak">'.&mt('Location:').' '.
'<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.
(' 'x2).
'<label><input type="radio" name="'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'.
'</span></fieldset>';
}
$datatable .= '</td></tr>'."\n";
$rownum ++;
}
}
if ($position eq 'middle') {
my %choices;
my $corelink = &core_link_msu();
$choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink);
$choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]',
$corelink);
$choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink);
my @toggles = ('reporterrors','reportupdates','reportstatus');
my %defaultchecked = ('reporterrors' => 'on',
'reportupdates' => 'on',
'reportstatus' => 'on');
(my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
\%choices,$rownum);
$datatable .= $reports;
} elsif ($position eq 'lower') {
my (%current,%excluded,%weights);
my ($defaults,$names) = &Apache::loncommon::lon_status_items();
if ($lonstatus{'threshold'} =~ /^\d+$/) {
$current{'errorthreshold'} = $lonstatus{'threshold'};
} else {
$current{'errorthreshold'} = $defaults->{'threshold'};
}
if ($lonstatus{'sysmail'} =~ /^\d+$/) {
$current{'errorsysmail'} = $lonstatus{'sysmail'};
} else {
$current{'errorsysmail'} = $defaults->{'sysmail'};
}
if (ref($lonstatus{'weights'}) eq 'HASH') {
foreach my $type ('E','W','N','U') {
if ($lonstatus{'weights'}{$type} =~ /^\d+$/) {
$weights{$type} = $lonstatus{'weights'}{$type};
} else {
$weights{$type} = $defaults->{$type};
}
}
} else {
foreach my $type ('E','W','N','U') {
$weights{$type} = $defaults->{$type};
}
}
if (ref($lonstatus{'excluded'}) eq 'ARRAY') {
if (@{$lonstatus{'excluded'}} > 0) {
map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}};
}
}
foreach my $item ('errorthreshold','errorsysmail') {
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
$titles->{$item}.
'</span></td><td class="LC_left_item">'.
'<input type="text" name="'.$item.'" value="'.
$current{$item}.'" size="5" /></td></tr>';
$rownum ++;
}
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.
'<span class="LC_nobreak">'.$titles->{'errorweights'}.
'</span></td><td class="LC_left_item"><table><tr>';
foreach my $type ('E','W','N','U') {
$datatable .= '<td>'.$names->{$type}.'<br />'.
'<input type="text" name="errorweights_'.$type.'" value="'.
$weights{$type}.'" size="5" /></td>';
}
$datatable .= '</tr></table></tr>';
$rownum ++;
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td class="LC_left_item">'.
$titles->{'errorexcluded'}.'</td>'.
'<td class="LC_left_item"><table>';
my $numinrow = 4;
my @ids = sort(values(%Apache::lonnet::serverhomeIDs));
for (my $i=0; $i<@ids; $i++) {
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
my $check;
if ($excluded{$ids[$i]}) {
$check = ' checked="checked" ';
}
$datatable .= '<td class="LC_left_item">'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="errorexcluded" '.
'value="'.$ids[$i].'"'.$check.' />'.
$ids[$i].'</label></span></td>';
}
my $colsleft = $numinrow - @ids%($numinrow);
if ($colsleft > 1 ) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$datatable .= '<td class="LC_left_item"> </td>';
}
$datatable .= '</tr></table></td></tr>';
$rownum ++;
} elsif ($position eq 'bottom') {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my (@posstypes,%usertypeshash);
if (ref($types) eq 'ARRAY') {
@posstypes = @{$types};
}
if (@posstypes) {
if (ref($usertypes) eq 'HASH') {
%usertypeshash = %{$usertypes};
}
my @overridden;
my $numinrow = 4;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'overrides'}) eq 'HASH') {
foreach my $key (sort(keys(%{$settings->{'overrides'}}))) {
if (ref($settings->{'overrides'}{$key}) eq 'HASH') {
push(@overridden,$key);
foreach my $item (@contacts) {
if ($settings->{'overrides'}{$key}{$item}) {
$checked{'override_'.$key}{$item} = ' checked="checked" ';
}
}
$otheremails{'override_'.$key} = $settings->{'overrides'}{$key}{'others'};
$bccemails{'override_'.$key} = $settings->{'overrides'}{$key}{'bcc'};
$includeloc{'override_'.$key} = '';
$includestr{'override_'.$key} = '';
if ($settings->{'overrides'}{$key}{'include'} ne '') {
($includeloc{'override_'.$key},$includestr{'override_'.$key}) =
split(/:/,$settings->{'overrides'}{$key}{'include'},2);
$includestr{'override_'.$key} = &unescape($includestr{'override_'.$key});
}
}
}
}
}
my $customclass = 'LC_helpdesk_override';
my $optionsprefix = 'LC_options_helpdesk_';
my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');";
$datatable .= &insttypes_row($settings,$types,$usertypes,$dom,
$numinrow,$othertitle,'overrides',
\$rownum,$onclicktypes,$customclass);
$rownum ++;
$usertypeshash{'default'} = $othertitle;
foreach my $status (@posstypes) {
my $css_class;
if ($rownum%2) {
$css_class = 'LC_odd_row ';
}
$css_class .= $customclass;
my $rowid = $optionsprefix.$status;
my $hidden = 1;
my $currstyle = 'display:none';
if (grep(/^\Q$status\E$/,@overridden)) {
$currstyle = 'display:table-row';
$hidden = 0;
}
my $key = 'override_'.$status;
$datatable .= &overridden_helpdesk($checked{$key},$otheremails{$key},$bccemails{$key},
$includeloc{$key},$includestr{$key},$status,$rowid,
$usertypeshash{$status},$css_class,$currstyle,
\@contacts,$short_titles);
unless ($hidden) {
$rownum ++;
}
}
}
}
$$rowtotal += $rownum;
return $datatable;
}
sub core_link_msu {
return &Apache::loncommon::modal_link('http://loncapa.org/core.html',
&mt('LON-CAPA core group - MSU'),600,500);
}
sub overridden_helpdesk {
my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid,
$typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_;
my $class = 'LC_left_item';
if ($css_class) {
$css_class = ' class="'.$css_class.'"';
}
if ($rowid) {
$rowid = ' id="'.$rowid.'"';
}
if ($rowstyle) {
$rowstyle = ' style="'.$rowstyle.'"';
}
my ($output,$description);
$description = &mt('Helpdesk requests from: [_1] in this domain (overrides default)',"<b>$typetitle</b>");
$output = '<tr'.$css_class.$rowid.$rowstyle.'>'.
"<td>$description</td>\n".
'<td class="'.$class.'" colspan="2">'.
'<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>'.
'<span class="LC_nobreak">';
if (ref($contacts) eq 'ARRAY') {
foreach my $item (@{$contacts}) {
my $check;
if (ref($checked) eq 'HASH') {
$check = $checked->{$item};
}
my $title;
if (ref($short_titles) eq 'HASH') {
$title = $short_titles->{$item};
}
$output .= '<label>'.
'<input type="checkbox" name="override_'.$type.'"'.$check.
' value="'.$item.'" />'.$title.'</label> ';
}
}
$output .= '</span><br />'.&mt('Others').': '.
'<input type="text" name="override_'.$type.'_others" '.
'value="'.$otheremails.'" />';
my %locchecked;
foreach my $loc ('s','b') {
if ($includeloc eq $loc) {
$locchecked{$loc} = ' checked="checked"';
last;
}
}
$output .= '<br />'.&mt('Bcc:').(' 'x6).
'<input type="text" name="override_'.$type.'_bcc" '.
'value="'.$bccemails.'" /></fieldset>'.
'<fieldset><legend>'.&mt('Optional added text').'</legend>'.
&mt('Text automatically added to e-mail:').' '.
'<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br />'.
'<span class="LC_nobreak">'.&mt('Location:').' '.
'<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'.
(' 'x2).
'<label><input type="radio" name="override_'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'.
'</span></fieldset>'.
'</td></tr>'."\n";
return $output;
}
sub contacts_javascript {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function screenshotSize(field) {
if (document.getElementById('help_screenshotsize')) {
if (field.value == 'no') {
document.getElementById('help_screenshotsize').style.display="none";
} else {
document.getElementById('help_screenshotsize').style.display="";
}
}
return;
}
function toggleHelpdeskRow(form,checkbox,target,prefix,docount) {
if (form.elements[checkbox].length != undefined) {
var count = 0;
if (docount) {
for (var i=0; i<form.elements[checkbox].length; i++) {
if (form.elements[checkbox][i].checked) {
count ++;
}
}
}
for (var i=0; i<form.elements[checkbox].length; i++) {
var type = form.elements[checkbox][i].value;
if (document.getElementById(prefix+type)) {
if (form.elements[checkbox][i].checked) {
document.getElementById(prefix+type).style.display = 'table-row';
if (count % 2 == 1) {
document.getElementById(prefix+type).className = target+' LC_odd_row';
} else {
document.getElementById(prefix+type).className = target;
}
count ++;
} else {
document.getElementById(prefix+type).style.display = 'none';
}
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub print_helpsettings {
my ($position,$dom,$settings,$rowtotal) = @_;
my $confname = $dom.'-domainconfig';
my $formname = 'display';
my ($datatable,$itemcount);
if ($position eq 'top') {
$itemcount = 1;
my (%choices,%defaultchecked,@toggles);
$choices{'submitbugs'} = &mt('Display link to: [_1]?',
&Apache::loncommon::modal_link('http://bugs.loncapa.org',
&mt('LON-CAPA bug tracker'),600,500));
%defaultchecked = ('submitbugs' => 'on');
@toggles = ('submitbugs');
($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
\%choices,$itemcount);
$$rowtotal ++;
} else {
my $css_class;
my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_');
my (%customroles,%ordered,%current);
if (ref($settings) eq 'HASH') {
if (ref($settings->{'adhoc'}) eq 'HASH') {
%current = %{$settings->{'adhoc'}};
}
}
my $count = 0;
foreach my $key (sort(keys(%existing))) {
if ($key=~/^rolesdef\_(\w+)$/) {
my $rolename = $1;
my (%privs,$order);
($privs{'system'},$privs{'domain'},$privs{'course'}) = split(/\_/,$existing{$key});
$customroles{$rolename} = \%privs;
if (ref($current{$rolename}) eq 'HASH') {
$order = $current{$rolename}{'order'};
}
if ($order eq '') {
$order = $count;
}
$ordered{$order} = $rolename;
$count++;
}
}
my $maxnum = scalar(keys(%ordered));
my @roles_by_num = ();
foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
push(@roles_by_num,$item);
}
my $context = 'domprefs';
my $crstype = 'Course';
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my @accesstypes = ('all','dh','da','none');
my ($numstatustypes,@jsarray);
if (ref($types) eq 'ARRAY') {
if (@{$types} > 0) {
$numstatustypes = scalar(@{$types});
push(@accesstypes,'status');
@jsarray = ('bystatus');
}
}
my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']);
if (keys(%domhelpdesk)) {
push(@accesstypes,('inc','exc'));
push(@jsarray,('notinc','notexc'));
}
my $hiddenstr = join("','",@jsarray);
my $context = 'domprefs';
my $crstype = 'Course';
my $prefix = 'helproles_';
my $add_class = 'LC_hidden';
foreach my $num (@roles_by_num) {
my $role = $ordered{$num};
my ($desc,$access,@statuses);
if (ref($current{$role}) eq 'HASH') {
$desc = $current{$role}{'desc'};
$access = $current{$role}{'access'};
if (ref($current{$role}{'insttypes'}) eq 'ARRAY') {
@statuses = @{$current{$role}{'insttypes'}};
}
}
if ($desc eq '') {
$desc = $role;
}
my $identifier = 'custhelp'.$num;
my %full=();
my %levels= (
course => {},
domain => {},
system => {},
);
my %levelscurrent=(
course => {},
domain => {},
system => {},
);
&Apache::lonuserutils::custom_role_privs($customroles{$role},\%full,\%levels,\%levelscurrent);
my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';
$datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'.
'<select name="helproles_'.$num.'_pos"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $num) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select>'.(' 'x2).
'<input type="hidden" name="helproles_'.$num.'" value="'.$role.'" />'.
'</td>'.
'<td><fieldset><legend>'.&mt('Role name').'</legend>'.
&mt('Name shown to users:').
'<input type="text" name="helproles_'.$num.'_desc" value="'.$desc.'" />'.
'</fieldset>'.
&helpdeskroles_access($dom,$prefix,$num,$add_class,$current{$role},\@accesstypes,
$othertitle,$usertypes,$types,\%domhelpdesk).
'<fieldset>'.
'<legend>'.&mt('Role privileges').&adhocbutton($prefix,$num,'privs','show').'</legend>'.
&Apache::lonuserutils::custom_role_table($crstype,\%full,\%levels,
\%levelscurrent,$identifier,
'LC_hidden',$prefix.$num.'_privs').
'</fieldset></td>';
$itemcount ++;
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $newcust = 'custhelp'.$count;
my (%privs,%levelscurrent);
my %full=();
my %levels= (
course => {},
domain => {},
system => {},
);
&Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';
$datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'.
'<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".
'<select name="helproles_'.$count.'_pos"'.$chgstr.'>';
for (my $k=0; $k<$maxnum+1; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $maxnum) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select> '."\n".
'<input type="checkbox" name="newcusthelp" value="'.$count.'" />'. &mt('Add').
'</label></span></td>'.
'<td><fieldset><legend>'.&mt('Role name').'</legend>'.
'<span class="LC_nobreak">'.
&mt('Internal name:').
'<input type="text" size="10" name="custhelpname'.$count.'" value="" />'.
'</span>'.(' 'x4).
'<span class="LC_nobreak">'.
&mt('Name shown to users:').
'<input type="text" size="20" name="helproles_'.$count.'_desc" value="" />'.
'</span></fieldset>'.
&helpdeskroles_access($dom,$prefix,$count,'',undef,\@accesstypes,$othertitle,
$usertypes,$types,\%domhelpdesk).
'<fieldset><legend>'.&mt('Role privileges').'</legend>'.
&Apache::lonuserutils::custom_role_header($context,$crstype,
\@templateroles,$newcust).
&Apache::lonuserutils::custom_role_table('Course',\%full,\%levels,
\%levelscurrent,$newcust).
'</fieldset>'.
&helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname).
'</td></tr>';
$count ++;
$$rowtotal += $count;
}
return $datatable;
}
sub adhocbutton {
my ($prefix,$num,$field,$visibility) = @_;
my %lt = &Apache::lonlocal::texthash(
show => 'Show details',
hide => 'Hide details',
);
return '<span style="text-decoration:line-through; font-weight: normal;">'.(' 'x10).
'</span>'.(' 'x2).'<input type="button" id="'.$prefix.$num.'_'.$field.'_vis"'.
' value="'.$lt{$visibility}.'" style="height:20px;" '.
'onclick="toggleHelpdeskItem('."'$num','$field'".');" />'.(' 'x2);
}
sub helpsettings_javascript {
my ($roles_by_num,$total,$hiddenstr,$formname) = @_;
return unless(ref($roles_by_num) eq 'ARRAY');
my %html_js_lt = &Apache::lonlocal::texthash(
show => 'Show details',
hide => 'Hide details',
);
&html_escape(\%html_js_lt);
my $jstext = ' var helproles = Array('."'".join("','",@{$roles_by_num})."'".');'."\n";
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderHelpRoles(form,item) {
var changedVal;
$jstext
var newpos = 'helproles_${total}_pos';
var maxh = 1 + $total;
var current = new Array();
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
if (item == newpos) {
changedVal = newitemVal;
} else {
changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
current[newitemVal] = newpos;
}
for (var i=0; i<helproles.length; i++) {
var elementName = 'helproles_'+helproles[i]+'_pos';
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
function helpdeskAccess(num) {
var curraccess = null;
if (document.$formname.elements['helproles_'+num+'_access'].length) {
for (var i=0; i<document.$formname.elements['helproles_'+num+'_access'].length; i++) {
if (document.$formname.elements['helproles_'+num+'_access'][i].checked) {
curraccess = document.$formname.elements['helproles_'+num+'_access'][i].value;
}
}
}
var shown = Array();
var hidden = Array();
if (curraccess == 'none') {
hidden = Array('$hiddenstr');
} else {
if (curraccess == 'status') {
shown = Array('bystatus');
hidden = Array('notinc','notexc');
} else {
if (curraccess == 'exc') {
shown = Array('notexc');
hidden = Array('notinc','bystatus');
}
if (curraccess == 'inc') {
shown = Array('notinc');
hidden = Array('notexc','bystatus');
}
if ((curraccess == 'all') || (curraccess == 'dh') || (curraccess == 'da')) {
hidden = Array('notinc','notexc','bystatus');
}
}
}
if (hidden.length > 0) {
for (var i=0; i<hidden.length; i++) {
if (document.getElementById('helproles_'+num+'_'+hidden[i])) {
document.getElementById('helproles_'+num+'_'+hidden[i]).style.display = 'none';
}
}
}
if (shown.length > 0) {
for (var i=0; i<shown.length; i++) {
if (document.getElementById('helproles_'+num+'_'+shown[i])) {
if (shown[i] == 'privs') {
document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'block';
} else {
document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'inline-block';
}
}
}
}
return;
}
function toggleHelpdeskItem(num,field) {
if (document.getElementById('helproles_'+num+'_'+field)) {
if (document.getElementById('helproles_'+num+'_'+field).className.match(/(?:^|\\s)LC_hidden(?!\\S)/)) {
document.getElementById('helproles_'+num+'_'+field).className =
document.getElementById('helproles_'+num+'_'+field).className.replace(/(?:^|\\s)LC_hidden(?!\\S)/g ,'');
if (document.getElementById('helproles_'+num+'_'+field+'_vis')) {
document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{hide}';
}
} else {
document.getElementById('helproles_'+num+'_'+field).className += ' LC_hidden';
if (document.getElementById('helproles_'+num+'_'+field+'_vis')) {
document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{show}';
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub helpdeskroles_access {
my ($dom,$prefix,$num,$add_class,$current,$accesstypes,$othertitle,
$usertypes,$types,$domhelpdesk) = @_;
return unless ((ref($accesstypes) eq 'ARRAY') && (ref($domhelpdesk) eq 'HASH'));
my %lt = &Apache::lonlocal::texthash(
'rou' => 'Role usage',
'whi' => 'Which helpdesk personnel may use this role?',
'all' => 'All with domain helpdesk or helpdesk assistant role',
'dh' => 'All with domain helpdesk role',
'da' => 'All with domain helpdesk assistant role',
'none' => 'None',
'status' => 'Determined based on institutional status',
'inc' => 'Include all, but exclude specific personnel',
'exc' => 'Exclude all, but include specific personnel',
);
my %usecheck = (
all => ' checked="checked"',
);
my %displaydiv = (
status => 'none',
inc => 'none',
exc => 'none',
priv => 'block',
);
my $output;
if (ref($current) eq 'HASH') {
if (($current->{'access'} ne '') && ($current->{'access'} ne 'all')) {
if (grep(/^\Q$current->{access}\E$/,@{$accesstypes})) {
$usecheck{$current->{access}} = $usecheck{'all'};
delete($usecheck{'all'});
if ($current->{access} =~ /^(status|inc|exc)$/) {
my $access = $1;
$displaydiv{$access} = 'inline';
} elsif ($current->{access} eq 'none') {
$displaydiv{'priv'} = 'none';
}
}
}
}
$output = '<fieldset id="'.$prefix.$num.'_usage"><legend>'.$lt{'rou'}.'</legend>'.
'<p>'.$lt{'whi'}.'</p>';
foreach my $access (@{$accesstypes}) {
$output .= '<p><label><input type="radio" name="'.$prefix.$num.'_access" value="'.$access.'" '.$usecheck{$access}.
' onclick="helpdeskAccess('."'$num'".');" />'.
$lt{$access}.'</label>';
if ($access eq 'status') {
$output .= '<div id="'.$prefix.$num.'_bystatus" style="display:'.$displaydiv{$access}.'">'.
&Apache::lonuserutils::adhoc_status_types($dom,$prefix,$num,$current->{$access},
$othertitle,$usertypes,$types).
'</div>';
} elsif (($access eq 'inc') && (keys(%{$domhelpdesk}) > 0)) {
$output .= '<div id="'.$prefix.$num.'_notinc" style="display:'.$displaydiv{$access}.'">'.
&Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk).
'</div>';
} elsif (($access eq 'exc') && (keys(%{$domhelpdesk}) > 0)) {
$output .= '<div id="'.$prefix.$num.'_notexc" style="display:'.$displaydiv{$access}.'">'.
&Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk).
'</div>';
}
$output .= '</p>';
}
$output .= '</fieldset>';
return $output;
}
sub radiobutton_prefs {
my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick,
$additional,$align,$firstval) = @_;
return unless ((ref($toggles) eq 'ARRAY') && (ref($defaultchecked) eq 'HASH') &&
(ref($choices) eq 'HASH'));
my (%checkedon,%checkedoff,$datatable,$css_class);
foreach my $item (@{$toggles}) {
if ($defaultchecked->{$item} eq 'on') {
$checkedon{$item} = ' checked="checked" ';
$checkedoff{$item} = ' ';
} elsif ($defaultchecked->{$item} eq 'off') {
$checkedoff{$item} = ' checked="checked" ';
$checkedon{$item} = ' ';
}
}
if (ref($settings) eq 'HASH') {
foreach my $item (@{$toggles}) {
if ($settings->{$item} eq '1') {
$checkedon{$item} = ' checked="checked" ';
$checkedoff{$item} = ' ';
} elsif ($settings->{$item} eq '0') {
$checkedoff{$item} = ' checked="checked" ';
$checkedon{$item} = ' ';
}
}
}
if ($onclick) {
$onclick = ' onclick="'.$onclick.'"';
}
foreach my $item (@{$toggles}) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .=
'<tr'.$css_class.'><td style="vertical-align: top">'.
'<span class="LC_nobreak">'.$choices->{$item}.
'</span></td>';
if ($align eq 'left') {
$datatable .= '<td class="LC_left_item">';
} else {
$datatable .= '<td class="LC_right_item">';
}
$datatable .= '<span class="LC_nobreak">';
if ($firstval eq 'no') {
$datatable .=
'<label><input type="radio" name="'.
$item.'" '.$checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').
'</label> <label><input type="radio" name="'.$item.'" '.
$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>';
} else {
$datatable .=
'<label><input type="radio" name="'.
$item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').
'</label> <label><input type="radio" name="'.$item.'" '.
$checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>';
}
$datatable .= '</span>'.$additional.'</td></tr>';
$itemcount ++;
}
return ($datatable,$itemcount);
}
sub print_ltitools {
my ($position,$dom,$settings,$rowtotal) = @_;
my (%rules,%encrypt,%privkeys,%linkprot);
if (ref($settings) eq 'HASH') {
if ($position eq 'top') {
if (exists($settings->{'encrypt'})) {
if (ref($settings->{'encrypt'}) eq 'HASH') {
foreach my $key (keys(%{$settings->{'encrypt'}})) {
$encrypt{'toolsec_'.$key} = $settings->{'encrypt'}{$key};
}
}
}
if (exists($settings->{'private'})) {
if (ref($settings->{'private'}) eq 'HASH') {
if (ref($settings->{'private'}) eq 'HASH') {
if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {
map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});
}
}
}
}
} elsif ($position eq 'middle') {
if (exists($settings->{'rules'})) {
if (ref($settings->{'rules'}) eq 'HASH') {
%rules = %{$settings->{'rules'}};
}
}
} else {
foreach my $key ('encrypt','private','rules') {
if (exists($settings->{$key})) {
delete($settings->{$key});
}
}
}
}
my $datatable;
my $itemcount = 1;
if ($position eq 'top') {
$datatable = &secrets_form($dom,'toolsec',\%encrypt,\%privkeys,$rowtotal);
} elsif ($position eq 'middle') {
$datatable = &password_rules('toolsecrets',\$itemcount,\%rules);
$$rowtotal += $itemcount;
} else {
$datatable = &Apache::courseprefs::print_ltitools($dom,'',$settings,\$rowtotal,'','','domain');
}
return $datatable;
}
sub ltitools_names {
my %lt = &Apache::lonlocal::texthash(
'title' => 'Title',
'version' => 'Version',
'msgtype' => 'Message Type',
'sigmethod' => 'Signature Method',
'url' => 'URL',
'key' => 'Key',
'lifetime' => 'Nonce lifetime (s)',
'secret' => 'Secret',
'icon' => 'Icon',
'user' => 'User',
'fullname' => 'Full Name',
'firstname' => 'First Name',
'lastname' => 'Last Name',
'email' => 'E-mail',
'roles' => 'Role',
'window' => 'Window',
'tab' => 'Tab',
'iframe' => 'iFrame',
'height' => 'Height',
'width' => 'Width',
'linktext' => 'Default Link Text',
'explanation' => 'Default Explanation',
'passback' => 'Tool can return grades:',
'roster' => 'Tool can retrieve roster:',
'crstarget' => 'Display target',
'crslabel' => 'Course label',
'crstitle' => 'Course title',
'crslinktext' => 'Link Text',
'crsexplanation' => 'Explanation',
'crsappend' => 'Provider URL',
);
return %lt;
}
sub secrets_form {
my ($dom,$context,$encrypt,$privkeys,$rowtotal) = @_;
my @ids=&Apache::lonnet::current_machine_ids();
my %servers = &Apache::lonnet::get_servers($dom,'library');
my $primary = &Apache::lonnet::domain($dom,'primary');
my ($css_class,$extra,$numshown,$itemcount,$output);
$itemcount = 0;
foreach my $hostid (sort(keys(%servers))) {
my ($showextra,$divsty,$switch);
if ($hostid eq $primary) {
if ($context eq 'ltisec') {
if (($encrypt->{'ltisec_consumers'}) || ($encrypt->{'ltisec_domlinkprot'})) {
$showextra = 1;
}
if ($encrypt->{'ltisec_crslinkprot'}) {
$showextra = 1;
}
} else {
if (($encrypt->{'toolsec_crs'}) || ($encrypt->{'toolsec_dom'})) {
$showextra = 1;
}
}
unless (grep(/^\Q$hostid\E$/,@ids)) {
$switch = 1;
}
if ($showextra) {
$numshown ++;
$divsty = 'display:inline-block';
} else {
$divsty = 'display:none';
}
$extra .= '<fieldset id="'.$context.'_info_'.$hostid.'" style="'.$divsty.'">'.
'<legend>'.$hostid.'</legend>';
if ($switch) {
my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&role='.
&HTML::Entities::encode($env{'request.role'},'\'<>"&').
'&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
if (exists($privkeys->{$hostid})) {
$extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'.
'<span class="LC_nobreak">'.
&mt('Encryption Key').': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'.
'<span class="LC_nobreak">'.&mt('Change?').
'<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.
(' 'x2).
'<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').
'</label> </span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.
'<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).
'</span></div>';
} else {
$extra .= '<span class="LC_nobreak">'.
&mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver).
'</span>'."\n";
}
} elsif (exists($privkeys->{$hostid})) {
$extra .= '<div id="'.$context.'_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'.
&mt('Encryption Key').': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'.
'<span class="LC_nobreak">'.&mt('Change?').
'<label><input type="radio" value="0" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" checked="checked" />'.&mt('No').'</label>'.
(' 'x2).
'<label><input type="radio" value="1" name="'.$context.'_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$context','$hostid'".');" />'.&mt('Yes').
'</label> </span><div id="'.$context.'_divchgprivkey_'.$hostid.'" style="display:none" />'.
'<span class="LC_nobreak">'.&mt('New Key').':'.
'<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.
'<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
'</span></div>';
} else {
$extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'.
'<input type="password" size="20" name="'.$context.'_privkey_'.$hostid.'" value="" autocomplete="new-password" />'.
'<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.'.$context.'_privkey_'.$hostid.'.type='."'text'".' } else { this.form.'.$context.'_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';
}
$extra .= '</fieldset>';
}
}
my (%choices,@toggles,%defaultchecked);
if ($context eq 'ltisec') {
%choices = &Apache::lonlocal::texthash (
ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses',
ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain',
ltisec_consumers => 'Encrypt stored consumer secrets defined in domain',
);
@toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers);
%defaultchecked = (
'ltisec_crslinkprot' => 'off',
'ltisec_domlinkprot' => 'off',
'ltisec_consumers' => 'off',
);
} else {
%choices = &Apache::lonlocal::texthash (
toolsec_crs => 'Encrypt stored external tool secrets defined in courses',
toolsec_dom => 'Encrypt stored external tool secrets defined in domain',
);
@toggles = qw(toolsec_crs toolsec_dom);
%defaultchecked = (
'toolsec_crs' => 'off',
'toolsec_dom' => 'off',
);
}
my ($onclick,$itemcount);
$onclick = 'javascript:toggleLTIEncKey(this.form,'."'$context'".');';
($output,$itemcount) = &radiobutton_prefs($encrypt,\@toggles,\%defaultchecked,
\%choices,$itemcount,$onclick,'','left','no');
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $noprivkeysty = 'display:inline-block';
if ($numshown) {
$noprivkeysty = 'display:none';
}
$output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'.
'<td><div id="'.$context.'_noprivkey" style="'.$noprivkeysty.'" >'.
'<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'.
$extra.
'</td></tr>';
$itemcount ++;
$$rowtotal += $itemcount;
return $output;
}
sub print_proctoring {
my ($dom,$settings,$rowtotal) = @_;
my $itemcount = 1;
my (%ordered,%providernames,%current,%currentdef);
my $confname = $dom.'-domainconfig';
my $switchserver = &check_switchserver($dom,$confname);
if (ref($settings) eq 'HASH') {
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
$ordered{$num} = $item;
}
}
} else {
%ordered = (
1 => 'proctorio',
2 => 'examity',
);
}
%providernames = &proctoring_providernames();
my $maxnum = scalar(keys(%ordered));
my (%requserfields,%optuserfields,%defaults,%extended,%crsconf,@courseroles,@ltiroles);
my ($requref,$opturef,$defref,$extref,$crsref,$rolesref,$ltiref) = &proctoring_data();
if (ref($requref) eq 'HASH') {
%requserfields = %{$requref};
}
if (ref($opturef) eq 'HASH') {
%optuserfields = %{$opturef};
}
if (ref($defref) eq 'HASH') {
%defaults = %{$defref};
}
if (ref($extref) eq 'HASH') {
%extended = %{$extref};
}
if (ref($crsref) eq 'HASH') {
%crsconf = %{$crsref};
}
if (ref($rolesref) eq 'ARRAY') {
@courseroles = @{$rolesref};
}
if (ref($ltiref) eq 'ARRAY') {
@ltiroles = @{$ltiref};
}
my $datatable;
my $css_class;
if (keys(%ordered)) {
my @items = sort { $a <=> $b } keys(%ordered);
for (my $i=0; $i<@items; $i++) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $provider = $ordered{$items[$i]};
my $optionsty = 'none';
my ($available,$version,$lifetime,$imgsrc,$userincdom,$showroles,
%checkedfields,%rolemaps,%inuse,%crsconfig,%current);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$provider}) eq 'HASH') {
%current = %{$settings->{$provider}};
if ($current{'available'}) {
$optionsty = 'block';
$available = 1;
}
if ($current{'lifetime'} =~ /^\d+$/) {
$lifetime = $current{'lifetime'};
}
if ($current{'version'} =~ /^\d+\.\d+$/) {
$version = $current{'version'};
}
if ($current{'image'} ne '') {
$imgsrc = '<img src="'.$current{'image'}.'" alt="'.&mt('Proctoring service icon').'" />';
}
if (ref($current{'fields'}) eq 'ARRAY') {
map { $checkedfields{$_} = 1; } @{$current{'fields'}};
}
$userincdom = $current{'incdom'};
if (ref($current{'roles'}) eq 'HASH') {
%rolemaps = %{$current{'roles'}};
$checkedfields{'roles'} = 1;
}
if (ref($current{'defaults'}) eq 'ARRAY') {
foreach my $val (@{$current{'defaults'}}) {
if (grep(/^\Q$val\E$/,@{$defaults{$provider}})) {
$inuse{$val} = 1;
} else {
foreach my $poss (keys(%{$extended{$provider}})) {
if (ref($extended{$provider}{$poss}) eq 'ARRAY') {
if (grep(/^\Q$val\E$/,@{$extended{$provider}{$poss}})) {
$inuse{$poss} = $val;
last;
}
}
}
}
}
} elsif (ref($current{'defaults'}) eq 'HASH') {
foreach my $key (keys(%{$current{'defaults'}})) {
my $currval = $current{'defaults'}{$key};
if (grep(/^\Q$key\E$/,@{$defaults{$provider}})) {
$inuse{$key} = 1;
} else {
my $match;
foreach my $poss (keys(%{$extended{$provider}})) {
if (ref($extended{$provider}{$poss}) eq 'ARRAY') {
if (grep(/^\Q$key\E$/,@{$extended{$provider}{$poss}})) {
$inuse{$poss} = $key;
last;
}
} elsif (ref($extended{$provider}{$poss}) eq 'HASH') {
foreach my $inner (sort(keys(%{$extended{$provider}{$poss}}))) {
if (ref($extended{$provider}{$poss}{$inner}) eq 'ARRAY') {
if (grep(/^\Q$currval\E$/,@{$extended{$provider}{$poss}{$inner}})) {
$currentdef{$inner} = $currval;
$match = 1;
last;
}
} elsif ($inner eq $key) {
$currentdef{$key} = $currval;
$match = 1;
last;
}
}
}
last if ($match);
}
}
}
}
if (ref($current{'crsconf'}) eq 'ARRAY') {
map { $crsconfig{$_} = 1; } @{$current{'crsconf'}};
}
}
}
my %lt = &proctoring_titles($provider);
my %fieldtitles = &proctoring_fieldtitles($provider);
my $onclickavailable = ' onclick="toggleProctoring(this.form,'."'$provider'".');"';
my %checkedavailable = (
yes => '',
no => ' checked="checked"',
);
if ($available) {
$checkedavailable{'yes'} = $checkedavailable{'no'};
$checkedavailable{'no'} = '';
}
my $chgstr = ' onchange="javascript:reorderProctoring(this.form,'."'proctoring_pos_".$provider."'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="proctoring_pos_'.$provider.'"'.$chgstr.'>';
for (my $k=0; $k<$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $i) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
if ($version eq '') {
if ($provider eq 'proctorio') {
$version = '1.0';
} elsif ($provider eq 'examity') {
$version = '1.1';
}
}
if ($lifetime eq '') {
$lifetime = '300';
}
$datatable .=
'</select>'.(' 'x2).'<b>'.$providernames{$provider}.'</b></span><br />'.
'<span class="LC_nobreak">'.$lt{'avai'}.' '.
'<label><input type="radio" name="proctoring_available_'.$provider.'" value="1"'.$onclickavailable.$checkedavailable{yes}.' />'.&mt('Yes').'</label> '."\n".
'<label><input type="radio" name="proctoring_available_'.$provider.'" value="0"'.$onclickavailable.$checkedavailable{no}.' />'.&mt('No').'</label></span>'."\n".
'</td>'.
'<td colspan="2">'.
'<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'base'}.'</legend>'.
'<span class="LC_nobreak">'.$lt{'version'}.':<select name="proctoring_'.$provider.'_version">'.
'<option value="'.$version.'" selected="selected">'.$version.'</option></select></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="proctoring_'.$provider.'_sigmethod">'.
'<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'.
'<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'.
(' 'x2).
'<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="proctoring_'.$provider.'_lifetime" value="'.$lifetime.'" /></span> '."\n".
'<br />'.
'<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="proctoring_'.$provider.'_url" value="'.$current{'url'}.'" /></span> '."\n".
'<br />'.
'<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="proctoring_'.$provider.'_key" value="'.$current{'key'}.'" /></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="proctoring_'.$provider.'_secret" value="'.$current{'secret'}.'" />'.
'<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.proctoring_'.$provider.'_secret.type='."'text'".' } else { this.form.proctoring_'.$provider.'_secret.type='."'password'".' }" />'.$lt{'visible'}.'</label></span><br />'."\n";
$datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': ';
if ($imgsrc) {
$datatable .= $imgsrc.
'<label><input type="checkbox" name="proctoring_image_del"'.
' value="'.$provider.'" />'.&mt('Delete?').'</label></span> '.
'<span class="LC_nobreak"> '.&mt('Replace:');
}
$datatable .= ' ';
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .= '<input type="file" name="proctoring_image_'.$provider.'" value="" />';
}
unless ($imgsrc) {
$datatable .= '<br />('.&mt('if larger than 21x21 pixels, image will be scaled').')';
}
$datatable .= '</fieldset>'."\n";
if (ref($requserfields{$provider}) eq 'ARRAY') {
if (@{$requserfields{$provider}} > 0) {
$datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'requ'}.'</legend>';
foreach my $field (@{$requserfields{$provider}}) {
$datatable .= '<span class="LC_nobreak">'.
'<label><input type="checkbox" name="proctoring_reqd_'.$provider.'" value="'.$field.'" checked="checked" disabled="disabled" />'.
$lt{$field}.'</label>';
if ($field eq 'user') {
my $seluserdom = '';
my $unseluserdom = ' selected="selected"';
if ($userincdom) {
$seluserdom = $unseluserdom;
$unseluserdom = '';
}
$datatable .= ': '.
'<select name="proctoring_userincdom_'.$provider.'">'.
'<option value="0"'.$unseluserdom.'>'.$lt{'username'}.'</option>'.
'<option value="1"'.$seluserdom.'>'.$lt{'uname:dom'}.'</option>'.
'</select> ';
} else {
$datatable .= ' ';
if ($field eq 'roles') {
$showroles = 1;
}
}
$datatable .= '</span> ';
}
}
$datatable .= '</fieldset>'."\n";
}
if (ref($optuserfields{$provider}) eq 'ARRAY') {
if (@{$optuserfields{$provider}} > 0) {
$datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'optu'}.'</legend>';
foreach my $field (@{$optuserfields{$provider}}) {
my $checked;
if ($checkedfields{$field}) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak">'.
'<label><input type="checkbox" name="proctoring_optional_'.$provider.'" value="'.$field.'"'.$checked.' />'.$lt{$field}.'</label></span> ';
}
$datatable .= '</fieldset>'."\n";
}
}
if (ref($defaults{$provider}) eq 'ARRAY') {
if (@{$defaults{$provider}}) {
my (%options,@selectboxes);
if (ref($extended{$provider}) eq 'HASH') {
%options = %{$extended{$provider}};
}
$datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'defa'}.'</legend>';
my ($rem,$numinrow,$dropdowns);
if ($provider eq 'proctorio') {
$datatable .= '<table>';
$numinrow = 4;
}
my $i = 0;
foreach my $field (@{$defaults{$provider}}) {
my $checked;
if ($inuse{$field}) {
$checked = ' checked="checked"';
}
if ($provider eq 'examity') {
if ($field eq 'display') {
$datatable .= '<span class="LC_nobreak">'.&mt('Display target:');
foreach my $option ('iframe','tab','window') {
my $checkdisp;
if ($currentdef{'target'} eq $option) {
$checkdisp = ' checked="checked"';
}
$datatable .= '<label><input type="radio" name="proctoring_target_'.$provider.'" value="'.$option.'"'.$checkdisp.' />'.
$fieldtitles{$option}.'</label>'.(' 'x2);
}
$datatable .= (' 'x4);
foreach my $dimen ('width','height') {
$datatable .= '<label>'.$fieldtitles{$dimen}.' '.
'<input type="text" name="proctoring_'.$dimen.'_'.$provider.'" size="5" '.
'value="'.$currentdef{$dimen}.'" /></label>'.
(' 'x2);
}
$datatable .= '</span><br />'.
'<div class="LC_left_float">'.$fieldtitles{'linktext'}.'<br />'.
'<input type="text" name="proctoring_linktext_'.$provider.'" '.
'size="25" value="'.$currentdef{'linktext'}.'" /></div>'.
'<div class="LC_left_float">'.$fieldtitles{'explanation'}.'<br />'.
'<textarea name="proctoring_explanation_'.$provider.'" rows="5" cols="40">'.
$currentdef{'explanation'}.
'</textarea></div><div style=""></div><br />';
}
} else {
if ((exists($options{$field})) && (ref($options{$field}) eq 'ARRAY')) {
my ($output,$selnone);
unless ($checked) {
$selnone = ' selected="selected"';
}
$output .= '<span class="LC_nobreak">'.$fieldtitles{$field}.': '.
'<select name="proctoring_defaults_'.$field.'_'.$provider.'">'.
'<option value=""'.$selnone.'>'.&mt('Not in use').'</option>';
foreach my $option (@{$options{$field}}) {
my $sel;
if ($inuse{$field} eq $option) {
$sel = ' selected="selected"';
}
$output .= '<option value="'.$option.'"'.$sel.'>'.$fieldtitles{$option}.'</option>';
}
$output .= '</select></span>';
push(@selectboxes,$output);
} else {
$rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
$datatable .= '<td class="LC_left_item">'.
'<span class="LC_nobreak">'.
'<label><input type="checkbox" name="proctoring_defaults_'.$provider.'" value="'.$field.'"'.$checked.' />'.
$fieldtitles{$field}.'</label></span></td>';
$i++;
}
}
}
if ($provider eq 'proctorio') {
if ($numinrow) {
$rem = $i%$numinrow;
}
my $colsleft = $numinrow - $rem;
if ($colsleft > 1) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
} else {
$datatable .= '<td class="LC_left_item">';
}
$datatable .= ' '.
'</td></tr></table>';
if (@selectboxes) {
$datatable .= '<hr /><table>';
$numinrow = 2;
for (my $i=0; $i<@selectboxes; $i++) {
$rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
$datatable .= '<td class="LC_left_item">'.
$selectboxes[$i].'</td>';
}
if ($numinrow) {
$rem = $i%$numinrow;
}
$colsleft = $numinrow - $rem;
if ($colsleft > 1) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
} else {
$datatable .= '<td class="LC_left_item">';
}
$datatable .= ' '.
'</td></tr></table>';
}
}
$datatable .= '</fieldset>';
}
if (ref($crsconf{$provider}) eq 'ARRAY') {
$datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'.
'<legend>'.&mt('Configurable in course').'</legend>';
my ($rem,$numinrow);
if ($provider eq 'proctorio') {
$datatable .= '<table>';
$numinrow = 4;
}
my $i = 0;
foreach my $item (@{$crsconf{$provider}}) {
my $name;
if ($provider eq 'examity') {
$name = $lt{'crs'.$item};
} elsif ($provider eq 'proctorio') {
$name = $fieldtitles{$item};
$rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
$datatable .= '<td class="LC_left_item>';
}
my $checked;
if ($crsconfig{$item}) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="proctoring_crsconf_'.$provider.'" value="'.$item.'"'.$checked.' />'.
$name.'</label></span>';
if ($provider eq 'examity') {
$datatable .= ' ';
}
$datatable .= "\n";
$i++;
}
if ($provider eq 'proctorio') {
if ($numinrow) {
$rem = $i%$numinrow;
}
my $colsleft = $numinrow - $rem;
if ($colsleft > 1) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
} else {
$datatable .= '<td class="LC_left_item">';
}
$datatable .= ' '.
'</td></tr></table>';
}
$datatable .= '</fieldset>';
}
if ($showroles) {
$datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'.
'<legend>'.&mt('Role mapping').'</legend><table><tr>';
foreach my $role (@courseroles) {
my ($selected,$selectnone);
if (!$rolemaps{$role}) {
$selectnone = ' selected="selected"';
}
$datatable .= '<td style="text-align: center">'.
&Apache::lonnet::plaintext($role,'Course').'<br />'.
'<select name="proctoring_roles_'.$role.'_'.$provider.'">'.
'<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
foreach my $ltirole (@ltiroles) {
unless ($selectnone) {
if ($rolemaps{$role} eq $ltirole) {
$selected = ' selected="selected"';
} else {
$selected = '';
}
}
$datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>';
}
$datatable .= '</select></td>';
}
$datatable .= '</tr></table></fieldset>'.
'<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'.
'<legend>'.&mt('Custom items sent on launch').'</legend>'.
'<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'.
'<tr><td></td><td>lms</td>'.
'<td><input type="text" name="proctoring_customval_lms_'.$provider.'"'.
' value="Loncapa" disabled="disabled"/></td></tr>';
if ((ref($settings) eq 'HASH') && (ref($settings->{$provider}) eq 'HASH') &&
(ref($settings->{$provider}->{'custom'}) eq 'HASH')) {
my %custom = %{$settings->{$provider}->{'custom'}};
if (keys(%custom) > 0) {
foreach my $key (sort(keys(%custom))) {
next if ($key eq 'lms');
$datatable .= '<tr><td><span class="LC_nobreak">'.
'<label><input type="checkbox" name="proctoring_customdel_'.$provider.'" value="'.
$key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'.
'<td><input type="text" name="proctoring_customval_'.$key.'_'.$provider.'"'.
' value="'.$custom{$key}.'" /></td></tr>';
}
}
}
$datatable .= '<tr><td><span class="LC_nobreak">'.
'<label><input type="checkbox" name="proctoring_customadd" value="'.$provider.'" />'.
&mt('Add more').'</label></span></td><td><input type="text" name="proctoring_custom_name_'.$provider.'" />'.
'</td><td><input type="text" name="proctoring_custom_value_'.$provider.'" /></td></tr>'.
'</table></fieldset></td></tr>'."\n";
}
$datatable .= '</td></tr>';
}
$itemcount ++;
}
}
return $datatable;
}
sub proctoring_data {
my $requserfields = {
proctorio => ['user'],
examity => ['roles','user'],
};
my $optuserfields = {
proctorio => ['fullname'],
examity => ['fullname','firstname','lastname','email'],
};
my $defaults = {
proctorio => ['recordvideo','recordaudio','recordscreen','recordwebtraffic',
'recordroomstart','verifyvideo','verifyaudio','verifydesktop',
'verifyid','verifysignature','fullscreen','clipboard','tabslinks',
'closetabs','onescreen','print','downloads','cache','rightclick',
'reentry','calculator','whiteboard'],
examity => ['display'],
};
my $extended = {
proctorio => {
verifyid => ['verifyidauto','verifyidlive'],
fullscreen => ['fullscreenlenient','fullscreenmoderate','fullscreensever'],
tabslinks => ['notabs','linksonly'],
reentry => ['noreentry','agentreentry'],
calculator => ['calculatorbasic','calculatorsci'],
},
examity => {
display => {
target => ['iframe','tab','window'],
width => '',
height => '',
linktext => '',
explanation => '',
},
},
};
my $crsconf = {
proctorio => ['recordvideo','recordaudio','recordscreen','recordwebtraffic',
'recordroomstart','verifyvideo','verifyaudio','verifydesktop',
'verifyid','verifysignature','fullscreen','clipboard','tabslinks',
'closetabs','onescreen','print','downloads','cache','rightclick',
'reentry','calculator','whiteboard'],
examity => ['label','title','target','linktext','explanation','append'],
};
my $courseroles = ['cc','in','ta','ep','st'];
my $ltiroles = ['Instructor','ContentDeveloper','TeachingAssistant','Learner'];
return ($requserfields,$optuserfields,$defaults,$extended,$crsconf,$courseroles,$ltiroles);
}
sub proctoring_titles {
my ($item) = @_;
my (%common_lt,%custom_lt);
%common_lt = &Apache::lonlocal::texthash (
'avai' => 'Available?',
'base' => 'Basic Settings',
'requ' => 'User data required to be sent on launch',
'optu' => 'User data optionally sent on launch',
'udsl' => 'User data sent on launch',
'defa' => 'Defaults for items configurable in course',
'sigmethod' => 'Signature Method',
'key' => 'Key',
'lifetime' => 'Nonce lifetime (s)',
'secret' => 'Secret',
'icon' => 'Icon',
'fullname' => 'Full Name',
'visible' => 'Visible input',
'username' => 'username',
'user' => 'User',
);
if ($item eq 'proctorio') {
%custom_lt = &Apache::lonlocal::texthash (
'version' => 'OAuth version',
'url' => 'API URL',
'uname:dom' => 'username-domain',
);
} elsif ($item eq 'examity') {
%custom_lt = &Apache::lonlocal::texthash (
'version' => 'LTI Version',
'url' => 'URL',
'uname:dom' => 'username:domain',
'msgtype' => 'Message Type',
'firstname' => 'First Name',
'lastname' => 'Last Name',
'email' => 'E-mail',
'roles' => 'Role',
'crstarget' => 'Display target',
'crslabel' => 'Course label',
'crstitle' => 'Course title',
'crslinktext' => 'Link Text',
'crsexplanation' => 'Explanation',
'crsappend' => 'Provider URL',
);
}
my %lt = (%common_lt,%custom_lt);
return %lt;
}
sub proctoring_fieldtitles {
my ($item) = @_;
if ($item eq 'proctorio') {
return &Apache::lonlocal::texthash (
'recordvideo' => 'Record video',
'recordaudio' => 'Record audio',
'recordscreen' => 'Record screen',
'recordwebtraffic' => 'Record web traffic',
'recordroomstart' => 'Record room scan',
'verifyvideo' => 'Verify webcam',
'verifyaudio' => 'Verify microphone',
'verifydesktop' => 'Verify desktop recording',
'verifyid' => 'Photo ID verification',
'verifysignature' => 'Require signature',
'fullscreen' => 'Fullscreen',
'clipboard' => 'Disable copy/paste',
'tabslinks' => 'New tabs/windows',
'closetabs' => 'Close other tabs',
'onescreen' => 'Limit to single screen',
'print' => 'Disable Printing',
'downloads' => 'Disable Downloads',
'cache' => 'Empty cache after exam',
'rightclick' => 'Disable right click',
'reentry' => 'Re-entry to exam',
'calculator' => 'Onscreen calculator',
'whiteboard' => 'Onscreen whiteboard',
'verifyidauto' => 'Automated verification',
'verifyidlive' => 'Live agent verification',
'fullscreenlenient' => 'Forced, but can navigate away for up to 30s',
'fullscreenmoderate' => 'Forced, but can navigate away for up to 15s',
'fullscreensever' => 'Forced, navigation away ends exam',
'notabs' => 'Disaallowed',
'linksonly' => 'Allowed from links in exam',
'noreentry' => 'Disallowed',
'agentreentry' => 'Agent required for re-entry',
'calculatorbasic' => 'Basic',
'calculatorsci' => 'Scientific',
);
} elsif ($item eq 'examity') {
return &Apache::lonlocal::texthash (
'target' => 'Display target',
'window' => 'Window',
'tab' => 'Tab',
'iframe' => 'iFrame',
'height' => 'Height (pixels)',
'width' => 'Width (pixels)',
'linktext' => 'Default Link Text',
'explanation' => 'Default Explanation',
'append' => 'Provider URL',
);
}
}
sub proctoring_providernames {
return (
proctorio => 'Proctorio',
examity => 'Examity',
);
}
sub print_lti {
my ($position,$dom,$settings,$rowtotal) = @_;
my $itemcount = 1;
my ($datatable,$css_class);
my (%rules,%encrypt,%privkeys,%linkprot,%suggestions);
if (ref($settings) eq 'HASH') {
if ($position eq 'top') {
if (exists($settings->{'encrypt'})) {
if (ref($settings->{'encrypt'}) eq 'HASH') {
foreach my $key (keys(%{$settings->{'encrypt'}})) {
if ($key eq 'consumers') {
$encrypt{'ltisec_'.$key} = $settings->{'encrypt'}{$key};
} else {
$encrypt{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key};
}
}
}
}
if (exists($settings->{'private'})) {
if (ref($settings->{'private'}) eq 'HASH') {
if (ref($settings->{'private'}) eq 'HASH') {
if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') {
map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}});
}
}
}
}
} elsif ($position eq 'upper') {
if (exists($settings->{'rules'})) {
if (ref($settings->{'rules'}) eq 'HASH') {
%rules = %{$settings->{'rules'}};
}
}
} elsif ($position eq 'middle') {
if (exists($settings->{'suggested'})) {
if (ref($settings->{'suggested'}) eq 'HASH') {
%suggestions = %{$settings->{'suggested'}};
}
}
} elsif ($position eq 'lower') {
if (exists($settings->{'linkprot'})) {
if (ref($settings->{'linkprot'}) eq 'HASH') {
%linkprot = %{$settings->{'linkprot'}};
if ($linkprot{'lock'}) {
delete($linkprot{'lock'});
}
}
}
} else {
foreach my $key ('encrypt','private','rules','linkprot','suggestions') {
if (exists($settings->{$key})) {
delete($settings->{$key});
}
}
}
}
if ($position eq 'top') {
$datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);
} elsif ($position eq 'upper') {
$datatable = &password_rules('ltisecrets',\$itemcount,\%rules);
$$rowtotal += $itemcount;
} elsif ($position eq 'middle') {
$datatable = &linkprot_suggestions(\%suggestions,\$itemcount);
$$rowtotal += $itemcount;
} elsif ($position eq 'lower') {
$datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');
} else {
my ($switchserver,$switchmessage);
$switchserver = &check_switchserver($dom);
$switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);
my $maxnum = 0;
my %ordered;
if (ref($settings) eq 'HASH') {
foreach my $item (keys(%{$settings})) {
if (ref($settings->{$item}) eq 'HASH') {
my $num = $settings->{$item}{'order'};
if ($num eq '') {
$num = scalar(keys(%{$settings}));
}
$ordered{$num} = $item;
}
}
}
$maxnum = scalar(keys(%ordered));
my %lt = <i_names();
if (keys(%ordered)) {
my @items = sort { $a <=> $b } keys(%ordered);
for (my $i=0; $i<@items; $i++) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $item = $ordered{$items[$i]};
my ($key,$secret,$usable,$lifetime,$consumer,$requser,$crsinc,$current);
if (ref($settings->{$item}) eq 'HASH') {
$key = $settings->{$item}->{'key'};
$usable = $settings->{$item}->{'usable'};
$lifetime = $settings->{$item}->{'lifetime'};
$consumer = $settings->{$item}->{'consumer'};
$requser = $settings->{$item}->{'requser'};
$crsinc = $settings->{$item}->{'crsinc'};
$current = $settings->{$item};
}
my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"';
my %checkedrequser = (
yes => ' checked="checked"',
no => '',
);
if (!$requser) {
$checkedrequser{'no'} = $checkedrequser{'yes'};
$checkedrequser{'yes'} = '';
}
my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"';
my %checkedcrsinc = (
yes => ' checked="checked"',
no => '',
);
if (!$crsinc) {
$checkedcrsinc{'no'} = $checkedcrsinc{'yes'};
$checkedcrsinc{'yes'} = '';
}
my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="lti_pos_'.$item.'"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $i) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select>'.(' 'x2).
'<label><input type="checkbox" name="lti_del" value="'.$item.'" />'.
&mt('Delete?').'</label></span></td>'.
'<td colspan="2">'.
'<fieldset><legend>'.&mt('Required settings').'</legend>'.
'<span class="LC_nobreak">'.$lt{'consumer'}.
':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '.
(' 'x2).
'<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'.
'<option value="LTI-1p0" selected="selected">1.1</option></select></span> '.
(' 'x2).
'<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'.
'value="'.$lifetime.'" size="3" /></span><br /><br />';
if ($key ne '') {
$datatable .= '<span class="LC_nobreak">'.$lt{'key'};
if ($switchserver) {
$datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']';
} else {
$datatable .= ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />';
}
$datatable .= '</span> '.(' 'x2);
} elsif (!$switchserver) {
$datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':'.
'<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" autocomplete="off" />'.
'</span> '.(' 'x2);
}
if ($switchserver) {
if ($usable ne '') {
$datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.
$lt{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'.
'<span class="LC_nobreak">'.&mt('Change secret?').
'<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.
(' 'x2).
'<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').'</label>'.(' 'x2).
'</span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.
'<span class="LC_nobreak"> - '.$switchmessage.'</span>'.
'</div>';
} elsif ($key eq '') {
$datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";
} else {
$datatable .= '<span class="LC_nobreak">'.&mt('Secret required').' - '.$switchmessage.'</span>'."\n";
}
} else {
if ($usable ne '') {
$datatable .= '<div id="lti_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'.
$lt{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'.
'<span class="LC_nobreak">'.&mt('Change?').
'<label><input type="radio" value="0" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" checked="checked" />'.&mt('No').'</label>'.
(' 'x2).
'<label><input type="radio" value="1" name="lti_changesecret_'.$i.'" onclick="javascript:toggleChgSecret(this.form,'."'$i','secret','lti'".');" />'.&mt('Yes').
'</label> </span><div id="lti_divchgsecret_'.$i.'" style="display:none" />'.
'<span class="LC_nobreak">'.&mt('New Secret').':'.
'<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.
'<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label></span></div>';
} else {
$datatable .=
'<span class="LC_nobreak">'.$lt{'secret'}.':'.
'<input type="password" size="20" name="lti_secret_'.$i.'" value="" autocomplete="new-password" />'.
'<label><input type="checkbox" name="lti_visible_'.$i.'" id="lti_visible_'.$i.'" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>';
}
}
$datatable .= '<br /><br />'.
'<span class="LC_nobreak">'.$lt{'requser'}.':'.
'<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label> '."\n".
'<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n".
'<br /><br />'.
'<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
'<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label> '."\n".
'<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n".
(' 'x4).
'<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
'</fieldset>'.<i_options($i,$current,$itemcount,%lt).'</td></tr>';
$itemcount ++;
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
'<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n".
'<select name="lti_pos_add"'.$chgstr.'>';
for (my $k=0; $k<$maxnum+1; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $maxnum) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select> '."\n".
'<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n".
'<td colspan="2">'.
'<fieldset><legend>'.&mt('Required settings').'</legend>'.
'<span class="LC_nobreak">'.$lt{'consumer'}.
':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'.
'<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span><br /><br />'."\n";
if ($switchserver) {
$datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n";
} else {
$datatable .= '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" autocomplete="off" /></span> '."\n".
(' 'x2).
'<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" autocomplete="new-password" />'.
'<label><input type="checkbox" name="lti_add_visible" id="lti_add_visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n";
}
$datatable .= '<br /><br />'.
'<span class="LC_nobreak">'.$lt{'requser'}.':'.
'<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n".
'<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n".
'<br /><br />'.
'<span class="LC_nobreak">'.$lt{'crsinc'}.':'.
'<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n".
'<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n".
'</fieldset>'.<i_options('add',undef,$itemcount,%lt).
'</td>'."\n".
'</tr>'."\n";
$itemcount ++;
}
$$rowtotal += $itemcount;
return $datatable;
}
sub lti_names {
my %lt = &Apache::lonlocal::texthash(
'version' => 'LTI Version',
'url' => 'URL',
'key' => 'Key',
'lifetime' => 'Nonce lifetime (s)',
'consumer' => 'Consumer',
'secret' => 'Secret',
'requser' => "User's identity sent",
'crsinc' => "Course's identity sent",
'email' => 'Email address',
'sourcedid' => 'User ID',
'other' => 'Other',
'passback' => 'Can return grades to Consumer:',
'roster' => 'Can retrieve roster from Consumer:',
'topmenu' => 'Display LON-CAPA page header',
'inlinemenu'=> 'Display LON-CAPA inline menu',
);
return %lt;
}
sub lti_options {
my ($num,$current,$itemcount,%lt) = @_;
my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);
$checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
$checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';
$checked{'storecrs'}{'Y'} = ' checked="checked"';
$checked{'makecrs'}{'N'} = ' checked="checked"';
$checked{'mapcrstype'} = {};
$checked{'makeuser'} = {};
$checked{'selfenroll'} = {};
$checked{'crssec'} = {};
$checked{'crssecsrc'} = {};
$checked{'lcauth'} = {};
$checked{'menuitem'} = {};
if ($num eq 'add') {
$checked{'lcauth'}{'lti'} = ' checked="checked"';
}
my $userfieldsty = 'none';
my $crsfieldsty = 'none';
my $crssecfieldsty = 'none';
my $secsrcfieldsty = 'none';
my $callbacksty = 'none';
my $passbacksty = 'none';
my $optionsty = 'block';
my $crssty = 'block';
my $lcauthparm;
my $lcauthparmstyle = 'display:none';
my $lcauthparmtext;
my $menusty;
my $numinrow = 4;
my %menutitles = <imenu_titles();
if (ref($current) eq 'HASH') {
if (!$current->{'requser'}) {
$optionsty = 'none';
$crssty = 'none';
} elsif (!$current->{'crsinc'}) {
$crssty = 'none';
}
if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {
$checked{'mapuser'}{'sourcedid'} = '';
if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {
$checked{'mapuser'}{'email'} = ' checked="checked"';
} else {
$checked{'mapuser'}{'other'} = ' checked="checked"';
$userfield = $current->{'mapuser'};
$userfieldsty = 'inline-block';
}
}
if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) {
$checked{'mapcrs'}{'course_offering_sourcedid'} = '';
if ($current->{'mapcrs'} eq 'context_id') {
$checked{'mapcrs'}{'context_id'} = ' checked="checked"';
} else {
$checked{'mapcrs'}{'other'} = ' checked="checked"';
$cidfield = $current->{'mapcrs'};
$crsfieldsty = 'inline-block';
}
}
if (ref($current->{'mapcrstype'}) eq 'ARRAY') {
foreach my $type (@{$current->{'mapcrstype'}}) {
$checked{'mapcrstype'}{$type} = ' checked="checked"';
}
}
if (!$current->{'storecrs'}) {
$checked{'storecrs'}{'N'} = $checked{'storecrs'}{'Y'};
$checked{'storecrs'}{'Y'} = '';
}
if ($current->{'makecrs'}) {
$checked{'makecrs'}{'Y'} = ' checked="checked"';
}
if (ref($current->{'makeuser'}) eq 'ARRAY') {
foreach my $role (@{$current->{'makeuser'}}) {
$checked{'makeuser'}{$role} = ' checked="checked"';
}
}
if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) {
$checked{'lcauth'}{$1} = ' checked="checked"';
unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {
$lcauthparm = $current->{'lcauthparm'};
$lcauthparmstyle = 'display:table-row';
if ($current->{'lcauth'} eq 'localauth') {
$lcauthparmtext = &mt('Local auth argument');
} else {
$lcauthparmtext = &mt('Kerberos domain');
}
}
}
if (ref($current->{'selfenroll'}) eq 'ARRAY') {
foreach my $role (@{$current->{'selfenroll'}}) {
$checked{'selfenroll'}{$role} = ' checked="checked"';
}
}
if (ref($current->{'maproles'}) eq 'HASH') {
%rolemaps = %{$current->{'maproles'}};
}
if ($current->{'section'} ne '') {
$checked{'crssec'}{'Y'} = ' checked="checked"';
$crssecfieldsty = 'inline-block';
if ($current->{'section'} eq 'course_section_sourcedid') {
$checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"';
} else {
$checked{'crssecsrc'}{'other'} = ' checked="checked"';
$crssecsrc = $current->{'section'};
$secsrcfieldsty = 'inline-block';
}
} else {
$checked{'crssec'}{'N'} = ' checked="checked"';
}
if ($current->{'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 {
$checked{'topmenu'}{'N'} = ' checked="checked"';
}
if ($current->{'inlinemenu'}) {
$checked{'inlinemenu'}{'Y'} = ' checked="checked"';
} else {
$checked{'inlinemenu'}{'N'} = ' checked="checked"';
}
if (($current->{'topmenu'}) || ($current->{'inlinemenu'})) {
$menusty = 'inline-block';
if (ref($current->{'lcmenu'}) eq 'ARRAY') {
foreach my $item (@{$current->{'lcmenu'}}) {
if (exists($menutitles{$item})) {
$checked{'menuitem'}{$item} = ' checked="checked"';
}
}
}
} else {
$menusty = 'none';
}
} 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"';
$menusty = 'inline-block';
}
my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
my %coursetypetitles = &Apache::lonlocal::texthash (
official => 'Official',
unofficial => 'Unofficial',
community => 'Community',
textbook => 'Textbook',
placement => 'Placement Test',
lti => 'LTI Provider',
);
my @authtypes = ('internal','krb4','krb5','localauth');
my %shortauth = (
internal => 'int',
krb4 => 'krb4',
krb5 => 'krb5',
localauth => 'loc'
);
my %authnames = &authtype_names();
my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor);
my @courseroles = ('cc','in','ta','ep','st');
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'".');"';
my $output = '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Logout options').'</legend>'.
'<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback to logout LON-CAPA on log out from Consumer').': '.
'<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.
$checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.
$checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.
'<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.
'<span class="LC_nobreak">'.&mt('Parameter').': '.
'<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.
'</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.
'<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'.
'<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').': ';
foreach my $option ('sourcedid','email','other') {
$output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'.
$checked{'mapuser'}{$option}.$onclickuser.' />'.$lt{$option}.'</label>'.
($option eq 'other' ? '' : (' 'x2) );
}
$output .= '</span></div>'.
'<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'.
'<input type="text" name="lti_customuser_'.$num.'" '.
'value="'.$userfield.'" /></div></fieldset>'.
'<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>';
foreach my $ltirole (@ltiroles) {
$output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'.
$checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label> </span> ';
}
$output .= '</fieldset>'.
'<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'.
'<table>'.
&modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).
'</table>'.
'<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'.
'<td class="LC_left_item">';
foreach my $auth ('lti',@authtypes) {
my $authtext;
if ($auth eq 'lti') {
$authtext = &mt('None');
} else {
$authtext = $authnames{$shortauth{$auth}};
}
$output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num.
'" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'.
$authtext.'</label></span> ';
}
$output .= '</td></tr>'.
'<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'.
'<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'.
'<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.
'<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.
'</table></fieldset>'.
'<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.
&mt('LON-CAPA menu items (Course Coordinator can override)').'</legend>'.
'<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.': '.
'<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.
$checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'.
$checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'.
'<div style="padding:0;clear:both;margin:0;border:0"></div>'.
'<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.': '.
'<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'.
$checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'.
$checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>';
$output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'.
'<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'.
'<span class="LC_nobreak">'.&mt('Menu items').': ';
foreach my $type ('fullname','coursetitle','role','logout','grades') {
$output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'.
$checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'.
(' 'x2);
}
$output .= '</span></div></fieldset>'.
'<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping courses').'</legend>'.
'<div class="LC_floatleft"><span class="LC_nobreak">'.
&mt('Unique course identifier').': ';
foreach my $option ('course_offering_sourcedid','context_id','other') {
$output .= '<label><input type="radio" name="lti_mapcrs_'.$num.'" value="'.$option.'"'.
$checked{'mapcrs'}{$option}.$onclickcrs.' />'.$option.'</label>'.
($option eq 'other' ? '' : (' 'x2) );
}
$output .= '</span></div><div class="LC_floatleft" style="display:'.$crsfieldsty.';" id="lti_crsfield_'.$num.'">'.
'<input type="text" name="lti_mapcrsfield_'.$num.'" value="'.$cidfield.'" />'.
'</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.
'<span class="LC_nobreak">'.&mt('LON-CAPA course type(s)').': ';
foreach my $type (@coursetypes) {
$output .= '<label><input type="checkbox" name="lti_mapcrstype_'.$num.'" value="'.$type.'"'.
$checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'.
(' 'x2);
}
$output .= '</span><br /><br />'.
'<span class="LC_nobreak">'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '.
'<label><input type="radio" name="lti_storecrs_'.$num.'" value="0"'.
$checked{'storecrs'}{'N'}.' />'.&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_storecrs_'.$num.'" value="1"'.
$checked{'storecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.
'</fieldset>'.
'<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>';
foreach my $ltirole (@lticourseroles) {
my ($selected,$selectnone);
if ($rolemaps{$ltirole} eq '') {
$selectnone = ' selected="selected"';
}
$output .= '<td style="text-align: center">'.$ltirole.'<br />'.
'<select name="lti_maprole_'.$ltirole.'_'.$num.'">'.
'<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
foreach my $role (@courseroles) {
unless ($selectnone) {
if ($rolemaps{$ltirole} eq $role) {
$selected = ' selected="selected"';
} else {
$selected = '';
}
}
$output .= '<option value="'.$role.'"'.$selected.'>'.
&Apache::lonnet::plaintext($role,'Course').
'</option>';
}
$output .= '</select></td>';
}
$output .= '</tr></table></fieldset>'.
'<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Creating courses').'</legend>'.
'<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').': '.
'<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'.
$checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'.
$checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'.
'</fieldset>'.
'<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>';
foreach my $lticrsrole (@lticourseroles) {
$output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'.
$checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label> </span> ';
}
$output .= '</fieldset>'.
'<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Course options').'</legend>'.
'<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').': '.
'<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'.
$checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_crssec_'.$num.'" value="1"'.
$checked{'crssec'}{'Y'}.$onclicksec.' />'.&mt('Yes').'</label></span></div>'.
'<div class="LC_floatleft" style="display:'.$crssecfieldsty.';" id="lti_crssecfield_'.$num.'">'.
'<span class="LC_nobreak">'.&mt('From').':<label>'.
'<input type="radio" name="lti_crssecsrc_'.$num.'" value="course_section_sourcedid"'.
$checked{'crssecsrc'}{'sourcedid'}.$onclicksecsrc.' />'.
&mt('Standard field').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_crssecsrc_'.$num.'" value="other"'.
$checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other').
'</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'.
'<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'.
'</div><div style="padding:0;clear:both;margin:0;border:0"></div>';
my ($pb1p1chk,$pb1p0chk,$onclickpb);
foreach my $extra ('roster','passback') {
my $checkedon = '';
my $checkedoff = ' checked="checked"';
if ($extra eq 'passback') {
$pb1p1chk = ' checked="checked"';
$pb1p0chk = '';
$onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"';
} else {
$onclickpb = '';
}
if (ref($current) eq 'HASH') {
if (($current->{$extra})) {
$checkedon = $checkedoff;
$checkedoff = '';
if ($extra eq 'passback') {
$passbacksty = 'inline-block';
}
if ($current->{'passbackformat'} eq '1.0') {
$pb1p0chk = ' checked="checked"';
$pb1p1chk = '';
}
}
}
$output .= $lt{$extra}.' '.
'<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'.
&mt('No').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb.' />'.
&mt('Yes').'</label><br />';
}
$output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'.
'<span class="LC_nobreak">'.&mt('Grade format').
'<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'.
&mt('Outcomes Service (1.1)').'</label>'.(' 'x2).
'<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.
&mt('Outcomes Extension (1.0)').'</label></span></div>'.
'<div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>';
$output .= '</span></div></fieldset>';
# '<fieldset><legend>'.&mt('Assigning author roles').'</legend>';
#
# $output .= '</fieldset>'.
# '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>';
return $output;
}
sub ltimenu_titles {
return &Apache::lonlocal::texthash(
fullname => 'Full name',
coursetitle => 'Course title',
role => 'Role',
logout => 'Logout',
grades => 'Grades',
);
}
sub linkprot_suggestions {
my ($suggested,$itemcount) = @_;
my $count = 0;
my $next = 1;
my %lt = &Apache::lonlocal::texthash(
'name' => 'Suggested Launcher',
'info' => 'Recommendations',
);
my ($datatable,$css_class,$dest);
if (ref($suggested) eq 'HASH') {
my @current = sort { $a <=> $b } keys(%{$suggested});
$next += $current[-1];
for (my $i=0; $i<@current; $i++) {
my $num = $current[$i];
my %values;
if (ref($suggested->{$num}) eq 'HASH') {
%values = %{$suggested->{$num}};
} else {
next;
}
$css_class = $$itemcount%2?' class="LC_odd_row"':'';
$datatable .=
'<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
'<label><input type="checkbox" name="linkprot_suggested_del" value="'.$i.'" />'."\n".
&mt('Delete?').'</label></span></td><td>'."\n".
'<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".
'<input type="text" size="15" name="linkprot_suggested_name_'.$i.'" value="'.$values{'name'}.'" autocomplete="off" />'."\n".
'</fieldset></div>'.
'<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".
'<textarea cols="55" rows="5" name="linkprot_suggested_info_'.$i.'">'.$values{'info'}.'</textarea>'.
'</fieldset></div>'.
'<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".
'<input type="hidden" name="linkprot_suggested_id_'.$i.'" value="'.$num.'" /></td></tr>'."\n";
$$itemcount ++;
}
}
$css_class = $$itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".
'<input type="hidden" name="linkprot_suggested_maxnum" value="'.$next.'" />'."\n".
'<input type="checkbox" name="linkprot_suggested_add" value="1" />'.&mt('Add').'</span></td>'."\n".
'<td>'."\n".
'<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".
'<input type="text" size="15" name="linkprot_suggested_name_add" value="" autocomplete="off" />'."\n".
'</fieldset></div>'.
'<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".
'<textarea cols="55" rows="5" name="linkprot_suggested_info_add"></textarea>'.
'</fieldset></div>'.
'<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".
'</td></tr>'."\n";
return $datatable;
}
sub print_coursedefaults {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);
my $itemcount = 1;
my %choices = &Apache::lonlocal::texthash (
canuse_pdfforms => 'Course/Community users can create/upload PDF forms',
uploadquota => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',
coursequota => 'Default cumulative quota for all group portfolio spaces in course (MB)',
anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
coursecredits => 'Credits can be specified for courses',
uselcmath => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
inline_chem => 'Use inline previewer for chemical reaction response in place of pop-up',
texengine => 'Default method to display mathematics',
postsubmit => 'Disable submit button/keypress following student submission',
canclone => "People who may clone a course (besides course's owner and coordinators)",
mysqltables => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
ltiauth => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',
domexttool => 'External Tools defined in the domain may be used in courses/communities (by type)',
exttool => 'External Tools can be defined and configured in courses/communities (by type)',
crsauthor => 'Standard LON-CAPA problems can be created within a course/community (by type)',
crseditors => 'Available editors for web pages and/or problems created in a course/community',
);
my %staticdefaults = (
anonsurvey_threshold => 10,
uploadquota => 500,
coursequota => 20,
postsubmit => 60,
mysqltables => 172800,
domexttool => 1,
exttool => 0,
crsauthor => 1,
crseditors => ['edit','xml'],
);
if ($position eq 'top') {
%defaultchecked = (
'canuse_pdfforms' => 'off',
'uselcmath' => 'on',
'usejsme' => 'on',
'inline_chem' => 'on',
'canclone' => 'none',
);
@toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem');
my $deftex = $Apache::lonnet::deftex;
if (ref($settings) eq 'HASH') {
if ($settings->{'texengine'}) {
if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) {
$deftex = $settings->{'texengine'};
}
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $mathdisp = '<tr'.$css_class.'><td style="vertical-align: top">'.
'<span class="LC_nobreak">'.$choices{'texengine'}.
'</span></td><td class="LC_right_item">'.
'<select name="texengine">'."\n";
my %texoptions = (
MathJax => 'MathJax',
mimetex => &mt('Convert to Images'),
tth => &mt('TeX to HTML'),
);
foreach my $renderer ('MathJax','mimetex','tth') {
my $selected = '';
if ($renderer eq $deftex) {
$selected = ' selected="selected"';
}
$mathdisp .= '<option value="'.$renderer.'"'.$selected.'>'.$texoptions{$renderer}.'</option>'."\n";
}
$mathdisp .= '</select></td></tr>'."\n";
$itemcount ++;
($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
\%choices,$itemcount);
$datatable = $mathdisp.$datatable;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .=
'<tr'.$css_class.'><td style="vertical-align: top">'.
'<span class="LC_nobreak">'.$choices{'canclone'}.
'</span></td><td class="LC_left_item">';
my $currcanclone = 'none';
my $onclick;
my @cloneoptions = ('none','domain');
my %clonetitles = &Apache::lonlocal::texthash (
none => 'No additional course requesters',
domain => "Any course requester in course's domain",
instcode => 'Course requests for official courses ...',
);
my (%codedefaults,@code_order,@posscodes);
if (&Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults,
\@code_order) eq 'ok') {
if (@code_order > 0) {
push(@cloneoptions,'instcode');
$onclick = ' onclick="toggleDisplay(this.form,'."'cloneinstcode'".');"';
}
}
if (ref($settings) eq 'HASH') {
if ($settings->{'canclone'}) {
if (ref($settings->{'canclone'}) eq 'HASH') {
if (ref($settings->{'canclone'}{'instcode'}) eq 'ARRAY') {
if (@code_order > 0) {
$currcanclone = 'instcode';
@posscodes = @{$settings->{'canclone'}{'instcode'}};
}
}
} elsif ($settings->{'canclone'} eq 'domain') {
$currcanclone = $settings->{'canclone'};
}
}
}
foreach my $option (@cloneoptions) {
my ($checked,$additional);
if ($currcanclone eq $option) {
$checked = ' checked="checked"';
}
if ($option eq 'instcode') {
if (@code_order) {
my $show = 'none';
if ($checked) {
$show = 'block';
}
$additional = '<div id="cloneinstcode" style="display:'.$show.';" />'.
&mt('Institutional codes for new and cloned course have identical:').
'<br />';
foreach my $item (@code_order) {
my $codechk;
if ($checked) {
if (grep(/^\Q$item\E$/,@posscodes)) {
$codechk = ' checked="checked"';
}
}
$additional .= '<label>'.
'<input type="checkbox" name="clonecode" value="'.$item.'"'.$codechk.' />'.
$item.'</label>';
}
$additional .= (' 'x2).'('.&mt('check as many as needed').')</div>';
}
}
$datatable .=
'<span class="LC_nobreak"><label><input type="radio" name="canclone"'.$checked.
' value="'.$option.'"'.$onclick.' />'.$clonetitles{$option}.
'</label> '.$additional.'</span><br />';
}
$datatable .= '</td>'.
'</tr>';
$itemcount ++;
} else {
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
my ($currdefresponder,%defcredits,%curruploadquota,%currcoursequota,
%deftimeout,%currmysql);
my $currusecredits = 0;
my $postsubmitclient = 1;
my $ltiauth = 0;
my %domexttool;
my %exttool;
my %crsauthor;
my %crseditors;
my @types = ('official','unofficial','community','textbook','placement');
if (ref($settings) eq 'HASH') {
if ($settings->{'ltiauth'}) {
$ltiauth = 1;
}
if (ref($settings->{'domexttool'}) eq 'HASH') {
foreach my $type (@types) {
if ($settings->{'domexttool'}->{$type}) {
$domexttool{$type} = ' checked="checked"';
}
}
} else {
foreach my $type (@types) {
if ($staticdefaults{'domexttool'}) {
$domexttool{$type} = ' checked="checked"';
}
}
}
if (ref($settings->{'exttool'}) eq 'HASH') {
foreach my $type (@types) {
if ($settings->{'exttool'}->{$type}) {
$exttool{$type} = ' checked="checked"';
}
}
}
if (ref($settings->{'crsauthor'}) eq 'HASH') {
foreach my $type (@types) {
if ($settings->{'crsauthor'}->{$type}) {
$crsauthor{$type} = ' checked="checked"';
}
}
} else {
foreach my $type (@types) {
if ($staticdefaults{'crsauthor'}) {
$crsauthor{$type} = ' checked="checked"';
}
}
}
if (ref($settings->{'crseditors'}) eq 'ARRAY') {
foreach my $editor (@{$settings->{'crseditors'}}) {
$crseditors{$editor} = ' checked="checked"';
}
} else {
foreach my $editor (@{$staticdefaults{'crseditors'}}) {
$crseditors{$editor} = ' checked="checked"';
}
}
$currdefresponder = $settings->{'anonsurvey_threshold'};
if (ref($settings->{'uploadquota'}) eq 'HASH') {
foreach my $type (keys(%{$settings->{'uploadquota'}})) {
$curruploadquota{$type} = $settings->{'uploadquota'}{$type};
}
}
if (ref($settings->{'coursequota'}) eq 'HASH') {
foreach my $type (keys(%{$settings->{'coursequota'}})) {
$currcoursequota{$type} = $settings->{'coursequota'}{$type};
}
}
if (ref($settings->{'coursecredits'}) eq 'HASH') {
foreach my $type (@types) {
next if ($type eq 'community');
$defcredits{$type} = $settings->{'coursecredits'}->{$type};
if ($defcredits{$type} ne '') {
$currusecredits = 1;
}
}
}
if (ref($settings->{'postsubmit'}) eq 'HASH') {
if ($settings->{'postsubmit'}->{'client'} eq 'off') {
$postsubmitclient = 0;
foreach my $type (@types) {
$deftimeout{$type} = $staticdefaults{'postsubmit'};
}
} else {
foreach my $type (@types) {
if (ref($settings->{'postsubmit'}->{'timeout'}) eq 'HASH') {
if ($settings->{'postsubmit'}->{'timeout'}->{$type} =~ /^\d+$/) {
$deftimeout{$type} = $settings->{'postsubmit'}->{'timeout'}->{$type};
} else {
$deftimeout{$type} = $staticdefaults{'postsubmit'};
}
} else {
$deftimeout{$type} = $staticdefaults{'postsubmit'};
}
}
}
} else {
foreach my $type (@types) {
$deftimeout{$type} = $staticdefaults{'postsubmit'};
}
}
if (ref($settings->{'mysqltables'}) eq 'HASH') {
foreach my $type (keys(%{$settings->{'mysqltables'}})) {
$currmysql{$type} = $settings->{'mysqltables'}{$type};
}
} else {
foreach my $type (@types) {
$currmysql{$type} = $staticdefaults{'mysqltables'};
}
}
} else {
foreach my $type (@types) {
$deftimeout{$type} = $staticdefaults{'postsubmit'};
if ($staticdefaults{'domexttool'}) {
$domexttool{$type} = ' checked="checked"';
}
if ($staticdefaults{'crsauthor'}) {
$crsauthor{$type} = ' checked="checked"';
}
}
foreach my $editor (@{$staticdefaults{'crseditors'}}) {
$crseditors{$editor} = ' checked="checked"';
}
}
if (!$currdefresponder) {
$currdefresponder = $staticdefaults{'anonsurvey_threshold'};
} elsif ($currdefresponder < 1) {
$currdefresponder = 1;
}
foreach my $type (@types) {
if ($curruploadquota{$type} eq '') {
$curruploadquota{$type} = $staticdefaults{'uploadquota'};
}
if ($currcoursequota{$type} eq '') {
$currcoursequota{$type} = $staticdefaults{'coursequota'};
}
}
$datatable .=
'<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'anonsurvey_threshold'}.
'</span></td>'.
'<td class="LC_right_item"><span class="LC_nobreak">'.
'<input type="text" name="anonsurvey_threshold"'.
' value="'.$currdefresponder.'" size="5" /></span>'.
'</td></tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'uploadquota'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
foreach my $type (@types) {
$datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
'<input type="text" name="uploadquota_'.$type.'"'.
' value="'.$curruploadquota{$type}.'" size="5" /></td>';
}
$datatable .= '</tr></table></td></tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'coursequota'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
foreach my $type (@types) {
$datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
'<input type="text" name="coursequota_'.$type.'"'.
' value="'.$currcoursequota{$type}.'" size="5" /></td>';
}
$datatable .= '</tr></table></td></tr>'."\n";
$itemcount ++;
my $onclick = "toggleDisplay(this.form,'credits');";
my $display = 'none';
if ($currusecredits) {
$display = 'block';
}
my $additional = '<div id="credits" style="display: '.$display.'">'.
'<i>'.&mt('Default credits').'</i><br /><table><tr>';
foreach my $type (@types) {
next if ($type eq 'community');
$additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
'<input type="text" name="'.$type.'_credits"'.
' value="'.$defcredits{$type}.'" size="3" /></td>';
}
$additional .= '</tr></table></div>'."\n";
%defaultchecked = ('coursecredits' => 'off');
@toggles = ('coursecredits');
my $current = {
'coursecredits' => $currusecredits,
};
(my $table,$itemcount) =
&radiobutton_prefs($current,\@toggles,\%defaultchecked,
\%choices,$itemcount,$onclick,$additional,'left');
$datatable .= $table;
$onclick = "toggleDisplay(this.form,'studentsubmission');";
my $display = 'none';
if ($postsubmitclient) {
$display = 'block';
}
$additional = '<div id="studentsubmission" style="display: '.$display.'">'.
&mt('Number of seconds submit is disabled').'<br />'.
'<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.
'<table><tr>';
foreach my $type (@types) {
$additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
'<input type="text" name="'.$type.'_timeout" value="'.
$deftimeout{$type}.'" size="5" /></td>';
}
$additional .= '</tr></table></div>'."\n";
%defaultchecked = ('postsubmit' => 'on');
@toggles = ('postsubmit');
$current = {
'postsubmit' => $postsubmitclient,
};
($table,$itemcount) =
&radiobutton_prefs($current,\@toggles,\%defaultchecked,
\%choices,$itemcount,$onclick,$additional,'left');
$datatable .= $table;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'mysqltables'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
foreach my $type (@types) {
$datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
'<input type="text" name="mysqltables_'.$type.'"'.
' value="'.$currmysql{$type}.'" size="8" /></td>';
}
$datatable .= '</tr></table></td></tr>'."\n";
$itemcount ++;
%defaultchecked = ('ltiauth' => 'off');
@toggles = ('ltiauth');
$current = {
'ltiauth' => $ltiauth,
};
($table,$itemcount) =
&radiobutton_prefs($current,\@toggles,\%defaultchecked,
\%choices,$itemcount,undef,undef,'left');
$datatable .= $table;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'domexttool'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
foreach my $type (@types) {
$datatable .= '<td style="text-align: left">'.
'<span class="LC_nobreak">'.
'<label><input type="checkbox" name="domexttool"'.
' value="'.$type.'"'.$domexttool{$type}.' />'.
&mt($type).'</label></span></td>'."\n";
}
$datatable .= '</tr></table></td></tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'exttool'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
foreach my $type (@types) {
$datatable .= '<td style="text-align: left">'.
'<span class="LC_nobreak">'.
'<label><input type="checkbox" name="exttool"'.
' value="'.$type.'"'.$exttool{$type}.' />'.
&mt($type).'</label></span></td>'."\n";
}
$datatable .= '</tr></table></td></tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'crsauthor'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
foreach my $type (@types) {
$datatable .= '<td style="text-align: left">'.
'<span class="LC_nobreak">'.
'<label><input type="checkbox" name="crsauthor"'.
' value="'.$type.'"'.$crsauthor{$type}.' />'.
&mt($type).'</label></span></td>'."\n";
}
$datatable .= '</tr></table></td></tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$choices{'crseditors'}.
'</span></td>'.
'<td style="text-align: right" class="LC_right_item">'.
'<table><tr>';
my @editors = ('edit','xml','daxe');
my %editornames = &crseditor_titles();
foreach my $editor (@editors) {
$datatable .= '<td style="text-align: left">'.
'<span class="LC_nobreak">'.
'<label><input type="checkbox" name="crseditors"'.
' value="'.$editor.'"'.$crseditors{$editor}.' />'.
$editornames{$editor}.'</label></span></td>'."\n";
}
$datatable .= '</tr></table></td></tr>'."\n";
}
$$rowtotal += $itemcount;
return $datatable;
}
sub crseditor_titles {
return &Apache::lonlocal::texthash(
edit => 'Standard editor (Edit)',
xml => 'Text editor (EditXML)',
daxe => 'Daxe editor (Daxe)',
);
}
sub print_authordefaults {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable,%checkedon,%checkedoff);
my $itemcount = 1;
my %titles = &authordefaults_titles();
if ($position eq 'top') {
my %defaultchecked = (
'nocodemirror' => 'off',
'daxecollapse' => 'off',
'domcoordacc' => 'on',
);
my @toggles = ('nocodemirror','daxecollapse','domcoordacc');
($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,
\%titles,$itemcount);
my %staticdefaults = (
'copyright' => 'default',
'sourceavail' => 'closed',
);
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my %currrights;
foreach my $item ('copyright','sourceavail') {
$currrights{$item} = $staticdefaults{$item};
if (ref($settings) eq 'HASH') {
if (exists($settings->{$item})) {
$currrights{$item} = $settings->{$item};
}
}
}
$datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.
'<span class="LC_nobreak">'.$titles{'copyright'}.
'</span></td><td class="LC_right_item">'.
&selectbox('copyright',$currrights{'copyright'},'',
\&Apache::loncommon::copyrightdescription,
(grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))).
'</td></tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.
'<span class="LC_nobreak">'.$titles{'sourceavail'}.
'</span></td><td class="LC_right_item">'.
&selectbox('sourceavail',$currrights{'sourceavail'},'',
\&Apache::loncommon::source_copyrightdescription,
(&Apache::loncommon::source_copyrightids)).
'</td></tr>'."\n";
} else {
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
my $curreditors;
my %staticdefaults = (
editors => ['edit','xml'],
authorquota => 500,
webdav => 0,
);
my $curreditors = $staticdefaults{'editors'};
if ((ref($settings) eq 'HASH') &&
(ref($settings->{'editors'}) eq 'ARRAY')) {
$curreditors = $settings->{'editors'};
} else {
$curreditors = $staticdefaults{'editors'};
}
my @editors = ('edit','xml','daxe');
$datatable = '<tr'.$css_class.'>'."\n".
'<td>'.$titles{'editors'}.'</td>'."\n".
'<td class="LC_left_item">'."\n".
'<span class="LC_nobreak">';
foreach my $editor (@editors) {
my $checked;
if (grep(/^\Q$editor\E$/,@{$curreditors})) {
$checked = ' checked="checked"';
}
$datatable .= '<label>'.
'<input type="checkbox" name="author_editors" '.
$checked.' value="'.$editor.'" '.
'onclick="javascript:checkEditors(this.form,'."'author_editors'".',this);" />'.
$titles{$editor}.'</label> ';
}
$datatable .= '</span>'."\n".'</td>'."\n".'</tr>'."\n";
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my @insttypes;
if (ref($types) eq 'ARRAY') {
@insttypes = @{$types};
}
my $typecount = 0;
my %domconf = &Apache::lonnet::get_dom('configuration',['quotas'],$dom);
my @items = ('webdav','authorquota');
my %quotas;
if (ref($domconf{'quotas'}) eq 'HASH') {
%quotas = %{$domconf{'quotas'}};
foreach my $item (@items) {
if (ref($quotas{$item}) eq 'HASH') {
foreach my $type (@insttypes,'default') {
if ($item eq 'authorquota') {
if ($quotas{$item}{$type} !~ /^\d+$/) {
$quotas{$item}{$type} = $staticdefaults{$item};
}
} elsif ($item eq 'webdav') {
if ($quotas{$item}{$type} !~ /^(0|1)$/) {
$quotas{$item}{$type} = $staticdefaults{$item};
}
}
}
} else {
foreach my $type (@insttypes,'default') {
$quotas{$item}{$type} = $staticdefaults{$item};
}
}
}
} else {
foreach my $item (@items) {
foreach my $type (@insttypes,'default') {
$quotas{$item}{$type} = $staticdefaults{$item};
}
}
}
if (ref($usertypes) eq 'HASH') {
my $numinrow = 4;
my $onclick = '';
$datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,
$numinrow,$othertitle,'authorquota',
\$itemcount,$onclick);
$itemcount ++;
$datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,
$numinrow,$othertitle,'webdav',
\$itemcount);
$itemcount ++;
}
my $checkedno = ' checked="checked"';
my ($checkedon,$checkedoff);
if (ref($quotas{'webdav'}) eq 'HASH') {
if ($quotas{'webdav'}{'_LC_adv'} =~ /^0|1$/) {
if ($quotas{'webdav'}{'_LC_adv'}) {
$checkedon = $checkedno;
} else {
$checkedoff = $checkedno;
}
undef($checkedno);
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$titles{'webdav_LC_adv'}.'<br />'.
$titles{'webdav_LC_adv_over'}.
'</td>'.
'<td class="LC_left_item">';
foreach my $option ('none','off','on') {
my ($text,$val,$checked);
if ($option eq 'none') {
$text = $titles{'none'};
$val = '';
$checked = $checkedno;
} elsif ($option eq 'off') {
$text = $titles{'overoff'};
$val = 0;
$checked = $checkedoff;
} elsif ($option eq 'on') {
$text = $titles{'overon'};
$val = 1;
$checked = $checkedon;
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="webdav_LC_adv"'.
' value="'.$val.'"'.$checked.' />'.
$text.'</label></span> ';
}
$datatable .= '</td></tr>';
$itemcount ++;
my %defchecked = (
'archive' => 'off',
);
my @toggles = ('archive');
(my $archive,$itemcount) = &radiobutton_prefs($settings,['archive'],
{'archive' => 'off'},
\%titles,$itemcount);
$datatable .= $archive."\n";
$itemcount ++;
}
$$rowtotal += $itemcount;
return $datatable;
}
sub authordefaults_titles {
return &Apache::lonlocal::texthash(
copyright => 'Copyright/Distribution',
sourceavail => ' Source Available',
editors => 'Available Editors',
webdav => 'WebDAV',
authorquota => 'Authoring Space quotas (MB)',
nocodemirror => 'Deactivate CodeMirror for EditXML editor',
daxecollapse => 'Daxe editor: LON-CAPA standard menus start collapsed',
domcoordacc => 'Dom. Coords. can enter Authoring Spaces in domain',
edit => 'Standard editor (Edit)',
xml => 'Text editor (EditXML)',
daxe => 'Daxe editor (Daxe)',
webdav_LC_adv => 'WebDAV access for LON-CAPA "advanced" users',
webdav_LC_adv_over => '(overrides access based on affiliation, if set)',
none => 'No override set',
overon => 'Override -- webDAV on',
overoff => 'Override -- webDAV off',
archive => 'Authors can download tar.gz file of Authoring Space',
);
}
sub selectbox {
my ($name,$value,$readonly,$functionref,@idlist)=@_;
my $selout = '<select name="'.$name.'">';
foreach my $id (@idlist) {
$selout.='<option value="'.$id.'"';
if ($id eq $value) {
$selout.=' selected="selected"';
}
if ($readonly) {
$selout .= ' disabled="disabled"';
}
$selout.='>'.&{$functionref}($id).'</option>';
}
$selout.='</select>';
return $selout;
}
sub print_selfenrollment {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable);
my $itemcount = 1;
my @types = ('official','unofficial','community','textbook','placement');
if (($position eq 'top') || ($position eq 'middle')) {
my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
my %descs = &Apache::lonuserutils::selfenroll_default_descs();
my @rows;
my $key;
if ($position eq 'top') {
$key = 'admin';
if (ref($rowsref) eq 'ARRAY') {
@rows = @{$rowsref};
}
} elsif ($position eq 'middle') {
$key = 'default';
@rows = ('types','registered','approval','limit');
}
foreach my $row (@rows) {
if (defined($titlesref->{$row})) {
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$titlesref->{$row}.'</td>'.
'<td class="LC_left_item">'.
'<table><tr>';
my (%current,%currentcap);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$key}) eq 'HASH') {
foreach my $type (@types) {
if (ref($settings->{$key}->{$type}) eq 'HASH') {
$current{$type} = $settings->{$key}->{$type}->{$row};
}
if (($row eq 'limit') && ($key eq 'default')) {
if (ref($settings->{$key}->{$type}) eq 'HASH') {
$currentcap{$type} = $settings->{$key}->{$type}->{'cap'};
}
}
}
}
}
my %roles = (
'0' => &Apache::lonnet::plaintext('dc'),
);
foreach my $type (@types) {
unless (($row eq 'registered') && ($key eq 'default')) {
$datatable .= '<th>'.&mt($type).'</th>';
}
}
unless (($row eq 'registered') && ($key eq 'default')) {
$datatable .= '</tr><tr>';
}
foreach my $type (@types) {
if ($type eq 'community') {
$roles{'1'} = &mt('Community personnel');
} else {
$roles{'1'} = &mt('Course personnel');
}
$datatable .= '<td style="vertical-align: top">';
if ($position eq 'top') {
my %checked;
if ($current{$type} eq '0') {
$checked{'0'} = ' checked="checked"';
} else {
$checked{'1'} = ' checked="checked"';
}
foreach my $role ('1','0') {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="selfenrolladmin_'.$row.'_'.$type.'" '.
'value="'.$role.'"'.$checked{$role}.' />'.
$roles{$role}.'</label></span> ';
}
} else {
if ($row eq 'types') {
my %checked;
if ($current{$type} =~ /^(all|dom)$/) {
$checked{$1} = ' checked="checked"';
} else {
$checked{''} = ' checked="checked"';
}
foreach my $val ('','dom','all') {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type ="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '.
'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> ';
}
} elsif ($row eq 'registered') {
my %checked;
if ($current{$type} eq '1') {
$checked{'1'} = ' checked="checked"';
} else {
$checked{'0'} = ' checked="checked"';
}
foreach my $val ('0','1') {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type ="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '.
'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> ';
}
} elsif ($row eq 'approval') {
my %checked;
if ($current{$type} =~ /^([12])$/) {
$checked{$1} = ' checked="checked"';
} else {
$checked{'0'} = ' checked="checked"';
}
for my $val (0..2) {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '.
'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> ';
}
} elsif ($row eq 'limit') {
my %checked;
if ($current{$type} =~ /^(allstudents|selfenrolled)$/) {
$checked{$1} = ' checked="checked"';
} else {
$checked{'none'} = ' checked="checked"';
}
my $cap;
if ($currentcap{$type} =~ /^\d+$/) {
$cap = $currentcap{$type};
}
foreach my $val ('none','allstudents','selfenrolled') {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '.
'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> ';
}
$datatable .= '<br />'.
'<span class="LC_nobreak">'.&mt('Maximum allowed: ').
'<input type="text" name="selfenrolldefault_cap_'.$type.'" size = "5" value="'.$cap.'" />'.
'</span>';
}
}
$datatable .= '</td>';
}
$datatable .= '</tr>';
}
$datatable .= '</table></td></tr>';
}
} elsif ($position eq 'bottom') {
$datatable .= &print_validation_rows('selfenroll',$dom,$settings,\$itemcount);
}
$$rowtotal += $itemcount;
return $datatable;
}
sub print_validation_rows {
my ($caller,$dom,$settings,$rowtotal) = @_;
my ($itemsref,$namesref,$fieldsref);
if ($caller eq 'selfenroll') {
($itemsref,$namesref,$fieldsref) = &Apache::lonuserutils::selfenroll_validation_types();
} elsif ($caller eq 'requestcourses') {
($itemsref,$namesref,$fieldsref) = &Apache::loncoursequeueadmin::requestcourses_validation_types();
}
my %currvalidation;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'validation'}) eq 'HASH') {
%currvalidation = %{$settings->{'validation'}};
}
}
my $datatable;
my $itemcount = 0;
foreach my $item (@{$itemsref}) {
my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
$namesref->{$item}.
'</span></td>'.
'<td class="LC_left_item">';
if (($item eq 'url') || ($item eq 'button')) {
$datatable .= '<span class="LC_nobreak">'.
'<input type="text" name="'.$caller.'_validation_'.$item.'"'.
' value="'.$currvalidation{$item}.'" size="50" /></span>';
} elsif ($item eq 'fields') {
my @currfields;
if (ref($currvalidation{$item}) eq 'ARRAY') {
@currfields = @{$currvalidation{$item}};
}
foreach my $field (@{$fieldsref}) {
my $check = '';
if (grep(/^\Q$field\E$/,@currfields)) {
$check = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$caller.'_validation_fields"'.
' value="'.$field.'"'.$check.' />'.$field.
'</label></span> ';
}
} elsif ($item eq 'markup') {
$datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5">'.
$currvalidation{$item}.
'</textarea>';
}
$datatable .= '</td></tr>'."\n";
if (ref($rowtotal)) {
$itemcount ++;
}
}
if ($caller eq 'requestcourses') {
my %currhash;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'validation'}) eq 'HASH') {
if ($settings->{'validation'}{'dc'} ne '') {
$currhash{$settings->{'validation'}{'dc'}} = 1;
}
}
}
my $numinrow = 2;
my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio',
'validationdc',%currhash);
my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'><td>';
if ($numdc > 1) {
$datatable .= &mt('Course creation processed as: (choose Dom. Coord.)');
} else {
$datatable .= &mt('Course creation processed as: ');
}
$datatable .= '</td><td class="LC_left_item">'.$dctable.'</td></tr>';
$itemcount ++;
}
if (ref($rowtotal)) {
$$rowtotal += $itemcount;
}
return $datatable;
}
sub print_privacy {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($datatable,$css_class,$numinrow,@items,%names,$othertitle,$usertypes,$types);
my $itemcount = 0;
if ($position eq 'top') {
$numinrow = 2;
} else {
@items = ('domain','author','course','community');
%names = &Apache::lonlocal::texthash (
domain => 'Assigned domain role(s)',
author => 'Assigned co-author role(s)',
course => 'Assigned course role(s)',
community => 'Assigned community role(s)',
);
$numinrow = 4;
($othertitle,$usertypes,$types) =
&Apache::loncommon::sorted_inst_types($dom);
}
if (($position eq 'top') || ($position eq 'middle')) {
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
if ($position eq 'top') {
my %curr;
my @options = ('none','user','domain','auto');
my %titles = &Apache::lonlocal::texthash (
none => 'Not allowed',
user => 'User authorizes',
domain => 'DC authorizes',
auto => 'Unrestricted',
instdom => 'Other domain shares institution/provider',
extdom => 'Other domain has different institution/provider',
notify => 'Notify when role needs authorization',
);
my %names = &Apache::lonlocal::texthash (
domain => 'Domain role',
author => 'Co-author role',
course => 'Course role',
community => 'Community role',
);
my $primary_id = &Apache::lonnet::domain($dom,'primary');
my $intdom = &Apache::lonnet::internet_dom($primary_id);
foreach my $domtype ('instdom','extdom') {
my (%checked,$skip);
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{$domtype}.'</td>'.
'<td class="LC_left_item">';
if ($domtype eq 'instdom') {
unless (@instdoms > 1) {
$datatable .= &mt('Nothing to set, as no domains besides [_1] are hosted by [_2]',$dom,$intdom);
$skip = 1;
}
} elsif ($domtype eq 'extdom') {
if (keys(%by_location) == 0) {
$datatable .= &mt('Nothing to set, as no other hosts besides [_1]',$intdom);
$skip = 1;
}
}
unless ($skip) {
foreach my $roletype ('domain','author','course','community') {
$checked{'auto'} = ' checked="checked"';
if (ref($settings) eq 'HASH') {
if (ref($settings->{approval}) eq 'HASH') {
if (ref($settings->{approval}->{$domtype}) eq 'HASH') {
if ($settings->{approval}->{$domtype}->{$roletype}=~ /^(none|user|domain)$/) {
$checked{$1} = ' checked="checked"';
$checked{'auto'} = '';
}
}
}
}
$datatable .= '<fieldset><legend>'.$names{$roletype}.'</legend>';
foreach my $option (@options) {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="privacy_approval_'.$domtype.'_'.$roletype.'" '.
'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
'</label></span> ';
}
$datatable .= '</fieldset>';
}
}
$datatable .= '</td></tr>';
$itemcount ++;
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'notify'}.'</td>'.
'<td class="LC_left_item">';
if ((@instdoms > 1) || (keys(%by_location) > 0)) {
my %curr;
if (ref($settings) eq 'HASH') {
if ($settings->{'notify'} ne '') {
map {$curr{$_}=1;} split(/,/,$settings->{'notify'});
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my ($numdc,$table,$rows) = &active_dc_picker($dom,$numinrow,'checkbox',
'privacy_notify',%curr);
if ($numdc > 0) {
$datatable .= $table;
} else {
$datatable .= &mt('There are no active Domain Coordinators');
}
} else {
$datatable .= &mt('Nothing to set here, as there are no other domains');
}
$datatable .='</td></tr>';
} elsif ($position eq 'middle') {
if ((@instdoms > 1) || (keys(%by_location) > 0)) {
if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
foreach my $item (@{$types}) {
$datatable .= &modifiable_userdata_row('privacy','othdom_'.$item,$settings,
$numinrow,$itemcount,'','','','','',
'',$usertypes->{$item});
$itemcount ++;
}
}
$datatable .= &modifiable_userdata_row('privacy','othdom_default',$settings,
$numinrow,$itemcount,'','','','','',
'',$othertitle);
$itemcount ++;
} else {
my (@insttypes,%insttitles);
if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
@insttypes = @{$types};
%insttitles = %{$usertypes};
}
foreach my $item (@insttypes,'default') {
my $title;
if ($item eq 'default') {
$title = $othertitle;
} else {
$title = $insttitles{$item};
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.$title.'</td>'.
'<td class="LC_left_item">'.
&mt('Nothing to set here, as there are no other domains').
'</td></tr>';
$itemcount ++;
}
}
}
} else {
my $prefix;
if ($position eq 'lower') {
$prefix = 'priv';
} else {
$prefix = 'unpriv';
}
foreach my $item (@items) {
$datatable .= &modifiable_userdata_row('privacy',$prefix.'_'.$item,$settings,
$numinrow,$itemcount,'','','','','',
'',$names{$item});
$itemcount ++;
}
}
if (ref($rowtotal)) {
$$rowtotal += $itemcount;
}
return $datatable;
}
sub print_passwords {
my ($position,$dom,$confname,$settings,$rowtotal) = @_;
my ($datatable,$css_class);
my $itemcount = 0;
my %titles = &Apache::lonlocal::texthash (
captcha => '"Forgot Password" CAPTCHA validation',
link => 'Reset link expiration (hours)',
case => 'Case-sensitive usernames/e-mail',
prelink => 'Information required (form 1)',
postlink => 'Information required (form 2)',
emailsrc => 'LON-CAPA e-mail address type(s)',
customtext => 'Domain specific text (HTML)',
intauth_cost => 'Encryption cost for bcrypt (positive integer)',
intauth_check => 'Check bcrypt cost if authenticated',
intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',
permanent => 'Permanent e-mail address',
critical => 'Critical notification address',
notify => 'Notification address',
min => 'Minimum password length',
max => 'Maximum password length',
chars => 'Required characters',
expire => 'Password expiration (days)',
numsaved => 'Number of previous passwords to save and disallow reuse',
);
if ($position eq 'top') {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my $shownlinklife = 2;
my $prelink = 'both';
my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl);
if (ref($settings) eq 'HASH') {
if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) {
$shownlinklife = $settings->{resetlink};
}
if (ref($settings->{resetcase}) eq 'ARRAY') {
map { $casesens{$_} = 1; } (@{$settings->{resetcase}});
}
if ($settings->{resetprelink} =~ /^(both|either)$/) {
$prelink = $settings->{resetprelink};
}
if (ref($settings->{resetpostlink}) eq 'HASH') {
%postlink = %{$settings->{resetpostlink}};
}
if (ref($settings->{resetemail}) eq 'ARRAY') {
map { $emailsrc{$_} = 1; } (@{$settings->{resetemail}});
}
if ($settings->{resetremove}) {
$nostdtext = 1;
}
if ($settings->{resetcustom}) {
$customurl = $settings->{resetcustom};
}
} else {
if (ref($types) eq 'ARRAY') {
foreach my $item (@{$types}) {
$casesens{$item} = 1;
$postlink{$item} = ['username','email'];
}
}
$casesens{'default'} = 1;
$postlink{'default'} = ['username','email'];
$prelink = 'both';
%emailsrc = (
permanent => 1,
critical => 1,
notify => 1,
);
}
$datatable = &captcha_choice('passwords',$settings,$$rowtotal);
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'link'}.'</td>'.
'<td class="LC_left_item">'.
'<input type="textbox" value="'.$shownlinklife.'" '.
'name="passwords_link" size="3" /></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'case'}.'</td>'.
'<td class="LC_left_item">';
if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
foreach my $item (@{$types}) {
my $checkedcase;
if ($casesens{$item}) {
$checkedcase = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="passwords_case_sensitive" value="'.
$item.'"'.$checkedcase.' />'.$usertypes->{$item}.'</label>'.
'</span> ';
}
}
my $checkedcase;
if ($casesens{'default'}) {
$checkedcase = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.
'name="passwords_case_sensitive" value="default"'.$checkedcase.' />'.
$othertitle.'</label></span></td>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my %checkedpre = (
both => ' checked="checked"',
either => '',
);
if ($prelink eq 'either') {
$checkedpre{either} = ' checked="checked"';
$checkedpre{both} = '';
}
$datatable .= '<tr'.$css_class.'><td>'.$titles{'prelink'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
'<label><input type="radio" name="passwords_prelink" value="both"'.$checkedpre{'both'}.' />'.
&mt('Both username and e-mail address').'</label></span> '.
'<span class="LC_nobreak"><label>'.
'<input type="radio" name="passwords_prelink" value="either"'.$checkedpre{'either'}.' />'.
&mt('Either username or e-mail address').'</label></span></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'postlink'}.'</td>'.
'<td class="LC_left_item">';
my %postlinked;
if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
foreach my $item (@{$types}) {
undef(%postlinked);
$datatable .= '<fieldset style="display: inline-block;">'.
'<legend>'.$usertypes->{$item}.'</legend>';
if (ref($postlink{$item}) eq 'ARRAY') {
map { $postlinked{$_} = 1; } (@{$postlink{$item}});
}
foreach my $field ('email','username') {
my $checked;
if ($postlinked{$field}) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="passwords_postlink_'.$item.'" value="'.
$field.'"'.$checked.' />'.$field.'</label>'.
'<span> ';
}
$datatable .= '</fieldset>';
}
}
if (ref($postlink{'default'}) eq 'ARRAY') {
map { $postlinked{$_} = 1; } (@{$postlink{'default'}});
}
$datatable .= '<fieldset style="display: inline-block;">'.
'<legend>'.$othertitle.'</legend>';
foreach my $field ('email','username') {
my $checked;
if ($postlinked{$field}) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="passwords_postlink_default" value="'.
$field.'"'.$checked.' />'.$field.'</label>'.
'<span> ';
}
$datatable .= '</fieldset></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'.
'<td class="LC_left_item">';
foreach my $type ('permanent','critical','notify') {
my $checkedemail;
if ($emailsrc{$type}) {
$checkedemail = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="passwords_emailsrc" value="'.
$type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'.
'<span> ';
}
$datatable .= '</td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $switchserver = &check_switchserver($dom,$confname);
my ($showstd,$noshowstd);
if ($nostdtext) {
$noshowstd = ' checked="checked"';
} else {
$showstd = ' checked="checked"';
}
$datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
&mt('Retain standard text:').
'<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'.
&mt('Yes').'</label>'.' '.
'<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'.
&mt('No').'</label></span><br />'.
'<span class="LC_fontsize_small">'.
&mt('(If you use the same account ... reset a password from this page.)').'</span><br /><br />'.
&mt('Include custom text:');
if ($customurl) {
my $link = &Apache::loncommon::modal_link($customurl,&mt('custom text'),600,500,
undef,undef,undef,undef,'background-color:#ffffff');
$datatable .= '<span class="LC_nobreak"> '.$link.
'<label><input type="checkbox" name="passwords_custom_del"'.
' value="1" />'.&mt('Delete?').'</label></span>'.
' <span class="LC_nobreak"> '.&mt('Replace:').'</span>';
}
if ($switchserver) {
$datatable .= '<span class="LC_nobreak"> '.&mt('Upload to library server: [_1]',$switchserver).'</span>';
} else {
$datatable .='<span class="LC_nobreak"> '.
'<input type="file" name="passwords_customfile" /></span>';
}
$datatable .= '</td></tr>';
} elsif ($position eq 'middle') {
my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom);
my @items = ('intauth_cost','intauth_check','intauth_switch');
my %defaults;
if (ref($domconf{'defaults'}) eq 'HASH') {
%defaults = %{$domconf{'defaults'}};
if ($defaults{'intauth_cost'} !~ /^\d+$/) {
$defaults{'intauth_cost'} = 10;
}
if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {
$defaults{'intauth_check'} = 0;
}
if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {
$defaults{'intauth_switch'} = 0;
}
} else {
%defaults = (
'intauth_cost' => 10,
'intauth_check' => 0,
'intauth_switch' => 0,
);
}
foreach my $item (@items) {
if ($itemcount%2) {
$css_class = '';
} else {
$css_class = ' class="LC_odd_row" ';
}
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.$titles{$item}.
'</span></td><td class="LC_left_item" colspan="3">';
if ($item eq 'intauth_switch') {
my @options = (0,1,2);
my %optiondesc = &Apache::lonlocal::texthash (
0 => 'No',
1 => 'Yes',
2 => 'Yes, and copy existing passwd file to passwd.bak file',
);
$datatable .= '<table width="100%">';
foreach my $option (@options) {
my $checked = ' ';
if ($defaults{$item} eq $option) {
$checked = ' checked="checked"';
}
$datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
'<label><input type="radio" name="'.$item.
'" value="'.$option.'"'.$checked.' />'.
$optiondesc{$option}.'</label></span></td></tr>';
}
$datatable .= '</table>';
} elsif ($item eq 'intauth_check') {
my @options = (0,1,2);
my %optiondesc = &Apache::lonlocal::texthash (
0 => 'No',
1 => 'Yes, allow login then update passwd file using default cost (if higher)',
2 => 'Yes, disallow login if stored cost is less than domain default',
);
$datatable .= '<table width="100%">';
foreach my $option (@options) {
my $checked = ' ';
my $onclick;
if ($defaults{$item} eq $option) {
$checked = ' checked="checked"';
}
if ($option == 2) {
$onclick = ' onclick="javascript:warnIntAuth(this);"';
}
$datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
'<label><input type="radio" name="'.$item.
'" value="'.$option.'"'.$checked.$onclick.' />'.
$optiondesc{$option}.'</label></span></td></tr>';
}
$datatable .= '</table>';
} else {
$datatable .= '<input type="text" name="'.$item.'" value="'.
$defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />';
}
$datatable .= '</td></tr>';
$itemcount ++;
}
} elsif ($position eq 'lower') {
$datatable .= &password_rules('passwords',\$itemcount,$settings);
} else {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my %ownerchg = (
by => {},
for => {},
);
my %ownertitles = &Apache::lonlocal::texthash (
by => 'Course owner status(es) allowed',
for => 'Student status(es) allowed',
);
if (ref($settings) eq 'HASH') {
if (ref($settings->{crsownerchg}) eq 'HASH') {
if (ref($settings->{crsownerchg}{'by'}) eq 'ARRAY') {
map { $ownerchg{by}{$_} = 1; } (@{$settings->{crsownerchg}{'by'}});
}
if (ref($settings->{crsownerchg}{'for'}) eq 'ARRAY') {
map { $ownerchg{for}{$_} = 1; } (@{$settings->{crsownerchg}{'for'}});
}
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr '.$css_class.'>'.
'<td>'.
&mt('Requirements').'<ul>'.
'<li>'.&mt("Course 'type' is not a Community or Placement Test").'</li>'.
'<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.
'<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.
'<li>'.&mt('User, course, and student share same domain').'</li>'.
'</ul>'.
'</td>'.
'<td class="LC_left_item">';
foreach my $item ('by','for') {
$datatable .= '<fieldset style="display: inline-block;">'.
'<legend>'.$ownertitles{$item}.'</legend>';
if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
foreach my $type (@{$types}) {
my $checked;
if ($ownerchg{$item}{$type}) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="passwords_crsowner_'.$item.'" value="'.
$type.'"'.$checked.' />'.$usertypes->{$type}.'</label>'.
'</span> ';
}
}
my $checked;
if ($ownerchg{$item}{'default'}) {
$checked = ' checked="checked"';
}
$datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.
'name="passwords_crsowner_'.$item.'" value="default"'.$checked.' />'.
$othertitle.'</label></span></fieldset>';
}
$datatable .= '</td></tr>';
}
return $datatable;
}
sub password_rules {
my ($prefix,$itemcountref,$settings) = @_;
my ($min,$max,%chars,$expire,$numsaved,$numinrow);
my %titles;
if ($prefix eq 'passwords') {
%titles = &Apache::lonlocal::texthash (
min => 'Minimum password length',
max => 'Maximum password length',
chars => 'Required characters',
);
} elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
%titles = &Apache::lonlocal::texthash (
min => 'Minimum secret length',
max => 'Maximum secret length',
chars => 'Required characters',
);
}
$min = $Apache::lonnet::passwdmin;
my $datatable;
my $itemcount;
if (ref($itemcountref)) {
$itemcount = $$itemcountref;
}
if (ref($settings) eq 'HASH') {
if ($settings->{min}) {
$min = $settings->{min};
}
if ($settings->{max}) {
$max = $settings->{max};
}
if (ref($settings->{chars}) eq 'ARRAY') {
map { $chars{$_} = 1; } (@{$settings->{chars}});
}
if ($prefix eq 'passwords') {
if ($settings->{expire}) {
$expire = $settings->{expire};
}
if ($settings->{numsaved}) {
$numsaved = $settings->{numsaved};
}
}
}
my %rulenames = &Apache::lonlocal::texthash(
uc => 'At least one upper case letter',
lc => 'At least one lower case letter',
num => 'At least one number',
spec => 'At least one non-alphanumeric',
);
my $css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
'<input type="text" name="'.$prefix.'_min" value="'.$min.'" size="3" '.
'onblur="javascript:warnInt'.$prefix.'(this);" />'.
'<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'.
'</span></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
'<input type="text" name="'.$prefix.'_max" value="'.$max.'" size="3" '.
'onblur="javascript:warnInt'.$prefix.'(this);" />'.
'<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
'</span></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
'<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
'</span></td>';
my $numinrow = 2;
my @possrules = ('uc','lc','num','spec');
$datatable .= '<td class="LC_left_item"><table>';
for (my $i=0; $i<@possrules; $i++) {
my ($rem,$checked);
if ($chars{$possrules[$i]}) {
$checked = ' checked="checked"';
}
$rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
$datatable .= '<td><span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'.
$rulenames{$possrules[$i]}.'</label></span></td>';
}
my $rem = @possrules%($numinrow);
my $colsleft = $numinrow - $rem;
if ($colsleft > 1 ) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$datatable .= '<td class="LC_left_item"> </td>';
}
$datatable .='</table></td></tr>';
$itemcount ++;
if ($prefix eq 'passwords') {
$titles{'expire'} = &mt('Password expiration (days)');
$titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
'<input type="text" name="'.$prefix.'_expire" value="'.$expire.'" size="4" '.
'onblur="javascript:warnInt'.$prefix.'(this);" />'.
'<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
'</span></td></tr>';
$itemcount ++;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
'<td class="LC_left_item"><span class="LC_nobreak">'.
'<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.
'onblur="javascript:warnInt'.$prefix.'(this);" />'.
'<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.
'</span></td></tr>';
$itemcount ++;
}
if (ref($itemcountref)) {
$$itemcountref += $itemcount;
}
return $datatable;
}
sub print_wafproxy {
my ($position,$dom,$settings,$rowtotal) = @_;
my $css_class;
my $itemcount = 0;
my $datatable;
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my (%othercontrol,%otherdoms,%aliases,%saml,%values,$setdom,$showdom);
my %lt = &wafproxy_titles();
foreach my $server (sort(keys(%servers))) {
my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
next if ($serverhome eq '');
my $serverdom;
if ($serverhome ne $server) {
$serverdom = &Apache::lonnet::host_domain($serverhome);
if (($serverdom ne '') && (&Apache::lonnet::domain($serverdom) ne '')) {
$othercontrol{$server} = $serverdom;
}
} else {
$serverdom = &Apache::lonnet::host_domain($server);
next if (($serverdom eq '') || (&Apache::lonnet::domain($serverdom) eq ''));
if ($serverdom ne $dom) {
$othercontrol{$server} = $serverdom;
} else {
$setdom = 1;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'alias'}) eq 'HASH') {
$aliases{$dom} = $settings->{'alias'};
if ($aliases{$dom} ne '') {
$showdom = 1;
}
}
if (ref($settings->{'saml'}) eq 'HASH') {
$saml{$dom} = $settings->{'saml'};
}
}
}
}
}
if ($setdom) {
%{$values{$dom}} = ();
if (ref($settings) eq 'HASH') {
foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {
$values{$dom}{$item} = $settings->{$item};
}
}
}
if (keys(%othercontrol)) {
%otherdoms = reverse(%othercontrol);
foreach my $domain (keys(%otherdoms)) {
%{$values{$domain}} = ();
my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain);
if (ref($config{'wafproxy'}) eq 'HASH') {
$aliases{$domain} = $config{'wafproxy'}{'alias'};
if (exists($config{'wafproxy'}{'saml'})) {
$saml{$domain} = $config{'wafproxy'}{'saml'};
}
foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') {
$values{$domain}{$item} = $config{'wafproxy'}{$item};
}
}
}
}
if ($position eq 'top') {
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %aliasinfo;
foreach my $server (sort(keys(%servers))) {
$itemcount ++;
my $dom_in_effect;
my $aliasrows = '<tr>'.
'<td class="LC_left_item" style="vertical-align: baseline;">'.
&mt('Hostname').': '.
'<span class="LC_nobreak LC_cusr_emph">'.
&Apache::lonnet::hostname($server).
'</span></td><td> </td>';
if ($othercontrol{$server}) {
$dom_in_effect = $othercontrol{$server};
my ($current,$forsaml);
if (ref($aliases{$dom_in_effect}) eq 'HASH') {
$current = $aliases{$dom_in_effect}{$server};
}
if (ref($saml{$dom_in_effect}) eq 'HASH') {
if ($saml{$dom_in_effect}{$server}) {
$forsaml = 1;
}
}
$aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'.
&mt('Alias').': ';
if ($current) {
$aliasrows .= $current;
if ($forsaml) {
$aliasrows .= ' ('.&mt('also for SSO Auth').')';
}
} else {
$aliasrows .= &mt('None');
}
$aliasrows .= ' <span class="LC_small">('.
&mt('controlled by domain: [_1]',
'<b>'.$dom_in_effect.'</b>').')</span></td>';
} else {
$dom_in_effect = $dom;
my ($current,$samlon,$samloff);
$samloff = ' checked="checked"';
if (ref($aliases{$dom}) eq 'HASH') {
if ($aliases{$dom}{$server}) {
$current = $aliases{$dom}{$server};
}
}
if (ref($saml{$dom}) eq 'HASH') {
if ($saml{$dom}{$server}) {
$samlon = $samloff;
undef($samloff);
}
}
$aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'.
&mt('Alias').': '.
'<input type="text" name="wafproxy_alias_'.$server.'" '.
'value="'.$current.'" size="30" />'.
(' 'x2).'<span class="LC_nobreak">'.
&mt('Alias used for SSO Auth').': <label>'.
'<input type="radio" value="0"'.$samloff.' name="wafproxy_alias_saml_'.$server.'" />'.
&mt('No').'</label> <label>'.
'<input type="radio" value="1"'.$samlon.' name="wafproxy_alias_saml_'.$server.'" />'.
&mt('Yes').'</label></span>'.
'</td>';
}
$aliasrows .= '</tr>';
$aliasinfo{$dom_in_effect} .= $aliasrows;
}
if ($aliasinfo{$dom}) {
my ($onclick,$wafon,$wafoff,$showtable);
$onclick = ' onclick="javascript:toggleWAF();"';
$wafoff = ' checked="checked"';
$showtable = ' style="display:none";';
if ($showdom) {
$wafon = $wafoff;
$wafoff = '';
$showtable = ' style="display:inline;"';
}
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable = '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br />'.
'<span class="LC_nobreak">'.&mt('WAF in use?').' <label>'.
'<input type="radio" name="wafproxy_'.$dom.'" value="1"'.$wafon.$onclick.' />'.
&mt('Yes').'</label>'.(' 'x2).'<label>'.
'<input type="radio" name="wafproxy_'.$dom.'" value="0"'.$wafoff.$onclick.' />'.
&mt('No').'</label></span></td>'.
'<td class="LC_left_item">'.
'<table id="wafproxy_table"'.$showtable.'>'.$aliasinfo{$dom}.
'</table></td></tr>';
$itemcount++;
}
if (keys(%otherdoms)) {
foreach my $key (sort(keys(%otherdoms))) {
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$key.'</b>').'</td>'.
'<td class="LC_left_item"><table>'.$aliasinfo{$key}.
'</table></td></tr>';
$itemcount++;
}
}
} else {
my %ip_methods = &remoteip_methods();
if ($setdom) {
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
my ($nowafstyle,$wafstyle,$curr_remotip,$currwafdisplay,$vpndircheck,$vpnaliascheck,
$currwafvpn,$wafrangestyle,$alltossl,$ssltossl);
$wafstyle = ' style="display:none;"';
$nowafstyle = ' style="display:table-row;"';
$currwafdisplay = ' style="display: none"';
$wafrangestyle = ' style="display: none"';
$curr_remotip = 'n';
$ssltossl = ' checked="checked"';
if ($showdom) {
$wafstyle = ' style="display:table-row;"';
$nowafstyle = ' style="display:none;"';
if (keys(%{$values{$dom}})) {
if ($values{$dom}{remoteip} =~ /^[nmh]$/) {
$curr_remotip = $values{$dom}{remoteip};
}
if ($curr_remotip eq 'h') {
$currwafdisplay = ' style="display:table-row"';
$wafrangestyle = ' style="display:inline-block;"';
}
if ($values{$dom}{'sslopt'}) {
$alltossl = ' checked="checked"';
$ssltossl = '';
}
}
if (($values{$dom}{'vpnint'} ne '') || ($values{$dom}{'vpnext'} ne '')) {
$vpndircheck = ' checked="checked"';
$currwafvpn = ' style="display:table-row;"';
$wafrangestyle = ' style="display:inline-block;"';
} else {
$vpnaliascheck = ' checked="checked"';
$currwafvpn = ' style="display:none;"';
}
}
$datatable .= '<tr'.$css_class.' id="nowafproxyrow_'.$dom.'"'.$wafstyle.'>'.
'<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'</td>'.
'<td class="LC_right_item">'.&mt('WAF not in use, nothing to set').'</td>'.
'</tr>'.
'<tr'.$css_class.' id="wafproxyrow_'.$dom.'"'.$wafstyle.'>'.
'<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'.
'<div id="wafproxyranges_'.$dom.'">'.&mt('Format for comma separated IP ranges').':<br />'.
&mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'.
&mt('Range(s) stored in CIDR notation').'</div></td>'.
'<td class="LC_left_item"><table>'.
'<tr>'.
'<td valign="top">'.$lt{'remoteip'}.': '.
'<select name="wafproxy_remoteip" id="wafproxy_remoteip" onchange="javascript:updateWAF();">';
foreach my $option ('m','h','n') {
my $sel;
if ($option eq $curr_remotip) {
$sel = ' selected="selected"';
}
$datatable .= '<option value="'.$option.'"'.$sel.'>'.
$ip_methods{$option}.'</option>';
}
$datatable .= '</select></td></tr>'."\n".
'<tr id="wafproxy_header"'.$currwafdisplay.'><td>'.
$lt{'ipheader'}.': '.
'<input type="text" value="'.$values{$dom}{'ipheader'}.'" '.
'name="wafproxy_ipheader" />'.
'</td></tr>'."\n".
'<tr id="wafproxy_trust"'.$currwafdisplay.'><td>'.
$lt{'trusted'}.':<br />'.
'<textarea name="wafproxy_trusted" rows="3" cols="80">'.
$values{$dom}{'trusted'}.'</textarea>'.
'</td></tr>'."\n".
'<tr><td><hr /></td></tr>'."\n".
'<tr>'.
'<td valign="top">'.$lt{'vpnaccess'}.':<br /><span class="LC_nobreak">'.
'<label><input type="radio" name="wafproxy_vpnaccess"'.$vpndircheck.' value="1" onclick="javascript:checkWAF();" />'.
$lt{'vpndirect'}.'</label>'.(' 'x2).
'<label><input type="radio" name="wafproxy_vpnaccess"'.$vpnaliascheck.' value="0" onclick="javascript:checkWAF();" />'.
$lt{'vpnaliased'}.'</label></span></td></tr>';
foreach my $item ('vpnint','vpnext') {
$datatable .= '<tr id="wafproxy_show_'.$item.'"'.$currwafvpn.'>'.
'<td valign="top">'.$lt{$item}.':<br />'.
'<textarea name="wafproxy_'.$item.'" rows="3" cols="80">'.
$values{$dom}{$item}.'</textarea>'.
'</td></tr>'."\n";
}
$datatable .= '<tr><td><hr /></td></tr>'."\n".
'<tr>'.
'<td valign="top">'.$lt{'sslopt'}.':<br /><span class="LC_nobreak">'.
'<label><input type="radio" name="wafproxy_sslopt"'.$alltossl.' value="1" />'.
$lt{'alltossl'}.'</label>'.(' 'x2).
'<label><input type="radio" name="wafproxy_sslopt"'.$ssltossl.' value="0" />'.
$lt{'ssltossl'}.'</label></span></td></tr>'."\n".
'</table></td></tr>';
}
if (keys(%otherdoms)) {
foreach my $domain (sort(keys(%otherdoms))) {
$itemcount ++;
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$domain.'</b>').'</td>'.
'<td class="LC_left_item"><table>';
foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
my $showval = &mt('None');
if ($item eq 'ssl') {
$showval = $lt{'ssltossl'};
}
if ($values{$domain}{$item}) {
$showval = $values{$domain}{$item};
if ($item eq 'ssl') {
$showval = $lt{'alltossl'};
} elsif ($item eq 'remoteip') {
$showval = $ip_methods{$values{$domain}{$item}};
}
}
$datatable .= '<tr>'.
'<td>'.$lt{$item}.': '.$showval.'</td></tr>';
}
$datatable .= '</table></td></tr>';
}
}
}
$$rowtotal += $itemcount;
return $datatable;
}
sub wafproxy_titles {
return &Apache::lonlocal::texthash(
remoteip => "Method for determining user's IP",
ipheader => 'Request header containing remote IP',
trusted => 'Trusted IP range(s)',
vpnaccess => 'Access from institutional VPN',
vpndirect => 'via regular hostname (no WAF)',
vpnaliased => 'via aliased hostname (WAF)',
vpnint => 'Internal IP Range(s) for VPN sessions',
vpnext => 'IP Range(s) for backend WAF connections',
sslopt => 'Forwarding http/https',
alltossl => 'WAF forwards both http and https requests to https',
ssltossl => 'WAF forwards http requests to http and https to https',
);
}
sub remoteip_methods {
return &Apache::lonlocal::texthash(
m => 'Use Apache mod_remoteip',
h => 'Use headers parsed by LON-CAPA',
n => 'Not in use',
);
}
sub print_usersessions {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable,$itemcount,%checked,%choices);
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my @alldoms = &Apache::lonnet::all_domains();
my %serverhomes = %Apache::lonnet::serverhomeIDs;
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %altids = &id_for_thisdom(%servers);
if ($position eq 'top') {
if (keys(%serverhomes) > 1) {
my %spareid = ¤t_offloads_to($dom,$settings,\%servers);
my ($curroffloadnow,$curroffloadoth);
if (ref($settings) eq 'HASH') {
if (ref($settings->{'offloadnow'}) eq 'HASH') {
$curroffloadnow = $settings->{'offloadnow'};
}
if (ref($settings->{'offloadoth'}) eq 'HASH') {
$curroffloadoth = $settings->{'offloadoth'};
}
}
my $other_insts = scalar(keys(%by_location));
$datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,
$other_insts,$curroffloadnow,$curroffloadoth,$rowtotal);
} else {
$datatable .= '<tr'.$css_class.'><td colspan="2">'.
&mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.').
'</td></tr>';
}
} else {
my %titles = &usersession_titles();
my ($prefix,@types);
if ($position eq 'bottom') {
$prefix = 'remote';
@types = ('version','excludedomain','includedomain');
} else {
$prefix = 'hosted';
@types = ('excludedomain','includedomain');
}
($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
}
$$rowtotal += $itemcount;
return $datatable;
}
sub rules_by_location {
my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_;
my ($datatable,$itemcount,$css_class);
if (keys(%{$by_location}) == 0) {
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable = '<tr'.$css_class.'><td colspan="2">'.
&mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').
'</td></tr>';
$itemcount = 1;
} else {
$itemcount = 0;
my $numinrow = 5;
my (%current,%checkedon,%checkedoff);
my @locations = sort(keys(%{$by_location}));
foreach my $type (@{$types}) {
$checkedon{$type} = '';
$checkedoff{$type} = ' checked="checked"';
}
if (ref($settings) eq 'HASH') {
if (ref($settings->{$prefix}) eq 'HASH') {
foreach my $key (keys(%{$settings->{$prefix}})) {
$current{$key} = $settings->{$prefix}{$key};
if ($key eq 'version') {
if ($current{$key} ne '') {
$checkedon{$key} = ' checked="checked"';
$checkedoff{$key} = '';
}
} elsif (ref($current{$key}) eq 'ARRAY') {
$checkedon{$key} = ' checked="checked"';
$checkedoff{$key} = '';
}
}
}
}
foreach my $type (@{$types}) {
next if ($type ne 'version' && !@locations);
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'>
<td><span class="LC_nobreak">'.$titles->{$type}.'</span><br />
<span class="LC_nobreak">
<label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>
<label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
if ($type eq 'version') {
my @lcversions = &Apache::lonnet::all_loncaparevs();
my $selector = '<select name="'.$prefix.'_version">';
foreach my $version (@lcversions) {
my $selected = '';
if ($current{'version'} eq $version) {
$selected = ' selected="selected"';
}
$selector .= ' <option value="'.$version.'"'.
$selected.'>'.$version.'</option>';
}
$selector .= '</select> ';
$datatable .= &mt('remote server must be version: [_1] or later',$selector);
} else {
$datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
' />'.(' 'x2).
'<input type="button" value="'.&mt('uncheck all').'" '.
'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
"\n".
'</div><div><table>';
my $rem;
for (my $i=0; $i<@locations; $i++) {
my ($showloc,$value,$checkedtype);
if (ref($by_location->{$locations[$i]}) eq 'ARRAY') {
my $ip = $by_location->{$locations[$i]}->[0];
if (ref($by_ip->{$ip}) eq 'ARRAY') {
$value = join(':',@{$by_ip->{$ip}});
$showloc = join(', ',@{$by_ip->{$ip}});
if (ref($current{$type}) eq 'ARRAY') {
foreach my $loc (@{$by_ip->{$ip}}) {
if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
$checkedtype = ' checked="checked"';
last;
}
}
}
}
}
$rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
$datatable .= '<td class="LC_left_item">'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$prefix.'_'.$type.
'" value="'.$value.'"'.$checkedtype.' />'.$showloc.
'</label></span></td>';
}
$rem = @locations%($numinrow);
my $colsleft = $numinrow - $rem;
if ($colsleft > 1 ) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$datatable .= '<td class="LC_left_item"> </td>';
}
$datatable .= '</tr></table>';
}
$datatable .= '</td></tr>';
$itemcount ++;
}
}
return ($datatable,$itemcount);
}
sub print_ssl {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable);
my $itemcount = 1;
if ($position eq 'top') {
my $primary_id = &Apache::lonnet::domain($dom,'primary');
my $intdom = &Apache::lonnet::internet_dom($primary_id);
my $same_institution;
if ($intdom ne '') {
my $internet_names = &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
if (ref($internet_names) eq 'ARRAY') {
if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
$same_institution = 1;
}
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable = '<tr'.$css_class.'><td colspan="2">';
if ($same_institution) {
my %domservers = &Apache::lonnet::get_servers($dom);
$datatable .= &LONCAPA::SSL::print_certstatus(\%domservers,'web','domprefs');
} else {
$datatable .= &mt("You need to be logged into one of your own domain's servers to display information about the status of LON-CAPA SSL certificates.");
}
$datatable .= '</td></tr>';
$itemcount ++;
} else {
my %titles = &ssl_titles();
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my @alldoms = &Apache::lonnet::all_domains();
my %serverhomes = %Apache::lonnet::serverhomeIDs;
my @domservers = &Apache::lonnet::get_servers($dom);
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %altids = &id_for_thisdom(%servers);
if (($position eq 'connto') || ($position eq 'connfrom')) {
my $legacy;
unless (ref($settings) eq 'HASH') {
my $name;
if ($position eq 'connto') {
$name = 'loncAllowInsecure';
} else {
$name = 'londAllowInsecure';
}
my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
my @ids=&Apache::lonnet::current_machine_ids();
if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) {
my %what = (
$name => 1,
);
my ($result,$returnhash) =
&Apache::lonnet::get_remote_globals($primarylibserv,\%what);
if ($result eq 'ok') {
if (ref($returnhash) eq 'HASH') {
$legacy = $returnhash->{$name};
}
}
} else {
$legacy = $Apache::lonnet::perlvar{$name};
}
}
foreach my $type ('dom','intdom','other') {
my %checked;
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$titles{$type}.'</td>'.
'<td class="LC_right_item">';
my $skip;
if ($type eq 'dom') {
unless (keys(%servers) > 1) {
$datatable .= &mt('Nothing to set here, as there are no other servers/VMs');
$skip = 1;
}
}
if ($type eq 'intdom') {
unless (@instdoms > 1) {
$datatable .= &mt('Nothing to set here, as there are no other domains for this institution');
$skip = 1;
}
} elsif ($type eq 'other') {
if (keys(%by_location) == 0) {
$datatable .= &mt('Nothing to set here, as there are no other institutions');
$skip = 1;
}
}
unless ($skip) {
$checked{'yes'} = ' checked="checked"';
if (ref($settings) eq 'HASH') {
if (ref($settings->{$position}) eq 'HASH') {
if ($settings->{$position}->{$type} =~ /^(no|req)$/) {
$checked{$1} = $checked{'yes'};
delete($checked{'yes'});
}
}
} else {
if ($legacy == 0) {
$checked{'req'} = $checked{'yes'};
delete($checked{'yes'});
}
}
foreach my $option ('no','yes','req') {
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="'.$position.'_'.$type.'" '.
'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
'</label></span>'.(' 'x2);
}
}
$datatable .= '</td></tr>';
$itemcount ++;
}
} else {
my $prefix = 'replication';
my @types = ('certreq','nocertreq');
if (keys(%by_location) == 0) {
$datatable .= '<tr'.$css_class.'><td>'.
&mt('Nothing to set here, as there are no other institutions').
'</td></tr>';
$itemcount ++;
} else {
($datatable,$itemcount) =
&rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
}
}
}
$$rowtotal += $itemcount;
return $datatable;
}
sub ssl_titles {
return &Apache::lonlocal::texthash (
dom => 'LON-CAPA servers/VMs from same domain',
intdom => 'LON-CAPA servers/VMs from same "internet" domain',
other => 'External LON-CAPA servers/VMs',
connto => 'Connections to other servers',
connfrom => 'Connections from other servers',
replication => 'Replicating content to other institutions',
certreq => 'Client certificate required, but specific domains exempt',
nocertreq => 'No client certificate required, except for specific domains',
no => 'SSL not used',
yes => 'SSL Optional (used if available)',
req => 'SSL Required',
);
}
sub print_trust {
my ($prefix,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable,%checked,%choices);
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my $itemcount = 1;
my %titles = &trust_titles();
my @types = ('exc','inc');
if ($prefix eq 'top') {
$prefix = 'content';
} elsif ($prefix eq 'bottom') {
$prefix = 'msg';
}
($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
$$rowtotal += $itemcount;
return $datatable;
}
sub trust_titles {
return &Apache::lonlocal::texthash(
content => "Access to this domain's content by others",
shared => "Access to other domain's content by this domain",
enroll => "Enrollment in this domain's courses by others",
othcoau => "Co-author roles in this domain for others",
coaurem => "Co-author roles for this domain's users elsewhere",
domroles => "Domain roles in this domain assignable to others",
catalog => "Course Catalog for this domain displayed elsewhere",
reqcrs => "Requests for creation of courses in this domain by others",
msg => "Users in other domains can send messages to this domain",
exc => "Allow all, but exclude specific domains",
inc => "Deny all, but include specific domains",
);
}
sub build_location_hashes {
my ($intdoms,$by_ip,$by_location,$instdoms) = @_;
return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&
(ref($by_location) eq 'HASH') && (ref($instdoms) eq 'ARRAY'));
my %iphost = &Apache::lonnet::get_iphost();
my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');
my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
if (ref($iphost{$primary_ip}) eq 'ARRAY') {
foreach my $id (@{$iphost{$primary_ip}}) {
my $intdom = &Apache::lonnet::internet_dom($id);
unless(grep(/^\Q$intdom\E$/,@{$intdoms})) {
push(@{$intdoms},$intdom);
}
}
}
foreach my $ip (keys(%iphost)) {
if (ref($iphost{$ip}) eq 'ARRAY') {
foreach my $id (@{$iphost{$ip}}) {
my $location = &Apache::lonnet::internet_dom($id);
if ($location) {
if (grep(/^\Q$location\E$/,@{$intdoms})) {
my $dom = &Apache::lonnet::host_domain($id);
unless (grep(/^\Q$dom\E/,@{$instdoms})) {
push(@{$instdoms},$dom);
}
next;
}
if (ref($by_ip->{$ip}) eq 'ARRAY') {
unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {
push(@{$by_ip->{$ip}},$location);
}
} else {
$by_ip->{$ip} = [$location];
}
}
}
}
}
foreach my $ip (sort(keys(%{$by_ip}))) {
if (ref($by_ip->{$ip}) eq 'ARRAY') {
@{$by_ip->{$ip}} = sort(@{$by_ip->{$ip}});
my $first = $by_ip->{$ip}->[0];
if (ref($by_location->{$first}) eq 'ARRAY') {
unless (grep(/^\Q$ip\E$/,@{$by_location->{$first}})) {
push(@{$by_location->{$first}},$ip);
}
} else {
$by_location->{$first} = [$ip];
}
}
}
return;
}
sub current_offloads_to {
my ($dom,$settings,$servers) = @_;
my (%spareid,%otherdomconfigs);
if (ref($servers) eq 'HASH') {
foreach my $lonhost (sort(keys(%{$servers}))) {
my $gotspares;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'spares'}) eq 'HASH') {
if (ref($settings->{'spares'}{$lonhost}) eq 'HASH') {
$spareid{$lonhost}{'primary'} = $settings->{'spares'}{$lonhost}{'primary'};
$spareid{$lonhost}{'default'} = $settings->{'spares'}{$lonhost}{'default'};
$gotspares = 1;
}
}
}
unless ($gotspares) {
my $gotspares;
my $serverhomeID =
&Apache::lonnet::get_server_homeID($servers->{$lonhost});
my $serverhomedom =
&Apache::lonnet::host_domain($serverhomeID);
if ($serverhomedom ne $dom) {
if (ref($otherdomconfigs{$serverhomedom} eq 'HASH')) {
if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') {
if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') {
$spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'};
$spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'};
$gotspares = 1;
}
}
} else {
$otherdomconfigs{$serverhomedom} =
&Apache::lonnet::get_dom('configuration',['usersessions'],$serverhomedom);
if (ref($otherdomconfigs{$serverhomedom}) eq 'HASH') {
if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') {
if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') {
if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{$lonhost}) eq 'HASH') {
$spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'};
$spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'};
$gotspares = 1;
}
}
}
}
}
}
}
unless ($gotspares) {
if ($lonhost eq $Apache::lonnet::perlvar{'lonHostID'}) {
$spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'};
$spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'};
} else {
my $server_hostname = &Apache::lonnet::hostname($lonhost);
my $server_homeID = &Apache::lonnet::get_server_homeID($server_hostname);
if ($server_homeID eq $Apache::lonnet::perlvar{'lonHostID'}) {
$spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'};
$spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'};
} else {
my %what = (
spareid => 1,
);
my ($result,$returnhash) =
&Apache::lonnet::get_remote_globals($lonhost,\%what);
if ($result eq 'ok') {
if (ref($returnhash) eq 'HASH') {
if (ref($returnhash->{'spareid'}) eq 'HASH') {
$spareid{$lonhost}{'primary'} = $returnhash->{'spareid'}->{'primary'};
$spareid{$lonhost}{'default'} = $returnhash->{'spareid'}->{'default'};
}
}
}
}
}
}
}
}
return %spareid;
}
sub spares_row {
my ($dom,$servers,$spareid,$serverhomes,$altids,$other_insts,
$curroffloadnow,$curroffloadoth,$rowtotal) = @_;
my $css_class;
my $numinrow = 4;
my $itemcount = 1;
my $datatable;
my %typetitles = &sparestype_titles();
if ((ref($servers) eq 'HASH') && (ref($spareid) eq 'HASH') && (ref($altids) eq 'HASH')) {
foreach my $server (sort(keys(%{$servers}))) {
my $serverhome = &Apache::lonnet::get_server_homeID($servers->{$server});
my ($othercontrol,$serverdom);
if ($serverhome ne $server) {
$serverdom = &Apache::lonnet::host_domain($serverhome);
$othercontrol = &mt('Session offloading controlled by domain: [_1]','<b>'.$serverdom.'</b>');
} else {
$serverdom = &Apache::lonnet::host_domain($server);
if ($serverdom ne $dom) {
$othercontrol = &mt('Session offloading controlled by domain: [_1]','<b>'.$serverdom.'</b>');
}
}
next unless (ref($spareid->{$server}) eq 'HASH');
my ($checkednow,$checkedoth);
if (ref($curroffloadnow) eq 'HASH') {
if ($curroffloadnow->{$server}) {
$checkednow = ' checked="checked"';
}
}
if (ref($curroffloadoth) eq 'HASH') {
if ($curroffloadoth->{$server}) {
$checkedoth = ' checked="checked"';
}
}
$css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
$datatable .= '<tr'.$css_class.'>
<td rowspan="2">
<span class="LC_nobreak">'.
&mt('[_1] when busy, offloads to:'
,'<b>'.$server.'</b>').'</span><br />'.
'<span class="LC_nobreak">'."\n".
'<label><input type="checkbox" name="offloadnow" value="'.$server.'"'.$checkednow.' />'.
' '.&mt('Switch any active user on next access').'</label></span>'.
"\n";
if ($other_insts) {
$datatable .= '<br />'.
'<span class="LC_nobreak">'."\n".
'<label><input type="checkbox" name="offloadoth" value="'.$server.'"'.$checkedoth.' />'.
' '.&mt('Switch other institutions on next access').'</label></span>'.
"\n";
}
my (%current,%canselect);
my @choices =
&possible_newspares($server,$spareid->{$server},$serverhomes,$altids);
foreach my $type ('primary','default') {
if (ref($spareid->{$server}) eq 'HASH') {
if (ref($spareid->{$server}{$type}) eq 'ARRAY') {
my @spares = @{$spareid->{$server}{$type}};
if (@spares > 0) {
if ($othercontrol) {
$current{$type} = join(', ',@spares);
} else {
$current{$type} .= '<table>';
my $numspares = scalar(@spares);
for (my $i=0; $i<@spares; $i++) {
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$current{$type} .= '</tr>';
}
$current{$type} .= '<tr>';
}
$current{$type} .= '<td><label><input type="checkbox" name="spare_'.$type.'_'.$server.'" id="spare_'.$type.'_'.$server.'_'.$i.'" checked="checked" value="'.$spareid->{$server}{$type}[$i].'" onclick="updateNewSpares(this.form,'."'$server'".');" /> '.
$spareid->{$server}{$type}[$i].
'</label></td>'."\n";
}
my $rem = @spares%($numinrow);
my $colsleft = $numinrow - $rem;
if ($colsleft > 1 ) {
$current{$type} .= '<td colspan="'.$colsleft.
'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$current{$type} .= '<td class="LC_left_item"> </td>'."\n";
}
$current{$type} .= '</tr></table>';
}
}
}
if ($current{$type} eq '') {
$current{$type} = &mt('None specified');
}
if ($othercontrol) {
if ($type eq 'primary') {
$canselect{$type} = $othercontrol;
}
} else {
$canselect{$type} =
&mt('Add new [_1]'.$type.'[_2]:','<i>','</i>').' '.
'<select name="newspare_'.$type.'_'.$server.'" '.
'id="newspare_'.$type.'_'.$server.'" onchange="checkNewSpares('."'$server','$type'".');">'."\n".
'<option value="" selected ="selected">'.&mt('Select').'</option>'."\n";
if (@choices > 0) {
foreach my $lonhost (@choices) {
$canselect{$type} .= '<option value="'.$lonhost.'">'.$lonhost.'</option>'."\n";
}
}
$canselect{$type} .= '</select>'."\n";
}
} else {
$current{$type} = &mt('Could not be determined');
if ($type eq 'primary') {
$canselect{$type} = $othercontrol;
}
}
if ($type eq 'default') {
$datatable .= '<tr'.$css_class.'>';
}
$datatable .= '<td><i>'.$typetitles{$type}.'</i></td>'."\n".
'<td>'.$current{$type}.'</td>'."\n".
'<td>'.$canselect{$type}.'</td></tr>'."\n";
}
$itemcount ++;
}
}
$$rowtotal += $itemcount;
return $datatable;
}
sub possible_newspares {
my ($server,$currspares,$serverhomes,$altids) = @_;
my $serverhostname = &Apache::lonnet::hostname($server);
my %excluded;
if ($serverhostname ne '') {
%excluded = (
$serverhostname => 1,
);
}
if (ref($currspares) eq 'HASH') {
foreach my $type (keys(%{$currspares})) {
if (ref($currspares->{$type}) eq 'ARRAY') {
if (@{$currspares->{$type}} > 0) {
foreach my $curr (@{$currspares->{$type}}) {
my $hostname = &Apache::lonnet::hostname($curr);
$excluded{$hostname} = 1;
}
}
}
}
}
my @choices;
if ((ref($serverhomes) eq 'HASH') && (ref($altids) eq 'HASH')) {
if (keys(%{$serverhomes}) > 1) {
foreach my $name (sort(keys(%{$serverhomes}))) {
unless ($excluded{$name}) {
if (exists($altids->{$serverhomes->{$name}})) {
push(@choices,$altids->{$serverhomes->{$name}});
} else {
push(@choices,$serverhomes->{$name});
}
}
}
}
}
return sort(@choices);
}
sub print_loadbalancing {
my ($dom,$settings,$rowtotal) = @_;
my $primary_id = &Apache::lonnet::domain($dom,'primary');
my $intdom = &Apache::lonnet::internet_dom($primary_id);
my $numinrow = 1;
my $datatable;
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);
if (ref($settings) eq 'HASH') {
%existing = %{$settings};
}
if ((keys(%servers) > 1) || (keys(%existing) > 0)) {
&get_loadbalancers_config(\%servers,\%existing,\%currbalancer,
\%currtargets,\%currrules,\%currcookies);
} else {
return;
}
my ($othertitle,$usertypes,$types) =
&Apache::loncommon::sorted_inst_types($dom);
my $rownum = 8;
if (ref($types) eq 'ARRAY') {
$rownum += scalar(@{$types});
}
my @css_class = ('LC_odd_row','LC_even_row');
my $balnum = 0;
my $islast;
my (@toshow,$disabledtext);
if (keys(%currbalancer) > 0) {
@toshow = sort(keys(%currbalancer));
if (scalar(@toshow) < scalar(keys(%servers)) + 1) {
push(@toshow,'');
}
} else {
@toshow = ('');
$disabledtext = &mt('No existing load balancer');
}
foreach my $lonhost (@toshow) {
if ($balnum == scalar(@toshow)-1) {
$islast = 1;
} else {
$islast = 0;
}
my $cssidx = $balnum%2;
my $targets_div_style = 'display: none';
my $disabled_div_style = 'display: block';
my $homedom_div_style = 'display: none';
$datatable .= '<tr class="'.$css_class[$cssidx].'">'.
'<td rowspan="'.$rownum.'" style="vertical-align: top">'.
'<p>';
if ($lonhost eq '') {
$datatable .= '<span class="LC_nobreak">';
if (keys(%currbalancer) > 0) {
$datatable .= &mt('Add balancer:');
} else {
$datatable .= &mt('Enable balancer:');
}
$datatable .= ' '.
'<select name="loadbalancing_lonhost_'.$balnum.'"'.
' id="loadbalancing_lonhost_'.$balnum.'"'.
' onchange="toggleTargets('."'$balnum'".');">'."\n".
'<option value="" selected="selected">'.&mt('None').
'</option>'."\n";
foreach my $server (sort(keys(%servers))) {
next if ($currbalancer{$server});
$datatable .= '<option value="'.$server.'">'.$server.'</option>'."\n";
}
$datatable .=
'</select>'."\n".
'<input type="hidden" name="loadbalancing_prevlonhost_'.$balnum.'" id="loadbalancing_prevlonhost_'.$balnum.'" value="" /> </span>'."\n";
} else {
$datatable .= '<i>'.$lonhost.'</i><br /><span class="LC_nobreak">'.
'<label><input type="checkbox" name="loadbalancing_delete" value="'.$balnum.'" id="loadbalancing_delete_'.$balnum.'" onclick="javascript:balancerDeleteChange('."'$balnum'".');" /> '.
&mt('Stop balancing').'</label>'.
'<input type="hidden" name="loadbalancing_lonhost_'.$balnum.'" value="'.$lonhost.'" id="loadbalancing_lonhost_'.$balnum.'" /></span>';
$targets_div_style = 'display: block';
$disabled_div_style = 'display: none';
if ($dom eq &Apache::lonnet::host_domain($lonhost)) {
$homedom_div_style = 'display: block';
}
}
$datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'.
'<div id="loadbalancing_disabled_'.$balnum.'" style="'.
$disabled_div_style.'">'.$disabledtext.'</div>'."\n".
'<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';
my ($numspares,@spares) = &count_servers($lonhost,%servers);
my @sparestypes = ('primary','default');
my %typetitles = &sparestype_titles();
my %hostherechecked = (
no => ' checked="checked"',
);
my %balcookiechecked = (
no => ' checked="checked"',
);
foreach my $sparetype (@sparestypes) {
my $targettable;
for (my $i=0; $i<$numspares; $i++) {
my $checked;
if (ref($currtargets{$lonhost}) eq 'HASH') {
if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') {
if (grep(/^\Q$spares[$i]\E$/,@{$currtargets{$lonhost}{$sparetype}})) {
$checked = ' checked="checked"';
}
}
}
my ($chkboxval,$disabled);
if (($lonhost ne '') && (exists($servers{$lonhost}))) {
$chkboxval = $spares[$i];
}
if (exists($currbalancer{$spares[$i]})) {
$disabled = ' disabled="disabled"';
}
$targettable .=
'<td><span class="LC_nobreak"><label>'.
'<input type="checkbox" name="loadbalancing_target_'.$balnum.'_'.$sparetype.'"'.
$checked.$disabled.' value="'.$chkboxval.'" id="loadbalancing_target_'.$balnum.'_'.$sparetype.'_'.$i.'" onclick="checkOffloads('."this,'$balnum','$sparetype'".');" /><span id="loadbalancing_targettxt_'.$balnum.'_'.$sparetype.'_'.$i.'"> '.$chkboxval.
'</span></label></span></td>';
my $rem = $i%($numinrow);
if ($rem == 0) {
if (($i > 0) && ($i < $numspares-1)) {
$targettable .= '</tr>';
}
if ($i < $numspares-1) {
$targettable .= '<tr>';
}
}
}
if ($targettable ne '') {
my $rem = $numspares%($numinrow);
my $colsleft = $numinrow - $rem;
if ($colsleft > 1 ) {
$targettable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$targettable .= '<td class="LC_left_item"> </td>';
}
$datatable .= '<i>'.$typetitles{$sparetype}.'</i><br />'.
'<table><tr>'.$targettable.'</tr></table><br />';
}
$hostherechecked{$sparetype} = '';
if (ref($currtargets{$lonhost}) eq 'HASH') {
if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') {
if (grep(/^\Q$lonhost\E$/,@{$currtargets{$lonhost}{$sparetype}})) {
$hostherechecked{$sparetype} = ' checked="checked"';
$hostherechecked{'no'} = '';
}
}
}
}
if ($currcookies{$lonhost}) {
%balcookiechecked = (
yes => ' checked="checked"',
);
}
$datatable .= &mt('Hosting on balancer itself').'<br />'.
'<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'.
$hostherechecked{'no'}.' />'.&mt('No').'</label><br />';
foreach my $sparetype (@sparestypes) {
$datatable .= '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" '.
'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}.
'</i></label><br />';
}
$datatable .= &mt('Use balancer cookie').'<br />'.
'<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="1"'.
$balcookiechecked{'yes'}.' />'.&mt('Yes').'</label><br />'.
'<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="0"'.
$balcookiechecked{'no'}.' />'.&mt('No').'</label><br />'.
'</div></td></tr>'.
&loadbalancing_rules($dom,$intdom,$currrules{$lonhost},
$othertitle,$usertypes,$types,\%servers,
\%currbalancer,$lonhost,
$targets_div_style,$homedom_div_style,
$css_class[$cssidx],$balnum,$islast);
$$rowtotal += $rownum;
$balnum ++;
}
$datatable .= '<input type="hidden" name="loadbalancing_total" id="loadbalancing_total" value="'.$balnum.'" />';
return $datatable;
}
sub get_loadbalancers_config {
my ($servers,$existing,$currbalancer,$currtargets,$currrules,$currcookies) = @_;
return unless ((ref($servers) eq 'HASH') &&
(ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') &&
(ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH') &&
(ref($currcookies) eq 'HASH'));
if (keys(%{$existing}) > 0) {
my $oldlonhost;
foreach my $key (sort(keys(%{$existing}))) {
if ($key eq 'lonhost') {
$oldlonhost = $existing->{'lonhost'};
$currbalancer->{$oldlonhost} = 1;
} elsif ($key eq 'targets') {
if ($oldlonhost) {
$currtargets->{$oldlonhost} = $existing->{'targets'};
}
} elsif ($key eq 'rules') {
if ($oldlonhost) {
$currrules->{$oldlonhost} = $existing->{'rules'};
}
} elsif (ref($existing->{$key}) eq 'HASH') {
$currbalancer->{$key} = 1;
$currtargets->{$key} = $existing->{$key}{'targets'};
$currrules->{$key} = $existing->{$key}{'rules'};
if ($existing->{$key}{'cookie'}) {
$currcookies->{$key} = 1;
}
}
}
} else {
my ($balancerref,$targetsref) =
&Apache::lonnet::get_lonbalancer_config($servers);
if ((ref($balancerref) eq 'HASH') && (ref($targetsref) eq 'HASH')) {
foreach my $server (sort(keys(%{$balancerref}))) {
$currbalancer->{$server} = 1;
$currtargets->{$server} = $targetsref->{$server};
}
}
}
return;
}
sub loadbalancing_rules {
my ($dom,$intdom,$currrules,$othertitle,$usertypes,$types,$servers,
$currbalancer,$lonhost,$targets_div_style,$homedom_div_style,
$css_class,$balnum,$islast) = @_;
my $output;
my $num = 0;
my ($alltypes,$othertypes,$titles) =
&loadbalancing_titles($dom,$intdom,$usertypes,$types);
if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) {
foreach my $type (@{$alltypes}) {
$num ++;
my $current;
if (ref($currrules) eq 'HASH') {
$current = $currrules->{$type};
}
if (($type eq '_LC_external') || ($type eq '_LC_internetdom')) {
if ($dom ne &Apache::lonnet::host_domain($lonhost)) {
$current = '';
}
}
$output .= &loadbalance_rule_row($type,$titles->{$type},$current,
$servers,$currbalancer,$lonhost,$dom,
$targets_div_style,$homedom_div_style,
$css_class,$balnum,$num,$islast);
}
}
return $output;
}
sub loadbalancing_titles {
my ($dom,$intdom,$usertypes,$types) = @_;
my %othertypes = (
'_LC_adv' => &mt('Advanced users from [_1]',$dom),
'_LC_author' => &mt('Users from [_1] with author role',$dom),
'_LC_internetdom' => &mt('Users not from [_1], but from [_2]',$dom,$intdom),
'_LC_external' => &mt('Users not from [_1]',$intdom),
'_LC_ipchangesso' => &mt('SSO users from [_1], with IP mismatch',$dom),
'_LC_ipchange' => &mt('Non-SSO users with IP mismatch'),
);
my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange');
my @available;
if (ref($types) eq 'ARRAY') {
@available = @{$types};
}
unless (grep(/^default$/,@available)) {
push(@available,'default');
}
unshift(@alltypes,@available);
my %titles;
foreach my $type (@alltypes) {
if ($type =~ /^_LC_/) {
$titles{$type} = $othertypes{$type};
} elsif ($type eq 'default') {
$titles{$type} = &mt('All users from [_1]',$dom);
if (ref($types) eq 'ARRAY') {
if (@{$types} > 0) {
$titles{$type} = &mt('Other users from [_1]',$dom);
}
}
} elsif (ref($usertypes) eq 'HASH') {
$titles{$type} = $usertypes->{$type};
}
}
return (\@alltypes,\%othertypes,\%titles);
}
sub loadbalance_rule_row {
my ($type,$title,$current,$servers,$currbalancer,$lonhost,$dom,
$targets_div_style,$homedom_div_style,$css_class,$balnum,$num,$islast) = @_;
my @rulenames;
my %ruletitles = &offloadtype_text();
if (($type eq '_LC_ipchangesso') || ($type eq '_LC_ipchange')) {
@rulenames = ('balancer','offloadedto','specific');
} else {
@rulenames = ('default','homeserver');
if ($type eq '_LC_external') {
push(@rulenames,'externalbalancer');
} else {
push(@rulenames,'specific');
}
push(@rulenames,'none');
}
my $style = $targets_div_style;
if (($type eq '_LC_external') || ($type eq '_LC_internetdom')) {
$style = $homedom_div_style;
}
my $space;
if ($islast && $num == 1) {
$space = '<div style="display:inline-block;"> </div>';
}
my $output =
'<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td style="vertical-align: top">'.$space.
'<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".
'<td valaign="top">'.$space.
'<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";
for (my $i=0; $i<@rulenames; $i++) {
my $rule = $rulenames[$i];
my ($checked,$extra);
if ($rulenames[$i] eq 'default') {
$rule = '';
}
if ($rulenames[$i] eq 'specific') {
if (ref($servers) eq 'HASH') {
my $default;
if (($current ne '') && (exists($servers->{$current}))) {
$checked = ' checked="checked"';
}
unless ($checked) {
$default = ' selected="selected"';
}
$extra =
': <select name="loadbalancing_singleserver_'.$balnum.'_'.$type.
'" id="loadbalancing_singleserver_'.$balnum.'_'.$type.
'" onchange="singleServerToggle('."'$balnum','$type'".')">'."\n".
'<option value=""'.$default.'></option>'."\n";
foreach my $server (sort(keys(%{$servers}))) {
if (ref($currbalancer) eq 'HASH') {
next if (exists($currbalancer->{$server}));
}
my $selected;
if ($server eq $current) {
$selected = ' selected="selected"';
}
$extra .= '<option value="'.$server.'"'.$selected.'>'.$server.'</option>';
}
$extra .= '</select>';
}
} elsif ($rule eq $current) {
$checked = ' checked="checked"';
}
$output .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="loadbalancing_rules_'.$balnum.'_'.$type.
'" id="loadbalancing_rules_'.$balnum.'_'.$type.'_'.$i.'" value="'.
$rule.'" onclick="balanceruleChange('."this.form,'$balnum','$type'".
')"'.$checked.' /> ';
if (($rulenames[$i] eq 'specific') && ($type =~ /^_LC_ipchange/)) {
$output .= $ruletitles{'particular'};
} else {
$output .= $ruletitles{$rulenames[$i]};
}
$output .= '</label>'.$extra.'</span><br />'."\n";
}
$output .= '</div></td></tr>'."\n";
return $output;
}
sub offloadtype_text {
my %ruletitles = &Apache::lonlocal::texthash (
'default' => 'Offloads to default destinations',
'homeserver' => "Offloads to user's home server",
'externalbalancer' => "Offloads to Load Balancer in user's domain",
'specific' => 'Offloads to specific server',
'none' => 'No offload',
'balancer' => 'Session hosted on Load Balancer, after re-authentication',
'offloadedto' => 'Session hosted on offload server, after re-authentication',
'particular' => 'Session hosted (after re-auth) on server:',
);
return %ruletitles;
}
sub sparestype_titles {
my %typestitles = &Apache::lonlocal::texthash (
'primary' => 'primary',
'default' => 'default',
);
return %typestitles;
}
sub contact_titles {
my %titles = &Apache::lonlocal::texthash (
'supportemail' => 'Support E-mail address',
'adminemail' => 'Default Server Admin E-mail address',
'errormail' => 'Error reports to be e-mailed to',
'packagesmail' => 'Package update alerts to be e-mailed to',
'helpdeskmail' => "Helpdesk requests from all users in this domain",
'otherdomsmail' => 'Helpdesk requests from users in other (unconfigured) domains',
'lonstatusmail' => 'E-mail from nightly status check (warnings/errors)',
'requestsmail' => 'E-mail from course requests requiring approval',
'updatesmail' => 'E-mail from nightly check of LON-CAPA module integrity/updates',
'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID',
'hostipmail' => 'E-mail from nightly check of hostname/IP network changes',
'errorthreshold' => 'Error count threshold for status e-mail to admin(s)',
'errorsysmail' => 'Error count threshold for e-mail to developer group',
'errorweights' => 'Weights used to compute error count',
'errorexcluded' => 'Servers with unsent updates excluded from count',
);
my %short_titles = &Apache::lonlocal::texthash (
adminemail => 'Admin E-mail address',
supportemail => 'Support E-mail',
);
return (\%titles,\%short_titles);
}
sub helpform_fields {
my %titles = &Apache::lonlocal::texthash (
'username' => 'Name',
'user' => 'Username/domain',
'phone' => 'Phone',
'cc' => 'Cc e-mail',
'course' => 'Course Details',
'section' => 'Sections',
'screenshot' => 'File upload',
);
my @fields = ('username','phone','user','course','section','cc','screenshot');
my %possoptions = (
username => ['yes','no','req'],
phone => ['yes','no','req'],
user => ['yes','no'],
cc => ['yes','no'],
course => ['yes','no'],
section => ['yes','no'],
screenshot => ['yes','no'],
);
my %fieldoptions = &Apache::lonlocal::texthash (
'yes' => 'Optional',
'req' => 'Required',
'no' => "Not shown",
);
return (\@fields,\%titles,\%fieldoptions,\%possoptions);
}
sub tool_titles {
my %titles = &Apache::lonlocal::texthash (
aboutme => 'Personal web page',
blog => 'Blog',
portfolio => 'Portfolio',
portaccess => 'Share portfolio files',
timezone => 'Can set time zone',
official => 'Official courses (with institutional codes)',
unofficial => 'Unofficial courses',
community => 'Communities',
textbook => 'Textbook courses',
placement => 'Placement tests',
);
return %titles;
}
sub courserequest_titles {
my %titles = &Apache::lonlocal::texthash (
official => 'Official',
unofficial => 'Unofficial',
community => 'Communities',
textbook => 'Textbook',
placement => 'Placement tests',
lti => 'LTI Provider',
norequest => 'Not allowed',
approval => 'Approval by DC',
validate => 'With validation',
autolimit => 'Numerical limit',
unlimited => '(blank for unlimited)',
);
return %titles;
}
sub authorrequest_titles {
my %titles = &Apache::lonlocal::texthash (
norequest => 'Not allowed',
approval => 'Approval by Dom. Coord.',
automatic => 'Automatic approval',
);
return %titles;
}
sub courserequest_conditions {
my %conditions = &Apache::lonlocal::texthash (
approval => '(Processing of request subject to approval by Domain Coordinator).',
validate => '(Processing of request subject to institutional validation).',
);
return %conditions;
}
sub print_usercreation {
my ($position,$dom,$settings,$rowtotal) = @_;
my $numinrow = 4;
my $datatable;
if ($position eq 'top') {
$$rowtotal ++;
my $rowcount = 0;
my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($dom,'username');
if (ref($rules) eq 'HASH') {
if (keys(%{$rules}) > 0) {
$datatable .= &user_formats_row('username',$settings,$rules,
$ruleorder,$numinrow,$rowcount);
$$rowtotal ++;
$rowcount ++;
}
}
my ($idrules,$idruleorder) = &Apache::lonnet::inst_userrules($dom,'id');
if (ref($idrules) eq 'HASH') {
if (keys(%{$idrules}) > 0) {
$datatable .= &user_formats_row('id',$settings,$idrules,
$idruleorder,$numinrow,$rowcount);
$$rowtotal ++;
$rowcount ++;
}
}
if ($rowcount == 0) {
$datatable .= '<tr><td colspan="2">'.&mt('No format rules have been defined for usernames or IDs in this domain.').'</td></tr>';
$$rowtotal ++;
$rowcount ++;
}
} elsif ($position eq 'middle') {
my @creators = ('author','course','requestcrs');
my ($rules,$ruleorder) =
&Apache::lonnet::inst_userrules($dom,'username');
my %lt = &usercreation_types();
my %checked;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'cancreate'}) eq 'HASH') {
foreach my $item (@creators) {
$checked{$item} = $settings->{'cancreate'}{$item};
}
} elsif (ref($settings->{'cancreate'}) eq 'ARRAY') {
foreach my $item (@creators) {
if (grep(/^\Q$item\E$/,@{$settings->{'cancreate'}})) {
$checked{$item} = 'none';
}
}
}
}
my $rownum = 0;
foreach my $item (@creators) {
$rownum ++;
if ($checked{$item} eq '') {
$checked{$item} = 'any';
}
my $css_class;
if ($rownum%2) {
$css_class = '';
} else {
$css_class = ' class="LC_odd_row" ';
}
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.$lt{$item}.
'</span></td><td style="text-align: right">';
my @options = ('any');
if (ref($rules) eq 'HASH') {
if (keys(%{$rules}) > 0) {
push(@options,('official','unofficial'));
}
}
push(@options,'none');
foreach my $option (@options) {
my $type = 'radio';
my $check = ' ';
if ($checked{$item} eq $option) {
$check = ' checked="checked" ';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="'.$type.'" name="can_createuser_'.
$item.'" value="'.$option.'"'.$check.'/> '.
$lt{$option}.'</label> </span>';
}
$datatable .= '</td></tr>';
}
} else {
my @contexts = ('author','course','domain');
my @authtypes = ('int','krb4','krb5','loc','lti');
my %checked;
if (ref($settings) eq 'HASH') {
if (ref($settings->{'authtypes'}) eq 'HASH') {
foreach my $item (@contexts) {
if (ref($settings->{'authtypes'}{$item}) eq 'HASH') {
foreach my $auth (@authtypes) {
if ($settings->{'authtypes'}{$item}{$auth}) {
$checked{$item}{$auth} = ' checked="checked" ';
}
}
}
}
}
} else {
foreach my $item (@contexts) {
foreach my $auth (@authtypes) {
$checked{$item}{$auth} = ' checked="checked" ';
}
}
}
my %title = &context_names();
my %authname = &authtype_names();
my $rownum = 0;
my $css_class;
foreach my $item (@contexts) {
if ($rownum%2) {
$css_class = '';
} else {
$css_class = ' class="LC_odd_row" ';
}
$datatable .= '<tr'.$css_class.'>'.
'<td>'.$title{$item}.
'</td><td class="LC_left_item">'.
'<span class="LC_nobreak">';
foreach my $auth (@authtypes) {
$datatable .= '<label>'.
'<input type="checkbox" name="'.$item.'_auth" '.
$checked{$item}{$auth}.' value="'.$auth.'" />'.
$authname{$auth}.'</label> ';
}
$datatable .= '</span></td></tr>';
$rownum ++;
}
$$rowtotal += $rownum;
}
return $datatable;
}
sub print_selfcreation {
my ($position,$dom,$settings,$rowtotal) = @_;
my (@selfcreate,$createsettings,$processing,$emailoptions,$emailverified,
$emaildomain,$datatable);
if (ref($settings) eq 'HASH') {
if (ref($settings->{'cancreate'}) eq 'HASH') {
$createsettings = $settings->{'cancreate'};
if (ref($createsettings) eq 'HASH') {
if (ref($createsettings->{'selfcreate'}) eq 'ARRAY') {
@selfcreate = @{$createsettings->{'selfcreate'}};
} elsif ($createsettings->{'selfcreate'} ne '') {
if ($settings->{'cancreate'}{'selfcreate'} eq 'any') {
@selfcreate = ('email','login','sso');
} elsif ($createsettings->{'selfcreate'} ne 'none') {
@selfcreate = ($createsettings->{'selfcreate'});
}
}
if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') {
$processing = $createsettings->{'selfcreateprocessing'};
}
if (ref($createsettings->{'emailoptions'}) eq 'HASH') {
$emailoptions = $createsettings->{'emailoptions'};
}
if (ref($createsettings->{'emailverified'}) eq 'HASH') {
$emailverified = $createsettings->{'emailverified'};
}
if (ref($createsettings->{'emaildomain'}) eq 'HASH') {
$emaildomain = $createsettings->{'emaildomain'};
}
}
}
}
my %radiohash;
my $numinrow = 4;
map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate;
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
if ($position eq 'top') {
my %choices = &Apache::lonlocal::texthash (
cancreate_login => 'Institutional Login',
cancreate_sso => 'Institutional Single Sign On',
);
my @toggles = sort(keys(%choices));
my %defaultchecked = (
'cancreate_login' => 'off',
'cancreate_sso' => 'off',
);
my ($onclick,$itemcount);
($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,
\%choices,$itemcount,$onclick);
$$rowtotal += $itemcount;
if (ref($usertypes) eq 'HASH') {
if (keys(%{$usertypes}) > 0) {
$datatable .= &insttypes_row($createsettings,$types,$usertypes,
$dom,$numinrow,$othertitle,
'statustocreate',$rowtotal);
$$rowtotal ++;
}
}
my @fields = ('lastname','firstname','middlename','permanentemail','id','inststatus');
my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
$fieldtitles{'inststatus'} = &mt('Institutional status');
my $rem;
my $numperrow = 2;
my $css_class = $$rowtotal%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'.
'<td class="LC_left_item">'."\n".
'<table>'."\n";
for (my $i=0; $i<@fields; $i++) {
$rem = $i%($numperrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
my $currval;
if (ref($createsettings) eq 'HASH') {
if (ref($createsettings->{'shibenv'}) eq 'HASH') {
$currval = $createsettings->{'shibenv'}{$fields[$i]};
}
}
$datatable .= '<td class="LC_left_item">'.
'<span class="LC_nobreak">'.
'<input type="text" name="shibenv_'.$fields[$i].'" '.
'value="'.$currval.'" size="10" /> '.
$fieldtitles{$fields[$i]}.'</span></td>';
}
my $colsleft = $numperrow - $rem;
if ($colsleft > 1 ) {
$datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$datatable .= '<td class="LC_left_item"> </td>';
}
$datatable .= '</tr></table></td></tr>';
$$rowtotal ++;
} elsif ($position eq 'middle') {
my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom);
my @posstypes;
if (ref($types) eq 'ARRAY') {
@posstypes = @{$types};
}
unless (grep(/^default$/,@posstypes)) {
push(@posstypes,'default');
}
my %usertypeshash;
if (ref($usertypes) eq 'HASH') {
%usertypeshash = %{$usertypes};
}
$usertypeshash{'default'} = $othertitle;
foreach my $status (@posstypes) {
$datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'},
$numinrow,$$rowtotal,\%usertypeshash);
$$rowtotal ++;
}
} else {
my %choices = &Apache::lonlocal::texthash (
'cancreate_email' => 'Non-institutional username (via e-mail verification)',
);
my @toggles = sort(keys(%choices));
my %defaultchecked = (
'cancreate_email' => 'off',
);
my $customclass = 'LC_selfcreate_email';
my $classprefix = 'LC_canmodify_emailusername_';
my $optionsprefix = 'LC_options_emailusername_';
my $display = 'none';
my $rowstyle = 'display:none';
if (grep(/^\Qemail\E$/,@selfcreate)) {
$display = 'block';
$rowstyle = 'display:table-row';
}
my $onclick = "toggleRows(this.form,'cancreate_email','selfassign','$customclass','$classprefix','$optionsprefix');";
($datatable,$$rowtotal) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked,
\%choices,$$rowtotal,$onclick);
$datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal,$customclass,
$rowstyle);
$$rowtotal ++;
$datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal,$customclass,
$rowstyle);
$$rowtotal ++;
my (@ordered,@posstypes,%usertypeshash);
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
my ($emailrules,$emailruleorder) =
&Apache::lonnet::inst_userrules($dom,'email');
my $primary_id = &Apache::lonnet::domain($dom,'primary');
my $intdom = &Apache::lonnet::internet_dom($primary_id);
if (ref($types) eq 'ARRAY') {
@posstypes = @{$types};
}
if (@posstypes) {
unless (grep(/^default$/,@posstypes)) {
push(@posstypes,'default');
}
if (ref($usertypes) eq 'HASH') {
%usertypeshash = %{$usertypes};
}
my $currassign;
if (ref($domdefaults{'inststatusguest'}) eq 'ARRAY') {
$currassign = {
selfassign => $domdefaults{'inststatusguest'},
};
@ordered = @{$domdefaults{'inststatusguest'}};
} else {
$currassign = { selfassign => [] };
}
my $onclicktypes = "toggleDataRow(this.form,'selfassign','$customclass','$optionsprefix',);".
"toggleDataRow(this.form,'selfassign','$customclass','$classprefix',1);";
$datatable .= &insttypes_row($currassign,$types,$usertypes,$dom,
$numinrow,$othertitle,'selfassign',
$rowtotal,$onclicktypes,$customclass,
$rowstyle);
$$rowtotal ++;
$usertypeshash{'default'} = $othertitle;
foreach my $status (@posstypes) {
my $css_class;
if ($$rowtotal%2) {
$css_class = 'LC_odd_row ';
}
$css_class .= $customclass;
my $rowid = $optionsprefix.$status;
my $hidden = 1;
my $currstyle = 'display:none';
if (grep(/^\Q$status\E$/,@ordered)) {
$currstyle = $rowstyle;
$hidden = 0;
}
$datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,
$emailrules,$emailruleorder,$settings,$status,$rowid,
$usertypeshash{$status},$css_class,$currstyle,$intdom);
unless ($hidden) {
$$rowtotal ++;
}
}
} else {
my $css_class;
if ($$rowtotal%2) {
$css_class = 'LC_odd_row ';
}
$css_class .= $customclass;
$usertypeshash{'default'} = $othertitle;
$datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain,
$emailrules,$emailruleorder,$settings,'default','',
$othertitle,$css_class,$rowstyle,$intdom);
$$rowtotal ++;
}
my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();
$numinrow = 1;
if (@posstypes) {
foreach my $status (@posstypes) {
my $rowid = $classprefix.$status;
my $datarowstyle = 'display:none';
if (grep(/^\Q$status\E$/,@ordered)) {
$datarowstyle = $rowstyle;
}
$datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings,
$numinrow,$$rowtotal,\%usertypeshash,$infofields,
$infotitles,$rowid,$customclass,$datarowstyle);
unless ($datarowstyle eq 'display:none') {
$$rowtotal ++;
}
}
} else {
$datatable .= &modifiable_userdata_row('cancreate','emailusername_default',$settings,
$numinrow,$$rowtotal,\%usertypeshash,$infofields,
$infotitles,'',$customclass,$rowstyle);
}
}
return $datatable;
}
sub selfcreate_javascript {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleRows(form,radio,checkbox,target,prefix,altprefix) {
var x = document.getElementsByClassName(target);
var insttypes = 0;
var insttypeRegExp = new RegExp(prefix);
if ((x.length != undefined) && (x.length > 0)) {
if (form.elements[radio].length != undefined) {
for (var i=0; i<form.elements[radio].length; i++) {
if (form.elements[radio][i].checked) {
if (form.elements[radio][i].value == 1) {
for (var j=0; j<x.length; j++) {
if (x[j].id == 'undefined') {
x[j].style.display = 'table-row';
} else if (insttypeRegExp.test(x[j].id)) {
insttypes ++;
} else {
x[j].style.display = 'table-row';
}
}
} else {
for (var j=0; j<x.length; j++) {
x[j].style.display = 'none';
}
}
break;
}
}
if (insttypes > 0) {
toggleDataRow(form,checkbox,target,altprefix);
toggleDataRow(form,checkbox,target,prefix,1);
}
}
}
return;
}
function toggleDataRow(form,checkbox,target,prefix,docount) {
if (form.elements[checkbox].length != undefined) {
var count = 0;
if (docount) {
for (var i=0; i<form.elements[checkbox].length; i++) {
if (form.elements[checkbox][i].checked) {
count ++;
}
}
}
for (var i=0; i<form.elements[checkbox].length; i++) {
var type = form.elements[checkbox][i].value;
if (document.getElementById(prefix+type)) {
if (form.elements[checkbox][i].checked) {
document.getElementById(prefix+type).style.display = 'table-row';
if (count % 2 == 1) {
document.getElementById(prefix+type).className = target+' LC_odd_row';
} else {
document.getElementById(prefix+type).className = target;
}
count ++;
} else {
document.getElementById(prefix+type).style.display = 'none';
}
}
}
}
return;
}
function toggleEmailOptions(form,radio,prefix,altprefix,status) {
var caller = radio+'_'+status;
if (form.elements[caller].length != undefined) {
for (var i=0; i<form.elements[caller].length; i++) {
if (form.elements[caller][i].checked) {
if (document.getElementById(altprefix+'_inst_'+status)) {
var curr = form.elements[caller][i].value;
if (prefix) {
document.getElementById(prefix+'_'+status).style.display = 'none';
}
document.getElementById(altprefix+'_inst_'+status).style.display = 'none';
document.getElementById(altprefix+'_noninst_'+status).style.display = 'none';
if (curr == 'custom') {
if (prefix) {
document.getElementById(prefix+'_'+status).style.display = 'inline';
}
} else if (curr == 'inst') {
document.getElementById(altprefix+'_inst_'+status).style.display = 'inline';
} else if (curr == 'noninst') {
document.getElementById(altprefix+'_noninst_'+status).style.display = 'inline';
}
break;
}
}
}
}
}
// ]]>
</script>
ENDSCRIPT
}
sub noninst_users {
my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules,
$emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_;
my $class = 'LC_left_item';
if ($css_class) {
$css_class = ' class="'.$css_class.'"';
}
if ($rowid) {
$rowid = ' id="'.$rowid.'"';
}
if ($rowstyle) {
$rowstyle = ' style="'.$rowstyle.'"';
}
my ($output,$description);
if ($type eq 'default') {
$description = &mt('Requests for: [_1]',$typetitle);
} else {
$description = &mt('Requests for: [_1] (status self-reported)',$typetitle);
}
$output = '<tr'.$css_class.$rowid.$rowstyle.'>'.
"<td>$description</td>\n".
'<td class="'.$class.'" colspan="2">'.
'<table><tr>';
my %headers = &Apache::lonlocal::texthash(
approve => 'Processing',
email => 'E-mail',
username => 'Username',
);
foreach my $item ('approve','email','username') {
$output .= '<th>'.$headers{$item}.'</th>';
}
$output .= '</tr><tr>';
foreach my $item ('approve','email','username') {
$output .= '<td style="vertical-align: top">';
my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);
if ($item eq 'approve') {
%choices = &Apache::lonlocal::texthash (
automatic => 'Automatically approved',
approval => 'Queued for approval',
);
@options = ('automatic','approval');
$hashref = $processing;
$defoption = 'automatic';
$name = 'cancreate_emailprocess_'.$type;
} elsif ($item eq 'email') {
%choices = &Apache::lonlocal::texthash (
any => 'Any e-mail',
inst => 'Institutional only',
noninst => 'Non-institutional only',
custom => 'Custom restrictions',
);
@options = ('any','inst','noninst');
my $showcustom;
if (ref($emailrules) eq 'HASH') {
if (keys(%{$emailrules}) > 0) {
push(@options,'custom');
$showcustom = 'cancreate_emailrule';
if (ref($settings) eq 'HASH') {
if (ref($settings->{'email_rule'}) eq 'ARRAY') {
foreach my $rule (@{$settings->{'email_rule'}}) {
if (exists($emailrules->{$rule})) {
$hascustom ++;
}
}
} elsif (ref($settings->{'email_rule'}) eq 'HASH') {
if (ref($settings->{'email_rule'}{$type}) eq 'ARRAY') {
foreach my $rule (@{$settings->{'email_rule'}{$type}}) {
if (exists($emailrules->{$rule})) {
$hascustom ++;
}
}
}
}
}
}
}
$onclick = ' onclick="toggleEmailOptions(this.form,'."'cancreate_emailoptions','$showcustom',".
"'cancreate_emaildomain','$type'".');"';
$hashref = $emailoptions;
$defoption = 'any';
$name = 'cancreate_emailoptions_'.$type;
} elsif ($item eq 'username') {
%choices = &Apache::lonlocal::texthash (
all => 'Same as e-mail',
first => 'Omit @domain',
free => 'Free to choose',
);
@options = ('all','first','free');
$hashref = $emailverified;
$defoption = 'all';
$name = 'cancreate_usernameoptions_'.$type;
}
foreach my $option (@options) {
my $checked;
if (ref($hashref) eq 'HASH') {
if ($type eq '') {
if (!exists($hashref->{'default'})) {
if ($option eq $defoption) {
$checked = ' checked="checked"';
}
} else {
if ($hashref->{'default'} eq $option) {
$checked = ' checked="checked"';
}
}
} else {
if (!exists($hashref->{$type})) {
if ($option eq $defoption) {
$checked = ' checked="checked"';
}
} else {
if ($hashref->{$type} eq $option) {
$checked = ' checked="checked"';
}
}
}
} elsif (($item eq 'email') && ($hascustom)) {
if ($option eq 'custom') {
$checked = ' checked="checked"';
}
} elsif ($option eq $defoption) {
$checked = ' checked="checked"';
}
$output .= '<span class="LC_nobreak"><label>'.
'<input type="radio" name="'.$name.'"'.
$checked.' value="'.$option.'"'.$onclick.' />'.
$choices{$option}.'</label></span><br />';
if ($item eq 'email') {
if ($option eq 'custom') {
my $id = 'cancreate_emailrule_'.$type;
my $display = 'none';
if ($checked) {
$display = 'inline';
}
my $numinrow = 2;
$output .= '<fieldset id="'.$id.'" style="display:'.$display.';">'.
'<legend>'.&mt('Disallow').'</legend><table>'.
&user_formats_row('email',$settings,$emailrules,
$emailruleorder,$numinrow,'',$type);
'</table></fieldset>';
} elsif (($option eq 'inst') || ($option eq 'noninst')) {
my %text = &Apache::lonlocal::texthash (
inst => 'must end:',
noninst => 'cannot end:',
);
my $value;
if (ref($emaildomain) eq 'HASH') {
if (ref($emaildomain->{$type}) eq 'HASH') {
$value = $emaildomain->{$type}->{$option};
}
}
if ($value eq '') {
$value = '@'.$intdom;
}
my $condition = 'cancreate_emaildomain_'.$option.'_'.$type;
my $display = 'none';
if ($checked) {
$display = 'inline';
}
$output .= '<div id="'.$condition.'" style="display:'.$display.';">'.
'<span class="LC_domprefs_email">'.$text{$option}.'</span> '.
'<input type="text" name="'.$condition.'" value="'.$value.'" size="10" />'.
'</div>';
}
}
}
$output .= '</td>'."\n";
}
$output .= "</tr></table></td></tr>\n";
return $output;
}
sub captcha_choice {
my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_;
my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext,
$vertext,$currver);
my %lt = &captcha_phrases();
$keyentry = 'hidden';
my $colspan=2;
if ($context eq 'cancreate') {
$rowname = &mt('CAPTCHA validation');
} elsif ($context eq 'login') {
$rowname = &mt('"Contact helpdesk" CAPTCHA validation');
} elsif ($context eq 'passwords') {
$rowname = &mt('"Forgot Password" CAPTCHA validation');
$colspan=1;
}
if (ref($settings) eq 'HASH') {
if ($settings->{'captcha'}) {
$checked{$settings->{'captcha'}} = ' checked="checked"';
} else {
$checked{'original'} = ' checked="checked"';
}
if ($settings->{'captcha'} eq 'recaptcha') {
$pubtext = $lt{'pub'};
$privtext = $lt{'priv'};
$keyentry = 'text';
$vertext = $lt{'ver'};
$currver = $settings->{'recaptchaversion'};
if ($currver ne '2') {
$currver = 1;
}
}
if (ref($settings->{'recaptchakeys'}) eq 'HASH') {
$currpub = $settings->{'recaptchakeys'}{'public'};
$currpriv = $settings->{'recaptchakeys'}{'private'};
}
} else {
$checked{'original'} = ' checked="checked"';
}
my $css_class;
if ($itemcount%2) {
$css_class = 'LC_odd_row';
}
if ($customcss) {
$css_class .= " $customcss";
}
$css_class =~ s/^\s+//;
if ($css_class) {
$css_class = ' class="'.$css_class.'"';
}
if ($rowstyle) {
$css_class .= ' style="'.$rowstyle.'"';
}
my $output = '<tr'.$css_class.'>'.
'<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="'.$colspan.'">'."\n".
'<table><tr><td>'."\n";
foreach my $option ('original','recaptcha','notused') {
$output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.
$option.'" '.$checked{$option}.' onchange="javascript:updateCaptcha('."this,'$context'".');" />'.
$lt{$option}.'</label></span>';
unless ($option eq 'notused') {
$output .= (' 'x2)."\n";
}
}
#
# Note: If reCAPTCHA is to be used for LON-CAPA servers in a domain, a domain coordinator should visit:
# https://www.google.com/recaptcha and generate a Public and Private key. For domains with multiple
# servers a single key pair will be used for all servers, so the internet domain (e.g., yourcollege.edu)
# specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain.
#
$output .= '</td></tr>'."\n".
'<tr><td class="LC_zero_height">'."\n".
'<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span> '."\n".
'<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'.
$currpub.'" size="40" /></span><br />'."\n".
'<span class="LC_nobreak"><span id="'.$context.'_recaptchaprivtxt">'.$privtext.'</span> '."\n".
'<input type="'.$keyentry.'" id="'.$context.'_recaptchapriv" name="'.$context.'_recaptchapriv" value="'.
$currpriv.'" size="40" /></span><br />'.
'<span class="LC_nobreak"><span id="'.$context.'_recaptchavertxt">'.$vertext.'</span> '."\n".
'<input type="'.$keyentry.'" id="'.$context.'_recaptchaversion" name="'.$context.'_recaptchaversion" value="'.
$currver.'" size="3" /></span><br />'.
'</td></tr></table>'."\n".
'</td></tr>';
return $output;
}
sub user_formats_row {
my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount,$status) = @_;
my $output;
my %text = (
'username' => 'new usernames',
'id' => 'IDs',
);
unless (($type eq 'email') || ($type eq 'unamemap')) {
my $css_class = $rowcount%2?' class="LC_odd_row"':'';
$output = '<tr '.$css_class.'>'.
'<td><span class="LC_nobreak">'.
&mt("Format rules to check for $text{$type}: ").
'</td><td class="LC_left_item" colspan="2"><table>';
}
my $rem;
if (ref($ruleorder) eq 'ARRAY') {
for (my $i=0; $i<@{$ruleorder}; $i++) {
if (ref($rules->{$ruleorder->[$i]}) eq 'HASH') {
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$output .= '</tr>';
}
$output .= '<tr>';
}
my $check = ' ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{$type.'_rule'}) eq 'ARRAY') {
if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) {
$check = ' checked="checked" ';
}
} elsif ((ref($settings->{$type.'_rule'}) eq 'HASH') && ($status ne '')) {
if (ref($settings->{$type.'_rule'}->{$status}) eq 'ARRAY') {
if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}->{$status}})) {
$check = ' checked="checked" ';
}
}
}
}
my $name = $type.'_rule';
if ($type eq 'email') {
$name .= '_'.$status;
}
$output .= '<td class="LC_left_item">'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$name.'" '.
'value="'.$ruleorder->[$i].'"'.$check.'/>'.
$rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>';
}
}
$rem = @{$ruleorder}%($numinrow);
}
my $colsleft;
if ($rem) {
$colsleft = $numinrow - $rem;
}
if ($colsleft > 1 ) {
$output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$output .= '<td class="LC_left_item"> </td>';
}
$output .= '</tr>';
unless (($type eq 'email') || ($type eq 'unamemap')) {
$output .= '</table></td></tr>';
}
return $output;
}
sub usercreation_types {
my %lt = &Apache::lonlocal::texthash (
author => 'When adding a co-author',
course => 'When adding a user to a course',
requestcrs => 'When requesting a course',
any => 'Any',
official => 'Institutional only ',
unofficial => 'Non-institutional only',
none => 'None',
);
return %lt;
}
sub selfcreation_types {
my %lt = &Apache::lonlocal::texthash (
selfcreate => 'User creates own account',
any => 'Any',
official => 'Institutional only ',
unofficial => 'Non-institutional only',
email => 'E-mail address',
login => 'Institutional Login',
sso => 'SSO',
);
}
sub authtype_names {
my %lt = &Apache::lonlocal::texthash(
int => 'Internal',
krb4 => 'Kerberos 4',
krb5 => 'Kerberos 5',
loc => 'Local',
lti => 'LTI',
);
return %lt;
}
sub context_names {
my %context_title = &Apache::lonlocal::texthash(
author => 'Creating users when an Author',
course => 'Creating users when in a course',
domain => 'Creating users when a Domain Coordinator',
);
return %context_title;
}
sub print_usermodification {
my ($position,$dom,$settings,$rowtotal) = @_;
my $numinrow = 4;
my ($context,$datatable,$rowcount);
if ($position eq 'top') {
$rowcount = 0;
$context = 'author';
foreach my $role ('ca','aa') {
$datatable .= &modifiable_userdata_row($context,$role,$settings,
$numinrow,$rowcount);
$$rowtotal ++;
$rowcount ++;
}
} elsif ($position eq 'middle') {
$rowcount = 0;
$context = 'coauthor';
foreach my $role ('ca','aa') {
$datatable .= &modifiable_userdata_row($context,$role,$settings,
$numinrow,$rowcount);
$$rowtotal ++;
$rowcount ++;
}
} elsif ($position eq 'bottom') {
$context = 'course';
$rowcount = 0;
foreach my $role ('st','ep','ta','in','cr') {
$datatable .= &modifiable_userdata_row($context,$role,$settings,
$numinrow,$rowcount);
$$rowtotal ++;
$rowcount ++;
}
}
return $datatable;
}
sub print_defaults {
my ($position,$dom,$settings,$rowtotal) = @_;
my $rownum = 0;
my ($datatable,$css_class,$titles);
unless ($position eq 'bottom') {
$titles = &defaults_titles($dom);
}
if ($position eq 'top') {
my @items = ('auth_def','auth_arg_def','lang_def','timezone_def',
'datelocale_def','portal_def');
my %defaults;
if (ref($settings) eq 'HASH') {
%defaults = %{$settings};
} else {
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
foreach my $item (@items) {
$defaults{$item} = $domdefaults{$item};
}
}
foreach my $item (@items) {
if ($rownum%2) {
$css_class = '';
} else {
$css_class = ' class="LC_odd_row" ';
}
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.$titles->{$item}.
'</span></td><td class="LC_right_item" colspan="3">';
if ($item eq 'auth_def') {
my @authtypes = ('internal','krb4','krb5','localauth','lti');
my %shortauth = (
internal => 'int',
krb4 => 'krb4',
krb5 => 'krb5',
localauth => 'loc',
lti => 'lti',
);
my %authnames = &authtype_names();
foreach my $auth (@authtypes) {
my $checked = ' ';
if ($defaults{$item} eq $auth) {
$checked = ' checked="checked" ';
}
$datatable .= '<label><input type="radio" name="'.$item.
'" value="'.$auth.'"'.$checked.'/>'.
$authnames{$shortauth{$auth}}.'</label> ';
}
} elsif ($item eq 'timezone_def') {
my $includeempty = 1;
$datatable .= &Apache::loncommon::select_timezone($item,$defaults{$item},undef,$includeempty);
} elsif ($item eq 'datelocale_def') {
my $includeempty = 1;
$datatable .= &Apache::loncommon::select_datelocale($item,$defaults{$item},undef,$includeempty);
} elsif ($item eq 'lang_def') {
my $includeempty = 1;
$datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty);
} elsif ($item eq 'portal_def') {
$datatable .= '<input type="text" name="'.$item.'" value="'.
$defaults{$item}.'" size="25" onkeyup="portalExtras(this);" />';
my $portalsty = 'none';
if ($defaults{$item}) {
$portalsty = 'block';
}
foreach my $field ('email','web') {
my $checkedoff = ' checked="checked"';
my $checkedon;
if ($defaults{$item.'_'.$field}) {
$checkedon = $checkedoff;
$checkedoff = '';
}
$datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'.
'<span class="LC_nobreak">'.$titles->{$field}.' '.
'<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'.
(' 'x2).
'<label><input type="radio" name="'.$item.'_'.$field.'" value="0"'.$checkedoff.'/>'.&mt('No').'</label>'.
'</div>';
}
} else {
$datatable .= '<input type="text" name="'.$item.'" value="'.$defaults{$item}.'" />';
}
$datatable .= '</td></tr>';
$rownum ++;
}
} elsif ($position eq 'middle') {
my %defaults;
if (ref($settings) eq 'HASH') {
if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
my $maxnum = @{$settings->{'inststatusorder'}};
for (my $i=0; $i<$maxnum; $i++) {
$css_class = $rownum%2?' class="LC_odd_row"':'';
my $item = $settings->{'inststatusorder'}->[$i];
my $title = $settings->{'inststatustypes'}->{$item};
my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.
'<select name="inststatus_pos_'.$item.'"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $i) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select> '.&mt('Internal ID:').' <b>'.$item.'</b> '.
'<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
&mt('delete').'</span></td>'.
'<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed').':'.
'<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
'</span></td></tr>';
}
$css_class = $rownum%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';
$datatable .= '<tr '.$css_class.'>'.
'<td><span class="LC_nobreak"><select name="addinststatus_pos"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $maxnum) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select> '.&mt('Internal ID:').
'<input type="text" size="10" name="addinststatus" value="" />'.
' '.&mt('(new)').
'</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
&mt('Name displayed').':'.
'<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
'</tr>'."\n";
$rownum ++;
}
}
} else {
my ($unamemaprules,$ruleorder) =
&Apache::lonnet::inst_userrules($dom,'unamemap');
$css_class = $rownum%2?' class="LC_odd_row"':'';
if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
my $numinrow = 2;
$datatable .= '<tr'.$css_class.'><td>'.&mt('Available conversions').'</td><td><table>'.
&user_formats_row('unamemap',$settings,$unamemaprules,
$ruleorder,$numinrow).
'</table></td></tr>';
}
if ($datatable eq '') {
$datatable .= '<tr'.$css_class.'><td colspan="2">'.
&mt('No rules set for domain in customized localenroll.pm').
'</td></tr>';
}
}
$$rowtotal += $rownum;
return $datatable;
}
sub get_languages_hash {
my %langchoices;
foreach my $id (&Apache::loncommon::languageids()) {
my $code = &Apache::loncommon::supportedlanguagecode($id);
if ($code ne '') {
$langchoices{$code} = &Apache::loncommon::plainlanguagedescription($id);
}
}
return %langchoices;
}
sub defaults_titles {
my ($dom) = @_;
my %titles = &Apache::lonlocal::texthash (
'auth_def' => 'Default authentication type',
'auth_arg_def' => 'Default authentication argument',
'lang_def' => 'Default language',
'timezone_def' => 'Default timezone',
'datelocale_def' => 'Default locale for dates',
'portal_def' => 'Portal/Default URL',
'email' => 'Email links use portal URL',
'web' => 'Public web links use portal URL',
'intauth_cost' => 'Encryption cost for bcrypt (positive integer)',
'intauth_check' => 'Check bcrypt cost if authenticated',
'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication',
);
if ($dom) {
my $uprimary_id = &Apache::lonnet::domain($dom,'primary');
my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
my $protocol = $Apache::lonnet::protocol{$uprimary_id};
$protocol = 'http' if ($protocol ne 'https');
if ($uint_dom) {
$titles{'portal_def'} .= ' '.&mt('(for example: [_1])',$protocol.'://loncapa.'.
$uint_dom);
}
}
return (\%titles);
}
sub print_scantron {
my ($r,$position,$dom,$confname,$settings,$rowtotal) = @_;
if ($position eq 'top') {
return &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
} else {
return &print_scantronconfig($dom,$settings,\$rowtotal);
}
}
sub scantron_javascript {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleScantron(form) {
var csvfieldset = new Array();
if (document.getElementById('scantroncsv_cols')) {
csvfieldset.push(document.getElementById('scantroncsv_cols'));
}
if (document.getElementById('scantroncsv_options')) {
csvfieldset.push(document.getElementById('scantroncsv_options'));
}
if (csvfieldset.length) {
if (document.getElementById('scantronconfcsv')) {
var scantroncsv = document.getElementById('scantronconfcsv');
if (scantroncsv.checked) {
for (var i=0; i<csvfieldset.length; i++) {
csvfieldset[i].style.display = 'block';
}
} else {
for (var i=0; i<csvfieldset.length; i++) {
csvfieldset[i].style.display = 'none';
}
var csvselects = document.getElementsByClassName('scantronconfig_csv');
if (csvselects.length) {
for (var j=0; j<csvselects.length; j++) {
csvselects[j].selectedIndex = 0;
}
}
}
}
}
return;
}
// ]]>
</script>
ENDSCRIPT
}
sub print_scantronformat {
my ($r,$dom,$confname,$settings,$rowtotal) = @_;
my $itemcount = 1;
my ($datatable,$css_class,$scantronurl,$is_custom,%error,%scantronurls,
%confhash);
my $switchserver = &check_switchserver($dom,$confname);
my %lt = &Apache::lonlocal::texthash (
default => 'Default bubblesheet format file error',
custom => 'Custom bubblesheet format file error',
);
my %scantronfiles = (
default => 'default.tab',
custom => 'custom.tab',
);
foreach my $key (keys(%scantronfiles)) {
$scantronurls{$key} = '/res/'.$dom.'/'.$confname.'/scantron/'
.$scantronfiles{$key};
}
my @defaultinfo = &Apache::lonnet::stat_file($scantronurls{'default'});
if ((!@defaultinfo) || ($defaultinfo[0] eq 'no_such_dir')) {
if (!$switchserver) {
my $servadm = $r->dir_config('lonAdmEMail');
my ($configuserok,$author_ok) = &config_check($dom,$confname,$servadm);
if ($configuserok eq 'ok') {
if ($author_ok eq 'ok') {
my %legacyfile = (
default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab',
custom => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab',
);
my %md5chk;
foreach my $type (keys(%legacyfile)) {
($md5chk{$type}) = split(/ /,`md5sum $legacyfile{$type}`);
chomp($md5chk{$type});
}
if ($md5chk{'default'} ne $md5chk{'custom'}) {
foreach my $type (keys(%legacyfile)) {
($scantronurls{$type},my $error) =
&legacy_scantronformat($r,$dom,$confname,
$type,$legacyfile{$type},
$scantronurls{$type},
$scantronfiles{$type});
if ($error ne '') {
$error{$type} = $error;
}
}
if (keys(%error) == 0) {
$is_custom = 1;
$confhash{'scantron'}{'scantronformat'} =
$scantronurls{'custom'};
my $putresult =
&Apache::lonnet::put_dom('configuration',
\%confhash,$dom);
if ($putresult ne 'ok') {
$error{'custom'} =
'<span class="LC_error">'.
&mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';
}
}
} else {
($scantronurls{'default'},my $error) =
&legacy_scantronformat($r,$dom,$confname,
'default',$legacyfile{'default'},
$scantronurls{'default'},
$scantronfiles{'default'});
if ($error eq '') {
$confhash{'scantron'}{'scantronformat'} = '';
my $putresult =
&Apache::lonnet::put_dom('configuration',
\%confhash,$dom);
if ($putresult ne 'ok') {
$error{'default'} =
'<span class="LC_error">'.
&mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';
}
} else {
$error{'default'} = $error;
}
}
}
}
} else {
$error{'default'} = &mt("Unable to copy default bubblesheet formatfile to domain's RES space: [_1]",$switchserver);
}
}
if (ref($settings) eq 'HASH') {
if ($settings->{'scantronformat'} eq "/res/$dom/$confname/scantron/custom.tab") {
my @info = &Apache::lonnet::stat_file($settings->{'scantronformat'});
if ((!@info) || ($info[0] eq 'no_such_dir')) {
$scantronurl = '';
} else {
$scantronurl = $settings->{'scantronformat'};
}
$is_custom = 1;
} else {
$scantronurl = $scantronurls{'default'};
}
} else {
if ($is_custom) {
$scantronurl = $scantronurls{'custom'};
} else {
$scantronurl = $scantronurls{'default'};
}
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>';
if (!$is_custom) {
$datatable .= '<td>'.&mt('Default in use:').'<br />'.
'<span class="LC_nobreak">';
if ($scantronurl) {
$datatable .= &Apache::loncommon::modal_link($scantronurl,&mt('Default bubblesheet format file'),600,500,
undef,undef,undef,undef,'background-color:#ffffff');
} else {
$datatable = &mt('File unavailable for display');
}
$datatable .= '</span></td>';
if (keys(%error) == 0) {
$datatable .= '<td style="vertical-align: bottom">';
if (!$switchserver) {
$datatable .= &mt('Upload:').'<br />';
}
} else {
my $errorstr;
foreach my $key (sort(keys(%error))) {
$errorstr .= $lt{$key}.': '.$error{$key}.'<br />';
}
$datatable .= '<td>'.$errorstr;
}
} else {
if (keys(%error) > 0) {
my $errorstr;
foreach my $key (sort(keys(%error))) {
$errorstr .= $lt{$key}.': '.$error{$key}.'<br />';
}
$datatable .= '<td>'.$errorstr.'</td><td> ';
} elsif ($scantronurl) {
my $link = &Apache::loncommon::modal_link($scantronurl,&mt('Custom bubblesheet format file'),600,500,
undef,undef,undef,undef,'background-color:#ffffff');
$datatable .= '<td><span class="LC_nobreak">'.
$link.
'<label><input type="checkbox" name="scantronformat_del"'.
' value="1" />'.&mt('Delete?').'</label></span></td>'.
'<td><span class="LC_nobreak"> '.
&mt('Replace:').'</span><br />';
}
}
if (keys(%error) == 0) {
if ($switchserver) {
$datatable .= &mt('Upload to library server: [_1]',$switchserver);
} else {
$datatable .='<span class="LC_nobreak"> '.
'<input type="file" name="scantronformat" /></span>';
}
}
$datatable .= '</td></tr>';
$$rowtotal ++;
return $datatable;
}
sub legacy_scantronformat {
my ($r,$dom,$confname,$file,$legacyfile,$newurl,$newfile) = @_;
my ($url,$error);
my @statinfo = &Apache::lonnet::stat_file($newurl);
if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) {
my $modified = [];
(my $result,$url) =
&Apache::lonconfigsettings::publishlogo($r,'copy',$legacyfile,$dom,$confname,
'scantron','','',$newfile,$modified);
if ($result eq 'ok') {
&update_modify_urls($r,$modified);
} else {
$error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result);
}
}
return ($url,$error);
}
sub print_scantronconfig {
my ($dom,$settings,$rowtotal) = @_;
my $itemcount = 2;
my $is_checked = ' checked="checked"';
my %optionson = (
hdr => ' checked="checked"',
pad => ' checked="checked"',
rem => ' checked="checked"',
);
my %optionsoff = (
hdr => '',
pad => '',
rem => '',
);
my $currcsvsty = 'none';
my ($datatable,%csvfields,%checked,%onclick,%csvoptions);
my @fields = &scantroncsv_fields();
my %titles = &scantronconfig_titles();
if (ref($settings) eq 'HASH') {
if (ref($settings->{config}) eq 'HASH') {
if ($settings->{config}->{dat}) {
$checked{'dat'} = $is_checked;
}
if (ref($settings->{config}->{csv}) eq 'HASH') {
if (ref($settings->{config}->{csv}->{fields}) eq 'HASH') {
%csvfields = %{$settings->{config}->{csv}->{fields}};
if (keys(%csvfields) > 0) {
$checked{'csv'} = $is_checked;
$currcsvsty = 'block';
}
}
if (ref($settings->{config}->{csv}->{options}) eq 'HASH') {
%csvoptions = %{$settings->{config}->{csv}->{options}};
foreach my $option (keys(%optionson)) {
unless ($csvoptions{$option}) {
$optionsoff{$option} = $optionson{$option};
$optionson{$option} = '';
}
}
}
}
} else {
$checked{'dat'} = $is_checked;
}
} else {
$checked{'dat'} = $is_checked;
}
$onclick{'csv'} = ' onclick="toggleScantron(this.form);"';
my $css_class = $itemcount%2? ' class="LC_odd_row"':'';
$datatable = '<tr '.$css_class.'><td>'.&mt('Supported formats').'</td>'.
'<td class="LC_left_item" valign="top"><span class="LC_nobreak">';
foreach my $item ('dat','csv') {
my $id;
if ($item eq 'csv') {
$id = 'id="scantronconfcsv" ';
}
$datatable .= '<label><input type="checkbox" name="scantronconfig" '.$id.'value="'.$item.'"'.$checked{$item}.$onclick{$item}.' />'.
$titles{$item}.'</label>'.(' 'x3);
if ($item eq 'csv') {
$datatable .= '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_cols">'.
'<legend>'.&mt('CSV Column Mapping').'</legend>'.
'<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Location').'</th></tr>'."\n";
foreach my $col (@fields) {
my $selnone;
if ($csvfields{$col} eq '') {
$selnone = ' selected="selected"';
}
$datatable .= '<tr><td>'.$titles{$col}.'</td>'.
'<td><select name="scantronconfig_csv_'.$col.'" class="scantronconfig_csv">'.
'<option value=""'.$selnone.'></option>';
for (my $i=0; $i<20; $i++) {
my $shown = $i+1;
my $sel;
unless ($selnone) {
if (exists($csvfields{$col})) {
if ($csvfields{$col} == $i) {
$sel = ' selected="selected"';
}
}
}
$datatable .= '<option value="'.$i.'"'.$sel.'>'.$shown.'</option>';
}
$datatable .= '</select></td></tr>';
}
$datatable .= '</table></fieldset>'.
'<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_options">'.
'<legend>'.&mt('CSV Options').'</legend>';
foreach my $option ('hdr','pad','rem') {
$datatable .= '<span class="LC_nobreak">'.$titles{$option}.':'.
'<label><input type="radio" name="scantroncsv_'.$option.'" value="1"'.$optionson{$option}.' />'.
&mt('Yes').'</label>'.(' 'x2)."\n".
'<label><input type="radio" name="scantroncsv_'.$option.'" value="0"'.$optionsoff{$option}.' />'.&mt('No').'</label></span><br />';
}
$datatable .= '</fieldset>';
$itemcount ++;
}
}
$datatable .= '</td></tr>';
$$rowtotal ++;
return $datatable;
}
sub scantronconfig_titles {
return &Apache::lonlocal::texthash(
dat => 'Standard format (.dat)',
csv => 'Comma separated values (.csv)',
hdr => 'Remove first line in file (contains column titles)',
pad => 'Prepend 0s to PaperID',
rem => 'Remove leading spaces (except Question Response columns)',
CODE => 'CODE',
ID => 'Student ID',
PaperID => 'Paper ID',
FirstName => 'First Name',
LastName => 'Last Name',
FirstQuestion => 'First Question Response',
Section => 'Section',
);
}
sub scantroncsv_fields {
return ('PaperID','LastName','FirstName','ID','Section','CODE','FirstQuestion');
}
sub print_coursecategories {
my ($position,$dom,$hdritem,$settings,$rowtotal) = @_;
my $datatable;
if ($position eq 'top') {
my (%checked);
my @catitems = ('unauth','auth');
my @cattypes = ('std','domonly','codesrch','none');
$checked{'unauth'} = 'std';
$checked{'auth'} = 'std';
if (ref($settings) eq 'HASH') {
foreach my $type (@cattypes) {
if ($type eq $settings->{'unauth'}) {
$checked{'unauth'} = $type;
}
if ($type eq $settings->{'auth'}) {
$checked{'auth'} = $type;
}
}
}
my %lt = &Apache::lonlocal::texthash (
unauth => 'Catalog type for unauthenticated users',
auth => 'Catalog type for authenticated users',
none => 'No catalog',
std => 'Standard catalog',
domonly => 'Domain-only catalog',
codesrch => "Code search form",
);
my $itemcount = 0;
foreach my $item (@catitems) {
my $css_class = $itemcount%2? ' class="LC_odd_row"':'';
$datatable .= '<tr '.$css_class.'>'.
'<td>'.$lt{$item}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak">';
foreach my $type (@cattypes) {
my $ischecked;
if ($checked{$item} eq $type) {
$ischecked=' checked="checked"';
}
$datatable .= '<label>'.
'<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked.
' />'.$lt{$type}.'</label> ';
}
$datatable .= '</span></td></tr>';
$itemcount ++;
}
$$rowtotal += $itemcount;
} elsif ($position eq 'middle') {
my $toggle_cats_crs = ' ';
my $toggle_cats_dom = ' checked="checked" ';
my $can_cat_crs = ' ';
my $can_cat_dom = ' checked="checked" ';
my $toggle_catscomm_comm = ' ';
my $toggle_catscomm_dom = ' checked="checked" ';
my $can_catcomm_comm = ' ';
my $can_catcomm_dom = ' checked="checked" ';
my $toggle_catsplace_place = ' ';
my $toggle_catsplace_dom = ' checked="checked" ';
my $can_catplace_place = ' ';
my $can_catplace_dom = ' checked="checked" ';
if (ref($settings) eq 'HASH') {
if ($settings->{'togglecats'} eq 'crs') {
$toggle_cats_crs = $toggle_cats_dom;
$toggle_cats_dom = ' ';
}
if ($settings->{'categorize'} eq 'crs') {
$can_cat_crs = $can_cat_dom;
$can_cat_dom = ' ';
}
if ($settings->{'togglecatscomm'} eq 'comm') {
$toggle_catscomm_comm = $toggle_catscomm_dom;
$toggle_catscomm_dom = ' ';
}
if ($settings->{'categorizecomm'} eq 'comm') {
$can_catcomm_comm = $can_catcomm_dom;
$can_catcomm_dom = ' ';
}
if ($settings->{'togglecatsplace'} eq 'place') {
$toggle_catsplace_place = $toggle_catsplace_dom;
$toggle_catsplace_dom = ' ';
}
if ($settings->{'categorizeplace'} eq 'place') {
$can_catplace_place = $can_catplace_dom;
$can_catplace_dom = ' ';
}
}
my %title = &Apache::lonlocal::texthash (
togglecats => 'Show/Hide a course in catalog',
togglecatscomm => 'Show/Hide a community in catalog',
togglecatsplace => 'Show/Hide a placement test in catalog',
categorize => 'Assign a category to a course',
categorizecomm => 'Assign a category to a community',
categorizeplace => 'Assign a category to a placement test',
);
my %level = &Apache::lonlocal::texthash (
dom => 'Set in Domain',
crs => 'Set in Course',
comm => 'Set in Community',
place => 'Set in Placement Test',
);
$datatable = '<tr class="LC_odd_row">'.
'<td>'.$title{'togglecats'}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="togglecats"'.
$toggle_cats_dom.' value="dom" />'.$level{'dom'}.'</label> '.
'<label><input type="radio" name="togglecats"'.
$toggle_cats_crs.' value="crs" />'.$level{'crs'}.'</label></span></td>'.
'</tr><tr>'.
'<td>'.$title{'categorize'}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak">'.
'<label><input type="radio" name="categorize"'.
$can_cat_dom.' value="dom" />'.$level{'dom'}.'</label> '.
'<label><input type="radio" name="categorize"'.
$can_cat_crs.'value="crs" />'.$level{'crs'}.'</label></span></td>'.
'</tr><tr class="LC_odd_row">'.
'<td>'.$title{'togglecatscomm'}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="togglecatscomm"'.
$toggle_catscomm_dom.' value="dom" />'.$level{'dom'}.'</label> '.
'<label><input type="radio" name="togglecatscomm"'.
$toggle_catscomm_comm.' value="comm" />'.$level{'comm'}.'</label></span></td>'.
'</tr><tr>'.
'<td>'.$title{'categorizecomm'}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak">'.
'<label><input type="radio" name="categorizecomm"'.
$can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label> '.
'<label><input type="radio" name="categorizecomm"'.
$can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.
'</tr><tr class="LC_odd_row">'.
'<td>'.$title{'togglecatsplace'}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak"><label>'.
'<input type="radio" name="togglecatsplace"'.
$toggle_catsplace_dom.' value="dom" />'.$level{'dom'}.'</label> '.
'<label><input type="radio" name="togglecatscomm"'.
$toggle_catsplace_place.' value="comm" />'.$level{'place'}.'</label></span></td>'.
'</tr><tr>'.
'<td>'.$title{'categorizeplace'}.'</td>'.
'<td class="LC_right_item"><span class="LC_nobreak">'.
'<label><input type="radio" name="categorizeplace"'.
$can_catplace_dom.' value="dom" />'.$level{'dom'}.'</label> '.
'<label><input type="radio" name="categorizeplace"'.
$can_catplace_place.'value="place" />'.$level{'place'}.'</label></span></td>'.
'</tr>';
$$rowtotal += 6;
} else {
my $css_class;
my $itemcount = 1;
my $cathash;
if (ref($settings) eq 'HASH') {
$cathash = $settings->{'cats'};
}
if (ref($cathash) eq 'HASH') {
my (@cats,@trails,%allitems,%idx,@jsarray);
&Apache::loncommon::extract_categories($cathash,\@cats,\@trails,
\%allitems,\%idx,\@jsarray);
my $maxdepth = scalar(@cats);
my $colattrib = '';
if ($maxdepth > 2) {
$colattrib = ' colspan="2" ';
}
my @path;
if (@cats > 0) {
if (ref($cats[0]) eq 'ARRAY') {
my $numtop = @{$cats[0]};
my $maxnum = $numtop;
my %default_names = (
instcode => &mt('Official courses'),
communities => &mt('Communities'),
placement => &mt('Placement Tests'),
);
if ((!grep(/^instcode$/,@{$cats[0]})) ||
($cathash->{'instcode::0'} eq '') ||
(!grep(/^communities$/,@{$cats[0]})) ||
($cathash->{'communities::0'} eq '') ||
(!grep(/^placement$/,@{$cats[0]})) ||
($cathash->{'placement::0'} eq '')) {
$maxnum ++;
}
my $lastidx;
for (my $i=0; $i<$numtop; $i++) {
my $parent = $cats[0][$i];
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $item = &escape($parent).'::0';
my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$item','$idx{$item}'".');"';
$lastidx = $idx{$item};
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="'.$item.'"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $i) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select></span></td><td>';
if ($parent eq 'instcode' || $parent eq 'communities' || $parent eq 'placement') {
$datatable .= '<span class="LC_nobreak">'
.$default_names{$parent}.'</span>';
if ($parent eq 'instcode') {
$datatable .= '<br /><span class="LC_nobreak">('
.&mt('with institutional codes')
.')</span></td><td'.$colattrib.'>';
} else {
$datatable .= '<table><tr><td>';
}
$datatable .= '<span class="LC_nobreak">'
.'<label><input type="radio" name="'
.$parent.'" value="1" checked="checked" />'
.&mt('Display').'</label>';
if ($parent eq 'instcode') {
$datatable .= ' ';
} else {
$datatable .= '</span></td></tr><tr><td>'
.'<span class="LC_nobreak">';
}
$datatable .= '<label><input type="radio" name="'
.$parent.'" value="0" />'
.&mt('Do not display').'</label></span>';
if (($parent eq 'communities') || ($parent eq 'placement')) {
$datatable .= '</td></tr></table>';
}
$datatable .= '</td>';
} else {
$datatable .= $parent
.' <span class="LC_nobreak"><label>'
.'<input type="checkbox" name="deletecategory" '
.'value="'.$item.'" />'.&mt('Delete').'</label></span></td>';
}
my $depth = 1;
push(@path,$parent);
$datatable .= &build_category_rows($itemcount,\@cats,$depth,$parent,\@path,\%idx);
pop(@path);
$datatable .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
$itemcount ++;
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','addcategory_pos','$lastidx'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak"><select name="addcategory_pos"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $numtop) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select></span></td><td colspan="2">'.&mt('Add category:').' '
.'<input type="text" size="20" name="addcategory_name" value="" /></td>'
.'</tr>'."\n";
$itemcount ++;
foreach my $default ('instcode','communities','placement') {
if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';
$datatable .= '<tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr><tr '.$css_class.'><td>'.
'<span class="LC_nobreak"><select name="'.$default.'_pos"'.$chgstr.'>';
for (my $k=0; $k<=$maxnum; $k++) {
my $vpos = $k+1;
my $selstr;
if ($k == $maxnum) {
$selstr = ' selected="selected" ';
}
$datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
}
$datatable .= '</select></span></td>'.
'<td><span class="LC_nobreak">'.
$default_names{$default}.'</span>';
if ($default eq 'instcode') {
$datatable .= '<br /><span class="LC_nobreak">('
.&mt('with institutional codes').')</span>';
}
$datatable .= '</td>'
.'<td><span class="LC_nobreak"><label><input type="radio" name="'.$default.'" value="1" />'
.&mt('Display').'</label> '
.'<label><input type="radio" name="'.$default.'" value="0" checked="checked"/>'
.&mt('Do not display').'</label></span></td></tr>';
}
}
}
} else {
$datatable .= &initialize_categories($itemcount);
}
} else {
$datatable .= '<tr><td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td></tr>'
.&initialize_categories($itemcount);
}
$$rowtotal += $itemcount;
}
return $datatable;
}
sub print_serverstatuses {
my ($dom,$settings,$rowtotal) = @_;
my $datatable;
my @pages = &serverstatus_pages();
my (%namedaccess,%machineaccess);
foreach my $type (@pages) {
$namedaccess{$type} = '';
$machineaccess{$type}= '';
}
if (ref($settings) eq 'HASH') {
foreach my $type (@pages) {
if (exists($settings->{$type})) {
if (ref($settings->{$type}) eq 'HASH') {
foreach my $key (keys(%{$settings->{$type}})) {
if ($key eq 'namedusers') {
$namedaccess{$type} = $settings->{$type}->{$key};
} elsif ($key eq 'machines') {
$machineaccess{$type} = $settings->{$type}->{$key};
}
}
}
}
}
}
my $titles= &LONCAPA::lonauthcgi::serverstatus_titles();
my $rownum = 0;
my $css_class;
foreach my $type (@pages) {
$rownum ++;
$css_class = $rownum%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'>'.
'<td><span class="LC_nobreak">'.
$titles->{$type}.'</span></td>'.
'<td class="LC_left_item">'.
'<input type="text" name="'.$type.'_namedusers" '.
'value="'.$namedaccess{$type}.'" size="30" /></td>'.
'<td class="LC_right_item">'.
'<span class="LC_nobreak">'.
'<input type="text" name="'.$type.'_machines" '.
'value="'.$machineaccess{$type}.'" size="10" />'.
'</span></td></tr>'."\n";
}
$$rowtotal += $rownum;
return $datatable;
}
sub serverstatus_pages {
return ('userstatus','lonstatus','loncron','server-status','codeversions',
'checksums','clusterstatus','certstatus','metadata_keywords',
'metadata_harvest','takeoffline','takeonline','showenv','toggledebug',
'ping','domconf','uniquecodes','diskusage','coursecatalog');
}
sub defaults_javascript {
my ($settings) = @_;
return unless (ref($settings) eq 'HASH');
my $portal_js = <<"ENDPORTAL";
function portalExtras(caller) {
var x = caller.value;
var y = new Array('email','web');
for (var i=0; i<y.length; i++) {
if (document.getElementById('portal_def_'+y[i]+'_div')) {
var z = document.getElementById('portal_def_'+y[i]+'_div');
if (x.length > 0) {
z.style.display = 'block';
} else {
z.style.display = 'none';
}
}
}
}
ENDPORTAL
if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
my $maxnum = scalar(@{$settings->{'inststatusorder'}});
if ($maxnum eq '') {
$maxnum = 0;
}
$maxnum ++;
my $jstext = ' var inststatuses = Array('."'".join("','",@{$settings->{'inststatusorder'}})."'".');';
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderTypes(form,caller) {
var changedVal;
$jstext
var newpos = 'addinststatus_pos';
var current = new Array;
var maxh = $maxnum;
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
var oldVal;
if (caller == newpos) {
changedVal = newitemVal;
} else {
var curritem = 'inststatus_pos_'+caller;
changedVal = form.elements[curritem].options[form.elements[curritem].selectedIndex].value;
current[newitemVal] = newpos;
}
for (var i=0; i<inststatuses.length; i++) {
if (inststatuses[i] != caller) {
var elementName = 'inststatus_pos_'+inststatuses[i];
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
$portal_js
// ]]>
</script>
ENDSCRIPT
} else {
return <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
$portal_js
// ]]>
</script>
ENDSCRIPT
}
return;
}
sub passwords_javascript {
my ($prefix) = @_;
my %intalert;
if ($prefix eq 'passwords') {
%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).',
);
} elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
%intalert = &Apache::lonlocal::texthash (
passmin => 'Warning: minimum secret length must be a positive integer greater than 6.',
passmax => 'Warning: maximum secret length must be a positive integer (or blank).',
);
}
&js_escape(\%intalert);
my $defmin = $Apache::lonnet::passwdmin;
my $intauthjs;
if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT";
function warnIntAuth(field) {
if (field.name == 'intauth_check') {
if (field.value == '2') {
alert('$intalert{authcheck}');
}
}
if (field.name == 'intauth_cost') {
field.value.replace(/\s/g,'');
if (field.value != '') {
var regexdigit=/^\\d+\$/;
if (!regexdigit.test(field.value)) {
alert('$intalert{authcost}');
}
}
}
return;
}
ENDSCRIPT
}
$intauthjs .= <<"ENDSCRIPT";
function warnInt$prefix(field) {
field.value.replace(/^\s+/,'');
field.value.replace(/\s+\$/,'');
var regexdigit=/^\\d+\$/;
if (field.name == '${prefix}_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 == '${prefix}_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 == '${prefix}_max') {
alert('$intalert{passmax}');
} else {
if (field.name == '${prefix}_numsaved') {
alert('$intalert{passnum}');
}
}
field.value = '';
}
}
}
}
return;
}
ENDSCRIPT
return &Apache::lonhtmlcommon::scripttag($intauthjs);
}
sub coursecategories_javascript {
my ($settings) = @_;
my ($output,$jstext,$cathash);
if (ref($settings) eq 'HASH') {
$cathash = $settings->{'cats'};
}
if (ref($cathash) eq 'HASH') {
my (@cats,@jsarray,%idx);
&Apache::loncommon::gather_categories($cathash,\@cats,\%idx,\@jsarray);
if (@jsarray > 0) {
$jstext = ' var categories = Array('.scalar(@jsarray).');'."\n";
for (my $i=0; $i<@jsarray; $i++) {
if (ref($jsarray[$i]) eq 'ARRAY') {
my $catstr = join('","',@{$jsarray[$i]});
$jstext .= ' categories['.$i.'] = Array("'.$catstr.'");'."\n";
}
}
}
} else {
$jstext = ' var categories = Array(1);'."\n".
' categories[0] = Array("instcode_pos");'."\n";
}
my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');
my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');
my $placement_reserved = &mt('The name: [_1] is a reserved category.','"placement"');
my $choose_again = "\n".&mt('Please use a different name for the new top level category.');
&js_escape(\$instcode_reserved);
&js_escape(\$communities_reserved);
&js_escape(\$placement_reserved);
&js_escape(\$choose_again);
$output = <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function reorderCats(form,parent,item,idx) {
var changedVal;
$jstext
var newpos = 'addcategory_pos';
if (parent == '') {
var has_instcode = 0;
var maxtop = categories[idx].length;
for (var j=0; j<maxtop; j++) {
if (categories[idx][j] == 'instcode::0') {
has_instcode == 1;
}
}
if (has_instcode == 0) {
categories[idx][maxtop] = 'instcode_pos';
}
} else {
newpos += '_'+parent;
}
var maxh = 1 + categories[idx].length;
var current = new Array;
var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value;
if (item == newpos) {
changedVal = newitemVal;
} else {
changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
current[newitemVal] = newpos;
}
for (var i=0; i<categories[idx].length; i++) {
var elementName = categories[idx][i];
if (elementName != item) {
if (form.elements[elementName]) {
var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
current[currVal] = elementName;
}
}
}
var oldVal;
for (var j=0; j<maxh; j++) {
if (current[j] == undefined) {
oldVal = j;
}
}
if (oldVal < changedVal) {
for (var k=oldVal+1; k<=changedVal ; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
}
} else {
for (var k=changedVal; k<oldVal; k++) {
var elementName = current[k];
form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
}
}
return;
}
function categoryCheck(form) {
if (form.elements['addcategory_name'].value == 'instcode') {
alert('$instcode_reserved\\n$choose_again');
return false;
}
if (form.elements['addcategory_name'].value == 'communities') {
alert('$communities_reserved\\n$choose_again');
return false;
}
if (form.elements['addcategory_name'].value == 'placement') {
alert('$placement_reserved\\n$choose_again');
return false;
}
return true;
}
// ]]>
</script>
ENDSCRIPT
return $output;
}
sub initialize_categories {
my ($itemcount) = @_;
my ($datatable,$css_class,$chgstr);
my %default_names = &Apache::lonlocal::texthash (
instcode => 'Official courses (with institutional codes)',
communities => 'Communities',
placement => 'Placement Tests',
);
my %selnum = (
instcode => '0',
communities => '1',
placement => '2',
);
my %selected;
foreach my $default ('instcode','communities','placement') {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';
map { $selected{$selnum{$_}} = '' } keys(%selnum);
$selected{$selnum{$default}} = ' selected="selected"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="'.$default.'_pos"'.$chgstr.'>'
.'<option value="0"'.$selected{'0'}.'>1</option>'
.'<option value="1"'.$selected{'1'}.'>2</option>'
.'<option value="2"'.$selected{'2'}.'>3</option>'
.'<option value="3">4</option></select> '
.$default_names{$default}
.'</span></td><td><span class="LC_nobreak">'
.'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'
.&mt('Display').'</label> <label>'
.'<input type="radio" name="'.$default.'" value="0" />'.&mt('Do not display')
.'</label></span></td></tr>';
$itemcount ++;
}
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$chgstr = ' onchange="javascript:reorderCats(this.form,'."'','addcategory_pos','0'".');"';
$datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
.'<select name="addcategory_pos"'.$chgstr.'>'
.'<option value="0">1</option>'
.'<option value="1">2</option>'
.'<option value="2">3</option>'
.'<option value="3" selected="selected">4</option></select> '
.&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')
.' <input type="text" size="20" name="addcategory_name" value="" /></span>'
.'</td></tr>';
return $datatable;
}
sub build_category_rows {
my ($itemcount,$cats,$depth,$parent,$path,$idx) = @_;
my ($text,$name,$item,$chgstr);
if (ref($cats) eq 'ARRAY') {
my $maxdepth = scalar(@{$cats});
if (ref($cats->[$depth]) eq 'HASH') {
if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
my $numchildren = @{$cats->[$depth]{$parent}};
my $css_class = $itemcount%2?' class="LC_odd_row"':'';
$text .= '<td><table class="LC_data_table">';
my ($idxnum,$parent_name,$parent_item);
my $higher = $depth - 1;
if ($higher == 0) {
$parent_name = &escape($parent).'::'.$higher;
} else {
if (ref($path) eq 'ARRAY') {
$parent_name = &escape($parent).':'.&escape($path->[-2]).':'.$higher;
}
}
$parent_item = 'addcategory_pos_'.$parent_name;
for (my $j=0; $j<=$numchildren; $j++) {
if ($j < $numchildren) {
$name = $cats->[$depth]{$parent}[$j];
$item = &escape($name).':'.&escape($parent).':'.$depth;
$idxnum = $idx->{$item};
} else {
$name = $parent_name;
$item = $parent_item;
}
$chgstr = ' onchange="javascript:reorderCats(this.form,'."'$parent_name','$item','$idxnum'".');"';
$text .= '<tr '.$css_class.'><td><span class="LC_nobreak"><select name="'.$item.'"'.$chgstr.'>';
for (my $i=0; $i<=$numchildren; $i++) {
my $vpos = $i+1;
my $selstr;
if ($j == $i) {
$selstr = ' selected="selected" ';
}
$text .= '<option value="'.$i.'"'.$selstr.'>'.$vpos.'</option>';
}
$text .= '</select> ';
if ($j < $numchildren) {
my $deeper = $depth+1;
$text .= $name.' '
.'<label><input type="checkbox" name="deletecategory" value="'
.$item.'" />'.&mt('Delete').'</label></span></td><td>';
if(ref($path) eq 'ARRAY') {
push(@{$path},$name);
$text .= &build_category_rows($itemcount,$cats,$deeper,$name,$path,$idx);
pop(@{$path});
}
} else {
$text .= &mt('Add subcategory:').' </span><input type="text" size="20" name="addcategory_name_';
if ($j == $numchildren) {
$text .= $name;
} else {
$text .= $item;
}
$text .= '" value="" />';
}
$text .= '</td></tr>';
}
$text .= '</table></td>';
} else {
my $higher = $depth-1;
if ($higher == 0) {
$name = &escape($parent).'::'.$higher;
} else {
if (ref($path) eq 'ARRAY') {
$name = &escape($parent).':'.&escape($path->[-2]).':'.$higher;
}
}
my $colspan;
if ($parent ne 'instcode') {
$colspan = $maxdepth - $depth - 1;
$text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="text" size="20" name="subcat_'.$name.'" value="" /></td>';
}
}
}
}
return $text;
}
sub modifiable_userdata_row {
my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref,
$rowid,$customcss,$rowstyle,$itemdesc) = @_;
my ($role,$rolename,$statustype);
$role = $item;
if ($context eq 'cancreate') {
if ($item =~ /^(emailusername)_(.+)$/) {
$role = $1;
$statustype = $2;
if (ref($usertypes) eq 'HASH') {
if ($usertypes->{$statustype}) {
$rolename = &mt('Data provided by [_1]',$usertypes->{$statustype});
} else {
$rolename = &mt('Data provided by user');
}
}
}
} elsif ($context eq 'selfcreate') {
if (ref($usertypes) eq 'HASH') {
$rolename = $usertypes->{$role};
} else {
$rolename = $role;
}
} elsif ($context eq 'lti') {
$rolename = &mt('Institutional data used (if available)');
} elsif ($context eq 'privacy') {
$rolename = $itemdesc;
} else {
if ($role eq 'cr') {
$rolename = &mt('Custom role');
} else {
$rolename = &Apache::lonnet::plaintext($role);
}
}
my (@fields,%fieldtitles);
if (ref($fieldsref) eq 'ARRAY') {
@fields = @{$fieldsref};
} else {
@fields = ('lastname','firstname','middlename','generation',
'permanentemail','id');
}
if ((ref($titlesref) eq 'HASH')) {
%fieldtitles = %{$titlesref};
} else {
%fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
}
my $output;
my $css_class;
if ($rowcount%2) {
$css_class = 'LC_odd_row';
}
if ($customcss) {
$css_class .= " $customcss";
}
$css_class =~ s/^\s+//;
if ($css_class) {
$css_class = ' class="'.$css_class.'"';
}
if ($rowstyle) {
$css_class .= ' style="'.$rowstyle.'"';
}
if ($rowid) {
$rowid = ' id="'.$rowid.'"';
}
$output = '<tr '.$css_class.$rowid.'>'.
'<td><span class="LC_nobreak">'.$rolename.'</span></td>'.
'<td class="LC_left_item" colspan="2"><table>';
my $rem;
my %checks;
if (ref($settings) eq 'HASH') {
my $hashref;
if ($context eq 'lti') {
if (ref($settings) eq 'HASH') {
$hashref = $settings->{'instdata'};
}
} elsif ($context eq 'privacy') {
my ($key,$inner) = split(/_/,$role);
if (ref($settings) eq 'HASH') {
if (ref($settings->{$key}) eq 'HASH') {
$hashref = $settings->{$key}->{$inner};
}
}
} elsif (ref($settings->{$context}) eq 'HASH') {
if (ref($settings->{$context}->{$role}) eq 'HASH') {
$hashref = $settings->{'lti_instdata'};
}
if ($role eq 'emailusername') {
if ($statustype) {
if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
$hashref = $settings->{$context}->{$role}->{$statustype};
}
}
}
}
if (ref($hashref) eq 'HASH') {
foreach my $field (@fields) {
if ($hashref->{$field}) {
if ($role eq 'emailusername') {
$checks{$field} = $hashref->{$field};
} else {
$checks{$field} = ' checked="checked" ';
}
}
}
}
}
my $total = scalar(@fields);
for (my $i=0; $i<$total; $i++) {
$rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$output .= '</tr>';
}
$output .= '<tr>';
}
my $check = ' ';
unless ($role eq 'emailusername') {
if (exists($checks{$fields[$i]})) {
$check = $checks{$fields[$i]};
} elsif ($context eq 'privacy') {
if ($role =~ /^priv_(domain|course)$/) {
if (ref($settings) ne 'HASH') {
$check = ' checked="checked" ';
}
} elsif ($role =~ /^priv_(author|community)$/) {
if (ref($settings) ne 'HASH') {
unless ($fields[$i] eq 'id') {
$check = ' checked="checked" ';
}
}
} elsif ($role =~ /^(unpriv|othdom)_/) {
if (ref($settings) ne 'HASH') {
if (($fields[$i] eq 'lastname') || ($fields[$i] eq 'firstname')) {
$check = ' checked="checked" ';
}
}
}
} elsif ($context ne 'lti') {
if ($role eq 'st') {
if (ref($settings) ne 'HASH') {
$check = ' checked="checked" ';
}
}
}
}
$output .= '<td class="LC_left_item">'.
'<span class="LC_nobreak">';
my $prefix = 'canmodify';
if ($role eq 'emailusername') {
unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {
$checks{$fields[$i]} = 'omit';
}
foreach my $option ('required','optional','omit') {
my $checked='';
if ($checks{$fields[$i]} eq $option) {
$checked='checked="checked" ';
}
$output .= '<label>'.
'<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.
&mt($option).'</label>'.(' ' x2);
}
$output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';
} else {
if ($context eq 'lti') {
$prefix = 'lti';
} elsif ($context eq 'coauthor') {
$prefix = 'cacanmodify';
} elsif ($context eq 'privacy') {
$prefix = 'privacy';
}
$output .= '<label>'.
'<input type="checkbox" name="'.$prefix.'_'.$role.'" '.
'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.
'</label>';
}
$output .= '</span></td>';
}
$rem = $total%$numinrow;
my $colsleft;
if ($rem) {
$colsleft = $numinrow - $rem;
}
if ($colsleft > 1) {
$output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
' </td>';
} elsif ($colsleft == 1) {
$output .= '<td class="LC_left_item"> </td>';
}
$output .= '</tr></table></td></tr>';
return $output;
}
sub insttypes_row {
my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,
$customcss,$rowstyle) = @_;
my %lt = &Apache::lonlocal::texthash (
cansearch => 'Users allowed to search',
statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',
lockablenames => 'User preference to lock name',
selfassign => 'Self-reportable affiliations',
overrides => "Override domain's helpdesk settings based on requester's affiliation",
webdav => 'WebDAV access available',
authorquota => 'Authoring Space quota (MB)',
);
my ($showdom,$defaultquota);
if ($context eq 'cansearch') {
$showdom = ' ('.$dom.')';
} elsif ($context eq 'authorquota') {
$defaultquota = 500;
}
my $class = 'LC_left_item';
if ($context eq 'statustocreate') {
$class = 'LC_right_item';
}
my $css_class;
if ($$rowtotal%2) {
$css_class = 'LC_odd_row';
}
if ($customcss) {
$css_class .= ' '.$customcss;
}
$css_class =~ s/^\s+//;
if ($css_class) {
$css_class = ' class="'.$css_class.'"';
}
if ($rowstyle) {
$css_class .= ' style="'.$rowstyle.'"';
}
if ($onclick) {
$onclick = 'onclick="'.$onclick.'" ';
}
my $output = '<tr'.$css_class.'>'.
'<td>'.$lt{$context}.$showdom.
'</td><td class="'.$class.'" colspan="2"><table>';
my $rem;
if (ref($types) eq 'ARRAY') {
for (my $i=0; $i<@{$types}; $i++) {
if (defined($usertypes->{$types->[$i]})) {
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$output .= '</tr>';
}
$output .= '<tr>';
}
if ($context eq 'authorquota') {
my $currquota;
if ($settings->{$context}->{$types->[$i]} =~ /^\d+$/) {
$currquota = $settings->{$context}->{$types->[$i]};
} else {
$currquota = $defaultquota;
}
$output .= '<td class="LC_left_item">'."\n".
'<label><span class="LC_nobreak">'."\n".
$usertypes->{$types->[$i]}.'</span><br />'."\n".
'<input type="text" name="'.$context.'_'.$types->[$i].'" '.
'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".
'</label></td>';
} else {
my $check = ' ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{$context}) eq 'ARRAY') {
if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {
$check = ' checked="checked" ';
}
} elsif (ref($settings->{$context}) eq 'HASH') {
if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {
$check = ' checked="checked" ';
} elsif ($context eq 'webdav') {
if ($settings->{$context}->{$types->[$i]}) {
$check = ' checked="checked" ';
}
}
} elsif ($context eq 'statustocreate') {
$check = ' checked="checked" ';
}
}
$output .= '<td class="LC_left_item">'.
'<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$context.'" '.
'value="'.$types->[$i].'"'.$check.$onclick.'/>'.
$usertypes->{$types->[$i]}.'</label></span></td>';
}
}
}
$rem = @{$types}%($numinrow);
}
my $colsleft = $numinrow - $rem;
if ($context eq 'overrides') {
if ($colsleft > 1) {
$output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
} else {
$output .= '<td class="LC_left_item">';
}
$output .= ' ';
} else {
if ($rem == 0) {
$output .= '<tr>';
}
if ($colsleft > 1) {
$output .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
} else {
$output .= '<td class="LC_left_item">';
}
if ($context eq 'authorquota') {
my $currquota = 500;
if ((ref($settings) eq 'HASH') && (ref($settings->{$context}) eq 'HASH')) {
if ($settings->{$context}{'default'} =~ /^\d+$/) {
$currquota = $settings->{$context}{'default'};
}
}
$output .= '<label><span class="LC_nobreak">'.$othertitle.'</span><br />'."\n".
'<input type="text" name="'.$context.'_default" '.
'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".
'</label>';
} else {
my $defcheck = ' ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{$context}) eq 'ARRAY') {
if (grep(/^default$/,@{$settings->{$context}})) {
$defcheck = ' checked="checked" ';
}
} elsif (ref($settings->{$context}) eq 'HASH') {
if (ref($settings->{$context}->{'default'}) eq 'HASH') {
$defcheck = ' checked="checked" ';
} elsif ($context eq 'webdav') {
if ($settings->{$context}->{'default'}) {
$defcheck = ' checked="checked" ';
}
}
} elsif ($context eq 'statustocreate') {
$defcheck = ' checked="checked" ';
}
}
$output .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$context.'" '.
'value="default"'.$defcheck.$onclick.'/>'.
$othertitle.'</label></span>';
}
}
$output .= '</td></tr></table></td></tr>';
return $output;
}
sub sorted_searchtitles {
my %searchtitles = &Apache::lonlocal::texthash(
'uname' => 'username',
'lastname' => 'last name',
'lastfirst' => 'last name, first name',
);
my @titleorder = ('uname','lastname','lastfirst');
return (\%searchtitles,\@titleorder);
}
sub sorted_searchtypes {
my %srchtypes_desc = (
exact => 'is exact match',
contains => 'contains ..',
begins => 'begins with ..',
);
my @srchtypeorder = ('exact','begins','contains');
return (\%srchtypes_desc,\@srchtypeorder);
}
sub usertype_update_row {
my ($settings,$usertypes,$fieldtitles,$fields,$types,$rownums) = @_;
my $datatable;
my $numinrow = 4;
foreach my $type (@{$types}) {
if (defined($usertypes->{$type})) {
$$rownums ++;
my $css_class = $$rownums%2?' class="LC_odd_row"':'';
$datatable .= '<tr'.$css_class.'><td>'.$usertypes->{$type}.
'</td><td class="LC_left_item"><table>';
for (my $i=0; $i<@{$fields}; $i++) {
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$datatable .= '</tr>';
}
$datatable .= '<tr>';
}
my $check = ' ';
if (ref($settings) eq 'HASH') {
if (ref($settings->{'fields'}) eq 'HASH') {
if (ref($settings->{'fields'}{$type}) eq 'ARRAY') {
if (grep(/^\Q$fields->[$i]\E$/,@{$settings->{'fields'}{$type}})) {
$check = ' checked="checked" ';
}
}
}
}
if ($i == @{$fields}-1) {
my $colsleft = $numinrow - $rem;
if ($colsleft > 1) {
$datatable .= '<td colspan="'.$colsleft.'">';
} else {
$datatable .= '<td>';
}
} else {
$datatable .= '<td>';
}
$datatable .= '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="updateable_'.$type.
'_'.$fields->[$i].'" value="1"'.$check.'/>'.
$fieldtitles->{$fields->[$i]}.'</label></span></td>';
}
$datatable .= '</tr></table></td></tr>';
}
}
return $datatable;
}
sub modify_login {
my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,
%curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon,
%currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso);
%title = ( coursecatalog => 'Display course catalog',
adminmail => 'Display administrator E-mail address',
helpdesk => 'Display "Contact Helpdesk" link',
newuser => 'Link for visitors to create a user account',
loginheader => 'Log-in box header',
saml => 'Dual SSO and non-SSO login');
@offon = ('off','on');
if (ref($domconfig{login}) eq 'HASH') {
if (ref($domconfig{login}{loginvia}) eq 'HASH') {
foreach my $lonhost (keys(%{$domconfig{login}{loginvia}})) {
$curr_loginvia{$lonhost} = $domconfig{login}{loginvia}{$lonhost};
}
}
if (ref($domconfig{login}{'saml'}) eq 'HASH') {
foreach my $lonhost (keys(%{$domconfig{login}{'saml'}})) {
if (ref($domconfig{login}{'saml'}{$lonhost}) eq 'HASH') {
$currsaml{$lonhost} = $domconfig{login}{'saml'}{$lonhost};
$saml{$lonhost} = 1;
$samltext{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'text'};
$samlurl{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'url'};
$samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'};
$samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'};
$samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'};
$samlwindow{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'window'};
$samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'};
}
}
}
}
($errors,%colchanges) = &modify_colors($r,$dom,$confname,['login'],
\%domconfig,\%loginhash);
my @toggles = ('coursecatalog','adminmail','helpdesk','newuser');
foreach my $item (@toggles) {
$loginhash{login}{$item} = $env{'form.'.$item};
}
$loginhash{login}{loginheader} = $env{'form.loginheader'};
if (ref($colchanges{'login'}) eq 'HASH') {
$colchgtext = &display_colorchgs($dom,\%colchanges,['login'],
\%loginhash);
}
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %domservers = &Apache::lonnet::get_servers($dom);
my @loginvia_attribs = ('serverpath','custompath','exempt');
if (keys(%servers) > 1) {
foreach my $lonhost (keys(%servers)) {
next if ($env{'form.'.$lonhost.'_server'} eq $lonhost);
if (ref($curr_loginvia{$lonhost}) eq 'HASH') {
if ($env{'form.'.$lonhost.'_server'} eq $curr_loginvia{$lonhost}{'server'}) {
$loginhash{login}{loginvia}{$lonhost}{'server'} = $curr_loginvia{$lonhost}{'server'};
} elsif ($curr_loginvia{$lonhost}{'server'} ne '') {
if (defined($servers{$env{'form.'.$lonhost.'_server'}})) {
$loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'};
$changes{'loginvia'}{$lonhost} = 1;
} else {
$loginhash{login}{loginvia}{$lonhost}{'server'} = '';
$changes{'loginvia'}{$lonhost} = 1;
}
} else {
if (defined($servers{$env{'form.'.$lonhost.'_server'}})) {
$loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'};
$changes{'loginvia'}{$lonhost} = 1;
}
}
if ($loginhash{login}{loginvia}{$lonhost}{'server'} eq '') {
foreach my $item (@loginvia_attribs) {
$loginhash{login}{loginvia}{$lonhost}{$item} = '';
}
} else {
foreach my $item (@loginvia_attribs) {
my $new = $env{'form.'.$lonhost.'_'.$item};
if (($item eq 'serverpath') && ($new eq 'custom')) {
$env{'form.'.$lonhost.'_custompath'} =~ s/\s+//g;
if ($env{'form.'.$lonhost.'_custompath'} eq '') {
$new = '/';
}
}
if (($item eq 'custompath') &&
($env{'form.'.$lonhost.'_serverpath'} ne 'custom')) {
$new = '';
}
if ($new ne $curr_loginvia{$lonhost}{$item}) {
$changes{'loginvia'}{$lonhost} = 1;
}
if ($item eq 'exempt') {
$new = &check_exempt_addresses($new);
}
$loginhash{login}{loginvia}{$lonhost}{$item} = $new;
}
}
} else {
if (defined($servers{$env{'form.'.$lonhost.'_server'}})) {
$loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'};
$changes{'loginvia'}{$lonhost} = 1;
foreach my $item (@loginvia_attribs) {
my $new = $env{'form.'.$lonhost.'_'.$item};
if (($item eq 'serverpath') && ($new eq 'custom')) {
if ($env{'form.'.$lonhost.'_custompath'} eq '') {
$new = '/';
}
}
if (($item eq 'custompath') &&
($env{'form.'.$lonhost.'_serverpath'} ne 'custom')) {
$new = '';
}
$loginhash{login}{loginvia}{$lonhost}{$item} = $new;
}
}
}
}
}
my $servadm = $r->dir_config('lonAdmEMail');
my %langchoices = &Apache::lonlocal::texthash(&get_languages_hash());
if (ref($domconfig{'login'}) eq 'HASH') {
if (ref($domconfig{'login'}{'helpurl'}) eq 'HASH') {
foreach my $lang (sort(keys(%{$domconfig{'login'}{'helpurl'}}))) {
if ($lang eq 'nolang') {
push(@currlangs,$lang);
} elsif (defined($langchoices{$lang})) {
push(@currlangs,$lang);
} else {
next;
}
}
}
}
my @delurls = &Apache::loncommon::get_env_multiple('form.loginhelpurl_del');
if (@currlangs > 0) {
foreach my $lang (@currlangs) {
if (grep(/^\Q$lang\E$/,@delurls)) {
$changes{'helpurl'}{$lang} = 1;
} elsif ($env{'form.loginhelpurl_'.$lang.'.filename'}) {
$changes{'helpurl'}{$lang} = 1;
$newfile{$lang} = $env{'form.loginhelpurl_'.$lang.'.filename'};
push(@newlangs,$lang);
} else {
$loginhash{'login'}{'helpurl'}{$lang} = $domconfig{'login'}{'helpurl'}{$lang};
}
}
}
unless (grep(/^nolang$/,@currlangs)) {
if ($env{'form.loginhelpurl_nolang.filename'}) {
$changes{'helpurl'}{'nolang'} = 1;
$newfile{'nolang'} = $env{'form.loginhelpurl_nolang.filename'};
push(@newlangs,'nolang');
}
}
if ($env{'form.loginhelpurl_add_lang'}) {
if ((defined($langchoices{$env{'form.loginhelpurl_add_lang'}})) &&
($env{'form.loginhelpurl_add_file.filename'})) {
$newfile{$env{'form.loginhelpurl_add_lang'}} = $env{'form.loginhelpurl_add_file.filename'};
$addedfile = $env{'form.loginhelpurl_add_lang'};
}
}
if ((@newlangs > 0) || ($addedfile)) {
my $error;
my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt("Upload of custom help file is not permitted to this server: [_1]",$switchserver);
} elsif ($author_ok eq 'ok') {
my @allnew = @newlangs;
if ($addedfile ne '') {
push(@allnew,$addedfile);
}
my $modified = [];
foreach my $lang (@allnew) {
my $formelem = 'loginhelpurl_'.$lang;
if ($lang eq $env{'form.loginhelpurl_add_lang'}) {
$formelem = 'loginhelpurl_add_file';
}
(my $result,$newurl{$lang}) =
&Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
"help/$lang",'','',$newfile{$lang},
$modified);
if ($result eq 'ok') {
$loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};
$changes{'helpurl'}{$lang} = 1;
} else {
my $puberror = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$newfile{$lang},$result);
$errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
if ((grep(/^\Q$lang\E$/,@currlangs)) &&
(!grep(/^\Q$lang\E$/,@delurls))) {
$loginhash{'login'}{'helpurl'}{$lang} = $domconfig{'login'}{'helpurl'}{$lang};
}
}
}
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok);
}
} else {
$error = &mt("Upload of custom log-in help file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2]. Error was: [_3].",$confname,$dom,$configuserok);
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
my (%currheadtagurls,%currexempt,@newhosts,%newheadtagurls,%possexempt);
if (ref($domconfig{'login'}) eq 'HASH') {
if (ref($domconfig{'login'}{'headtag'}) eq 'HASH') {
foreach my $lonhost (keys(%{$domconfig{'login'}{'headtag'}})) {
if ($domservers{$lonhost}) {
if (ref($domconfig{'login'}{'headtag'}{$lonhost}) eq 'HASH') {
$currheadtagurls{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'url'};
$currexempt{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'exempt'};
}
}
}
}
}
my @delheadtagurls = &Apache::loncommon::get_env_multiple('form.loginheadtag_del');
foreach my $lonhost (sort(keys(%domservers))) {
if (grep(/^\Q$lonhost\E$/,@delheadtagurls)) {
$changes{'headtag'}{$lonhost} = 1;
} else {
if ($env{'form.loginheadtagexempt_'.$lonhost}) {
$possexempt{$lonhost} = &check_exempt_addresses($env{'form.loginheadtagexempt_'.$lonhost});
}
if ($env{'form.loginheadtag_'.$lonhost.'.filename'}) {
push(@newhosts,$lonhost);
} elsif ($currheadtagurls{$lonhost}) {
$loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $currheadtagurls{$lonhost};
if ($currexempt{$lonhost}) {
if ((!exists($possexempt{$lonhost})) || ($possexempt{$lonhost} ne $currexempt{$lonhost})) {
$changes{'headtag'}{$lonhost} = 1;
}
} elsif ($possexempt{$lonhost}) {
$changes{'headtag'}{$lonhost} = 1;
}
if ($possexempt{$lonhost}) {
$loginhash{'login'}{'headtag'}{$lonhost}{'exempt'} = $possexempt{$lonhost};
}
}
}
}
if (@newhosts) {
my $error;
my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);
} elsif ($author_ok eq 'ok') {
my $modified = [];
foreach my $lonhost (@newhosts) {
my $formelem = 'loginheadtag_'.$lonhost;
(my $result,$newheadtagurls{$lonhost}) =
&Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
"login/headtag/$lonhost",'','',
$env{'form.loginheadtag_'.$lonhost.'.filename'},
$modified);
if ($result eq 'ok') {
$loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};
$changes{'headtag'}{$lonhost} = 1;
if ($possexempt{$lonhost}) {
$loginhash{'login'}{'headtag'}{$lonhost}{'exempt'} = $possexempt{$lonhost};
}
} else {
my $puberror = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",
$newheadtagurls{$lonhost},$result);
$errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
if ((grep(/^\Q$lonhost\E$/,keys(%currheadtagurls))) &&
(!grep(/^\Q$lonhost\E$/,@delheadtagurls))) {
$loginhash{'login'}{'headtag'}{$lonhost} = $currheadtagurls{$lonhost};
}
}
}
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok);
}
} else {
$error = &mt("Upload of custom markup file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2]. Error was: [_3].",$confname,$dom,$configuserok);
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
my @delsamlimg = &Apache::loncommon::get_env_multiple('form.saml_img_del');
my @newsamlimgs;
foreach my $lonhost (keys(%domservers)) {
if ($env{'form.saml_'.$lonhost}) {
if ($env{'form.saml_img_'.$lonhost.'.filename'}) {
push(@newsamlimgs,$lonhost);
}
foreach my $item ('text','alt','url','title','window','notsso') {
$env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;
}
if ($saml{$lonhost}) {
if ($env{'form.saml_window_'.$lonhost} ne '1') {
$env{'form.saml_window_'.$lonhost} = '';
}
if (grep(/^\Q$lonhost\E$/,@delsamlimg)) {
#FIXME Need to obsolete published image
delete($currsaml{$lonhost}{'img'});
$changes{'saml'}{$lonhost} = 1;
}
if ($env{'form.saml_alt_'.$lonhost} ne $samlalt{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
if ($env{'form.saml_text_'.$lonhost} ne $samltext{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
if ($env{'form.saml_url_'.$lonhost} ne $samlurl{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
if ($env{'form.saml_window_'.$lonhost} ne $samlwindow{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
} else {
$changes{'saml'}{$lonhost} = 1;
}
foreach my $item ('text','alt','url','title','window','notsso') {
$currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};
}
} else {
if ($saml{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
delete($currsaml{$lonhost});
}
}
}
foreach my $posshost (keys(%currsaml)) {
unless (exists($domservers{$posshost})) {
delete($currsaml{$posshost});
}
}
%{$loginhash{'login'}{'saml'}} = %currsaml;
if (@newsamlimgs) {
my $error;
my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);
} elsif ($author_ok eq 'ok') {
my $modified = [];
foreach my $lonhost (@newsamlimgs) {
my $formelem = 'saml_img_'.$lonhost;
my ($result,$imgurl) =
&Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
"login/saml/$lonhost",'','',
$env{'form.saml_img_'.$lonhost.'.filename'},
$modified);
if ($result eq 'ok') {
$currsaml{$lonhost}{'img'} = $imgurl;
$loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;
$changes{'saml'}{$lonhost} = 1;
} else {
my $puberror = &mt("Upload of SSO button image failed for [_1] because an error occurred publishing the file in RES space. Error was: [_2].",
$lonhost,$result);
$errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
}
}
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of SSO button image file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok);
}
} else {
$error = &mt("Upload of SSO button image file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2]. Error was: [_3].",$confname,$dom,$configuserok);
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
&process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'});
my $defaulthelpfile = '/adm/loginproblems.html';
my $defaulttext = &mt('Default in use');
my $putresult = &Apache::lonnet::put_dom('configuration',\%loginhash,
$dom);
if ($putresult eq 'ok') {
my @toggles = ('coursecatalog','adminmail','helpdesk','newuser');
my %defaultchecked = (
'coursecatalog' => 'on',
'helpdesk' => 'on',
'adminmail' => 'off',
'newuser' => 'off',
);
if (ref($domconfig{'login'}) eq 'HASH') {
foreach my $item (@toggles) {
if ($defaultchecked{$item} eq 'on') {
if (($domconfig{'login'}{$item} eq '0') &&
($env{'form.'.$item} eq '1')) {
$changes{$item} = 1;
} elsif (($domconfig{'login'}{$item} eq '' ||
$domconfig{'login'}{$item} eq '1') &&
($env{'form.'.$item} eq '0')) {
$changes{$item} = 1;
}
} elsif ($defaultchecked{$item} eq 'off') {
if (($domconfig{'login'}{$item} eq '1') &&
($env{'form.'.$item} eq '0')) {
$changes{$item} = 1;
} elsif (($domconfig{'login'}{$item} eq '' ||
$domconfig{'login'}{$item} eq '0') &&
($env{'form.'.$item} eq '1')) {
$changes{$item} = 1;
}
}
}
}
if (keys(%changes) > 0 || $colchgtext) {
&Apache::loncommon::devalidate_domconfig_cache($dom);
if (exists($changes{'saml'})) {
my $hostid_in_use;
my @hosts = &Apache::lonnet::current_machine_ids();
if (@hosts > 1) {
foreach my $hostid (@hosts) {
if (&Apache::lonnet::host_domain($hostid) eq $dom) {
$hostid_in_use = $hostid;
last;
}
}
} else {
$hostid_in_use = $r->dir_config('lonHostID');
}
if (($hostid_in_use) &&
(&Apache::lonnet::host_domain($hostid_in_use) eq $dom)) {
&Apache::lonnet::devalidate_cache_new('samllanding',$hostid_in_use);
}
if (ref($lastactref) eq 'HASH') {
if (ref($changes{'saml'}) eq 'HASH') {
my %updates;
map { $updates{$_} = 1; } keys(%{$changes{'saml'}});
$lastactref->{'samllanding'} = \%updates;
}
}
}
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
$resulttext = &mt('Changes made:').'<ul>';
foreach my $item (sort(keys(%changes))) {
if ($item eq 'loginvia') {
if (ref($changes{$item}) eq 'HASH') {
$resulttext .= '<li>'.&mt('Log-in page availability:').'<ul>';
foreach my $lonhost (sort(keys(%{$changes{$item}}))) {
if (defined($servers{$loginhash{login}{loginvia}{$lonhost}{'server'}})) {
if (ref($loginhash{login}{loginvia}{$lonhost}) eq 'HASH') {
my $protocol = $Apache::lonnet::protocol{$env{'form.'.$lonhost.'_server'}};
$protocol = 'http' if ($protocol ne 'https');
my $target = $protocol.'://'.$servers{$env{'form.'.$lonhost.'_server'}};
if ($loginhash{login}{loginvia}{$lonhost}{'serverpath'} eq 'custom') {
$target .= $loginhash{login}{loginvia}{$lonhost}{'custompath'};
} else {
$target .= $loginhash{login}{loginvia}{$lonhost}{'serverpath'};
}
$resulttext .= '<li>'.&mt('Server: [_1] log-in page redirects to [_2].',$servers{$lonhost},'<a href="'.$target.'">'.$target.'</a>');
if ($loginhash{login}{loginvia}{$lonhost}{'exempt'} ne '') {
$resulttext .= ' '.&mt('No redirection for clients from following IPs:').' '.$loginhash{login}{loginvia}{$lonhost}{'exempt'};
}
$resulttext .= '</li>';
} else {
$resulttext .= '<li>'.&mt('Server: [_1] has standard log-in page.',$lonhost).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Server: [_1] has standard log-in page.',$servers{$lonhost}).'</li>';
}
}
$resulttext .= '</ul></li>';
}
} elsif ($item eq 'helpurl') {
if (ref($changes{$item}) eq 'HASH') {
foreach my $lang (sort(keys(%{$changes{$item}}))) {
if (grep(/^\Q$lang\E$/,@delurls)) {
my ($chg,$link);
$link = &Apache::loncommon::modal_link($defaulthelpfile,$defaulttext,600,500);
if ($lang eq 'nolang') {
$chg = &mt('custom log-in help file removed for no preferred language; [_1]',$link);
} else {
$chg = &mt('custom log-in help file removed for specific language: [_1]; [_2]',$langchoices{$lang},$link);
}
$resulttext .= '<li>'.$chg.'</li>';
} else {
my $chg;
if ($lang eq 'nolang') {
$chg = &mt('custom log-in help file for no preferred language');
} else {
$chg = &mt('custom log-in help file for specific language: [_1]',$langchoices{$lang});
}
$resulttext .= '<li>'.&Apache::loncommon::modal_link(
$loginhash{'login'}{'helpurl'}{$lang}.
'?inhibitmenu=yes',$chg,600,500).
'</li>';
}
}
}
} elsif ($item eq 'headtag') {
if (ref($changes{$item}) eq 'HASH') {
foreach my $lonhost (sort(keys(%{$changes{$item}}))) {
if (grep(/^\Q$lonhost\E$/,@delheadtagurls)) {
$resulttext .= '<li>'.&mt('custom markup file removed for [_1]',$domservers{$lonhost}).'</li>';
} elsif (ref($loginhash{'login'}{'headtag'}{$lonhost}) eq 'HASH') {
$resulttext .= '<li><a href="'.
"javascript:void(open('$loginhash{'login'}{'headtag'}{$lonhost}{'url'}?inhibitmenu=yes','Custom_HeadTag',
'menubar=0,toolbar=1,scrollbars=1,width=600,height=500,resizable=yes'))".
'">'.&mt('custom markup').'</a> '.&mt('(for [_1])',$servers{$lonhost}).' ';
if ($possexempt{$lonhost}) {
$resulttext .= &mt('not included for client IP(s): [_1]',$possexempt{$lonhost});
} else {
$resulttext .= &mt('included for any client IP');
}
$resulttext .= '</li>';
}
}
}
} elsif ($item eq 'saml') {
if (ref($changes{$item}) eq 'HASH') {
my %notlt = (
text => 'Text for log-in by SSO',
img => 'SSO button image',
alt => 'Alt text for button image',
url => 'SSO URL',
title => 'Tooltip for SSO link',
window => 'Pop-up window if iframe',
notsso => 'Text for non-SSO log-in',
);
foreach my $lonhost (sort(keys(%{$changes{$item}}))) {
if (ref($currsaml{$lonhost}) eq 'HASH') {
$resulttext .= '<li>'.&mt("$title{$item} in use for [_1]","<b>$lonhost</b>").
'<ul>';
foreach my $key ('text','img','alt','url','title','window','notsso') {
if ($currsaml{$lonhost}{$key} eq '') {
$resulttext .= '<li>'.&mt("$notlt{$key} not in use").'</li>';
} else {
my $value = "'$currsaml{$lonhost}{$key}'";
if ($key eq 'img') {
$value = '<img src="'.$currsaml{$lonhost}{$key}.'" />';
} elsif ($key eq 'window') {
$value = 'On';
}
$resulttext .= '<li>'.&mt("$notlt{$key} set to: [_1]",
$value).'</li>';
}
}
$resulttext .= '</ul></li>';
} else {
$resulttext .= '<li>'.&mt("$title{$item} not in use for [_1]",$lonhost).'</li>';
}
}
}
} elsif ($item eq 'captcha') {
if (ref($loginhash{'login'}) eq 'HASH') {
my $chgtxt;
if ($loginhash{'login'}{$item} eq 'notused') {
$chgtxt .= &mt('No CAPTCHA validation in use for helpdesk form.');
} else {
my %captchas = &captcha_phrases();
if ($captchas{$loginhash{'login'}{$item}}) {
$chgtxt .= &mt("Validation for helpdesk form set to $captchas{$loginhash{'login'}{$item}}.");
} else {
$chgtxt .= &mt('Validation for helpdesk form set to unknown type.');
}
}
$resulttext .= '<li>'.$chgtxt.'</li>';
}
} elsif ($item eq 'recaptchakeys') {
if (ref($loginhash{'login'}) eq 'HASH') {
my ($privkey,$pubkey);
if (ref($loginhash{'login'}{$item}) eq 'HASH') {
$pubkey = $loginhash{'login'}{$item}{'public'};
$privkey = $loginhash{'login'}{$item}{'private'};
}
my $chgtxt .= &mt('ReCAPTCHA keys changes').'<ul>';
if (!$pubkey) {
$chgtxt .= '<li>'.&mt('Public key deleted').'</li>';
} else {
$chgtxt .= '<li>'.&mt('Public key set to [_1]',$pubkey).'</li>';
}
if (!$privkey) {
$chgtxt .= '<li>'.&mt('Private key deleted').'</li>';
} else {
$chgtxt .= '<li>'.&mt('Private key set to [_1]',$privkey).'</li>';
}
$chgtxt .= '</ul>';
$resulttext .= '<li>'.$chgtxt.'</li>';
}
} elsif ($item eq 'recaptchaversion') {
if (ref($loginhash{'login'}) eq 'HASH') {
if ($loginhash{'login'}{'captcha'} eq 'recaptcha') {
$resulttext .= '<li>'.&mt('ReCAPTCHA for helpdesk form set to version [_1]',$loginhash{'login'}{'recaptchaversion'}).
'</li>';
}
}
} else {
$resulttext .= '<li>'.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'</li>';
}
}
$resulttext .= $colchgtext.'</ul>';
} else {
$resulttext = &mt('No changes made to log-in page settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if ($errors) {
$resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul>';
}
return $resulttext;
}
sub check_exempt_addresses {
my ($iplist) = @_;
$iplist =~ s/^\s+//;
$iplist =~ s/\s+$//;
my @poss_ips = split(/\s*[,:]\s*/,$iplist);
my (@okips,$new);
foreach my $ip (@poss_ips) {
if ($ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
if (($1 <= 255) && ($2 <= 255) && ($3 <= 255) && ($4 <= 255)) {
push(@okips,$ip);
}
}
}
if (@okips > 0) {
$new = join(',',@okips);
} else {
$new = '';
}
return $new;
}
sub color_font_choices {
my %choices =
&Apache::lonlocal::texthash (
bgs => "Background colors",
links => "Link colors",
images => "Images",
font => "Font color",
fontmenu => "Font menu",
pgbg => "Page",
tabbg => "Header",
sidebg => "Border",
link => "Link",
alink => "Active link",
vlink => "Visited link",
);
return %choices;
}
sub modify_ipaccess {
my ($dom,$lastactref,%domconfig) = @_;
my (@allpos,%changes,%confhash,$errors,$resulttext);
my (@items,%deletions,%itemids,@warnings);
my ($typeorder,$types) = &commblocktype_text();
if ($env{'form.ipaccess_add'}) {
my $name = $env{'form.ipaccess_name_add'};
my ($newid,$error) = &get_ipaccess_id($dom,$name);
if ($newid) {
$itemids{'add'} = $newid;
push(@items,'add');
$changes{$newid} = 1;
} else {
$error = &mt('Failed to acquire unique ID for new IP access control item');
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
if (ref($domconfig{'ipaccess'}) eq 'HASH') {
my @todelete = &Apache::loncommon::get_env_multiple('form.ipaccess_del');
if (@todelete) {
map { $deletions{$_} = 1; } @todelete;
}
my $maxnum = $env{'form.ipaccess_maxnum'};
for (my $i=0; $i<$maxnum; $i++) {
my $itemid = $env{'form.ipaccess_id_'.$i};
$itemid =~ s/\D+//g;
if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {
if ($deletions{$itemid}) {
$changes{$itemid} = $domconfig{'ipaccess'}{$itemid}{'name'};
} else {
push(@items,$i);
$itemids{$i} = $itemid;
}
}
}
}
foreach my $idx (@items) {
my $itemid = $itemids{$idx};
next unless ($itemid);
my %current;
unless ($idx eq 'add') {
if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {
%current = %{$domconfig{'ipaccess'}{$itemid}};
}
}
my $position = $env{'form.ipaccess_pos_'.$itemid};
$position =~ s/\D+//g;
if ($position ne '') {
$allpos[$position] = $itemid;
}
my $name = $env{'form.ipaccess_name_'.$idx};
$name =~ s/^\s+|\s+$//g;
$confhash{$itemid}{'name'} = $name;
my $possrange = $env{'form.ipaccess_range_'.$idx};
$possrange =~ s/^\s+|\s+$//g;
unless ($possrange eq '') {
$possrange =~ s/[\r\n]+/\s/g;
$possrange =~ s/\s*-\s*/-/g;
$possrange =~ s/\s+/,/g;
$possrange =~ s/,+/,/g;
if ($possrange ne '') {
my (@ok,$count);
$count = 0;
foreach my $poss (split(/\,/,$possrange)) {
$count ++;
$poss = &validate_ip_pattern($poss);
if ($poss ne '') {
push(@ok,$poss);
}
}
my $diff = $count - scalar(@ok);
if ($diff) {
$errors .= '<li><span class="LC_error">'.
&mt('[quant,_1,IP] invalid and excluded from saved value for IP range(s) for [_2]',
$diff,$name).
'</span></li>';
}
if (@ok) {
my @cidr_list;
foreach my $item (@ok) {
@cidr_list = &Net::CIDR::cidradd($item,@cidr_list);
}
$confhash{$itemid}{'ip'} = join(',',@cidr_list);
}
}
}
foreach my $field ('name','ip') {
unless (($idx eq 'add') || ($changes{$itemid})) {
if ($current{$field} ne $confhash{$itemid}{$field}) {
$changes{$itemid} = 1;
last;
}
}
}
$confhash{$itemid}{'commblocks'} = {};
my %commblocks;
map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx);
foreach my $type (@{$typeorder}) {
if ($commblocks{$type}) {
$confhash{$itemid}{'commblocks'}{$type} = 'on';
}
unless (($idx eq 'add') || ($changes{$itemid})) {
if (ref($current{'commblocks'}) eq 'HASH') {
if ($confhash{$itemid}{'commblocks'}{$type} ne $current{'commblocks'}{$type}) {
$changes{$itemid} = 1;
}
} elsif ($confhash{$itemid}{'commblocks'}{$type}) {
$changes{$itemid} = 1;
}
}
}
$confhash{$itemid}{'courses'} = {};
my %crsdeletions;
my @delcrs = &Apache::loncommon::get_env_multiple('form.ipaccess_course_delete_'.$idx);
if (@delcrs) {
map { $crsdeletions{$_} = 1; } @delcrs;
}
if (ref($current{'courses'}) eq 'HASH') {
foreach my $cid (sort(keys(%{$current{'courses'}}))) {
if ($crsdeletions{$cid}) {
$changes{$itemid} = 1;
} else {
$confhash{$itemid}{'courses'}{$cid} = 1;
}
}
}
$env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g;
$env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g;
if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) &&
($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) {
if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx},
$env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') {
$errors .= '<li><span class="LC_error">'.
&mt('Invalid courseID [_1] omitted from list of allowed courses',
$env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}).
'</span></li>';
} else {
$confhash{$itemid}{'courses'}{$env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}} = 1;
$changes{$itemid} = 1;
}
}
}
if (@allpos > 0) {
my $idx = 0;
foreach my $itemid (@allpos) {
if ($itemid ne '') {
$confhash{$itemid}{'order'} = $idx;
unless ($changes{$itemid}) {
if (ref($domconfig{'ipaccess'}) eq 'HASH') {
if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') {
if ($domconfig{'ipaccess'}{$itemid}{'order'} ne $idx) {
$changes{$itemid} = 1;
}
}
}
}
$idx ++;
}
}
}
if (keys(%changes)) {
my %defaultshash = (
ipaccess => \%confhash,
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
$dom);
if ($putresult eq 'ok') {
my $cachetime = 1800;
&Apache::lonnet::do_cache_new('ipaccess',$dom,\%confhash,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'ipaccess'} = 1;
}
$resulttext = &mt('Changes made:').'<ul>';
my %bynum;
foreach my $itemid (sort(keys(%changes))) {
if (ref($confhash{$itemid}) eq 'HASH') {
my $position = $confhash{$itemid}{'order'};
if ($position =~ /^\d+$/) {
$bynum{$position} = $itemid;
}
}
}
if (keys(%deletions)) {
foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {
$resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
}
}
foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
my $itemid = $bynum{$pos};
if (ref($confhash{$itemid}) eq 'HASH') {
$resulttext .= '<li><b>'.$confhash{$itemid}{'name'}.'</b><ul>';
my $position = $pos + 1;
$resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
if ($confhash{$itemid}{'ip'} eq '') {
$resulttext .= '<li>'.&mt('No IP Range(s) set').'</li>';
} else {
$resulttext .= '<li>'.&mt('IP Range(s): [_1]',$confhash{$itemid}{'ip'}).'</li>';
}
if (keys(%{$confhash{$itemid}{'commblocks'}})) {
$resulttext .= '<li>'.&mt('Functionality Blocked: [_1]',
join(', ', map { $types->{$_}; } sort(keys(%{$confhash{$itemid}{'commblocks'}})))).
'</li>';
} else {
$resulttext .= '<li>'.&mt('No functionality blocked').'</li>';
}
if (keys(%{$confhash{$itemid}{'courses'}})) {
my @courses;
foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) {
my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1});
push(@courses,$courseinfo{'description'}.' ('.$cid.')');
}
$resulttext .= '<li>'.&mt('Courses/Communities allowed').':<ul><li>'.
join('</li><li>',@courses).'</li></ul>';
} else {
$resulttext .= '<li>'.&mt('No courses allowed').'</li>';
}
$resulttext .= '</ul></li>';
}
}
$resulttext .= '</ul>';
} else {
$errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
}
} else {
$resulttext = &mt('No changes made');
}
if ($errors) {
$resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul></p>';
}
return $resulttext;
}
sub get_ipaccess_id {
my ($domain,$location) = @_;
# get lock on ipaccess db
my $lockhash = {
lock => $env{'user.name'}.
':'.$env{'user.domain'},
};
my $tries = 0;
my $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain);
my ($id,$error);
while (($gotlock ne 'ok') && ($tries<10)) {
$tries ++;
sleep (0.1);
$gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain);
}
if ($gotlock eq 'ok') {
my %currids = &Apache::lonnet::dump_dom('ipaccess',$domain);
if ($currids{'lock'}) {
delete($currids{'lock'});
if (keys(%currids)) {
my @curr = sort { $a <=> $b } keys(%currids);
if ($curr[-1] =~ /^\d+$/) {
$id = 1 + $curr[-1];
}
} else {
$id = 1;
}
if ($id) {
unless (&Apache::lonnet::newput_dom('ipaccess',{ $id => $location },$domain) eq 'ok') {
$error = 'nostore';
}
} else {
$error = 'nonumber';
}
}
my $dellockoutcome = &Apache::lonnet::del_dom('ipaccess',['lock'],$domain);
} else {
$error = 'nolock';
}
return ($id,$error);
}
sub modify_authordefaults {
my ($dom,$lastactref,%domconfig) = @_;
#
# Retrieve current domain configuration for webDAV and Authoring Space quotas from $domconfig{'quotas'}.
#
my (%curr_quotas,%save_quotas,%confhash,%changes,%newvalues);
if (ref($domconfig{'quotas'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'quotas'}})) {
if ($key =~ /^webdav|authorquota$/) {
$curr_quotas{$key} = $domconfig{'quotas'}{$key};
} else {
$save_quotas{$key} = $domconfig{'quotas'}{$key};
}
}
}
my %staticdefaults = (
'copyright' => 'default',
'sourceavail' => 'closed',
'nocodemirror' => 'off',
'daxecollapse' => 'off',
'domcoordacc' => 'on',
'editors' => ['edit','xml'],
'authorquota' => 500,
'webdav' => 0,
'archive' => 'off',
);
my %titles = &authordefaults_titles();
foreach my $item ('nocodemirror','daxecollapse','domcoordacc','archive') {
if ($env{'form.'.$item} =~ /^(0|1)$/) {
$confhash{$item} = $env{'form.'.$item};
}
}
if ($env{'form.copyright'} =~ /^(default|domain|public)$/) {
$confhash{'copyright'} = $1;
}
if ($env{'form.sourceavail'} =~ /^(closed|open)$/) {
$confhash{'sourceavail'} = $1;
}
my @posseditors = &Apache::loncommon::get_env_multiple('form.author_editors');
my @okeditors = ('edit','xml','daxe');
my @editors;
foreach my $item (@posseditors) {
if (grep(/^\Q$item\E$/,@okeditors)) {
push(@editors,$item);
}
}
$confhash{'editors'} = \@editors;
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my @insttypes;
if (ref($types) eq 'ARRAY') {
@insttypes = @{$types};
}
my @webdavon = &Apache::loncommon::get_env_multiple('form.webdav');
my %webdav;
map { $webdav{$_} = 1; } @webdavon;
foreach my $type (@insttypes,'default') {
my $possquota = $env{'form.authorquota_'.$type};
if ($possquota =~ /^\d+$/) {
$save_quotas{'authorquota'}{$type} = $possquota;
}
if ($webdav{$type}) {
$save_quotas{'webdav'}{$type} = 1;
} else {
$save_quotas{'webdav'}{$type} = 0;
}
}
if ($env{'form.webdav_LC_adv'} =~ /^(0|1)$/) {
$save_quotas{'webdav'}{'_LC_adv'} = $env{'form.webdav_LC_adv'};
}
if (ref($domconfig{'authordefaults'}) eq 'HASH') {
foreach my $item ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail','archive') {
if ($domconfig{'authordefaults'}{$item} ne $confhash{$item}) {
$changes{$item} = 1;
}
}
if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') {
my @diffs =
&Apache::loncommon::compare_arrays($confhash{'editors'},
$domconfig{'authordefaults'}{'editors'});
unless (@diffs == 0) {
$changes{'editors'} = 1;
}
} else {
my @diffs =
&Apache::loncommon::compare_arrays($confhash{'editors'},
$staticdefaults{'editors'});
unless (@diffs == 0) {
$changes{'editors'} = 1;
}
}
} else {
my @offon = ('off','on');
foreach my $item ('nocodemirror','daxecollapse','domcoordacc','archive') {
if ($offon[$confhash{$item}] ne $staticdefaults{$item}) {
$changes{$item} = 1;
}
}
foreach my $item ('copyright','sourceavail') {
if ($confhash{$item} ne $staticdefaults{$item}) {
$changes{$item} = 1;
}
}
my @diffs =
&Apache::loncommon::compare_arrays($confhash{'editors'},
$staticdefaults{'editors'});
unless (@diffs == 0) {
$changes{'editors'} = 1;
}
}
foreach my $key ('authorquota','webdav') {
if (ref($curr_quotas{$key}) eq 'HASH') {
foreach my $type (@insttypes,'default') {
if (exists($save_quotas{$key}{$type})) {
if ($save_quotas{$key}{$type} ne $curr_quotas{$key}{$type}) {
$changes{$key}{$type} = 1;
}
} elsif (exists($curr_quotas{$key}{$type})) {
$save_quotas{$key}{$type} = $curr_quotas{$key}{$type};
} else {
$save_quotas{$key}{$type} = $staticdefaults{$key};
}
}
} else {
foreach my $type (@insttypes,'default') {
if (exists($save_quotas{$key}{$type})) {
unless ($save_quotas{$key}{$type} eq $staticdefaults{$key}) {
$changes{$key}{$type} = 1;
}
} else {
$save_quotas{$key}{$type} = $staticdefaults{$key};
}
}
}
}
if (ref($curr_quotas{'webdav'}) eq 'HASH') {
if (exists($save_quotas{'webdav'}{'_LC_adv'})) {
if ($save_quotas{'webdav'}{'_LC_adv'} ne $curr_quotas{'webdav'}{'_LC_adv'}) {
$changes{'webdav_LC_adv'} = 1;
}
} elsif (exists($curr_quotas{'webdav'}{'_LC_adv'})) {
$changes{'webdav_LC_adv'} = 1;
}
} elsif (exists($save_quotas{'webdav'}{'_LC_adv'})) {
$changes{'webdav_LC_adv'} = 1;
}
my %confighash = (
quotas => \%save_quotas,
authordefaults => \%confhash,
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,
$dom);
my $resulttext;
if ($putresult eq 'ok') {
if (keys(%changes)) {
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
if ((exists($changes{'authorquota'})) || (exists($changes{'webdav'})) ||
($changes{'webdav_LC_adv'})) {
if ((exists($changes{'authorquota'})) && (ref($save_quotas{'authorquota'}) eq 'HASH')) {
$domdefaults{'authorquota'} = $save_quotas{'authorquota'};
}
if (((exists($changes{'webdav'})) || ($changes{'webdav_LC_adv'})) &&
(ref($save_quotas{'webdav'}) eq 'HASH')) {
$domdefaults{'webdav'} = $save_quotas{'webdav'};
}
}
$resulttext = &mt('Changes made:').'<ul>';
my $authoroverride;
foreach my $key ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') {
if (exists($changes{$key})) {
$domdefaults{$key} = $confhash{$key};
my $shown;
unless ($authoroverride) {
$resulttext .= '<li>'.&mt('Defaults which can be overridden by Author').'<ul>';
$authoroverride = 1;
}
if (($key eq 'nocodemirror') || ($key eq 'daxecollapse') || ($key eq 'domcoordacc')) {
$shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));
} elsif ($key eq 'copyright') {
$shown = &Apache::loncommon::copyrightdescription($confhash{$key});
} elsif ($key eq 'sourceavail') {
$shown = &Apache::loncommon::source_copyrightdescription($confhash{$key});
}
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
}
}
if ($authoroverride) {
$resulttext .= '</ul></li>';
}
my $domcoordoverride;
foreach my $key ('editors','authorquota','webdav','webdav_LC_adv','archive') {
if (exists($changes{$key})) {
my $shown;
unless ($domcoordoverride) {
$resulttext .= '<li>'.&mt('Defaults which can be overridden by a Domain Coodinator').'<ul>';
$domcoordoverride = 1;
}
if ($key eq 'editors') {
if (ref($confhash{'editors'}) eq 'ARRAY') {
$domdefaults{'editors'} = join(',',@{$confhash{'editors'}});
if (@{$confhash{'editors'}}) {
$shown = join(', ', map { $titles{$_} } @{$confhash{'editors'}});
} else {
$shown = &mt('None');
}
}
} elsif ($key eq 'authorquota') {
foreach my $type (@insttypes) {
$shown .= $usertypes->{$type}.' -- '.$save_quotas{$key}{$type}.', ';
}
$shown .= $othertitle.' -- '.$save_quotas{$key}{'default'};
} elsif ($key eq 'webdav') {
foreach my $type (@insttypes) {
$shown .= $usertypes->{$type}.' -- '. ($save_quotas{$key}{$type} ? &mt('Yes') : &mt('No')).', ';
}
$shown .= $othertitle.' -- '. ($save_quotas{$key}{'default'} ? &mt('Yes') : &mt('No'));
} elsif ($key eq 'webdav_LC_adv') {
if (exists($save_quotas{'webdav'}{'_LC_adv'})) {
$shown = ($save_quotas{'webdav'}{'_LC_adv'} ? $titles{'overon'} : $titles{'overoff'});
} else {
$shown = $titles{'none'};
}
} elsif ($key eq 'archive') {
$domdefaults{$key} = $confhash{$key};
$shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));
}
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
}
}
if ($domcoordoverride) {
$resulttext .= '</ul></li>';
}
$resulttext .= '</ul>';
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
} else {
$resulttext = &mt('No changes made to Authoring Space defaults');
}
}
return $resulttext;
}
sub modify_rolecolors {
my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
my ($resulttext,%rolehash);
$rolehash{'rolecolors'} = {};
if (ref($domconfig{'rolecolors'}) ne 'HASH') {
if ($domconfig{'rolecolors'} eq '') {
$domconfig{'rolecolors'} = {};
}
}
my ($errors,%changes) = &modify_colors($r,$dom,$confname,$roles,
$domconfig{'rolecolors'},$rolehash{'rolecolors'});
my $putresult = &Apache::lonnet::put_dom('configuration',\%rolehash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
&Apache::loncommon::devalidate_domconfig_cache($dom);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
$resulttext = &display_colorchgs($dom,\%changes,$roles,
$rolehash{'rolecolors'});
} else {
$resulttext = &mt('No changes made to default color schemes');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if ($errors) {
$resulttext .= &mt('The following errors occurred: ').'<ul>'.
$errors.'</ul>';
}
return $resulttext;
}
sub modify_colors {
my ($r,$dom,$confname,$roles,$domconfig,$confhash) = @_;
my (%changes,%choices);
my @bgs;
my @links = ('link','alink','vlink');
my @logintext;
my @images;
my $servadm = $r->dir_config('lonAdmEMail');
my $errors;
my %defaults;
foreach my $role (@{$roles}) {
if ($role eq 'login') {
%choices = &login_choices();
@logintext = ('textcol','bgcol');
} else {
%choices = &color_font_choices();
}
if ($role eq 'login') {
@images = ('img','logo','domlogo','login');
@bgs = ('pgbg','mainbg','sidebg');
} else {
@images = ();
@bgs = ('pgbg','tabbg','sidebg');
}
my %defaults = &role_defaults($role,\@bgs,\@links,\@images,\@logintext);
$env{'form.'.$role.'_font'} = lc($env{'form.'.$role.'_font'});
if ($env{'form.'.$role.'_font'} =~ /^\w+/) {
$env{'form.'.$role.'_font'} = '#'.$env{'form.'.$role.'_font'};
}
unless ($env{'form.'.$role.'_font'} eq lc($defaults{'font'})) {
$confhash->{$role}{'font'} = $env{'form.'.$role.'_font'};
}
if ($role eq 'login') {
foreach my $item (@logintext) {
$env{'form.'.$role.'_'.$item} = lc($env{'form.'.$role.'_'.$item});
if ($env{'form.'.$role.'_'.$item} =~ /^\w+/) {
$env{'form.'.$role.'_'.$item} = '#'.$env{'form.'.$role.'_'.$item};
}
unless ($env{'form.'.$role.'_'.$item} eq lc($defaults{'logintext'}{$item})) {
$confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item};
}
}
} else {
$env{'form.'.$role.'_fontmenu'} = lc($env{'form.'.$role.'_fontmenu'});
if ($env{'form.'.$role.'_fontmenu'} =~ /^\w+/) {
$env{'form.'.$role.'_fontmenu'} = '#'.$env{'form.'.$role.'_fontmenu'};
}
unless ($env{'form.'.$role.'_fontmenu'} eq lc($defaults{'fontmenu'})) {
$confhash->{$role}{'fontmenu'} = $env{'form.'.$role.'_fontmenu'};
}
}
foreach my $item (@bgs) {
$env{'form.'.$role.'_'.$item} = lc($env{'form.'.$role.'_'.$item});
if ($env{'form.'.$role.'_'.$item} =~ /^\w+/) {
$env{'form.'.$role.'_'.$item} = '#'.$env{'form.'.$role.'_'.$item};
}
unless ($env{'form.'.$role.'_'.$item} eq lc($defaults{'bgs'}{$item})) {
$confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item};
}
}
foreach my $item (@links) {
$env{'form.'.$role.'_'.$item} = lc($env{'form.'.$role.'_'.$item});
if ($env{'form.'.$role.'_'.$item} =~ /^\w+/) {
$env{'form.'.$role.'_'.$item} = '#'.$env{'form.'.$role.'_'.$item};
}
unless ($env{'form.'.$role.'_'.$item} eq lc($defaults{'links'}{$item})) {
$confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item};
}
}
my ($configuserok,$author_ok,$switchserver) =
&config_check($dom,$confname,$servadm);
my ($width,$height) = &thumb_dimensions();
if (ref($domconfig->{$role}) ne 'HASH') {
$domconfig->{$role} = {};
}
foreach my $img (@images) {
if ($role eq 'login') {
if (($img eq 'img') || ($img eq 'logo')) {
if (defined($env{'form.login_showlogo_'.$img})) {
$confhash->{$role}{'showlogo'}{$img} = 1;
} else {
$confhash->{$role}{'showlogo'}{$img} = 0;
}
}
if ($env{'form.login_alt_'.$img} ne '') {
$confhash->{$role}{'alttext'}{$img} = $env{'form.login_alt_'.$img};
}
}
if ( ! $env{'form.'.$role.'_'.$img.'.filename'}
&& !defined($domconfig->{$role}{$img})
&& !$env{'form.'.$role.'_del_'.$img}
&& $env{'form.'.$role.'_import_'.$img}) {
# import the old configured image from the .tab setting
# if they haven't provided a new one
$domconfig->{$role}{$img} =
$env{'form.'.$role.'_import_'.$img};
}
if ($env{'form.'.$role.'_'.$img.'.filename'} ne '') {
my $error;
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver);
} else {
if ($author_ok eq 'ok') {
my $modified = [];
my ($result,$logourl) =
&Apache::lonconfigsettings::publishlogo($r,'upload',$role.'_'.$img,
$dom,$confname,$img,$width,$height,
'',$modified);
if ($result eq 'ok') {
$confhash->{$role}{$img} = $logourl;
$changes{$role}{'images'}{$img} = 1;
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of [_1] image for $role page(s) failed because an error occurred publishing the file in RES space. Error was: [_2].",$choices{img},$result);
}
} else {
$error = &mt("Upload of [_1] image for $role page(s) failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$choices{$img},$confname,$dom,$author_ok);
}
}
} else {
$error = &mt("Upload of [_1] image for $role page(s) failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$choices{$img},$confname,$dom,$configuserok);
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
} elsif ($domconfig->{$role}{$img} ne '') {
if ($domconfig->{$role}{$img} !~ m-^(/res/\Q$dom\E/\Q$confname\E/\Q$img\E)/([^/]+)$-) {
my $error;
if ($configuserok eq 'ok') {
# is confname an author?
if ($switchserver eq '') {
if ($author_ok eq 'ok') {
my $modified = [];
my ($result,$logourl) =
&Apache::lonconfigsettings::publishlogo($r,'copy',$domconfig->{$role}{$img},
$dom,$confname,$img,$width,$height,
'',$modified);
if ($result eq 'ok') {
$confhash->{$role}{$img} = $logourl;
$changes{$role}{'images'}{$img} = 1;
&update_modify_urls($r,$modified);
}
}
}
}
}
}
}
if (ref($domconfig) eq 'HASH') {
if (ref($domconfig->{$role}) eq 'HASH') {
foreach my $img (@images) {
if ($domconfig->{$role}{$img} ne '') {
if ($env{'form.'.$role.'_del_'.$img}) {
$confhash->{$role}{$img} = '';
$changes{$role}{'images'}{$img} = 1;
} else {
if ($confhash->{$role}{$img} eq '') {
$confhash->{$role}{$img} = $domconfig->{$role}{$img};
}
}
} else {
if ($env{'form.'.$role.'_del_'.$img}) {
$confhash->{$role}{$img} = '';
$changes{$role}{'images'}{$img} = 1;
}
}
if ($role eq 'login') {
if (($img eq 'logo') || ($img eq 'img')) {
if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') {
if ($confhash->{$role}{'showlogo'}{$img} ne
$domconfig->{$role}{'showlogo'}{$img}) {
$changes{$role}{'showlogo'}{$img} = 1;
}
} else {
if ($confhash->{$role}{'showlogo'}{$img} == 0) {
$changes{$role}{'showlogo'}{$img} = 1;
}
}
}
if ($img ne 'login') {
if (ref($domconfig->{$role}{'alttext'}) eq 'HASH') {
if ($confhash->{$role}{'alttext'}{$img} ne
$domconfig->{$role}{'alttext'}{$img}) {
$changes{$role}{'alttext'}{$img} = 1;
}
} else {
if ($confhash->{$role}{'alttext'}{$img} ne '') {
$changes{$role}{'alttext'}{$img} = 1;
}
}
}
}
}
if ($domconfig->{$role}{'font'} ne '') {
if ($confhash->{$role}{'font'} ne $domconfig->{$role}{'font'}) {
$changes{$role}{'font'} = 1;
}
} else {
if ($confhash->{$role}{'font'}) {
$changes{$role}{'font'} = 1;
}
}
if ($role ne 'login') {
if ($domconfig->{$role}{'fontmenu'} ne '') {
if ($confhash->{$role}{'fontmenu'} ne $domconfig->{$role}{'fontmenu'}) {
$changes{$role}{'fontmenu'} = 1;
}
} else {
if ($confhash->{$role}{'fontmenu'}) {
$changes{$role}{'fontmenu'} = 1;
}
}
}
foreach my $item (@bgs) {
if ($domconfig->{$role}{$item} ne '') {
if ($confhash->{$role}{$item} ne $domconfig->{$role}{$item}) {
$changes{$role}{'bgs'}{$item} = 1;
}
} else {
if ($confhash->{$role}{$item}) {
$changes{$role}{'bgs'}{$item} = 1;
}
}
}
foreach my $item (@links) {
if ($domconfig->{$role}{$item} ne '') {
if ($confhash->{$role}{$item} ne $domconfig->{$role}{$item}) {
$changes{$role}{'links'}{$item} = 1;
}
} else {
if ($confhash->{$role}{$item}) {
$changes{$role}{'links'}{$item} = 1;
}
}
}
foreach my $item (@logintext) {
if ($domconfig->{$role}{$item} ne '') {
if ($confhash->{$role}{$item} ne $domconfig->{$role}{$item}) {
$changes{$role}{'logintext'}{$item} = 1;
}
} else {
if ($confhash->{$role}{$item}) {
$changes{$role}{'logintext'}{$item} = 1;
}
}
}
} else {
&default_change_checker($role,\@images,\@links,\@bgs,
\@logintext,$confhash,\%changes);
}
} else {
&default_change_checker($role,\@images,\@links,\@bgs,
\@logintext,$confhash,\%changes);
}
}
return ($errors,%changes);
}
sub config_check {
my ($dom,$confname,$servadm) = @_;
my ($configuserok,$author_ok,$switchserver,%currroles);
my $uhome = &Apache::lonnet::homeserver($confname,$dom,1);
($configuserok,%currroles) = &check_configuser($uhome,$dom,
$confname,$servadm);
if ($configuserok eq 'ok') {
$switchserver = &check_switchserver($dom,$confname);
if ($switchserver eq '') {
$author_ok = &check_authorstatus($dom,$confname,%currroles);
}
}
return ($configuserok,$author_ok,$switchserver);
}
sub default_change_checker {
my ($role,$images,$links,$bgs,$logintext,$confhash,$changes) = @_;
foreach my $item (@{$links}) {
if ($confhash->{$role}{$item}) {
$changes->{$role}{'links'}{$item} = 1;
}
}
foreach my $item (@{$bgs}) {
if ($confhash->{$role}{$item}) {
$changes->{$role}{'bgs'}{$item} = 1;
}
}
foreach my $item (@{$logintext}) {
if ($confhash->{$role}{$item}) {
$changes->{$role}{'logintext'}{$item} = 1;
}
}
foreach my $img (@{$images}) {
if ($env{'form.'.$role.'_del_'.$img}) {
$confhash->{$role}{$img} = '';
$changes->{$role}{'images'}{$img} = 1;
}
if ($role eq 'login') {
if ($confhash->{$role}{'showlogo'}{$img} == 0) {
$changes->{$role}{'showlogo'}{$img} = 1;
}
if (ref($confhash->{$role}{'alttext'}) eq 'HASH') {
if ($confhash->{$role}{'alttext'}{$img} ne '') {
$changes->{$role}{'alttext'}{$img} = 1;
}
}
}
}
if ($confhash->{$role}{'font'}) {
$changes->{$role}{'font'} = 1;
}
}
sub display_colorchgs {
my ($dom,$changes,$roles,$confhash) = @_;
my (%choices,$resulttext);
if (!grep(/^login$/,@{$roles})) {
$resulttext = &mt('Changes made:').'<br />';
}
foreach my $role (@{$roles}) {
if ($role eq 'login') {
%choices = &login_choices();
} else {
%choices = &color_font_choices();
}
if (ref($changes->{$role}) eq 'HASH') {
if ($role ne 'login') {
$resulttext .= '<h4>'.&mt($role).'</h4>';
}
foreach my $key (sort(keys(%{$changes->{$role}}))) {
if ($role ne 'login') {
$resulttext .= '<ul>';
}
if (ref($changes->{$role}{$key}) eq 'HASH') {
if ($role ne 'login') {
$resulttext .= '<li>'.&mt($choices{$key}).':<ul>';
}
foreach my $item (sort(keys(%{$changes->{$role}{$key}}))) {
if (($role eq 'login') && ($key eq 'showlogo')) {
if ($confhash->{$role}{$key}{$item}) {
$resulttext .= '<li>'.&mt("$choices{$item} set to be displayed").'</li>';
} else {
$resulttext .= '<li>'.&mt("$choices{$item} set to not be displayed").'</li>';
}
} elsif (($role eq 'login') && ($key eq 'alttext')) {
if ($confhash->{$role}{$key}{$item} ne '') {
$resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} set to [_1].",
$confhash->{$role}{$key}{$item}).'</li>';
} else {
$resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} deleted.").'</li>';
}
} elsif ($confhash->{$role}{$item} eq '') {
$resulttext .= '<li>'.&mt("$choices{$item} set to default").'</li>';
} else {
my $newitem = $confhash->{$role}{$item};
if ($key eq 'images') {
$newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />';
}
$resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';
}
}
if ($role ne 'login') {
$resulttext .= '</ul></li>';
}
} else {
if ($confhash->{$role}{$key} eq '') {
$resulttext .= '<li>'.&mt("$choices{$key} set to default").'</li>';
} else {
$resulttext .= '<li>'.&mt("$choices{$key} set to [_1]",$confhash->{$role}{$key}).'</li>';
}
}
if ($role ne 'login') {
$resulttext .= '</ul>';
}
}
}
}
return $resulttext;
}
sub thumb_dimensions {
return ('200','50');
}
sub check_dimensions {
my ($inputfile) = @_;
my ($fullwidth,$fullheight);
if ($inputfile =~ m|^[/\w.\-]+$|) {
if (open(PIPE,"identify $inputfile 2>&1 |")) {
my $imageinfo = <PIPE>;
if (!close(PIPE)) {
&Apache::lonnet::logthis("Failed to close PIPE opened to retrieve image information for $inputfile");
}
chomp($imageinfo);
my ($fullsize) =
($imageinfo =~ /^\Q$inputfile\E\s+\w+\s+(\d+x\d+)/);
if ($fullsize) {
($fullwidth,$fullheight) = split(/x/,$fullsize);
}
}
}
return ($fullwidth,$fullheight);
}
sub check_configuser {
my ($uhome,$dom,$confname,$servadm) = @_;
my ($configuserok,%currroles);
if ($uhome eq 'no_host') {
srand( time() ^ ($$ + ($$ << 15)) ); # Seed rand.
my $configpass = &LONCAPA::Enrollment::create_password($dom);
$configuserok =
&Apache::lonnet::modifyuser($dom,$confname,'','internal',
$configpass,'','','','','',undef,$servadm);
} else {
$configuserok = 'ok';
%currroles =
&Apache::lonnet::get_my_roles($confname,$dom,'userroles');
}
return ($configuserok,%currroles);
}
sub check_authorstatus {
my ($dom,$confname,%currroles) = @_;
my $author_ok;
if (!$currroles{':'.$dom.':au'}) {
my $start = time;
my $end = 0;
$author_ok =
&Apache::lonnet::assignrole($dom,$confname,'/'.$dom.'/',
'au',$end,$start,'','','domconfig');
} else {
$author_ok = 'ok';
}
return $author_ok;
}
sub update_modify_urls {
my ($r,$modified) = @_;
if ((ref($modified) eq 'ARRAY') && (@{$modified})) {
push(@{$modified_urls},$modified);
unless ($registered_cleanup) {
my $handlers = $r->get_handlers('PerlCleanupHandler');
$r->set_handlers('PerlCleanupHandler' => [\¬ifysubscribed,@{$handlers}]);
$registered_cleanup=1;
}
}
}
sub notifysubscribed {
foreach my $targetsource (@{$modified_urls}){
next unless (ref($targetsource) eq 'ARRAY');
my ($target,$source)=@{$targetsource};
if ($source ne '') {
if (open(my $logfh,">>",$source.'.log')) {
print $logfh "\nCleanup phase: Notifications\n";
my @subscribed=&subscribed_hosts($target);
foreach my $subhost (@subscribed) {
print $logfh "\nNotifying host ".$subhost.':';
my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
print $logfh $reply;
}
my @subscribedmeta=&subscribed_hosts("$target.meta");
foreach my $subhost (@subscribedmeta) {
print $logfh "\nNotifying host for metadata only ".$subhost.':';
my $reply=&Apache::lonnet::critical('update:'.$target.'.meta',
$subhost);
print $logfh $reply;
}
print $logfh "\n============ Done ============\n";
close($logfh);
}
}
}
return OK;
}
sub subscribed_hosts {
my ($target) = @_;
my @subscribed;
if (open(my $fh,"<","$target.subscription")) {
while (my $subline=<$fh>) {
if ($subline =~ /^($match_lonid):/) {
my $host = $1;
if ($host ne $Apache::lonnet::perlvar{'lonHostID'}) {
unless (grep(/^\Q$host\E$/,@subscribed)) {
push(@subscribed,$host);
}
}
}
}
}
return @subscribed;
}
sub check_switchserver {
my ($dom,$confname) = @_;
my ($allowed,$switchserver,$home);
if ($confname eq '') {
$home = &Apache::lonnet::domain($dom,'primary');
} else {
$home = &Apache::lonnet::homeserver($confname,$dom);
if ($home eq 'no_host') {
$home = &Apache::lonnet::domain($dom,'primary');
}
}
my @ids=&Apache::lonnet::current_machine_ids();
foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
if (!$allowed) {
$switchserver='<a href="/adm/switchserver?otherserver='.$home.'&role='.
&HTML::Entities::encode($env{'request.role'},'\'<>"&').
'&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
}
return $switchserver;
}
sub modify_quotas {
my ($r,$dom,$action,$lastactref,%domconfig) = @_;
my ($context,@usertools,@options,%validations,%titles,%confhash,%toolshash,
%limithash,$toolregexp,%conditions,$resulttext,%changes,$confname,$configuserok,
$author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,
$validationfieldsref);
if ($action eq 'quotas') {
$context = 'tools';
} else {
$context = $action;
}
if ($context eq 'requestcourses') {
@usertools = ('official','unofficial','community','textbook','placement','lti');
@options =('norequest','approval','validate','autolimit');
%validations = &Apache::lonnet::auto_courserequest_checks($dom);
%titles = &courserequest_titles();
$toolregexp = join('|',@usertools);
%conditions = &courserequest_conditions();
$confname = $dom.'-domainconfig';
my $servadm = $r->dir_config('lonAdmEMail');
($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
($validationitemsref,$validationnamesref,$validationfieldsref) =
&Apache::loncoursequeueadmin::requestcourses_validation_types();
} elsif ($context eq 'requestauthor') {
@usertools = ('author');
%titles = &authorrequest_titles();
} else {
@usertools = ('aboutme','blog','portfolio','portaccess','timezone');
%titles = &tool_titles();
}
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
foreach my $key (keys(%env)) {
if ($context eq 'requestcourses') {
if ($key =~ /^form\.crsreq_($toolregexp)_(.+)$/) {
my $item = $1;
my $type = $2;
if ($type =~ /^limit_(.+)/) {
$limithash{$item}{$1} = $env{$key};
} else {
$confhash{$item}{$type} = $env{$key};
}
}
} elsif ($context eq 'requestauthor') {
if ($key =~ /^\Qform.authorreq_\E(.+)$/) {
$confhash{$1} = $env{$key};
}
} else {
if ($key =~ /^form\.quota_(.+)$/) {
$confhash{'defaultquota'}{$1} = $env{$key};
} elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {
@{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);
}
}
}
if (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');
@approvalnotify = sort(@approvalnotify);
$confhash{'notify'}{'approval'} = join(',',@approvalnotify);
my @crstypes = ('official','unofficial','community','textbook','placement','lti');
my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');
foreach my $type (@hasuniquecode) {
if (grep(/^\Q$type\E$/,@crstypes)) {
$confhash{'uniquecode'}{$type} = 1;
}
}
my (%newbook,%allpos);
if ($context eq 'requestcourses') {
foreach my $type ('textbooks','templates') {
@{$allpos{$type}} = ();
my $invalid;
if ($type eq 'textbooks') {
$invalid = &mt('Invalid LON-CAPA course for textbook');
} else {
$invalid = &mt('Invalid LON-CAPA course for template');
}
if ($env{'form.'.$type.'_addbook'}) {
if (($env{'form.'.$type.'_addbook_cnum'} =~ /^$match_courseid$/) &&
($env{'form.'.$type.'_addbook_cdom'} =~ /^$match_domain$/)) {
if (&Apache::lonnet::homeserver($env{'form.'.$type.'_addbook_cnum'},
$env{'form.'.$type.'_addbook_cdom'}) eq 'no_host') {
$errors .= '<li><span class="LC_error">'.$invalid.'</span></li>';
} else {
$newbook{$type} = $env{'form.'.$type.'_addbook_cdom'}.'_'.$env{'form.'.$type.'_addbook_cnum'};
my $position = $env{'form.'.$type.'_addbook_pos'};
$position =~ s/\D+//g;
if ($position ne '') {
$allpos{$type}[$position] = $newbook{$type};
}
}
} else {
$errors .= '<li><span class="LC_error">'.$invalid.'</span></li>';
}
}
}
}
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{'notify'}) eq 'HASH') {
if ($domconfig{$action}{'notify'}{'approval'} ne $confhash{'notify'}{'approval'}) {
$changes{'notify'}{'approval'} = 1;
}
} else {
if ($confhash{'notify'}{'approval'}) {
$changes{'notify'}{'approval'} = 1;
}
}
if (ref($domconfig{$action}{'uniquecode'}) eq 'HASH') {
if (ref($confhash{'uniquecode'}) eq 'HASH') {
foreach my $crstype (keys(%{$domconfig{$action}{'uniquecode'}})) {
unless ($confhash{'uniquecode'}{$crstype}) {
$changes{'uniquecode'} = 1;
}
}
unless ($changes{'uniquecode'}) {
foreach my $crstype (keys(%{$confhash{'uniquecode'}})) {
unless ($domconfig{$action}{'uniquecode'}{$crstype}) {
$changes{'uniquecode'} = 1;
}
}
}
} else {
$changes{'uniquecode'} = 1;
}
} elsif (ref($confhash{'uniquecode'}) eq 'HASH') {
$changes{'uniquecode'} = 1;
}
if ($context eq 'requestcourses') {
foreach my $type ('textbooks','templates') {
if (ref($domconfig{$action}{$type}) eq 'HASH') {
my %deletions;
my @todelete = &Apache::loncommon::get_env_multiple('form.'.$type.'_del');
if (@todelete) {
map { $deletions{$_} = 1; } @todelete;
}
my %imgdeletions;
my @todeleteimages = &Apache::loncommon::get_env_multiple('form.'.$type.'_image_del');
if (@todeleteimages) {
map { $imgdeletions{$_} = 1; } @todeleteimages;
}
my $maxnum = $env{'form.'.$type.'_maxnum'};
for (my $i=0; $i<=$maxnum; $i++) {
my $itemid = $env{'form.'.$type.'_id_'.$i};
my ($key) = ($itemid =~ /^\Q$type\E_(\w+)$/);
if (ref($domconfig{$action}{$type}{$key}) eq 'HASH') {
if ($deletions{$key}) {
if ($domconfig{$action}{$type}{$key}{'image'}) {
#FIXME need to obsolete item in RES space
}
next;
} else {
my $newpos = $env{'form.'.$itemid};
$newpos =~ s/\D+//g;
foreach my $item ('subject','title','publisher','author') {
next if ((($item eq 'author') || ($item eq 'publisher')) &&
($type eq 'templates'));
$confhash{$type}{$key}{$item} = $env{'form.'.$type.'_'.$item.'_'.$i};
if ($domconfig{$action}{$type}{$key}{$item} ne $confhash{$type}{$key}{$item}) {
$changes{$type}{$key} = 1;
}
}
$allpos{$type}[$newpos] = $key;
}
if ($imgdeletions{$key}) {
$changes{$type}{$key} = 1;
#FIXME need to obsolete item in RES space
} elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) {
my ($cdom,$cnum) = split(/_/,$key);
if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') {
$errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>';
} else {
my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i,
$cdom,$cnum,$type,$configuserok,
$switchserver,$author_ok);
if ($imgurl) {
$confhash{$type}{$key}{'image'} = $imgurl;
$changes{$type}{$key} = 1;
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
} elsif ($domconfig{$action}{$type}{$key}{'image'}) {
$confhash{$type}{$key}{'image'} =
$domconfig{$action}{$type}{$key}{'image'};
}
}
}
}
}
}
} else {
if ($confhash{'notify'}{'approval'}) {
$changes{'notify'}{'approval'} = 1;
}
if (ref($confhash{'uniquecode'} eq 'HASH')) {
$changes{'uniquecode'} = 1;
}
}
if ($context eq 'requestcourses') {
foreach my $type ('textbooks','templates') {
if ($newbook{$type}) {
$changes{$type}{$newbook{$type}} = 1;
foreach my $item ('subject','title','publisher','author') {
next if ((($item eq 'author') || ($item eq 'publisher')) &&
($type eq 'template'));
$env{'form.'.$type.'_addbook_'.$item} =~ s/(`)/'/g;
if ($env{'form.'.$type.'_addbook_'.$item}) {
$confhash{$type}{$newbook{$type}}{$item} = $env{'form.'.$type.'_addbook_'.$item};
}
}
if ($type eq 'textbooks') {
if ($env{'form.'.$type.'_addbook_image.filename'} ne '') {
my ($cdom,$cnum) = split(/_/,$newbook{$type});
if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') {
$errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>';
} else {
my ($imageurl,$error) =
&process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type,
$configuserok,$switchserver,$author_ok);
if ($imageurl) {
$confhash{$type}{$newbook{$type}}{'image'} = $imageurl;
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
}
}
}
if (@{$allpos{$type}} > 0) {
my $idx = 0;
foreach my $item (@{$allpos{$type}}) {
if ($item ne '') {
$confhash{$type}{$item}{'order'} = $idx;
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$type}) eq 'HASH') {
if (ref($domconfig{$action}{$type}{$item}) eq 'HASH') {
if ($domconfig{$action}{$type}{$item}{'order'} ne $idx) {
$changes{$type}{$item} = 1;
}
}
}
}
$idx ++;
}
}
}
}
if (ref($validationitemsref) eq 'ARRAY') {
foreach my $item (@{$validationitemsref}) {
if ($item eq 'fields') {
my @changed;
@{$confhash{'validation'}{$item}} = &Apache::loncommon::get_env_multiple('form.requestcourses_validation_'.$item);
if (@{$confhash{'validation'}{$item}} > 0) {
@{$confhash{'validation'}{$item}} = sort(@{$confhash{'validation'}{$item}});
}
if (ref($domconfig{'requestcourses'}) eq 'HASH') {
if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
if (ref($domconfig{'requestcourses'}{'validation'}{$item}) eq 'ARRAY') {
@changed = &Apache::loncommon::compare_arrays($confhash{'validation'}{$item},
$domconfig{'requestcourses'}{'validation'}{$item});
} else {
@changed = @{$confhash{'validation'}{$item}};
}
} else {
@changed = @{$confhash{'validation'}{$item}};
}
} else {
@changed = @{$confhash{'validation'}{$item}};
}
if (@changed) {
if ($confhash{'validation'}{$item}) {
$changes{'validation'}{$item} = join(', ',@{$confhash{'validation'}{$item}});
} else {
$changes{'validation'}{$item} = &mt('None');
}
}
} else {
$confhash{'validation'}{$item} = $env{'form.requestcourses_validation_'.$item};
if ($item eq 'markup') {
if ($env{'form.requestcourses_validation_'.$item}) {
$env{'form.requestcourses_validation_'.$item} =~ s/[\n\r\f]+/\s/gs;
}
}
if (ref($domconfig{'requestcourses'}) eq 'HASH') {
if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
if ($domconfig{'requestcourses'}{'validation'}{$item} ne $confhash{'validation'}{$item}) {
$changes{'validation'}{$item} = $confhash{'validation'}{$item};
}
} else {
if ($confhash{'validation'}{$item} ne '') {
$changes{'validation'}{$item} = $confhash{'validation'}{$item};
}
}
} else {
if ($confhash{'validation'}{$item} ne '') {
$changes{'validation'}{$item} = $confhash{'validation'}{$item};
}
}
}
}
}
if ($env{'form.validationdc'}) {
my $newval = $env{'form.validationdc'};
my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
if (exists($domcoords{$newval})) {
$confhash{'validation'}{'dc'} = $newval;
}
}
if (ref($confhash{'validation'}) eq 'HASH') {
if (ref($domconfig{'requestcourses'}) eq 'HASH') {
if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {
unless ($confhash{'validation'}{'dc'} eq $domconfig{'requestcourses'}{'validation'}{'dc'}) {
if ($confhash{'validation'}{'dc'} eq '') {
$changes{'validation'}{'dc'} = &mt('None');
} else {
$changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
}
}
} elsif ($confhash{'validation'}{'dc'} ne '') {
$changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
}
} elsif ($confhash{'validation'}{'dc'} ne '') {
$changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
}
} elsif ($confhash{'validation'}{'dc'} ne '') {
$changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'};
}
} else {
if (ref($domconfig{'requestcourses'}) eq 'HASH') {
if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') {
if ($domconfig{'requestcourses'}{'validation'}{'dc'}) {
$changes{'validation'}{'dc'} = &mt('None');
}
}
}
}
}
} else {
$confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};
}
foreach my $item (@usertools) {
foreach my $type (@{$types},'default','_LC_adv') {
my $unset;
if ($context eq 'requestcourses') {
$unset = '0';
if ($type eq '_LC_adv') {
$unset = '';
}
if ($confhash{$item}{$type} eq 'autolimit') {
$confhash{$item}{$type} .= '=';
unless ($limithash{$item}{$type} =~ /\D/) {
$confhash{$item}{$type} .= $limithash{$item}{$type};
}
}
} elsif ($context eq 'requestauthor') {
$unset = '0';
if ($type eq '_LC_adv') {
$unset = '';
}
} else {
if (grep(/^\Q$type\E$/,@{$toolshash{$item}})) {
$confhash{$item}{$type} = 1;
} else {
$confhash{$item}{$type} = 0;
}
}
if (ref($domconfig{$action}) eq 'HASH') {
if ($action eq 'requestauthor') {
if ($domconfig{$action}{$type} ne $confhash{$type}) {
$changes{$type} = 1;
}
} elsif (ref($domconfig{$action}{$item}) eq 'HASH') {
if ($domconfig{$action}{$item}{$type} ne $confhash{$item}{$type}) {
$changes{$item}{$type} = 1;
}
} else {
if ($context eq 'requestcourses') {
if ($confhash{$item}{$type} ne $unset) {
$changes{$item}{$type} = 1;
}
} else {
if (!$confhash{$item}{$type}) {
$changes{$item}{$type} = 1;
}
}
}
} else {
if ($context eq 'requestcourses') {
if ($confhash{$item}{$type} ne $unset) {
$changes{$item}{$type} = 1;
}
} elsif ($context eq 'requestauthor') {
if ($confhash{$type} ne $unset) {
$changes{$type} = 1;
}
} else {
if (!$confhash{$item}{$type}) {
$changes{$item}{$type} = 1;
}
}
}
}
}
unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
if (ref($domconfig{'quotas'}) eq 'HASH') {
if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'quotas'}{'defaultquota'}})) {
if (exists($confhash{'defaultquota'}{$key})) {
if ($confhash{'defaultquota'}{$key} ne $domconfig{'quotas'}{'defaultquota'}{$key}) {
$changes{'defaultquota'}{$key} = 1;
}
} else {
$confhash{'defaultquota'}{$key} = $domconfig{'quotas'}{'defaultquota'}{$key};
}
}
} else {
foreach my $key (keys(%{$domconfig{'quotas'}})) {
if (exists($confhash{'defaultquota'}{$key})) {
if ($confhash{'defaultquota'}{$key} ne $domconfig{'quotas'}{$key}) {
$changes{'defaultquota'}{$key} = 1;
}
} else {
$confhash{'defaultquota'}{$key} = $domconfig{'quotas'}{$key};
}
}
}
if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
$confhash{'authorquota'} = $domconfig{'quotas'}{'authorquota'};
}
if (ref($domconfig{'quotas'}{'webdav'}) eq 'HASH') {
$confhash{'webdav'} = $domconfig{'quotas'}{'webdav'};
}
}
if (ref($confhash{'defaultquota'}) eq 'HASH') {
foreach my $key (keys(%{$confhash{'defaultquota'}})) {
if (ref($domconfig{'quotas'}) eq 'HASH') {
if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') {
if (!exists($domconfig{'quotas'}{'defaultquota'}{$key})) {
$changes{'defaultquota'}{$key} = 1;
}
} else {
if (!exists($domconfig{'quotas'}{$key})) {
$changes{'defaultquota'}{$key} = 1;
}
}
} else {
$changes{'defaultquota'}{$key} = 1;
}
}
}
}
if ($context eq 'requestauthor') {
$domdefaults{'requestauthor'} = \%confhash;
} else {
foreach my $key (keys(%confhash)) {
unless (($context eq 'requestcourses') && (($key eq 'textbooks') || ($key eq 'templates'))) {
$domdefaults{$key} = $confhash{$key};
}
}
}
my %quotahash = (
$action => { %confhash }
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%quotahash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
$resulttext = &mt('Changes made:').'<ul>';
unless (($context eq 'requestcourses') ||
($context eq 'requestauthor')) {
if (ref($changes{'defaultquota'}) eq 'HASH') {
$resulttext .= '<li>'.&mt('Portfolio default quotas').'<ul>';
foreach my $type (@{$types},'default') {
if (defined($changes{'defaultquota'}{$type})) {
my $typetitle = $usertypes->{$type};
if ($type eq 'default') {
$typetitle = $othertitle;
}
$resulttext .= '<li>'.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'defaultquota'}{$type}).'</li>';
}
}
$resulttext .= '</ul></li>';
}
}
my %newenv;
foreach my $item (@usertools) {
my (%haschgs,%inconf);
if ($context eq 'requestauthor') {
%haschgs = %changes;
%inconf = %confhash;
} else {
if (ref($changes{$item}) eq 'HASH') {
%haschgs = %{$changes{$item}};
}
if (ref($confhash{$item}) eq 'HASH') {
%inconf = %{$confhash{$item}};
}
}
if (keys(%haschgs) > 0) {
my $newacc =
&Apache::lonnet::usertools_access($env{'user.name'},
$env{'user.domain'},
$item,'reload',$context);
if (($context eq 'requestcourses') ||
($context eq 'requestauthor')) {
if ($env{'environment.canrequest.'.$item} ne $newacc) {
$newenv{'environment.canrequest.'.$item} = $newacc;
}
} else {
if ($env{'environment.availabletools.'.$item} ne $newacc) {
$newenv{'environment.availabletools.'.$item} = $newacc;
}
}
unless ($context eq 'requestauthor') {
$resulttext .= '<li>'.$titles{$item}.'<ul>';
}
foreach my $type (@{$types},'default','_LC_adv') {
if ($haschgs{$type}) {
my $typetitle = $usertypes->{$type};
if ($type eq 'default') {
$typetitle = $othertitle;
} elsif ($type eq '_LC_adv') {
$typetitle = 'LON-CAPA Advanced Users';
}
if ($inconf{$type}) {
if ($context eq 'requestcourses') {
my $cond;
if ($inconf{$type} =~ /^autolimit=(\d*)$/) {
if ($1 eq '') {
$cond = &mt('(Automatic processing of any request).');
} else {
$cond = &mt('(Automatic processing of requests up to limit of [quant,_1,request] per user).',$1);
}
} else {
$cond = $conditions{$inconf{$type}};
}
$resulttext .= '<li>'.&mt('Set to be available to [_1].',$typetitle).' '.$cond.'</li>';
} elsif ($context eq 'requestauthor') {
$resulttext .= '<li>'.&mt('Set to "[_1]" for "[_2]".',
$titles{$inconf{$type}},$typetitle);
} else {
$resulttext .= '<li>'.&mt('Set to be available to [_1]',$typetitle).'</li>';
}
} else {
if ($type eq '_LC_adv') {
if ($inconf{$type} eq '0') {
$resulttext .= '<li>'.&mt('Set to be unavailable to [_1]',$typetitle).'</li>';
} else {
$resulttext .= '<li>'.&mt('No override set for [_1]',$typetitle).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Set to be unavailable to [_1]',$typetitle).'</li>';
}
}
}
}
unless ($context eq 'requestauthor') {
$resulttext .= '</ul></li>';
}
}
}
if (($action eq 'requestcourses') || ($action eq 'requestauthor')) {
if (ref($changes{'notify'}) eq 'HASH') {
if ($changes{'notify'}{'approval'}) {
if (ref($confhash{'notify'}) eq 'HASH') {
if ($confhash{'notify'}{'approval'}) {
$resulttext .= '<li>'.&mt('Notification of requests requiring approval will be sent to: ').$confhash{'notify'}{'approval'}.'</li>';
} else {
$resulttext .= '<li>'.&mt('No Domain Coordinators will receive notification of requests requiring approval.').'</li>';
}
}
}
}
}
if ($action eq 'requestcourses') {
my @offon = ('off','on');
if ($changes{'uniquecode'}) {
if (ref($confhash{'uniquecode'}) eq 'HASH') {
my $codestr = join(' ',map{ &mt($_); } sort(keys(%{$confhash{'uniquecode'}})));
$resulttext .= '<li>'.
&mt('Generation of six character code as course identifier for distribution to students set to on for: [_1].','<b>'.$codestr.'</b>').
'</li>';
} else {
$resulttext .= '<li>'.&mt('Generation of six character code as course identifier for distribution to students set to off.').
'</li>';
}
}
foreach my $type ('textbooks','templates') {
if (ref($changes{$type}) eq 'HASH') {
$resulttext .= '<li>'.&mt("Available $type updated").'<ul>';
foreach my $key (sort(keys(%{$changes{$type}}))) {
my %coursehash = &Apache::lonnet::coursedescription($key);
my $coursetitle = $coursehash{'description'};
my $position = $confhash{$type}{$key}{'order'} + 1;
$resulttext .= '<li>';
foreach my $item ('subject','title','publisher','author') {
next if ((($item eq 'author') || ($item eq 'publisher')) &&
($type eq 'templates'));
my $name = $item.':';
$name =~ s/^(\w)/\U$1/;
$resulttext .= &mt($name).' '.$confhash{$type}{$key}{$item}.'<br />';
}
$resulttext .= ' '.&mt('Order: [_1]',$position).'<br />';
if ($type eq 'textbooks') {
if ($confhash{$type}{$key}{'image'}) {
$resulttext .= ' '.&mt('Image: [_1]',
'<img src="'.$confhash{$type}{$key}{'image'}.'"'.
' alt="Textbook cover" />').'<br />';
}
}
$resulttext .= ' '.&mt('LON-CAPA Course: [_1]',$coursetitle).'</li>';
}
$resulttext .= '</ul></li>';
}
}
if (ref($changes{'validation'}) eq 'HASH') {
if ((ref($validationitemsref) eq 'ARRAY') && (ref($validationnamesref) eq 'HASH')) {
$resulttext .= '<li>'.&mt('Validation of courses/communities updated').'<ul>';
foreach my $item (@{$validationitemsref}) {
if (exists($changes{'validation'}{$item})) {
if ($item eq 'markup') {
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$validationnamesref->{$item},
'<br /><pre>'.$changes{'validation'}{$item}.'</pre>').'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$validationnamesref->{$item},
'<b>'.$changes{'validation'}{$item}.'</b>').'</li>';
}
}
}
if (exists($changes{'validation'}{'dc'})) {
$resulttext .= '<li>'.&mt('Validated course requests identified as processed by: [_1]',
'<b>'.$changes{'validation'}{'dc'}.'</b>').'</li>';
}
$resulttext .= '</ul></li>';
}
}
}
$resulttext .= '</ul>';
if (keys(%newenv)) {
&Apache::lonnet::appenv(\%newenv);
}
} else {
if ($context eq 'requestcourses') {
$resulttext = &mt('No changes made to rights to request creation of courses.');
} elsif ($context eq 'requestauthor') {
$resulttext = &mt('No changes made to rights to request author space.');
} else {
$resulttext = &mt('No changes made to availability of personal information pages, blogs, portfolios or default quotas');
}
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if ($errors) {
$resulttext .= '<p>'.&mt('The following errors occurred when modifying Textbook settings.').
'<ul>'.$errors.'</ul></p>';
}
return $resulttext;
}
sub process_textbook_image {
my ($r,$dom,$confname,$caller,$cdom,$cnum,$type,$configuserok,$switchserver,$author_ok) = @_;
my $filename = $env{'form.'.$caller.'.filename'};
my ($error,$url);
my ($width,$height) = (50,50);
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt('Upload of textbook image is not permitted to this server: [_1]',
$switchserver);
} elsif ($author_ok eq 'ok') {
my $modified = [];
my ($result,$imageurl) =
&Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
"$type/$cdom/$cnum/cover",$width,$height,
'',$modified);
if ($result eq 'ok') {
$url = $imageurl;
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
}
} else {
$error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$author_ok);
}
} else {
$error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$configuserok);
}
return ($url,$error);
}
sub modify_ltitools {
my ($r,$dom,$action,$lastactref,%domconfig) = @_;
my (%currtoolsec,%secchanges,%newtoolsec,%newkeyset);
&fetch_secrets($dom,'toolsec',\%domconfig,\%currtoolsec,\%secchanges,\%newtoolsec,\%newkeyset);
my $confname = $dom.'-domainconfig';
my $servadm = $r->dir_config('lonAdmEMail');
my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
my ($resulttext,$ltitoolsoutput,$is_home,$errors,%ltitoolschg,%newtoolsenc,%newltitools);
my $toolserror =
&Apache::courseprefs::process_ltitools($r,$dom,$confname,$domconfig{'ltitools'},\%ltitoolschg,'domain',
$lastactref,$configuserok,$switchserver,$author_ok);
my $home = &Apache::lonnet::domain($dom,'primary');
unless (($home eq 'no_host') || ($home eq '')) {
my @ids=&Apache::lonnet::current_machine_ids();
foreach my $id (@ids) { if ($id eq $home) { $is_home=1; last; } }
}
if (keys(%ltitoolschg)) {
foreach my $id (keys(%ltitoolschg)) {
if (ref($ltitoolschg{$id}) eq 'HASH') {
foreach my $inner (keys(%{$ltitoolschg{$id}})) {
if (($inner eq 'secret') || ($inner eq 'key')) {
if ($is_home) {
$newtoolsenc{$id}{$inner} = $ltitoolschg{$id}{$inner};
}
}
}
}
}
$ltitoolsoutput = &Apache::courseprefs::store_ltitools($dom,'','domain',\%ltitoolschg,$domconfig{'ltitools'});
if (keys(%ltitoolschg)) {
%newltitools = %ltitoolschg;
}
}
if (ref($domconfig{'ltitools'}) eq 'HASH') {
foreach my $id (%{$domconfig{'ltitools'}}) {
next if ($id !~ /^\d+$/);
unless (exists($ltitoolschg{$id})) {
if (ref($domconfig{'ltitools'}{$id}) eq 'HASH') {
foreach my $inner (keys(%{$domconfig{'ltitools'}{$id}})) {
if (($inner eq 'secret') || ($inner eq 'key')) {
if ($is_home) {
$newtoolsenc{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};
}
} else {
$newltitools{$id}{$inner} = $domconfig{'ltitools'}{$id}{$inner};
}
}
} else {
$newltitools{$id} = $domconfig{'ltitools'}{$id};
}
}
}
}
if ($toolserror) {
$errors = '<li>'.$toolserror.'</li>';
}
if ((keys(%ltitoolschg) == 0) && (keys(%secchanges) == 0)) {
$resulttext = &mt('No changes made.');
if ($errors) {
$resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul>';
}
return $resulttext;
}
my %ltitoolshash = (
$action => { %newltitools }
);
if (keys(%secchanges)) {
$ltitoolshash{'toolsec'} = \%newtoolsec;
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash,$dom);
if ($putresult eq 'ok') {
my %keystore;
if ($is_home) {
my %toolsenchash = (
$action => { %newtoolsenc }
);
&Apache::lonnet::put_dom('encconfig',\%toolsenchash,$dom,undef,1);
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('ltitoolsenc',$dom,\%newtoolsenc,$cachetime);
&store_security($dom,'ltitools',\%secchanges,\%newkeyset,\%keystore,$lastactref);
}
$resulttext = &mt('Changes made:').'<ul>';
if (keys(%secchanges) > 0) {
$resulttext .= <i_security_results($dom,'ltitools',\%secchanges,\%newtoolsec,\%newkeyset,\%keystore);
}
if (keys(%ltitoolschg) > 0) {
$resulttext .= $ltitoolsoutput;
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('ltitools',$dom,\%newltitools,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'ltitools'} = 1;
}
} else {
$errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
}
if ($errors) {
$resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul></p>';
}
return $resulttext;
}
sub fetch_secrets {
my ($dom,$context,$domconfig,$currsec,$secchanges,$newsec,$newkeyset) = @_;
my %keyset;
%{$currsec} = ();
$newsec->{'private'}{'keys'} = [];
$newsec->{'encrypt'} = {};
$newsec->{'rules'} = {};
if ($context eq 'ltisec') {
$newsec->{'linkprot'} = {};
}
if (ref($domconfig->{$context}) eq 'HASH') {
%{$currsec} = %{$domconfig->{$context}};
if ($context eq 'ltisec') {
if (ref($currsec->{'linkprot'}) eq 'HASH') {
foreach my $id (keys(%{$currsec->{'linkprot'}})) {
unless ($id =~ /^\d+$/) {
delete($currsec->{'linkprot'}{$id});
}
}
}
}
if (ref($currsec->{'private'}) eq 'HASH') {
if (ref($currsec->{'private'}{'keys'}) eq 'ARRAY') {
$newsec->{'private'}{'keys'} = $currsec->{'private'}{'keys'};
map { $keyset{$_} = 1; } @{$currsec->{'private'}{'keys'}};
}
}
}
my @items= ('crs','dom');
if ($context eq 'ltisec') {
push(@items,'consumers');
}
foreach my $item (@items) {
my $formelement;
if (($context eq 'toolsec') || ($item eq 'consumers')) {
$formelement = 'form.'.$context.'_'.$item;
} else {
$formelement = 'form.'.$context.'_'.$item.'linkprot';
}
if ($env{$formelement}) {
$newsec->{'encrypt'}{$item} = 1;
if (ref($currsec->{'encrypt'}) eq 'HASH') {
unless ($currsec->{'encrypt'}{$item}) {
$secchanges->{'encrypt'} = 1;
}
} else {
$secchanges->{'encrypt'} = 1;
}
} elsif (ref($currsec->{'encrypt'}) eq 'HASH') {
if ($currsec->{'encrypt'}{$item}) {
$secchanges->{'encrypt'} = 1;
}
}
}
my $secrets;
if ($context eq 'ltisec') {
$secrets = 'ltisecrets';
} else {
$secrets = 'toolsecrets';
}
unless (exists($currsec->{'rules'})) {
$currsec->{'rules'} = {};
}
&password_rule_changes($secrets,$newsec->{'rules'},$currsec->{'rules'},$secchanges);
my @ids=&Apache::lonnet::current_machine_ids();
my %servers = &Apache::lonnet::get_servers($dom,'library');
foreach my $hostid (keys(%servers)) {
if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {
my $keyitem = 'form.'.$context.'_privkey_'.$hostid;
if (exists($env{$keyitem})) {
$env{$keyitem} =~ s/(`)/'/g;
if ($keyset{$hostid}) {
if ($env{'form.'.$context.'_changeprivkey_'.$hostid}) {
if ($env{$keyitem} ne '') {
$secchanges->{'private'} = 1;
$newkeyset->{$hostid} = $env{$keyitem};
}
}
} elsif ($env{$keyitem} ne '') {
unless (grep(/^\Q$hostid\E$/,@{$newsec->{'private'}{'keys'}})) {
push(@{$newsec->{'private'}{'keys'}},$hostid);
}
$secchanges->{'private'} = 1;
$newkeyset->{$hostid} = $env{$keyitem};
}
}
}
}
}
sub store_security {
my ($dom,$context,$secchanges,$newkeyset,$keystore) = @_;
return unless ((ref($secchanges) eq 'HASH') && (ref($newkeyset) eq 'HASH') &&
(ref($keystore) eq 'HASH'));
if (keys(%{$secchanges})) {
if ($secchanges->{'private'}) {
my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});
foreach my $hostid (keys(%{$newkeyset})) {
my $storehash = {
key => $newkeyset->{$hostid},
who => $env{'user.name'}.':'.$env{'user.domain'},
};
$keystore->{$hostid} = &Apache::lonnet::store_dom($storehash,$context,'private',
$dom,$hostid);
}
}
}
}
sub lti_security_results {
my ($dom,$context,$secchanges,$newsec,$newkeyset,$keystore) = @_;
my $output;
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
my $needs_update;
foreach my $item (keys(%{$secchanges})) {
if ($item eq 'encrypt') {
$needs_update = 1;
my %encrypted;
if ($context eq 'lti') {
%encrypted = (
crs => {
on => &mt('Encryption of stored link protection secrets defined in courses enabled'),
off => &mt('Encryption of stored link protection secrets defined in courses disabled'),
},
dom => {
on => &mt('Encryption of stored link protection secrets defined in domain enabled'),
off => &mt('Encryption of stored link protection secrets defined in domain disabled'),
},
consumers => {
on => &mt('Encryption of stored consumer secrets defined in domain enabled'),
off => &mt('Encryption of stored consumer secrets defined in domain disabled'),
},
);
} else {
%encrypted = (
crs => {
on => &mt('Encryption of stored external tool secrets defined in courses enabled'),
off => &mt('Encryption of stored external tool secrets defined in courses disabled'),
},
dom => {
on => &mt('Encryption of stored external tool secrets defined in domain enabled'),
off => &mt('Encryption of stored external tool secrets defined in domain disabled'),
},
);
}
my @types= ('crs','dom');
if ($context eq 'lti') {
foreach my $type (@types) {
undef($domdefaults{'linkprotenc_'.$type});
}
push(@types,'consumers');
undef($domdefaults{'ltienc_consumers'});
} elsif ($context eq 'ltitools') {
foreach my $type (@types) {
undef($domdefaults{'toolenc_'.$type});
}
}
foreach my $type (@types) {
my $shown = $encrypted{$type}{'off'};
if (ref($newsec->{$item}) eq 'HASH') {
if ($newsec->{$item}{$type}) {
if ($context eq 'lti') {
if ($type eq 'consumers') {
$domdefaults{'ltienc_consumers'} = 1;
} else {
$domdefaults{'linkprotenc_'.$type} = 1;
}
} elsif ($context eq 'ltitools') {
$domdefaults{'toolenc_'.$type} = 1;
}
$shown = $encrypted{$type}{'on'};
}
}
$output .= '<li>'.$shown.'</li>';
}
} elsif ($item eq 'rules') {
my %titles = &Apache::lonlocal::texthash(
min => 'Minimum password length',
max => 'Maximum password length',
chars => 'Required characters',
);
foreach my $rule ('min','max') {
if ($newsec->{rules}{$rule} eq '') {
if ($rule eq 'min') {
$output .= '<li>'.&mt('[_1] not set.',$titles{$rule});
' '.&mt('Default of [_1] will be used',
$Apache::lonnet::passwdmin).'</li>';
} else {
$output .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';
}
} else {
$output .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newsec->{rules}{$rule}).'</li>';
}
}
if (ref($newsec->{'rules'}{'chars'}) eq 'ARRAY') {
if (@{$newsec->{'rules'}{'chars'}} > 0) {
my %rulenames = &Apache::lonlocal::texthash(
uc => 'At least one upper case letter',
lc => 'At least one lower case letter',
num => 'At least one number',
spec => 'At least one non-alphanumeric',
);
my $needed = '<ul><li>'.
join('</li><li>',map {$rulenames{$_} } @{$newsec->{'rules'}{'chars'}}).
'</li></ul>';
$output .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';
} else {
$output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
}
} else {
$output .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
}
} elsif ($item eq 'private') {
$needs_update = 1;
if ($context eq 'lti') {
undef($domdefaults{'ltiprivhosts'});
} elsif ($context eq 'ltitools') {
undef($domdefaults{'toolprivhosts'});
}
if (keys(%{$newkeyset})) {
my @privhosts;
foreach my $hostid (sort(keys(%{$newkeyset}))) {
if ($keystore->{$hostid} eq 'ok') {
$output .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>';
unless (grep(/^\Q$hostid\E$/,@privhosts)) {
push(@privhosts,$hostid);
}
}
}
if (@privhosts) {
if ($context eq 'lti') {
$domdefaults{'ltiprivhosts'} = \@privhosts;
} elsif ($context eq 'ltitools') {
$domdefaults{'toolprivhosts'} = \@privhosts;
}
}
}
} elsif ($item eq 'linkprot') {
next;
} elsif ($item eq 'suggested') {
if ((ref($secchanges->{'suggested'}) eq 'HASH') &&
(ref($newsec->{'suggested'}) eq 'HASH')) {
my $suggestions;
foreach my $id (sort { $a <=> $b } keys(%{$secchanges->{'suggested'}})) {
if (ref($newsec->{'suggested'}->{$id}) eq 'HASH') {
my $name = $newsec->{'suggested'}->{$id}->{'name'};
my $info = $newsec->{'suggested'}->{$id}->{'info'};
$suggestions .= '<li>'.&mt('Launcher: [_1]',$name).'<br />'.
&mt('Recommend: [_1]','<pre>'.$info.'</pre>').
'</li>';
} else {
$suggestions .= '<li>'.&mt('Recommendations deleted for Launcher: [_1]',
$newsec->{'suggested'}->{$id}).'</li>';
}
}
if ($suggestions) {
$output .= '<li>'.&mt('Hints in Courses for Link Protector Configuration').
'<ul>'.$suggestions.'</ul>'.
'</li>';
}
}
}
}
if ($needs_update) {
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
}
return $output;
}
sub modify_proctoring {
my ($r,$dom,$action,$lastactref,%domconfig) = @_;
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my (@allpos,%changes,%confhash,%encconfhash,$errors,$resulttext,%imgdeletions);
my $confname = $dom.'-domainconfig';
my $servadm = $r->dir_config('lonAdmEMail');
my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
my %providernames = &proctoring_providernames();
my $maxnum = scalar(keys(%providernames));
my (%requserfields,%optuserfields,%defaults,%extended,%crsconf,@courseroles,@ltiroles);
my ($requref,$opturef,$defref,$extref,$crsref,$rolesref,$ltiref) = &proctoring_data();
if (ref($requref) eq 'HASH') {
%requserfields = %{$requref};
}
if (ref($opturef) eq 'HASH') {
%optuserfields = %{$opturef};
}
if (ref($defref) eq 'HASH') {
%defaults = %{$defref};
}
if (ref($extref) eq 'HASH') {
%extended = %{$extref};
}
if (ref($crsref) eq 'HASH') {
%crsconf = %{$crsref};
}
if (ref($rolesref) eq 'ARRAY') {
@courseroles = @{$rolesref};
}
if (ref($ltiref) eq 'ARRAY') {
@ltiroles = @{$ltiref};
}
if (ref($domconfig{$action}) eq 'HASH') {
my @todeleteimages = &Apache::loncommon::get_env_multiple('form.proctoring_image_del');
if (@todeleteimages) {
map { $imgdeletions{$_} = 1; } @todeleteimages;
}
}
my %customadds;
my @newcustom = &Apache::loncommon::get_env_multiple('form.proctoring_customadd');
if (@newcustom) {
map { $customadds{$_} = 1; } @newcustom;
}
foreach my $provider (sort(keys(%providernames))) {
$confhash{$provider} = {};
my $pos = $env{'form.proctoring_pos_'.$provider};
$pos =~ s/\D+//g;
$allpos[$pos] = $provider;
my (%current,%currentenc);
my $showroles = 0;
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$provider}) eq 'HASH') {
%current = %{$domconfig{$action}{$provider}};
foreach my $item ('key','secret') {
$currentenc{$item} = $current{$item};
delete($current{$item});
}
}
}
if ($env{'form.proctoring_available_'.$provider}) {
$confhash{$provider}{'available'} = 1;
unless ($current{'available'}) {
$changes{$provider} = 1;
}
} else {
%{$confhash{$provider}} = %current;
%{$encconfhash{$provider}} = %currentenc;
$confhash{$provider}{'available'} = 0;
if ($current{'available'}) {
$changes{$provider} = 1;
}
}
if ($confhash{$provider}{'available'}) {
foreach my $field ('lifetime','version','sigmethod','url','key','secret') {
my $possval = $env{'form.proctoring_'.$provider.'_'.$field};
if ($field eq 'lifetime') {
if ($possval =~ /^\d+$/) {
$confhash{$provider}{$field} = $possval;
}
} elsif ($field eq 'version') {
if ($possval =~ /^\d+\.\d+$/) {
$confhash{$provider}{$field} = $possval;
}
} elsif ($field eq 'sigmethod') {
if ($possval =~ /^\QHMAC-SHA\E(1|256)$/) {
$confhash{$provider}{$field} = $possval;
}
} elsif ($field eq 'url') {
$confhash{$provider}{$field} = $possval;
} elsif (($field eq 'key') || ($field eq 'secret')) {
$encconfhash{$provider}{$field} = $possval;
unless ($currentenc{$field} eq $possval) {
$changes{$provider} = 1;
}
}
unless (($field eq 'key') || ($field eq 'secret')) {
unless ($current{$field} eq $confhash{$provider}{$field}) {
$changes{$provider} = 1;
}
}
}
if ($imgdeletions{$provider}) {
$changes{$provider} = 1;
} elsif ($env{'form.proctoring_image_'.$provider.'.filename'} ne '') {
my ($imageurl,$error) =
&process_proctoring_image($r,$dom,$confname,'proctoring_image_'.$provider,$provider,
$configuserok,$switchserver,$author_ok);
if ($imageurl) {
$confhash{$provider}{'image'} = $imageurl;
$changes{$provider} = 1;
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
} elsif (exists($current{'image'})) {
$confhash{$provider}{'image'} = $current{'image'};
}
if (ref($requserfields{$provider}) eq 'ARRAY') {
if (@{$requserfields{$provider}} > 0) {
if (grep(/^user$/,@{$requserfields{$provider}})) {
if ($env{'form.proctoring_userincdom_'.$provider}) {
$confhash{$provider}{'incdom'} = 1;
}
unless ($current{'incdom'} eq $confhash{$provider}{'incdom'}) {
$changes{$provider} = 1;
}
}
if (grep(/^roles$/,@{$requserfields{$provider}})) {
$showroles = 1;
}
}
}
$confhash{$provider}{'fields'} = [];
if (ref($optuserfields{$provider}) eq 'ARRAY') {
if (@{$optuserfields{$provider}} > 0) {
my @optfields = &Apache::loncommon::get_env_multiple('form.proctoring_optional_'.$provider);
foreach my $field (@{$optuserfields{$provider}}) {
if (grep(/^\Q$field\E$/,@optfields)) {
push(@{$confhash{$provider}{'fields'}},$field);
}
}
}
if (ref($current{'fields'}) eq 'ARRAY') {
unless ($changes{$provider}) {
my @new = sort(@{$confhash{$provider}{'fields'}});
my @old = sort(@{$current{'fields'}});
my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old);
if (@diffs) {
$changes{$provider} = 1;
}
}
} elsif (@{$confhash{$provider}{'fields'}}) {
$changes{$provider} = 1;
}
}
if (ref($defaults{$provider}) eq 'ARRAY') {
if (@{$defaults{$provider}} > 0) {
my %options;
if (ref($extended{$provider}) eq 'HASH') {
%options = %{$extended{$provider}};
}
my @checked = &Apache::loncommon::get_env_multiple('form.proctoring_defaults_'.$provider);
foreach my $field (@{$defaults{$provider}}) {
if ((exists($options{$field})) && (ref($options{$field}) eq 'ARRAY')) {
my $poss = $env{'form.proctoring_defaults_'.$field.'_'.$provider};
if (grep(/^\Q$poss\E$/,@{$options{$field}})) {
push(@{$confhash{$provider}{'defaults'}},$poss);
}
} elsif ((exists($options{$field})) && (ref($options{$field}) eq 'HASH')) {
foreach my $inner (keys(%{$options{$field}})) {
if (ref($options{$field}{$inner}) eq 'ARRAY') {
my $poss = $env{'form.proctoring_'.$inner.'_'.$provider};
if (grep(/^\Q$poss\E$/,@{$options{$field}{$inner}})) {
$confhash{$provider}{'defaults'}{$inner} = $poss;
}
} else {
$confhash{$provider}{'defaults'}{$inner} = $env{'form.proctoring_'.$inner.'_'.$provider};
}
}
} else {
if (grep(/^\Q$field\E$/,@checked)) {
push(@{$confhash{$provider}{'defaults'}},$field);
}
}
}
if (ref($confhash{$provider}{'defaults'}) eq 'ARRAY') {
if (ref($current{'defaults'}) eq 'ARRAY') {
unless ($changes{$provider}) {
my @new = sort(@{$confhash{$provider}{'defaults'}});
my @old = sort(@{$current{'defaults'}});
my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old);
if (@diffs) {
$changes{$provider} = 1;
}
}
} elsif (ref($current{'defaults'}) eq 'ARRAY') {
if (@{$current{'defaults'}}) {
$changes{$provider} = 1;
}
}
} elsif (ref($confhash{$provider}{'defaults'}) eq 'HASH') {
if (ref($current{'defaults'}) eq 'HASH') {
unless ($changes{$provider}) {
foreach my $key (keys(%{$confhash{$provider}{'defaults'}})) {
unless ($confhash{$provider}{'defaults'}{$key} eq $current{'defaults'}{$key}) {
$changes{$provider} = 1;
last;
}
}
}
unless ($changes{$provider}) {
foreach my $key (keys(%{$current{'defaults'}})) {
unless ($current{'defaults'}{$key} eq $confhash{$provider}{'defaults'}{$key}) {
$changes{$provider} = 1;
last;
}
}
}
} elsif (keys(%{$confhash{$provider}{'defaults'}})) {
$changes{$provider} = 1;
}
}
}
}
if (ref($crsconf{$provider}) eq 'ARRAY') {
if (@{$crsconf{$provider}} > 0) {
$confhash{$provider}{'crsconf'} = [];
my @checked = &Apache::loncommon::get_env_multiple('form.proctoring_crsconf_'.$provider);
foreach my $crsfield (@{$crsconf{$provider}}) {
if (grep(/^\Q$crsfield\E$/,@checked)) {
push(@{$confhash{$provider}{'crsconf'}},$crsfield);
}
}
if (ref($current{'crsconf'}) eq 'ARRAY') {
unless ($changes{$provider}) {
my @new = sort(@{$confhash{$provider}{'crsconf'}});
my @old = sort(@{$current{'crsconf'}});
my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old);
if (@diffs) {
$changes{$provider} = 1;
}
}
} elsif (@{$confhash{$provider}{'crsconf'}}) {
$changes{$provider} = 1;
}
}
}
if ($showroles) {
$confhash{$provider}{'roles'} = {};
foreach my $role (@courseroles) {
my $poss = $env{'form.proctoring_roles_'.$role.'_'.$provider};
if (grep(/^\Q$poss\E$/,@ltiroles)) {
$confhash{$provider}{'roles'}{$role} = $poss;
}
}
unless ($changes{$provider}) {
if (ref($current{'roles'}) eq 'HASH') {
foreach my $role (keys(%{$current{'roles'}})) {
unless ($current{'roles'}{$role} eq $confhash{$provider}{'roles'}{$role}) {
$changes{$provider} = 1;
last
}
}
unless ($changes{$provider}) {
foreach my $role (keys(%{$confhash{$provider}{'roles'}})) {
unless ($confhash{$provider}{'roles'}{$role} eq $current{'roles'}{$role}) {
$changes{$provider} = 1;
last;
}
}
}
} elsif (keys(%{$confhash{$provider}{'roles'}})) {
$changes{$provider} = 1;
}
}
}
if (ref($current{'custom'}) eq 'HASH') {
my @customdels = &Apache::loncommon::get_env_multiple('form.proctoring_customdel_'.$provider);
foreach my $key (keys(%{$current{'custom'}})) {
if (grep(/^\Q$key\E$/,@customdels)) {
$changes{$provider} = 1;
} else {
$confhash{$provider}{'custom'}{$key} = $env{'form.proctoring_customval_'.$key.'_'.$provider};
if ($confhash{$provider}{'custom'}{$key} ne $current{'custom'}{$key}) {
$changes{$provider} = 1;
}
}
}
}
if ($customadds{$provider}) {
my $name = $env{'form.proctoring_custom_name_'.$provider};
$name =~ s/(`)/'/g;
$name =~ s/^\s+//;
$name =~ s/\s+$//;
my $value = $env{'form.proctoring_custom_value_'.$provider};
$value =~ s/(`)/'/g;
$value =~ s/^\s+//;
$value =~ s/\s+$//;
if ($name ne '') {
$confhash{$provider}{'custom'}{$name} = $value;
$changes{$provider} = 1;
}
}
}
}
if (@allpos > 0) {
my $idx = 0;
foreach my $provider (@allpos) {
if ($provider ne '') {
$confhash{$provider}{'order'} = $idx;
unless ($changes{$provider}) {
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$provider}) eq 'HASH') {
if ($domconfig{$action}{$provider}{'order'} ne $idx) {
$changes{$provider} = 1;
}
}
}
}
$idx ++;
}
}
}
my %proc_hash = (
$action => { %confhash }
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%proc_hash,
$dom);
if ($putresult eq 'ok') {
my %proc_enchash = (
$action => { %encconfhash }
);
&Apache::lonnet::put_dom('encconfig',\%proc_enchash,$dom,undef,1);
if (keys(%changes) > 0) {
my $cachetime = 24*60*60;
my %procall = %confhash;
foreach my $provider (keys(%procall)) {
if (ref($encconfhash{$provider}) eq 'HASH') {
foreach my $key ('key','secret') {
$procall{$provider}{$key} = $encconfhash{$provider}{$key};
}
}
}
&Apache::lonnet::do_cache_new('proctoring',$dom,\%procall,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'proctoring'} = 1;
}
$resulttext = &mt('Configuration for Provider(s) with changes:').'<ul>';
my %bynum;
foreach my $provider (sort(keys(%changes))) {
my $position = $confhash{$provider}{'order'};
$bynum{$position} = $provider;
}
foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
my $provider = $bynum{$pos};
my %lt = &proctoring_titles($provider);
my %fieldtitles = &proctoring_fieldtitles($provider);
if (!$confhash{$provider}{'available'}) {
$resulttext .= '<li>'.&mt('Proctoring integration unavailable for: [_1]','<b>'.$providernames{$provider}.'</b>').'</li>';
} else {
$resulttext .= '<li>'.&mt('Proctoring integration available for: [_1]','<b>'.$providernames{$provider}.'</b>');
if ($confhash{$provider}{'image'}) {
$resulttext .= ' '.
'<img src="'.$confhash{$provider}{'image'}.'"'.
' alt="'.&mt('Proctoring icon').'" />';
}
$resulttext .= '<ul>';
my $position = $pos + 1;
$resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
foreach my $key ('version','sigmethod','url','lifetime') {
if ($confhash{$provider}{$key} ne '') {
$resulttext .= '<li>'.$lt{$key}.': '.$confhash{$provider}{$key}.'</li>';
}
}
if ($encconfhash{$provider}{'key'} ne '') {
$resulttext .= '<li>'.$lt{'key'}.': '.$encconfhash{$provider}{'key'}.'</li>';
}
if ($encconfhash{$provider}{'secret'} ne '') {
$resulttext .= '<li>'.$lt{'secret'}.': ';
my $num = length($encconfhash{$provider}{'secret'});
$resulttext .= ('*'x$num).'</li>';
}
my (@fields,$showroles);
if (ref($requserfields{$provider}) eq 'ARRAY') {
push(@fields,@{$requserfields{$provider}});
}
if (ref($confhash{$provider}{'fields'}) eq 'ARRAY') {
push(@fields,@{$confhash{$provider}{'fields'}});
} elsif (ref($confhash{$provider}{'fields'}) eq 'HASH') {
push(@fields,(keys(%{$confhash{$provider}{'fields'}})));
}
if (@fields) {
if (grep(/^roles$/,@fields)) {
$showroles = 1;
}
$resulttext .= '<li>'.$lt{'udsl'}.': "'.
join('", "', map { $lt{$_}; } @fields).'"</li>';
}
if (ref($requserfields{$provider}) eq 'ARRAY') {
if (grep(/^user$/,@{$requserfields{$provider}})) {
if ($confhash{$provider}{'incdom'}) {
$resulttext .= '<li>'.&mt('[_1] sent as [_2]',$lt{'user'},$lt{'uname:dom'}).'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] sent as [_2]',$lt{'user'},$lt{'username'}).'</li>';
}
}
}
if (ref($confhash{$provider}{'defaults'}) eq 'ARRAY') {
if (@{$confhash{$provider}{'defaults'}} > 0) {
$resulttext .= '<li>'.$lt{'defa'};
foreach my $field (@{$confhash{$provider}{'defaults'}}) {
$resulttext .= ' "'.$fieldtitles{$field}.'",';
}
$resulttext =~ s/,$//;
$resulttext .= '</li>';
}
} elsif (ref($confhash{$provider}{'defaults'}) eq 'HASH') {
if (keys(%{$confhash{$provider}{'defaults'}})) {
$resulttext .= '<li>'.$lt{'defa'}.': <ul>';
foreach my $key (sort(keys(%{$confhash{$provider}{'defaults'}}))) {
if ($confhash{$provider}{'defaults'}{$key} ne '') {
$resulttext .= '<li>'.$fieldtitles{$key}.' = '.$confhash{$provider}{'defaults'}{$key}.'</li>';
}
}
$resulttext .= '</ul></li>';
}
}
if (ref($crsconf{$provider}) eq 'ARRAY') {
if (@{$crsconf{$provider}} > 0) {
$resulttext .= '<li>'.&mt('Configurable in course:');
my $numconfig = 0;
if (ref($confhash{$provider}{'crsconf'}) eq 'ARRAY') {
if (@{$confhash{$provider}{'crsconf'}} > 0) {
foreach my $field (@{$confhash{$provider}{'crsconf'}}) {
$numconfig ++;
if ($provider eq 'examity') {
$resulttext .= ' "'.$lt{'crs'.$field}.'",';
} else {
$resulttext .= ' "'.$fieldtitles{$field}.'",';
}
}
$resulttext =~ s/,$//;
}
}
if (!$numconfig) {
$resulttext .= ' '.&mt('None');
}
$resulttext .= '</li>';
}
}
if ($showroles) {
if (ref($confhash{$provider}{'roles'}) eq 'HASH') {
my $rolemaps;
foreach my $role (@courseroles) {
if ($confhash{$provider}{'roles'}{$role}) {
$rolemaps .= (' 'x2).&Apache::lonnet::plaintext($role,'Course').'='.
$confhash{$provider}{'roles'}{$role}.',';
}
}
if ($rolemaps) {
$rolemaps =~ s/,$//;
$resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
}
}
}
if (ref($confhash{$provider}{'custom'}) eq 'HASH') {
my $customlist;
if (keys(%{$confhash{$provider}{'custom'}})) {
foreach my $key (sort(keys(%{$confhash{$provider}{'custom'}}))) {
$customlist .= $key.'='.$confhash{$provider}{'custom'}{$key}.', ';
}
$customlist =~ s/,$//;
}
if ($customlist) {
$resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';
}
}
$resulttext .= '</ul></li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made.');
}
} else {
$errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
}
if ($errors) {
$resulttext .= &mt('The following errors occurred: ').'<ul>'.
$errors.'</ul>';
}
return $resulttext;
}
sub process_proctoring_image {
my ($r,$dom,$confname,$caller,$provider,$configuserok,$switchserver,$author_ok) = @_;
my $filename = $env{'form.'.$caller.'.filename'};
my ($error,$url);
my ($width,$height) = (21,21);
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt('Upload of Remote Proctoring Provider icon is not permitted to this server: [_1]',
$switchserver);
} elsif ($author_ok eq 'ok') {
my $modified = [];
my ($result,$imageurl,$madethumb) =
&Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
"proctoring/$provider/icon",$width,$height,
'',$modified);
if ($result eq 'ok') {
if ($madethumb) {
my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
my $imagethumb = "$path/tn-".$imagefile;
$url = $imagethumb;
} else {
$url = $imageurl;
}
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
}
} else {
$error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$author_ok);
}
} else {
$error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$configuserok);
}
return ($url,$error);
}
sub modify_lti {
my ($r,$dom,$action,$lastactref,%domconfig) = @_;
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my ($newid,@allpos,%changes,%confhash,%ltienc,$errors,$resulttext);
my (%posslti,%posslticrs,%posscrstype);
my @courseroles = ('cc','in','ta','ep','st');
my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner);
my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
my %coursetypetitles = &Apache::lonlocal::texthash (
official => 'Official',
unofficial => 'Unofficial',
community => 'Community',
textbook => 'Textbook',
placement => 'Placement Test',
lti => 'LTI Provider',
);
my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
my %lt = <i_names();
map { $posslti{$_} = 1; } @ltiroles;
map { $posslticrs{$_} = 1; } @lticourseroles;
map { $posscrstype{$_} = 1; } @coursetypes;
my %menutitles = <imenu_titles();
my (%currltisec,%secchanges,%newltisec,%newltienc,%newkeyset);
&fetch_secrets($dom,'ltisec',\%domconfig,\%currltisec,\%secchanges,\%newltisec,\%newkeyset);
my (%linkprotchg,$linkprotoutput,$is_home);
my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'},
\%linkprotchg,'domain');
my $home = &Apache::lonnet::domain($dom,'primary');
unless (($home eq 'no_host') || ($home eq '')) {
my @ids=&Apache::lonnet::current_machine_ids();
foreach my $id (@ids) { if ($id eq $home) { $is_home=1; } }
}
if (keys(%linkprotchg)) {
$secchanges{'linkprot'} = 1;
my %oldlinkprot;
if (ref($currltisec{'linkprot'}) eq 'HASH') {
%oldlinkprot = %{$currltisec{'linkprot'}};
}
foreach my $id (keys(%linkprotchg)) {
if (ref($linkprotchg{$id}) eq 'HASH') {
foreach my $inner (keys(%{$linkprotchg{$id}})) {
if (($inner eq 'secret') || ($inner eq 'key')) {
if ($is_home) {
$newltienc{$id}{$inner} = $linkprotchg{$id}{$inner};
}
}
}
} else {
$newltisec{'linkprot'}{$id} = $linkprotchg{$id};
}
}
$linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot);
if (keys(%linkprotchg)) {
%{$newltisec{'linkprot'}} = %linkprotchg;
}
}
if (ref($currltisec{'linkprot'}) eq 'HASH') {
foreach my $id (keys(%{$currltisec{'linkprot'}})) {
next if ($id !~ /^\d+$/);
unless (exists($linkprotchg{$id})) {
if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {
foreach my $inner (keys(%{$currltisec{'linkprot'}{$id}})) {
if (($inner eq 'secret') || ($inner eq 'key')) {
if ($is_home) {
$newltienc{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};
}
} else {
$newltisec{'linkprot'}{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner};
}
}
} else {
$newltisec{'linkprot'}{$id} = $currltisec{'linkprot'}{$id};
}
}
}
}
if ($proterror) {
$errors .= '<li>'.$proterror.'</li>';
}
my (%delsuggested,%suggids,@suggested);;
if (ref($currltisec{'suggested'}) eq 'HASH') {
my $maxnum = $env{'form.linkprot_suggested_maxnum'};
my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_suggested_del');
for (my $i=0; $i<$maxnum; $i++) {
my $itemid = $env{'form.linkprot_suggested_id_'.$i};
$itemid =~ s/\D+//g;
if ($itemid) {
if (ref($currltisec{'suggested'}->{$itemid}) eq 'HASH') {
push(@suggested,$i);
$suggids{$i} = $itemid;
if ((@todelete > 0) && (grep(/^$i$/,@todelete))) {
if (ref($currltisec{'suggested'}{$itemid}) eq 'HASH') {
$delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};
}
} else {
if ($env{'form.linkprot_suggested_name_'.$i} eq '') {
$delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};
} else {
$env{'form.linkprot_suggested_name_'.$i} =~ s/(`)/'/g;
$env{'form.linkprot_suggested_info_'.$i} =~ s/(`)/'/g;
$newltisec{'suggested'}{$itemid}{'name'} = $env{'form.linkprot_suggested_name_'.$i};
$newltisec{'suggested'}{$itemid}{'info'} = $env{'form.linkprot_suggested_info_'.$i};
if (($currltisec{'suggested'}{$itemid}{'name'} ne $newltisec{'suggested'}{$itemid}{'name'}) ||
($currltisec{'suggested'}{$itemid}{'info'} ne $newltisec{'suggested'}{$itemid}{'info'})) {
$secchanges{'suggested'}{$itemid} = 1;
}
}
}
}
}
}
}
foreach my $key (keys(%delsuggested)) {
$newltisec{'suggested'}{$key} = $delsuggested{$key};
$secchanges{'suggested'}{$key} = 1;
}
if (($env{'form.linkprot_suggested_add'}) &&
($env{'form.linkprot_suggested_name_add'} ne '')) {
$env{'form.linkprot_suggested_name_add'} =~ s/(`)/'/g;
$env{'form.linkprot_suggested_info_add'} =~ s/(`)/'/g;
my ($newsuggid,$errormsg) = &get_lti_id($dom,$env{'form.linkprot_suggested_name_add'},'suggested');
if ($newsuggid) {
$newltisec{'suggested'}{$newsuggid}{'name'} = $env{'form.linkprot_suggested_name_add'};
$newltisec{'suggested'}{$newsuggid}{'info'} = $env{'form.linkprot_suggested_info_add'};
$secchanges{'suggested'}{$newsuggid} = 1;
} else {
my $error = &mt('Failed to acquire unique ID for new Link Protectors in Courses Suggestion');
if ($errormsg) {
$error .= ' ('.$errormsg.')';
}
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
my (@items,%deletions,%itemids);
if ($env{'form.lti_add'}) {
my $consumer = $env{'form.lti_consumer_add'};
$consumer =~ s/(`)/'/g;
($newid,my $errormsg) = &get_lti_id($dom,$consumer,'lti');
if ($newid) {
$itemids{'add'} = $newid;
push(@items,'add');
$changes{$newid} = 1;
} else {
my $error = &mt('Failed to acquire unique ID for new LTI configuration');
if ($errormsg) {
$error .= ' ('.$errormsg.')';
}
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
if (ref($domconfig{$action}) eq 'HASH') {
my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del');
if (@todelete) {
map { $deletions{$_} = 1; } @todelete;
}
my $maxnum = $env{'form.lti_maxnum'};
for (my $i=0; $i<$maxnum; $i++) {
my $itemid = $env{'form.lti_id_'.$i};
$itemid =~ s/\D+//g;
if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
if ($deletions{$itemid}) {
$changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'};
} else {
push(@items,$i);
$itemids{$i} = $itemid;
}
}
}
}
my (%keystore,$secstored);
if ($is_home) {
&store_security($dom,'lti',\%secchanges,\%newkeyset,\%keystore);
}
my ($cipher,$privnum);
if ((@items > 0) && ($is_home)) {
($cipher,$privnum) = &get_priv_creds($dom,$home,$secchanges{'encrypt'},
$newltisec{'encrypt'},$keystore{$home});
}
foreach my $idx (@items) {
my $itemid = $itemids{$idx};
next unless ($itemid);
my %currlti;
unless ($idx eq 'add') {
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
%currlti = %{$domconfig{$action}{$itemid}};
}
}
}
my $position = $env{'form.lti_pos_'.$itemid};
$position =~ s/\D+//g;
if ($position ne '') {
$allpos[$position] = $itemid;
}
foreach my $item ('consumer','lifetime','requser','crsinc') {
my $formitem = 'form.lti_'.$item.'_'.$idx;
$env{$formitem} =~ s/(`)/'/g;
if ($item eq 'lifetime') {
$env{$formitem} =~ s/[^\d.]//g;
}
if ($env{$formitem} ne '') {
$confhash{$itemid}{$item} = $env{$formitem};
unless (($idx eq 'add') || ($changes{$itemid})) {
if ($currlti{$item} ne $confhash{$itemid}{$item}) {
$changes{$itemid} = 1;
}
}
}
}
if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') {
$confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx};
}
if ($confhash{$itemid}{'requser'}) {
if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') {
$confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid';
} elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') {
$confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary';
} elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') {
my $mapuser = $env{'form.lti_customuser_'.$idx};
$mapuser =~ s/(`)/'/g;
$mapuser =~ s/^\s+|\s+$//g;
$confhash{$itemid}{'mapuser'} = $mapuser;
}
my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx);
my @makeuser;
foreach my $ltirole (sort(@possmakeuser)) {
if ($posslti{$ltirole}) {
push(@makeuser,$ltirole);
}
}
$confhash{$itemid}{'makeuser'} = \@makeuser;
if (@makeuser) {
my $lcauth = $env{'form.lti_lcauth_'.$idx};
if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) {
$confhash{$itemid}{'lcauth'} = $lcauth;
if ($lcauth ne 'internal') {
my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx};
$lcauthparm =~ s/^(\s+|\s+)$//g;
$lcauthparm =~ s/`//g;
if ($lcauthparm ne '') {
$confhash{$itemid}{'lcauthparm'} = $lcauthparm;
}
}
} else {
$confhash{$itemid}{'lcauth'} = 'lti';
}
}
my @possinstdata = &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx);
if (@possinstdata) {
foreach my $field (@possinstdata) {
if (exists($fieldtitles{$field})) {
push(@{$confhash{$itemid}{'instdata'}});
}
}
}
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 ('topmenu','inlinemenu') {
if ($env{'form.lti_'.$field.'_'.$idx}) {
$confhash{$itemid}{$field} = 1;
}
}
if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) {
$confhash{$itemid}{lcmenu} = [];
my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx);
foreach my $field (@possmenu) {
if (exists($menutitles{$field})) {
if ($field eq 'grades') {
next unless ($env{'form.lti_inlinemenu_'.$idx});
}
push(@{$confhash{$itemid}{lcmenu}},$field);
}
}
}
if ($confhash{$itemid}{'crsinc'}) {
if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||
($env{'form.lti_mapcrs_'.$idx} eq 'context_id')) {
$confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};
} elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {
my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx};
$mapcrs =~ s/(`)/'/g;
$mapcrs =~ s/^\s+|\s+$//g;
$confhash{$itemid}{'mapcrs'} = $mapcrs;
}
my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx);
my @crstypes;
foreach my $type (sort(@posstypes)) {
if ($posscrstype{$type}) {
push(@crstypes,$type);
}
}
$confhash{$itemid}{'mapcrstype'} = \@crstypes;
if ($env{'form.lti_storecrs_'.$idx}) {
$confhash{$itemid}{'storecrs'} = 1;
}
if ($env{'form.lti_makecrs_'.$idx}) {
$confhash{$itemid}{'makecrs'} = 1;
}
foreach my $ltirole (@lticourseroles) {
my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx};
if (grep(/^\Q$possrole\E$/,@courseroles)) {
$confhash{$itemid}{'maproles'}{$ltirole} = $possrole;
}
}
my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx);
my @selfenroll;
foreach my $type (sort(@possenroll)) {
if ($posslticrs{$type}) {
push(@selfenroll,$type);
}
}
$confhash{$itemid}{'selfenroll'} = \@selfenroll;
if ($env{'form.lti_crssec_'.$idx}) {
if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') {
$confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx};
} elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') {
my $section = $env{'form.lti_customsection_'.$idx};
$section =~ s/(`)/'/g;
$section =~ s/^\s+|\s+$//g;
if ($section ne '') {
$confhash{$itemid}{'section'} = $section;
}
}
}
foreach my $field ('passback','roster') {
if ($env{'form.lti_'.$field.'_'.$idx}) {
$confhash{$itemid}{$field} = 1;
}
}
if ($env{'form.lti_passback_'.$idx}) {
if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') {
$confhash{$itemid}{'passbackformat'} = '1.0';
} else {
$confhash{$itemid}{'passbackformat'} = '1.1';
}
}
}
unless (($idx eq 'add') || ($changes{$itemid})) {
if ($confhash{$itemid}{'crsinc'}) {
foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') {
if ($currlti{$field} ne $confhash{$itemid}{$field}) {
$changes{$itemid} = 1;
}
}
unless ($changes{$itemid}) {
if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) {
if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) {
$changes{$itemid} = 1;
}
}
}
foreach my $field ('mapcrstype','selfenroll') {
unless ($changes{$itemid}) {
if (ref($currlti{$field}) eq 'ARRAY') {
if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},
$confhash{$itemid}{$field});
if (@diffs) {
$changes{$itemid} = 1;
}
} elsif (@{$currlti{$field}} > 0) {
$changes{$itemid} = 1;
}
} elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
if (@{$confhash{$itemid}{$field}} > 0) {
$changes{$itemid} = 1;
}
}
}
}
unless ($changes{$itemid}) {
if (ref($currlti{'maproles'}) eq 'HASH') {
if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
foreach my $ltirole (keys(%{$currlti{'maproles'}})) {
if ($currlti{'maproles'}{$ltirole} ne
$confhash{$itemid}{'maproles'}{$ltirole}) {
$changes{$itemid} = 1;
last;
}
}
unless ($changes{$itemid}) {
foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {
if ($confhash{$itemid}{'maproles'}{$ltirole} ne
$currlti{'maproles'}{$ltirole}) {
$changes{$itemid} = 1;
last;
}
}
}
} elsif (keys(%{$currlti{'maproles'}}) > 0) {
$changes{$itemid} = 1;
}
} elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
unless ($changes{$itemid}) {
if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) {
$changes{$itemid} = 1;
}
}
}
}
}
unless ($changes{$itemid}) {
foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') {
if ($currlti{$field} ne $confhash{$itemid}{$field}) {
$changes{$itemid} = 1;
}
}
unless ($changes{$itemid}) {
foreach my $field ('makeuser','lcmenu') {
if (ref($currlti{$field}) eq 'ARRAY') {
if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($currlti{$field},
$confhash{$itemid}{$field});
if (@diffs) {
$changes{$itemid} = 1;
}
} elsif (@{$currlti{$field}} > 0) {
$changes{$itemid} = 1;
}
} elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
if (@{$confhash{$itemid}{$field}} > 0) {
$changes{$itemid} = 1;
}
}
}
}
}
}
}
if ($is_home) {
my $keyitem = 'form.lti_key_'.$idx;
$env{$keyitem} =~ s/(`)/'/g;
if ($env{$keyitem} ne '') {
$ltienc{$itemid}{'key'} = $env{$keyitem};
unless ($changes{$itemid}) {
if ($currlti{'key'} ne $env{$keyitem}) {
$changes{$itemid} = 1;
}
}
}
my $secretitem = 'form.lti_secret_'.$idx;
$env{$secretitem} =~ s/(`)/'/g;
if ($currlti{'usable'}) {
if ($env{'form.lti_changesecret_'.$idx}) {
if ($env{$secretitem} ne '') {
if ($privnum && $cipher) {
$ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
$confhash{$itemid}{'cipher'} = $privnum;
} else {
$ltienc{$itemid}{'secret'} = $env{$secretitem};
}
$changes{$itemid} = 1;
}
} else {
$ltienc{$itemid}{'secret'} = $currlti{'secret'};
$confhash{$itemid}{'cipher'} = $currlti{'cipher'};
}
if (ref($ltienc{$itemid}) eq 'HASH') {
if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'secret'} ne '')) {
$confhash{$itemid}{'usable'} = 1;
}
}
} elsif ($env{$secretitem} ne '') {
if ($privnum && $cipher) {
$ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
$confhash{$itemid}{'cipher'} = $privnum;
} else {
$ltienc{$itemid}{'secret'} = $env{$secretitem};
}
if (ref($ltienc{$itemid}) eq 'HASH') {
if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) {
$confhash{$itemid}{'usable'} = 1;
}
}
$changes{$itemid} = 1;
}
}
unless ($changes{$itemid}) {
foreach my $key (keys(%currlti)) {
if (ref($currlti{$key}) eq 'HASH') {
if (ref($confhash{$itemid}{$key}) eq 'HASH') {
foreach my $innerkey (keys(%{$currlti{$key}})) {
unless (exists($confhash{$itemid}{$key}{$innerkey})) {
$changes{$itemid} = 1;
last;
}
}
} elsif (keys(%{$currlti{$key}}) > 0) {
$changes{$itemid} = 1;
}
}
last if ($changes{$itemid});
}
}
}
if (@allpos > 0) {
my $idx = 0;
foreach my $itemid (@allpos) {
if ($itemid ne '') {
$confhash{$itemid}{'order'} = $idx;
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$itemid}) eq 'HASH') {
if ($domconfig{$action}{$itemid}{'order'} ne $idx) {
$changes{$itemid} = 1;
}
}
}
$idx ++;
}
}
}
if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) {
return &mt('No changes made.');
}
my %ltihash = (
$action => { %confhash }
);
my %ltienchash;
if ($is_home) {
%ltienchash = (
$action => { %ltienc }
);
}
if (keys(%secchanges)) {
$ltihash{'ltisec'} = \%newltisec;
if ($secchanges{'linkprot'}) {
if ($is_home) {
$ltienchash{'linkprot'} = \%newltienc;
}
}
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom);
if ($putresult eq 'ok') {
if (keys(%ltienchash)) {
&Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1);
}
$resulttext = &mt('Changes made:').'<ul>';
if (keys(%secchanges) > 0) {
$resulttext .= <i_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore);
if (exists($secchanges{'linkprot'})) {
$resulttext .= $linkprotoutput;
}
}
if (keys(%changes) > 0) {
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('lti',$dom,\%confhash,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'lti'} = 1;
}
my %bynum;
foreach my $itemid (sort(keys(%changes))) {
if (ref($confhash{$itemid}) eq 'HASH') {
my $position = $confhash{$itemid}{'order'};
$bynum{$position} = $itemid;
}
}
foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
my $itemid = $bynum{$pos};
if (ref($confhash{$itemid}) eq 'HASH') {
$resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>';
my $position = $pos + 1;
$resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
foreach my $item ('version','lifetime') {
if ($confhash{$itemid}{$item} ne '') {
$resulttext .= '<li>'.$lt{$item}.': '.$confhash{$itemid}{$item}.'</li>';
}
}
if ($ltienc{$itemid}{'key'} ne '') {
$resulttext .= '<li>'.$lt{'key'}.': '.$ltienc{$itemid}{'key'}.'</li>';
}
if ($ltienc{$itemid}{'secret'} ne '') {
$resulttext .= '<li>'.$lt{'secret'}.': ['.&mt('not shown').']</li>';
}
if ($confhash{$itemid}{'requser'}) {
if ($confhash{$itemid}{'callback'}) {
$resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';
} else {
$resulttext .= '<li>'.&mt('Callback to logout LON-CAPA on log out from Consumer').'</li>';
}
if ($confhash{$itemid}{'mapuser'}) {
my $shownmapuser;
if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {
$shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)';
} elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {
$shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)';
} else {
$shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')';
}
$resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';
}
if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
if (@{$confhash{$itemid}{'makeuser'}} > 0) {
$resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',
join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';
if ($confhash{$itemid}{'lcauth'} eq 'lti') {
$resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>';
} else {
$resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]',
$confhash{$itemid}{'lcauth'});
if ($confhash{$itemid}{'lcauth'} eq 'internal') {
$resulttext .= '; '.&mt('a randomly generated password will be created');
} elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') {
if ($confhash{$itemid}{'lcauthparm'} ne '') {
$resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'});
}
} else {
$resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'});
}
}
$resulttext .= '</li>';
} else {
$resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>';
}
}
if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') {
if (@{$confhash{$itemid}{'instdata'}} > 0) {
$resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]',
join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>';
} else {
$resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';
}
}
foreach my $item ('topmenu','inlinemenu') {
$resulttext .= '<li>'.$lt{$item}.': ';
if ($confhash{$itemid}{$item}) {
$resulttext .= &mt('Yes');
} else {
$resulttext .= &mt('No');
}
$resulttext .= '</li>';
}
if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {
if (@{$confhash{$itemid}{'lcmenu'}} > 0) {
$resulttext .= '<li>'.&mt('Menu items:').' '.
join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';
} else {
$resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';
}
}
if ($confhash{$itemid}{'crsinc'}) {
if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
my $rolemaps;
foreach my $role (@ltiroles) {
if ($confhash{$itemid}{'maproles'}{$role}) {
$rolemaps .= (' 'x2).$role.'='.
&Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role},
'Course').',';
}
}
if ($rolemaps) {
$rolemaps =~ s/,$//;
$resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
}
}
if ($confhash{$itemid}{'mapcrs'}) {
$resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>';
}
if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') {
if (@{$confhash{$itemid}{'mapcrstype'}} > 0) {
$resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]',
join(', ',map { $coursetypetitles{$_}; } @coursetypes)).
'</li>';
} else {
$resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>';
}
}
if ($confhash{$itemid}{'storecrs'}) {
$resulttext .= '<li>'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '.$confhash{$itemid}{'storecrs'}.'</li>';
}
if ($confhash{$itemid}{'makecrs'}) {
$resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>';
} else {
$resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>';
}
if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') {
if (@{$confhash{$itemid}{'selfenroll'}} > 0) {
$resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]',
join(', ',@{$confhash{$itemid}{'selfenroll'}})).
'</li>';
} else {
$resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>';
}
}
if ($confhash{$itemid}{'section'}) {
if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {
$resulttext .= '<li>'.&mt('User section from standard field:').
' (course_section_sourcedid)'.'</li>';
} else {
$resulttext .= '<li>'.&mt('User section from:').' '.
$confhash{$itemid}{'section'}.'</li>';
}
} else {
$resulttext .= '<li>'.&mt('No section assignment').'</li>';
}
foreach my $item ('passback','roster','topmenu','inlinemenu') {
$resulttext .= '<li>'.$lt{$item}.': ';
if ($confhash{$itemid}{$item}) {
$resulttext .= &mt('Yes');
if ($item eq 'passback') {
if ($confhash{$itemid}{'passbackformat'} eq '1.0') {
$resulttext .= ' ('.&mt('Outcomes Extension (1.0)').')';
} elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') {
$resulttext .= ' ('.&mt('Outcomes Service (1.1)').')';
}
}
} else {
$resulttext .= &mt('No');
}
$resulttext .= '</li>';
}
if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {
if (@{$confhash{$itemid}{'lcmenu'}} > 0) {
$resulttext .= '<li>'.&mt('Menu items:').' '.
join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';
} else {
$resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';
}
}
}
}
$resulttext .= '</ul></li>';
}
}
if (keys(%deletions)) {
foreach my $itemid (sort { $a <=> $b } keys(%deletions)) {
$resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>';
}
}
}
$resulttext .= '</ul>';
if (ref($lastactref) eq 'HASH') {
if (($secchanges{'encrypt'}) || ($secchanges{'private'}) || (exists($secchanges{'suggested'}))) {
&Apache::lonnet::get_domain_defaults($dom,1);
$lastactref->{'domdefaults'} = 1;
}
}
} else {
$errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
}
if ($errors) {
$resulttext .= &mt('The following errors occurred: ').'<ul>'.
$errors.'</ul>';
}
return $resulttext;
}
sub get_priv_creds {
my ($dom,$home,$encchg,$encrypt,$storedsec) = @_;
my ($needenc,$cipher,$privnum);
my %domdefs = &Apache::lonnet::get_domain_defaults($dom);
if (($encchg) && (ref($encrypt) eq 'HASH')) {
$needenc = $encrypt->{'consumers'}
} else {
$needenc = $domdefs{'ltienc_consumers'};
}
if ($needenc) {
if (($storedsec eq 'ok') || ((ref($domdefs{'ltiprivhosts'}) eq 'ARRAY') &&
(grep(/^\Q$home\E$/,@{$domdefs{'ltiprivhosts'}})))) {
my %privhash = &Apache::lonnet::restore_dom('lti','private',$dom,$home,1);
my $privkey = $privhash{'key'};
$privnum = $privhash{'version'};
if (($privnum) && ($privkey ne '')) {
$cipher = Crypt::CBC->new({'key' => $privkey,
'cipher' => 'DES'});
}
}
}
return ($cipher,$privnum);
}
sub get_lti_id {
my ($domain,$consumer,$dbname) = @_;
unless (($dbname eq 'lti') || ($dbname eq 'suggested')) {
return ('','invalid db');
}
# get lock on db
my $lockhash = {
lock => $env{'user.name'}.
':'.$env{'user.domain'},
};
my $tries = 0;
my $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);
my ($id,$error);
while (($gotlock ne 'ok') && ($tries<10)) {
$tries ++;
sleep (0.1);
$gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);
}
if ($gotlock eq 'ok') {
my %currids = &Apache::lonnet::dump_dom($dbname,$domain);
if ($currids{'lock'}) {
delete($currids{'lock'});
if (keys(%currids)) {
my @curr = sort { $a <=> $b } keys(%currids);
if ($curr[-1] =~ /^\d+$/) {
$id = 1 + $curr[-1];
}
} else {
$id = 1;
}
if ($id) {
unless (&Apache::lonnet::newput_dom($dbname,{ $id => $consumer },$domain) eq 'ok') {
$error = 'nostore';
}
} else {
$error = 'nonumber';
}
}
my $dellockoutcome = &Apache::lonnet::del_dom($dbname,['lock'],$domain);
} else {
$error = 'nolock';
}
return ($id,$error);
}
sub modify_autoenroll {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,%changes);
my %currautoenroll;
if (ref($domconfig{'autoenroll'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'autoenroll'}})) {
$currautoenroll{$key} = $domconfig{'autoenroll'}{$key};
}
}
my $autorun = &Apache::lonnet::auto_run(undef,$dom),
my %title = ( run => 'Auto-enrollment active',
sender => 'Sender for notification messages',
coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)',
autofailsafe => 'Failsafe for no drops if institutional data missing for a section');
my @offon = ('off','on');
my $sender_uname = $env{'form.sender_uname'};
my $sender_domain = $env{'form.sender_domain'};
if ($sender_domain eq '') {
$sender_uname = '';
} elsif ($sender_uname eq '') {
$sender_domain = '';
}
my $coowners = $env{'form.autoassign_coowners'};
my $autofailsafe = $env{'form.autoenroll_autofailsafe'};
$autofailsafe =~ s{^\s+|\s+$}{}g;
if ($autofailsafe =~ /\D/) {
undef($autofailsafe);
}
my $failsafe = $env{'form.autoenroll_failsafe'};
unless (($failsafe eq 'zero') || ($failsafe eq 'any')) {
$failsafe = 'off';
undef($autofailsafe);
}
my %autoenrollhash = (
autoenroll => { 'run' => $env{'form.autoenroll_run'},
'sender_uname' => $sender_uname,
'sender_domain' => $sender_domain,
'co-owners' => $coowners,
'autofailsafe' => $autofailsafe,
'failsafe' => $failsafe,
}
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash,
$dom);
if ($putresult eq 'ok') {
if (exists($currautoenroll{'run'})) {
if ($currautoenroll{'run'} ne $env{'form.autoenroll_run'}) {
$changes{'run'} = 1;
}
} elsif ($autorun) {
if ($env{'form.autoenroll_run'} ne '1') {
$changes{'run'} = 1;
}
}
if ($currautoenroll{'sender_uname'} ne $sender_uname) {
$changes{'sender'} = 1;
}
if ($currautoenroll{'sender_domain'} ne $sender_domain) {
$changes{'sender'} = 1;
}
if ($currautoenroll{'co-owners'} ne '') {
if ($currautoenroll{'co-owners'} ne $coowners) {
$changes{'coowners'} = 1;
}
} elsif ($coowners) {
$changes{'coowners'} = 1;
}
if ($currautoenroll{'autofailsafe'} ne $autofailsafe) {
$changes{'autofailsafe'} = 1;
}
if ($currautoenroll{'failsafe'} ne $failsafe) {
$changes{'failsafe'} = 1;
}
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made:').'<ul>';
if ($changes{'run'}) {
$resulttext .= '<li>'.&mt("$title{'run'} set to $offon[$env{'form.autoenroll_run'}]").'</li>';
}
if ($changes{'sender'}) {
if ($sender_uname eq '' || $sender_domain eq '') {
$resulttext .= '<li>'.&mt("$title{'sender'} set to default (course owner).").'</li>';
} else {
$resulttext .= '<li>'.&mt("$title{'sender'} set to [_1]",$sender_uname.':'.$sender_domain).'</li>';
}
}
if ($changes{'coowners'}) {
$resulttext .= '<li>'.&mt("$title{'coowners'} set to $offon[$env{'form.autoassign_coowners'}]").'</li>';
&Apache::loncommon::devalidate_domconfig_cache($dom);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
}
if ($changes{'autofailsafe'}) {
if ($autofailsafe ne '') {
$resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$autofailsafe).'</li>';
} else {
$resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';
}
}
if ($changes{'failsafe'}) {
if ($failsafe eq 'off') {
unless ($changes{'autofailsafe'}) {
$resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>';
}
} elsif ($failsafe eq 'zero') {
$resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero').'</li>';
} else {
$resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero or greater').'</li>';
}
}
if (($changes{'autofailsafe'}) || ($changes{'failsafe'})) {
&Apache::lonnet::get_domain_defaults($dom,1);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to auto-enrollment settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_autoupdate {
my ($dom,%domconfig) = @_;
my ($resulttext,%currautoupdate,%fields,%changes);
if (ref($domconfig{'autoupdate'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'autoupdate'}})) {
$currautoupdate{$key} = $domconfig{'autoupdate'}{$key};
}
}
my @offon = ('off','on');
my %title = &Apache::lonlocal::texthash (
run => 'Auto-update:',
classlists => 'Updates to user information in classlists?',
unexpired => 'Skip updates for users without active or future roles?',
lastactive => 'Skip updates for inactive users?',
);
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my %fieldtitles = &Apache::lonlocal::texthash (
id => 'Student/Employee ID',
permanentemail => 'E-mail address',
lastname => 'Last Name',
firstname => 'First Name',
middlename => 'Middle Name',
generation => 'Generation',
);
$othertitle = &mt('All users');
if (keys(%{$usertypes}) > 0) {
$othertitle = &mt('Other users');
}
foreach my $key (keys(%env)) {
if ($key =~ /^form\.updateable_(.+)_([^_]+)$/) {
my ($usertype,$item) = ($1,$2);
if (grep(/^\Q$item\E$/,keys(%fieldtitles))) {
if ($usertype eq 'default') {
push(@{$fields{$1}},$2);
} elsif (ref($types) eq 'ARRAY') {
if (grep(/^\Q$usertype\E$/,@{$types})) {
push(@{$fields{$1}},$2);
}
}
}
}
}
my @lockablenames = &Apache::loncommon::get_env_multiple('form.lockablenames');
@lockablenames = sort(@lockablenames);
if (ref($currautoupdate{'lockablenames'}) eq 'ARRAY') {
my @changed = &Apache::loncommon::compare_arrays($currautoupdate{'lockablenames'},\@lockablenames);
if (@changed) {
$changes{'lockablenames'} = 1;
}
} else {
if (@lockablenames) {
$changes{'lockablenames'} = 1;
}
}
my %updatehash = (
autoupdate => { run => $env{'form.autoupdate_run'},
classlists => $env{'form.classlists'},
unexpired => $env{'form.unexpired'},
fields => {%fields},
lockablenames => \@lockablenames,
}
);
my $lastactivedays;
if ($env{'form.lastactive'}) {
$lastactivedays = $env{'form.lastactivedays'};
$lastactivedays =~ s/^\s+|\s+$//g;
unless ($lastactivedays =~ /^\d+$/) {
undef($lastactivedays);
$env{'form.lastactive'} = 0;
}
}
$updatehash{'autoupdate'}{'lastactive'} = $lastactivedays;
foreach my $key (keys(%currautoupdate)) {
if (($key eq 'run') || ($key eq 'classlists') || ($key eq 'unexpired') || ($key eq 'lastactive')) {
if (exists($updatehash{autoupdate}{$key})) {
if ($currautoupdate{$key} ne $updatehash{autoupdate}{$key}) {
$changes{$key} = 1;
}
}
} elsif ($key eq 'fields') {
if (ref($currautoupdate{$key}) eq 'HASH') {
foreach my $item (@{$types},'default') {
if (ref($currautoupdate{$key}{$item}) eq 'ARRAY') {
my $change = 0;
foreach my $type (@{$currautoupdate{$key}{$item}}) {
if (!exists($fields{$item})) {
$change = 1;
last;
} elsif (ref($fields{$item}) eq 'ARRAY') {
if (!grep(/^\Q$type\E$/,@{$fields{$item}})) {
$change = 1;
last;
}
}
}
if ($change) {
push(@{$changes{$key}},$item);
}
}
}
}
} elsif ($key eq 'lockablenames') {
if (ref($currautoupdate{$key}) eq 'ARRAY') {
my @changed = &Apache::loncommon::compare_arrays($currautoupdate{'lockablenames'},\@lockablenames);
if (@changed) {
$changes{'lockablenames'} = 1;
}
} else {
if (@lockablenames) {
$changes{'lockablenames'} = 1;
}
}
}
}
unless (grep(/^\Qlockablenames\E$/,keys(%currautoupdate))) {
if (@lockablenames) {
$changes{'lockablenames'} = 1;
}
}
unless (grep(/^unexpired$/,keys(%currautoupdate))) {
if ($updatehash{'autoupdate'}{'unexpired'}) {
$changes{'unexpired'} = 1;
}
}
unless (grep(/^lastactive$/,keys(%currautoupdate))) {
if ($updatehash{'autoupdate'}{'lastactive'} ne '') {
$changes{'lastactive'} = 1;
}
}
foreach my $item (@{$types},'default') {
if (defined($fields{$item})) {
if (ref($currautoupdate{'fields'}) eq 'HASH') {
if (ref($currautoupdate{'fields'}{$item}) eq 'ARRAY') {
my $change = 0;
if (ref($fields{$item}) eq 'ARRAY') {
foreach my $type (@{$fields{$item}}) {
if (!grep(/^\Q$type\E$/,@{$currautoupdate{'fields'}{$item}})) {
$change = 1;
last;
}
}
}
if ($change) {
push(@{$changes{'fields'}},$item);
}
} else {
push(@{$changes{'fields'}},$item);
}
} else {
push(@{$changes{'fields'}},$item);
}
}
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%updatehash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made:').'<ul>';
foreach my $key (sort(keys(%changes))) {
if ($key eq 'lockablenames') {
$resulttext .= '<li>';
if (@lockablenames) {
$usertypes->{'default'} = $othertitle;
$resulttext .= &mt("User preference to disable replacement of user's name with institutional data (by auto-update), available for the following affiliations:").' '.
join(', ', map { $usertypes->{$_}; } @lockablenames).'</li>';
} else {
$resulttext .= &mt("User preference to disable replacement of user's name with institutional data (by auto-update) is unavailable.");
}
$resulttext .= '</li>';
} elsif (ref($changes{$key}) eq 'ARRAY') {
foreach my $item (@{$changes{$key}}) {
my @newvalues;
foreach my $type (@{$fields{$item}}) {
push(@newvalues,$fieldtitles{$type});
}
my $newvaluestr;
if (@newvalues > 0) {
$newvaluestr = join(', ',@newvalues);
} else {
$newvaluestr = &mt('none');
}
if ($item eq 'default') {
$resulttext .= '<li>'.&mt("Updates for '[_1]' set to: '[_2]'",$othertitle,$newvaluestr).'</li>';
} else {
$resulttext .= '<li>'.&mt("Updates for '[_1]' set to: '[_2]'",$usertypes->{$item},$newvaluestr).'</li>';
}
}
} else {
my $newvalue;
if ($key eq 'run') {
$newvalue = $offon[$env{'form.autoupdate_run'}];
} elsif ($key eq 'lastactive') {
$newvalue = $offon[$env{'form.lastactive'}];
unless ($lastactivedays eq '') {
$newvalue .= '; '.&mt('inactive = no activity in last [quant,_1,day]',$lastactivedays);
}
} else {
$newvalue = $offon[$env{'form.'.$key}];
}
$resulttext .= '<li>'.&mt("[_1] set to $newvalue",$title{$key}).'</li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to autoupdates');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_autocreate {
my ($dom,%domconfig) = @_;
my ($resulttext,%changes,%currautocreate,%newvals,%autocreatehash);
if (ref($domconfig{'autocreate'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'autocreate'}})) {
$currautocreate{$key} = $domconfig{'autocreate'}{$key};
}
}
my %title= ( xml => 'Auto-creation of courses in XML course description files',
req => 'Auto-creation of validated requests for official courses',
xmldc => 'Identity of course creator of courses from XML files',
);
my @types = ('xml','req');
foreach my $item (@types) {
$newvals{$item} = $env{'form.autocreate_'.$item};
$newvals{$item} =~ s/\D//g;
$newvals{$item} = 0 if ($newvals{$item} eq '');
}
$newvals{'xmldc'} = $env{'form.autocreate_xmldc'};
my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
unless (exists($domcoords{$newvals{'xmldc'}})) {
$newvals{'xmldc'} = '';
}
%autocreatehash = (
autocreate => { xml => $newvals{'xml'},
req => $newvals{'req'},
}
);
if ($newvals{'xmldc'} ne '') {
$autocreatehash{'autocreate'}{'xmldc'} = $newvals{'xmldc'};
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%autocreatehash,
$dom);
if ($putresult eq 'ok') {
my @items = @types;
if ($newvals{'xml'}) {
push(@items,'xmldc');
}
foreach my $item (@items) {
if (exists($currautocreate{$item})) {
if ($currautocreate{$item} ne $newvals{$item}) {
$changes{$item} = 1;
}
} elsif ($newvals{$item}) {
$changes{$item} = 1;
}
}
if (keys(%changes) > 0) {
my @offon = ('off','on');
$resulttext = &mt('Changes made:').'<ul>';
foreach my $item (@types) {
if ($changes{$item}) {
my $newtxt = $offon[$newvals{$item}];
$resulttext .= '<li>'.
&mt("$title{$item} set to [_1]$newtxt [_2]",
'<b>','</b>').
'</li>';
}
}
if ($changes{'xmldc'}) {
my ($dcname,$dcdom) = split(':',$newvals{'xmldc'});
my $newtxt = &Apache::loncommon::plainname($dcname,$dcdom);
$resulttext .= '<li>'.&mt("$title{'xmldc'} set to [_1]",'<b>'.$newtxt.'</b>').'</li>';
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to auto-creation settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_directorysrch {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,%changes);
my %currdirsrch;
if (ref($domconfig{'directorysrch'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'directorysrch'}})) {
$currdirsrch{$key} = $domconfig{'directorysrch'}{$key};
}
}
my %title = ( available => 'Institutional directory search available',
localonly => 'Other domains can search institution',
lcavailable => 'LON-CAPA directory search available',
lclocalonly => 'Other domains can search LON-CAPA domain',
searchby => 'Search types',
searchtypes => 'Search latitude');
my @offon = ('off','on');
my @otherdoms = ('Yes','No');
my @searchtypes = &Apache::loncommon::get_env_multiple('form.searchtypes');
my @cansearch = &Apache::loncommon::get_env_multiple('form.cansearch');
my @searchby = &Apache::loncommon::get_env_multiple('form.searchby');
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
if (keys(%{$usertypes}) == 0) {
@cansearch = ('default');
} else {
if (ref($currdirsrch{'cansearch'}) eq 'ARRAY') {
foreach my $type (@{$currdirsrch{'cansearch'}}) {
if (!grep(/^\Q$type\E$/,@cansearch)) {
push(@{$changes{'cansearch'}},$type);
}
}
foreach my $type (@cansearch) {
if (!grep(/^\Q$type\E$/,@{$currdirsrch{'cansearch'}})) {
push(@{$changes{'cansearch'}},$type);
}
}
} else {
push(@{$changes{'cansearch'}},@cansearch);
}
}
if (ref($currdirsrch{'searchby'}) eq 'ARRAY') {
foreach my $by (@{$currdirsrch{'searchby'}}) {
if (!grep(/^\Q$by\E$/,@searchby)) {
push(@{$changes{'searchby'}},$by);
}
}
foreach my $by (@searchby) {
if (!grep(/^\Q$by\E$/,@{$currdirsrch{'searchby'}})) {
push(@{$changes{'searchby'}},$by);
}
}
} else {
push(@{$changes{'searchby'}},@searchby);
}
if (ref($currdirsrch{'searchtypes'}) eq 'ARRAY') {
foreach my $type (@{$currdirsrch{'searchtypes'}}) {
if (!grep(/^\Q$type\E$/,@searchtypes)) {
push(@{$changes{'searchtypes'}},$type);
}
}
foreach my $type (@searchtypes) {
if (!grep(/^\Q$type\E$/,@{$currdirsrch{'searchtypes'}})) {
push(@{$changes{'searchtypes'}},$type);
}
}
} else {
if (exists($currdirsrch{'searchtypes'})) {
foreach my $type (@searchtypes) {
if ($type ne $currdirsrch{'searchtypes'}) {
push(@{$changes{'searchtypes'}},$type);
}
}
if (!grep(/^\Q$currdirsrch{'searchtypes'}\E/,@searchtypes)) {
push(@{$changes{'searchtypes'}},$currdirsrch{'searchtypes'});
}
} else {
push(@{$changes{'searchtypes'}},@searchtypes);
}
}
my %dirsrch_hash = (
directorysrch => { available => $env{'form.dirsrch_available'},
cansearch => \@cansearch,
localonly => $env{'form.dirsrch_instlocalonly'},
lclocalonly => $env{'form.dirsrch_domlocalonly'},
lcavailable => $env{'form.dirsrch_domavailable'},
searchby => \@searchby,
searchtypes => \@searchtypes,
}
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%dirsrch_hash,
$dom);
if ($putresult eq 'ok') {
if (exists($currdirsrch{'available'})) {
if ($currdirsrch{'available'} ne $env{'form.dirsrch_available'}) {
$changes{'available'} = 1;
}
} else {
if ($env{'form.dirsrch_available'} eq '1') {
$changes{'available'} = 1;
}
}
if (exists($currdirsrch{'lcavailable'})) {
if ($currdirsrch{'lcavailable'} ne $env{'form.dirsrch_domavailable'}) {
$changes{'lcavailable'} = 1;
}
} else {
if ($env{'form.dirsrch_lcavailable'} eq '1') {
$changes{'lcavailable'} = 1;
}
}
if (exists($currdirsrch{'localonly'})) {
if ($currdirsrch{'localonly'} ne $env{'form.dirsrch_instlocalonly'}) {
$changes{'localonly'} = 1;
}
} else {
if ($env{'form.dirsrch_instlocalonly'} eq '1') {
$changes{'localonly'} = 1;
}
}
if (exists($currdirsrch{'lclocalonly'})) {
if ($currdirsrch{'lclocalonly'} ne $env{'form.dirsrch_domlocalonly'}) {
$changes{'lclocalonly'} = 1;
}
} else {
if ($env{'form.dirsrch_domlocalonly'} eq '1') {
$changes{'lclocalonly'} = 1;
}
}
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made:').'<ul>';
if ($changes{'available'}) {
$resulttext .= '<li>'.&mt("$title{'available'} set to: $offon[$env{'form.dirsrch_available'}]").'</li>';
}
if ($changes{'lcavailable'}) {
$resulttext .= '<li>'.&mt("$title{'lcavailable'} set to: $offon[$env{'form.dirsrch_domavailable'}]").'</li>';
}
if ($changes{'localonly'}) {
$resulttext .= '<li>'.&mt("$title{'localonly'} set to: $otherdoms[$env{'form.dirsrch_instlocalonly'}]").'</li>';
}
if ($changes{'lclocalonly'}) {
$resulttext .= '<li>'.&mt("$title{'lclocalonly'} set to: $otherdoms[$env{'form.dirsrch_domlocalonly'}]").'</li>';
}
if (ref($changes{'cansearch'}) eq 'ARRAY') {
my $chgtext;
if (ref($usertypes) eq 'HASH') {
if (keys(%{$usertypes}) > 0) {
foreach my $type (@{$types}) {
if (grep(/^\Q$type\E$/,@cansearch)) {
$chgtext .= $usertypes->{$type}.'; ';
}
}
if (grep(/^default$/,@cansearch)) {
$chgtext .= $othertitle;
} else {
$chgtext =~ s/\; $//;
}
$resulttext .=
'<li>'.
&mt("Users from domain '[_1]' permitted to search the institutional directory set to: [_2]",
'<span class="LC_cusr_emph">'.$dom.'</span>',$chgtext).
'</li>';
}
}
}
if (ref($changes{'searchby'}) eq 'ARRAY') {
my ($searchtitles,$titleorder) = &sorted_searchtitles();
my $chgtext;
foreach my $type (@{$titleorder}) {
if (grep(/^\Q$type\E$/,@searchby)) {
if (defined($searchtitles->{$type})) {
$chgtext .= $searchtitles->{$type}.'; ';
}
}
}
$chgtext =~ s/\; $//;
$resulttext .= '<li>'.&mt("$title{'searchby'} set to: [_1]",$chgtext).'</li>';
}
if (ref($changes{'searchtypes'}) eq 'ARRAY') {
my ($srchtypes_desc,$srchtypeorder) = &sorted_searchtypes();
my $chgtext;
foreach my $type (@{$srchtypeorder}) {
if (grep(/^\Q$type\E$/,@searchtypes)) {
if (defined($srchtypes_desc->{$type})) {
$chgtext .= $srchtypes_desc->{$type}.'; ';
}
}
}
$chgtext =~ s/\; $//;
$resulttext .= '<li>'.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'</li>';
}
$resulttext .= '</ul>';
&Apache::lonnet::do_cache_new('directorysrch',$dom,$dirsrch_hash{'directorysrch'},3600);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'directorysrch'} = 1;
}
} else {
$resulttext = &mt('No changes made to directory search settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_contacts {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,%currsetting,%newsetting,%changes,%contacts_hash);
if (ref($domconfig{'contacts'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'contacts'}})) {
$currsetting{$key} = $domconfig{'contacts'}{$key};
}
}
my (%others,%to,%bcc,%includestr,%includeloc);
my @contacts = ('supportemail','adminemail');
my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail',
'lonstatusmail','requestsmail','updatesmail','idconflictsmail','hostipmail');
my @toggles = ('reporterrors','reportupdates','reportstatus');
my @lonstatus = ('threshold','sysmail','weights','excluded');
my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields();
foreach my $type (@mailings) {
@{$newsetting{$type}} =
&Apache::loncommon::get_env_multiple('form.'.$type);
foreach my $item (@contacts) {
if (grep(/^\Q$item\E$/,@{$newsetting{$type}})) {
$contacts_hash{contacts}{$type}{$item} = 1;
} else {
$contacts_hash{contacts}{$type}{$item} = 0;
}
}
$others{$type} = $env{'form.'.$type.'_others'};
$contacts_hash{contacts}{$type}{'others'} = $others{$type};
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
$bcc{$type} = $env{'form.'.$type.'_bcc'};
$contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type};
if (($env{'form.'.$type.'_includestr'} ne '') && ($env{'form.'.$type.'_includeloc'} =~ /^s|b$/)) {
$includestr{$type} = $env{'form.'.$type.'_includestr'};
$includeloc{$type} = $env{'form.'.$type.'_includeloc'};
$contacts_hash{contacts}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});
}
}
}
foreach my $item (@contacts) {
$to{$item} = $env{'form.'.$item};
$contacts_hash{'contacts'}{$item} = $to{$item};
}
foreach my $item (@toggles) {
if ($env{'form.'.$item} =~ /^(0|1)$/) {
$contacts_hash{'contacts'}{$item} = $env{'form.'.$item};
}
}
my ($lonstatus_defs,$lonstatus_names) = &Apache::loncommon::lon_status_items();
foreach my $item (@lonstatus) {
if ($item eq 'excluded') {
my (%serverhomes,@excluded);
map { $serverhomes{$_} = 1; } values(%Apache::lonnet::serverhomeIDs);
my @possexcluded = &Apache::loncommon::get_env_multiple('form.errorexcluded');
if (@possexcluded) {
foreach my $id (sort(@possexcluded)) {
if ($serverhomes{$id}) {
push(@excluded,$id);
}
}
}
if (@excluded) {
$contacts_hash{'contacts'}{'lonstatus'}{$item} = \@excluded;
}
} elsif ($item eq 'weights') {
foreach my $type ('E','W','N','U') {
$env{'form.error'.$item.'_'.$type} =~ s/^\s+|\s+$//g;
if ($env{'form.error'.$item.'_'.$type} =~ /^\d+$/) {
unless ($env{'form.error'.$item.'_'.$type} == $lonstatus_defs->{$type}) {
$contacts_hash{'contacts'}{'lonstatus'}{$item}{$type} =
$env{'form.error'.$item.'_'.$type};
}
}
}
} elsif (($item eq 'threshold') || ($item eq 'sysmail')) {
$env{'form.error'.$item} =~ s/^\s+|\s+$//g;
if ($env{'form.error'.$item} =~ /^\d+$/) {
unless ($env{'form.error'.$item} == $lonstatus_defs->{$item}) {
$contacts_hash{'contacts'}{'lonstatus'}{$item} = $env{'form.error'.$item};
}
}
}
}
if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) {
foreach my $field (@{$fields}) {
if (ref($possoptions->{$field}) eq 'ARRAY') {
my $value = $env{'form.helpform_'.$field};
$value =~ s/^\s+|\s+$//g;
if (grep(/^\Q$value\E$/,@{$possoptions->{$field}})) {
$contacts_hash{'contacts'}{'helpform'}{$field} = $value;
if ($field eq 'screenshot') {
$env{'form.helpform_maxsize'} =~ s/^\s+|\s+$//g;
if ($env{'form.helpform_maxsize'} =~ /^\d+\.?\d*$/) {
$contacts_hash{'contacts'}{'helpform'}{'maxsize'} = $env{'form.helpform_maxsize'};
}
}
}
}
}
}
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my (@statuses,%usertypeshash,@overrides);
if ((ref($types) eq 'ARRAY') && (@{$types} > 0)) {
@statuses = @{$types};
if (ref($usertypes) eq 'HASH') {
%usertypeshash = %{$usertypes};
}
}
if (@statuses) {
my @possoverrides = &Apache::loncommon::get_env_multiple('form.overrides');
foreach my $type (@possoverrides) {
if (($type ne '') && (grep(/^\Q$type\E$/,@statuses))) {
push(@overrides,$type);
}
}
if (@overrides) {
foreach my $type (@overrides) {
my @standard = &Apache::loncommon::get_env_multiple('form.override_'.$type);
foreach my $item (@contacts) {
if (grep(/^\Q$item\E$/,@standard)) {
$contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 1;
$newsetting{'override_'.$type}{$item} = 1;
} else {
$contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 0;
$newsetting{'override_'.$type}{$item} = 0;
}
}
$contacts_hash{'contacts'}{'overrides'}{$type}{'others'} = $env{'form.override_'.$type.'_others'};
$contacts_hash{'contacts'}{'overrides'}{$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'};
$newsetting{'override_'.$type}{'others'} = $env{'form.override_'.$type.'_others'};
$newsetting{'override_'.$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'};
if (($env{'form.override_'.$type.'_includestr'} ne '') && ($env{'form.override_'.$type.'_includeloc'} =~ /^s|b$/)) {
$includestr{$type} = $env{'form.override_'.$type.'_includestr'};
$includeloc{$type} = $env{'form.override_'.$type.'_includeloc'};
$contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type});
$newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'};
}
}
}
}
if (keys(%currsetting) > 0) {
foreach my $item (@contacts) {
if ($to{$item} ne $currsetting{$item}) {
$changes{$item} = 1;
}
}
foreach my $type (@mailings) {
foreach my $item (@contacts) {
if (ref($currsetting{$type}) eq 'HASH') {
if ($currsetting{$type}{$item} ne $contacts_hash{contacts}{$type}{$item}) {
push(@{$changes{$type}},$item);
}
} else {
push(@{$changes{$type}},@{$newsetting{$type}});
}
}
if ($others{$type} ne $currsetting{$type}{'others'}) {
push(@{$changes{$type}},'others');
}
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
if ($bcc{$type} ne $currsetting{$type}{'bcc'}) {
push(@{$changes{$type}},'bcc');
}
my ($currloc,$currstr) = split(/:/,$currsetting{$type}{'include'},2);
if (($includeloc{$type} ne $currloc) || (&escape($includestr{$type}) ne $currstr)) {
push(@{$changes{$type}},'include');
}
}
}
if (ref($fields) eq 'ARRAY') {
if (ref($currsetting{'helpform'}) eq 'HASH') {
foreach my $field (@{$fields}) {
if ($currsetting{'helpform'}{$field} ne $contacts_hash{'contacts'}{'helpform'}{$field}) {
push(@{$changes{'helpform'}},$field);
}
if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {
if ($currsetting{'helpform'}{'maxsize'} ne $contacts_hash{'contacts'}{'helpform'}{'maxsize'}) {
push(@{$changes{'helpform'}},'maxsize');
}
}
}
} else {
foreach my $field (@{$fields}) {
if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') {
push(@{$changes{'helpform'}},$field);
}
if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {
if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) {
push(@{$changes{'helpform'}},'maxsize');
}
}
}
}
}
if (@statuses) {
if (ref($currsetting{'overrides'}) eq 'HASH') {
foreach my $key (keys(%{$currsetting{'overrides'}})) {
if (ref($currsetting{'overrides'}{$key}) eq 'HASH') {
if (ref($newsetting{'override_'.$key}) eq 'HASH') {
foreach my $item (@contacts,'bcc','others','include') {
if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) {
push(@{$changes{'overrides'}},$key);
last;
}
}
} else {
push(@{$changes{'overrides'}},$key);
}
}
}
foreach my $key (@overrides) {
unless (exists($currsetting{'overrides'}{$key})) {
push(@{$changes{'overrides'}},$key);
}
}
} else {
foreach my $key (@overrides) {
push(@{$changes{'overrides'}},$key);
}
}
}
if (ref($currsetting{'lonstatus'}) eq 'HASH') {
foreach my $key ('excluded','weights','threshold','sysmail') {
if ($key eq 'excluded') {
if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&
(ref($contacts_hash{contacts}{lonstatus}{excluded}) eq 'ARRAY')) {
if ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&
(@{$currsetting{'lonstatus'}{$key}})) {
my @diffs =
&Apache::loncommon::compare_arrays($contacts_hash{contacts}{lonstatus}{excluded},
$currsetting{'lonstatus'}{$key});
if (@diffs) {
push(@{$changes{'lonstatus'}},$key);
}
} elsif (@{$contacts_hash{contacts}{lonstatus}{excluded}}) {
push(@{$changes{'lonstatus'}},$key);
}
} elsif ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') &&
(@{$currsetting{'lonstatus'}{$key}})) {
push(@{$changes{'lonstatus'}},$key);
}
} elsif ($key eq 'weights') {
if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') &&
(ref($contacts_hash{contacts}{lonstatus}{$key}) eq 'HASH')) {
if (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {
foreach my $type ('E','W','N','U') {
unless ($contacts_hash{contacts}{lonstatus}{$key}{$type} eq
$currsetting{'lonstatus'}{$key}{$type}) {
push(@{$changes{'lonstatus'}},$key);
last;
}
}
} else {
foreach my $type ('E','W','N','U') {
if ($contacts_hash{contacts}{lonstatus}{$key}{$type} ne '') {
push(@{$changes{'lonstatus'}},$key);
last;
}
}
}
} elsif (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') {
foreach my $type ('E','W','N','U') {
if ($currsetting{'lonstatus'}{$key}{$type} ne '') {
push(@{$changes{'lonstatus'}},$key);
last;
}
}
}
} elsif (($key eq 'threshold') || ($key eq 'sysmail')) {
if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
if ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {
if ($currsetting{'lonstatus'}{$key} != $contacts_hash{contacts}{lonstatus}{$key}) {
push(@{$changes{'lonstatus'}},$key);
}
} elsif ($contacts_hash{contacts}{lonstatus}{$key} =~ /^\d+$/) {
push(@{$changes{'lonstatus'}},$key);
}
} elsif ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) {
push(@{$changes{'lonstatus'}},$key);
}
}
}
} else {
if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
foreach my $key ('excluded','weights','threshold','sysmail') {
if (exists($contacts_hash{contacts}{lonstatus}{$key})) {
push(@{$changes{'lonstatus'}},$key);
}
}
}
}
} else {
my %default;
$default{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'};
$default{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'};
$default{'errormail'} = 'adminemail';
$default{'packagesmail'} = 'adminemail';
$default{'helpdeskmail'} = 'supportemail';
$default{'otherdomsmail'} = 'supportemail';
$default{'lonstatusmail'} = 'adminemail';
$default{'requestsmail'} = 'adminemail';
$default{'updatesmail'} = 'adminemail';
$default{'hostipmail'} = 'adminemail';
foreach my $item (@contacts) {
if ($to{$item} ne $default{$item}) {
$changes{$item} = 1;
}
}
foreach my $type (@mailings) {
if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) {
push(@{$changes{$type}},@{$newsetting{$type}});
}
if ($others{$type} ne '') {
push(@{$changes{$type}},'others');
}
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
if ($bcc{$type} ne '') {
push(@{$changes{$type}},'bcc');
}
if (($includeloc{$type} =~ /^b|s$/) && ($includestr{$type} ne '')) {
push(@{$changes{$type}},'include');
}
}
}
if (ref($fields) eq 'ARRAY') {
foreach my $field (@{$fields}) {
if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') {
push(@{$changes{'helpform'}},$field);
}
if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) {
if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) {
push(@{$changes{'helpform'}},'maxsize');
}
}
}
}
if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') {
foreach my $key ('excluded','weights','threshold','sysmail') {
if (exists($contacts_hash{contacts}{lonstatus}{$key})) {
push(@{$changes{'lonstatus'}},$key);
}
}
}
}
foreach my $item (@toggles) {
if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) {
$changes{$item} = 1;
} elsif ((!$env{'form.'.$item}) &&
(($currsetting{$item} eq '') || ($currsetting{$item} == 1))) {
$changes{$item} = 1;
}
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%contacts_hash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
&Apache::loncommon::devalidate_domconfig_cache($dom);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
my ($titles,$short_titles) = &contact_titles();
$resulttext = &mt('Changes made:').'<ul>';
foreach my $item (@contacts) {
if ($changes{$item}) {
$resulttext .= '<li>'.$titles->{$item}.
&mt(' set to: ').
'<span class="LC_cusr_emph">'.
$to{$item}.'</span></li>';
}
}
foreach my $type (@mailings) {
if (ref($changes{$type}) eq 'ARRAY') {
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
$resulttext .= '<li>'.$titles->{$type}.' -- '.&mt('sent to').': ';
} else {
$resulttext .= '<li>'.$titles->{$type}.': ';
}
my @text;
foreach my $item (@{$newsetting{$type}}) {
push(@text,$short_titles->{$item});
}
if ($others{$type} ne '') {
push(@text,$others{$type});
}
if (@text) {
$resulttext .= '<span class="LC_cusr_emph">'.
join(', ',@text).'</span>';
}
if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) {
if ($bcc{$type} ne '') {
my $bcctext;
if (@text) {
$bcctext = ' '.&mt('with Bcc to');
} else {
$bcctext = '(Bcc)';
}
$resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>';
} elsif (!@text) {
$resulttext .= &mt('No one');
}
if ($includestr{$type} ne '') {
if ($includeloc{$type} eq 'b') {
$resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type};
} elsif ($includeloc{$type} eq 's') {
$resulttext .= '<br />'.&mt('Text automatically added to e-mail subject:').' '.$includestr{$type};
}
}
} elsif (!@text) {
$resulttext .= &mt('No recipients');
}
$resulttext .= '</li>';
}
}
if (ref($changes{'overrides'}) eq 'ARRAY') {
my @deletions;
foreach my $type (@{$changes{'overrides'}}) {
if ($usertypeshash{$type}) {
if (grep(/^\Q$type\E/,@overrides)) {
$resulttext .= '<li>'.&mt("Overrides based on requester's affiliation set for [_1]",
$usertypeshash{$type}).'<ul><li>';
if (ref($newsetting{'override_'.$type}) eq 'HASH') {
my @text;
foreach my $item (@contacts) {
if ($newsetting{'override_'.$type}{$item}) {
push(@text,$short_titles->{$item});
}
}
if ($newsetting{'override_'.$type}{'others'} ne '') {
push(@text,$newsetting{'override_'.$type}{'others'});
}
if (@text) {
$resulttext .= &mt('Helpdesk e-mail sent to: [_1]',
'<span class="LC_cusr_emph">'.join(', ',@text).'</span>');
}
if ($newsetting{'override_'.$type}{'bcc'} ne '') {
my $bcctext;
if (@text) {
$bcctext = ' '.&mt('with Bcc to');
} else {
$bcctext = '(Bcc)';
}
$resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$newsetting{'override_'.$type}{'bcc'}.'</span>';
} elsif (!@text) {
$resulttext .= &mt('Helpdesk e-mail sent to no one');
}
$resulttext .= '</li>';
if ($newsetting{'override_'.$type}{'include'} ne '') {
my ($loc,$str) = split(/:/,$newsetting{'override_'.$type}{'include'});
if ($loc eq 'b') {
$resulttext .= '<li>'.&mt('Text automatically added to e-mail body:').' '.&unescape($str).'</li>';
} elsif ($loc eq 's') {
$resulttext .= '<li>'.&mt('Text automatically added to e-mail subject:').' '.&unescape($str).'</li>';
}
}
}
$resulttext .= '</li></ul></li>';
} else {
push(@deletions,$usertypeshash{$type});
}
}
}
if (@deletions) {
$resulttext .= '<li>'.&mt("Overrides based on requester's affiliation discontinued for: [_1]",
join(', ',@deletions)).'</li>';
}
}
my @offon = ('off','on');
my $corelink = &core_link_msu();
if ($changes{'reporterrors'}) {
$resulttext .= '<li>'.
&mt('E-mail error reports to [_1] set to "'.
$offon[$env{'form.reporterrors'}].'".',
$corelink).
'</li>';
}
if ($changes{'reportupdates'}) {
$resulttext .= '<li>'.
&mt('E-mail record of completed LON-CAPA updates to [_1] set to "'.
$offon[$env{'form.reportupdates'}].'".',
$corelink).
'</li>';
}
if ($changes{'reportstatus'}) {
$resulttext .= '<li>'.
&mt('E-mail status if errors above threshold to [_1] set to "'.
$offon[$env{'form.reportstatus'}].'".',
$corelink).
'</li>';
}
if (ref($changes{'lonstatus'}) eq 'ARRAY') {
$resulttext .= '<li>'.
&mt('Nightly status check e-mail settings').':<ul>';
my (%defval,%use_def,%shown);
$defval{'threshold'} = $lonstatus_defs->{'threshold'};
$defval{'sysmail'} = $lonstatus_defs->{'sysmail'};
$defval{'weights'} =
join(', ',map { $lonstatus_names->{$_}.'='.$lonstatus_defs->{$_}; } ('E','W','N','U'));
$defval{'excluded'} = &mt('None');
if (ref($contacts_hash{'contacts'}{'lonstatus'}) eq 'HASH') {
foreach my $item ('threshold','sysmail','weights','excluded') {
if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item})) {
if (($item eq 'threshold') || ($item eq 'sysmail')) {
$shown{$item} = $contacts_hash{'contacts'}{'lonstatus'}{$item};
} elsif ($item eq 'weights') {
if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'HASH') {
foreach my $type ('E','W','N','U') {
$shown{$item} .= $lonstatus_names->{$type}.'=';
if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item}{$type})) {
$shown{$item} .= $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type};
} else {
$shown{$item} .= $lonstatus_defs->{$type};
}
$shown{$item} .= ', ';
}
$shown{$item} =~ s/, $//;
} else {
$shown{$item} = $defval{$item};
}
} elsif ($item eq 'excluded') {
if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'ARRAY') {
$shown{$item} = join(', ',@{$contacts_hash{'contacts'}{'lonstatus'}{$item}});
} else {
$shown{$item} = $defval{$item};
}
}
} else {
$shown{$item} = $defval{$item};
}
}
} else {
foreach my $item ('threshold','weights','excluded','sysmail') {
$shown{$item} = $defval{$item};
}
}
foreach my $item ('threshold','weights','excluded','sysmail') {
$resulttext .= '<li>'.&mt($titles->{'error'.$item}.' -- [_1]',
$shown{$item}).'</li>';
}
$resulttext .= '</ul></li>';
}
if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) {
my (@optional,@required,@unused,$maxsizechg);
foreach my $field (@{$changes{'helpform'}}) {
if ($field eq 'maxsize') {
$maxsizechg = 1;
next;
}
if ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'yes') {
push(@optional,$field);
} elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'no') {
push(@unused,$field);
} elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'req') {
push(@required,$field);
}
}
if (@optional) {
$resulttext .= '<li>'.
&mt('Help form fields changed to "Optional": [_1].',
'<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @optional)).'</span>'.
'</li>';
}
if (@required) {
$resulttext .= '<li>'.
&mt('Help form fields changed to "Required": [_1].',
'<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @required)).'</span>'.
'</li>';
}
if (@unused) {
$resulttext .= '<li>'.
&mt('Help form fields changed to "Not shown": [_1].',
'<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @unused)).'</span>'.
'</li>';
}
if ($maxsizechg) {
$resulttext .= '<li>'.
&mt('Max size for file uploaded to help form by logged-in user set to [_1] MB.',
$contacts_hash{'contacts'}{'helpform'}{'maxsize'}).
'</li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to contacts and form settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1].',$putresult).'</span>';
}
return $resulttext;
}
sub modify_privacy {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,%current,%changes);
if (ref($domconfig{'privacy'}) eq 'HASH') {
%current = %{$domconfig{'privacy'}};
}
my @fields = ('lastname','firstname','middlename','generation','permanentemail','id');
my @items = ('domain','author','course','community');
my %names = &Apache::lonlocal::texthash (
domain => 'Assigned domain role(s)',
author => 'Assigned co-author role(s)',
course => 'Assigned course role(s)',
community => 'Assigned community role(s)',
);
my %roles = &Apache::lonlocal::texthash (
domain => 'Domain role',
author => 'Co-author role',
course => 'Course role',
community => 'Community role',
);
my %titles = &Apache::lonlocal::texthash (
approval => 'Approval for role in different domain',
othdom => 'User information available in other domain',
priv => 'Information viewable by privileged user in same domain',
unpriv => 'Information viewable by unprivileged user in same domain',
instdom => 'Other domain shares institution/provider',
extdom => 'Other domain has different institution/provider',
none => 'Not allowed',
user => 'User authorizes',
domain => 'Domain Coordinator authorizes',
auto => 'Unrestricted',
notify => 'Notify when role needs authorization',
);
my %fieldnames = &Apache::lonlocal::texthash (
id => 'Student/Employee ID',
permanentemail => 'E-mail address',
lastname => 'Last Name',
firstname => 'First Name',
middlename => 'Middle Name',
generation => 'Generation',
);
my ($othertitle,$usertypes,$types) =
&Apache::loncommon::sorted_inst_types($dom);
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my %privacyhash = (
'approval' => {
instdom => {},
extdom => {},
},
'othdom' => {},
'priv' => {},
'unpriv' => {},
);
foreach my $item (@items) {
if (@instdoms > 1) {
if ($env{'form.privacy_approval_instdom_'.$item} =~ /^(none|user|domain|auto)$/) {
$privacyhash{'approval'}{'instdom'}{$item} = $env{'form.privacy_approval_instdom_'.$item};
}
if (ref($current{'approval'}) eq 'HASH') {
if (ref($current{'approval'}{'instdom'}) eq 'HASH') {
unless ($privacyhash{'approval'}{'instdom'}{$item} eq $current{'approval'}{'instdom'}{$item}) {
$changes{'approval'} = 1;
}
}
} elsif ($privacyhash{'approval'}{'instdom'}{$item} ne 'auto') {
$changes{'approval'} = 1;
}
}
if (keys(%by_location) > 0) {
if ($env{'form.privacy_approval_extdom_'.$item} =~ /^(none|user|domain|auto)$/) {
$privacyhash{'approval'}{'extdom'}{$item} = $env{'form.privacy_approval_extdom_'.$item};
}
if (ref($current{'approval'}) eq 'HASH') {
if (ref($current{'approval'}{'extdom'}) eq 'HASH') {
unless ($privacyhash{'approval'}{'extdom'}{$item} eq $current{'approval'}{'extdom'}{$item}) {
$changes{'approval'} = 1;
}
}
} elsif ($privacyhash{'approval'}{'extdom'}{$item} ne 'auto') {
$changes{'approval'} = 1;
}
}
foreach my $status ('priv','unpriv') {
my @possibles = sort(&Apache::loncommon::get_env_multiple('form.privacy_'.$status.'_'.$item));
my @newvalues;
foreach my $field (@possibles) {
if (grep(/^\Q$field\E$/,@fields)) {
$privacyhash{$status}{$item}{$field} = 1;
push(@newvalues,$field);
}
}
@newvalues = sort(@newvalues);
if (ref($current{$status}) eq 'HASH') {
if (ref($current{$status}{$item}) eq 'HASH') {
my @currvalues = sort(keys(%{$current{$status}{$item}}));
my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues);
if (@diffs > 0) {
$changes{$status} = 1;
}
}
} else {
my @stdfields;
foreach my $field (@fields) {
if ($field eq 'id') {
next if ($status eq 'unpriv');
next if (($status eq 'priv') && ($item eq 'community'));
}
push(@stdfields,$field);
}
my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues);
if (@diffs > 0) {
$changes{$status} = 1;
}
}
}
}
if ((@instdoms > 1) || (keys(%by_location) > 0)) {
my @statuses;
if (ref($types) eq 'ARRAY') {
@statuses = @{$types};
}
foreach my $type (@statuses,'default') {
my @possfields = &Apache::loncommon::get_env_multiple('form.privacy_othdom_'.$type);
my @newvalues;
foreach my $field (sort(@possfields)) {
if (grep(/^\Q$field\E$/,@fields)) {
$privacyhash{'othdom'}{$type}{$field} = 1;
push(@newvalues,$field);
}
}
@newvalues = sort(@newvalues);
if (ref($current{'othdom'}) eq 'HASH') {
if (ref($current{'othdom'}{$type}) eq 'HASH') {
my @currvalues = sort(keys(%{$current{'othdom'}{$type}}));
my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues);
if (@diffs > 0) {
$changes{'othdom'} = 1;
}
}
} else {
my @stdfields = ('lastname','firstname','middlename','generation','permanentemail');
my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues);
if (@diffs > 0) {
$changes{'othdom'} = 1;
}
}
}
my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
my %notify;
foreach my $possdc (&Apache::loncommon::get_env_multiple('form.privacy_notify')) {
if (exists($domcoords{$possdc})) {
$notify{$possdc} = 1;
}
}
my $notify = join(',',sort(keys(%notify)));
if ($current{'notify'} ne $notify) {
$changes{'notify'} = 1;
}
$privacyhash{'notify'} = $notify;
}
my %confighash = (
privacy => \%privacyhash,
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made: ').'<ul>';
foreach my $key ('approval','notify','othdom','priv','unpriv') {
if ($changes{$key}) {
$resulttext .= '<li>'.$titles{$key}.':<ul>';
if ($key eq 'approval') {
if (keys(%{$privacyhash{$key}{instdom}})) {
$resulttext .= '<li>'.$titles{'instdom'}.'<ul>';
foreach my $item (@items) {
$resulttext .= '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{instdom}{$item}}.'</li>';
}
$resulttext .= '</ul></li>';
}
if (keys(%{$privacyhash{$key}{extdom}})) {
$resulttext .= '<li>'.$titles{'extdom'}.'<ul>';
foreach my $item (@items) {
$resulttext .= '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{extdom}{$item}}.'</li>';
}
$resulttext .= '</ul></li>';
}
} elsif ($key eq 'notify') {
if ($privacyhash{$key}) {
foreach my $dc (split(/,/,$privacyhash{$key})) {
my ($dcname,$dcdom) = split(/:/,$dc);
$resulttext .= '<li>'.&Apache::loncommon::plainname($dcname,$dcdom).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('No DCs to notify').'</li>';
}
} elsif ($key eq 'othdom') {
my @statuses;
if (ref($types) eq 'ARRAY') {
@statuses = @{$types};
}
if (ref($privacyhash{$key}) eq 'HASH') {
foreach my $status (@statuses,'default') {
if ($status eq 'default') {
$resulttext .= '<li>'.$othertitle.': ';
} elsif (ref($usertypes) eq 'HASH') {
$resulttext .= '<li>'.$usertypes->{$status}.': ';
} else {
next;
}
if (ref($privacyhash{$key}{$status}) eq 'HASH') {
if (keys(%{$privacyhash{$key}{$status}})) {
$resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$status}}))));
} else {
$resulttext .= &mt('none');
}
}
$resulttext .= '</li>';
}
}
} else {
foreach my $item (@items) {
if (ref($privacyhash{$key}{$item}) eq 'HASH') {
$resulttext .= '<li>'.$names{$item}.': ';
if (keys(%{$privacyhash{$key}{$item}})) {
$resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$item}}))));
} else {
$resulttext .= &mt('none');
}
$resulttext .= '</li>';
}
}
}
$resulttext .= '</ul></li>';
}
}
$resulttext .= '</ul>';
if ($changes{'approval'}) {
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
delete($domdefaults{'userapprovals'});
if (ref($privacyhash{'approval'}) eq 'HASH') {
foreach my $domtype ('instdom','extdom') {
if (ref($privacyhash{'approval'}{$domtype}) eq 'HASH') {
foreach my $roletype ('domain','author','course','community') {
if ($privacyhash{'approval'}{$domtype}{$roletype} eq 'user') {
$domdefaults{'userapprovals'} = 1;
last;
}
}
}
last if ($domdefaults{'userapprovals'});
}
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
} else {
$resulttext = &mt('No changes made to user information settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_passwords {
my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
my ($resulttext,%current,%changes,%newvalues,@oktypes,$errors,
$updatedefaults,$updateconf);
my $customfn = 'resetpw.html';
if (ref($domconfig{'passwords'}) eq 'HASH') {
%current = %{$domconfig{'passwords'}};
}
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
if (ref($types) eq 'ARRAY') {
@oktypes = @{$types};
}
push(@oktypes,'default');
my %titles = &Apache::lonlocal::texthash (
intauth_cost => 'Encryption cost for bcrypt (positive integer)',
intauth_check => 'Check bcrypt cost if authenticated',
intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',
permanent => 'Permanent e-mail address',
critical => 'Critical notification address',
notify => 'Notification address',
min => 'Minimum password length',
max => 'Maximum password length',
chars => 'Required characters',
expire => 'Password expiration (days)',
numsaved => 'Number of previous passwords to save',
reset => 'Resetting Forgotten Password',
intauth => 'Encryption of Stored Passwords (Internal Auth)',
rules => 'Rules for LON-CAPA Passwords',
crsownerchg => 'Course Owner Changing Student Passwords',
username => 'Username',
email => 'E-mail address',
);
#
# Retrieve current domain configuration for internal authentication from $domconfig{'defaults'}.
#
my (%curr_defaults,%save_defaults);
if (ref($domconfig{'defaults'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'defaults'}})) {
if ($key =~ /^intauth_(cost|check|switch)$/) {
$curr_defaults{$key} = $domconfig{'defaults'}{$key};
} else {
$save_defaults{$key} = $domconfig{'defaults'}{$key};
}
}
}
my %staticdefaults = (
'resetlink' => 2,
'resetcase' => \@oktypes,
'resetprelink' => 'both',
'resetemail' => ['critical','notify','permanent'],
'intauth_cost' => 10,
'intauth_check' => 0,
'intauth_switch' => 0,
);
$staticdefaults{'min'} = $Apache::lonnet::passwdmin;
foreach my $type (@oktypes) {
$staticdefaults{'resetpostlink'}{$type} = ['email','username'];
}
my $linklife = $env{'form.passwords_link'};
$linklife =~ s/^\s+|\s+$//g;
if (($linklife =~ /^\d+(|\.\d*)$/) && ($linklife > 0)) {
$newvalues{'resetlink'} = $linklife;
if ($current{'resetlink'}) {
if ($current{'resetlink'} ne $linklife) {
$changes{'reset'} = 1;
}
} elsif (!ref($domconfig{passwords}) eq 'HASH') {
if ($staticdefaults{'resetlink'} ne $linklife) {
$changes{'reset'} = 1;
}
}
} elsif ($current{'resetlink'}) {
$changes{'reset'} = 1;
}
my @casesens;
my @posscase = &Apache::loncommon::get_env_multiple('form.passwords_case_sensitive');
foreach my $case (sort(@posscase)) {
if (grep(/^\Q$case\E$/,@oktypes)) {
push(@casesens,$case);
}
}
$newvalues{'resetcase'} = \@casesens;
if (ref($current{'resetcase'}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($current{'resetcase'},\@casesens);
if (@diffs > 0) {
$changes{'reset'} = 1;
}
} elsif (!ref($domconfig{passwords}) eq 'HASH') {
my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens);
if (@diffs > 0) {
$changes{'reset'} = 1;
}
}
if ($env{'form.passwords_prelink'} =~ /^(both|either)$/) {
$newvalues{'resetprelink'} = $env{'form.passwords_prelink'};
if (exists($current{'resetprelink'})) {
if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) {
$changes{'reset'} = 1;
}
} elsif (!ref($domconfig{passwords}) eq 'HASH') {
if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) {
$changes{'reset'} = 1;
}
}
} elsif ($current{'resetprelink'}) {
$changes{'reset'} = 1;
}
foreach my $type (@oktypes) {
my @possplink = &Apache::loncommon::get_env_multiple('form.passwords_postlink_'.$type);
my @postlink;
foreach my $item (sort(@possplink)) {
if ($item =~ /^(email|username)$/) {
push(@postlink,$item);
}
}
$newvalues{'resetpostlink'}{$type} = \@postlink;
unless ($changes{'reset'}) {
if (ref($current{'resetpostlink'}) eq 'HASH') {
if (ref($current{'resetpostlink'}{$type}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($current{'resetpostlink'}{$type},\@postlink);
if (@diffs > 0) {
$changes{'reset'} = 1;
}
} else {
$changes{'reset'} = 1;
}
} elsif (!ref($domconfig{passwords}) eq 'HASH') {
my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink);
if (@diffs > 0) {
$changes{'reset'} = 1;
}
}
}
}
my @possemailsrc = &Apache::loncommon::get_env_multiple('form.passwords_emailsrc');
my @resetemail;
foreach my $item (sort(@possemailsrc)) {
if ($item =~ /^(permanent|critical|notify)$/) {
push(@resetemail,$item);
}
}
$newvalues{'resetemail'} = \@resetemail;
unless ($changes{'reset'}) {
if (ref($current{'resetemail'}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($current{'resetemail'},\@resetemail);
if (@diffs > 0) {
$changes{'reset'} = 1;
}
} elsif (!ref($domconfig{passwords}) eq 'HASH') {
my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail);
if (@diffs > 0) {
$changes{'reset'} = 1;
}
}
}
if ($env{'form.passwords_stdtext'} == 0) {
$newvalues{'resetremove'} = 1;
unless ($current{'resetremove'}) {
$changes{'reset'} = 1;
}
} elsif ($current{'resetremove'}) {
$changes{'reset'} = 1;
}
if ($env{'form.passwords_customfile.filename'} ne '') {
my $servadm = $r->dir_config('lonAdmEMail');
my ($configuserok,$author_ok,$switchserver) =
&config_check($dom,$confname,$servadm);
my $error;
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);
} else {
if ($author_ok eq 'ok') {
my $modified = [];
my ($result,$customurl) =
&Apache::lonconfigsettings::publishlogo($r,'upload','passwords_customfile',$dom,
$confname,'customtext/resetpw','','',$customfn,
$modified);
if ($result eq 'ok') {
$newvalues{'resetcustom'} = $customurl;
$changes{'reset'} = 1;
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);
}
} else {
$error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$customfn,$confname,$dom,$author_ok);
}
}
} else {
$error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$customfn,$confname,$dom,$configuserok);
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
} elsif ($current{'resetcustom'}) {
if ($env{'form.passwords_custom_del'}) {
$changes{'reset'} = 1;
} else {
$newvalues{'resetcustom'} = $current{'resetcustom'};
}
}
$env{'form.intauth_cost'} =~ s/^\s+|\s+$//g;
if (($env{'form.intauth_cost'} ne '') && ($env{'form.intauth_cost'} =~ /^\d+$/)) {
$save_defaults{'intauth_cost'} = $env{'form.intauth_cost'};
if ($save_defaults{'intauth_cost'} ne $curr_defaults{'intauth_cost'}) {
$changes{'intauth'} = 1;
}
} else {
$save_defaults{'intauth_cost'} = $curr_defaults{'intauth_cost'};
}
if ($env{'form.intauth_check'} =~ /^(0|1|2)$/) {
$save_defaults{'intauth_check'} = $env{'form.intauth_check'};
if ($save_defaults{'intauth_check'} ne $curr_defaults{'intauth_check'}) {
$changes{'intauth'} = 1;
}
} else {
$save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};
}
if ($env{'form.intauth_switch'} =~ /^(0|1|2)$/) {
$save_defaults{'intauth_switch'} = $env{'form.intauth_switch'};
if ($save_defaults{'intauth_switch'} ne $curr_defaults{'intauth_switch'}) {
$changes{'intauth'} = 1;
}
} else {
$save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};
}
foreach my $item ('cost','check','switch') {
if ($save_defaults{'intauth_'.$item} ne $domdefaults{'intauth_'.$item}) {
$domdefaults{'intauth_'.$item} = $save_defaults{'intauth_'.$item};
$updatedefaults = 1;
}
}
&password_rule_changes('passwords',\%newvalues,\%current,\%changes);
my %crsownerchg = (
by => [],
for => [],
);
foreach my $item ('by','for') {
my @posstypes = &Apache::loncommon::get_env_multiple('form.passwords_crsowner_'.$item);
foreach my $type (sort(@posstypes)) {
if (grep(/^\Q$type\E$/,@oktypes)) {
push(@{$crsownerchg{$item}},$type);
}
}
}
$newvalues{'crsownerchg'} = \%crsownerchg;
if (ref($current{'crsownerchg'}) eq 'HASH') {
foreach my $item ('by','for') {
if (ref($current{'crsownerchg'}{$item}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($current{'crsownerchg'}{$item},$crsownerchg{$item});
if (@diffs > 0) {
$changes{'crsownerchg'} = 1;
last;
}
}
}
} elsif (!(ref($domconfig{passwords}) eq 'HASH')) {
foreach my $item ('by','for') {
if (@{$crsownerchg{$item}} > 0) {
$changes{'crsownerchg'} = 1;
last;
}
}
}
my %confighash = (
defaults => \%save_defaults,
passwords => \%newvalues,
);
&process_captcha('passwords',\%changes,$confighash{'passwords'},$domconfig{'passwords'});
my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made: ').'<ul>';
foreach my $key ('reset','intauth','rules','crsownerchg') {
if ($changes{$key}) {
unless ($key eq 'intauth') {
$updateconf = 1;
}
$resulttext .= '<li>'.$titles{$key}.':<ul>';
if ($key eq 'reset') {
if ($confighash{'passwords'}{'captcha'} eq 'original') {
$resulttext .= '<li>'.&mt('CAPTCHA validation set to use: original CAPTCHA').'</li>';
} elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') {
$resulttext .= '<li>'.&mt('CAPTCHA validation set to use: reCAPTCHA').' '.
&mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'<br />';
if (ref($confighash{'passwords'}{'recaptchakeys'}) eq 'HASH') {
$resulttext .= &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'public'}).'</br>'.
&mt('Private key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'private'}).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('No CAPTCHA validation').'</li>';
}
if ($confighash{'passwords'}{'resetlink'}) {
$resulttext .= '<li>'.&mt('Reset link expiration set to [quant,_1,hour]',$confighash{'passwords'}{'resetlink'}).'</li>';
} else {
$resulttext .= '<li>'.&mt('No reset link expiration set.').' '.
&mt('Will default to 2 hours').'</li>';
}
if (ref($confighash{'passwords'}{'resetcase'}) eq 'ARRAY') {
if (@{$confighash{'passwords'}{'resetcase'}} == 0) {
$resulttext .= '<li>'.&mt('User input for username and/or e-mail address not case sensitive for "Forgot Password" web form').'</li>';
} else {
my $casesens;
foreach my $type (@{$confighash{'passwords'}{'resetcase'}}) {
if ($type eq 'default') {
$casesens .= $othertitle.', ';
} elsif ($usertypes->{$type} ne '') {
$casesens .= $usertypes->{$type}.', ';
}
}
$casesens =~ s/\Q, \E$//;
$resulttext .= '<li>'.&mt('"Forgot Password" web form input for username and/or e-mail address is case-sensitive for: [_1]',$casesens).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Case-sensitivity not set for "Forgot Password" web form').' '.&mt('Will default to case-sensitive for username and/or e-mail address for all').'</li>';
}
if ($confighash{'passwords'}{'resetprelink'} eq 'either') {
$resulttext .= '<li>'.&mt('Users can enter either a username or an e-mail address in "Forgot Password" web form').'</li>';
} else {
$resulttext .= '<li>'.&mt('Users can enter both a username and an e-mail address in "Forgot Password" web form').'</li>';
}
if (ref($confighash{'passwords'}{'resetpostlink'}) eq 'HASH') {
my $output;
if (ref($types) eq 'ARRAY') {
foreach my $type (@{$types}) {
if (ref($confighash{'passwords'}{'resetpostlink'}{$type}) eq 'ARRAY') {
if (@{$confighash{'passwords'}{'resetpostlink'}{$type}} == 0) {
$output .= $usertypes->{$type}.' -- '.&mt('none');
} else {
$output .= $usertypes->{$type}.' -- '.
join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{$type}})).'; ';
}
}
}
}
if (ref($confighash{'passwords'}{'resetpostlink'}{'default'}) eq 'ARRAY') {
if (@{$confighash{'passwords'}{'resetpostlink'}{'default'}} == 0) {
$output .= $othertitle.' -- '.&mt('none');
} else {
$output .= $othertitle.' -- '.
join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{'default'}}));
}
}
if ($output) {
$resulttext .= '<li>'.&mt('Information required for new password form (by user type) set to: [_1]',$output).'</li>';
} else {
$resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';
}
if (ref($confighash{'passwords'}{'resetemail'}) eq 'ARRAY') {
if (@{$confighash{'passwords'}{'resetemail'}} > 0) {
$resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$confighash{'passwords'}{'resetemail'}})).'</li>';
} else {
$resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
}
if ($confighash{'passwords'}{'resetremove'}) {
$resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';
} else {
$resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form is shown').'</li>';
}
if ($confighash{'passwords'}{'resetcustom'}) {
my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'},
&mt('custom text'),600,500,undef,undef,
undef,undef,'background-color:#ffffff');
$resulttext .= '<li>'.&mt('Preamble to "Forgot Password" form includes: [_1]',$customlink).'</li>';
} else {
$resulttext .= '<li>'.&mt('No custom text included in preamble to "Forgot Password" form').'</li>';
}
} elsif ($key eq 'intauth') {
foreach my $item ('cost','switch','check') {
my $value = $save_defaults{$key.'_'.$item};
if ($item eq 'switch') {
my %optiondesc = &Apache::lonlocal::texthash (
0 => 'No',
1 => 'Yes',
2 => 'Yes, and copy existing passwd file to passwd.bak file',
);
if ($value =~ /^(0|1|2)$/) {
$value = $optiondesc{$value};
} else {
$value = &mt('none -- defaults to No');
}
} elsif ($item eq 'check') {
my %optiondesc = &Apache::lonlocal::texthash (
0 => 'No',
1 => 'Yes, allow login then update passwd file using default cost (if higher)',
2 => 'Yes, disallow login if stored cost is less than domain default',
);
if ($value =~ /^(0|1|2)$/) {
$value = $optiondesc{$value};
} else {
$value = &mt('none -- defaults to No');
}
}
$resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';
}
} elsif ($key eq 'rules') {
foreach my $rule ('min','max','expire','numsaved') {
if ($confighash{'passwords'}{$rule} eq '') {
if ($rule eq 'min') {
$resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
' '.&mt('Default of [_1] will be used',
$Apache::lonnet::passwdmin).'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>';
}
}
if (ref($confighash{'passwords'}{'chars'}) eq 'ARRAY') {
if (@{$confighash{'passwords'}{'chars'}} > 0) {
my %rulenames = &Apache::lonlocal::texthash(
uc => 'At least one upper case letter',
lc => 'At least one lower case letter',
num => 'At least one number',
spec => 'At least one non-alphanumeric',
);
my $needed = '<ul><li>'.
join('</li><li>',map {$rulenames{$_} } @{$confighash{'passwords'}{'chars'}}).
'</li></ul>';
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>';
}
} elsif ($key eq 'crsownerchg') {
if (ref($confighash{'passwords'}{'crsownerchg'}) eq 'HASH') {
if ((@{$confighash{'passwords'}{'crsownerchg'}{'by'}} == 0) ||
(@{$confighash{'passwords'}{'crsownerchg'}{'for'}} == 0)) {
$resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';
} else {
my %crsownerstr;
foreach my $item ('by','for') {
if (ref($confighash{'passwords'}{'crsownerchg'}{$item}) eq 'ARRAY') {
foreach my $type (@{$confighash{'passwords'}{'crsownerchg'}{$item}}) {
if ($type eq 'default') {
$crsownerstr{$item} .= $othertitle.', ';
} elsif ($usertypes->{$type} ne '') {
$crsownerstr{$item} .= $usertypes->{$type}.', ';
}
}
$crsownerstr{$item} =~ s/\Q, \E$//;
}
}
$resulttext .= '<li>'.&mt('Course owner (with status: [_1]) may change passwords for students (with status: [_2]).',
$crsownerstr{'by'},$crsownerstr{'for'}).'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>';
}
}
$resulttext .= '</ul></li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to password settings');
}
my $cachetime = 24*60*60;
if ($updatedefaults) {
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
if ($updateconf) {
&Apache::lonnet::do_cache_new('passwdconf',$dom,$confighash{'passwords'},$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'passwdconf'} = 1;
}
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if ($errors) {
$resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul></p>';
}
return $resulttext;
}
sub password_rule_changes {
my ($prefix,$newvalues,$current,$changes) = @_;
return unless ((ref($newvalues) eq 'HASH') &&
(ref($current) eq 'HASH') &&
(ref($changes) eq 'HASH'));
my (@rules,%staticdefaults);
if ($prefix eq 'passwords') {
@rules = ('min','max','expire','numsaved');
} elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
@rules = ('min','max');
}
$staticdefaults{'min'} = $Apache::lonnet::passwdmin;
foreach my $rule (@rules) {
$env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;
my $ruleok;
if ($rule eq 'expire') {
if (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+(|\.\d*)$/) &&
($env{'form.'.$prefix.'_'.$rule} ne '0')) {
$ruleok = 1;
}
} elsif ($rule eq 'min') {
if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) {
if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) {
$ruleok = 1;
}
}
} elsif (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) &&
($env{'form.'.$prefix.'_'.$rule} ne '0')) {
$ruleok = 1;
}
if ($ruleok) {
$newvalues->{$rule} = $env{'form.'.$prefix.'_'.$rule};
if (exists($current->{$rule})) {
if ($newvalues->{$rule} ne $current->{$rule}) {
$changes->{'rules'} = 1;
}
} elsif ($rule eq 'min') {
if ($staticdefaults{$rule} ne $newvalues->{$rule}) {
$changes->{'rules'} = 1;
}
} else {
$changes->{'rules'} = 1;
}
} elsif (exists($current->{$rule})) {
$changes->{'rules'} = 1;
}
}
my @posschars = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_chars');
my @chars;
foreach my $item (sort(@posschars)) {
if ($item =~ /^(uc|lc|num|spec)$/) {
push(@chars,$item);
}
}
$newvalues->{'chars'} = \@chars;
unless ($changes->{'rules'}) {
if (ref($current->{'chars'}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($current->{'chars'},\@chars);
if (@diffs > 0) {
$changes->{'rules'} = 1;
}
} else {
if (@chars > 0) {
$changes->{'rules'} = 1;
}
}
}
return;
}
sub modify_usercreation {
my ($dom,%domconfig) = @_;
my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);
my $warningmsg;
if (ref($domconfig{'usercreation'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'usercreation'}})) {
if ($key eq 'cancreate') {
if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {
foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {
if (($item eq 'requestcrs') || ($item eq 'course') || ($item eq 'author')) {
$curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
} else {
$save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
}
}
}
} elsif ($key eq 'email_rule') {
$save_usercreate{$key} = $domconfig{'usercreation'}{$key};
} else {
$curr_usercreation{$key} = $domconfig{'usercreation'}{$key};
}
}
}
my @username_rule = &Apache::loncommon::get_env_multiple('form.username_rule');
my @id_rule = &Apache::loncommon::get_env_multiple('form.id_rule');
my @contexts = ('author','course','requestcrs');
foreach my $item(@contexts) {
$cancreate{$item} = $env{'form.can_createuser_'.$item};
}
if (ref($curr_usercreation{'cancreate'}) eq 'HASH') {
foreach my $item (@contexts) {
if ($curr_usercreation{'cancreate'}{$item} ne $cancreate{$item}) {
push(@{$changes{'cancreate'}},$item);
}
}
} elsif (ref($curr_usercreation{'cancreate'}) eq 'ARRAY') {
foreach my $item (@contexts) {
if (!grep(/^\Q$item\E$/,@{$curr_usercreation{'cancreate'}})) {
if ($cancreate{$item} ne 'any') {
push(@{$changes{'cancreate'}},$item);
}
} else {
if ($cancreate{$item} ne 'none') {
push(@{$changes{'cancreate'}},$item);
}
}
}
} else {
foreach my $item (@contexts) {
push(@{$changes{'cancreate'}},$item);
}
}
if (ref($curr_usercreation{'username_rule'}) eq 'ARRAY') {
foreach my $type (@{$curr_usercreation{'username_rule'}}) {
if (!grep(/^\Q$type\E$/,@username_rule)) {
push(@{$changes{'username_rule'}},$type);
}
}
foreach my $type (@username_rule) {
if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'username_rule'}})) {
push(@{$changes{'username_rule'}},$type);
}
}
} else {
push(@{$changes{'username_rule'}},@username_rule);
}
if (ref($curr_usercreation{'id_rule'}) eq 'ARRAY') {
foreach my $type (@{$curr_usercreation{'id_rule'}}) {
if (!grep(/^\Q$type\E$/,@id_rule)) {
push(@{$changes{'id_rule'}},$type);
}
}
foreach my $type (@id_rule) {
if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'id_rule'}})) {
push(@{$changes{'id_rule'}},$type);
}
}
} else {
push(@{$changes{'id_rule'}},@id_rule);
}
my @authen_contexts = ('author','course','domain');
my @authtypes = ('int','krb4','krb5','loc','lti');
my %authhash;
foreach my $item (@authen_contexts) {
my @authallowed = &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');
foreach my $auth (@authtypes) {
if (grep(/^\Q$auth\E$/,@authallowed)) {
$authhash{$item}{$auth} = 1;
} else {
$authhash{$item}{$auth} = 0;
}
}
}
if (ref($curr_usercreation{'authtypes'}) eq 'HASH') {
foreach my $item (@authen_contexts) {
if (ref($curr_usercreation{'authtypes'}{$item}) eq 'HASH') {
foreach my $auth (@authtypes) {
if ($authhash{$item}{$auth} ne $curr_usercreation{'authtypes'}{$item}{$auth}) {
push(@{$changes{'authtypes'}},$item);
last;
}
}
}
}
} else {
foreach my $item (@authen_contexts) {
push(@{$changes{'authtypes'}},$item);
}
}
$save_usercreate{'cancreate'}{'course'} = $cancreate{'course'};
$save_usercreate{'cancreate'}{'author'} = $cancreate{'author'};
$save_usercreate{'cancreate'}{'requestcrs'} = $cancreate{'requestcrs'};
$save_usercreate{'id_rule'} = \@id_rule;
$save_usercreate{'username_rule'} = \@username_rule,
$save_usercreate{'authtypes'} = \%authhash;
my %usercreation_hash = (
usercreation => \%save_usercreate,
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%usercreation_hash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made:').'<ul>';
if (ref($changes{'cancreate'}) eq 'ARRAY') {
my %lt = &usercreation_types();
foreach my $type (@{$changes{'cancreate'}}) {
my $chgtext = $lt{$type}.', ';
if ($cancreate{$type} eq 'none') {
$chgtext .= &mt('creation of new users is not permitted, except by a Domain Coordinator.');
} elsif ($cancreate{$type} eq 'any') {
$chgtext .= &mt('creation of new users is permitted for both institutional and non-institutional usernames.');
} elsif ($cancreate{$type} eq 'official') {
$chgtext .= &mt('creation of new users is only permitted for institutional usernames.');
} elsif ($cancreate{$type} eq 'unofficial') {
$chgtext .= &mt('creation of new users is only permitted for non-institutional usernames.');
}
$resulttext .= '<li>'.$chgtext.'</li>';
}
}
if (ref($changes{'username_rule'}) eq 'ARRAY') {
my ($rules,$ruleorder) =
&Apache::lonnet::inst_userrules($dom,'username');
my $chgtext = '<ul>';
foreach my $type (@username_rule) {
if (ref($rules->{$type}) eq 'HASH') {
$chgtext .= '<li>'.$rules->{$type}{'name'}.'</li>';
}
}
$chgtext .= '</ul>';
if (@username_rule > 0) {
$resulttext .= '<li>'.&mt('Usernames with the following formats are restricted to verified users in the institutional directory: ').$chgtext.'</li>';
} else {
$resulttext .= '<li>'.&mt('There are now no username formats restricted to verified users in the institutional directory.').'</li>';
}
}
if (ref($changes{'id_rule'}) eq 'ARRAY') {
my ($idrules,$idruleorder) =
&Apache::lonnet::inst_userrules($dom,'id');
my $chgtext = '<ul>';
foreach my $type (@id_rule) {
if (ref($idrules->{$type}) eq 'HASH') {
$chgtext .= '<li>'.$idrules->{$type}{'name'}.'</li>';
}
}
$chgtext .= '</ul>';
if (@id_rule > 0) {
$resulttext .= '<li>'.&mt('IDs with the following formats are restricted to verified users in the institutional directory: ').$chgtext.'</li>';
} else {
$resulttext .= '<li>'.&mt('There are now no ID formats restricted to verified users in the institutional directory.').'</li>';
}
}
my %authname = &authtype_names();
my %context_title = &context_names();
if (ref($changes{'authtypes'}) eq 'ARRAY') {
my $chgtext = '<ul>';
foreach my $type (@{$changes{'authtypes'}}) {
my @allowed;
$chgtext .= '<li><span class="LC_cusr_emph">'.$context_title{$type}.'</span> - '.&mt('assignable authentication types: ');
foreach my $auth (@authtypes) {
if ($authhash{$type}{$auth}) {
push(@allowed,$authname{$auth});
}
}
if (@allowed > 0) {
$chgtext .= join(', ',@allowed).'</li>';
} else {
$chgtext .= &mt('none').'</li>';
}
}
$chgtext .= '</ul>';
$resulttext .= '<li>'.&mt('Authentication types available for assignment to new users').'<br />'.$chgtext;
$resulttext .= '</li>';
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to user creation settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if ($warningmsg ne '') {
$resulttext .= '<br /><span class="LC_warning">'.$warningmsg.'</span><br />';
}
return $resulttext;
}
sub modify_selfcreation {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%curr_inststatus,%changes,%cancreate);
my (%save_usercreate,%save_usermodify,%save_inststatus,@types,%usertypes);
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my ($othertitle,$usertypesref,$typesref) = &Apache::loncommon::sorted_inst_types($dom);
if (ref($typesref) eq 'ARRAY') {
@types = @{$typesref};
}
if (ref($usertypesref) eq 'HASH') {
%usertypes = %{$usertypesref};
}
$usertypes{'default'} = $othertitle;
#
# Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}.
#
if (ref($domconfig{'usercreation'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'usercreation'}})) {
if ($key eq 'cancreate') {
if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') {
foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) {
if (($item eq 'selfcreate') || ($item eq 'statustocreate') ||
($item eq 'captcha') || ($item eq 'recaptchakeys') ||
($item eq 'recaptchaversion') || ($item eq 'notify') ||
($item eq 'emailusername') || ($item eq 'shibenv') ||
($item eq 'selfcreateprocessing') || ($item eq 'emailverified') ||
($item eq 'emailoptions') || ($item eq 'emaildomain')) {
$curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
} else {
$save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item};
}
}
}
} elsif ($key eq 'email_rule') {
$curr_usercreation{$key} = $domconfig{'usercreation'}{$key};
} else {
$save_usercreate{$key} = $domconfig{'usercreation'}{$key};
}
}
}
#
# Retrieve current domain configuration for self-creation of usernames from $domconfig{'usermodification'}.
#
if (ref($domconfig{'usermodification'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'usermodification'}})) {
if ($key eq 'selfcreate') {
$curr_usermodify{$key} = $domconfig{'usermodification'}{$key};
} else {
$save_usermodify{$key} = $domconfig{'usermodification'}{$key};
}
}
}
#
# Retrieve current domain configuration for institutional status types from $domconfig{'inststatus'}.
#
if (ref($domconfig{'inststatus'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'inststatus'}})) {
if ($key eq 'inststatusguest') {
$curr_inststatus{$key} = $domconfig{'inststatus'}{$key};
} else {
$save_inststatus{$key} = $domconfig{'inststatus'}{$key};
}
}
}
my @contexts = ('selfcreate');
@{$cancreate{'selfcreate'}} = ();
%{$cancreate{'emailusername'}} = ();
if (@types) {
@{$cancreate{'statustocreate'}} = ();
}
%{$cancreate{'selfcreateprocessing'}} = ();
%{$cancreate{'shibenv'}} = ();
%{$cancreate{'emailverified'}} = ();
%{$cancreate{'emailoptions'}} = ();
%{$cancreate{'emaildomain'}} = ();
my %selfcreatetypes = (
sso => 'users authenticated by institutional single sign on',
login => 'users authenticated by institutional log-in',
email => 'users verified by e-mail',
);
#
# Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts
# is permitted.
#
my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email');
my (@statuses,%email_rule);
foreach my $item ('login','sso','email') {
if ($item eq 'email') {
if ($env{'form.cancreate_email'}) {
if (@types) {
my @poss_statuses = &Apache::loncommon::get_env_multiple('form.selfassign');
foreach my $status (@poss_statuses) {
if (grep(/^\Q$status\E$/,(@types,'default'))) {
push(@statuses,$status);
}
}
$save_inststatus{'inststatusguest'} = \@statuses;
} else {
push(@statuses,'default');
}
if (@statuses) {
my %curr_rule;
if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') {
foreach my $type (@statuses) {
$curr_rule{$type} = $curr_usercreation{'email_rule'};
}
} elsif (ref($curr_usercreation{'email_rule'}) eq 'HASH') {
foreach my $type (@statuses) {
$curr_rule{$type} = $curr_usercreation{'email_rule'}{$type};
}
}
push(@{$cancreate{'selfcreate'}},'email');
push(@contexts,('selfcreateprocessing','emailverified','emailoptions'));
my %curremaildom;
if (ref($curr_usercreation{'cancreate'}{'emaildomain'}) eq 'HASH') {
%curremaildom = %{$curr_usercreation{'cancreate'}{'emaildomain'}};
}
foreach my $type (@statuses) {
if ($env{'form.cancreate_emailprocess_'.$type} =~ /^(?:approval|automatic)$/) {
$cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type};
}
if ($env{'form.cancreate_usernameoptions_'.$type} =~ /^(?:all|first|free)$/) {
$cancreate{'emailverified'}{$type} = $env{'form.cancreate_usernameoptions_'.$type};
}
if ($env{'form.cancreate_emailoptions_'.$type} =~ /^(any|inst|noninst|custom)$/) {
#
# Retrieve rules (if any) governing types of e-mail address which may be used to verify a username.
#
my $chosen = $1;
if (($chosen eq 'inst') || ($chosen eq 'noninst')) {
my $emaildom;
if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) {
$emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type};
$cancreate{'emaildomain'}{$type}{$chosen} = $emaildom;
if (ref($curremaildom{$type}) eq 'HASH') {
if (exists($curremaildom{$type}{$chosen})) {
if ($curremaildom{$type}{$chosen} ne $emaildom) {
push(@{$changes{'cancreate'}},'emaildomain');
}
} elsif ($emaildom ne '') {
push(@{$changes{'cancreate'}},'emaildomain');
}
} elsif ($emaildom ne '') {
push(@{$changes{'cancreate'}},'emaildomain');
}
}
$cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};
} elsif ($chosen eq 'custom') {
my @possemail_rules = &Apache::loncommon::get_env_multiple('form.email_rule_'.$type);
$email_rule{$type} = [];
if (ref($emailrules) eq 'HASH') {
foreach my $rule (@possemail_rules) {
if (exists($emailrules->{$rule})) {
push(@{$email_rule{$type}},$rule);
}
}
}
if (@{$email_rule{$type}}) {
$cancreate{'emailoptions'}{$type} = 'custom';
if (ref($curr_rule{$type}) eq 'ARRAY') {
if (@{$curr_rule{$type}} > 0) {
foreach my $rule (@{$curr_rule{$type}}) {
if (!grep(/^\Q$rule\E$/,@{$email_rule{$type}})) {
push(@{$changes{'email_rule'}},$type);
}
}
}
foreach my $type (@{$email_rule{$type}}) {
if (!grep(/^\Q$type\E$/,@{$curr_rule{$type}})) {
push(@{$changes{'email_rule'}},$type);
}
}
} else {
push(@{$changes{'email_rule'}},$type);
}
}
} else {
$cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type};
}
}
}
if (@types) {
if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {
my @changed = &Apache::loncommon::compare_arrays(\@statuses,$curr_inststatus{'inststatusguest'});
if (@changed) {
push(@{$changes{'inststatus'}},'inststatusguest');
}
} else {
push(@{$changes{'inststatus'}},'inststatusguest');
}
}
} else {
delete($env{'form.cancreate_email'});
if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {
if (@{$curr_inststatus{'inststatusguest'}} > 0) {
push(@{$changes{'inststatus'}},'inststatusguest');
}
}
}
} else {
$save_inststatus{'inststatusguest'} = [];
if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') {
if (@{$curr_inststatus{'inststatusguest'}} > 0) {
push(@{$changes{'inststatus'}},'inststatusguest');
}
}
}
} else {
if ($env{'form.cancreate_'.$item}) {
push(@{$cancreate{'selfcreate'}},$item);
}
}
}
my (%userinfo,%savecaptcha);
my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info();
#
# Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data
# value set to one), if self-creation with e-mail address permitted, where $type is user type: faculty, staff, student etc.
#
if ($env{'form.cancreate_email'}) {
push(@contexts,'emailusername');
if (@statuses) {
foreach my $type (@statuses) {
if (ref($infofields) eq 'ARRAY') {
foreach my $field (@{$infofields}) {
if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) {
$cancreate{'emailusername'}{$type}{$field} = $1;
}
}
}
}
}
#
# Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of
# queued requests for self-creation of account verified by e-mail.
#
my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval');
@approvalnotify = sort(@approvalnotify);
$cancreate{'notify'}{'approval'} = join(',',@approvalnotify);
if (ref($curr_usercreation{'cancreate'}) eq 'HASH') {
if (ref($curr_usercreation{'cancreate'}{'notify'}) eq 'HASH') {
if ($curr_usercreation{'cancreate'}{'notify'}{'approval'} ne $cancreate{'notify'}{'approval'}) {
push(@{$changes{'cancreate'}},'notify');
}
} else {
if ($cancreate{'notify'}{'approval'}) {
push(@{$changes{'cancreate'}},'notify');
}
}
} elsif ($cancreate{'notify'}{'approval'}) {
push(@{$changes{'cancreate'}},'notify');
}
&process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'});
}
#
# Check if domain default is set appropriately, if self-creation of accounts is to be available for
# institutional log-in.
#
if (grep(/^login$/,@{$cancreate{'selfcreate'}})) {
if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) ||
($domdefaults{'auth_def'} eq 'localauth'))) {
$warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.
&mt('You need to set the default authentication type to Kerberos 4 or 5 (with a Kerberos domain specified), or to Local authentication, if the localauth module has been customized in your domain to authenticate institutional logins.');
}
}
my @fields = ('lastname','firstname','middlename','generation',
'permanentemail','id');
my @shibfields = (@fields,'inststatus');
my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
#
# Where usernames may created for institutional log-in and/or institutional single sign on:
# (a) populate $cancreate{'statustocreate'} array reference with institutional status types who
# may self-create accounts
# (b) populate $save_usermodify{'selfcreate'} hash reference with status types, and information fields
# which the user may supply, if institutional data is unavailable.
#
if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) {
if (@types) {
@{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate');
push(@contexts,'statustocreate');
foreach my $type (@types) {
my @modifiable = &Apache::loncommon::get_env_multiple('form.canmodify_'.$type);
foreach my $field (@fields) {
if (grep(/^\Q$field\E$/,@modifiable)) {
$save_usermodify{'selfcreate'}{$type}{$field} = 1;
} else {
$save_usermodify{'selfcreate'}{$type}{$field} = 0;
}
}
}
if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') {
foreach my $type (@types) {
if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') {
foreach my $field (@fields) {
if ($save_usermodify{'selfcreate'}{$type}{$field} ne
$curr_usermodify{'selfcreate'}{$type}{$field}) {
push(@{$changes{'selfcreate'}},$type);
last;
}
}
}
}
} else {
foreach my $type (@types) {
push(@{$changes{'selfcreate'}},$type);
}
}
}
foreach my $field (@shibfields) {
if ($env{'form.shibenv_'.$field} ne '') {
$cancreate{'shibenv'}{$field} = $env{'form.shibenv_'.$field};
}
}
if (ref($curr_usercreation{'cancreate'}) eq 'HASH') {
if (ref($curr_usercreation{'cancreate'}{'shibenv'}) eq 'HASH') {
foreach my $field (@shibfields) {
if ($env{'form.shibenv_'.$field} ne $curr_usercreation{'cancreate'}{'shibenv'}{$field}) {
push(@{$changes{'cancreate'}},'shibenv');
}
}
} else {
foreach my $field (@shibfields) {
if ($env{'form.shibenv_'.$field}) {
push(@{$changes{'cancreate'}},'shibenv');
last;
}
}
}
}
}
foreach my $item (@contexts) {
if (ref($curr_usercreation{'cancreate'}{$item}) eq 'ARRAY') {
foreach my $curr (@{$curr_usercreation{'cancreate'}{$item}}) {
if (ref($cancreate{$item}) eq 'ARRAY') {
if (!grep(/^$curr$/,@{$cancreate{$item}})) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
}
if (ref($cancreate{$item}) eq 'ARRAY') {
foreach my $type (@{$cancreate{$item}}) {
if (!grep(/^$type$/,@{$curr_usercreation{'cancreate'}{$item}})) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
}
} elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') {
if (ref($cancreate{$item}) eq 'HASH') {
foreach my $type (keys(%{$curr_usercreation{'cancreate'}{$item}})) {
if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') {
foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$type}})) {
unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
} elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {
if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
}
foreach my $type (keys(%{$cancreate{$item}})) {
if (ref($cancreate{$item}{$type}) eq 'HASH') {
foreach my $field (keys(%{$cancreate{$item}{$type}})) {
if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') {
unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
} else {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
} elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {
if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
}
}
} elsif ($curr_usercreation{'cancreate'}{$item}) {
if (ref($cancreate{$item}) eq 'ARRAY') {
if (!grep(/^\Q$curr_usercreation{'cancreate'}{$item}\E$/,@{$cancreate{$item}})) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
}
} elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) {
if (ref($cancreate{$item}) eq 'HASH') {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
}
} elsif ($item eq 'emailusername') {
if (ref($cancreate{$item}) eq 'HASH') {
foreach my $type (keys(%{$cancreate{$item}})) {
if (ref($cancreate{$item}{$type}) eq 'HASH') {
foreach my $field (keys(%{$cancreate{$item}{$type}})) {
if ($cancreate{$item}{$type}{$field}) {
if (!grep(/^$item$/,@{$changes{'cancreate'}})) {
push(@{$changes{'cancreate'}},$item);
}
last;
}
}
}
}
}
}
}
#
# Populate %save_usercreate hash with updates to self-creation configuration.
#
$save_usercreate{'cancreate'}{'captcha'} = $savecaptcha{'captcha'};
$save_usercreate{'cancreate'}{'recaptchakeys'} = $savecaptcha{'recaptchakeys'};
$save_usercreate{'cancreate'}{'recaptchaversion'} = $savecaptcha{'recaptchaversion'};
$save_usercreate{'cancreate'}{'selfcreate'} = $cancreate{'selfcreate'};
if (ref($cancreate{'notify'}) eq 'HASH') {
$save_usercreate{'cancreate'}{'notify'} = $cancreate{'notify'};
}
if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') {
$save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'};
}
if (ref($cancreate{'emailverified'}) eq 'HASH') {
$save_usercreate{'cancreate'}{'emailverified'} = $cancreate{'emailverified'};
}
if (ref($cancreate{'emailoptions'}) eq 'HASH') {
$save_usercreate{'cancreate'}{'emailoptions'} = $cancreate{'emailoptions'};
}
if (ref($cancreate{'emaildomain'}) eq 'HASH') {
$save_usercreate{'cancreate'}{'emaildomain'} = $cancreate{'emaildomain'};
}
if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {
$save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'};
}
if (ref($cancreate{'shibenv'}) eq 'HASH') {
$save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'};
}
$save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'};
$save_usercreate{'email_rule'} = \%email_rule;
my %userconfig_hash = (
usercreation => \%save_usercreate,
usermodification => \%save_usermodify,
inststatus => \%save_inststatus,
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash,
$dom);
#
# Accumulate details of changes to domain configuration for self-creation of usernames in $resulttext
#
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made:').'<ul>';
if (ref($changes{'cancreate'}) eq 'ARRAY') {
my %lt = &selfcreation_types();
foreach my $type (@{$changes{'cancreate'}}) {
my $chgtext = '';
if ($type eq 'selfcreate') {
if (@{$cancreate{$type}} == 0) {
$chgtext .= &mt('Self creation of a new user account is not permitted.');
} else {
$chgtext .= &mt('Self-creation of a new account is permitted for:').
'<ul>';
foreach my $case (@{$cancreate{$type}}) {
$chgtext .= '<li>'.$selfcreatetypes{$case}.'</li>';
}
$chgtext .= '</ul>';
if (ref($cancreate{$type}) eq 'ARRAY') {
if (grep(/^(login|sso)$/,@{$cancreate{$type}})) {
if (ref($cancreate{'statustocreate'}) eq 'ARRAY') {
if (@{$cancreate{'statustocreate'}} == 0) {
$chgtext .= '<span class="LC_warning">'.
&mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts via log-in or single sign-on.").
'</span><br />';
}
}
}
if (grep(/^email$/,@{$cancreate{$type}})) {
if (!@statuses) {
$chgtext .= '<span class="LC_warning">'.
&mt("However, e-mail verification is currently set to 'unavailable' for all user types (including 'other'), so self-creation of accounts is not possible for non-institutional log-in.").
'</span><br />';
}
}
}
}
} elsif ($type eq 'shibenv') {
if (keys(%{$cancreate{$type}}) == 0) {
$chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information').'<br />';
} else {
$chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:').
'<ul>';
foreach my $field (@shibfields) {
next if ($cancreate{$type}{$field} eq '');
if ($field eq 'inststatus') {
$chgtext .= '<li>'.&mt('Institutional status').' -- '.$cancreate{$type}{$field}.'</li>';
} else {
$chgtext .= '<li>'.$fieldtitles{$field}.' -- '.$cancreate{$type}{$field}.'</li>';
}
}
$chgtext .= '</ul>';
}
} elsif ($type eq 'statustocreate') {
if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') &&
(ref($cancreate{'statustocreate'}) eq 'ARRAY')) {
if (@{$cancreate{'selfcreate'}} > 0) {
if (@{$cancreate{'statustocreate'}} == 0) {
$chgtext .= &mt("Institutional affiliations permitted to create accounts set to 'None'.");
if (!grep(/^email$/,@{$cancreate{'selfcreate'}})) {
$chgtext .= '<br />'.
'<span class="LC_warning">'.
&mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").
'</span>';
}
} elsif (keys(%usertypes) > 0) {
if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {
$chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):');
} else {
$chgtext .= &mt('Institutional affiliations permitted to create accounts with institutional authentication were set as follows:');
}
$chgtext .= '<ul>';
foreach my $case (@{$cancreate{$type}}) {
if ($case eq 'default') {
$chgtext .= '<li>'.$othertitle.'</li>';
} else {
$chgtext .= '<li>'.$usertypes{$case}.'</li>';
}
}
$chgtext .= '</ul>';
if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) {
$chgtext .= '<span class="LC_warning">'.
&mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.').
'</span>';
}
}
} else {
if (@{$cancreate{$type}} == 0) {
$chgtext .= &mt("Institutional affiliations permitted to create accounts were set to 'none'.");
} else {
$chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.');
}
}
$chgtext .= '<br />';
}
} elsif ($type eq 'selfcreateprocessing') {
my %choices = &Apache::lonlocal::texthash (
automatic => 'Automatic approval',
approval => 'Queued for approval',
);
if (@types) {
if (@statuses) {
$chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:').
'<ul>';
foreach my $status (@statuses) {
if ($status eq 'default') {
$chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>';
} else {
$chgtext .= '<li>'.$usertypes{$status}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>';
}
}
$chgtext .= '</ul>';
}
} else {
$chgtext .= &mt('Processing of requests to create account with e-mail verification set to: "[_1]"',
$choices{$cancreate{'selfcreateprocessing'}{'default'}});
}
} elsif ($type eq 'emailverified') {
my %options = &Apache::lonlocal::texthash (
all => 'Same as e-mail',
first => 'Omit @domain',
free => 'Free to choose',
);
if (@types) {
if (@statuses) {
$chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:').
'<ul>';
foreach my $status (@statuses) {
if ($status eq 'default') {
$chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
} else {
$chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>';
}
}
$chgtext .= '</ul>';
}
} else {
$chgtext .= &mt("For self-created accounts verified by e-mail address, user's username is: '[_1]'",
$options{$cancreate{'emailverified'}{'default'}});
}
} elsif ($type eq 'emailoptions') {
my %options = &Apache::lonlocal::texthash (
any => 'Any e-mail',
inst => 'Institutional only',
noninst => 'Non-institutional only',
custom => 'Custom restrictions',
);
if (@types) {
if (@statuses) {
$chgtext .= &mt('For self-created accounts verified by e-mail address, requirements for e-mail address are as follows:').
'<ul>';
foreach my $status (@statuses) {
if ($type eq 'default') {
$chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>';
} else {
$chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>';
}
}
$chgtext .= '</ul>';
}
} else {
if ($cancreate{'emailoptions'}{'default'} eq 'any') {
$chgtext .= &mt('For self-created accounts verified by e-mail address, any e-mail may be used');
} else {
$chgtext .= &mt('For self-created accounts verified by e-mail address, e-mail restricted to: "[_1]"',
$options{$cancreate{'emailoptions'}{'default'}});
}
}
} elsif ($type eq 'emaildomain') {
my $output;
if (@statuses) {
foreach my $type (@statuses) {
if (ref($cancreate{'emaildomain'}{$type}) eq 'HASH') {
if ($cancreate{'emailoptions'}{$type} eq 'inst') {
if ($type eq 'default') {
if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
($cancreate{'emaildomain'}{$type}{'inst'} eq '')) {
$output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>';
} else {
$output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address needs to end: [_1]",
$cancreate{'emaildomain'}{$type}{'inst'}).'</li>';
}
} else {
if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
($cancreate{'emaildomain'}{$type}{'inst'} eq '')) {
$output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
} else {
$output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]",
$cancreate{'emaildomain'}{$type}{'inst'}).'</li>';
}
}
} elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') {
if ($type eq 'default') {
if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) {
$output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>';
} else {
$output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address must not end: [_1]",
$cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';
}
} else {
if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') ||
($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) {
$output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>';
} else {
$output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]",
$cancreate{'emaildomain'}{$type}{'noninst'}).'</li>';
}
}
}
}
}
}
if ($output ne '') {
$chgtext .= &mt('For self-created accounts verified by e-mail address:').
'<ul>'.$output.'</ul>';
}
} elsif ($type eq 'captcha') {
if ($savecaptcha{$type} eq 'notused') {
$chgtext .= &mt('No CAPTCHA validation in use for self-creation screen.');
} else {
my %captchas = &captcha_phrases();
if ($captchas{$savecaptcha{$type}}) {
$chgtext .= &mt("Validation for self-creation screen set to $captchas{$savecaptcha{$type}}.");
} else {
$chgtext .= &mt('Validation for self-creation screen set to unknown type.');
}
}
} elsif ($type eq 'recaptchakeys') {
my ($privkey,$pubkey);
if (ref($savecaptcha{$type}) eq 'HASH') {
$pubkey = $savecaptcha{$type}{'public'};
$privkey = $savecaptcha{$type}{'private'};
}
$chgtext .= &mt('ReCAPTCHA keys changes').'<ul>';
if (!$pubkey) {
$chgtext .= '<li>'.&mt('Public key deleted').'</li>';
} else {
$chgtext .= '<li>'.&mt('Public key set to [_1]',$pubkey).'</li>';
}
if (!$privkey) {
$chgtext .= '<li>'.&mt('Private key deleted').'</li>';
} else {
$chgtext .= '<li>'.&mt('Private key set to [_1]',$pubkey).'</li>';
}
$chgtext .= '</ul>';
} elsif ($type eq 'recaptchaversion') {
if ($savecaptcha{'captcha'} eq 'recaptcha') {
$chgtext .= &mt('ReCAPTCHA set to version [_1]',$savecaptcha{$type});
}
} elsif ($type eq 'emailusername') {
if (ref($cancreate{'emailusername'}) eq 'HASH') {
if (@statuses) {
foreach my $type (@statuses) {
if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') {
if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) {
$chgtext .= &mt('When self-creating account with e-mail verification, the following information will be provided by [_1]:',"'$usertypes{$type}'").
'<ul>';
foreach my $field (@{$infofields}) {
if ($cancreate{'emailusername'}{$type}{$field}) {
$chgtext .= '<li>'.$infotitles->{$field}.'</li>';
}
}
$chgtext .= '</ul>';
} else {
$chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />';
}
} else {
$chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />';
}
}
}
}
} elsif ($type eq 'notify') {
my $numapprove = 0;
if (ref($changes{'cancreate'}) eq 'ARRAY') {
if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) {
if ($cancreate{'notify'}{'approval'}) {
$chgtext .= &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'};
$numapprove ++;
}
}
}
unless ($numapprove) {
$chgtext .= &mt('No Domain Coordinators will receive notification of username requests requiring approval.');
}
}
if ($chgtext) {
$resulttext .= '<li>'.$chgtext.'</li>';
}
}
}
if ((ref($changes{'email_rule'}) eq 'ARRAY') && (@{$changes{'email_rule'}} > 0)) {
my ($emailrules,$emailruleorder) =
&Apache::lonnet::inst_userrules($dom,'email');
foreach my $type (@{$changes{'email_rule'}}) {
if (ref($email_rule{$type}) eq 'ARRAY') {
my $chgtext = '<ul>';
foreach my $rule (@{$email_rule{$type}}) {
if (ref($emailrules->{$rule}) eq 'HASH') {
$chgtext .= '<li>'.$emailrules->{$rule}{'name'}.'</li>';
}
}
$chgtext .= '</ul>';
my $typename;
if (@types) {
if ($type eq 'default') {
$typename = $othertitle;
} else {
$typename = $usertypes{$type};
}
$chgtext .= &mt('(Affiliation: [_1])',$typename);
}
if (@{$email_rule{$type}} > 0) {
$resulttext .= '<li>'.
&mt('Accounts may not be created by users verified by e-mail, for e-mail addresses of the following types: ',
$usertypes{$type}).
$chgtext.
'</li>';
} else {
$resulttext .= '<li>'.
&mt('There are now no restrictions on e-mail addresses which may be used for verification when a user requests an account.').
'</li>'.
&mt('(Affiliation: [_1])',$typename);
}
}
}
}
if (ref($changes{'inststatus'}) eq 'ARRAY') {
if (ref($save_inststatus{'inststatusguest'}) eq 'ARRAY') {
if (@{$save_inststatus{'inststatusguest'}} > 0) {
my $chgtext = '<ul>';
foreach my $type (@{$save_inststatus{'inststatusguest'}}) {
$chgtext .= '<li>'.$usertypes{$type}.'</li>';
}
$chgtext .= '</ul>';
$resulttext .= '<li>'.
&mt('A user will self-report one of the following affiliations when requesting an account verified by e-mail: ').
$chgtext.
'</li>';
} else {
$resulttext .= '<li>'.
&mt('No affiliations available for self-reporting when requesting an account verified by e-mail.').
'</li>';
}
}
}
if (ref($changes{'selfcreate'}) eq 'ARRAY') {
$resulttext .= '<li>'.&mt('When self-creating institutional account:').'<ul>';
my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
foreach my $type (@{$changes{'selfcreate'}}) {
my $typename = $type;
if (keys(%usertypes) > 0) {
if ($usertypes{$type} ne '') {
$typename = $usertypes{$type};
}
}
my @modifiable;
$resulttext .= '<li>'.
&mt('Self-creation of account by users with status: [_1]',
'<span class="LC_cusr_emph">'.$typename.'</span>').
' - '.&mt('modifiable fields (if institutional data blank): ');
foreach my $field (@fields) {
if ($save_usermodify{'selfcreate'}{$type}{$field}) {
push(@modifiable,'<b>'.$fieldtitles{$field}.'</b>');
}
}
if (@modifiable > 0) {
$resulttext .= join(', ',@modifiable);
} else {
$resulttext .= &mt('none');
}
$resulttext .= '</li>';
}
$resulttext .= '</ul></li>';
}
$resulttext .= '</ul>';
my $cachetime = 24*60*60;
$domdefaults{'inststatusguest'} = $save_inststatus{'inststatusguest'};
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
} else {
$resulttext = &mt('No changes made to self-creation settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if ($warningmsg ne '') {
$resulttext .= '<br /><span class="LC_warning">'.$warningmsg.'</span><br />';
}
return $resulttext;
}
sub process_captcha {
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';
}
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;
}
}
my ($newpub,$newpriv,$currpub,$currpriv,$newversion,$currversion);
if ($newsettings->{'captcha'} eq 'recaptcha') {
$newpub = $env{'form.'.$container.'_recaptchapub'};
$newpriv = $env{'form.'.$container.'_recaptchapriv'};
$newpub =~ s/[^\w\-]//g;
$newpriv =~ s/[^\w\-]//g;
$newsettings->{'recaptchakeys'} = {
public => $newpub,
private => $newpriv,
};
$newversion = $env{'form.'.$container.'_recaptchaversion'};
$newversion =~ s/\D//g;
if ($newversion ne '2') {
$newversion = 1;
}
$newsettings->{'recaptchaversion'} = $newversion;
}
if (ref($current{'recaptchakeys'}) eq 'HASH') {
$currpub = $current{'recaptchakeys'}{'public'};
$currpriv = $current{'recaptchakeys'}{'private'};
unless ($newsettings->{'captcha'} eq 'recaptcha') {
$newsettings->{'recaptchakeys'} = {
public => '',
private => '',
}
}
}
if ($current{'captcha'} eq 'recaptcha') {
$currversion = $current{'recaptchaversion'};
if ($currversion ne '2') {
$currversion = 1;
}
}
if ($currversion ne $newversion) {
if ($container eq 'cancreate') {
if (ref($changes->{'cancreate'}) eq 'ARRAY') {
push(@{$changes->{'cancreate'}},'recaptchaversion');
} elsif (!defined($changes->{'cancreate'})) {
$changes->{'cancreate'} = ['recaptchaversion'];
}
} elsif ($container eq 'passwords') {
$changes->{'reset'} = 1;
} else {
$changes->{'recaptchaversion'} = 1;
}
}
if (($newpub ne $currpub) || ($newpriv ne $currpriv)) {
if ($container eq 'cancreate') {
if (ref($changes->{'cancreate'}) eq 'ARRAY') {
push(@{$changes->{'cancreate'}},'recaptchakeys');
} elsif (!defined($changes->{'cancreate'})) {
$changes->{'cancreate'} = ['recaptchakeys'];
}
} elsif ($container eq 'passwords') {
$changes->{'reset'} = 1;
} else {
$changes->{'recaptchakeys'} = 1;
}
}
return;
}
sub modify_usermodification {
my ($dom,%domconfig) = @_;
my ($resulttext,%curr_usermodification,%changes,%modifyhash);
if (ref($domconfig{'usermodification'}) eq 'HASH') {
foreach my $key (keys(%{$domconfig{'usermodification'}})) {
if ($key eq 'selfcreate') {
$modifyhash{$key} = $domconfig{'usermodification'}{$key};
} else {
$curr_usermodification{$key} = $domconfig{'usermodification'}{$key};
}
}
}
my @contexts = ('author','coauthor','course');
my %context_title = (
author => 'In author context',
coauthor => 'As co-author manager',
course => 'In course context',
);
my @fields = ('lastname','firstname','middlename','generation',
'permanentemail','id');
my %roles = (
author => ['ca','aa'],
coauthor => ['ca','aa'],
course => ['st','ep','ta','in','cr'],
);
my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
foreach my $context (@contexts) {
my $prefix = 'canmodify';
if ($context eq 'coauthor') {
$prefix = 'cacanmodify';
}
foreach my $role (@{$roles{$context}}) {
my @modifiable = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$role);
foreach my $item (@fields) {
if (grep(/^\Q$item\E$/,@modifiable)) {
$modifyhash{$context}{$role}{$item} = 1;
} else {
$modifyhash{$context}{$role}{$item} = 0;
}
}
}
if (ref($curr_usermodification{$context}) eq 'HASH') {
foreach my $role (@{$roles{$context}}) {
if (ref($curr_usermodification{$context}{$role}) eq 'HASH') {
foreach my $field (@fields) {
if ($modifyhash{$context}{$role}{$field} ne
$curr_usermodification{$context}{$role}{$field}) {
push(@{$changes{$context}},$role);
last;
}
}
}
}
} else {
foreach my $context (@contexts) {
foreach my $role (@{$roles{$context}}) {
push(@{$changes{$context}},$role);
}
}
}
}
my %usermodification_hash = (
usermodification => \%modifyhash,
);
my $putresult = &Apache::lonnet::put_dom('configuration',
\%usermodification_hash,$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made: ').'<ul>';
foreach my $context (@contexts) {
if (ref($changes{$context}) eq 'ARRAY') {
$resulttext .= '<li>'.$context_title{$context}.':<ul>';
if (ref($changes{$context}) eq 'ARRAY') {
foreach my $role (@{$changes{$context}}) {
my $rolename;
if ($role eq 'cr') {
$rolename = &mt('Custom');
} else {
$rolename = &Apache::lonnet::plaintext($role);
}
my @modifiable;
$resulttext .= '<li><span class="LC_cusr_emph">'.&mt('Target user with [_1] role',$rolename).'</span> - '.&mt('modifiable fields: ');
foreach my $field (@fields) {
if ($modifyhash{$context}{$role}{$field}) {
push(@modifiable,$fieldtitles{$field});
}
}
if (@modifiable > 0) {
$resulttext .= join(', ',@modifiable);
} else {
$resulttext .= &mt('none');
}
$resulttext .= '</li>';
}
$resulttext .= '</ul></li>';
}
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to user modification settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_defaults {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',
'portal_def');
my @authtypes = ('internal','krb4','krb5','localauth','lti');
foreach my $item (@items) {
$newvalues{$item} = $env{'form.'.$item};
if ($item eq 'auth_def') {
if ($newvalues{$item} ne '') {
if (!grep(/^\Q$newvalues{$item}\E$/,@authtypes)) {
push(@errors,$item);
}
}
} elsif ($item eq 'lang_def') {
if ($newvalues{$item} ne '') {
if ($newvalues{$item} =~ /^(\w+)/) {
my $langcode = $1;
if ($langcode ne 'x_chef') {
if (code2language($langcode) eq '') {
push(@errors,$item);
}
}
} else {
push(@errors,$item);
}
}
} elsif ($item eq 'timezone_def') {
if ($newvalues{$item} ne '') {
if (!DateTime::TimeZone->is_valid_name($newvalues{$item})) {
push(@errors,$item);
}
}
} elsif ($item eq 'datelocale_def') {
if ($newvalues{$item} ne '') {
my @datelocale_ids = DateTime::Locale->ids();
if (!grep(/^\Q$newvalues{$item}\E$/,@datelocale_ids)) {
push(@errors,$item);
}
}
} elsif ($item eq 'portal_def') {
if ($newvalues{$item} ne '') {
if ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) {
foreach my $field ('email','web') {
if ($env{'form.'.$item.'_'.$field}) {
$newvalues{$item.'_'.$field} = $env{'form.'.$item.'_'.$field};
}
}
} else {
push(@errors,$item);
}
}
}
if (grep(/^\Q$item\E$/,@errors)) {
$newvalues{$item} = $domdefaults{$item};
if ($item eq 'portal_def') {
if ($domdefaults{$item}) {
foreach my $field ('email','web') {
if (exists($domdefaults{$item.'_'.$field})) {
$newvalues{$item.'_'.$field} = $domdefaults{$item.'_'.$field};
}
}
}
}
} elsif ($domdefaults{$item} ne $newvalues{$item}) {
$changes{$item} = 1;
}
if ($item eq 'portal_def') {
unless (grep(/^\Q$item\E$/,@errors)) {
if ($newvalues{$item} eq '') {
foreach my $field ('email','web') {
if (exists($domdefaults{$item.'_'.$field})) {
delete($domdefaults{$item.'_'.$field});
}
}
} else {
unless ($changes{$item}) {
foreach my $field ('email','web') {
if ($domdefaults{$item.'_'.$field} ne $newvalues{$item.'_'.$field}) {
$changes{$item} = 1;
last;
}
}
}
foreach my $field ('email','web') {
if ($newvalues{$item.'_'.$field}) {
$domdefaults{$item.'_'.$field} = $newvalues{$item.'_'.$field};
} elsif (exists($domdefaults{$item.'_'.$field})) {
delete($domdefaults{$item.'_'.$field});
}
}
}
}
}
$domdefaults{$item} = $newvalues{$item};
}
my %staticdefaults = (
'intauth_cost' => 10,
'intauth_check' => 0,
'intauth_switch' => 0,
);
foreach my $item ('intauth_cost','intauth_check','intauth_switch') {
if (exists($domdefaults{$item})) {
$newvalues{$item} = $domdefaults{$item};
} else {
$newvalues{$item} = $staticdefaults{$item};
}
}
my ($unamemaprules,$ruleorder);
my @possunamemaprules = &Apache::loncommon::get_env_multiple('form.unamemap_rule');
if (@possunamemaprules) {
($unamemaprules,$ruleorder) =
&Apache::lonnet::inst_userrules($dom,'unamemap');
if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
if (@{$ruleorder} > 0) {
my %possrules;
map { $possrules{$_} = 1; } @possunamemaprules;
foreach my $rule (@{$ruleorder}) {
if ($possrules{$rule}) {
push(@{$newvalues{'unamemap_rule'}},$rule);
}
}
}
}
}
if (ref($domdefaults{'unamemap_rule'}) eq 'ARRAY') {
if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {
my @rulediffs = &Apache::loncommon::compare_arrays($domdefaults{'unamemap_rule'},
$newvalues{'unamemap_rule'});
if (@rulediffs) {
$changes{'unamemap_rule'} = 1;
$domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};
}
} elsif (@{$domdefaults{'unamemap_rule'}} > 0) {
$changes{'unamemap_rule'} = 1;
delete($domdefaults{'unamemap_rule'});
}
} elsif (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {
if (@{$newvalues{'unamemap_rule'}} > 0) {
$changes{'unamemap_rule'} = 1;
$domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'};
}
}
my %defaults_hash = (
defaults => \%newvalues,
);
my $title = &defaults_titles();
my $currinststatus;
if (ref($domconfig{'inststatus'}) eq 'HASH') {
$currinststatus = $domconfig{'inststatus'};
} else {
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
$currinststatus = {
inststatustypes => $usertypes,
inststatusorder => $types,
inststatusguest => [],
};
}
my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete');
my @allpos;
my %alltypes;
my @inststatusguest;
if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {
foreach my $type (@{$currinststatus->{'inststatusguest'}}) {
unless (grep(/^\Q$type\E$/,@todelete)) {
push(@inststatusguest,$type);
}
}
}
my ($currtitles,$currorder);
if (ref($currinststatus) eq 'HASH') {
if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') {
foreach my $type (@{$currinststatus->{'inststatusorder'}}) {
if (ref($currinststatus->{inststatustypes}) eq 'HASH') {
if ($currinststatus->{inststatustypes}->{$type} ne '') {
$currtitles .= $currinststatus->{inststatustypes}->{$type}.',';
}
}
unless (grep(/^\Q$type\E$/,@todelete)) {
my $position = $env{'form.inststatus_pos_'.$type};
$position =~ s/\D+//g;
$allpos[$position] = $type;
$alltypes{$type} = $env{'form.inststatus_title_'.$type};
$alltypes{$type} =~ s/`//g;
}
}
$currorder = join(',',@{$currinststatus->{'inststatusorder'}});
$currtitles =~ s/,$//;
}
}
if ($env{'form.addinststatus'}) {
my $newtype = $env{'form.addinststatus'};
$newtype =~ s/\W//g;
unless (exists($alltypes{$newtype})) {
$alltypes{$newtype} = $env{'form.addinststatus_title'};
$alltypes{$newtype} =~ s/`//g;
my $position = $env{'form.addinststatus_pos'};
$position =~ s/\D+//g;
if ($position ne '') {
$allpos[$position] = $newtype;
}
}
}
my @orderedstatus;
foreach my $type (@allpos) {
unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) {
push(@orderedstatus,$type);
}
}
foreach my $type (keys(%alltypes)) {
unless (grep(/^\Q$type\E$/,@orderedstatus)) {
delete($alltypes{$type});
}
}
$defaults_hash{'inststatus'} = {
inststatustypes => \%alltypes,
inststatusorder => \@orderedstatus,
inststatusguest => \@inststatusguest,
};
if (ref($defaults_hash{'inststatus'}) eq 'HASH') {
foreach my $item ('inststatustypes','inststatusorder','inststatusguest') {
$domdefaults{$item} = $defaults_hash{'inststatus'}{$item};
}
}
if ($currorder ne join(',',@orderedstatus)) {
$changes{'inststatus'}{'inststatusorder'} = 1;
}
my $newtitles;
foreach my $item (@orderedstatus) {
$newtitles .= $alltypes{$item}.',';
}
$newtitles =~ s/,$//;
if ($currtitles ne $newtitles) {
$changes{'inststatus'}{'inststatustypes'} = 1;
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaults_hash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
$resulttext = &mt('Changes made:').'<ul>';
my $version = &Apache::lonnet::get_server_loncaparev($dom);
my $mailmsgtext = "Changes made to domain settings in a LON-CAPA installation - domain: $dom (running version: $version) - dns_domain.tab needs to be updated with the following changes, to support legacy 2.4, 2.5 and 2.6 versions of LON-CAPA.\n\n";
foreach my $item (sort(keys(%changes))) {
if ($item eq 'inststatus') {
if (ref($changes{'inststatus'}) eq 'HASH') {
if (@orderedstatus) {
$resulttext .= '<li>'.&mt('Institutional user status types set to:').' ';
foreach my $type (@orderedstatus) {
$resulttext .= $alltypes{$type}.', ';
}
$resulttext =~ s/, $//;
$resulttext .= '</li>';
} else {
$resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>';
}
}
} elsif ($item eq 'unamemap_rule') {
if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') {
my @rulenames;
if (ref($unamemaprules) eq 'HASH') {
foreach my $rule (@{$newvalues{'unamemap_rule'}}) {
if (ref($unamemaprules->{$rule}) eq 'HASH') {
push(@rulenames,$unamemaprules->{$rule}->{'name'});
}
}
}
if (@rulenames) {
$resulttext .= '<li>'.&mt('Mapping for missing usernames includes: [_1]',
'<ul><li>'.join('</li><li>',@rulenames).'</li></ul>').
'</li>';
} else {
$resulttext .= '<li>'.&mt('No mapping for missing usernames via standard log-in').'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Mapping for missing usernames via standard log-in deleted').'</li>';
}
} else {
my $value = $env{'form.'.$item};
if ($value eq '') {
$value = &mt('none');
} elsif ($item eq 'auth_def') {
my %authnames = &authtype_names();
my %shortauth = (
internal => 'int',
krb4 => 'krb4',
krb5 => 'krb5',
localauth => 'loc',
lti => 'lti',
);
$value = $authnames{$shortauth{$value}};
}
$resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';
$mailmsgtext .= "$title->{$item} set to $value\n";
if ($item eq 'portal_def') {
if ($env{'form.'.$item} ne '') {
foreach my $field ('email','web') {
$value = $env{'form.'.$item.'_'.$field};
if ($value) {
$value = &mt('Yes');
} else {
$value = &mt('No');
}
$resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'</li>';
}
}
}
}
}
$resulttext .= '</ul>';
$mailmsgtext .= "\n";
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
if ($changes{'auth_def'} || $changes{'auth_arg_def'} || $changes{'lang_def'} || $changes{'datelocale_def'}) {
my $notify = 1;
if (ref($domconfig{'contacts'}) eq 'HASH') {
if ($domconfig{'contacts'}{'reportupdates'} == 0) {
$notify = 0;
}
}
if ($notify) {
&Apache::lonmsg::sendemail('installrecord@loncapa.org',
"LON-CAPA Domain Settings Change - $dom",
$mailmsgtext);
}
}
} else {
$resulttext = &mt('No changes made to default authentication/language/timezone settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
if (@errors > 0) {
$resulttext .= '<br />'.&mt('The following were left unchanged because the values entered were invalid:');
foreach my $item (@errors) {
$resulttext .= ' "'.$title->{$item}.'",';
}
$resulttext =~ s/,$//;
}
return $resulttext;
}
sub modify_scantron {
my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
my ($resulttext,%confhash,%changes,$errors);
my $custom = 'custom.tab';
my $default = 'default.tab';
my $servadm = $r->dir_config('lonAdmEMail');
my ($configuserok,$author_ok,$switchserver) =
&config_check($dom,$confname,$servadm);
if ($env{'form.scantronformat.filename'} ne '') {
my $error;
if ($configuserok eq 'ok') {
if ($switchserver) {
$error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);
} else {
if ($author_ok eq 'ok') {
my $modified = [];
my ($result,$scantronurl) =
&Apache::lonconfigsettings::publishlogo($r,'upload','scantronformat',$dom,
$confname,'scantron','','',$custom,
$modified);
if ($result eq 'ok') {
$confhash{'scantron'}{'scantronformat'} = $scantronurl;
$changes{'scantronformat'} = 1;
&update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);
}
} else {
$error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$custom,$confname,$dom,$author_ok);
}
}
} else {
$error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$custom,$confname,$dom,$configuserok);
}
if ($error) {
&Apache::lonnet::logthis($error);
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
if (ref($domconfig{'scantron'}) eq 'HASH') {
if ($domconfig{'scantron'}{'scantronformat'} ne '') {
if ($env{'form.scantronformat_del'}) {
$confhash{'scantron'}{'scantronformat'} = '';
$changes{'scantronformat'} = 1;
} else {
$confhash{'scantron'}{'scantronformat'} = $domconfig{'scantron'}{'scantronformat'};
}
}
}
my @options = ('hdr','pad','rem');
my @fields = &scantroncsv_fields();
my %titles = &scantronconfig_titles();
my @formats = &Apache::loncommon::get_env_multiple('form.scantronconfig');
my ($newdat,$currdat,%newcol,%currcol);
if (grep(/^dat$/,@formats)) {
$confhash{'scantron'}{config}{dat} = 1;
$newdat = 1;
} else {
$newdat = 0;
}
if (grep(/^csv$/,@formats)) {
my %bynum;
foreach my $field (@fields) {
if ($env{'form.scantronconfig_csv_'.$field} =~ /^(\d+)$/) {
my $posscol = $1;
if (($posscol < 20) && (!$bynum{$posscol})) {
$confhash{'scantron'}{config}{csv}{fields}{$field} = $posscol;
$bynum{$posscol} = $field;
$newcol{$field} = $posscol;
}
}
}
if (keys(%newcol)) {
foreach my $option (@options) {
if ($env{'form.scantroncsv_'.$option}) {
$confhash{'scantron'}{config}{csv}{options}{$option} = 1;
}
}
}
}
$currdat = 1;
if (ref($domconfig{'scantron'}) eq 'HASH') {
if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
unless (exists($domconfig{'scantron'}{'config'}{'dat'})) {
$currdat = 0;
}
if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') {
%currcol = %{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}};
}
}
}
}
if ($currdat != $newdat) {
$changes{'config'} = 1;
} else {
foreach my $field (@fields) {
if ($currcol{$field} ne '') {
if ($currcol{$field} ne $newcol{$field}) {
$changes{'config'} = 1;
last;
}
} elsif ($newcol{$field} ne '') {
$changes{'config'} = 1;
last;
}
}
}
if (keys(%confhash) > 0) {
my $putresult = &Apache::lonnet::put_dom('configuration',\%confhash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
if (ref($confhash{'scantron'}) eq 'HASH') {
$resulttext = &mt('Changes made:').'<ul>';
if ($changes{'scantronformat'}) {
if ($confhash{'scantron'}{'scantronformat'} eq '') {
$resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';
} else {
$resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';
}
}
if ($changes{'config'}) {
if (ref($confhash{'scantron'}{'config'}) eq 'HASH') {
if ($confhash{'scantron'}{'config'}{'dat'}) {
$resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .dat format').'</li>';
}
if (ref($confhash{'scantron'}{'config'}{'csv'}) eq 'HASH') {
if (ref($confhash{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') {
if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'fields'}})) {
$resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following fields/column numbers supported:').'<ul>';
foreach my $field (@fields) {
if ($confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} ne '') {
my $showcol = $confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} + 1;
$resulttext .= '<li>'.$titles{$field}.': '.$showcol.'</li>';
}
}
$resulttext .= '</ul></li>';
if (ref($confhash{'scantron'}{'config'}{'csv'}{'options'}) eq 'HASH') {
if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'options'}})) {
$resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following options:').'<ul>';
foreach my $option (@options) {
if ($confhash{'scantron'}{'config'}{'csv'}{'options'}{$option} ne '') {
$resulttext .= '<li>'.$titles{$option}.'</li>';
}
}
$resulttext .= '</ul></li>';
}
}
}
}
}
} else {
$resulttext .= '<li>'.&mt('No bubblesheet data upload formats set -- will default to assuming .dat format').'</li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('Changes made to bubblesheet format file.');
}
&Apache::loncommon::devalidate_domconfig_cache($dom);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
} else {
$resulttext = &mt('No changes made to bubblesheet format settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} else {
$resulttext = &mt('No changes made to bubblesheet format file');
}
if ($errors) {
$resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul></p>';
}
return $resulttext;
}
sub modify_coursecategories {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,%deletions,%reorderings,%needreordering,%adds,%changes,$errors,
$cathash);
my @deletecategory = &Apache::loncommon::get_env_multiple('form.deletecategory');
my @catitems = ('unauth','auth');
my @cattypes = ('std','domonly','codesrch','none');
if (ref($domconfig{'coursecategories'}) eq 'HASH') {
$cathash = $domconfig{'coursecategories'}{'cats'};
if ($domconfig{'coursecategories'}{'togglecats'} ne $env{'form.togglecats'}) {
$changes{'togglecats'} = 1;
$domconfig{'coursecategories'}{'togglecats'} = $env{'form.togglecats'};
}
if ($domconfig{'coursecategories'}{'categorize'} ne $env{'form.categorize'}) {
$changes{'categorize'} = 1;
$domconfig{'coursecategories'}{'categorize'} = $env{'form.categorize'};
}
if ($domconfig{'coursecategories'}{'togglecatscomm'} ne $env{'form.togglecatscomm'}) {
$changes{'togglecatscomm'} = 1;
$domconfig{'coursecategories'}{'togglecatscomm'} = $env{'form.togglecatscomm'};
}
if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {
$changes{'categorizecomm'} = 1;
$domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};
}
if ($domconfig{'coursecategories'}{'togglecatsplace'} ne $env{'form.togglecatsplace'}) {
$changes{'togglecatsplace'} = 1;
$domconfig{'coursecategories'}{'togglecatsplace'} = $env{'form.togglecatsplace'};
}
if ($domconfig{'coursecategories'}{'categorizeplace'} ne $env{'form.categorizeplace'}) {
$changes{'categorizeplace'} = 1;
$domconfig{'coursecategories'}{'categorizeplace'} = $env{'form.categorizeplace'};
}
foreach my $item (@catitems) {
if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {
if ($domconfig{'coursecategories'}{$item} ne $env{'form.coursecat_'.$item}) {
$changes{$item} = 1;
$domconfig{'coursecategories'}{$item} = $env{'form.coursecat_'.$item};
}
}
}
} else {
$changes{'togglecats'} = 1;
$changes{'categorize'} = 1;
$changes{'togglecatscomm'} = 1;
$changes{'categorizecomm'} = 1;
$changes{'togglecatsplace'} = 1;
$changes{'categorizeplace'} = 1;
$domconfig{'coursecategories'} = {
togglecats => $env{'form.togglecats'},
categorize => $env{'form.categorize'},
togglecatscomm => $env{'form.togglecatscomm'},
categorizecomm => $env{'form.categorizecomm'},
togglecatsplace => $env{'form.togglecatsplace'},
categorizeplace => $env{'form.categorizeplace'},
};
foreach my $item (@catitems) {
if ($env{'form.coursecat_'.$item} ne 'std') {
$changes{$item} = 1;
}
if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {
$domconfig{'coursecategories'}{$item} = $env{'form.coursecat_'.$item};
}
}
}
if (ref($cathash) eq 'HASH') {
if (($domconfig{'coursecategories'}{'cats'}{'instcode::0'} ne '') && ($env{'form.instcode'} == 0)) {
push (@deletecategory,'instcode::0');
}
if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '') && ($env{'form.communities'} == 0)) {
push(@deletecategory,'communities::0');
}
if (($domconfig{'coursecategories'}{'cats'}{'placement::0'} ne '') && ($env{'form.placement'} == 0)) {
push(@deletecategory,'placement::0');
}
}
my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);
if (ref($cathash) eq 'HASH') {
if (@deletecategory > 0) {
#FIXME Need to remove category from all courses using a deleted category
&Apache::loncommon::extract_categories($cathash,\@predelcats,\@predeltrails,\%predelallitems);
foreach my $item (@deletecategory) {
if ($domconfig{'coursecategories'}{'cats'}{$item} ne '') {
delete($domconfig{'coursecategories'}{'cats'}{$item});
$deletions{$item} = 1;
&recurse_cat_deletes($item,$cathash,\%deletions);
}
}
}
foreach my $item (keys(%{$cathash})) {
my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
if ($cathash->{$item} ne $env{'form.'.$item}) {
$reorderings{$item} = 1;
$domconfig{'coursecategories'}{'cats'}{$item} = $env{'form.'.$item};
}
if ($env{'form.addcategory_name_'.$item} ne '') {
my $newcat = $env{'form.addcategory_name_'.$item};
my $newdepth = $depth+1;
my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth;
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos_'.$item};
$adds{$newitem} = 1;
}
if ($env{'form.subcat_'.$item} ne '') {
my $newcat = $env{'form.subcat_'.$item};
my $newdepth = $depth+1;
my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth;
$domconfig{'coursecategories'}{'cats'}{$newitem} = 0;
$adds{$newitem} = 1;
}
}
}
if ($env{'form.instcode'} eq '1') {
if (ref($cathash) eq 'HASH') {
my $newitem = 'instcode::0';
if ($cathash->{$newitem} eq '') {
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'};
$adds{$newitem} = 1;
}
} else {
my $newitem = 'instcode::0';
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'};
$adds{$newitem} = 1;
}
}
if ($env{'form.communities'} eq '1') {
if (ref($cathash) eq 'HASH') {
my $newitem = 'communities::0';
if ($cathash->{$newitem} eq '') {
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.communities_pos'};
$adds{$newitem} = 1;
}
} else {
my $newitem = 'communities::0';
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.communities_pos'};
$adds{$newitem} = 1;
}
}
if ($env{'form.placement'} eq '1') {
if (ref($cathash) eq 'HASH') {
my $newitem = 'placement::0';
if ($cathash->{$newitem} eq '') {
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
$adds{$newitem} = 1;
}
} else {
my $newitem = 'placement::0';
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
$adds{$newitem} = 1;
}
}
if ($env{'form.addcategory_name'} ne '') {
if (($env{'form.addcategory_name'} ne 'instcode') &&
($env{'form.addcategory_name'} ne 'communities') &&
($env{'form.addcategory_name'} ne 'placement')) {
my $newitem = &escape($env{'form.addcategory_name'}).'::0';
$domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};
$adds{$newitem} = 1;
}
}
my $putresult;
if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) {
if (keys(%deletions) > 0) {
foreach my $key (keys(%deletions)) {
if ($predelallitems{$key} ne '') {
$sort_by_deltrail{$predelallitems{$key}} = $predeltrails[$predelallitems{$key}];
}
}
}
my (@chkcats,@chktrails,%chkallitems);
&Apache::loncommon::extract_categories($domconfig{'coursecategories'}{'cats'},\@chkcats,\@chktrails,\%chkallitems);
if (ref($chkcats[0]) eq 'ARRAY') {
my $depth = 0;
my $chg = 0;
for (my $i=0; $i<@{$chkcats[0]}; $i++) {
my $name = $chkcats[0][$i];
my $item;
if ($name eq '') {
$chg ++;
} else {
$item = &escape($name).'::0';
if ($chg) {
$domconfig{'coursecategories'}{'cats'}{$item} -= $chg;
}
$depth ++;
&recurse_check(\@chkcats,$domconfig{'coursecategories'}{'cats'},$depth,$name);
$depth --;
}
}
}
}
if ((keys(%changes) > 0) || (keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) {
$putresult = &Apache::lonnet::put_dom('configuration',\%domconfig,$dom);
if ($putresult eq 'ok') {
my %title = (
togglecats => 'Show/Hide a course in catalog',
categorize => 'Assign a category to a course',
togglecatscomm => 'Show/Hide a community in catalog',
categorizecomm => 'Assign a category to a community',
);
my %level = (
dom => 'set in Domain ("Modify Course/Community")',
crs => 'set in Course ("Course Configuration")',
comm => 'set in Community ("Community Configuration")',
none => 'No catalog',
std => 'Standard catalog',
domonly => 'Domain-only catalog',
codesrch => 'Code search form',
);
$resulttext = &mt('Changes made:').'<ul>';
if ($changes{'togglecats'}) {
$resulttext .= '<li>'.&mt("$title{'togglecats'} $level{$env{'form.togglecats'}}").'</li>';
}
if ($changes{'categorize'}) {
$resulttext .= '<li>'.&mt("$title{'categorize'} $level{$env{'form.categorize'}}").'</li>';
}
if ($changes{'togglecatscomm'}) {
$resulttext .= '<li>'.&mt("$title{'togglecatscomm'} $level{$env{'form.togglecatscomm'}}").'</li>';
}
if ($changes{'categorizecomm'}) {
$resulttext .= '<li>'.&mt("$title{'categorizecomm'} $level{$env{'form.categorizecomm'}}").'</li>';
}
if ($changes{'unauth'}) {
$resulttext .= '<li>'.&mt('Catalog type for unauthenticated users set to "'.$level{$env{'form.coursecat_unauth'}}.'"').'</li>';
}
if ($changes{'auth'}) {
$resulttext .= '<li>'.&mt('Catalog type for authenticated users set to "'.$level{$env{'form.coursecat_auth'}}.'"').'</li>';
}
if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) {
my $cathash;
if (ref($domconfig{'coursecategories'}) eq 'HASH') {
$cathash = $domconfig{'coursecategories'}{'cats'};
} else {
$cathash = {};
}
my (@cats,@trails,%allitems);
&Apache::loncommon::extract_categories($cathash,\@cats,\@trails,\%allitems);
if (keys(%deletions) > 0) {
$resulttext .= '<li>'.&mt('Deleted categories:').'<ul>';
foreach my $predeltrail (sort {$a <=> $b } (keys(%sort_by_deltrail))) {
$resulttext .= '<li>'.$predeltrails[$predeltrail].'</li>';
}
$resulttext .= '</ul></li>';
}
if (keys(%reorderings) > 0) {
my %sort_by_trail;
$resulttext .= '<li>'.&mt('Reordered categories:').'<ul>';
foreach my $key (keys(%reorderings)) {
if ($allitems{$key} ne '') {
$sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}];
}
}
foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) {
$resulttext .= '<li>'.$trails[$trail].'</li>';
}
$resulttext .= '</ul></li>';
}
if (keys(%adds) > 0) {
my %sort_by_trail;
$resulttext .= '<li>'.&mt('Added categories:').'<ul>';
foreach my $key (keys(%adds)) {
if ($allitems{$key} ne '') {
$sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}];
}
}
foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) {
$resulttext .= '<li>'.$trails[$trail].'</li>';
}
$resulttext .= '</ul></li>';
}
&Apache::lonnet::do_cache_new('cats',$dom,$cathash,3600);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'cats'} = 1;
}
}
$resulttext .= '</ul>';
if ($changes{'unauth'} || $changes{'auth'}) {
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
if ($changes{'auth'}) {
$domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'};
}
if ($changes{'unauth'}) {
$domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'};
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} else {
$resulttext = &mt('No changes made to course and community categories');
}
return $resulttext;
}
sub modify_serverstatuses {
my ($dom,%domconfig) = @_;
my ($resulttext,%changes,%currserverstatus,%newserverstatus);
if (ref($domconfig{'serverstatuses'}) eq 'HASH') {
%currserverstatus = %{$domconfig{'serverstatuses'}};
}
my @pages = &serverstatus_pages();
foreach my $type (@pages) {
$newserverstatus{$type}{'namedusers'} = '';
$newserverstatus{$type}{'machines'} = '';
if (defined($env{'form.'.$type.'_namedusers'})) {
my @users = split(/,/,$env{'form.'.$type.'_namedusers'});
my @okusers;
foreach my $user (@users) {
my ($uname,$udom) = split(/:/,$user);
if (($udom =~ /^$match_domain$/) &&
(&Apache::lonnet::domain($udom)) &&
($uname =~ /^$match_username$/)) {
if (!grep(/^\Q$user\E/,@okusers)) {
push(@okusers,$user);
}
}
}
if (@okusers > 0) {
@okusers = sort(@okusers);
$newserverstatus{$type}{'namedusers'} = join(',',@okusers);
}
}
if (defined($env{'form.'.$type.'_machines'})) {
my @machines = split(/,/,$env{'form.'.$type.'_machines'});
my @okmachines;
foreach my $ip (@machines) {
my @parts = split(/\./,$ip);
next if (@parts < 4);
my $badip = 0;
for (my $i=0; $i<4; $i++) {
if (!(($parts[$i] >= 0) && ($parts[$i] <= 255))) {
$badip = 1;
last;
}
}
if (!$badip) {
push(@okmachines,$ip);
}
}
@okmachines = sort(@okmachines);
$newserverstatus{$type}{'machines'} = join(',',@okmachines);
}
}
my %serverstatushash = (
serverstatuses => \%newserverstatus,
);
foreach my $type (@pages) {
foreach my $setting ('namedusers','machines') {
my (@current,@new);
if (ref($currserverstatus{$type}) eq 'HASH') {
if ($currserverstatus{$type}{$setting} ne '') {
@current = split(/,/,$currserverstatus{$type}{$setting});
}
}
if ($newserverstatus{$type}{$setting} ne '') {
@new = split(/,/,$newserverstatus{$type}{$setting});
}
if (@current > 0) {
if (@new > 0) {
foreach my $item (@current) {
if (!grep(/^\Q$item\E$/,@new)) {
$changes{$type}{$setting} = 1;
last;
}
}
foreach my $item (@new) {
if (!grep(/^\Q$item\E$/,@current)) {
$changes{$type}{$setting} = 1;
last;
}
}
} else {
$changes{$type}{$setting} = 1;
}
} elsif (@new > 0) {
$changes{$type}{$setting} = 1;
}
}
}
if (keys(%changes) > 0) {
my $titles= &LONCAPA::lonauthcgi::serverstatus_titles();
my $putresult = &Apache::lonnet::put_dom('configuration',
\%serverstatushash,$dom);
if ($putresult eq 'ok') {
$resulttext .= &mt('Changes made:').'<ul>';
foreach my $type (@pages) {
if (ref($changes{$type}) eq 'HASH') {
$resulttext .= '<li>'.$titles->{$type}.'<ul>';
if ($changes{$type}{'namedusers'}) {
if ($newserverstatus{$type}{'namedusers'} eq '') {
$resulttext .= '<li>'.&mt("Access terminated for all specific (named) users").'</li>'."\n";
} else {
$resulttext .= '<li>'.&mt("Access available for the following specified users: ").$newserverstatus{$type}{'namedusers'}.'</li>'."\n";
}
}
if ($changes{$type}{'machines'}) {
if ($newserverstatus{$type}{'machines'} eq '') {
$resulttext .= '<li>'.&mt("Access terminated for all specific IP addresses").'</li>'."\n";
} else {
$resulttext .= '<li>'.&mt("Access available for the following specified IP addresses: ").$newserverstatus{$type}{'machines'}.'</li>'."\n";
}
}
$resulttext .= '</ul></li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred saving access settings for server status pages: [_1].',$putresult).'</span>';
}
} else {
$resulttext = &mt('No changes made to access to server status pages');
}
return $resulttext;
}
sub modify_helpsettings {
my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
my ($resulttext,$errors,%changes,%helphash);
my %defaultchecked = ('submitbugs' => 'on');
my @offon = ('off','on');
my @toggles = ('submitbugs');
my %current = ('submitbugs' => '',
'adhoc' => {},
);
if (ref($domconfig{'helpsettings'}) eq 'HASH') {
%current = %{$domconfig{'helpsettings'}};
}
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
foreach my $item (@toggles) {
if ($defaultchecked{$item} eq 'on') {
if ($current{$item} eq '') {
if ($env{'form.'.$item} eq '0') {
$changes{$item} = 1;
}
} elsif ($current{$item} ne $env{'form.'.$item}) {
$changes{$item} = 1;
}
} elsif ($defaultchecked{$item} eq 'off') {
if ($current{$item} eq '') {
if ($env{'form.'.$item} eq '1') {
$changes{$item} = 1;
}
} elsif ($current{$item} ne $env{'form.'.$item}) {
$changes{$item} = 1;
}
}
if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) {
$helphash{'helpsettings'}{$item} = $env{'form.'.$item};
}
}
my $maxnum = $env{'form.helproles_maxnum'};
my $confname = $dom.'-domainconfig';
my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_');
my (@allpos,%newsettings,%changedprivs,$newrole);
my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
my @accesstypes = ('all','dh','da','none','status','inc','exc');
my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']);
my %lt = &Apache::lonlocal::texthash(
s => 'system',
d => 'domain',
order => 'Display order',
access => 'Role usage',
all => 'All with domain helpdesk or helpdesk assistant role',
dh => 'All with domain helpdesk role',
da => 'All with domain helpdesk assistant role',
none => 'None',
status => 'Determined based on institutional status',
inc => 'Include all, but exclude specific personnel',
exc => 'Exclude all, but include specific personnel',
);
for (my $num=0; $num<=$maxnum; $num++) {
my ($prefix,$identifier,$rolename,%curr);
if ($num == $maxnum) {
next unless ($env{'form.newcusthelp'} == $maxnum);
$identifier = 'custhelp'.$num;
$prefix = 'helproles_'.$num;
$rolename = $env{'form.custhelpname'.$num};
$rolename=~s/[^A-Za-z0-9]//gs;
next if ($rolename eq '');
next if (exists($existing{'rolesdef_'.$rolename}));
my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier);
my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'},
$newprivs{'c'},$confname,$dom);
if ($result ne 'ok') {
$errors .= '<li><span class="LC_error">'.
&mt('An error occurred storing the new custom role: [_1]',
$result).'</span></li>';
next;
} else {
$changedprivs{$rolename} = \%newprivs;
$newrole = $rolename;
}
} else {
$prefix = 'helproles_'.$num;
$rolename = $env{'form.'.$prefix};
next if ($rolename eq '');
next unless (exists($existing{'rolesdef_'.$rolename}));
$identifier = 'custhelp'.$num;
my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier);
my %currprivs;
($currprivs{'s'},$currprivs{'d'},$currprivs{'c'}) =
split(/\_/,$existing{'rolesdef_'.$rolename});
foreach my $level ('c','d','s') {
if ($newprivs{$level} ne $currprivs{$level}) {
my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'},
$newprivs{'c'},$confname,$dom);
if ($result ne 'ok') {
$errors .= '<li><span class="LC_error">'.
&mt('An error occurred storing privileges for existing role [_1]: [_2]',
$rolename,$result).'</span></li>';
} else {
$changedprivs{$rolename} = \%newprivs;
}
last;
}
}
if (ref($current{'adhoc'}) eq 'HASH') {
if (ref($current{'adhoc'}{$rolename}) eq 'HASH') {
%curr = %{$current{'adhoc'}{$rolename}};
}
}
}
my $newpos = $env{'form.'.$prefix.'_pos'};
$newpos =~ s/\D+//g;
$allpos[$newpos] = $rolename;
my $newdesc = $env{'form.'.$prefix.'_desc'};
$helphash{'helpsettings'}{'adhoc'}{$rolename}{'desc'} = $newdesc;
if ($curr{'desc'}) {
if ($curr{'desc'} ne $newdesc) {
$changes{'customrole'}{$rolename}{'desc'} = 1;
$newsettings{$rolename}{'desc'} = $newdesc;
}
} elsif ($newdesc ne '') {
$changes{'customrole'}{$rolename}{'desc'} = 1;
$newsettings{$rolename}{'desc'} = $newdesc;
}
my $access = $env{'form.'.$prefix.'_access'};
if (grep(/^\Q$access\E$/,@accesstypes)) {
$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = $access;
if ($access eq 'status') {
my @statuses = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_status');
if (scalar(@statuses) == 0) {
$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'none';
} else {
my (@shownstatus,$numtypes);
$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = [];
if (ref($types) eq 'ARRAY') {
$numtypes = scalar(@{$types});
foreach my $type (sort(@statuses)) {
if ($type eq 'default') {
push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type);
} elsif (grep(/^\Q$type\E$/,@{$types})) {
push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type);
push(@shownstatus,$usertypes->{$type});
}
}
}
if (grep(/^default$/,@statuses)) {
push(@shownstatus,$othertitle);
}
if (scalar(@shownstatus) == 1+$numtypes) {
$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'all';
delete($helphash{'helpsettings'}{'adhoc'}{$rolename}{'status'});
} else {
$newsettings{$rolename}{'status'} = join(' '.&mt('or').' ',@shownstatus);
if (ref($curr{'status'}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access});
if (@diffs) {
$changes{'customrole'}{$rolename}{$access} = 1;
}
} elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {
$changes{'customrole'}{$rolename}{$access} = 1;
}
}
}
} elsif (($access eq 'inc') || ($access eq 'exc')) {
my @personnel = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_staff_'.$access);
my @newspecstaff;
$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = [];
foreach my $person (sort(@personnel)) {
if ($domhelpdesk{$person}) {
push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$person);
}
}
if (ref($curr{$access}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access});
if (@diffs) {
$changes{'customrole'}{$rolename}{$access} = 1;
}
} elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {
$changes{'customrole'}{$rolename}{$access} = 1;
}
foreach my $person (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) {
my ($uname,$udom) = split(/:/,$person);
push(@newspecstaff,&Apache::loncommon::aboutmewrapper(&Apache::loncommon::plainname($uname,$udom,'lastname'),$uname,$udom));
}
$newsettings{$rolename}{$access} = join(', ',sort(@newspecstaff));
}
} else {
$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}= 'all';
}
unless ($curr{'access'} eq $access) {
$changes{'customrole'}{$rolename}{'access'} = 1;
$newsettings{$rolename}{'access'} = $lt{$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}};
}
}
if (@allpos > 0) {
my $idx = 0;
foreach my $rolename (@allpos) {
if ($rolename ne '') {
$helphash{'helpsettings'}{'adhoc'}{$rolename}{'order'} = $idx;
if (ref($current{'adhoc'}) eq 'HASH') {
if (ref($current{'adhoc'}{$rolename}) eq 'HASH') {
if ($current{'adhoc'}{$rolename}{'order'} ne $idx) {
$changes{'customrole'}{$rolename}{'order'} = 1;
$newsettings{$rolename}{'order'} = $idx+1;
}
}
}
$idx ++;
}
}
}
my $putresult;
if (keys(%changes) > 0) {
$putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom);
if ($putresult eq 'ok') {
if (ref($helphash{'helpsettings'}) eq 'HASH') {
$domdefaults{'submitbugs'} = $helphash{'helpsettings'}{'submitbugs'};
if (ref($helphash{'helpsettings'}{'adhoc'}) eq 'HASH') {
$domdefaults{'adhocroles'} = $helphash{'helpsettings'}{'adhoc'};
}
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
} else {
$errors .= '<li><span class="LC_error">'.
&mt('An error occurred storing the settings: [_1]',
$putresult).'</span></li>';
}
}
if ((keys(%changes) && ($putresult eq 'ok')) || (keys(%changedprivs))) {
$resulttext = &mt('Changes made:').'<ul>';
my (%shownprivs,@levelorder);
@levelorder = ('c','d','s');
if ((keys(%changes)) && ($putresult eq 'ok')) {
foreach my $item (sort(keys(%changes))) {
if ($item eq 'submitbugs') {
$resulttext .= '<li>'.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".',
&Apache::loncommon::modal_link('http://bugs.loncapa.org',
&mt('LON-CAPA bug tracker'),600,500)).'</li>';
} elsif ($item eq 'customrole') {
if (ref($changes{'customrole'}) eq 'HASH') {
my @keyorder = ('order','desc','access','status','exc','inc');
my %keytext = &Apache::lonlocal::texthash(
order => 'Order',
desc => 'Role description',
access => 'Role usage',
status => 'Allowed institutional types',
exc => 'Allowed personnel',
inc => 'Disallowed personnel',
);
foreach my $role (sort(keys(%{$changes{'customrole'}}))) {
if (ref($changes{'customrole'}{$role}) eq 'HASH') {
if ($role eq $newrole) {
$resulttext .= '<li>'.&mt('New custom role added: [_1]',
$role).'<ul>';
} else {
$resulttext .= '<li>'.&mt('Existing custom role modified: [_1]',
$role).'<ul>';
}
foreach my $key (@keyorder) {
if ($changes{'customrole'}{$role}{$key}) {
$resulttext .= '<li>'.&mt("[_1] set to: [_2]",
$keytext{$key},$newsettings{$role}{$key}).
'</li>';
}
}
if (ref($changedprivs{$role}) eq 'HASH') {
$shownprivs{$role} = 1;
$resulttext .= '<li>'.&mt('Privileges set to :').'<ul>';
foreach my $level (@levelorder) {
foreach my $item (split(/\:/,$changedprivs{$role}{$level})) {
next if ($item eq '');
my ($priv) = split(/\&/,$item,2);
if (&Apache::lonnet::plaintext($priv)) {
$resulttext .= '<li>'.&Apache::lonnet::plaintext($priv);
unless ($level eq 'c') {
$resulttext .= ' ('.$lt{$level}.')';
}
$resulttext .= '</li>';
}
}
}
$resulttext .= '</ul>';
}
$resulttext .= '</ul></li>';
}
}
}
}
}
}
if (keys(%changedprivs)) {
foreach my $role (sort(keys(%changedprivs))) {
unless ($shownprivs{$role}) {
$resulttext .= '<li>'.&mt('Existing custom role modified: [_1]',
$role).'<ul>'.
'<li>'.&mt('Privileges set to :').'<ul>';
foreach my $level (@levelorder) {
foreach my $item (split(/\:/,$changedprivs{$role}{$level})) {
next if ($item eq '');
my ($priv) = split(/\&/,$item,2);
if (&Apache::lonnet::plaintext($priv)) {
$resulttext .= '<li>'.&Apache::lonnet::plaintext($priv);
unless ($level eq 'c') {
$resulttext .= ' ('.$lt{$level}.')';
}
$resulttext .= '</li>';
}
}
}
$resulttext .= '</ul></li></ul></li>';
}
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to help settings');
}
if ($errors) {
$resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'.
$errors.'</ul>';
}
return $resulttext;
}
sub modify_coursedefaults {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,$errors,%changes,%defaultshash);
my %defaultchecked = (
'canuse_pdfforms' => 'off',
'uselcmath' => 'on',
'usejsme' => 'on',
'inline_chem' => 'on',
'ltiauth' => 'off',
);
my @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem','ltiauth');
my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
'uploadquota_community','uploadquota_textbook','uploadquota_placement',
'coursequota_official','coursequota_unofficial','coursequota_community',
'coursequota_textbook','coursequota_placement','mysqltables_official',
'mysqltables_unofficial','mysqltables_community','mysqltables_textbook',
'mysqltables_placement');
my @types = ('official','unofficial','community','textbook','placement');
my %staticdefaults = (
anonsurvey_threshold => 10,
uploadquota => 500,
coursequota => 20,
postsubmit => 60,
mysqltables => 172800,
domexttool => 1,
crsauthor => 1,
crseditors => ['edit','xml'],
);
my %texoptions = (
MathJax => 'MathJax',
mimetex => &mt('Convert to Images'),
tth => &mt('TeX to HTML'),
);
my @editors = ('edit','xml','daxe');
my %editornames = &crseditor_titles();
$defaultshash{'coursedefaults'} = {};
if (ref($domconfig{'coursedefaults'}) ne 'HASH') {
if ($domconfig{'coursedefaults'} eq '') {
$domconfig{'coursedefaults'} = {};
}
}
if (ref($domconfig{'coursedefaults'}) eq 'HASH') {
foreach my $item (@toggles) {
if ($defaultchecked{$item} eq 'on') {
if (($domconfig{'coursedefaults'}{$item} eq '') &&
($env{'form.'.$item} eq '0')) {
$changes{$item} = 1;
} elsif ($domconfig{'coursedefaults'}{$item} ne $env{'form.'.$item}) {
$changes{$item} = 1;
}
} elsif ($defaultchecked{$item} eq 'off') {
if (($domconfig{'coursedefaults'}{$item} eq '') &&
($env{'form.'.$item} eq '1')) {
$changes{$item} = 1;
} elsif ($domconfig{'coursedefaults'}{$item} ne $env{'form.'.$item}) {
$changes{$item} = 1;
}
}
$defaultshash{'coursedefaults'}{$item} = $env{'form.'.$item};
}
foreach my $item (@numbers) {
my ($currdef,$newdef);
$newdef = $env{'form.'.$item};
if ($item eq 'anonsurvey_threshold') {
$currdef = $domconfig{'coursedefaults'}{$item};
$newdef =~ s/\D//g;
if ($newdef eq '' || $newdef < 1) {
$newdef = 1;
}
$defaultshash{'coursedefaults'}{$item} = $newdef;
} else {
my ($setting,$type) = ($item =~ /^(uploadquota|coursequota|mysqltables)_(\w+)$/);
if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
$currdef = $domconfig{'coursedefaults'}{$setting}{$type};
}
$newdef =~ s/[^\w.\-]//g;
$defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;
}
if ($currdef ne $newdef) {
if ($item eq 'anonsurvey_threshold') {
unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
$changes{$item} = 1;
}
} elsif ($item =~ /^(uploadquota|coursequota|mysqltables)_/) {
my $setting = $1;
unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
$changes{$setting} = 1;
}
}
}
}
my $texengine;
if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) {
$texengine = $env{'form.texengine'};
my $currdef = $domconfig{'coursedefaults'}{'texengine'};
if ($currdef eq '') {
unless ($texengine eq $Apache::lonnet::deftex) {
$changes{'texengine'} = 1;
}
} elsif ($currdef ne $texengine) {
$changes{'texengine'} = 1;
}
}
if ($texengine ne '') {
$defaultshash{'coursedefaults'}{'texengine'} = $texengine;
}
my $currclone = $domconfig{'coursedefaults'}{'canclone'};
my @currclonecode;
if (ref($currclone) eq 'HASH') {
if (ref($currclone->{'instcode'}) eq 'ARRAY') {
@currclonecode = @{$currclone->{'instcode'}};
}
}
my $newclone;
if ($env{'form.canclone'} =~ /^(none|domain|instcode)$/) {
$newclone = $env{'form.canclone'};
}
if ($newclone eq 'instcode') {
my @newcodes = &Apache::loncommon::get_env_multiple('form.clonecode');
my (%codedefaults,@code_order,@clonecode);
&Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults,
\@code_order);
foreach my $item (@code_order) {
if (grep(/^\Q$item\E$/,@newcodes)) {
push(@clonecode,$item);
}
}
if (@clonecode) {
$defaultshash{'coursedefaults'}{'canclone'} = { $newclone => \@clonecode };
my @diffs = &Apache::loncommon::compare_arrays(\@currclonecode,\@clonecode);
if (@diffs) {
$changes{'canclone'} = 1;
}
} else {
$newclone eq '';
}
} elsif ($newclone ne '') {
$defaultshash{'coursedefaults'}{'canclone'} = $newclone;
}
if ($newclone ne $currclone) {
$changes{'canclone'} = 1;
}
my %credits;
foreach my $type (@types) {
unless ($type eq 'community') {
$credits{$type} = $env{'form.'.$type.'_credits'};
$credits{$type} =~ s/[^\d.]+//g;
}
}
if ((ref($domconfig{'coursedefaults'}{'coursecredits'}) ne 'HASH') &&
($env{'form.coursecredits'} eq '1')) {
$changes{'coursecredits'} = 1;
foreach my $type (keys(%credits)) {
$defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};
}
} else {
if ($env{'form.coursecredits'} eq '1') {
foreach my $type (@types) {
unless ($type eq 'community') {
if ($domconfig{'coursedefaults'}{'coursecredits'}{$type} ne $credits{$type}) {
$changes{'coursecredits'} = 1;
}
$defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type};
}
}
} elsif (ref($domconfig{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
foreach my $type (@types) {
unless ($type eq 'community') {
if ($domconfig{'coursedefaults'}{'coursecredits'}{$type}) {
$changes{'coursecredits'} = 1;
last;
}
}
}
}
}
if ($env{'form.postsubmit'} eq '1') {
$defaultshash{'coursedefaults'}{'postsubmit'}{'client'} = 'on';
my %currtimeout;
if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
if ($domconfig{'coursedefaults'}{'postsubmit'}{'client'} eq 'off') {
$changes{'postsubmit'} = 1;
}
if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') {
%currtimeout = %{$domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}};
}
} else {
$changes{'postsubmit'} = 1;
}
foreach my $type (@types) {
my $timeout = $env{'form.'.$type.'_timeout'};
$timeout =~ s/\D//g;
if ($timeout == $staticdefaults{'postsubmit'}) {
$timeout = '';
} elsif (($timeout eq '') || ($timeout =~ /^0+$/)) {
$timeout = '0';
}
unless ($timeout eq '') {
$defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}{$type} = $timeout;
}
if (exists($currtimeout{$type})) {
if ($timeout ne $currtimeout{$type}) {
$changes{'postsubmit'} = 1;
}
} elsif ($timeout ne '') {
$changes{'postsubmit'} = 1;
}
}
} else {
$defaultshash{'coursedefaults'}{'postsubmit'}{'client'} = 'off';
if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
if ($domconfig{'coursedefaults'}{'postsubmit'}{'client'} eq 'on') {
$changes{'postsubmit'} = 1;
}
} else {
$changes{'postsubmit'} = 1;
}
}
my (%newdomexttool,%newexttool,%newcrsauthor,%olddomexttool,%oldexttool,%oldcrsauthor,
%posscrseditors);
map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');
map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');
map { $newcrsauthor{$_} = 1; } &Apache::loncommon::get_env_multiple('form.crsauthor');
map { $posscrseditors{$_} = 1; } &Apache::loncommon::get_env_multiple('form.crseditors');
if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') {
%olddomexttool = %{$domconfig{'coursedefaults'}{'domexttool'}};
} else {
foreach my $type (@types) {
if ($staticdefaults{'domexttool'}) {
$olddomexttool{$type} = 1;
} else {
$olddomexttool{$type} = 0;
}
}
}
if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') {
%oldexttool = %{$domconfig{'coursedefaults'}{'exttool'}};
} else {
foreach my $type (@types) {
if ($staticdefaults{'exttool'}) {
$oldexttool{$type} = 1;
} else {
$oldexttool{$type} = 0;
}
}
}
if (ref($domconfig{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
%oldcrsauthor = %{$domconfig{'coursedefaults'}{'crsauthor'}};
} else {
foreach my $type (@types) {
if ($staticdefaults{'crsauthor'}) {
$oldcrsauthor{$type} = 1;
} else {
$oldcrsauthor{$type} = 0;
}
}
}
my @newcrseditors = ();
foreach my $editor (@editors) {
if ($posscrseditors{$editor}) {
push(@newcrseditors,$editor);
}
}
if (ref($domconfig{'coursedefaults'}{'crseditors'}) eq 'ARRAY') {
my @diffs =
&Apache::loncommon::compare_arrays($domconfig{'coursedefaults'}{'crseditors'},
\@newcrseditors);
if (@diffs) {
$changes{'crseditors'} = 1;
}
} else {
my @diffs =
&Apache::loncommon::compare_arrays($staticdefaults{'crseditors'},
\@newcrseditors);
unless (@diffs == 0) {
$changes{'crseditors'} = 1;
}
}
foreach my $type (@types) {
unless ($newdomexttool{$type}) {
$newdomexttool{$type} = 0;
}
unless ($newexttool{$type}) {
$newexttool{$type} = 0;
}
unless ($newcrsauthor{$type}) {
$newcrsauthor{$type} = 0;
}
if ($newdomexttool{$type} != $olddomexttool{$type}) {
$changes{'domexttool'} = 1;
}
if ($newexttool{$type} != $oldexttool{$type}) {
$changes{'exttool'} = 1;
}
if ($newcrsauthor{$type} != $oldcrsauthor{$type}) {
$changes{'crsauthor'} = 1;
}
}
$defaultshash{'coursedefaults'}{'domexttool'} = \%newdomexttool;
$defaultshash{'coursedefaults'}{'exttool'} = \%newexttool;
$defaultshash{'coursedefaults'}{'crsauthor'} = \%newcrsauthor;
$defaultshash{'coursedefaults'}{'crseditors'} = \@newcrseditors;
}
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||
($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||
($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||
($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||
($changes{'exttool'}) || ($changes{'coursequota'}) || ($changes{'crsauthor'})) {
foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine',
'ltiauth') {
if ($changes{$item}) {
$domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
}
}
if ($changes{'coursecredits'}) {
if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'coursecredits'}})) {
$domdefaults{$type.'credits'} =
$defaultshash{'coursedefaults'}{'coursecredits'}{$type};
}
}
}
if ($changes{'postsubmit'}) {
if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
$domdefaults{'postsubmit'} = $defaultshash{'coursedefaults'}{'postsubmit'}{'client'};
if (ref($defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') {
foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}})) {
$domdefaults{$type.'postsubtimeout'} =
$defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}{$type};
}
}
}
}
if ($changes{'uploadquota'}) {
if (ref($defaultshash{'coursedefaults'}{'uploadquota'}) eq 'HASH') {
foreach my $type (@types) {
$domdefaults{$type.'quota'}=$defaultshash{'coursedefaults'}{'uploadquota'}{$type};
}
}
}
if ($changes{'coursequota'}) {
if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {
foreach my $type (@types) {
$domdefaults{$type.'coursequota'}=$defaultshash{'coursedefaults'}{'coursequota'}{$type};
}
}
}
if ($changes{'canclone'}) {
if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
my @clonecodes = @{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}};
if (@clonecodes) {
$domdefaults{'canclone'} = join('+',@clonecodes);
}
}
} else {
$domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'};
}
}
if ($changes{'domexttool'}) {
if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {
foreach my $type (@types) {
$domdefaults{$type.'domexttool'}=$defaultshash{'coursedefaults'}{'domexttool'}{$type};
}
}
}
if ($changes{'exttool'}) {
if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {
foreach my $type (@types) {
$domdefaults{$type.'exttool'}=$defaultshash{'coursedefaults'}{'exttool'}{$type};
}
}
}
if ($changes{'crsauthor'}) {
if (ref($defaultshash{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
foreach my $type (@types) {
$domdefaults{$type.'crsauthor'}=$defaultshash{'coursedefaults'}{'crsauthor'}{$type};
}
}
}
if ($changes{'crseditors'}) {
if (ref($defaultshash{'coursedefaults'}{'crseditors'}) eq 'ARRAY') {
$domdefaults{'crseditors'}=join(',',@{$defaultshash{'coursedefaults'}{'crseditors'}});
}
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
$resulttext = &mt('Changes made:').'<ul>';
foreach my $item (sort(keys(%changes))) {
if ($item eq 'canuse_pdfforms') {
if ($env{'form.'.$item} eq '1') {
$resulttext .= '<li>'.&mt("Course/Community users can create/upload PDF forms set to 'on'").'</li>';
} else {
$resulttext .= '<li>'.&mt('Course/Community users can create/upload PDF forms set to "off"').'</li>';
}
} elsif ($item eq 'uselcmath') {
if ($env{'form.'.$item} eq '1') {
$resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';
} else {
$resulttext .= '<li>'.&mt('Math preview uses DragMath (Java), if supported by client OS.').'</li>';
}
} elsif ($item eq 'usejsme') {
if ($env{'form.'.$item} eq '1') {
$resulttext .= '<li>'.&mt('Molecule editor uses JSME (HTML5), if supported by browser.').'</li>';
} else {
$resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>';
}
} elsif ($item eq 'inline_chem') {
if ($env{'form.'.$item} eq '1') {
$resulttext .= '<li>'.&mt('Chemical Reaction Response uses inline previewer').'</li>';
} else {
$resulttext .= '<li>'.&mt('Chemical Reaction Response uses pop-up previewer').'</li>';
}
} elsif ($item eq 'texengine') {
if ($defaultshash{'coursedefaults'}{'texengine'} ne '') {
$resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"',
$texoptions{$defaultshash{'coursedefaults'}{'texengine'}}).'</li>';
}
} elsif ($item eq 'anonsurvey_threshold') {
$resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>';
} elsif ($item eq 'uploadquota') {
if (ref($defaultshash{'coursedefaults'}{'uploadquota'}) eq 'HASH') {
$resulttext .= '<li>'.&mt('Default quota for content uploaded to a course/community via Course Editor set as follows:').'<ul>'.
'<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.
'<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.
'<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.
'<li>'.&mt('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'placement'}.'</b>').'</li>'.
'<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.
'</ul>'.
'</li>';
} else {
$resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';
}
} elsif ($item eq 'coursequota') {
if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {
$resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course set as follows:').'<ul>'.
'<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'official'}.'</b>').'</li>'.
'<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'unofficial'}.'</b>').'</li>'.
'<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'textbook'}.'</b>').'</li>'.
'<li>'.&mt('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'placement'}.'</b>').'</li>'.
'<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'community'}.'</b>').'</li>'.
'</ul>'.
'</li>';
} else {
$resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course remains default: [_1] MB',$staticdefaults{'coursequota'}).'</li>';
}
} elsif ($item eq 'mysqltables') {
if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
$resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.
'<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.
'<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.
'<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.
'<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'.
'<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.
'</ul>'.
'</li>';
} else {
$resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver remains default: [_1] s',$staticdefaults{'uploadquota'}).'</li>';
}
} elsif ($item eq 'postsubmit') {
if ($domdefaults{'postsubmit'} eq 'off') {
$resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.');
} else {
$resulttext .= '<li>'.&mt('Submit button(s) disabled on page after student makes submission').'; ';
if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
$resulttext .= &mt('durations:').'<ul>';
foreach my $type (@types) {
$resulttext .= '<li>';
my $timeout;
if (ref($defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') {
$timeout = $defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}{$type};
}
my $display;
if ($timeout eq '0') {
$display = &mt('unlimited');
} elsif ($timeout eq '') {
$display = &mt('[quant,_1,second] (default)',$staticdefaults{'postsubmit'});
} else {
$display = &mt('[quant,_1,second]',$timeout);
}
if ($type eq 'community') {
$resulttext .= &mt('Communities');
} elsif ($type eq 'official') {
$resulttext .= &mt('Official courses');
} elsif ($type eq 'unofficial') {
$resulttext .= &mt('Unofficial courses');
} elsif ($type eq 'textbook') {
$resulttext .= &mt('Textbook courses');
} elsif ($type eq 'placement') {
$resulttext .= &mt('Placement tests');
}
$resulttext .= ' -- '.$display.'</li>';
}
$resulttext .= '</ul>';
}
$resulttext .= '</li>';
}
} elsif ($item eq 'coursecredits') {
if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') {
if (($domdefaults{'officialcredits'} eq '') &&
($domdefaults{'unofficialcredits'} eq '') &&
($domdefaults{'textbookcredits'} eq '')) {
$resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>';
} else {
$resulttext .= '<li>'.&mt('Student credits can be set per course by a Domain Coordinator, with the following defaults applying:').'<ul>'.
'<li>'.&mt('Official courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'official'}).'</li>'.
'<li>'.&mt('Unofficial courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'unofficial'}).'</li>'.
'<li>'.&mt('Textbook courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'textbook'}).'</li>'.
'</ul>'.
'</li>';
}
} else {
$resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>';
}
} elsif ($item eq 'canclone') {
if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
my $clonecodes = join(' '.&mt('and').' ',@{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}});
$resulttext .= '<li>'.&mt('By default, official courses can be cloned from existing courses with the same: [_1]','<b>'.$clonecodes.'</b>').'</li>';
}
} elsif ($defaultshash{'coursedefaults'}{'canclone'} eq 'domain') {
$resulttext .= '<li>'.&mt('By default, a course requester can clone any course from his/her domain.').'</li>';
} else {
$resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>';
}
} elsif ($item eq 'ltiauth') {
if ($env{'form.'.$item} eq '1') {
$resulttext .= '<li>'.&mt('LTI launch of deep-linked URL need not require re-authentication').'</li>';
} else {
$resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';
}
} elsif (($item eq 'domexttool') || ($item eq 'exttool') || ($item eq 'crsauthor')) {
my @noyes = (&mt('no'),&mt('yes'));
my %status = (
domexttool => {
ishash => &mt('External Tools defined in the domain may be used as follows:'),
default => &mt('External Tools defined in the domain may be used in all course types, by default'),
},
exttool => {
ishash => &mt('External Tools can be defined and configured in course containers as follows:'),
default => &mt('External Tools can not be defined in any course types, by default'),
},
crsauthor => {
ishash => &mt('Standard Problems can be created within course containers as follows:'),
default => &mt('Standard Problems can be created within any course type, by default'),
},
);
if (ref($defaultshash{'coursedefaults'}{$item}) eq 'HASH') {
$resulttext .= '<li>'.$status{$item}{'ishash'}.'<ul>'.
'<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'official'}].'</b>').'</li>'.
'<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'unofficial'}].'</b>').'</li>'.
'<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'textbook'}].'</b>').'</li>'.
'<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'placement'}].'</b>').'</li>'.
'<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'community'}].'</b>').'</li>'.
'</ul>'.
'</li>';
} else {
$resulttext .= '<li>'.$status{$item}{'default'}.'</li>';
}
} elsif ($item eq 'crseditors') {
if (ref($defaultshash{'coursedefaults'}{$item}) eq 'ARRAY') {
my $shown;
if (@{$defaultshash{'coursedefaults'}{$item}}) {
$shown = join(', ', map { $editornames{$_} } @{$defaultshash{'coursedefaults'}{$item}});
} else {
$shown = &mt('None');
}
$resulttext .= '<li>'.&mt('Available editors for course/community resources: [_1]',$shown).'</li>';
}
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to course defaults');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_selfenrollment {
my ($dom,$lastactref,%domconfig) = @_;
my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);
my @types = ('official','unofficial','community','textbook','placement');
my %titles = &tool_titles();
my %descs = &Apache::lonuserutils::selfenroll_default_descs();
($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
$ordered{'default'} = ['types','registered','approval','limit'];
my (%roles,%shown,%toplevel);
$roles{'0'} = &Apache::lonnet::plaintext('dc');
if (ref($domconfig{'selfenrollment'}) ne 'HASH') {
if ($domconfig{'selfenrollment'} eq '') {
$domconfig{'selfenrollment'} = {};
}
}
%toplevel = (
admin => 'Configuration Rights',
default => 'Default settings',
validation => 'Validation of self-enrollment requests',
);
my ($itemsref,$namesref,$fieldsref) = &Apache::lonuserutils::selfenroll_validation_types();
if (ref($ordered{'admin'}) eq 'ARRAY') {
foreach my $item (@{$ordered{'admin'}}) {
foreach my $type (@types) {
if ($env{'form.selfenrolladmin_'.$item.'_'.$type}) {
$selfenrollhash{'admin'}{$type}{$item} = 1;
} else {
$selfenrollhash{'admin'}{$type}{$item} = 0;
}
if (ref($domconfig{'selfenrollment'}{'admin'}) eq 'HASH') {
if (ref($domconfig{'selfenrollment'}{'admin'}{$type}) eq 'HASH') {
if ($selfenrollhash{'admin'}{$type}{$item} ne
$domconfig{'selfenrollment'}{'admin'}{$type}{$item}) {
push(@{$changes{'admin'}{$type}},$item);
}
} else {
if (!$selfenrollhash{'admin'}{$type}{$item}) {
push(@{$changes{'admin'}{$type}},$item);
}
}
} elsif (!$selfenrollhash{'admin'}{$type}{$item}) {
push(@{$changes{'admin'}{$type}},$item);
}
}
}
}
foreach my $item (@{$ordered{'default'}}) {
foreach my $type (@types) {
my $value = $env{'form.selfenrolldefault_'.$item.'_'.$type};
if ($item eq 'types') {
unless (($value eq 'all') || ($value eq 'dom')) {
$value = '';
}
} elsif ($item eq 'registered') {
unless ($value eq '1') {
$value = 0;
}
} elsif ($item eq 'approval') {
unless ($value =~ /^[012]$/) {
$value = 0;
}
} else {
unless (($value eq 'allstudents') || ($value eq 'selfenrolled')) {
$value = 'none';
}
}
$selfenrollhash{'default'}{$type}{$item} = $value;
if (ref($domconfig{'selfenrollment'}{'default'}) eq 'HASH') {
if (ref($domconfig{'selfenrollment'}{'default'}{$type}) eq 'HASH') {
if ($selfenrollhash{'default'}{$type}{$item} ne
$domconfig{'selfenrollment'}{'default'}{$type}{$item}) {
push(@{$changes{'default'}{$type}},$item);
}
} else {
push(@{$changes{'default'}{$type}},$item);
}
} else {
push(@{$changes{'default'}{$type}},$item);
}
if ($item eq 'limit') {
if (($value eq 'allstudents') || ($value eq 'selfenrolled')) {
$env{'form.selfenrolldefault_cap_'.$type} =~ s/\D//g;
if ($env{'form.selfenrolldefault_cap_'.$type} ne '') {
$selfenrollhash{'default'}{$type}{'cap'} = $env{'form.selfenrolldefault_cap_'.$type};
}
} else {
$selfenrollhash{'default'}{$type}{'cap'} = '';
}
if (ref($domconfig{'selfenrollment'}{'default'}{$type}) eq 'HASH') {
if ($selfenrollhash{'default'}{$type}{'cap'} ne
$domconfig{'selfenrollment'}{'admin'}{$type}{'cap'}) {
push(@{$changes{'default'}{$type}},'cap');
}
} elsif ($selfenrollhash{'default'}{$type}{'cap'} ne '') {
push(@{$changes{'default'}{$type}},'cap');
}
}
}
}
foreach my $item (@{$itemsref}) {
if ($item eq 'fields') {
my @changed;
@{$selfenrollhash{'validation'}{$item}} = &Apache::loncommon::get_env_multiple('form.selfenroll_validation_'.$item);
if (@{$selfenrollhash{'validation'}{$item}} > 0) {
@{$selfenrollhash{'validation'}{$item}} = sort(@{$selfenrollhash{'validation'}{$item}});
}
if (ref($domconfig{'selfenrollment'}{'validation'}) eq 'HASH') {
if (ref($domconfig{'selfenrollment'}{'validation'}{$item}) eq 'ARRAY') {
@changed = &Apache::loncommon::compare_arrays($selfenrollhash{'validation'}{$item},
$domconfig{'selfenrollment'}{'validation'}{$item});
} else {
@changed = @{$selfenrollhash{'validation'}{$item}};
}
} else {
@changed = @{$selfenrollhash{'validation'}{$item}};
}
if (@changed) {
if ($selfenrollhash{'validation'}{$item}) {
$changes{'validation'}{$item} = join(', ',@{$selfenrollhash{'validation'}{$item}});
} else {
$changes{'validation'}{$item} = &mt('None');
}
}
} else {
$selfenrollhash{'validation'}{$item} = $env{'form.selfenroll_validation_'.$item};
if ($item eq 'markup') {
if ($env{'form.selfenroll_validation_'.$item}) {
$env{'form.selfenroll_validation_'.$item} =~ s/[\n\r\f]+/\s/gs;
}
}
if (ref($domconfig{'selfenrollment'}{'validation'}) eq 'HASH') {
if ($domconfig{'selfenrollment'}{'validation'}{$item} ne $selfenrollhash{'validation'}{$item}) {
$changes{'validation'}{$item} = $selfenrollhash{'validation'}{$item};
}
}
}
}
my $putresult = &Apache::lonnet::put_dom('configuration',{'selfenrollment' => \%selfenrollhash},
$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
$resulttext = &mt('Changes made:').'<ul>';
foreach my $key ('admin','default','validation') {
if (ref($changes{$key}) eq 'HASH') {
$resulttext .= '<li>'.$toplevel{$key}.'<ul>';
if ($key eq 'validation') {
foreach my $item (@{$itemsref}) {
if (exists($changes{$key}{$item})) {
if ($item eq 'markup') {
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$namesref->{$item},
'<br /><pre>'.$changes{$key}{$item}.'</pre>').'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to: [_2]',$namesref->{$item},
'<b>'.$changes{$key}{$item}.'</b>').'</li>';
}
}
}
} else {
foreach my $type (@types) {
if ($type eq 'community') {
$roles{'1'} = &mt('Community personnel');
} else {
$roles{'1'} = &mt('Course personnel');
}
if (ref($changes{$key}{$type}) eq 'ARRAY') {
if (ref($selfenrollhash{$key}{$type}) eq 'HASH') {
if ($key eq 'admin') {
my @mgrdc = ();
if (ref($ordered{$key}) eq 'ARRAY') {
foreach my $item (@{$ordered{'admin'}}) {
if (ref($selfenrollhash{$key}{$type}) eq 'HASH') {
if ($selfenrollhash{$key}{$type}{$item} eq '0') {
push(@mgrdc,$item);
}
}
}
if (@mgrdc) {
$domdefaults{$type.'selfenrolladmdc'} = join(',',@mgrdc);
} else {
delete($domdefaults{$type.'selfenrolladmdc'});
}
}
} else {
if (ref($ordered{$key}) eq 'ARRAY') {
foreach my $item (@{$ordered{$key}}) {
if (grep(/^\Q$item\E$/,@{$changes{$key}{$type}})) {
$domdefaults{$type.'selfenroll'.$item} =
$selfenrollhash{$key}{$type}{$item};
}
}
}
}
}
$resulttext .= '<li>'.$titles{$type}.'<ul>';
foreach my $item (@{$ordered{$key}}) {
if (grep(/^\Q$item\E$/,@{$changes{$key}{$type}})) {
$resulttext .= '<li>';
if ($key eq 'admin') {
$resulttext .= &mt('[_1] -- management by: [_2]',$titlesref->{$item},
'<b>'.$roles{$selfenrollhash{'admin'}{$type}{$item}}.'</b>');
} else {
$resulttext .= &mt('[_1] set to: [_2]',$titlesref->{$item},
'<b>'.$descs{$item}{$selfenrollhash{'default'}{$type}{$item}}.'</b>');
}
$resulttext .= '</li>';
}
}
$resulttext .= '</ul></li>';
}
}
$resulttext .= '</ul></li>';
}
}
}
if ((exists($changes{'admin'})) || (exists($changes{'default'}))) {
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('No changes made to self-enrollment settings');
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
return $resulttext;
}
sub modify_wafproxy {
my ($dom,$action,$lastactref,%domconfig) = @_;
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my (%othercontrol,%canset,%values,%curralias,%currsaml,%currvalue,@warnings,
%wafproxy,%changes,%expirecache,%expiresaml);
foreach my $server (sort(keys(%servers))) {
my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
if ($serverhome eq $server) {
my $serverdom = &Apache::lonnet::host_domain($server);
if ($serverdom eq $dom) {
$canset{$server} = 1;
}
}
}
if (ref($domconfig{'wafproxy'}) eq 'HASH') {
%{$values{$dom}} = ();
if (ref($domconfig{'wafproxy'}{'alias'}) eq 'HASH') {
%curralias = %{$domconfig{'wafproxy'}{'alias'}};
}
if (ref($domconfig{'wafproxy'}{'saml'}) eq 'HASH') {
%currsaml = %{$domconfig{'wafproxy'}{'saml'}};
}
foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
$currvalue{$item} = $domconfig{'wafproxy'}{$item};
}
}
my $output;
if (keys(%canset)) {
%{$wafproxy{'alias'}} = ();
%{$wafproxy{'saml'}} = ();
foreach my $key (sort(keys(%canset))) {
if ($env{'form.wafproxy_'.$dom}) {
$wafproxy{'alias'}{$key} = $env{'form.wafproxy_alias_'.$key};
$wafproxy{'alias'}{$key} =~ s/^\s+|\s+$//g;
if ($wafproxy{'alias'}{$key} ne $curralias{$key}) {
$changes{'alias'} = 1;
}
if ($env{'form.wafproxy_alias_saml_'.$key}) {
$wafproxy{'saml'}{$key} = 1;
}
if ($wafproxy{'saml'}{$key} ne $currsaml{$key}) {
$changes{'saml'} = 1;
}
} else {
$wafproxy{'alias'}{$key} = '';
$wafproxy{'saml'}{$key} = '';
if ($curralias{$key}) {
$changes{'alias'} = 1;
}
if ($currsaml{$key}) {
$changes{'saml'} = 1;
}
}
if ($wafproxy{'alias'}{$key} eq '') {
if ($curralias{$key}) {
$expirecache{$key} = 1;
}
delete($wafproxy{'alias'}{$key});
}
if ($wafproxy{'saml'}{$key} eq '') {
if ($currsaml{$key}) {
$expiresaml{$key} = 1;
}
delete($wafproxy{'saml'}{$key});
}
}
unless (keys(%{$wafproxy{'alias'}})) {
delete($wafproxy{'alias'});
}
unless (keys(%{$wafproxy{'saml'}})) {
delete($wafproxy{'saml'});
}
# Localization for values in %warn occurs in &mt() calls separately.
my %warn = (
trusted => 'trusted IP range(s)',
vpnint => 'internal IP range(s) for VPN sessions(s)',
vpnext => 'IP range(s) for backend WAF connections',
);
foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
my $possible = $env{'form.wafproxy_'.$item};
$possible =~ s/^\s+|\s+$//g;
if ($possible ne '') {
if ($item eq 'remoteip') {
if ($possible =~ /^[mhn]$/) {
$wafproxy{$item} = $possible;
}
} elsif ($item eq 'ipheader') {
if ($wafproxy{'remoteip'} eq 'h') {
$wafproxy{$item} = $possible;
}
} elsif ($item eq 'sslopt') {
if ($possible =~ /^0|1$/) {
$wafproxy{$item} = $possible;
}
} else {
my (@ok,$count);
if (($item eq 'vpnint') || ($item eq 'vpnext')) {
unless ($env{'form.wafproxy_vpnaccess'}) {
$possible = '';
}
} elsif ($item eq 'trusted') {
unless ($wafproxy{'remoteip'} eq 'h') {
$possible = '';
}
}
unless ($possible eq '') {
$possible =~ s/[\r\n]+/\s/g;
$possible =~ s/\s*-\s*/-/g;
$possible =~ s/\s+/,/g;
$possible =~ s/,+/,/g;
}
$count = 0;
if ($possible ne '') {
foreach my $poss (split(/\,/,$possible)) {
$count ++;
$poss = &validate_ip_pattern($poss);
if ($poss ne '') {
push(@ok,$poss);
}
}
my $diff = $count - scalar(@ok);
if ($diff) {
push(@warnings,'<li>'.
&mt('[quant,_1,IP] invalid and excluded from saved value for [_2]',
$diff,$warn{$item}).
'</li>');
}
if (@ok) {
my @cidr_list;
foreach my $item (@ok) {
@cidr_list = &Net::CIDR::cidradd($item,@cidr_list);
}
$wafproxy{$item} = join(',',@cidr_list);
}
}
}
if ($wafproxy{$item} ne $currvalue{$item}) {
$changes{$item} = 1;
}
} elsif ($currvalue{$item}) {
$changes{$item} = 1;
}
}
} else {
if (keys(%curralias)) {
$changes{'alias'} = 1;
}
if (keys(%currsaml)) {
$changes{'saml'} = 1;
}
if (keys(%currvalue)) {
foreach my $key (keys(%currvalue)) {
$changes{$key} = 1;
}
}
}
if (keys(%changes)) {
my %defaultshash = (
wafproxy => \%wafproxy,
);
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
$dom);
if ($putresult eq 'ok') {
my $cachetime = 24*60*60;
my (%domdefaults,$updatedomdefs);
foreach my $item ('ipheader','trusted','vpnint','vpnext','sslopt') {
if ($changes{$item}) {
unless ($updatedomdefs) {
%domdefaults = &Apache::lonnet::get_domain_defaults($dom);
$updatedomdefs = 1;
}
if ($wafproxy{$item}) {
$domdefaults{'waf_'.$item} = $wafproxy{$item};
} elsif (exists($domdefaults{'waf_'.$item})) {
delete($domdefaults{'waf_'.$item});
}
}
}
if ($updatedomdefs) {
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
}
if ((exists($wafproxy{'alias'})) || (keys(%expirecache))) {
my %updates = %expirecache;
foreach my $key (keys(%expirecache)) {
&Apache::lonnet::devalidate_cache_new('proxyalias',$key);
}
if (ref($wafproxy{'alias'}) eq 'HASH') {
my $cachetime = 24*60*60;
foreach my $key (keys(%{$wafproxy{'alias'}})) {
$updates{$key} = 1;
&Apache::lonnet::do_cache_new('proxyalias',$key,$wafproxy{'alias'}{$key},
$cachetime);
}
}
if (ref($lastactref) eq 'HASH') {
$lastactref->{'proxyalias'} = \%updates;
}
}
if ((exists($wafproxy{'saml'})) || (keys(%expiresaml))) {
my %samlupdates = %expiresaml;
foreach my $key (keys(%expiresaml)) {
&Apache::lonnet::devalidate_cache_new('proxysaml',$key);
}
if (ref($wafproxy{'saml'}) eq 'HASH') {
my $cachetime = 24*60*60;
foreach my $key (keys(%{$wafproxy{'saml'}})) {
$samlupdates{$key} = 1;
&Apache::lonnet::do_cache_new('proxysaml',$key,$wafproxy{'saml'}{$key},
$cachetime);
}
}
if (ref($lastactref) eq 'HASH') {
$lastactref->{'proxysaml'} = \%samlupdates;
}
}
$output = &mt('Changes were made to Web Application Firewall/Reverse Proxy').'<ul>';
foreach my $item ('alias','saml','remoteip','ipheader','trusted','vpnint','vpnext','sslopt') {
if ($changes{$item}) {
if ($item eq 'alias') {
my $numaliased = 0;
if (ref($wafproxy{'alias'}) eq 'HASH') {
my $shown;
if (keys(%{$wafproxy{'alias'}})) {
foreach my $server (sort(keys(%{$wafproxy{'alias'}}))) {
$shown .= '<li>'.&mt('[_1] aliased by [_2]',
&Apache::lonnet::hostname($server),
$wafproxy{'alias'}{$server}).'</li>';
$numaliased ++;
}
if ($numaliased) {
$output .= '<li>'.&mt('Aliases for hostnames set to: [_1]',
'<ul>'.$shown.'</ul>').'</li>';
}
}
}
unless ($numaliased) {
$output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>';
}
} elsif ($item eq 'saml') {
my $shown;
if (ref($wafproxy{'saml'}) eq 'HASH') {
if (keys(%{$wafproxy{'saml'}})) {
$shown = join(', ',sort(keys(%{$wafproxy{'saml'}})));
}
}
if ($shown) {
$output .= '<li>'.&mt('Alias used by SSO Auth for: [_1]',
$shown).'</li>';
} else {
$output .= '<li>'.&mt('No alias used for SSO Auth').'</li>';
}
} else {
if ($item eq 'remoteip') {
my %ip_methods = &remoteip_methods();
if ($wafproxy{$item} =~ /^[mh]$/) {
$output .= '<li>'.&mt("Method for determining user's IP set to: [_1]",
$ip_methods{$wafproxy{$item}}).'</li>';
} else {
if (($env{'form.wafproxy_'.$dom}) && (ref($wafproxy{'alias'}) eq 'HASH')) {
$output .= '<li>'.&mt("No method in use to get user's real IP (will report IP used by WAF).").
'</li>';
} else {
$output .= '<li>'.&mt('WAF/Reverse Proxy not in use').'</li>';
}
}
} elsif ($item eq 'ipheader') {
if ($wafproxy{$item}) {
$output .= '<li>'.&mt('Request header with remote IP set to: [_1]',
$wafproxy{$item}).'</li>';
} else {
$output .= '<li>'.&mt('Request header with remote IP deleted').'</li>';
}
} elsif ($item eq 'trusted') {
if ($wafproxy{$item}) {
$output .= '<li>'.&mt('Trusted IP range(s) set to: [_1]',
$wafproxy{$item}).'</li>';
} else {
$output .= '<li>'.&mt('Trusted IP range(s) deleted').'</li>';
}
} elsif ($item eq 'vpnint') {
if ($wafproxy{$item}) {
$output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions set to: [_1]',
$wafproxy{$item}).'</li>';
} else {
$output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions deleted').'</li>';
}
} elsif ($item eq 'vpnext') {
if ($wafproxy{$item}) {
$output .= '<li>'.&mt('IP Range(s) for backend WAF connections set to: [_1]',
$wafproxy{$item}).'</li>';
} else {
$output .= '<li>'.&mt('IP Range(s) for backend WAF connections deleted').'</li>';
}
} elsif ($item eq 'sslopt') {
if ($wafproxy{$item}) {
$output .= '<li>'.&mt('WAF/Reverse Proxy expected to forward requests to https on LON-CAPA node, regardless of original protocol in web browser (http or https).').'</li>';
} else {
$output .= '<li>'.&mt('WAF/Reverse Proxy expected to preserve original protocol in web browser (either http or https) when forwarding to LON-CAPA node.').'</li>';
}
}
}
}
}
$output .= '</ul>';
} else {
$output = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} elsif (keys(%canset)) {
$output = &mt('No changes made to Web Application Firewall/Reverse Proxy settings');
}
if (@warnings) {
$output .= '<br />'.&mt('Warnings:').'<ul>'.
join("\n",@warnings).'</ul>';
}
return $output;
}
sub validate_ip_pattern {
my ($pattern) = @_;
if ($pattern =~ /^([^-]+)\-([^-]+)$/) {
my ($start,$end) = ($1,$2);
if ((&Net::CIDR::cidrvalidate($start)) && (&Net::CIDR::cidrvalidate($end))) {
if (($start !~ m{/}) && ($end !~ m{/})) {
return $start.'-'.$end;
}
}
} elsif ($pattern ne '') {
$pattern = &Net::CIDR::cidrvalidate($pattern);
if ($pattern ne '') {
return $pattern;
}
}
return;
}
sub modify_usersessions {
my ($dom,$lastactref,%domconfig) = @_;
my @hostingtypes = ('version','excludedomain','includedomain');
my @offloadtypes = ('primary','default');
my %types = (
remote => \@hostingtypes,
hosted => \@hostingtypes,
spares => \@offloadtypes,
);
my @prefixes = ('remote','hosted','spares');
my @lcversions = &Apache::lonnet::all_loncaparevs();
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my @locations = sort(keys(%by_location));
my (%defaultshash,%changes);
foreach my $prefix (@prefixes) {
$defaultshash{'usersessions'}{$prefix} = {};
}
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my $resulttext;
my %iphost = &Apache::lonnet::get_iphost();
foreach my $prefix (@prefixes) {
next if ($prefix eq 'spares');
foreach my $type (@{$types{$prefix}}) {
my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
if ($type eq 'version') {
my $value = $env{'form.'.$prefix.'_'.$type};
my $okvalue;
if ($value ne '') {
if (grep(/^\Q$value\E$/,@lcversions)) {
$okvalue = $value;
}
}
if (ref($domconfig{'usersessions'}) eq 'HASH') {
if (ref($domconfig{'usersessions'}{$prefix}) eq 'HASH') {
if ($domconfig{'usersessions'}{$prefix}{$type} ne '') {
if ($inuse == 0) {
$changes{$prefix}{$type} = 1;
} else {
if ($okvalue ne $domconfig{'usersessions'}{$prefix}{$type}) {
$changes{$prefix}{$type} = 1;
}
if ($okvalue ne '') {
$defaultshash{'usersessions'}{$prefix}{$type} = $okvalue;
}
}
} else {
if (($inuse == 1) && ($okvalue ne '')) {
$defaultshash{'usersessions'}{$prefix}{$type} = $okvalue;
$changes{$prefix}{$type} = 1;
}
}
} else {
if (($inuse == 1) && ($okvalue ne '')) {
$defaultshash{'usersessions'}{$prefix}{$type} = $okvalue;
$changes{$prefix}{$type} = 1;
}
}
} else {
if (($inuse == 1) && ($okvalue ne '')) {
$defaultshash{'usersessions'}{$prefix}{$type} = $okvalue;
$changes{$prefix}{$type} = 1;
}
}
} else {
my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
my @okvals;
foreach my $val (@vals) {
if ($val =~ /:/) {
my @items = split(/:/,$val);
foreach my $item (@items) {
if (ref($by_location{$item}) eq 'ARRAY') {
push(@okvals,$item);
}
}
} else {
if (ref($by_location{$val}) eq 'ARRAY') {
push(@okvals,$val);
}
}
}
@okvals = sort(@okvals);
if (ref($domconfig{'usersessions'}) eq 'HASH') {
if (ref($domconfig{'usersessions'}{$prefix}) eq 'HASH') {
if (ref($domconfig{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
if ($inuse == 0) {
$changes{$prefix}{$type} = 1;
} else {
$defaultshash{'usersessions'}{$prefix}{$type} = \@okvals;
my @changed = &Apache::loncommon::compare_arrays($domconfig{'usersessions'}{$prefix}{$type},$defaultshash{'usersessions'}{$prefix}{$type});
if (@changed > 0) {
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{'usersessions'}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{'usersessions'}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{'usersessions'}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
}
}
}
my @alldoms = &Apache::lonnet::all_domains();
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %spareid = ¤t_offloads_to($dom,$domconfig{'usersessions'},\%servers);
my $savespares;
foreach my $lonhost (sort(keys(%servers))) {
my $serverhomeID =
&Apache::lonnet::get_server_homeID($servers{$lonhost});
my $serverhostname = &Apache::lonnet::hostname($lonhost);
$defaultshash{'usersessions'}{'spares'}{$lonhost} = {};
my %spareschg;
foreach my $type (@{$types{'spares'}}) {
my @okspares;
my @checked = &Apache::loncommon::get_env_multiple('form.spare_'.$type.'_'.$lonhost);
foreach my $server (@checked) {
if (&Apache::lonnet::hostname($server) ne '') {
unless (&Apache::lonnet::hostname($server) eq $serverhostname) {
unless (grep(/^\Q$server\E$/,@okspares)) {
push(@okspares,$server);
}
}
}
}
my $new = $env{'form.newspare_'.$type.'_'.$lonhost};
my $newspare;
if (($new ne '') && (&Apache::lonnet::hostname($new))) {
unless (&Apache::lonnet::hostname($new) eq $serverhostname) {
$newspare = $new;
}
}
my @spares;
if (($newspare ne '') && (!grep(/^\Q$newspare\E$/,@okspares))) {
@spares = sort(@okspares,$newspare);
} else {
@spares = sort(@okspares);
}
$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type} = \@spares;
if (ref($spareid{$lonhost}) eq 'HASH') {
if (ref($spareid{$lonhost}{$type}) eq 'ARRAY') {
my @diffs = &Apache::loncommon::compare_arrays($spareid{$lonhost}{$type},\@spares);
if (@diffs > 0) {
$spareschg{$type} = 1;
}
}
}
}
if (keys(%spareschg) > 0) {
$changes{'spares'}{$lonhost} = \%spareschg;
}
}
$defaultshash{'usersessions'}{'offloadnow'} = {};
$defaultshash{'usersessions'}{'offloadoth'} = {};
my @offloadnow = &Apache::loncommon::get_env_multiple('form.offloadnow');
my @okoffload;
if (@offloadnow) {
foreach my $server (@offloadnow) {
if (&Apache::lonnet::hostname($server) ne '') {
unless (grep(/^\Q$server\E$/,@okoffload)) {
push(@okoffload,$server);
}
}
}
if (@okoffload) {
foreach my $lonhost (@okoffload) {
$defaultshash{'usersessions'}{'offloadnow'}{$lonhost} = 1;
}
}
}
my @offloadoth = &Apache::loncommon::get_env_multiple('form.offloadoth');
my @okoffloadoth;
if (@offloadoth) {
foreach my $server (@offloadoth) {
if (&Apache::lonnet::hostname($server) ne '') {
unless (grep(/^\Q$server\E$/,@okoffloadoth)) {
push(@okoffloadoth,$server);
}
}
}
if (@okoffloadoth) {
foreach my $lonhost (@okoffloadoth) {
$defaultshash{'usersessions'}{'offloadoth'}{$lonhost} = 1;
}
}
}
if (ref($domconfig{'usersessions'}) eq 'HASH') {
if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {
if (ref($changes{'spares'}) eq 'HASH') {
if (keys(%{$changes{'spares'}}) > 0) {
$savespares = 1;
}
}
} else {
$savespares = 1;
}
foreach my $offload ('offloadnow','offloadoth') {
if (ref($domconfig{'usersessions'}{$offload}) eq 'HASH') {
foreach my $lonhost (keys(%{$domconfig{'usersessions'}{$offload}})) {
unless ($defaultshash{'usersessions'}{$offload}{$lonhost}) {
$changes{$offload} = 1;
last;
}
}
unless ($changes{$offload}) {
foreach my $lonhost (keys(%{$defaultshash{'usersessions'}{$offload}})) {
unless ($domconfig{'usersessions'}{$offload}{$lonhost}) {
$changes{$offload} = 1;
last;
}
}
}
} else {
if (($offload eq 'offloadnow') && (@okoffload)) {
$changes{'offloadnow'} = 1;
}
if (($offload eq 'offloadoth') && (@okoffloadoth)) {
$changes{'offloadoth'} = 1;
}
}
}
} else {
if (@okoffload) {
$changes{'offloadnow'} = 1;
}
if (@okoffloadoth) {
$changes{'offloadoth'} = 1;
}
}
my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.');
if ((keys(%changes) > 0) || ($savespares)) {
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
$dom);
if ($putresult eq 'ok') {
if (ref($defaultshash{'usersessions'}) eq 'HASH') {
if (ref($defaultshash{'usersessions'}{'remote'}) eq 'HASH') {
$domdefaults{'remotesessions'} = $defaultshash{'usersessions'}{'remote'};
}
if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') {
$domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'};
}
if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {
$domdefaults{'offloadnow'} = $defaultshash{'usersessions'}{'offloadnow'};
}
if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') {
$domdefaults{'offloadoth'} = $defaultshash{'usersessions'}{'offloadoth'};
}
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
&Apache::lonnet::do_cache_new('usersessions',$dom,$defaultshash{'usersessions'},3600);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
$lastactref->{'usersessions'} = 1;
}
if (keys(%changes) > 0) {
my %lt = &usersession_titles();
$resulttext = &mt('Changes made:').'<ul>';
foreach my $prefix (@prefixes) {
if (ref($changes{$prefix}) eq 'HASH') {
$resulttext .= '<li>'.$lt{$prefix}.'<ul>';
if ($prefix eq 'spares') {
if (ref($changes{$prefix}) eq 'HASH') {
foreach my $lonhost (sort(keys(%{$changes{$prefix}}))) {
$resulttext .= '<li><b>'.$lonhost.'</b> ';
my $lonhostdom = &Apache::lonnet::host_domain($lonhost);
my $cachekey = &escape('spares').':'.&escape($lonhostdom);
&Apache::lonnet::remote_devalidate_cache($lonhost,[$cachekey]);
if (ref($changes{$prefix}{$lonhost}) eq 'HASH') {
foreach my $type (@{$types{$prefix}}) {
if ($changes{$prefix}{$lonhost}{$type}) {
my $offloadto = &mt('None');
if (ref($defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}) eq 'ARRAY') {
if (@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}} > 0) {
$offloadto = join(', ',@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}});
}
}
$resulttext .= &mt('[_1] set to: [_2].','<i>'.$lt{$type}.'</i>',$offloadto).(' 'x3);
}
}
}
$resulttext .= '</li>';
}
}
} else {
foreach my $type (@{$types{$prefix}}) {
if (defined($changes{$prefix}{$type})) {
my ($newvalue,$notinuse);
if (ref($defaultshash{'usersessions'}) eq 'HASH') {
if (ref($defaultshash{'usersessions'}{$prefix})) {
if ($type eq 'version') {
$newvalue = $defaultshash{'usersessions'}{$prefix}{$type};
} else {
if (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {
$newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});
}
} else {
$notinuse = 1;
}
}
}
}
if ($newvalue eq '') {
if ($type eq 'version') {
$resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';
} elsif ($notinuse) {
$resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
}
} else {
if ($type eq 'version') {
$newvalue .= ' '.&mt('(or later)');
}
$resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
}
}
}
}
$resulttext .= '</ul>';
}
}
if ($changes{'offloadnow'}) {
if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') {
if (keys(%{$defaultshash{'usersessions'}{'offloadnow'}}) > 0) {
$resulttext .= '<li>'.&mt('Switch any active user on next access, for server(s):').'<ul>';
foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadnow'}}))) {
$resulttext .= '<li>'.$lonhost.'</li>';
}
$resulttext .= '</ul>';
} else {
$resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.');
}
} else {
$resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.').'</li>';
}
}
if ($changes{'offloadoth'}) {
if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') {
if (keys(%{$defaultshash{'usersessions'}{'offloadoth'}}) > 0) {
$resulttext .= '<li>'.&mt('Switch other institutions on next access, for server(s):').'<ul>';
foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadoth'}}))) {
$resulttext .= '<li>'.$lonhost.'</li>';
}
$resulttext .= '</ul>';
} else {
$resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.');
}
} else {
$resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.').'</li>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = $nochgmsg;
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} else {
$resulttext = $nochgmsg;
}
return $resulttext;
}
sub modify_ssl {
my ($dom,$lastactref,%domconfig) = @_;
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my @locations = sort(keys(%by_location));
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my (%defaultshash,%changes);
my $action = 'ssl';
my @prefixes = ('connto','connfrom','replication');
foreach my $prefix (@prefixes) {
$defaultshash{$action}{$prefix} = {};
}
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my $resulttext;
my %iphost = &Apache::lonnet::get_iphost();
my @reptypes = ('certreq','nocertreq');
my @connecttypes = ('dom','intdom','other');
my %types = (
connto => \@connecttypes,
connfrom => \@connecttypes,
replication => \@reptypes,
);
foreach my $prefix (sort(keys(%types))) {
foreach my $type (@{$types{$prefix}}) {
if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
my $value = 'yes';
if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) {
$value = $env{'form.'.$prefix.'_'.$type};
}
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
if ($domconfig{$action}{$prefix}{$type} ne '') {
if ($value ne $domconfig{$action}{$prefix}{$type}) {
$changes{$prefix}{$type} = 1;
}
$defaultshash{$action}{$prefix}{$type} = $value;
} else {
$defaultshash{$action}{$prefix}{$type} = $value;
$changes{$prefix}{$type} = 1;
}
} else {
$defaultshash{$action}{$prefix}{$type} = $value;
$changes{$prefix}{$type} = 1;
}
} else {
$defaultshash{$action}{$prefix}{$type} = $value;
$changes{$prefix}{$type} = 1;
}
if (($type eq 'dom') && (keys(%servers) == 1)) {
delete($changes{$prefix}{$type});
} elsif (($type eq 'intdom') && (@instdoms == 1)) {
delete($changes{$prefix}{$type});
} elsif (($type eq 'other') && (keys(%by_location) == 0)) {
delete($changes{$prefix}{$type});
}
} elsif ($prefix eq 'replication') {
if (@locations > 0) {
my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
my @okvals;
foreach my $val (@vals) {
if ($val =~ /:/) {
my @items = split(/:/,$val);
foreach my $item (@items) {
if (ref($by_location{$item}) eq 'ARRAY') {
push(@okvals,$item);
}
}
} else {
if (ref($by_location{$val}) eq 'ARRAY') {
push(@okvals,$val);
}
}
}
@okvals = sort(@okvals);
if (ref($domconfig{$action}) eq 'HASH') {
if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
if (ref($domconfig{$action}{$prefix}{$type}) eq 'ARRAY') {
if ($inuse == 0) {
$changes{$prefix}{$type} = 1;
} else {
$defaultshash{$action}{$prefix}{$type} = \@okvals;
my @changed = &Apache::loncommon::compare_arrays($domconfig{$action}{$prefix}{$type},$defaultshash{$action}{$prefix}{$type});
if (@changed > 0) {
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{$action}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{$action}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{$action}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
}
}
}
}
if (keys(%changes)) {
foreach my $prefix (keys(%changes)) {
if (ref($changes{$prefix}) eq 'HASH') {
if (scalar(keys(%{$changes{$prefix}})) == 0) {
delete($changes{$prefix});
}
} else {
delete($changes{$prefix});
}
}
}
my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings');
if (keys(%changes) > 0) {
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
$dom);
if ($putresult eq 'ok') {
if (ref($defaultshash{$action}) eq 'HASH') {
if (ref($defaultshash{$action}{'replication'}) eq 'HASH') {
$domdefaults{'replication'} = $defaultshash{$action}{'replication'};
}
if (ref($defaultshash{$action}{'connto'}) eq 'HASH') {
$domdefaults{'connto'} = $defaultshash{$action}{'connto'};
}
if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') {
$domdefaults{'connfrom'} = $defaultshash{$action}{'connfrom'};
}
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
}
if (keys(%changes) > 0) {
my %titles = &ssl_titles();
$resulttext = &mt('Changes made:').'<ul>';
foreach my $prefix (@prefixes) {
if (ref($changes{$prefix}) eq 'HASH') {
$resulttext .= '<li>'.$titles{$prefix}.'<ul>';
foreach my $type (@{$types{$prefix}}) {
if (defined($changes{$prefix}{$type})) {
my ($newvalue,$notinuse);
if (ref($defaultshash{$action}) eq 'HASH') {
if (ref($defaultshash{$action}{$prefix})) {
if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
$newvalue = $titles{$defaultshash{$action}{$prefix}{$type}};
} else {
if (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') {
if (@{$defaultshash{$action}{$prefix}{$type}} > 0) {
$newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}});
}
} else {
$notinuse = 1;
}
}
}
if ($notinuse) {
$resulttext .= '<li>'.&mt('[_1] set to: not in use',$titles{$type}).'</li>';
} elsif ($newvalue eq '') {
$resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>';
}
}
}
}
$resulttext .= '</ul>';
}
}
} else {
$resulttext = $nochgmsg;
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} else {
$resulttext = $nochgmsg;
}
return $resulttext;
}
sub modify_trust {
my ($dom,$lastactref,%domconfig) = @_;
my (%by_ip,%by_location,@intdoms,@instdoms);
&build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
my @locations = sort(keys(%by_location));
my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg);
my @types = ('exc','inc');
my (%defaultshash,%changes);
foreach my $prefix (@prefixes) {
$defaultshash{'trust'}{$prefix} = {};
}
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my $resulttext;
foreach my $prefix (@prefixes) {
foreach my $type (@types) {
my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
my @okvals;
foreach my $val (@vals) {
if ($val =~ /:/) {
my @items = split(/:/,$val);
foreach my $item (@items) {
if (ref($by_location{$item}) eq 'ARRAY') {
push(@okvals,$item);
}
}
} else {
if (ref($by_location{$val}) eq 'ARRAY') {
push(@okvals,$val);
}
}
}
@okvals = sort(@okvals);
if (ref($domconfig{'trust'}) eq 'HASH') {
if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') {
if (ref($domconfig{'trust'}{$prefix}{$type}) eq 'ARRAY') {
if ($inuse == 0) {
$changes{$prefix}{$type} = 1;
} else {
$defaultshash{'trust'}{$prefix}{$type} = \@okvals;
my @changed = &Apache::loncommon::compare_arrays($domconfig{'trust'}{$prefix}{$type},$defaultshash{'trust'}{$prefix}{$type});
if (@changed > 0) {
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{'trust'}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{'trust'}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
} else {
if ($inuse == 1) {
$defaultshash{'trust'}{$prefix}{$type} = \@okvals;
$changes{$prefix}{$type} = 1;
}
}
}
}
my $nochgmsg = &mt('No changes made to trust settings.');
if (keys(%changes) > 0) {
my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
$dom);
if ($putresult eq 'ok') {
if (ref($defaultshash{'trust'}) eq 'HASH') {
foreach my $prefix (@prefixes) {
if (ref($defaultshash{'trust'}{$prefix}) eq 'HASH') {
$domdefaults{'trust'.$prefix} = $defaultshash{'trust'}{$prefix};
}
}
}
my $cachetime = 24*60*60;
&Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
&Apache::lonnet::do_cache_new('trust',$dom,$defaultshash{'trust'},3600);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domdefaults'} = 1;
$lastactref->{'trust'} = 1;
}
if (keys(%changes) > 0) {
my %lt = &trust_titles();
$resulttext = &mt('Changes made:').'<ul>';
foreach my $prefix (@prefixes) {
if (ref($changes{$prefix}) eq 'HASH') {
$resulttext .= '<li>'.$lt{$prefix}.'<ul>';
foreach my $type (@types) {
if (defined($changes{$prefix}{$type})) {
my ($newvalue,$notinuse);
if (ref($defaultshash{'trust'}) eq 'HASH') {
if (ref($defaultshash{'trust'}{$prefix})) {
if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') {
if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) {
$newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}});
}
} else {
$notinuse = 1;
}
}
}
if ($notinuse) {
$resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
} elsif ($newvalue eq '') {
$resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
} else {
$resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
}
}
}
$resulttext .= '</ul>';
}
}
$resulttext .= '</ul>';
} else {
$resulttext = $nochgmsg;
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} else {
$resulttext = $nochgmsg;
}
return $resulttext;
}
sub modify_loadbalancing {
my ($dom,%domconfig) = @_;
my $primary_id = &Apache::lonnet::domain($dom,'primary');
my $intdom = &Apache::lonnet::internet_dom($primary_id);
my ($othertitle,$usertypes,$types) =
&Apache::loncommon::sorted_inst_types($dom);
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %libraryservers = &Apache::lonnet::get_servers($dom,'library');
my @sparestypes = ('primary','default');
my %typetitles = &sparestype_titles();
my $resulttext;
my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);
if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
%existing = %{$domconfig{'loadbalancing'}};
}
&get_loadbalancers_config(\%servers,\%existing,\%currbalancer,
\%currtargets,\%currrules,\%currcookies);
my ($saveloadbalancing,%defaultshash,%changes);
my ($alltypes,$othertypes,$titles) =
&loadbalancing_titles($dom,$intdom,$usertypes,$types);
my %ruletitles = &offloadtype_text();
my @deletions = &Apache::loncommon::get_env_multiple('form.loadbalancing_delete');
for (my $i=0; $i<$env{'form.loadbalancing_total'}; $i++) {
my $balancer = $env{'form.loadbalancing_lonhost_'.$i};
if ($balancer eq '') {
next;
}
if (!exists($servers{$balancer})) {
if (exists($currbalancer{$balancer})) {
push(@{$changes{'delete'}},$balancer);
}
next;
}
if ((@deletions > 0) && (grep(/^\Q$i\E$/,@deletions))) {
push(@{$changes{'delete'}},$balancer);
next;
}
if (!exists($currbalancer{$balancer})) {
push(@{$changes{'add'}},$balancer);
}
$defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'} = [];
$defaultshash{'loadbalancing'}{$balancer}{'targets'}{'default'} = [];
$defaultshash{'loadbalancing'}{$balancer}{'rules'} = {};
unless (ref($domconfig{'loadbalancing'}) eq 'HASH') {
$saveloadbalancing = 1;
}
foreach my $sparetype (@sparestypes) {
my @targets = &Apache::loncommon::get_env_multiple('form.loadbalancing_target_'.$i.'_'.$sparetype);
my @offloadto;
foreach my $target (@targets) {
if (($servers{$target}) && ($target ne $balancer)) {
if ($sparetype eq 'default') {
if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'}) eq 'ARRAY') {
next if (grep(/^\Q$target\E$/,@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'}}));
}
}
unless(grep(/^\Q$target\E$/,@offloadto)) {
push(@offloadto,$target);
}
}
}
if ($env{'form.loadbalancing_target_'.$i.'_hosthere'} eq $sparetype) {
unless(grep(/^\Q$balancer\E$/,@offloadto)) {
push(@offloadto,$balancer);
}
}
$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto;
}
if ($env{'form.loadbalancing_cookie_'.$i}) {
$defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1;
if (exists($currbalancer{$balancer})) {
unless ($currcookies{$balancer}) {
$changes{'curr'}{$balancer}{'cookie'} = 1;
}
}
} elsif (exists($currbalancer{$balancer})) {
if ($currcookies{$balancer}) {
$changes{'curr'}{$balancer}{'cookie'} = 1;
}
}
if (ref($currtargets{$balancer}) eq 'HASH') {
foreach my $sparetype (@sparestypes) {
if (ref($currtargets{$balancer}{$sparetype}) eq 'ARRAY') {
my @targetdiffs = &Apache::loncommon::compare_arrays($currtargets{$balancer}{$sparetype},$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype});
if (@targetdiffs > 0) {
$changes{'curr'}{$balancer}{'targets'} = 1;
}
} elsif (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {
if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) {
$changes{'curr'}{$balancer}{'targets'} = 1;
}
}
}
} else {
if (ref($defaultshash{'loadbalancing'}{$balancer}) eq 'HASH') {
foreach my $sparetype (@sparestypes) {
if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {
if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) {
$changes{'curr'}{$balancer}{'targets'} = 1;
}
}
}
}
}
my $ishomedom;
if (&Apache::lonnet::host_domain($balancer) eq $dom) {
$ishomedom = 1;
}
if (ref($alltypes) eq 'ARRAY') {
foreach my $type (@{$alltypes}) {
my $rule;
unless ((($type eq '_LC_external') || ($type eq '_LC_internetdom')) &&
(!$ishomedom)) {
$rule = $env{'form.loadbalancing_rules_'.$i.'_'.$type};
}
if ($rule eq 'specific') {
my $specifiedhost = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type};
if (exists($servers{$specifiedhost})) {
$rule = $specifiedhost;
}
}
$defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type} = $rule;
if (ref($currrules{$balancer}) eq 'HASH') {
if ($rule ne $currrules{$balancer}{$type}) {
$changes{'curr'}{$balancer}{'rules'}{$type} = 1;
}
} elsif ($rule ne '') {
$changes{'curr'}{$balancer}{'rules'}{$type} = 1;
}
}
}
}
my $nochgmsg = &mt('No changes made to Load Balancer settings.');
if ((keys(%changes) > 0) || ($saveloadbalancing)) {
unless (ref($defaultshash{'loadbalancing'}) eq 'HASH') {
$defaultshash{'loadbalancing'} = {};
}
my $putresult = &Apache::lonnet::put_dom('configuration',
\%defaultshash,$dom);
if ($putresult eq 'ok') {
if (keys(%changes) > 0) {
my %toupdate;
if (ref($changes{'delete'}) eq 'ARRAY') {
foreach my $balancer (sort(@{$changes{'delete'}})) {
$resulttext .= '<li>'.&mt('Load Balancing discontinued for: [_1]',$balancer).'</li>';
$toupdate{$balancer} = 1;
}
}
if (ref($changes{'add'}) eq 'ARRAY') {
foreach my $balancer (sort(@{$changes{'add'}})) {
$resulttext .= '<li>'.&mt('Load Balancing enabled for: [_1]',$balancer);
$toupdate{$balancer} = 1;
}
}
if (ref($changes{'curr'}) eq 'HASH') {
foreach my $balancer (sort(keys(%{$changes{'curr'}}))) {
$toupdate{$balancer} = 1;
if (ref($changes{'curr'}{$balancer}) eq 'HASH') {
if ($changes{'curr'}{$balancer}{'targets'}) {
my %offloadstr;
foreach my $sparetype (@sparestypes) {
if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {
if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) {
$offloadstr{$sparetype} = join(', ',@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}});
}
}
}
if (keys(%offloadstr) == 0) {
$resulttext .= '<li>'.&mt("Servers to which Load Balance server offloads set to 'None', by default").'</li>';
} else {
my $showoffload;
foreach my $sparetype (@sparestypes) {
$showoffload .= '<i>'.$typetitles{$sparetype}.'</i>: ';
if (defined($offloadstr{$sparetype})) {
$showoffload .= $offloadstr{$sparetype};
} else {
$showoffload .= &mt('None');
}
$showoffload .= (' 'x3);
}
$resulttext .= '<li>'.&mt('By default, Load Balancer: [_1] set to offload to - [_2]',$balancer,$showoffload).'</li>';
}
}
}
if (ref($changes{'curr'}{$balancer}{'rules'}) eq 'HASH') {
if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) {
foreach my $type (@{$alltypes}) {
if ($changes{'curr'}{$balancer}{'rules'}{$type}) {
my $rule = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type};
my $balancetext;
if ($rule eq '') {
$balancetext = $ruletitles{'default'};
} elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') ||
($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {
if (($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) {
foreach my $sparetype (@sparestypes) {
if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') {
map { $toupdate{$_} = 1; } (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}});
}
}
foreach my $item (@{$alltypes}) {
next if ($item =~ /^_LC_ipchange/);
my $hasrule = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$item};
if ($hasrule eq 'homeserver') {
map { $toupdate{$_} = 1; } (keys(%libraryservers));
} else {
unless (($hasrule eq 'default') || ($hasrule eq 'none') || ($hasrule eq 'externalbalancer')) {
if ($servers{$hasrule}) {
$toupdate{$hasrule} = 1;
}
}
}
}
if (($rule eq 'balancer') || ($rule eq 'offloadedto')) {
$balancetext = $ruletitles{$rule};
} else {
my $receiver = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type};
$balancetext = $ruletitles{'particular'}.' '.$receiver;
if ($receiver) {
$toupdate{$receiver};
}
}
} else {
$balancetext = $ruletitles{$rule};
}
} else {
$balancetext = &mt('offload to [_1]',$defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type});
}
$resulttext .= '<li>'.&mt('Load Balancer: [_1] -- balancing for [_2] set to - "[_3]"',$balancer,$titles->{$type},$balancetext).'</li>';
}
}
}
}
if ($changes{'curr'}{$balancer}{'cookie'}) {
if ($currcookies{$balancer}) {
$resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use disabled',
$balancer).'</li>';
} else {
$resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled',
$balancer).'</li>';
}
}
}
}
if (keys(%toupdate)) {
my %thismachine;
my $updatedhere;
my $cachetime = 60*60*24;
map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
foreach my $lonhost (keys(%toupdate)) {
if ($thismachine{$lonhost}) {
unless ($updatedhere) {
&Apache::lonnet::do_cache_new('loadbalancing',$dom,
$defaultshash{'loadbalancing'},
$cachetime);
$updatedhere = 1;
}
} else {
my $cachekey = &escape('loadbalancing').':'.&escape($dom);
&Apache::lonnet::remote_devalidate_cache($lonhost,[$cachekey]);
}
}
}
if ($resulttext ne '') {
$resulttext = &mt('Changes made:').'<ul>'.$resulttext.'</ul>';
} else {
$resulttext = $nochgmsg;
}
} else {
$resulttext = $nochgmsg;
}
} else {
$resulttext = '<span class="LC_error">'.
&mt('An error occurred: [_1]',$putresult).'</span>';
}
} else {
$resulttext = $nochgmsg;
}
return $resulttext;
}
sub recurse_check {
my ($chkcats,$categories,$depth,$name) = @_;
if (ref($chkcats->[$depth]{$name}) eq 'ARRAY') {
my $chg = 0;
for (my $j=0; $j<@{$chkcats->[$depth]{$name}}; $j++) {
my $category = $chkcats->[$depth]{$name}[$j];
my $item;
if ($category eq '') {
$chg ++;
} else {
my $deeper = $depth + 1;
$item = &escape($category).':'.&escape($name).':'.$depth;
if ($chg) {
$categories->{$item} -= $chg;
}
&recurse_check($chkcats,$categories,$deeper,$category);
$deeper --;
}
}
}
return;
}
sub recurse_cat_deletes {
my ($item,$coursecategories,$deletions) = @_;
my ($deleted,$container,$depth) = map { &unescape($_); } split(/:/,$item);
my $subdepth = $depth + 1;
if (ref($coursecategories) eq 'HASH') {
foreach my $subitem (keys(%{$coursecategories})) {
my ($child,$parent,$itemdepth) = map { &unescape($_); } split(/:/,$subitem);
if (($parent eq $deleted) && ($itemdepth == $subdepth)) {
delete($coursecategories->{$subitem});
$deletions->{$subitem} = 1;
&recurse_cat_deletes($subitem,$coursecategories,$deletions);
}
}
}
return;
}
sub active_dc_picker {
my ($dom,$numinrow,$inputtype,$name,%currhash) = @_;
my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
my @domcoord = keys(%domcoords);
if (keys(%currhash)) {
foreach my $dc (keys(%currhash)) {
unless (exists($domcoords{$dc})) {
push(@domcoord,$dc);
}
}
}
@domcoord = sort(@domcoord);
my $numdcs = scalar(@domcoord);
my $rows = 0;
my $table;
if ($numdcs > 1) {
$table = '<table>';
for (my $i=0; $i<@domcoord; $i++) {
my $rem = $i%($numinrow);
if ($rem == 0) {
if ($i > 0) {
$table .= '</tr>';
}
$table .= '<tr>';
$rows ++;
}
my $check = '';
if ($inputtype eq 'radio') {
if (keys(%currhash) == 0) {
if (!$i) {
$check = ' checked="checked"';
}
} elsif (exists($currhash{$domcoord[$i]})) {
$check = ' checked="checked"';
}
} else {
if (exists($currhash{$domcoord[$i]})) {
$check = ' checked="checked"';
}
}
if ($i == @domcoord - 1) {
my $colsleft = $numinrow - $rem;
if ($colsleft > 1) {
$table .= '<td class="LC_left_item" colspan="'.$colsleft.'">';
} else {
$table .= '<td class="LC_left_item">';
}
} else {
$table .= '<td class="LC_left_item">';
}
my ($dcname,$dcdom) = split(':',$domcoord[$i]);
my $user = &Apache::loncommon::plainname($dcname,$dcdom);
$table .= '<span class="LC_nobreak"><label>'.
'<input type="'.$inputtype.'" name="'.$name.'"'.
' value="'.$domcoord[$i].'"'.$check.' />'.$user;
if ($user ne $dcname.':'.$dcdom) {
$table .= ' ('.$dcname.':'.$dcdom.')';
}
$table .= '</label></span></td>';
}
$table .= '</tr></table>';
} elsif ($numdcs == 1) {
my ($dcname,$dcdom) = split(':',$domcoord[0]);
my $user = &Apache::loncommon::plainname($dcname,$dcdom);
if ($inputtype eq 'radio') {
$table = '<input type="hidden" name="'.$name.'" value="'.$domcoord[0].'" />'.$user;
if ($user ne $dcname.':'.$dcdom) {
$table .= ' ('.$dcname.':'.$dcdom.')';
}
} else {
my $check;
if (exists($currhash{$domcoord[0]})) {
$check = ' checked="checked"';
}
$table = '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="'.$name.'" '.
'value="'.$domcoord[0].'"'.$check.' />'.$user;
if ($user ne $dcname.':'.$dcdom) {
$table .= ' ('.$dcname.':'.$dcdom.')';
}
$table .= '</label></span>';
$rows ++;
}
}
return ($numdcs,$table,$rows);
}
sub usersession_titles {
return &Apache::lonlocal::texthash(
hosted => 'Hosting of sessions for users from other domains on servers in this domain',
remote => 'Hosting of sessions for users in this domain on servers in other domains',
spares => 'Servers offloaded to, when busy',
version => 'LON-CAPA version requirement',
excludedomain => 'Allow all, but exclude specific domains',
includedomain => 'Deny all, but include specific domains',
primary => 'Primary (checked first)',
default => 'Default',
);
}
sub id_for_thisdom {
my (%servers) = @_;
my %altids;
foreach my $server (keys(%servers)) {
my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
if ($serverhome ne $server) {
$altids{$serverhome} = $server;
}
}
return %altids;
}
sub count_servers {
my ($currbalancer,%servers) = @_;
my (@spares,$numspares);
foreach my $lonhost (sort(keys(%servers))) {
next if ($currbalancer eq $lonhost);
push(@spares,$lonhost);
}
if ($currbalancer) {
$numspares = scalar(@spares);
} else {
$numspares = scalar(@spares) - 1;
}
return ($numspares,@spares);
}
sub lonbalance_targets_js {
my ($dom,$types,$servers,$settings) = @_;
my $select = &mt('Select');
my ($alltargets,$allishome,$allinsttypes,@alltypes);
if (ref($servers) eq 'HASH') {
$alltargets = join("','",sort(keys(%{$servers})));
my @homedoms;
foreach my $server (sort(keys(%{$servers}))) {
if (&Apache::lonnet::host_domain($server) eq $dom) {
push(@homedoms,'1');
} else {
push(@homedoms,'0');
}
}
$allishome = join("','",@homedoms);
}
if (ref($types) eq 'ARRAY') {
if (@{$types} > 0) {
@alltypes = @{$types};
}
}
push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external');
$allinsttypes = join("','",@alltypes);
my (%currbalancer,%currtargets,%currrules,%existing,%currcookies);
if (ref($settings) eq 'HASH') {
%existing = %{$settings};
}
&get_loadbalancers_config($servers,\%existing,\%currbalancer,
\%currtargets,\%currrules,\%currcookies);
my $balancers = join("','",sort(keys(%currbalancer)));
return <<"END";
<script type="text/javascript">
// <![CDATA[
currBalancers = new Array('$balancers');
function toggleTargets(balnum) {
var lonhostitem = document.getElementById('loadbalancing_lonhost_'+balnum);
var prevhostitem = document.getElementById('loadbalancing_prevlonhost_'+balnum);
var balancer = lonhostitem.options[lonhostitem.selectedIndex].value;
var prevbalancer = prevhostitem.value;
var baltotal = document.getElementById('loadbalancing_total').value;
prevhostitem.value = balancer;
if (prevbalancer != '') {
var prevIdx = currBalancers.indexOf(prevbalancer);
if (prevIdx != -1) {
currBalancers.splice(prevIdx,1);
}
}
if (balancer == '') {
hideSpares(balnum);
} else {
var currIdx = currBalancers.indexOf(balancer);
if (currIdx == -1) {
currBalancers.push(balancer);
}
var homedoms = new Array('$allishome');
var ishomedom = homedoms[lonhostitem.selectedIndex];
showSpares(balancer,ishomedom,balnum);
}
balancerChange(balnum,baltotal,'change',prevbalancer,balancer);
return;
}
function showSpares(balancer,ishomedom,balnum) {
var alltargets = new Array('$alltargets');
var insttypes = new Array('$allinsttypes');
var offloadtypes = new Array('primary','default');
document.getElementById('loadbalancing_targets_'+balnum).style.display='block';
document.getElementById('loadbalancing_disabled_'+balnum).style.display='none';
for (var i=0; i<offloadtypes.length; i++) {
var count = 0;
for (var j=0; j<alltargets.length; j++) {
if (alltargets[j] != balancer) {
var item = document.getElementById('loadbalancing_target_'+balnum+'_'+offloadtypes[i]+'_'+count);
item.value = alltargets[j];
item.style.textAlign='left';
item.style.textFace='normal';
document.getElementById('loadbalancing_targettxt_'+balnum+'_'+offloadtypes[i]+'_'+count).innerHTML = alltargets[j];
if (currBalancers.indexOf(alltargets[j]) == -1) {
item.disabled = '';
} else {
item.disabled = 'disabled';
item.checked = false;
}
count ++;
}
}
}
for (var k=0; k<insttypes.length; k++) {
if ((insttypes[k] == '_LC_external') || (insttypes[k] == '_LC_internetdom')) {
if (ishomedom == 1) {
document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='block';
document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='block';
} else {
document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='none';
document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='none';
}
} else {
document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='block';
document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='block';
}
if ((insttypes[k] != '_LC_external') &&
((insttypes[k] != '_LC_internetdom') ||
((insttypes[k] == '_LC_internetdom') && (ishomedom == 1)))) {
var item = document.getElementById('loadbalancing_singleserver_'+balnum+'_'+insttypes[k]);
item.options.length = 0;
item.options[0] = new Option("","",true,true);
var idx = 0;
for (var m=0; m<alltargets.length; m++) {
if ((currBalancers.indexOf(alltargets[m]) == -1) && (alltargets[m] != balancer)) {
idx ++;
item.options[idx] = new Option(alltargets[m],alltargets[m],false,false);
}
}
}
}
return;
}
function hideSpares(balnum) {
var alltargets = new Array('$alltargets');
var insttypes = new Array('$allinsttypes');
var offloadtypes = new Array('primary','default');
document.getElementById('loadbalancing_targets_'+balnum).style.display='none';
document.getElementById('loadbalancing_disabled_'+balnum).style.display='block';
var total = alltargets.length - 1;
for (var i=0; i<offloadtypes; i++) {
for (var j=0; j<total; j++) {
document.getElementById('loadbalancing_target_'+balnum+'_'+offloadtypes[i]+'_'+j).checked = false;
document.getElementById('loadbalancing_target_'+balnum+'_'+offloadtypes[i]+'_'+j).value = '';
document.getElementById('loadbalancing_targettxt_'+balnum+'_'+offloadtypes[i]+'_'+j).innerHTML = '';
}
}
for (var k=0; k<insttypes.length; k++) {
document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='none';
document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='none';
if (insttypes[k] != '_LC_external') {
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+insttypes[k]).length = 0;
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+insttypes[k]).options[0] = new Option("","",true,true);
}
}
return;
}
function checkOffloads(item,balnum,type) {
var alltargets = new Array('$alltargets');
var offloadtypes = new Array('primary','default');
if (item.checked) {
var total = alltargets.length - 1;
var other;
if (type == offloadtypes[0]) {
other = offloadtypes[1];
} else {
other = offloadtypes[0];
}
for (var i=0; i<total; i++) {
var server = document.getElementById('loadbalancing_target_'+balnum+'_'+other+'_'+i).value;
if (server == item.value) {
if (document.getElementById('loadbalancing_target_'+balnum+'_'+other+'_'+i).checked) {
document.getElementById('loadbalancing_target_'+balnum+'_'+other+'_'+i).checked = false;
}
}
}
}
return;
}
function singleServerToggle(balnum,type) {
var offloadtoSelIdx = document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).selectedIndex;
if (offloadtoSelIdx == 0) {
document.getElementById('loadbalancing_rules_'+balnum+'_'+type+'_0').checked = true;
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = '';
} else {
document.getElementById('loadbalancing_rules_'+balnum+'_'+type+'_2').checked = true;
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = '$select';
}
return;
}
function balanceruleChange(formname,balnum,type) {
if (type == '_LC_external') {
return;
}
var typesRules = getIndicesByName(formname,'loadbalancing_rules_'+balnum+'_'+type);
for (var i=0; i<typesRules.length; i++) {
if (formname.elements[typesRules[i]].checked) {
if (formname.elements[typesRules[i]].value != 'specific') {
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).selectedIndex = 0;
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = '';
} else {
document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = '$select';
}
}
}
return;
}
function balancerDeleteChange(balnum) {
var hostitem = document.getElementById('loadbalancing_lonhost_'+balnum);
var baltotal = document.getElementById('loadbalancing_total').value;
var addtarget;
var removetarget;
var action = 'delete';
if (document.getElementById('loadbalancing_delete_'+balnum)) {
var lonhost = hostitem.value;
var currIdx = currBalancers.indexOf(lonhost);
if (document.getElementById('loadbalancing_delete_'+balnum).checked) {
if (currIdx != -1) {
currBalancers.splice(currIdx,1);
}
addtarget = lonhost;
} else {
if (currIdx == -1) {
currBalancers.push(lonhost);
}
removetarget = lonhost;
action = 'undelete';
}
balancerChange(balnum,baltotal,action,addtarget,removetarget);
}
return;
}
function balancerChange(balnum,baltotal,action,addtarget,removetarget) {
if (baltotal > 1) {
var offloadtypes = new Array('primary','default');
var alltargets = new Array('$alltargets');
var insttypes = new Array('$allinsttypes');
for (var i=0; i<baltotal; i++) {
if (i != balnum) {
for (var j=0; j<offloadtypes.length; j++) {
var total = alltargets.length - 1;
for (var k=0; k<total; k++) {
var serveritem = document.getElementById('loadbalancing_target_'+i+'_'+offloadtypes[j]+'_'+k);
var server = serveritem.value;
if ((action == 'delete') || (action == 'change' && addtarget != '')) {
if (server == addtarget) {
serveritem.disabled = '';
}
}
if ((action == 'undelete') || (action == 'change' && removetarget != '')) {
if (server == removetarget) {
serveritem.disabled = 'disabled';
serveritem.checked = false;
}
}
}
}
for (var j=0; j<insttypes.length; j++) {
if (insttypes[j] != '_LC_external') {
if (document.getElementById('loadbalancing_singleserver_'+i+'_'+insttypes[j])) {
var singleserver = document.getElementById('loadbalancing_singleserver_'+i+'_'+insttypes[j]);
var currSel = singleserver.selectedIndex;
var currVal = singleserver.options[currSel].value;
if ((action == 'delete') || (action == 'change' && addtarget != '')) {
var numoptions = singleserver.options.length;
var needsnew = 1;
for (var k=0; k<numoptions; k++) {
if (singleserver.options[k] == addtarget) {
needsnew = 0;
break;
}
}
if (needsnew == 1) {
singleserver.options[numoptions] = new Option(addtarget,addtarget,false,false);
}
}
if ((action == 'undelete') || (action == 'change' && removetarget != '')) {
singleserver.options.length = 0;
if ((currVal) && (currVal != removetarget)) {
singleserver.options[0] = new Option("","",false,false);
} else {
singleserver.options[0] = new Option("","",true,true);
}
var idx = 0;
for (var m=0; m<alltargets.length; m++) {
if (currBalancers.indexOf(alltargets[m]) == -1) {
idx ++;
if (currVal == alltargets[m]) {
singleserver.options[idx] = new Option(alltargets[m],alltargets[m],true,true);
} else {
singleserver.options[idx] = new Option(alltargets[m],alltargets[m],false,false);
}
}
}
}
}
}
}
}
}
}
return;
}
// ]]>
</script>
END
}
sub new_spares_js {
my @sparestypes = ('primary','default');
my $types = join("','",@sparestypes);
my $select = &mt('Select');
return <<"END";
<script type="text/javascript">
// <![CDATA[
function updateNewSpares(formname,lonhost) {
var types = new Array('$types');
var include = new Array();
var exclude = new Array();
for (var i=0; i<types.length; i++) {
var spareboxes = getIndicesByName(formname,'spare_'+types[i]+'_'+lonhost);
for (var j=0; j<spareboxes.length; j++) {
if (formname.elements[spareboxes[j]].checked) {
exclude.push(formname.elements[spareboxes[j]].value);
} else {
include.push(formname.elements[spareboxes[j]].value);
}
}
}
for (var i=0; i<types.length; i++) {
var newSpare = document.getElementById('newspare_'+types[i]+'_'+lonhost);
var selIdx = newSpare.selectedIndex;
var currnew = newSpare.options[selIdx].value;
var okSpares = new Array();
for (var j=0; j<newSpare.options.length; j++) {
var possible = newSpare.options[j].value;
if (possible != '') {
if (exclude.indexOf(possible) == -1) {
okSpares.push(possible);
} else {
if (currnew == possible) {
selIdx = 0;
}
}
}
}
for (var k=0; k<include.length; k++) {
if (okSpares.indexOf(include[k]) == -1) {
okSpares.push(include[k]);
}
}
okSpares.sort();
newSpare.options.length = 0;
if (selIdx == 0) {
newSpare.options[0] = new Option("$select","",true,true);
} else {
newSpare.options[0] = new Option("$select","",false,false);
}
for (var m=0; m<okSpares.length; m++) {
var idx = m+1;
var selThis = 0;
if (selIdx != 0) {
if (okSpares[m] == currnew) {
selThis = 1;
}
}
if (selThis == 1) {
newSpare.options[idx] = new Option(okSpares[m],okSpares[m],true,true);
} else {
newSpare.options[idx] = new Option(okSpares[m],okSpares[m],false,false);
}
}
}
return;
}
function checkNewSpares(lonhost,type) {
var newSpare = document.getElementById('newspare_'+type+'_'+lonhost);
var chosen = newSpare.options[newSpare.selectedIndex].value;
if (chosen != '') {
var othertype;
var othernewSpare;
if (type == 'primary') {
othernewSpare = document.getElementById('newspare_default_'+lonhost);
}
if (type == 'default') {
othernewSpare = document.getElementById('newspare_primary_'+lonhost);
}
if (othernewSpare.options[othernewSpare.selectedIndex].value == chosen) {
othernewSpare.selectedIndex = 0;
}
}
return;
}
// ]]>
</script>
END
}
sub common_domprefs_js {
return <<"END";
<script type="text/javascript">
// <![CDATA[
function getIndicesByName(formname,item) {
var group = new Array();
for (var i=0;i<formname.elements.length;i++) {
if (formname.elements[i].name == item) {
group.push(formname.elements[i].id);
}
}
return group;
}
// ]]>
</script>
END
}
sub recaptcha_js {
my %lt = &captcha_phrases();
return <<"END";
<script type="text/javascript">
// <![CDATA[
function updateCaptcha(caller,context) {
var privitem;
var pubitem;
var privtext;
var pubtext;
var versionitem;
var versiontext;
if (document.getElementById(context+'_recaptchapub')) {
pubitem = document.getElementById(context+'_recaptchapub');
} else {
return;
}
if (document.getElementById(context+'_recaptchapriv')) {
privitem = document.getElementById(context+'_recaptchapriv');
} else {
return;
}
if (document.getElementById(context+'_recaptchapubtxt')) {
pubtext = document.getElementById(context+'_recaptchapubtxt');
} else {
return;
}
if (document.getElementById(context+'_recaptchaprivtxt')) {
privtext = document.getElementById(context+'_recaptchaprivtxt');
} else {
return;
}
if (document.getElementById(context+'_recaptchaversion')) {
versionitem = document.getElementById(context+'_recaptchaversion');
} else {
return;
}
if (document.getElementById(context+'_recaptchavertxt')) {
versiontext = document.getElementById(context+'_recaptchavertxt');
} else {
return;
}
if (caller.checked) {
if (caller.value == 'recaptcha') {
pubitem.type = 'text';
privitem.type = 'text';
pubitem.size = '40';
privitem.size = '40';
pubtext.innerHTML = "$lt{'pub'}";
privtext.innerHTML = "$lt{'priv'}";
versionitem.type = 'text';
versionitem.size = '3';
versiontext.innerHTML = "$lt{'ver'}";
} else {
pubitem.type = 'hidden';
privitem.type = 'hidden';
versionitem.type = 'hidden';
pubtext.innerHTML = '';
privtext.innerHTML = '';
versiontext.innerHTML = '';
}
}
return;
}
// ]]>
</script>
END
}
sub toggle_display_js {
return <<"END";
<script type="text/javascript">
// <![CDATA[
function toggleDisplay(domForm,caller) {
if (document.getElementById(caller)) {
var divitem = document.getElementById(caller);
var optionsElement = domForm.coursecredits;
var checkval = 1;
var dispval = 'block';
var selfcreateRegExp = /^cancreate_emailverified/;
if (caller == 'emailoptions') {
optionsElement = domForm.cancreate_email;
}
if (caller == 'studentsubmission') {
optionsElement = domForm.postsubmit;
}
if (caller == 'cloneinstcode') {
optionsElement = domForm.canclone;
checkval = 'instcode';
}
if (selfcreateRegExp.test(caller)) {
optionsElement = domForm.elements[caller];
checkval = 'other';
dispval = 'inline'
}
if (optionsElement.length) {
var currval;
for (var i=0; i<optionsElement.length; i++) {
if (optionsElement[i].checked) {
currval = optionsElement[i].value;
}
}
if (currval == checkval) {
divitem.style.display = dispval;
} else {
divitem.style.display = 'none';
}
}
}
return;
}
// ]]>
</script>
END
}
sub captcha_phrases {
return &Apache::lonlocal::texthash (
priv => 'Private key',
pub => 'Public key',
original => 'original (CAPTCHA)',
recaptcha => 'successor (ReCAPTCHA)',
notused => 'unused',
ver => 'ReCAPTCHA version (1 or 2)',
);
}
sub devalidate_remote_domconfs {
my ($dom,$cachekeys) = @_;
return unless (ref($cachekeys) eq 'HASH');
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my %thismachine;
map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',
'directorysrch','passwdconf','cats','proxyalias','proxysaml',
'ipaccess','trust');
my %cache_by_lonhost;
if (exists($cachekeys->{'samllanding'})) {
if (ref($cachekeys->{'samllanding'}) eq 'HASH') {
my %landing = %{$cachekeys->{'samllanding'}};
my %domservers = &Apache::lonnet::get_servers($dom);
if (keys(%domservers)) {
foreach my $server (keys(%domservers)) {
my @cached;
next if ($thismachine{$server});
if ($landing{$server}) {
push(@cached,&escape('samllanding').':'.&escape($server));
}
if (@cached) {
$cache_by_lonhost{$server} = \@cached;
}
}
}
}
}
if (keys(%servers)) {
foreach my $server (keys(%servers)) {
next if ($thismachine{$server});
my @cached;
foreach my $name (@posscached) {
if ($cachekeys->{$name}) {
if (($name eq 'proxyalias') || ($name eq 'proxysaml')) {
if (ref($cachekeys->{$name}) eq 'HASH') {
foreach my $key (keys(%{$cachekeys->{$name}})) {
push(@cached,&escape($name).':'.&escape($key));
}
}
} else {
push(@cached,&escape($name).':'.&escape($dom));
}
}
}
if ((exists($cache_by_lonhost{$server})) &&
(ref($cache_by_lonhost{$server}) eq 'ARRAY')) {
push(@cached,@{$cache_by_lonhost{$server}});
}
if (@cached) {
&Apache::lonnet::remote_devalidate_cache($server,\@cached);
}
}
}
return;
}
1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>