![]() ![]() | ![]() |
- Wording change and fix typo in rev. 1.357
1: # The LearningOnline Network with CAPA 2: # Handler to set domain-wide configuration settings 3: # 4: # $Id: domainprefs.pm,v 1.416 2022/11/11 02:30:19 raeburn Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 28: # 29: ############################################################### 30: ############################################################### 31: 32: =pod 33: 34: =head1 NAME 35: 36: Apache::domainprefs.pm 37: 38: =head1 SYNOPSIS 39: 40: Handles configuration of a LON-CAPA domain. 41: 42: This is part of the LearningOnline Network with CAPA project 43: described at http://www.lon-capa.org. 44: 45: 46: =head1 OVERVIEW 47: 48: Each institution using LON-CAPA will typically have a single domain designated 49: for use by individuals affiliated with the institution. Accordingly, each domain 50: may define a default set of logos and a color scheme which can be used to "brand" 51: the LON-CAPA instance. In addition, an institution will typically have a language 52: and timezone which are used for the majority of courses. 53: 54: LON-CAPA provides a mechanism to display and modify these defaults, as well as a 55: host of other domain-wide settings which determine the types of functionality 56: available to users and courses in the domain. 57: 58: There is also a mechanism to configure cataloging of courses in the domain, and 59: controls on the operation of automated processes which govern such things as 60: roster updates, user directory updates and processing of course requests. 61: 62: The domain coordination manual which is built dynamically on install/update of 63: LON-CAPA from the relevant help items provides more information about domain 64: configuration. 65: 66: Most of the domain settings are stored in the configuration.db GDBM file which is 67: housed on the primary library server for the domain in /home/httpd/lonUsers/$dom, 68: where $dom is the domain. The configuration.db stores settings in a number of 69: frozen hashes of hashes. In a few cases, domain information must be uploaded to 70: the domain as files (e.g., image files for logos etc., or plain text files for 71: bubblesheet formats). In this case the domainprefs.pm must be running in a user 72: session hosted on the primary library server in the domain, as these files are 73: stored in author space belonging to a special $dom-domainconfig user. 74: 75: domainprefs.pm in combination with lonconfigsettings.pm will retrieve and display 76: the current settings, and provides an interface to make modifications. 77: 78: =head1 SUBROUTINES 79: 80: =over 81: 82: =item print_quotas() 83: 84: Inputs: 4 85: 86: $dom,$settings,$rowtotal,$action. 87: 88: $dom is the domain, $settings is a reference to a hash of current settings for 89: the current context, $rowtotal is a reference to the scalar used to record the 90: number of rows displayed on the page, and $action is the context (quotas, 91: requestcourses or requestauthor). 92: 93: The print_quotas routine was orginally created to display/store information 94: about default quota sizes for portfolio spaces for the different types of 95: institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.), 96: but is now also used to manage availability of user tools: 97: i.e., blogs, aboutme page, and portfolios, and the course request tool, 98: used by course owners to request creation of a course, and to display/store 99: default quota sizes for Authoring Spaces. 100: 101: Outputs: 1 102: 103: $datatable - HTML containing form elements which allow settings to be changed. 104: 105: In the case of course requests, radio buttons are displayed for each institutional 106: affiliate type (and also default, and _LC_adv) for each of the course types 107: (official, unofficial, community, textbook, placement, and lti). 108: In each case the radio buttons allow the selection of one of four values: 109: 110: 0, approval, validate, autolimit=N (where N is blank, or a positive integer). 111: which have the following effects: 112: 113: 0 114: 115: =over 116: 117: - course requests are not allowed for this course types/affiliation 118: 119: =back 120: 121: approval 122: 123: =over 124: 125: - course requests must be approved by a Doman Coordinator in the 126: course's domain 127: 128: =back 129: 130: validate 131: 132: =over 133: 134: - an institutional validation (e.g., check requestor is instructor 135: of record) needs to be passed before the course will be created. The required 136: validation is in localenroll.pm on the primary library server for the course 137: domain. 138: 139: =back 140: 141: autolimit 142: 143: =over 144: 145: - course requests will be processed automatically up to a limit of 146: N requests for the course type for the particular requestor. 147: If N is undefined, there is no limit to the number of course requests 148: which a course owner may submit and have processed automatically. 149: 150: =back 151: 152: =item modify_quotas() 153: 154: =back 155: 156: =cut 157: 158: package Apache::domainprefs; 159: 160: use strict; 161: use Apache::Constants qw(:common :http); 162: use Apache::lonnet; 163: use Apache::loncommon(); 164: use Apache::lonhtmlcommon(); 165: use Apache::lonlocal; 166: use Apache::lonmsg(); 167: use Apache::lonconfigsettings; 168: use Apache::lonuserutils(); 169: use Apache::loncoursequeueadmin(); 170: use LONCAPA qw(:DEFAULT :match); 171: use LONCAPA::Enrollment; 172: use LONCAPA::lonauthcgi(); 173: use LONCAPA::SSL; 174: use File::Copy; 175: use Locale::Language; 176: use DateTime::TimeZone; 177: use DateTime::Locale; 178: use Time::HiRes qw( sleep ); 179: use Net::CIDR; 180: 181: my $registered_cleanup; 182: my $modified_urls; 183: 184: sub handler { 185: my $r=shift; 186: if ($r->header_only) { 187: &Apache::loncommon::content_type($r,'text/html'); 188: $r->send_http_header; 189: return OK; 190: } 191: 192: my $context = 'domain'; 193: my $dom = $env{'request.role.domain'}; 194: my $domdesc = &Apache::lonnet::domain($dom,'description'); 195: if (&Apache::lonnet::allowed('mau',$dom)) { 196: &Apache::loncommon::content_type($r,'text/html'); 197: $r->send_http_header; 198: } else { 199: $env{'user.error.msg'}= 200: "/adm/domainprefs:mau:0:0:Cannot modify domain settings"; 201: return HTTP_NOT_ACCEPTABLE; 202: } 203: 204: $registered_cleanup=0; 205: @{$modified_urls}=(); 206: 207: &Apache::lonhtmlcommon::clear_breadcrumbs(); 208: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, 209: ['phase','actions']); 210: my $phase = 'pickactions'; 211: if ( exists($env{'form.phase'}) ) { 212: $phase = $env{'form.phase'}; 213: } 214: my %servers = &Apache::lonnet::internet_dom_servers($dom); 215: my %domconfig = 216: &Apache::lonnet::get_dom('configuration',['login','rolecolors', 217: 'quotas','autoenroll','autoupdate','autocreate', 218: 'directorysrch','usercreation','usermodification', 219: 'contacts','defaults','scantron','coursecategories', 220: 'serverstatuses','requestcourses','helpsettings', 221: 'coursedefaults','usersessions','loadbalancing', 222: 'requestauthor','selfenrollment','inststatus', 223: 'ltitools','ssl','trust','lti','ltisec','privacy','passwords', 224: 'proctoring','wafproxy','ipaccess'],$dom); 225: my %encconfig = 226: &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1); 227: if (ref($domconfig{'ltitools'}) eq 'HASH') { 228: if (ref($encconfig{'ltitools'}) eq 'HASH') { 229: foreach my $id (keys(%{$domconfig{'ltitools'}})) { 230: if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') && 231: (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) { 232: foreach my $item ('key','secret') { 233: $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item}; 234: } 235: } 236: } 237: } 238: } 239: if (ref($domconfig{'lti'}) eq 'HASH') { 240: if (ref($encconfig{'lti'}) eq 'HASH') { 241: foreach my $id (keys(%{$domconfig{'lti'}})) { 242: if ((ref($domconfig{'lti'}{$id}) eq 'HASH') && 243: (ref($encconfig{'lti'}{$id}) eq 'HASH')) { 244: foreach my $item ('key','secret') { 245: $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item}; 246: } 247: } 248: } 249: } 250: } 251: if (ref($domconfig{'ltisec'}) eq 'HASH') { 252: if (ref($domconfig{'ltisec'}{'linkprot'}) eq 'HASH') { 253: if (ref($encconfig{'linkprot'}) eq 'HASH') { 254: foreach my $id (keys(%{$domconfig{'ltisec'}{'linkprot'}})) { 255: unless ($id =~ /^\d+$/) { 256: delete($domconfig{'ltisec'}{'linkprot'}{$id}); 257: } 258: if ((ref($domconfig{'ltisec'}{'linkprot'}{$id}) eq 'HASH') && 259: (ref($encconfig{'linkprot'}{$id}) eq 'HASH')) { 260: foreach my $item ('key','secret') { 261: $domconfig{'ltisec'}{'linkprot'}{$id}{$item} = $encconfig{'linkprot'}{$id}{$item}; 262: } 263: } 264: } 265: } 266: } 267: } 268: if (ref($domconfig{'proctoring'}) eq 'HASH') { 269: if (ref($encconfig{'proctoring'}) eq 'HASH') { 270: foreach my $provider (keys(%{$domconfig{'proctoring'}})) { 271: if ((ref($domconfig{'proctoring'}{$provider}) eq 'HASH') && 272: (ref($encconfig{'proctoring'}{$provider}) eq 'HASH')) { 273: foreach my $item ('key','secret') { 274: $domconfig{'proctoring'}{$provider}{$item} = $encconfig{'proctoring'}{$provider}{$item}; 275: } 276: } 277: } 278: } 279: } 280: my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords', 281: 'quotas','autoenroll','autoupdate','autocreate','directorysrch', 282: 'contacts','privacy','usercreation','selfcreation', 283: 'usermodification','scantron','requestcourses','requestauthor', 284: 'coursecategories','serverstatuses','helpsettings','coursedefaults', 285: 'ltitools','proctoring','selfenrollment','usersessions','ssl', 286: 'trust','lti'); 287: my %existing; 288: if (ref($domconfig{'loadbalancing'}) eq 'HASH') { 289: %existing = %{$domconfig{'loadbalancing'}}; 290: } 291: if ((keys(%servers) > 1) || (keys(%existing) > 0)) { 292: push(@prefs_order,'loadbalancing'); 293: } 294: my %prefs = ( 295: 'rolecolors' => 296: { text => 'Default color schemes', 297: help => 'Domain_Configuration_Color_Schemes', 298: header => [{col1 => 'Student Settings', 299: col2 => '',}, 300: {col1 => 'Coordinator Settings', 301: col2 => '',}, 302: {col1 => 'Author Settings', 303: col2 => '',}, 304: {col1 => 'Administrator Settings', 305: col2 => '',}], 306: print => \&print_rolecolors, 307: modify => \&modify_rolecolors, 308: }, 309: 'login' => 310: { text => 'Log-in page options', 311: help => 'Domain_Configuration_Login_Page', 312: header => [{col1 => 'Log-in Page Items', 313: col2 => '',}, 314: {col1 => 'Log-in Help', 315: col2 => 'Value'}, 316: {col1 => 'Custom HTML in document head', 317: col2 => 'Value'}, 318: {col1 => 'SSO', 319: col2 => 'Dual login: SSO and non-SSO options'}, 320: ], 321: print => \&print_login, 322: modify => \&modify_login, 323: }, 324: 'defaults' => 325: { text => 'Default authentication/language/timezone/portal/types', 326: help => 'Domain_Configuration_LangTZAuth', 327: header => [{col1 => 'Setting', 328: col2 => 'Value'}, 329: {col1 => 'Institutional user types', 330: col2 => 'Name displayed'}, 331: {col1 => 'Mapping for missing usernames via standard log-in', 332: col2 => 'Rules in use'}], 333: print => \&print_defaults, 334: modify => \&modify_defaults, 335: }, 336: 'wafproxy' => 337: { text => 'Web Application Firewall/Reverse Proxy', 338: help => 'Domain_Configuration_WAF_Proxy', 339: header => [{col1 => 'Domain(s)', 340: col2 => 'Servers and WAF/Reverse Proxy alias(es)', 341: }, 342: {col1 => 'Domain(s)', 343: col2 => 'WAF Configuration',}], 344: print => \&print_wafproxy, 345: modify => \&modify_wafproxy, 346: }, 347: 'passwords' => 348: { text => 'Passwords (Internal authentication)', 349: help => 'Domain_Configuration_Passwords', 350: header => [{col1 => 'Resetting Forgotten Password', 351: col2 => 'Settings'}, 352: {col1 => 'Encryption of Stored Passwords (Internal Auth)', 353: col2 => 'Settings'}, 354: {col1 => 'Rules for LON-CAPA Passwords', 355: col2 => 'Settings'}, 356: {col1 => 'Course Owner Changing Student Passwords', 357: col2 => 'Settings'}], 358: print => \&print_passwords, 359: modify => \&modify_passwords, 360: }, 361: 'quotas' => 362: { text => 'Blogs, personal pages/timezones, webDAV/quotas, portfolio', 363: help => 'Domain_Configuration_Quotas', 364: header => [{col1 => 'User affiliation', 365: col2 => 'Available tools', 366: col3 => 'Quotas, MB; (Authoring requires role)',}], 367: print => \&print_quotas, 368: modify => \&modify_quotas, 369: }, 370: 'autoenroll' => 371: { text => 'Auto-enrollment settings', 372: help => 'Domain_Configuration_Auto_Enrollment', 373: header => [{col1 => 'Configuration setting', 374: col2 => 'Value(s)'}], 375: print => \&print_autoenroll, 376: modify => \&modify_autoenroll, 377: }, 378: 'autoupdate' => 379: { text => 'Auto-update settings', 380: help => 'Domain_Configuration_Auto_Updates', 381: header => [{col1 => 'Setting', 382: col2 => 'Value',}, 383: {col1 => 'Setting', 384: col2 => 'Affiliation'}, 385: {col1 => 'User population', 386: col2 => 'Updatable user data'}], 387: print => \&print_autoupdate, 388: modify => \&modify_autoupdate, 389: }, 390: 'autocreate' => 391: { text => 'Auto-course creation settings', 392: help => 'Domain_Configuration_Auto_Creation', 393: header => [{col1 => 'Configuration Setting', 394: col2 => 'Value',}], 395: print => \&print_autocreate, 396: modify => \&modify_autocreate, 397: }, 398: 'directorysrch' => 399: { text => 'Directory searches', 400: help => 'Domain_Configuration_InstDirectory_Search', 401: header => [{col1 => 'Institutional Directory Setting', 402: col2 => 'Value',}, 403: {col1 => 'LON-CAPA Directory Setting', 404: col2 => 'Value',}], 405: print => \&print_directorysrch, 406: modify => \&modify_directorysrch, 407: }, 408: 'contacts' => 409: { text => 'E-mail addresses and helpform', 410: help => 'Domain_Configuration_Contact_Info', 411: header => [{col1 => 'Default e-mail addresses', 412: col2 => 'Value',}, 413: {col1 => 'Recipient(s) for notifications', 414: col2 => 'Value',}, 415: {col1 => 'Nightly status check e-mail', 416: col2 => 'Settings',}, 417: {col1 => 'Ask helpdesk form settings', 418: col2 => 'Value',},], 419: print => \&print_contacts, 420: modify => \&modify_contacts, 421: }, 422: 'usercreation' => 423: { text => 'User creation', 424: help => 'Domain_Configuration_User_Creation', 425: header => [{col1 => 'Format rule type', 426: col2 => 'Format rules in force'}, 427: {col1 => 'User account creation', 428: col2 => 'Usernames which may be created',}, 429: {col1 => 'Context', 430: col2 => 'Assignable authentication types'}], 431: print => \&print_usercreation, 432: modify => \&modify_usercreation, 433: }, 434: 'selfcreation' => 435: { text => 'Users self-creating accounts', 436: help => 'Domain_Configuration_Self_Creation', 437: header => [{col1 => 'Self-creation with institutional username', 438: col2 => 'Enabled?'}, 439: {col1 => 'Institutional user type (login/SSO self-creation)', 440: col2 => 'Information user can enter'}, 441: {col1 => 'Self-creation with e-mail verification', 442: col2 => 'Settings'}], 443: print => \&print_selfcreation, 444: modify => \&modify_selfcreation, 445: }, 446: 'usermodification' => 447: { text => 'User modification', 448: help => 'Domain_Configuration_User_Modification', 449: header => [{col1 => 'Target user has role', 450: col2 => 'User information updatable in author context'}, 451: {col1 => 'Target user has role', 452: col2 => 'User information updatable in course context'}], 453: print => \&print_usermodification, 454: modify => \&modify_usermodification, 455: }, 456: 'scantron' => 457: { text => 'Bubblesheet format', 458: help => 'Domain_Configuration_Scantron_Format', 459: header => [ {col1 => 'Bubblesheet format file', 460: col2 => ''}, 461: {col1 => 'Bubblesheet data upload formats', 462: col2 => 'Settings'}], 463: print => \&print_scantron, 464: modify => \&modify_scantron, 465: }, 466: 'requestcourses' => 467: {text => 'Request creation of courses', 468: help => 'Domain_Configuration_Request_Courses', 469: header => [{col1 => 'User affiliation', 470: col2 => 'Availability/Processing of requests',}, 471: {col1 => 'Setting', 472: col2 => 'Value'}, 473: {col1 => 'Available textbooks', 474: col2 => ''}, 475: {col1 => 'Available templates', 476: col2 => ''}, 477: {col1 => 'Validation (not official courses)', 478: col2 => 'Value'},], 479: print => \&print_quotas, 480: modify => \&modify_quotas, 481: }, 482: 'requestauthor' => 483: {text => 'Request Authoring Space', 484: help => 'Domain_Configuration_Request_Author', 485: header => [{col1 => 'User affiliation', 486: col2 => 'Availability/Processing of requests',}, 487: {col1 => 'Setting', 488: col2 => 'Value'}], 489: print => \&print_quotas, 490: modify => \&modify_quotas, 491: }, 492: 'coursecategories' => 493: { text => 'Cataloging of courses/communities', 494: help => 'Domain_Configuration_Cataloging_Courses', 495: header => [{col1 => 'Catalog type/availability', 496: col2 => '',}, 497: {col1 => 'Category settings for standard catalog', 498: col2 => '',}, 499: {col1 => 'Categories', 500: col2 => '', 501: }], 502: print => \&print_coursecategories, 503: modify => \&modify_coursecategories, 504: }, 505: 'serverstatuses' => 506: {text => 'Access to server status pages', 507: help => 'Domain_Configuration_Server_Status', 508: header => [{col1 => 'Status Page', 509: col2 => 'Other named users', 510: col3 => 'Specific IPs', 511: }], 512: print => \&print_serverstatuses, 513: modify => \&modify_serverstatuses, 514: }, 515: 'helpsettings' => 516: {text => 'Support settings', 517: help => 'Domain_Configuration_Help_Settings', 518: header => [{col1 => 'Help Page Settings (logged-in users)', 519: col2 => 'Value'}, 520: {col1 => 'Helpdesk Roles', 521: col2 => 'Settings'},], 522: print => \&print_helpsettings, 523: modify => \&modify_helpsettings, 524: }, 525: 'coursedefaults' => 526: {text => 'Course/Community defaults', 527: help => 'Domain_Configuration_Course_Defaults', 528: header => [{col1 => 'Defaults which can be overridden in each course by a CC', 529: col2 => 'Value',}, 530: {col1 => 'Defaults which can be overridden for each course by a DC', 531: col2 => 'Value',},], 532: print => \&print_coursedefaults, 533: modify => \&modify_coursedefaults, 534: }, 535: 'selfenrollment' => 536: {text => 'Self-enrollment in Course/Community', 537: help => 'Domain_Configuration_Selfenrollment', 538: header => [{col1 => 'Configuration Rights', 539: col2 => 'Configured by Course Personnel or Domain Coordinator?'}, 540: {col1 => 'Defaults', 541: col2 => 'Value'}, 542: {col1 => 'Self-enrollment validation (optional)', 543: col2 => 'Value'},], 544: print => \&print_selfenrollment, 545: modify => \&modify_selfenrollment, 546: }, 547: 'privacy' => 548: {text => 'Availability of User Information', 549: help => 'Domain_Configuration_User_Privacy', 550: header => [{col1 => 'Role assigned in different domain', 551: col2 => 'Approval options'}, 552: {col1 => 'Role assigned in different domain to user of type', 553: col2 => 'User information available in that domain'}, 554: {col1 => "Role assigned in user's domain", 555: col2 => 'Information viewable by privileged user'}, 556: {col1 => "Role assigned in user's domain", 557: col2 => 'Information viewable by unprivileged user'}], 558: print => \&print_privacy, 559: modify => \&modify_privacy, 560: }, 561: 'usersessions' => 562: {text => 'User session hosting/offloading', 563: help => 'Domain_Configuration_User_Sessions', 564: header => [{col1 => 'Domain server', 565: col2 => 'Servers to offload sessions to when busy'}, 566: {col1 => 'Hosting of users from other domains', 567: col2 => 'Rules'}, 568: {col1 => "Hosting domain's own users elsewhere", 569: col2 => 'Rules'}], 570: print => \&print_usersessions, 571: modify => \&modify_usersessions, 572: }, 573: 'loadbalancing' => 574: {text => 'Dedicated Load Balancer(s)', 575: help => 'Domain_Configuration_Load_Balancing', 576: header => [{col1 => 'Balancers', 577: col2 => 'Default destinations', 578: col3 => 'User affiliation', 579: col4 => 'Overrides'}, 580: ], 581: print => \&print_loadbalancing, 582: modify => \&modify_loadbalancing, 583: }, 584: 'ltitools' => 585: {text => 'External Tools (LTI)', 586: help => 'Domain_Configuration_LTI_Tools', 587: header => [{col1 => 'Setting', 588: col2 => 'Value',}], 589: print => \&print_ltitools, 590: modify => \&modify_ltitools, 591: }, 592: 'proctoring' => 593: {text => 'Remote Proctoring Integration', 594: help => 'Domain_Configuration_Proctoring', 595: header => [{col1 => 'Name', 596: col2 => 'Configuration'}], 597: print => \&print_proctoring, 598: modify => \&modify_proctoring, 599: }, 600: 'ssl' => 601: {text => 'LON-CAPA Network (SSL)', 602: help => 'Domain_Configuration_Network_SSL', 603: header => [{col1 => 'Server', 604: col2 => 'Certificate Status'}, 605: {col1 => 'Connections to other servers', 606: col2 => 'Rules'}, 607: {col1 => 'Connections from other servers', 608: col2 => 'Rules'}, 609: {col1 => "Replicating domain's published content", 610: col2 => 'Rules'}], 611: print => \&print_ssl, 612: modify => \&modify_ssl, 613: }, 614: 'trust' => 615: {text => 'Trust Settings', 616: help => 'Domain_Configuration_Trust', 617: header => [{col1 => "Access to this domain's content by others", 618: col2 => 'Rules'}, 619: {col1 => "Access to other domain's content by this domain", 620: col2 => 'Rules'}, 621: {col1 => "Enrollment in this domain's courses by others", 622: col2 => 'Rules',}, 623: {col1 => "Co-author roles in this domain for others", 624: col2 => 'Rules',}, 625: {col1 => "Co-author roles for this domain's users elsewhere", 626: col2 => 'Rules',}, 627: {col1 => "Domain roles in this domain assignable to others", 628: col2 => 'Rules'}, 629: {col1 => "Course catalog for this domain displayed elsewhere", 630: col2 => 'Rules'}, 631: {col1 => "Requests for creation of courses in this domain by others", 632: col2 => 'Rules'}, 633: {col1 => "Users in other domains can send messages to this domain", 634: col2 => 'Rules'},], 635: print => \&print_trust, 636: modify => \&modify_trust, 637: }, 638: 'lti' => 639: {text => 'LTI Link Protection and LTI Consumers', 640: help => 'Domain_Configuration_LTI_Provider', 641: header => [{col1 => 'Encryption of shared secrets', 642: col2 => 'Settings'}, 643: {col1 => 'Rules for shared secrets', 644: col2 => 'Settings'}, 645: {col1 => 'Link Protectors', 646: col2 => 'Settings'}, 647: {col1 => 'Consumers', 648: col2 => 'Settings'},], 649: print => \&print_lti, 650: modify => \&modify_lti, 651: }, 652: 'ipaccess' => 653: {text => 'IP-based access control', 654: help => 'Domain_Configuration_IP_Access', 655: header => [{col1 => 'Setting', 656: col2 => 'Value'},], 657: print => \&print_ipaccess, 658: modify => \&modify_ipaccess, 659: }, 660: ); 661: if (keys(%servers) > 1) { 662: $prefs{'login'} = { text => 'Log-in page options', 663: help => 'Domain_Configuration_Login_Page', 664: header => [{col1 => 'Log-in Service', 665: col2 => 'Server Setting',}, 666: {col1 => 'Log-in Page Items', 667: col2 => 'Settings'}, 668: {col1 => 'Log-in Help', 669: col2 => 'Value'}, 670: {col1 => 'Custom HTML in document head', 671: col2 => 'Value'}, 672: {col1 => 'SSO', 673: col2 => 'Dual login: SSO and non-SSO options'}, 674: ], 675: print => \&print_login, 676: modify => \&modify_login, 677: }; 678: } 679: 680: my @roles = ('student','coordinator','author','admin'); 681: my @actions = &Apache::loncommon::get_env_multiple('form.actions'); 682: &Apache::lonhtmlcommon::add_breadcrumb 683: ({href=>"javascript:changePage(document.$phase,'pickactions')", 684: text=>"Settings to display/modify"}); 685: my $confname = $dom.'-domainconfig'; 686: 687: if ($phase eq 'process') { 688: my $result = &Apache::lonconfigsettings::make_changes($r,$dom,$phase,$context,\@prefs_order, 689: \%prefs,\%domconfig,$confname,\@roles); 690: if ((ref($result) eq 'HASH') && (keys(%{$result}))) { 691: $r->rflush(); 692: &devalidate_remote_domconfs($dom,$result); 693: } 694: } elsif ($phase eq 'display') { 695: my $js = &recaptcha_js(). 696: &toggle_display_js(); 697: if ((keys(%servers) > 1) || (keys(%existing) > 0)) { 698: my ($othertitle,$usertypes,$types) = 699: &Apache::loncommon::sorted_inst_types($dom); 700: $js .= &lonbalance_targets_js($dom,$types,\%servers, 701: $domconfig{'loadbalancing'}). 702: &new_spares_js(). 703: &common_domprefs_js(). 704: &Apache::loncommon::javascript_array_indexof(); 705: } 706: if (grep(/^requestcourses$/,@actions)) { 707: my $javascript_validations; 708: my $coursebrowserjs=&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'}); 709: $js .= <<END; 710: <script type="text/javascript"> 711: $javascript_validations 712: </script> 713: $coursebrowserjs 714: END 715: } elsif (grep(/^ipaccess$/,@actions)) { 716: $js .= &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'}); 717: } 718: if (grep(/^selfcreation$/,@actions)) { 719: $js .= &selfcreate_javascript(); 720: } 721: if (grep(/^contacts$/,@actions)) { 722: $js .= &contacts_javascript(); 723: } 724: if (grep(/^scantron$/,@actions)) { 725: $js .= &scantron_javascript(); 726: } 727: &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js); 728: } else { 729: # check if domconfig user exists for the domain. 730: my $servadm = $r->dir_config('lonAdmEMail'); 731: my ($configuserok,$author_ok,$switchserver) = 732: &config_check($dom,$confname,$servadm); 733: unless ($configuserok eq 'ok') { 734: &Apache::lonconfigsettings::print_header($r,$phase,$context); 735: $r->print(&mt('The domain configuration user "[_1]" has yet to be created.', 736: $confname). 737: '<br />' 738: ); 739: if ($switchserver) { 740: $r->print(&mt('Ordinarily, that domain configuration user is created when the ./UPDATE script is run to install LON-CAPA for the first time.'). 741: '<br />'. 742: &mt('However, that does not apply when new domains are added to a multi-domain server, and ./UPDATE has not been run recently.'). 743: '<br />'. 744: &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). 745: '<br />'. 746: &mt('To do that now, use the following link: [_1]',$switchserver) 747: ); 748: } else { 749: $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.'). 750: '<br />'. 751: &mt('Once that is done, you will be able to use the web-based "Set domain configuration" to configure the domain') 752: ); 753: } 754: $r->print(&Apache::loncommon::end_page()); 755: return OK; 756: } 757: if (keys(%domconfig) == 0) { 758: my $primarylibserv = &Apache::lonnet::domain($dom,'primary'); 759: my @ids=&Apache::lonnet::current_machine_ids(); 760: if (!grep(/^\Q$primarylibserv\E$/,@ids)) { 761: my %designhash = &Apache::loncommon::get_domainconf($dom); 762: my @loginimages = ('img','logo','domlogo','login'); 763: my $custom_img_count = 0; 764: foreach my $img (@loginimages) { 765: if ($designhash{$dom.'.login.'.$img} ne '') { 766: $custom_img_count ++; 767: } 768: } 769: foreach my $role (@roles) { 770: if ($designhash{$dom.'.'.$role.'.img'} ne '') { 771: $custom_img_count ++; 772: } 773: } 774: if ($custom_img_count > 0) { 775: &Apache::lonconfigsettings::print_header($r,$phase,$context); 776: my $switch_server = &check_switchserver($dom,$confname); 777: $r->print( 778: &mt('Domain configuration settings have yet to be saved for this domain via the web-based domain preferences interface.').'<br />'. 779: &mt("While this remains so, you must switch to the domain's primary library server in order to update settings.").'<br /><br />'. 780: &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 />'. 781: &mt("However, you will still need to switch to the domain's primary library server to upload new images or logos.").'<br /><br />'); 782: if ($switch_server) { 783: $r->print($switch_server.' '.&mt('to primary library server for domain: [_1]',$dom)); 784: } 785: $r->print(&Apache::loncommon::end_page()); 786: return OK; 787: } 788: } 789: } 790: &Apache::lonconfigsettings::display_choices($r,$phase,$context,\@prefs_order,\%prefs); 791: } 792: return OK; 793: } 794: 795: sub process_changes { 796: my ($r,$dom,$confname,$action,$roles,$values,$lastactref) = @_; 797: my %domconfig; 798: if (ref($values) eq 'HASH') { 799: %domconfig = %{$values}; 800: } 801: my $output; 802: if ($action eq 'login') { 803: $output = &modify_login($r,$dom,$confname,$lastactref,%domconfig); 804: } elsif ($action eq 'rolecolors') { 805: $output = &modify_rolecolors($r,$dom,$confname,$roles, 806: $lastactref,%domconfig); 807: } elsif ($action eq 'quotas') { 808: $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig); 809: } elsif ($action eq 'autoenroll') { 810: $output = &modify_autoenroll($dom,$lastactref,%domconfig); 811: } elsif ($action eq 'autoupdate') { 812: $output = &modify_autoupdate($dom,%domconfig); 813: } elsif ($action eq 'autocreate') { 814: $output = &modify_autocreate($dom,%domconfig); 815: } elsif ($action eq 'directorysrch') { 816: $output = &modify_directorysrch($dom,$lastactref,%domconfig); 817: } elsif ($action eq 'usercreation') { 818: $output = &modify_usercreation($dom,%domconfig); 819: } elsif ($action eq 'selfcreation') { 820: $output = &modify_selfcreation($dom,$lastactref,%domconfig); 821: } elsif ($action eq 'usermodification') { 822: $output = &modify_usermodification($dom,%domconfig); 823: } elsif ($action eq 'contacts') { 824: $output = &modify_contacts($dom,$lastactref,%domconfig); 825: } elsif ($action eq 'defaults') { 826: $output = &modify_defaults($dom,$lastactref,%domconfig); 827: } elsif ($action eq 'scantron') { 828: $output = &modify_scantron($r,$dom,$confname,$lastactref,%domconfig); 829: } elsif ($action eq 'coursecategories') { 830: $output = &modify_coursecategories($dom,$lastactref,%domconfig); 831: } elsif ($action eq 'serverstatuses') { 832: $output = &modify_serverstatuses($dom,%domconfig); 833: } elsif ($action eq 'requestcourses') { 834: $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig); 835: } elsif ($action eq 'requestauthor') { 836: $output = &modify_quotas($r,$dom,$action,$lastactref,%domconfig); 837: } elsif ($action eq 'helpsettings') { 838: $output = &modify_helpsettings($r,$dom,$confname,$lastactref,%domconfig); 839: } elsif ($action eq 'coursedefaults') { 840: $output = &modify_coursedefaults($dom,$lastactref,%domconfig); 841: } elsif ($action eq 'selfenrollment') { 842: $output = &modify_selfenrollment($dom,$lastactref,%domconfig) 843: } elsif ($action eq 'usersessions') { 844: $output = &modify_usersessions($dom,$lastactref,%domconfig); 845: } elsif ($action eq 'loadbalancing') { 846: $output = &modify_loadbalancing($dom,%domconfig); 847: } elsif ($action eq 'ltitools') { 848: $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig); 849: } elsif ($action eq 'proctoring') { 850: $output = &modify_proctoring($r,$dom,$action,$lastactref,%domconfig); 851: } elsif ($action eq 'ssl') { 852: $output = &modify_ssl($dom,$lastactref,%domconfig); 853: } elsif ($action eq 'trust') { 854: $output = &modify_trust($dom,$lastactref,%domconfig); 855: } elsif ($action eq 'lti') { 856: $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig); 857: } elsif ($action eq 'privacy') { 858: $output = &modify_privacy($dom,%domconfig); 859: } elsif ($action eq 'passwords') { 860: $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig); 861: } elsif ($action eq 'wafproxy') { 862: $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig); 863: } elsif ($action eq 'ipaccess') { 864: $output = &modify_ipaccess($dom,$lastactref,%domconfig); 865: } 866: return $output; 867: } 868: 869: sub print_config_box { 870: my ($r,$dom,$confname,$phase,$action,$item,$settings) = @_; 871: my $rowtotal = 0; 872: my $output; 873: if ($action eq 'coursecategories') { 874: $output = &coursecategories_javascript($settings); 875: } elsif ($action eq 'defaults') { 876: $output = &defaults_javascript($settings); 877: } elsif ($action eq 'passwords') { 878: $output = &passwords_javascript($action); 879: } elsif ($action eq 'helpsettings') { 880: my (%privs,%levelscurrent); 881: my %full=(); 882: my %levels=( 883: course => {}, 884: domain => {}, 885: system => {}, 886: ); 887: my $context = 'domain'; 888: my $crstype = 'Course'; 889: my $formname = 'display'; 890: &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent); 891: my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype); 892: $output = 893: &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full, 894: \@templateroles); 895: } elsif ($action eq 'ltitools') { 896: $output .= <itools_javascript($settings); 897: } elsif ($action eq 'lti') { 898: $output .= &passwords_javascript('secrets')."\n". 899: <i_javascript($dom,$settings); 900: } elsif ($action eq 'proctoring') { 901: $output .= &proctoring_javascript($settings); 902: } elsif ($action eq 'wafproxy') { 903: $output .= &wafproxy_javascript($dom); 904: } elsif ($action eq 'autoupdate') { 905: $output .= &autoupdate_javascript(); 906: } elsif ($action eq 'autoenroll') { 907: $output .= &autoenroll_javascript(); 908: } elsif ($action eq 'login') { 909: $output .= &saml_javascript(); 910: } elsif ($action eq 'ipaccess') { 911: $output .= &ipaccess_javascript($settings); 912: } 913: $output .= 914: '<table class="LC_nested_outer"> 915: <tr> 916: <th class="LC_left_item LC_middle"><span class="LC_nobreak">'. 917: &mt($item->{text}).' '. 918: &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n". 919: '</tr>'; 920: $rowtotal ++; 921: my $numheaders = 1; 922: if (ref($item->{'header'}) eq 'ARRAY') { 923: $numheaders = scalar(@{$item->{'header'}}); 924: } 925: if ($numheaders > 1) { 926: my $colspan = ''; 927: my $rightcolspan = ''; 928: my $leftnobr = ''; 929: if (($action eq 'rolecolors') || ($action eq 'defaults') || 930: ($action eq 'directorysrch') || 931: (($action eq 'login') && ($numheaders < 5))) { 932: $colspan = ' colspan="2"'; 933: } 934: if ($action eq 'usersessions') { 935: $rightcolspan = ' colspan="3"'; 936: } 937: if ($action eq 'passwords') { 938: $leftnobr = ' LC_nobreak'; 939: } 940: $output .= ' 941: <tr> 942: <td> 943: <table class="LC_nested"> 944: <tr class="LC_info_row"> 945: <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td> 946: <td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td> 947: </tr>'; 948: $rowtotal ++; 949: if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') || 950: ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') || 951: ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') || 952: ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') || 953: ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy') || ($action eq 'lti')) { 954: $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal); 955: } elsif ($action eq 'passwords') { 956: $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal); 957: } elsif ($action eq 'coursecategories') { 958: $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal); 959: } elsif ($action eq 'scantron') { 960: $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal); 961: } elsif ($action eq 'login') { 962: if ($numheaders == 5) { 963: $colspan = ' colspan="2"'; 964: $output .= &print_login('service',$dom,$confname,$phase,$settings,\$rowtotal); 965: } else { 966: $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal); 967: } 968: } elsif (($action eq 'requestcourses') || ($action eq 'requestauthor')) { 969: $output .= &print_quotas($dom,$settings,\$rowtotal,$action); 970: } elsif ($action eq 'rolecolors') { 971: $output .= &print_rolecolors($phase,'student',$dom,$confname,$settings,\$rowtotal); 972: } 973: $output .= ' 974: </table> 975: </td> 976: </tr> 977: <tr> 978: <td> 979: <table class="LC_nested"> 980: <tr class="LC_info_row"> 981: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[1]->{'col1'}).'</td> 982: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[1]->{'col2'}).'</td> 983: </tr>'; 984: $rowtotal ++; 985: if (($action eq 'autoupdate') || ($action eq 'usercreation') || 986: ($action eq 'selfcreation') || ($action eq 'selfenrollment') || 987: ($action eq 'usersessions') || ($action eq 'coursecategories') || 988: ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') || 989: ($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti')) { 990: if ($action eq 'coursecategories') { 991: $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal); 992: $colspan = ' colspan="2"'; 993: } elsif ($action eq 'trust') { 994: $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal); 995: } elsif ($action eq 'passwords') { 996: $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal); 997: } else { 998: $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal); 999: } 1000: if ($action eq 'trust') { 1001: $output .= ' 1002: </table> 1003: </td> 1004: </tr>'; 1005: my @trusthdrs = qw(2 3 4 5 6 7); 1006: my @prefixes = qw(enroll othcoau coaurem domroles catalog reqcrs); 1007: for (my $i=0; $i<@trusthdrs; $i++) { 1008: $output .= ' 1009: <tr> 1010: <td> 1011: <table class="LC_nested"> 1012: <tr class="LC_info_row"> 1013: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col1'}).'</td> 1014: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col2'}).'</td></tr>'. 1015: $item->{'print'}->($prefixes[$i],$dom,$settings,\$rowtotal).' 1016: </table> 1017: </td> 1018: </tr>'; 1019: } 1020: $output .= ' 1021: <tr> 1022: <td> 1023: <table class="LC_nested"> 1024: <tr class="LC_info_row"> 1025: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col1'}).'</td> 1026: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'. 1027: $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); 1028: } else { 1029: $output .= ' 1030: </table> 1031: </td> 1032: </tr> 1033: <tr> 1034: <td> 1035: <table class="LC_nested"> 1036: <tr class="LC_info_row"> 1037: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td> 1038: <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td> 1039: </tr>'."\n"; 1040: if ($action eq 'coursecategories') { 1041: $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal); 1042: } elsif (($action eq 'contacts') || ($action eq 'privacy') || 1043: ($action eq 'passwords') || ($action eq 'lti')) { 1044: if ($action eq 'passwords') { 1045: $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal); 1046: } else { 1047: $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal); 1048: } 1049: $output .= ' 1050: </tr> 1051: </table> 1052: </td> 1053: </tr> 1054: <tr> 1055: <td> 1056: <table class="LC_nested"> 1057: <tr class="LC_info_row"> 1058: <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> 1059: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n"; 1060: if ($action eq 'passwords') { 1061: $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal); 1062: } else { 1063: $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); 1064: } 1065: $output .= ' 1066: </table> 1067: </td> 1068: </tr> 1069: <tr>'; 1070: } else { 1071: $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); 1072: } 1073: } 1074: $rowtotal ++; 1075: } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') || 1076: ($action eq 'directorysrch') || ($action eq 'helpsettings') || 1077: ($action eq 'wafproxy')) { 1078: $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); 1079: } elsif ($action eq 'scantron') { 1080: $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal); 1081: } elsif ($action eq 'ssl') { 1082: $output .= $item->{'print'}->('connto',$dom,$settings,\$rowtotal).' 1083: </table> 1084: </td> 1085: </tr> 1086: <tr> 1087: <td> 1088: <table class="LC_nested"> 1089: <tr class="LC_info_row"> 1090: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td> 1091: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'. 1092: $item->{'print'}->('connfrom',$dom,$settings,\$rowtotal).' 1093: </table> 1094: </td> 1095: </tr> 1096: <tr> 1097: <td> 1098: <table class="LC_nested"> 1099: <tr class="LC_info_row"> 1100: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> 1101: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'. 1102: $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); 1103: } elsif ($action eq 'login') { 1104: if ($numheaders == 5) { 1105: $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).' 1106: </table> 1107: </td> 1108: </tr> 1109: <tr> 1110: <td> 1111: <table class="LC_nested"> 1112: <tr class="LC_info_row"> 1113: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td> 1114: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'. 1115: &print_login('help',$dom,$confname,$phase,$settings,\$rowtotal); 1116: $rowtotal ++; 1117: } else { 1118: $output .= &print_login('help',$dom,$confname,$phase,$settings,\$rowtotal); 1119: } 1120: $output .= ' 1121: </table> 1122: </td> 1123: </tr> 1124: <tr> 1125: <td> 1126: <table class="LC_nested"> 1127: <tr class="LC_info_row">'; 1128: if ($numheaders == 5) { 1129: $output .= ' 1130: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> 1131: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td> 1132: </tr>'; 1133: } else { 1134: $output .= ' 1135: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td> 1136: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td> 1137: </tr>'; 1138: } 1139: $rowtotal ++; 1140: $output .= &print_login('headtag',$dom,$confname,$phase,$settings,\$rowtotal).' 1141: </table> 1142: </td> 1143: </tr> 1144: <tr> 1145: <td> 1146: <table class="LC_nested"> 1147: <tr class="LC_info_row">'; 1148: if ($numheaders == 5) { 1149: $output .= ' 1150: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col1'}).'</td> 1151: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col2'}).'</td> 1152: </tr>'; 1153: } else { 1154: $output .= ' 1155: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> 1156: <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td> 1157: </tr>'; 1158: } 1159: $rowtotal ++; 1160: $output .= &print_login('saml',$dom,$confname,$phase,$settings,\$rowtotal); 1161: } elsif ($action eq 'requestcourses') { 1162: $output .= &print_requestmail($dom,$action,$settings,\$rowtotal); 1163: $rowtotal ++; 1164: $output .= &print_studentcode($settings,\$rowtotal).' 1165: </table> 1166: </td> 1167: </tr> 1168: <tr> 1169: <td> 1170: <table class="LC_nested"> 1171: <tr class="LC_info_row"> 1172: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td> 1173: <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td> </tr>'. 1174: &textbookcourses_javascript($settings). 1175: &print_textbookcourses($dom,'textbooks',$settings,\$rowtotal).' 1176: </table> 1177: </td> 1178: </tr> 1179: <tr> 1180: <td> 1181: <table class="LC_nested"> 1182: <tr class="LC_info_row"> 1183: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> 1184: <td class="LC_right_item">'.&mt($item->{'header'}->[3]->{'col2'}).'</td> </tr>'. 1185: &print_textbookcourses($dom,'templates',$settings,\$rowtotal).' 1186: </table> 1187: </td> 1188: </tr> 1189: <tr> 1190: <td> 1191: <table class="LC_nested"> 1192: <tr class="LC_info_row"> 1193: <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td> 1194: <td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td> 1195: </tr>'. 1196: &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal); 1197: } elsif ($action eq 'requestauthor') { 1198: $output .= &print_requestmail($dom,$action,$settings,\$rowtotal); 1199: $rowtotal ++; 1200: } elsif ($action eq 'rolecolors') { 1201: $output .= &print_rolecolors($phase,'coordinator',$dom,$confname,$settings,\$rowtotal).' 1202: </table> 1203: </td> 1204: </tr> 1205: <tr> 1206: <td> 1207: <table class="LC_nested"> 1208: <tr class="LC_info_row"> 1209: <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'. 1210: &mt($item->{'header'}->[2]->{'col1'}).'</td> 1211: <td class="LC_right_item" style="vertical-align: top">'. 1212: &mt($item->{'header'}->[2]->{'col2'}).'</td> 1213: </tr>'. 1214: &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).' 1215: </table> 1216: </td> 1217: </tr> 1218: <tr> 1219: <td> 1220: <table class="LC_nested"> 1221: <tr class="LC_info_row"> 1222: <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> 1223: <td class="LC_right_item">'.&mt($item->{'header'}->[3]->{'col2'}).'</td> 1224: </tr>'. 1225: &print_rolecolors($phase,'admin',$dom,$confname,$settings,\$rowtotal); 1226: $rowtotal += 2; 1227: } 1228: } else { 1229: $output .= ' 1230: <tr> 1231: <td> 1232: <table class="LC_nested"> 1233: <tr class="LC_info_row">'; 1234: if ($action eq 'login') { 1235: $output .= ' 1236: <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>'; 1237: } elsif ($action eq 'serverstatuses') { 1238: $output .= ' 1239: <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}). 1240: '<br />('.&mt('Automatic access for Dom. Coords.').')</td>'; 1241: 1242: } else { 1243: $output .= ' 1244: <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>'; 1245: } 1246: if (defined($item->{'header'}->[0]->{'col3'})) { 1247: $output .= '<td class="LC_left_item" style="vertical-align: top">'. 1248: &mt($item->{'header'}->[0]->{'col2'}); 1249: if ($action eq 'serverstatuses') { 1250: $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)'; 1251: } 1252: } else { 1253: $output .= '<td class="LC_right_item" style="vertical-align: top">'. 1254: &mt($item->{'header'}->[0]->{'col2'}); 1255: } 1256: $output .= '</td>'; 1257: if ($item->{'header'}->[0]->{'col3'}) { 1258: if (defined($item->{'header'}->[0]->{'col4'})) { 1259: $output .= '<td class="LC_left_item" style="vertical-align: top">'. 1260: &mt($item->{'header'}->[0]->{'col3'}); 1261: } else { 1262: $output .= '<td class="LC_right_item" style="vertical-align: top">'. 1263: &mt($item->{'header'}->[0]->{'col3'}); 1264: } 1265: if ($action eq 'serverstatuses') { 1266: $output .= '<br />(<tt>'.&mt('IP1,IP2 etc.').'</tt>)'; 1267: } 1268: $output .= '</td>'; 1269: } 1270: if ($item->{'header'}->[0]->{'col4'}) { 1271: $output .= '<td class="LC_right_item" style="vertical-align: top">'. 1272: &mt($item->{'header'}->[0]->{'col4'}); 1273: } 1274: $output .= '</tr>'; 1275: $rowtotal ++; 1276: if ($action eq 'quotas') { 1277: $output .= &print_quotas($dom,$settings,\$rowtotal,$action); 1278: } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || 1279: ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || 1280: ($action eq 'ltitools') || ($action eq 'proctoring') || 1281: ($action eq 'ipaccess')) { 1282: $output .= $item->{'print'}->($dom,$settings,\$rowtotal); 1283: } 1284: } 1285: $output .= ' 1286: </table> 1287: </td> 1288: </tr> 1289: </table><br />'; 1290: return ($output,$rowtotal); 1291: } 1292: 1293: sub print_login { 1294: my ($caller,$dom,$confname,$phase,$settings,$rowtotal) = @_; 1295: my ($css_class,$datatable,$switchserver,%lt); 1296: my %choices = &login_choices(); 1297: if (($caller eq 'help') || ($caller eq 'headtag') || ($caller eq 'saml')) { 1298: %lt = &login_file_options(); 1299: $switchserver = &check_switchserver($dom,$confname); 1300: } 1301: if ($caller eq 'service') { 1302: my %servers = &Apache::lonnet::internet_dom_servers($dom); 1303: my $choice = $choices{'disallowlogin'}; 1304: $css_class = ' class="LC_odd_row"'; 1305: $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'. 1306: '<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'. 1307: '<th>'.$choices{'server'}.'</th>'. 1308: '<th>'.$choices{'serverpath'}.'</th>'. 1309: '<th>'.$choices{'custompath'}.'</th>'. 1310: '<th><span class="LC_nobreak">'.$choices{'exempt'}.'</span></th></tr>'."\n"; 1311: my %disallowed; 1312: if (ref($settings) eq 'HASH') { 1313: if (ref($settings->{'loginvia'}) eq 'HASH') { 1314: %disallowed = %{$settings->{'loginvia'}}; 1315: } 1316: } 1317: foreach my $lonhost (sort(keys(%servers))) { 1318: my $direct = 'selected="selected"'; 1319: if (ref($disallowed{$lonhost}) eq 'HASH') { 1320: if ($disallowed{$lonhost}{'server'} ne '') { 1321: $direct = ''; 1322: } 1323: } 1324: $datatable .= '<tr><td>'.$servers{$lonhost}.'</td>'. 1325: '<td><select name="'.$lonhost.'_server">'. 1326: '<option value=""'.$direct.'>'.$choices{'directlogin'}. 1327: '</option>'; 1328: foreach my $hostid (sort(keys(%servers))) { 1329: next if ($servers{$hostid} eq $servers{$lonhost}); 1330: my $selected = ''; 1331: if (ref($disallowed{$lonhost}) eq 'HASH') { 1332: if ($hostid eq $disallowed{$lonhost}{'server'}) { 1333: $selected = 'selected="selected"'; 1334: } 1335: } 1336: $datatable .= '<option value="'.$hostid.'"'.$selected.'>'. 1337: $servers{$hostid}.'</option>'; 1338: } 1339: $datatable .= '</select></td>'. 1340: '<td><select name="'.$lonhost.'_serverpath">'; 1341: foreach my $path ('','/','/adm/login','/adm/roles','custom') { 1342: my $pathname = $path; 1343: if ($path eq 'custom') { 1344: $pathname = &mt('Custom Path').' ->'; 1345: } 1346: my $selected = ''; 1347: if (ref($disallowed{$lonhost}) eq 'HASH') { 1348: if ($path eq $disallowed{$lonhost}{'serverpath'}) { 1349: $selected = 'selected="selected"'; 1350: } 1351: } elsif ($path eq '') { 1352: $selected = 'selected="selected"'; 1353: } 1354: $datatable .= '<option value="'.$path.'"'.$selected.'>'.$pathname.'</option>'; 1355: } 1356: $datatable .= '</select></td>'; 1357: my ($custom,$exempt); 1358: if (ref($disallowed{$lonhost}) eq 'HASH') { 1359: $custom = $disallowed{$lonhost}{'custompath'}; 1360: $exempt = $disallowed{$lonhost}{'exempt'}; 1361: } 1362: $datatable .= '<td><input type="text" name="'.$lonhost.'_custompath" size="6" value="'.$custom.'" /></td>'. 1363: '<td><input type="text" name="'.$lonhost.'_exempt" size="8" value="'.$exempt.'" /></td>'. 1364: '</tr>'; 1365: } 1366: $datatable .= '</table></td></tr>'; 1367: return $datatable; 1368: } elsif ($caller eq 'page') { 1369: my %defaultchecked = ( 1370: 'coursecatalog' => 'on', 1371: 'helpdesk' => 'on', 1372: 'adminmail' => 'off', 1373: 'newuser' => 'off', 1374: ); 1375: my @toggles = ('coursecatalog','adminmail','helpdesk','newuser'); 1376: my (%checkedon,%checkedoff); 1377: foreach my $item (@toggles) { 1378: if ($defaultchecked{$item} eq 'on') { 1379: $checkedon{$item} = ' checked="checked" '; 1380: $checkedoff{$item} = ' '; 1381: } elsif ($defaultchecked{$item} eq 'off') { 1382: $checkedoff{$item} = ' checked="checked" '; 1383: $checkedon{$item} = ' '; 1384: } 1385: } 1386: my @images = ('img','logo','domlogo','login'); 1387: my @alttext = ('img','logo','domlogo'); 1388: my @logintext = ('textcol','bgcol'); 1389: my @bgs = ('pgbg','mainbg','sidebg'); 1390: my @links = ('link','alink','vlink'); 1391: my %designhash = &Apache::loncommon::get_domainconf($dom); 1392: my %defaultdesign = %Apache::loncommon::defaultdesign; 1393: my (%is_custom,%designs); 1394: my %defaults = ( 1395: font => $defaultdesign{'login.font'}, 1396: ); 1397: foreach my $item (@images) { 1398: $defaults{$item} = $defaultdesign{'login.'.$item}; 1399: $defaults{'showlogo'}{$item} = 1; 1400: } 1401: foreach my $item (@bgs) { 1402: $defaults{'bgs'}{$item} = $defaultdesign{'login.'.$item}; 1403: } 1404: foreach my $item (@logintext) { 1405: $defaults{'logintext'}{$item} = $defaultdesign{'login.'.$item}; 1406: } 1407: foreach my $item (@links) { 1408: $defaults{'links'}{$item} = $defaultdesign{'login.'.$item}; 1409: } 1410: if (ref($settings) eq 'HASH') { 1411: foreach my $item (@toggles) { 1412: if ($settings->{$item} eq '1') { 1413: $checkedon{$item} = ' checked="checked" '; 1414: $checkedoff{$item} = ' '; 1415: } elsif ($settings->{$item} eq '0') { 1416: $checkedoff{$item} = ' checked="checked" '; 1417: $checkedon{$item} = ' '; 1418: } 1419: } 1420: foreach my $item (@images) { 1421: if (defined($settings->{$item})) { 1422: $designs{$item} = $settings->{$item}; 1423: $is_custom{$item} = 1; 1424: } 1425: if (defined($settings->{'showlogo'}{$item})) { 1426: $designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item}; 1427: } 1428: } 1429: foreach my $item (@alttext) { 1430: if (ref($settings->{'alttext'}) eq 'HASH') { 1431: if ($settings->{'alttext'}->{$item} ne '') { 1432: $designs{'alttext'}{$item} = $settings->{'alttext'}{$item}; 1433: } 1434: } 1435: } 1436: foreach my $item (@logintext) { 1437: if ($settings->{$item} ne '') { 1438: $designs{'logintext'}{$item} = $settings->{$item}; 1439: $is_custom{$item} = 1; 1440: } 1441: } 1442: if ($settings->{'font'} ne '') { 1443: $designs{'font'} = $settings->{'font'}; 1444: $is_custom{'font'} = 1; 1445: } 1446: foreach my $item (@bgs) { 1447: if ($settings->{$item} ne '') { 1448: $designs{'bgs'}{$item} = $settings->{$item}; 1449: $is_custom{$item} = 1; 1450: } 1451: } 1452: foreach my $item (@links) { 1453: if ($settings->{$item} ne '') { 1454: $designs{'links'}{$item} = $settings->{$item}; 1455: $is_custom{$item} = 1; 1456: } 1457: } 1458: } else { 1459: if ($designhash{$dom.'.login.font'} ne '') { 1460: $designs{'font'} = $designhash{$dom.'.login.font'}; 1461: $is_custom{'font'} = 1; 1462: } 1463: foreach my $item (@images) { 1464: if ($designhash{$dom.'.login.'.$item} ne '') { 1465: $designs{$item} = $designhash{$dom.'.login.'.$item}; 1466: $is_custom{$item} = 1; 1467: } 1468: } 1469: foreach my $item (@bgs) { 1470: if ($designhash{$dom.'.login.'.$item} ne '') { 1471: $designs{'bgs'}{$item} = $designhash{$dom.'.login.'.$item}; 1472: $is_custom{$item} = 1; 1473: } 1474: } 1475: foreach my $item (@links) { 1476: if ($designhash{$dom.'.login.'.$item} ne '') { 1477: $designs{'links'}{$item} = $designhash{$dom.'.login.'.$item}; 1478: $is_custom{$item} = 1; 1479: } 1480: } 1481: } 1482: my %alt_text = &Apache::lonlocal::texthash ( img => 'Log-in banner', 1483: logo => 'Institution Logo', 1484: domlogo => 'Domain Logo', 1485: login => 'Login box'); 1486: my $itemcount = 1; 1487: foreach my $item (@toggles) { 1488: $css_class = $itemcount%2?' class="LC_odd_row"':''; 1489: $datatable .= 1490: '<tr'.$css_class.'><td colspan="2">'.$choices{$item}. 1491: '</td><td>'. 1492: '<span class="LC_nobreak"><label><input type="radio" name="'. 1493: $item.'"'.$checkedon{$item}.' value="1" />'.&mt('Yes'). 1494: '</label> <label><input type="radio" name="'.$item.'"'. 1495: $checkedoff{$item}.' value="0" />'.&mt('No').'</label></span></td>'. 1496: '</tr>'; 1497: $itemcount ++; 1498: } 1499: $datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext); 1500: $datatable .= '</tr></table></td></tr>'; 1501: } elsif ($caller eq 'help') { 1502: my ($defaulturl,$defaulttype,%url,%type,%langchoices); 1503: my $itemcount = 1; 1504: $defaulturl = '/adm/loginproblems.html'; 1505: $defaulttype = 'default'; 1506: %langchoices = &Apache::lonlocal::texthash(&get_languages_hash()); 1507: my @currlangs; 1508: if (ref($settings) eq 'HASH') { 1509: if (ref($settings->{'helpurl'}) eq 'HASH') { 1510: foreach my $key (sort(keys(%{$settings->{'helpurl'}}))) { 1511: next if ($settings->{'helpurl'}{$key} eq ''); 1512: $url{$key} = $settings->{'helpurl'}{$key}.'?inhibitmenu=yes'; 1513: $type{$key} = 'custom'; 1514: unless ($key eq 'nolang') { 1515: push(@currlangs,$key); 1516: } 1517: } 1518: } elsif ($settings->{'helpurl'} ne '') { 1519: $type{'nolang'} = 'custom'; 1520: $url{'nolang'} = $settings->{'helpurl'}.'?inhibitmenu=yes'; 1521: } 1522: } 1523: foreach my $lang ('nolang',sort(@currlangs)) { 1524: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 1525: $datatable .= '<tr'.$css_class.'>'; 1526: if ($url{$lang} eq '') { 1527: $url{$lang} = $defaulturl; 1528: } 1529: if ($type{$lang} eq '') { 1530: $type{$lang} = $defaulttype; 1531: } 1532: $datatable .= '<td colspan="2"><span class="LC_nobreak">'; 1533: if ($lang eq 'nolang') { 1534: $datatable .= &mt('Log-in help page if no specific language file: [_1]', 1535: &Apache::loncommon::modal_link($url{$lang},$lt{$type{$lang}},600,500)); 1536: } else { 1537: $datatable .= &mt('Log-in help page for language: [_1] is [_2]', 1538: $langchoices{$lang}, 1539: &Apache::loncommon::modal_link($url{$lang},$lt{$type{$lang}},600,500)); 1540: } 1541: $datatable .= '</span></td>'."\n". 1542: '<td class="LC_left_item">'; 1543: if ($type{$lang} eq 'custom') { 1544: $datatable .= '<span class="LC_nobreak"><label>'. 1545: '<input type="checkbox" name="loginhelpurl_del" value="'.$lang.'" />'. 1546: $lt{'del'}.'</label> '.$lt{'rep'}.'</span>'; 1547: } else { 1548: $datatable .= $lt{'upl'}; 1549: } 1550: $datatable .='<br />'; 1551: if ($switchserver) { 1552: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 1553: } else { 1554: $datatable .= '<input type="file" name="loginhelpurl_'.$lang.'" />'; 1555: } 1556: $datatable .= '</td></tr>'; 1557: $itemcount ++; 1558: } 1559: my @addlangs; 1560: foreach my $lang (sort(keys(%langchoices))) { 1561: next if ((grep(/^\Q$lang\E$/,@currlangs)) || ($lang eq 'x_chef')); 1562: push(@addlangs,$lang); 1563: } 1564: if (@addlangs > 0) { 1565: my %toadd; 1566: map { $toadd{$_} = $langchoices{$_} ; } @addlangs; 1567: $toadd{''} = &mt('Select'); 1568: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 1569: $datatable .= '<tr'.$css_class.'><td class="LC_left_item" colspan="2">'. 1570: &mt('Add log-in help page for a specific language:').' '. 1571: &Apache::loncommon::select_form('','loginhelpurl_add_lang',\%toadd). 1572: '</td><td class="LC_left_item">'.$lt{'upl'}.'<br />'; 1573: if ($switchserver) { 1574: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 1575: } else { 1576: $datatable .= '<input type="file" name="loginhelpurl_add_file" />'; 1577: } 1578: $datatable .= '</td></tr>'; 1579: $itemcount ++; 1580: } 1581: $datatable .= &captcha_choice('login',$settings,$itemcount); 1582: } elsif ($caller eq 'headtag') { 1583: my %domservers = &Apache::lonnet::get_servers($dom); 1584: my $choice = $choices{'headtag'}; 1585: $css_class = ' class="LC_odd_row"'; 1586: $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'. 1587: '<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'. 1588: '<th>'.$choices{'current'}.'</th>'. 1589: '<th>'.$choices{'action'}.'</th>'. 1590: '<th>'.$choices{'exempt'}.'</th></tr>'."\n"; 1591: my (%currurls,%currexempt); 1592: if (ref($settings) eq 'HASH') { 1593: if (ref($settings->{'headtag'}) eq 'HASH') { 1594: foreach my $lonhost (keys(%{$settings->{'headtag'}})) { 1595: if (ref($settings->{'headtag'}{$lonhost}) eq 'HASH') { 1596: $currurls{$lonhost} = $settings->{'headtag'}{$lonhost}{'url'}; 1597: $currexempt{$lonhost} = $settings->{'headtag'}{$lonhost}{'exempt'}; 1598: } 1599: } 1600: } 1601: } 1602: foreach my $lonhost (sort(keys(%domservers))) { 1603: my $exempt = &check_exempt_addresses($currexempt{$lonhost}); 1604: $datatable .= '<tr><td>'.$domservers{$lonhost}.'</td>'; 1605: if ($currurls{$lonhost}) { 1606: $datatable .= '<td class="LC_right_item"><a href="'. 1607: "javascript:void(open('$currurls{$lonhost}?inhibitmenu=yes','Custom_HeadTag', 1608: 'menubar=0,toolbar=1,scrollbars=1,width=600,height=500,resizable=yes'))". 1609: '">'.$lt{'curr'}.'</a></td>'. 1610: '<td><span class="LC_nobreak"><label>'. 1611: '<input type="checkbox" name="loginheadtag_del" value="'.$lonhost.'" />'. 1612: $lt{'del'}.'</label> '.$lt{'rep'}.'</span>'; 1613: } else { 1614: $datatable .= '<td class="LC_right_item">'.$lt{'none'}.'</td><td>'.$lt{'upl'}; 1615: } 1616: $datatable .='<br />'; 1617: if ($switchserver) { 1618: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 1619: } else { 1620: $datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />'; 1621: } 1622: $datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>'; 1623: } 1624: $datatable .= '</table></td></tr>'; 1625: } elsif ($caller eq 'saml') { 1626: my %domservers = &Apache::lonnet::get_servers($dom); 1627: $datatable .= '<tr><td colspan="3" style="text-align: left">'. 1628: '<table><tr><th>'.$choices{'hostid'}.'</th>'. 1629: '<th>'.$choices{'samllanding'}.'</th>'. 1630: '<th>'.$choices{'samloptions'}.'</th></tr>'."\n"; 1631: my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso,%styleon,%styleoff); 1632: foreach my $lonhost (keys(%domservers)) { 1633: $samlurl{$lonhost} = '/adm/sso'; 1634: $styleon{$lonhost} = 'display:none'; 1635: $styleoff{$lonhost} = ''; 1636: } 1637: if ((ref($settings) eq 'HASH') && (ref($settings->{'saml'}) eq 'HASH')) { 1638: foreach my $lonhost (keys(%{$settings->{'saml'}})) { 1639: if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') { 1640: $saml{$lonhost} = 1; 1641: $samltext{$lonhost} = $settings->{'saml'}{$lonhost}{'text'}; 1642: $samlimg{$lonhost} = $settings->{'saml'}{$lonhost}{'img'}; 1643: $samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'}; 1644: $samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'}; 1645: $samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'}; 1646: $samlwindow{$lonhost} = $settings->{'saml'}{$lonhost}{'window'}; 1647: $samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'}; 1648: $styleon{$lonhost} = ''; 1649: $styleoff{$lonhost} = 'display:none'; 1650: } else { 1651: $styleon{$lonhost} = 'display:none'; 1652: $styleoff{$lonhost} = ''; 1653: } 1654: } 1655: } 1656: my $itemcount = 1; 1657: foreach my $lonhost (sort(keys(%domservers))) { 1658: my $samlon = ' '; 1659: my $samloff = ' checked="checked" '; 1660: if ($saml{$lonhost}) { 1661: $samlon = $samloff; 1662: $samloff = ' '; 1663: } 1664: my $samlwinon = ''; 1665: my $samlwinoff = ' checked="checked"'; 1666: if ($samlwindow{$lonhost}) { 1667: $samlwinon = $samlwinoff; 1668: $samlwinoff = ''; 1669: } 1670: my $css_class = $itemcount%2?' class="LC_odd_row"':''; 1671: $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'. 1672: '<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff. 1673: 'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="0" />'. 1674: &mt('No').'</label>'.(' 'x2). 1675: '<label><input type="radio" name="saml_'.$lonhost.'"'.$samlon. 1676: 'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'. 1677: &mt('Yes').'</label></span></td>'. 1678: '<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'. 1679: '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th></tr>'. 1680: '<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'. 1681: '<th>'.&mt('Alt Text').'</th></tr>'. 1682: '<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="20" value="'. 1683: $samltext{$lonhost}.'" /></td><td>'; 1684: if ($samlimg{$lonhost}) { 1685: $datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'. 1686: '<span class="LC_nobreak"><label>'. 1687: '<input type="checkbox" name="saml_img_del" value="'.$lonhost.'" />'. 1688: $lt{'del'}.'</label> '.$lt{'rep'}.'</span>'; 1689: } else { 1690: $datatable .= $lt{'upl'}; 1691: } 1692: $datatable .='<br />'; 1693: if ($switchserver) { 1694: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 1695: } else { 1696: $datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />'; 1697: } 1698: $datatable .= '</td>'. 1699: '<td><input type="text" name="saml_alt_'.$lonhost.'" size="25" '. 1700: 'value="'.$samlalt{$lonhost}.'" /></td></tr></table><br />'. 1701: '<table width="100%"><tr><th colspan="3" align="center">'.&mt('SSO').'</th><th align="center">'. 1702: '<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'. 1703: '<tr><th>'.&mt('URL').'</th><th>'.&mt('Tool Tip').'</th>'. 1704: '<th>'.&mt('Pop-up if iframe').'</th><th>'.&mt('Text').'</th></tr>'. 1705: '<tr'.$css_class.'>'. 1706: '<td><input type="text" name="saml_url_'.$lonhost.'" size="30" '. 1707: 'value="'.$samlurl{$lonhost}.'" /></td>'. 1708: '<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="20">'. 1709: $samltitle{$lonhost}.'</textarea></td>'. 1710: '<td><label><input type="radio" name="saml_window_'.$lonhost.'" value=""'.$samlwinoff.'>'. 1711: &mt('No').'</label>'.(' 'x2).'<label><input type="radio" '. 1712: 'name="saml_window_'.$lonhost.'" value="1"'.$samlwinon.'>'.&mt('Yes').'</label></td>'. 1713: '<td><input type="text" name="saml_notsso_'.$lonhost.'" size="12" '. 1714: 'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'. 1715: '</table></td>'. 1716: '<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%"> </td></tr>'; 1717: $itemcount ++; 1718: } 1719: $datatable .= '</table></td></tr>'; 1720: } 1721: return $datatable; 1722: } 1723: 1724: sub login_choices { 1725: my %choices = 1726: &Apache::lonlocal::texthash ( 1727: coursecatalog => 'Display Course/Community Catalog link?', 1728: adminmail => "Display Administrator's E-mail Address?", 1729: helpdesk => 'Display "Contact Helpdesk" link', 1730: disallowlogin => "Login page requests redirected", 1731: hostid => "Server", 1732: server => "Redirect to:", 1733: serverpath => "Path", 1734: custompath => "Custom", 1735: exempt => "Exempt IP(s)", 1736: directlogin => "No redirect", 1737: newuser => "Link to create a user account", 1738: img => "Header", 1739: logo => "Main Logo", 1740: domlogo => "Domain Logo", 1741: login => "Log-in Header", 1742: textcol => "Text color", 1743: bgcol => "Box color", 1744: bgs => "Background colors", 1745: links => "Link colors", 1746: font => "Font color", 1747: pgbg => "Header", 1748: mainbg => "Page", 1749: sidebg => "Login box", 1750: link => "Link", 1751: alink => "Active link", 1752: vlink => "Visited link", 1753: headtag => "Custom markup", 1754: action => "Action", 1755: current => "Current", 1756: samllanding => "Dual login?", 1757: samloptions => "Options", 1758: alttext => "Alt text", 1759: ); 1760: return %choices; 1761: } 1762: 1763: sub login_file_options { 1764: return &Apache::lonlocal::texthash( 1765: del => 'Delete?', 1766: rep => 'Replace:', 1767: upl => 'Upload:', 1768: curr => 'View contents', 1769: default => 'Default', 1770: custom => 'Custom', 1771: none => 'None', 1772: ); 1773: } 1774: 1775: sub print_ipaccess { 1776: my ($dom,$settings,$rowtotal) = @_; 1777: my $css_class; 1778: my $itemcount = 0; 1779: my $datatable; 1780: my %ordered; 1781: if (ref($settings) eq 'HASH') { 1782: foreach my $item (keys(%{$settings})) { 1783: if (ref($settings->{$item}) eq 'HASH') { 1784: my $num = $settings->{$item}{'order'}; 1785: if ($num eq '') { 1786: $num = scalar(keys(%{$settings})); 1787: } 1788: $ordered{$num} = $item; 1789: } 1790: } 1791: } 1792: my $maxnum = scalar(keys(%ordered)); 1793: if (keys(%ordered)) { 1794: my @items = sort { $a <=> $b } keys(%ordered); 1795: for (my $i=0; $i<@items; $i++) { 1796: $css_class = $itemcount%2?' class="LC_odd_row"':''; 1797: my $item = $ordered{$items[$i]}; 1798: my ($name,$ipranges,%commblocks,%courses); 1799: if (ref($settings->{$item}) eq 'HASH') { 1800: $name = $settings->{$item}->{'name'}; 1801: $ipranges = $settings->{$item}->{'ip'}; 1802: if (ref($settings->{$item}->{'commblocks'}) eq 'HASH') { 1803: %commblocks = %{$settings->{$item}->{'commblocks'}}; 1804: } 1805: if (ref($settings->{$item}->{'courses'}) eq 'HASH') { 1806: %courses = %{$settings->{$item}->{'courses'}}; 1807: } 1808: } 1809: my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_".$item."'".');"'; 1810: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 1811: .'<select name="ipaccess_pos_'.$item.'"'.$chgstr.'>'; 1812: for (my $k=0; $k<=$maxnum; $k++) { 1813: my $vpos = $k+1; 1814: my $selstr; 1815: if ($k == $i) { 1816: $selstr = ' selected="selected" '; 1817: } 1818: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 1819: } 1820: $datatable .= '</select>'.(' 'x2). 1821: '<label><input type="checkbox" name="ipaccess_del" value="'.$item.'" />'. 1822: &mt('Delete?').'</label></span></td>'. 1823: '<td colspan="2"><input type="hidden" name="ipaccess_id_'.$i.'" value="'.$item.'" />'. 1824: &ipaccess_options($i,$itemcount,$dom,$name,$ipranges,\%commblocks,\%courses). 1825: '</td></tr>'; 1826: $itemcount ++; 1827: } 1828: } 1829: $css_class = $itemcount%2?' class="LC_odd_row"':''; 1830: my $chgstr = ' onchange="javascript:reorderIPaccess(this.form,'."'ipaccess_pos_add'".');"'; 1831: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". 1832: '<input type="hidden" name="ipaccess_maxnum" value="'.$maxnum.'" />'."\n". 1833: '<select name="ipaccess_pos_add"'.$chgstr.'>'; 1834: for (my $k=0; $k<$maxnum+1; $k++) { 1835: my $vpos = $k+1; 1836: my $selstr; 1837: if ($k == $maxnum) { 1838: $selstr = ' selected="selected" '; 1839: } 1840: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 1841: } 1842: $datatable .= '</select> '."\n". 1843: '<input type="checkbox" name="ipaccess_add" value="1" />'.&mt('Add').'</span></td>'."\n". 1844: '<td colspan="2">'. 1845: &ipaccess_options('add',$itemcount,$dom). 1846: '</td>'."\n". 1847: '</tr>'."\n"; 1848: $$rowtotal ++; 1849: return $datatable; 1850: } 1851: 1852: sub ipaccess_options { 1853: my ($num,$itemcount,$dom,$name,$ipranges,$blocksref,$coursesref) = @_; 1854: my (%currblocks,%currcourses,$output); 1855: if (ref($blocksref) eq 'HASH') { 1856: %currblocks = %{$blocksref}; 1857: } 1858: if (ref($coursesref) eq 'HASH') { 1859: %currcourses = %{$coursesref}; 1860: } 1861: $output = '<fieldset><legend>'.&mt('Location(s)').'</legend>'. 1862: '<span class="LC_nobreak">'.&mt('Name').': '. 1863: '<input type="text" name="ipaccess_name_'.$num.'" value="'.$name.'" />'. 1864: '</span></fieldset>'. 1865: '<fieldset><legend>'.&mt('IP Range(s)').'</legend>'. 1866: &mt('Format for each IP range').': '.&mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'. 1867: &mt('Range(s) will be stored as IP netblock(s) in CIDR notation (comma separated)').'<br />'. 1868: '<textarea name="ipaccess_range_'.$num.'" rows="3" cols="80">'. 1869: $ipranges.'</textarea></fieldset>'. 1870: '<fieldset><legend>'.&mt('Functionality Blocked?').'</legend>'. 1871: &blocker_checkboxes($num,$blocksref).'</fieldset>'. 1872: '<fieldset><legend>'.&mt('Courses/Communities allowed').'</legend>'. 1873: '<table>'; 1874: foreach my $cid (sort(keys(%currcourses))) { 1875: my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1}); 1876: $output .= '<tr><td><span class="LC_nobreak">'. 1877: '<label><input type="checkbox" name="ipaccess_course_delete_'.$num.'" value="'.$cid.'" />'. 1878: &mt('Delete?').' <span class="LC_cusr_emph">'.$courseinfo{'description'}.'</span></label></span>'. 1879: ' <span class="LC_fontsize_medium">('.$cid.')</span></td></tr>'; 1880: } 1881: $output .= '<tr><td><span class="LC_nobreak">'.&mt('Add').': '. 1882: '<input type="text" name="ipaccess_cdesc_'.$num.'" value="" onfocus="this.blur();opencrsbrowser('."'display','ipaccess_cnum_$num','ipaccess_cdom_$num','ipaccess_cdesc_$num'".');" />'. 1883: &Apache::loncommon::selectcourse_link('display','ipaccess_cnum_'.$num,'ipaccess_cdom_'.$num,'ipaccess_cdesc_'.$num,$dom,undef,'Course/Community'). 1884: '<input type="hidden" name="ipaccess_cnum_'.$num.'" value="" />'. 1885: '<input type="hidden" name="ipaccess_cdom_'.$num.'" value="" />'. 1886: '</span></td></tr></table>'."\n". 1887: '</fieldset>'; 1888: return $output; 1889: } 1890: 1891: sub blocker_checkboxes { 1892: my ($num,$blocks) = @_; 1893: my ($typeorder,$types) = &commblocktype_text(); 1894: my $numinrow = 6; 1895: my $output = '<table>'; 1896: for (my $i=0; $i<@{$typeorder}; $i++) { 1897: my $block = $typeorder->[$i]; 1898: my $blockstatus; 1899: if (ref($blocks) eq 'HASH') { 1900: if ($blocks->{$block} eq 'on') { 1901: $blockstatus = 'checked="checked"'; 1902: } 1903: } 1904: my $rem = $i%($numinrow); 1905: if ($rem == 0) { 1906: if ($i > 0) { 1907: $output .= '</tr>'; 1908: } 1909: $output .= '<tr>'; 1910: } 1911: if ($i == scalar(@{$typeorder})-1) { 1912: my $colsleft = $numinrow-$rem; 1913: if ($colsleft > 1) { 1914: $output .= '<td colspan="'.$colsleft.'">'; 1915: } else { 1916: $output .= '<td>'; 1917: } 1918: } else { 1919: $output .= '<td>'; 1920: } 1921: my $item = 'ipaccess_block_'.$num; 1922: if ($blockstatus) { 1923: $blockstatus = ' '.$blockstatus; 1924: } 1925: $output .= '<span class="LC_nobreak"><label>'."\n". 1926: '<input type="checkbox" name="'.$item.'"'. 1927: $blockstatus.' value="'.$block.'"'.' />'. 1928: $types->{$block}.'</label></span>'."\n". 1929: '<br /></td>'; 1930: } 1931: $output .= '</tr></table>'; 1932: return $output; 1933: } 1934: 1935: sub commblocktype_text { 1936: my %types = &Apache::lonlocal::texthash( 1937: 'com' => 'Messaging', 1938: 'chat' => 'Chat Room', 1939: 'boards' => 'Discussion', 1940: 'port' => 'Portfolio', 1941: 'groups' => 'Groups', 1942: 'blogs' => 'Blogs', 1943: 'about' => 'User Information', 1944: 'printout' => 'Printouts', 1945: 'passwd' => 'Change Password', 1946: 'grades' => 'Gradebook', 1947: 'search' => 'Course search', 1948: 'wishlist' => 'Stored links', 1949: 'annotate' => 'Annotations', 1950: ); 1951: my $typeorder = ['com','chat','boards','port','groups','blogs','about','wishlist','printout','grades','search','annotate','passwd']; 1952: return ($typeorder,\%types); 1953: } 1954: 1955: sub print_rolecolors { 1956: my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_; 1957: my %choices = &color_font_choices(); 1958: my @bgs = ('pgbg','tabbg','sidebg'); 1959: my @links = ('link','alink','vlink'); 1960: my @images = ('img'); 1961: my %alt_text = &Apache::lonlocal::texthash(img => "Banner for $role role"); 1962: my %designhash = &Apache::loncommon::get_domainconf($dom); 1963: my %defaultdesign = %Apache::loncommon::defaultdesign; 1964: my (%is_custom,%designs); 1965: my %defaults = &role_defaults($role,\@bgs,\@links,\@images); 1966: if (ref($settings) eq 'HASH') { 1967: if (ref($settings->{$role}) eq 'HASH') { 1968: if ($settings->{$role}->{'img'} ne '') { 1969: $designs{'img'} = $settings->{$role}->{'img'}; 1970: $is_custom{'img'} = 1; 1971: } 1972: if ($settings->{$role}->{'font'} ne '') { 1973: $designs{'font'} = $settings->{$role}->{'font'}; 1974: $is_custom{'font'} = 1; 1975: } 1976: if ($settings->{$role}->{'fontmenu'} ne '') { 1977: $designs{'fontmenu'} = $settings->{$role}->{'fontmenu'}; 1978: $is_custom{'fontmenu'} = 1; 1979: } 1980: foreach my $item (@bgs) { 1981: if ($settings->{$role}->{$item} ne '') { 1982: $designs{'bgs'}{$item} = $settings->{$role}->{$item}; 1983: $is_custom{$item} = 1; 1984: } 1985: } 1986: foreach my $item (@links) { 1987: if ($settings->{$role}->{$item} ne '') { 1988: $designs{'links'}{$item} = $settings->{$role}->{$item}; 1989: $is_custom{$item} = 1; 1990: } 1991: } 1992: } 1993: } else { 1994: if ($designhash{$dom.'.'.$role.'.img'} ne '') { 1995: $designs{img} = $designhash{$dom.'.'.$role.'.img'}; 1996: $is_custom{'img'} = 1; 1997: } 1998: if ($designhash{$dom.'.'.$role.'.fontmenu'} ne '') { 1999: $designs{fontmenu} = $designhash{$dom.'.'.$role.'.fontmenu'}; 2000: $is_custom{'fontmenu'} = 1; 2001: } 2002: if ($designhash{$dom.'.'.$role.'.font'} ne '') { 2003: $designs{font} = $designhash{$dom.'.'.$role.'.font'}; 2004: $is_custom{'font'} = 1; 2005: } 2006: foreach my $item (@bgs) { 2007: if ($designhash{$dom.'.'.$role.'.'.$item} ne '') { 2008: $designs{'bgs'}{$item} = $designhash{$dom.'.'.$role.'.'.$item}; 2009: $is_custom{$item} = 1; 2010: 2011: } 2012: } 2013: foreach my $item (@links) { 2014: if ($designhash{$dom.'.'.$role.'.'.$item} ne '') { 2015: $designs{'links'}{$item} = $designhash{$dom.'.'.$role.'.'.$item}; 2016: $is_custom{$item} = 1; 2017: } 2018: } 2019: } 2020: my $itemcount = 1; 2021: my $datatable = &display_color_options($dom,$confname,$phase,$role,$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal); 2022: $datatable .= '</tr></table></td></tr>'; 2023: return $datatable; 2024: } 2025: 2026: sub role_defaults { 2027: my ($role,$bgs,$links,$images,$logintext) = @_; 2028: my %defaults; 2029: unless ((ref($bgs) eq 'ARRAY') && (ref($links) eq 'ARRAY') && (ref($images) eq 'ARRAY')) { 2030: return %defaults; 2031: } 2032: my %defaultdesign = %Apache::loncommon::defaultdesign; 2033: if ($role eq 'login') { 2034: %defaults = ( 2035: font => $defaultdesign{$role.'.font'}, 2036: ); 2037: if (ref($logintext) eq 'ARRAY') { 2038: foreach my $item (@{$logintext}) { 2039: $defaults{'logintext'}{$item} = $defaultdesign{$role.'.'.$item}; 2040: } 2041: } 2042: foreach my $item (@{$images}) { 2043: $defaults{'showlogo'}{$item} = 1; 2044: } 2045: } else { 2046: %defaults = ( 2047: img => $defaultdesign{$role.'.img'}, 2048: font => $defaultdesign{$role.'.font'}, 2049: fontmenu => $defaultdesign{$role.'.fontmenu'}, 2050: ); 2051: } 2052: foreach my $item (@{$bgs}) { 2053: $defaults{'bgs'}{$item} = $defaultdesign{$role.'.'.$item}; 2054: } 2055: foreach my $item (@{$links}) { 2056: $defaults{'links'}{$item} = $defaultdesign{$role.'.'.$item}; 2057: } 2058: foreach my $item (@{$images}) { 2059: $defaults{$item} = $defaultdesign{$role.'.'.$item}; 2060: } 2061: return %defaults; 2062: } 2063: 2064: sub display_color_options { 2065: my ($dom,$confname,$phase,$role,$itemcount,$choices,$is_custom,$defaults,$designs, 2066: $images,$bgs,$links,$alt_text,$rowtotal,$logintext) = @_; 2067: my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; 2068: my $css_class = $itemcount%2?' class="LC_odd_row"':''; 2069: my $datatable = '<tr'.$css_class.'>'. 2070: '<td>'.$choices->{'font'}.'</td>'; 2071: if (!$is_custom->{'font'}) { 2072: $datatable .= '<td>'.&mt('Default in use:').' <span class="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>'; 2073: } else { 2074: $datatable .= '<td> </td>'; 2075: } 2076: my $current_color = $designs->{'font'} ? $designs->{'font'} : $defaults->{'font'}; 2077: 2078: $datatable .= '<td><span class="LC_nobreak">'. 2079: '<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'. 2080: ' value="'.$current_color.'" /> '. 2081: ' </span></td></tr>'; 2082: unless ($role eq 'login') { 2083: $datatable .= '<tr'.$css_class.'>'. 2084: '<td>'.$choices->{'fontmenu'}.'</td>'; 2085: if (!$is_custom->{'fontmenu'}) { 2086: $datatable .= '<td>'.&mt('Default in use:').' <span class="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>'; 2087: } else { 2088: $datatable .= '<td> </td>'; 2089: } 2090: $current_color = $designs->{'fontmenu'} ? 2091: $designs->{'fontmenu'} : $defaults->{'fontmenu'}; 2092: $datatable .= '<td><span class="LC_nobreak">'. 2093: '<input class="colorchooser" type="text" size="10" name="' 2094: .$role.'_fontmenu"'. 2095: ' value="'.$current_color.'" /> '. 2096: ' </span></td></tr>'; 2097: } 2098: my $switchserver = &check_switchserver($dom,$confname); 2099: foreach my $img (@{$images}) { 2100: $itemcount ++; 2101: $css_class = $itemcount%2?' class="LC_odd_row"':''; 2102: $datatable .= '<tr'.$css_class.'>'. 2103: '<td>'.$choices->{$img}; 2104: my ($imgfile,$img_import,$login_hdr_pick,$logincolors,$alttext); 2105: if ($role eq 'login') { 2106: if ($img eq 'login') { 2107: $login_hdr_pick = 2108: &login_header_options($img,$role,$defaults,$is_custom,$choices); 2109: $logincolors = 2110: &login_text_colors($img,$role,$logintext,$phase,$choices, 2111: $designs,$defaults); 2112: } else { 2113: if ($img ne 'domlogo') { 2114: $datatable.= &logo_display_options($img,$defaults,$designs); 2115: } 2116: if (ref($designs->{'alttext'}) eq 'HASH') { 2117: $alttext = $designs->{'alttext'}{$img}; 2118: } 2119: } 2120: } 2121: $datatable .= '</td>'; 2122: if ($designs->{$img} ne '') { 2123: $imgfile = $designs->{$img}; 2124: $img_import = ($imgfile =~ m{^/adm/}); 2125: } else { 2126: $imgfile = $defaults->{$img}; 2127: } 2128: if ($imgfile) { 2129: my ($showfile,$fullsize); 2130: if ($imgfile =~ m-^(/res/\Q$dom\E/\Q$confname\E/\Q$img\E)/([^/]+)$-) { 2131: my $urldir = $1; 2132: my $filename = $2; 2133: my @info = &Apache::lonnet::stat_file($designs->{$img}); 2134: if (@info) { 2135: my $thumbfile = 'tn-'.$filename; 2136: my @thumb=&Apache::lonnet::stat_file($urldir.'/'.$thumbfile); 2137: if (@thumb) { 2138: $showfile = $urldir.'/'.$thumbfile; 2139: } else { 2140: $showfile = $imgfile; 2141: } 2142: } else { 2143: $showfile = ''; 2144: } 2145: } elsif ($imgfile =~ m-^/(adm/[^/]+)/([^/]+)$-) { 2146: $showfile = $imgfile; 2147: my $imgdir = $1; 2148: my $filename = $2; 2149: if (-e "$londocroot/$imgdir/tn-".$filename) { 2150: $showfile = "/$imgdir/tn-".$filename; 2151: } else { 2152: my $input = $londocroot.$imgfile; 2153: my $output = "$londocroot/$imgdir/tn-".$filename; 2154: if (!-e $output) { 2155: my ($width,$height) = &thumb_dimensions(); 2156: my ($fullwidth,$fullheight) = &check_dimensions($input); 2157: if ($fullwidth ne '' && $fullheight ne '') { 2158: if ($fullwidth > $width && $fullheight > $height) { 2159: my $size = $width.'x'.$height; 2160: my @args = ('convert','-sample',$size,$input,$output); 2161: system({$args[0]} @args); 2162: $showfile = "/$imgdir/tn-".$filename; 2163: } 2164: } 2165: } 2166: } 2167: } 2168: if ($showfile) { 2169: if ($showfile =~ m{^/(adm|res)/}) { 2170: if ($showfile =~ m{^/res/}) { 2171: my $local_showfile = 2172: &Apache::lonnet::filelocation('',$showfile); 2173: &Apache::lonnet::repcopy($local_showfile); 2174: } 2175: $showfile = &Apache::loncommon::lonhttpdurl($showfile); 2176: } 2177: if ($imgfile) { 2178: if ($imgfile =~ m{^/(adm|res)/}) { 2179: if ($imgfile =~ m{^/res/}) { 2180: my $local_imgfile = 2181: &Apache::lonnet::filelocation('',$imgfile); 2182: &Apache::lonnet::repcopy($local_imgfile); 2183: } 2184: $fullsize = &Apache::loncommon::lonhttpdurl($imgfile); 2185: } else { 2186: $fullsize = $imgfile; 2187: } 2188: } 2189: $datatable .= '<td>'; 2190: if ($img eq 'login') { 2191: $datatable .= $login_hdr_pick; 2192: } 2193: $datatable .= &image_changes($is_custom->{$img},$alt_text->{$img},$img_import, 2194: $showfile,$fullsize,$role,$img,$imgfile,$logincolors); 2195: } else { 2196: $datatable .= '<td> </td><td class="LC_left_item">'. 2197: &mt('Upload:').'<br />'; 2198: } 2199: } else { 2200: $datatable .= '<td> </td><td class="LC_left_item">'. 2201: &mt('Upload:').'<br />'; 2202: } 2203: if ($switchserver) { 2204: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 2205: } else { 2206: if ($img ne 'login') { # suppress file selection for Log-in header 2207: $datatable .=' <input type="file" name="'.$role.'_'.$img.'" />'; 2208: } 2209: } 2210: if (($role eq 'login') && ($img ne 'login')) { 2211: $datatable .= (' ' x2).' <span class="LC_nobreak"><label>'.$choices->{'alttext'}.':'. 2212: '<input type="text" name="'.$role.'_alt_'.$img.'" size="10" value="'.$alttext.'" />'. 2213: '</label></span>'; 2214: } 2215: $datatable .= '</td></tr>'; 2216: } 2217: $itemcount ++; 2218: $css_class = $itemcount%2?' class="LC_odd_row"':''; 2219: $datatable .= '<tr'.$css_class.'>'. 2220: '<td>'.$choices->{'bgs'}.'</td>'; 2221: my $bgs_def; 2222: foreach my $item (@{$bgs}) { 2223: if (!$is_custom->{$item}) { 2224: $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>'; 2225: } 2226: } 2227: if ($bgs_def) { 2228: $datatable .= '<td>'.&mt('Default(s) in use:').'<br /><table border="0"><tr>'.$bgs_def.'</tr></table></td>'; 2229: } else { 2230: $datatable .= '<td> </td>'; 2231: } 2232: $datatable .= '<td class="LC_right_item">'. 2233: '<table border="0"><tr>'; 2234: 2235: foreach my $item (@{$bgs}) { 2236: $datatable .= '<td style="text-align: center">'.$choices->{$item}; 2237: my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item}; 2238: if ($designs->{'bgs'}{$item}) { 2239: $datatable .= ' '; 2240: } 2241: $datatable .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color. 2242: '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>'; 2243: } 2244: $datatable .= '</tr></table></td></tr>'; 2245: $itemcount ++; 2246: $css_class = $itemcount%2?' class="LC_odd_row"':''; 2247: $datatable .= '<tr'.$css_class.'>'. 2248: '<td>'.$choices->{'links'}.'</td>'; 2249: my $links_def; 2250: foreach my $item (@{$links}) { 2251: if (!$is_custom->{$item}) { 2252: $links_def .= '<td>'.$choices->{$item}.'<br /><span class="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>'; 2253: } 2254: } 2255: if ($links_def) { 2256: $datatable .= '<td>'.&mt('Default(s) in use:').'<br /><table border="0"><tr>'.$links_def.'</tr></table></td>'; 2257: } else { 2258: $datatable .= '<td> </td>'; 2259: } 2260: $datatable .= '<td class="LC_right_item">'. 2261: '<table border="0"><tr>'; 2262: foreach my $item (@{$links}) { 2263: my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item}; 2264: $datatable .= '<td style="text-align: center">'.$choices->{$item}."\n"; 2265: if ($designs->{'links'}{$item}) { 2266: $datatable.=' '; 2267: } 2268: $datatable .= '<br /><input type="text" size="8" class="colorchooser" name="'.$role.'_'.$item.'" value="'.$color. 2269: '" /></td>'; 2270: } 2271: $$rowtotal += $itemcount; 2272: return $datatable; 2273: } 2274: 2275: sub logo_display_options { 2276: my ($img,$defaults,$designs) = @_; 2277: my $checkedon; 2278: if (ref($defaults) eq 'HASH') { 2279: if (ref($defaults->{'showlogo'}) eq 'HASH') { 2280: if ($defaults->{'showlogo'}{$img}) { 2281: $checkedon = 'checked="checked" '; 2282: } 2283: } 2284: } 2285: if (ref($designs) eq 'HASH') { 2286: if (ref($designs->{'showlogo'}) eq 'HASH') { 2287: if (defined($designs->{'showlogo'}{$img})) { 2288: if ($designs->{'showlogo'}{$img} == 0) { 2289: $checkedon = ''; 2290: } elsif ($designs->{'showlogo'}{$img} == 1) { 2291: $checkedon = 'checked="checked" '; 2292: } 2293: } 2294: } 2295: } 2296: return '<br /><label> <input type="checkbox" name="'. 2297: 'login_showlogo_'.$img.'" value="1" '.$checkedon.'/>'. 2298: &mt('show').'</label>'."\n"; 2299: } 2300: 2301: sub login_header_options { 2302: my ($img,$role,$defaults,$is_custom,$choices) = @_; 2303: my $output = ''; 2304: if ((!$is_custom->{'textcol'}) || (!$is_custom->{'bgcol'})) { 2305: $output .= &mt('Text default(s):').'<br />'; 2306: if (!$is_custom->{'textcol'}) { 2307: $output .= $choices->{'textcol'}.': '.$defaults->{'logintext'}{'textcol'}. 2308: ' '; 2309: } 2310: if (!$is_custom->{'bgcol'}) { 2311: $output .= $choices->{'bgcol'}.': '. 2312: '<span id="css_'.$role.'_font" style="background-color: '. 2313: $defaults->{'logintext'}{'bgcol'}.';"> </span>'; 2314: } 2315: $output .= '<br />'; 2316: } 2317: $output .='<br />'; 2318: return $output; 2319: } 2320: 2321: sub login_text_colors { 2322: my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_; 2323: my $color_menu = '<table border="0"><tr>'; 2324: foreach my $item (@{$logintext}) { 2325: $color_menu .= '<td style="text-align: center">'.$choices->{$item}; 2326: my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item}; 2327: $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color. 2328: '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>'; 2329: } 2330: $color_menu .= '</tr></table><br />'; 2331: return $color_menu; 2332: } 2333: 2334: sub image_changes { 2335: my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_; 2336: my $output; 2337: if ($img eq 'login') { 2338: $output = '</td><td>'.$logincolors; # suppress image for Log-in header 2339: } elsif (!$is_custom) { 2340: if ($img ne 'domlogo') { 2341: $output = &mt('Default image:').'<br />'; 2342: } else { 2343: $output = &mt('Default in use:').'<br />'; 2344: } 2345: } 2346: if ($img ne 'login') { 2347: if ($img_import) { 2348: $output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />'; 2349: } 2350: $output .= '<a href="'.$fullsize.'" target="_blank"><img src="'. 2351: $showfile.'" alt="'.$alt_text.'" border="0" /></a></td>'; 2352: if ($is_custom) { 2353: $output .= '<td>'.$logincolors.'<span class="LC_nobreak"><label>'. 2354: '<input type="checkbox" name="'. 2355: $role.'_del_'.$img.'" value="1" />'.&mt('Delete?'). 2356: '</label> '.&mt('Replace:').'</span><br />'; 2357: } else { 2358: $output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />'; 2359: } 2360: } 2361: return $output; 2362: } 2363: 2364: sub print_quotas { 2365: my ($dom,$settings,$rowtotal,$action) = @_; 2366: my $context; 2367: if ($action eq 'quotas') { 2368: $context = 'tools'; 2369: } else { 2370: $context = $action; 2371: } 2372: my ($datatable,$defaultquota,$authorquota,@usertools,@options,%validations); 2373: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 2374: my $typecount = 0; 2375: my ($css_class,%titles); 2376: if ($context eq 'requestcourses') { 2377: @usertools = ('official','unofficial','community','textbook','placement','lti'); 2378: @options =('norequest','approval','validate','autolimit'); 2379: %validations = &Apache::lonnet::auto_courserequest_checks($dom); 2380: %titles = &courserequest_titles(); 2381: } elsif ($context eq 'requestauthor') { 2382: @usertools = ('author'); 2383: @options = ('norequest','approval','automatic'); 2384: %titles = &authorrequest_titles(); 2385: } else { 2386: @usertools = ('aboutme','blog','webdav','portfolio','timezone'); 2387: %titles = &tool_titles(); 2388: } 2389: if (ref($types) eq 'ARRAY') { 2390: foreach my $type (@{$types}) { 2391: my ($currdefquota,$currauthorquota); 2392: unless (($context eq 'requestcourses') || 2393: ($context eq 'requestauthor')) { 2394: if (ref($settings) eq 'HASH') { 2395: if (ref($settings->{defaultquota}) eq 'HASH') { 2396: $currdefquota = $settings->{defaultquota}->{$type}; 2397: } else { 2398: $currdefquota = $settings->{$type}; 2399: } 2400: if (ref($settings->{authorquota}) eq 'HASH') { 2401: $currauthorquota = $settings->{authorquota}->{$type}; 2402: } 2403: } 2404: } 2405: if (defined($usertypes->{$type})) { 2406: $typecount ++; 2407: $css_class = $typecount%2?' class="LC_odd_row"':''; 2408: $datatable .= '<tr'.$css_class.'>'. 2409: '<td>'.$usertypes->{$type}.'</td>'. 2410: '<td class="LC_left_item">'; 2411: if ($context eq 'requestcourses') { 2412: $datatable .= '<table><tr>'; 2413: } 2414: my %cell; 2415: foreach my $item (@usertools) { 2416: if ($context eq 'requestcourses') { 2417: my ($curroption,$currlimit); 2418: if (ref($settings) eq 'HASH') { 2419: if (ref($settings->{$item}) eq 'HASH') { 2420: $curroption = $settings->{$item}->{$type}; 2421: if ($curroption =~ /^autolimit=(\d*)$/) { 2422: $currlimit = $1; 2423: } 2424: } 2425: } 2426: if (!$curroption) { 2427: $curroption = 'norequest'; 2428: } 2429: $datatable .= '<th>'.$titles{$item}.'</th>'; 2430: foreach my $option (@options) { 2431: my $val = $option; 2432: if ($option eq 'norequest') { 2433: $val = 0; 2434: } 2435: if ($option eq 'validate') { 2436: my $canvalidate = 0; 2437: if (ref($validations{$item}) eq 'HASH') { 2438: if ($validations{$item}{$type}) { 2439: $canvalidate = 1; 2440: } 2441: } 2442: next if (!$canvalidate); 2443: } 2444: my $checked = ''; 2445: if ($option eq $curroption) { 2446: $checked = ' checked="checked"'; 2447: } elsif ($option eq 'autolimit') { 2448: if ($curroption =~ /^autolimit/) { 2449: $checked = ' checked="checked"'; 2450: } 2451: } 2452: $cell{$item} .= '<span class="LC_nobreak"><label>'. 2453: '<input type="radio" name="crsreq_'.$item. 2454: '_'.$type.'" value="'.$val.'"'.$checked.' />'. 2455: $titles{$option}.'</label>'; 2456: if ($option eq 'autolimit') { 2457: $cell{$item} .= ' <input type="text" name="crsreq_'. 2458: $item.'_limit_'.$type.'" size="1" '. 2459: 'value="'.$currlimit.'" />'; 2460: } 2461: $cell{$item} .= '</span> '; 2462: if ($option eq 'autolimit') { 2463: $cell{$item} .= $titles{'unlimited'}; 2464: } 2465: } 2466: } elsif ($context eq 'requestauthor') { 2467: my $curroption; 2468: if (ref($settings) eq 'HASH') { 2469: $curroption = $settings->{$type}; 2470: } 2471: if (!$curroption) { 2472: $curroption = 'norequest'; 2473: } 2474: foreach my $option (@options) { 2475: my $val = $option; 2476: if ($option eq 'norequest') { 2477: $val = 0; 2478: } 2479: my $checked = ''; 2480: if ($option eq $curroption) { 2481: $checked = ' checked="checked"'; 2482: } 2483: $datatable .= '<span class="LC_nobreak"><label>'. 2484: '<input type="radio" name="authorreq_'.$type. 2485: '" value="'.$val.'"'.$checked.' />'. 2486: $titles{$option}.'</label></span> '; 2487: } 2488: } else { 2489: my $checked = 'checked="checked" '; 2490: if ($item eq 'timezone') { 2491: $checked = ''; 2492: } 2493: if (ref($settings) eq 'HASH') { 2494: if (ref($settings->{$item}) eq 'HASH') { 2495: if (!$settings->{$item}->{$type}) { 2496: $checked = ''; 2497: } elsif ($settings->{$item}->{$type} == 1) { 2498: $checked = 'checked="checked" '; 2499: } 2500: } 2501: } 2502: $datatable .= '<span class="LC_nobreak"><label>'. 2503: '<input type="checkbox" name="'.$context.'_'.$item. 2504: '" value="'.$type.'" '.$checked.'/>'.$titles{$item}. 2505: '</label></span> '; 2506: } 2507: } 2508: if ($context eq 'requestcourses') { 2509: $datatable .= '</tr><tr>'; 2510: foreach my $item (@usertools) { 2511: $datatable .= '<td style="vertical-align: top">'.$cell{$item}.'</td>'; 2512: } 2513: $datatable .= '</tr></table>'; 2514: } 2515: $datatable .= '</td>'; 2516: unless (($context eq 'requestcourses') || 2517: ($context eq 'requestauthor')) { 2518: $datatable .= 2519: '<td class="LC_right_item">'. 2520: '<span class="LC_nobreak">'.&mt('Portfolio').': '. 2521: '<input type="text" name="quota_'.$type. 2522: '" value="'.$currdefquota. 2523: '" size="5" /></span>'.(' ' x 2). 2524: '<span class="LC_nobreak">'.&mt('Authoring').': '. 2525: '<input type="text" name="authorquota_'.$type. 2526: '" value="'.$currauthorquota. 2527: '" size="5" /></span></td>'; 2528: } 2529: $datatable .= '</tr>'; 2530: } 2531: } 2532: } 2533: unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { 2534: $defaultquota = '20'; 2535: $authorquota = '500'; 2536: if (ref($settings) eq 'HASH') { 2537: if (ref($settings->{'defaultquota'}) eq 'HASH') { 2538: $defaultquota = $settings->{'defaultquota'}->{'default'}; 2539: } elsif (defined($settings->{'default'})) { 2540: $defaultquota = $settings->{'default'}; 2541: } 2542: if (ref($settings->{'authorquota'}) eq 'HASH') { 2543: $authorquota = $settings->{'authorquota'}->{'default'}; 2544: } 2545: } 2546: } 2547: $typecount ++; 2548: $css_class = $typecount%2?' class="LC_odd_row"':''; 2549: $datatable .= '<tr'.$css_class.'>'. 2550: '<td>'.$othertitle.'</td>'. 2551: '<td class="LC_left_item">'; 2552: if ($context eq 'requestcourses') { 2553: $datatable .= '<table><tr>'; 2554: } 2555: my %defcell; 2556: foreach my $item (@usertools) { 2557: if ($context eq 'requestcourses') { 2558: my ($curroption,$currlimit); 2559: if (ref($settings) eq 'HASH') { 2560: if (ref($settings->{$item}) eq 'HASH') { 2561: $curroption = $settings->{$item}->{'default'}; 2562: if ($curroption =~ /^autolimit=(\d*)$/) { 2563: $currlimit = $1; 2564: } 2565: } 2566: } 2567: if (!$curroption) { 2568: $curroption = 'norequest'; 2569: } 2570: $datatable .= '<th>'.$titles{$item}.'</th>'; 2571: foreach my $option (@options) { 2572: my $val = $option; 2573: if ($option eq 'norequest') { 2574: $val = 0; 2575: } 2576: if ($option eq 'validate') { 2577: my $canvalidate = 0; 2578: if (ref($validations{$item}) eq 'HASH') { 2579: if ($validations{$item}{'default'}) { 2580: $canvalidate = 1; 2581: } 2582: } 2583: next if (!$canvalidate); 2584: } 2585: my $checked = ''; 2586: if ($option eq $curroption) { 2587: $checked = ' checked="checked"'; 2588: } elsif ($option eq 'autolimit') { 2589: if ($curroption =~ /^autolimit/) { 2590: $checked = ' checked="checked"'; 2591: } 2592: } 2593: $defcell{$item} .= '<span class="LC_nobreak"><label>'. 2594: '<input type="radio" name="crsreq_'.$item. 2595: '_default" value="'.$val.'"'.$checked.' />'. 2596: $titles{$option}.'</label>'; 2597: if ($option eq 'autolimit') { 2598: $defcell{$item} .= ' <input type="text" name="crsreq_'. 2599: $item.'_limit_default" size="1" '. 2600: 'value="'.$currlimit.'" />'; 2601: } 2602: $defcell{$item} .= '</span> '; 2603: if ($option eq 'autolimit') { 2604: $defcell{$item} .= $titles{'unlimited'}; 2605: } 2606: } 2607: } elsif ($context eq 'requestauthor') { 2608: my $curroption; 2609: if (ref($settings) eq 'HASH') { 2610: $curroption = $settings->{'default'}; 2611: } 2612: if (!$curroption) { 2613: $curroption = 'norequest'; 2614: } 2615: foreach my $option (@options) { 2616: my $val = $option; 2617: if ($option eq 'norequest') { 2618: $val = 0; 2619: } 2620: my $checked = ''; 2621: if ($option eq $curroption) { 2622: $checked = ' checked="checked"'; 2623: } 2624: $datatable .= '<span class="LC_nobreak"><label>'. 2625: '<input type="radio" name="authorreq_default"'. 2626: ' value="'.$val.'"'.$checked.' />'. 2627: $titles{$option}.'</label></span> '; 2628: } 2629: } else { 2630: my $checked = 'checked="checked" '; 2631: if (ref($settings) eq 'HASH') { 2632: if (ref($settings->{$item}) eq 'HASH') { 2633: if ($settings->{$item}->{'default'} == 0) { 2634: $checked = ''; 2635: } elsif ($settings->{$item}->{'default'} == 1) { 2636: $checked = 'checked="checked" '; 2637: } 2638: } 2639: } 2640: $datatable .= '<span class="LC_nobreak"><label>'. 2641: '<input type="checkbox" name="'.$context.'_'.$item. 2642: '" value="default" '.$checked.'/>'.$titles{$item}. 2643: '</label></span> '; 2644: } 2645: } 2646: if ($context eq 'requestcourses') { 2647: $datatable .= '</tr><tr>'; 2648: foreach my $item (@usertools) { 2649: $datatable .= '<td style="vertical-align: top">'.$defcell{$item}.'</td>'; 2650: } 2651: $datatable .= '</tr></table>'; 2652: } 2653: $datatable .= '</td>'; 2654: unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { 2655: $datatable .= '<td class="LC_right_item">'. 2656: '<span class="LC_nobreak">'.&mt('Portfolio').': '. 2657: '<input type="text" name="defaultquota" value="'. 2658: $defaultquota.'" size="5" /></span>'.(' ' x2). 2659: '<span class="LC_nobreak">'.&mt('Authoring').': '. 2660: '<input type="text" name="authorquota" value="'. 2661: $authorquota.'" size="5" /></span></td>'; 2662: } 2663: $datatable .= '</tr>'; 2664: $typecount ++; 2665: $css_class = $typecount%2?' class="LC_odd_row"':''; 2666: $datatable .= '<tr'.$css_class.'>'. 2667: '<td>'.&mt('LON-CAPA Advanced Users').'<br />'; 2668: if ($context eq 'requestcourses') { 2669: $datatable .= &mt('(overrides affiliation, if set)'). 2670: '</td>'. 2671: '<td class="LC_left_item">'. 2672: '<table><tr>'; 2673: } else { 2674: $datatable .= &mt('(overrides affiliation, if checked)'). 2675: '</td>'. 2676: '<td class="LC_left_item" colspan="2">'. 2677: '<br />'; 2678: } 2679: my %advcell; 2680: foreach my $item (@usertools) { 2681: if ($context eq 'requestcourses') { 2682: my ($curroption,$currlimit); 2683: if (ref($settings) eq 'HASH') { 2684: if (ref($settings->{$item}) eq 'HASH') { 2685: $curroption = $settings->{$item}->{'_LC_adv'}; 2686: if ($curroption =~ /^autolimit=(\d*)$/) { 2687: $currlimit = $1; 2688: } 2689: } 2690: } 2691: $datatable .= '<th>'.$titles{$item}.'</th>'; 2692: my $checked = ''; 2693: if ($curroption eq '') { 2694: $checked = ' checked="checked"'; 2695: } 2696: $advcell{$item} .= '<span class="LC_nobreak"><label>'. 2697: '<input type="radio" name="crsreq_'.$item. 2698: '__LC_adv" value=""'.$checked.' />'. 2699: &mt('No override set').'</label></span> '; 2700: foreach my $option (@options) { 2701: my $val = $option; 2702: if ($option eq 'norequest') { 2703: $val = 0; 2704: } 2705: if ($option eq 'validate') { 2706: my $canvalidate = 0; 2707: if (ref($validations{$item}) eq 'HASH') { 2708: if ($validations{$item}{'_LC_adv'}) { 2709: $canvalidate = 1; 2710: } 2711: } 2712: next if (!$canvalidate); 2713: } 2714: my $checked = ''; 2715: if ($val eq $curroption) { 2716: $checked = ' checked="checked"'; 2717: } elsif ($option eq 'autolimit') { 2718: if ($curroption =~ /^autolimit/) { 2719: $checked = ' checked="checked"'; 2720: } 2721: } 2722: $advcell{$item} .= '<span class="LC_nobreak"><label>'. 2723: '<input type="radio" name="crsreq_'.$item. 2724: '__LC_adv" value="'.$val.'"'.$checked.' />'. 2725: $titles{$option}.'</label>'; 2726: if ($option eq 'autolimit') { 2727: $advcell{$item} .= ' <input type="text" name="crsreq_'. 2728: $item.'_limit__LC_adv" size="1" '. 2729: 'value="'.$currlimit.'" />'; 2730: } 2731: $advcell{$item} .= '</span> '; 2732: if ($option eq 'autolimit') { 2733: $advcell{$item} .= $titles{'unlimited'}; 2734: } 2735: } 2736: } elsif ($context eq 'requestauthor') { 2737: my $curroption; 2738: if (ref($settings) eq 'HASH') { 2739: $curroption = $settings->{'_LC_adv'}; 2740: } 2741: my $checked = ''; 2742: if ($curroption eq '') { 2743: $checked = ' checked="checked"'; 2744: } 2745: $datatable .= '<span class="LC_nobreak"><label>'. 2746: '<input type="radio" name="authorreq__LC_adv"'. 2747: ' value=""'.$checked.' />'. 2748: &mt('No override set').'</label></span> '; 2749: foreach my $option (@options) { 2750: my $val = $option; 2751: if ($option eq 'norequest') { 2752: $val = 0; 2753: } 2754: my $checked = ''; 2755: if ($val eq $curroption) { 2756: $checked = ' checked="checked"'; 2757: } 2758: $datatable .= '<span class="LC_nobreak"><label>'. 2759: '<input type="radio" name="authorreq__LC_adv"'. 2760: ' value="'.$val.'"'.$checked.' />'. 2761: $titles{$option}.'</label></span> '; 2762: } 2763: } else { 2764: my $checked = 'checked="checked" '; 2765: if (ref($settings) eq 'HASH') { 2766: if (ref($settings->{$item}) eq 'HASH') { 2767: if ($settings->{$item}->{'_LC_adv'} == 0) { 2768: $checked = ''; 2769: } elsif ($settings->{$item}->{'_LC_adv'} == 1) { 2770: $checked = 'checked="checked" '; 2771: } 2772: } 2773: } 2774: $datatable .= '<span class="LC_nobreak"><label>'. 2775: '<input type="checkbox" name="'.$context.'_'.$item. 2776: '" value="_LC_adv" '.$checked.'/>'.$titles{$item}. 2777: '</label></span> '; 2778: } 2779: } 2780: if ($context eq 'requestcourses') { 2781: $datatable .= '</tr><tr>'; 2782: foreach my $item (@usertools) { 2783: $datatable .= '<td style="vertical-align: top">'.$advcell{$item}.'</td>'; 2784: } 2785: $datatable .= '</tr></table>'; 2786: } 2787: $datatable .= '</td></tr>'; 2788: $$rowtotal += $typecount; 2789: return $datatable; 2790: } 2791: 2792: sub print_requestmail { 2793: my ($dom,$action,$settings,$rowtotal,$customcss,$rowstyle) = @_; 2794: my ($now,$datatable,%currapp); 2795: $now = time; 2796: if (ref($settings) eq 'HASH') { 2797: if (ref($settings->{'notify'}) eq 'HASH') { 2798: if ($settings->{'notify'}{'approval'} ne '') { 2799: map {$currapp{$_}=1;} split(/,/,$settings->{'notify'}{'approval'}); 2800: } 2801: } 2802: } 2803: my $numinrow = 2; 2804: my $css_class; 2805: if ($$rowtotal%2) { 2806: $css_class = 'LC_odd_row'; 2807: } 2808: if ($customcss) { 2809: $css_class .= " $customcss"; 2810: } 2811: $css_class =~ s/^\s+//; 2812: if ($css_class) { 2813: $css_class = ' class="'.$css_class.'"'; 2814: } 2815: if ($rowstyle) { 2816: $css_class .= ' style="'.$rowstyle.'"'; 2817: } 2818: my $text; 2819: if ($action eq 'requestcourses') { 2820: $text = &mt('Receive notification of course requests requiring approval'); 2821: } elsif ($action eq 'requestauthor') { 2822: $text = &mt('Receive notification of Authoring Space requests requiring approval'); 2823: } else { 2824: $text = &mt('Receive notification of queued requests for self-created user accounts requiring approval'); 2825: } 2826: $datatable = '<tr'.$css_class.'>'. 2827: ' <td>'.$text.'</td>'. 2828: ' <td class="LC_left_item">'; 2829: my ($numdc,$table,$rows) = &active_dc_picker($dom,$numinrow,'checkbox', 2830: $action.'notifyapproval',%currapp); 2831: if ($numdc > 0) { 2832: $datatable .= $table; 2833: } else { 2834: $datatable .= &mt('There are no active Domain Coordinators'); 2835: } 2836: $datatable .='</td></tr>'; 2837: return $datatable; 2838: } 2839: 2840: sub print_studentcode { 2841: my ($settings,$rowtotal) = @_; 2842: my $rownum = 0; 2843: my ($output,%current); 2844: my @crstypes = ('official','unofficial','community','textbook','placement','lti'); 2845: if (ref($settings) eq 'HASH') { 2846: if (ref($settings->{'uniquecode'}) eq 'HASH') { 2847: foreach my $type (@crstypes) { 2848: $current{$type} = $settings->{'uniquecode'}{$type}; 2849: } 2850: } 2851: } 2852: $output .= '<tr>'. 2853: '<td class="LC_left_item">'.&mt('Generate unique six character code as course identifier?').'</td>'. 2854: '<td class="LC_left_item">'; 2855: foreach my $type (@crstypes) { 2856: my $check = ' '; 2857: if ($current{$type}) { 2858: $check = ' checked="checked" '; 2859: } 2860: $output .= '<span class="LC_nobreak"><label>'. 2861: '<input type="checkbox" name="uniquecode" value="'.$type.'"'.$check.'/>'. 2862: &mt($type).'</label></span>'.(' 'x2).' '; 2863: } 2864: $output .= '</td></tr>'; 2865: $$rowtotal ++; 2866: return $output; 2867: } 2868: 2869: sub print_textbookcourses { 2870: my ($dom,$type,$settings,$rowtotal) = @_; 2871: my $rownum = 0; 2872: my $css_class; 2873: my $itemcount = 1; 2874: my $maxnum = 0; 2875: my $bookshash; 2876: if (ref($settings) eq 'HASH') { 2877: $bookshash = $settings->{$type}; 2878: } 2879: my %ordered; 2880: if (ref($bookshash) eq 'HASH') { 2881: foreach my $item (keys(%{$bookshash})) { 2882: if (ref($bookshash->{$item}) eq 'HASH') { 2883: my $num = $bookshash->{$item}{'order'}; 2884: $ordered{$num} = $item; 2885: } 2886: } 2887: } 2888: my $confname = $dom.'-domainconfig'; 2889: my $switchserver = &check_switchserver($dom,$confname); 2890: my $maxnum = scalar(keys(%ordered)); 2891: my $datatable; 2892: if (keys(%ordered)) { 2893: my @items = sort { $a <=> $b } keys(%ordered); 2894: for (my $i=0; $i<@items; $i++) { 2895: $css_class = $itemcount%2?' class="LC_odd_row"':''; 2896: my $key = $ordered{$items[$i]}; 2897: my %coursehash=&Apache::lonnet::coursedescription($key); 2898: my $coursetitle = $coursehash{'description'}; 2899: my ($subject,$title,$author,$publisher,$image,$imgsrc,$cdom,$cnum); 2900: if (ref($bookshash->{$key}) eq 'HASH') { 2901: $subject = $bookshash->{$key}->{'subject'}; 2902: $title = $bookshash->{$key}->{'title'}; 2903: if ($type eq 'textbooks') { 2904: $publisher = $bookshash->{$key}->{'publisher'}; 2905: $author = $bookshash->{$key}->{'author'}; 2906: $image = $bookshash->{$key}->{'image'}; 2907: if ($image ne '') { 2908: my ($path,$imagefile) = ($image =~ m{^(.+)/([^/]+)$}); 2909: my $imagethumb = "$path/tn-".$imagefile; 2910: $imgsrc = '<img src="'.$imagethumb.'" alt="'.&mt('Textbook image').'" />'; 2911: } 2912: } 2913: } 2914: my $chgstr = ' onchange="javascript:reorderBooks(this.form,'."'$type".'_'."$key','$type'".');"'; 2915: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 2916: .'<select name="'.$type.'_'.$key.'"'.$chgstr.'>'; 2917: for (my $k=0; $k<=$maxnum; $k++) { 2918: my $vpos = $k+1; 2919: my $selstr; 2920: if ($k == $i) { 2921: $selstr = ' selected="selected" '; 2922: } 2923: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 2924: } 2925: $datatable .= '</select>'.(' 'x2). 2926: '<label><input type="checkbox" name="'.$type.'_del" value="'.$key.'" />'. 2927: &mt('Delete?').'</label></span></td>'. 2928: '<td colspan="2">'. 2929: '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_subject_'.$i.'" value="'.$subject.'" /></span> '. 2930: (' 'x2). 2931: '<span class="LC_nobreak">'.&mt('Title:').'<input type="text" size="30" name="'.$type.'_title_'.$i.'" value="'.$title.'" /></span> '; 2932: if ($type eq 'textbooks') { 2933: $datatable .= (' 'x2). 2934: '<span class="LC_nobreak">'.&mt('Publisher:').'<input type="text" size="10" name="'.$type.'_publisher_'.$i.'" value="'.$publisher.'" /></span> '. 2935: (' 'x2). 2936: '<span class="LC_nobreak">'.&mt('Author(s):').'<input type="text" size="25" name="'.$type.'_author_'.$i.'" value="'.$author.'" /></span> '. 2937: (' 'x2). 2938: '<span class="LC_nobreak">'.&mt('Thumbnail:'); 2939: if ($image) { 2940: $datatable .= $imgsrc. 2941: '<label><input type="checkbox" name="'.$type.'_image_del"'. 2942: ' value="'.$key.'" />'.&mt('Delete?').'</label></span> '. 2943: '<span class="LC_nobreak"> '.&mt('Replace:').' '; 2944: } 2945: if ($switchserver) { 2946: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 2947: } else { 2948: $datatable .= '<input type="file" name="'.$type.'_image_'.$i.'" value="" />'; 2949: } 2950: } 2951: $datatable .= '<input type="hidden" name="'.$type.'_id_'.$i.'" value="'.$type.'_'.$key.'" /></span> '. 2952: '<span class="LC_nobreak">'.&mt('LON-CAPA course:').' '. 2953: $coursetitle.'</span></td></tr>'."\n"; 2954: $itemcount ++; 2955: } 2956: } 2957: $css_class = $itemcount%2?' class="LC_odd_row"':''; 2958: my $chgstr = ' onchange="javascript:reorderBooks(this.form,'."'$type"."_addbook_pos','$type'".');"'; 2959: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". 2960: '<input type="hidden" name="'.$type.'_maxnum" value="'.$maxnum.'" />'."\n". 2961: '<select name="'.$type.'_addbook_pos"'.$chgstr.'>'; 2962: for (my $k=0; $k<$maxnum+1; $k++) { 2963: my $vpos = $k+1; 2964: my $selstr; 2965: if ($k == $maxnum) { 2966: $selstr = ' selected="selected" '; 2967: } 2968: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 2969: } 2970: $datatable .= '</select> '."\n". 2971: '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</span></td>'."\n". 2972: '<td colspan="2">'. 2973: '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n". 2974: (' 'x2). 2975: '<span class="LC_nobreak">'.&mt('Title:').'<input type="text" size="30" name="'.$type.'_addbook_title" value="" /></span> '."\n". 2976: (' 'x2); 2977: if ($type eq 'textbooks') { 2978: $datatable .= '<span class="LC_nobreak">'.&mt('Publisher:').'<input type="text" size="10" name="'.$type.'_addbook_publisher" value="" /></span> '."\n". 2979: (' 'x2). 2980: '<span class="LC_nobreak">'.&mt('Author(s):').'<input type="text" size="25" name="'.$type.'_addbook_author" value="" /></span> '."\n". 2981: (' 'x2). 2982: '<span class="LC_nobreak">'.&mt('Image:').' '; 2983: if ($switchserver) { 2984: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 2985: } else { 2986: $datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />'; 2987: } 2988: $datatable .= '</span>'."\n"; 2989: } 2990: $datatable .= '<span class="LC_nobreak">'.&mt('LON-CAPA course:').' '. 2991: &Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom'). 2992: '<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'. 2993: &Apache::loncommon::selectcourse_link 2994: ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course'). 2995: '</span></td>'."\n". 2996: '</tr>'."\n"; 2997: $itemcount ++; 2998: return $datatable; 2999: } 3000: 3001: sub textbookcourses_javascript { 3002: my ($settings) = @_; 3003: return unless(ref($settings) eq 'HASH'); 3004: my (%ordered,%total,%jstext); 3005: foreach my $type ('textbooks','templates') { 3006: $total{$type} = 0; 3007: if (ref($settings->{$type}) eq 'HASH') { 3008: foreach my $item (keys(%{$settings->{$type}})) { 3009: if (ref($settings->{$type}->{$item}) eq 'HASH') { 3010: my $num = $settings->{$type}->{$item}{'order'}; 3011: $ordered{$type}{$num} = $item; 3012: } 3013: } 3014: $total{$type} = scalar(keys(%{$settings->{$type}})); 3015: } 3016: my @jsarray = (); 3017: foreach my $item (sort {$a <=> $b } (keys(%{$ordered{$type}}))) { 3018: push(@jsarray,$ordered{$type}{$item}); 3019: } 3020: $jstext{$type} = ' var '.$type.' = Array('."'".join("','",@jsarray)."'".');'."\n"; 3021: } 3022: return <<"ENDSCRIPT"; 3023: <script type="text/javascript"> 3024: // <![CDATA[ 3025: function reorderBooks(form,item,caller) { 3026: var changedVal; 3027: $jstext{'textbooks'}; 3028: $jstext{'templates'}; 3029: var newpos; 3030: var maxh; 3031: if (caller == 'textbooks') { 3032: newpos = 'textbooks_addbook_pos'; 3033: maxh = 1 + $total{'textbooks'}; 3034: } else { 3035: newpos = 'templates_addbook_pos'; 3036: maxh = 1 + $total{'templates'}; 3037: } 3038: var current = new Array; 3039: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 3040: if (item == newpos) { 3041: changedVal = newitemVal; 3042: } else { 3043: changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 3044: current[newitemVal] = newpos; 3045: } 3046: if (caller == 'textbooks') { 3047: for (var i=0; i<textbooks.length; i++) { 3048: var elementName = 'textbooks_'+textbooks[i]; 3049: if (elementName != item) { 3050: if (form.elements[elementName]) { 3051: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 3052: current[currVal] = elementName; 3053: } 3054: } 3055: } 3056: } 3057: if (caller == 'templates') { 3058: for (var i=0; i<templates.length; i++) { 3059: var elementName = 'templates_'+templates[i]; 3060: if (elementName != item) { 3061: if (form.elements[elementName]) { 3062: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 3063: current[currVal] = elementName; 3064: } 3065: } 3066: } 3067: } 3068: var oldVal; 3069: for (var j=0; j<maxh; j++) { 3070: if (current[j] == undefined) { 3071: oldVal = j; 3072: } 3073: } 3074: if (oldVal < changedVal) { 3075: for (var k=oldVal+1; k<=changedVal ; k++) { 3076: var elementName = current[k]; 3077: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 3078: } 3079: } else { 3080: for (var k=changedVal; k<oldVal; k++) { 3081: var elementName = current[k]; 3082: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 3083: } 3084: } 3085: return; 3086: } 3087: 3088: // ]]> 3089: </script> 3090: 3091: ENDSCRIPT 3092: } 3093: 3094: sub ltitools_javascript { 3095: my ($settings) = @_; 3096: my $togglejs = <itools_toggle_js(); 3097: unless (ref($settings) eq 'HASH') { 3098: return $togglejs; 3099: } 3100: my (%ordered,$total,%jstext); 3101: $total = 0; 3102: foreach my $item (keys(%{$settings})) { 3103: if (ref($settings->{$item}) eq 'HASH') { 3104: my $num = $settings->{$item}{'order'}; 3105: $ordered{$num} = $item; 3106: } 3107: } 3108: $total = scalar(keys(%{$settings})); 3109: my @jsarray = (); 3110: foreach my $item (sort {$a <=> $b } (keys(%ordered))) { 3111: push(@jsarray,$ordered{$item}); 3112: } 3113: my $jstext = ' var ltitools = Array('."'".join("','",@jsarray)."'".');'."\n"; 3114: return <<"ENDSCRIPT"; 3115: <script type="text/javascript"> 3116: // <![CDATA[ 3117: function reorderLTITools(form,item) { 3118: var changedVal; 3119: $jstext 3120: var newpos = 'ltitools_add_pos'; 3121: var maxh = 1 + $total; 3122: var current = new Array; 3123: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 3124: if (item == newpos) { 3125: changedVal = newitemVal; 3126: } else { 3127: changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 3128: current[newitemVal] = newpos; 3129: } 3130: for (var i=0; i<ltitools.length; i++) { 3131: var elementName = 'ltitools_'+ltitools[i]; 3132: if (elementName != item) { 3133: if (form.elements[elementName]) { 3134: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 3135: current[currVal] = elementName; 3136: } 3137: } 3138: } 3139: var oldVal; 3140: for (var j=0; j<maxh; j++) { 3141: if (current[j] == undefined) { 3142: oldVal = j; 3143: } 3144: } 3145: if (oldVal < changedVal) { 3146: for (var k=oldVal+1; k<=changedVal ; k++) { 3147: var elementName = current[k]; 3148: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 3149: } 3150: } else { 3151: for (var k=changedVal; k<oldVal; k++) { 3152: var elementName = current[k]; 3153: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 3154: } 3155: } 3156: return; 3157: } 3158: 3159: // ]]> 3160: </script> 3161: 3162: $togglejs 3163: 3164: ENDSCRIPT 3165: } 3166: 3167: sub ltitools_toggle_js { 3168: return <<"ENDSCRIPT"; 3169: <script type="text/javascript"> 3170: // <![CDATA[ 3171: 3172: function toggleLTITools(form,setting,item) { 3173: var radioname = ''; 3174: var divid = ''; 3175: if ((setting == 'passback') || (setting == 'roster')) { 3176: radioname = 'ltitools_'+setting+'_'+item; 3177: divid = 'ltitools_'+setting+'time_'+item; 3178: var num = form.elements[radioname].length; 3179: if (num) { 3180: var setvis = ''; 3181: for (var i=0; i<num; i++) { 3182: if (form.elements[radioname][i].checked) { 3183: if (form.elements[radioname][i].value == '1') { 3184: if (document.getElementById(divid)) { 3185: document.getElementById(divid).style.display = 'inline-block'; 3186: } 3187: setvis = 1; 3188: } 3189: break; 3190: } 3191: } 3192: } 3193: if (!setvis) { 3194: if (document.getElementById(divid)) { 3195: document.getElementById(divid).style.display = 'none'; 3196: } 3197: } 3198: } 3199: if (setting == 'user') { 3200: divid = 'ltitools_'+setting+'_div_'+item; 3201: var checkid = 'ltitools_'+setting+'_field_'+item; 3202: if (document.getElementById(divid)) { 3203: if (document.getElementById(checkid)) { 3204: if (document.getElementById(checkid).checked) { 3205: document.getElementById(divid).style.display = 'inline-block'; 3206: } else { 3207: document.getElementById(divid).style.display = 'none'; 3208: } 3209: } 3210: } 3211: } 3212: return; 3213: } 3214: // ]]> 3215: </script> 3216: 3217: ENDSCRIPT 3218: } 3219: 3220: sub wafproxy_javascript { 3221: my ($dom) = @_; 3222: return <<"ENDSCRIPT"; 3223: <script type="text/javascript"> 3224: // <![CDATA[ 3225: function updateWAF() { 3226: if (document.getElementById('wafproxy_remoteip')) { 3227: var wafremote = 0; 3228: if (document.display.wafproxy_remoteip.options[document.display.wafproxy_remoteip.selectedIndex].value == 'h') { 3229: wafremote = 1; 3230: } 3231: var fields = new Array('header','trust'); 3232: for (var i=0; i<fields.length; i++) { 3233: if (document.getElementById('wafproxy_'+fields[i])) { 3234: if (wafremote == 1) { 3235: document.getElementById('wafproxy_'+fields[i]).style.display = 'table-row'; 3236: } 3237: else { 3238: document.getElementById('wafproxy_'+fields[i]).style.display = 'none'; 3239: } 3240: } 3241: } 3242: if (document.getElementById('wafproxyranges_$dom')) { 3243: if (wafremote == 1) { 3244: document.getElementById('wafproxyranges_$dom').style.display = 'inline-block'; 3245: } else { 3246: for (var i=0; i<document.display.wafproxy_vpnaccess.length; i++) { 3247: if (document.display.wafproxy_vpnaccess[i].checked) { 3248: if (document.display.wafproxy_vpnaccess[i].value == 0) { 3249: document.getElementById('wafproxyranges_$dom').style.display = 'none'; 3250: } 3251: } 3252: } 3253: } 3254: } 3255: } 3256: return; 3257: } 3258: 3259: function checkWAF() { 3260: if (document.getElementById('wafproxy_remoteip')) { 3261: var wafvpn = 0; 3262: for (var i=0; i<document.display.wafproxy_vpnaccess.length; i++) { 3263: if (document.display.wafproxy_vpnaccess[i].checked) { 3264: if (document.display.wafproxy_vpnaccess[i].value == 1) { 3265: wafvpn = 1; 3266: } 3267: break; 3268: } 3269: } 3270: var vpn = new Array('vpnint','vpnext'); 3271: for (var i=0; i<vpn.length; i++) { 3272: if (document.getElementById('wafproxy_show_'+vpn[i])) { 3273: if (wafvpn == 1) { 3274: document.getElementById('wafproxy_show_'+vpn[i]).style.display = 'table-row'; 3275: } 3276: else { 3277: document.getElementById('wafproxy_show_'+vpn[i]).style.display = 'none'; 3278: } 3279: } 3280: } 3281: if (document.getElementById('wafproxyranges_$dom')) { 3282: if (wafvpn == 1) { 3283: document.getElementById('wafproxyranges_$dom').style.display = 'inline-block'; 3284: } 3285: else if (document.display.wafproxy_remoteip.options[document.display.wafproxy_remoteip.selectedIndex].value != 'h') { 3286: document.getElementById('wafproxyranges_$dom').style.display = 'none'; 3287: } 3288: } 3289: } 3290: return; 3291: } 3292: 3293: function toggleWAF() { 3294: if (document.getElementById('wafproxy_table')) { 3295: var wafproxy = 0; 3296: for (var i=0; i<document.display.wafproxy_${dom}.length; i++) { 3297: if (document.display.wafproxy_${dom}[i].checked) { 3298: if (document.display.wafproxy_${dom}[i].value == 1) { 3299: wafproxy = 1; 3300: break; 3301: } 3302: } 3303: } 3304: if (wafproxy == 1) { 3305: document.getElementById('wafproxy_table').style.display='inline'; 3306: } 3307: else { 3308: document.getElementById('wafproxy_table').style.display='none'; 3309: } 3310: if (document.getElementById('wafproxyrow_${dom}')) { 3311: if (wafproxy == 1) { 3312: document.getElementById('wafproxyrow_${dom}').style.display = 'table-row'; 3313: } 3314: else { 3315: document.getElementById('wafproxyrow_${dom}').style.display = 'none'; 3316: } 3317: } 3318: if (document.getElementById('nowafproxyrow_$dom')) { 3319: if (wafproxy == 1) { 3320: document.getElementById('nowafproxyrow_${dom}').style.display = 'none'; 3321: } 3322: else { 3323: document.getElementById('nowafproxyrow_${dom}').style.display = 'table-row'; 3324: } 3325: } 3326: } 3327: return; 3328: } 3329: // ]]> 3330: </script> 3331: 3332: ENDSCRIPT 3333: } 3334: 3335: sub proctoring_javascript { 3336: my ($settings) = @_; 3337: my (%ordered,$total,%jstext); 3338: $total = 0; 3339: if (ref($settings) eq 'HASH') { 3340: foreach my $item (keys(%{$settings})) { 3341: if (ref($settings->{$item}) eq 'HASH') { 3342: my $num = $settings->{$item}{'order'}; 3343: $ordered{$num} = $item; 3344: } 3345: } 3346: $total = scalar(keys(%{$settings})); 3347: } else { 3348: %ordered = ( 3349: 0 => 'proctorio', 3350: 1 => 'examity', 3351: ); 3352: $total = 2; 3353: } 3354: my @jsarray = (); 3355: foreach my $item (sort {$a <=> $b } (keys(%ordered))) { 3356: push(@jsarray,$ordered{$item}); 3357: } 3358: my $jstext = ' var proctors = Array('."'".join("','",@jsarray)."'".');'."\n"; 3359: return <<"ENDSCRIPT"; 3360: <script type="text/javascript"> 3361: // <![CDATA[ 3362: function reorderProctoring(form,item) { 3363: var changedVal; 3364: $jstext 3365: var maxh = $total; 3366: var current = new Array; 3367: var changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 3368: for (var i=0; i<proctors.length; i++) { 3369: var elementName = 'proctoring_pos_'+proctors[i]; 3370: if (elementName != item) { 3371: if (form.elements[elementName]) { 3372: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 3373: current[currVal] = elementName; 3374: } 3375: } 3376: } 3377: var oldVal; 3378: for (var j=0; j<maxh; j++) { 3379: if (current[j] == undefined) { 3380: oldVal = j; 3381: } 3382: } 3383: if (oldVal < changedVal) { 3384: for (var k=oldVal+1; k<=changedVal ; k++) { 3385: var elementName = current[k]; 3386: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 3387: } 3388: } else { 3389: for (var k=changedVal; k<oldVal; k++) { 3390: var elementName = current[k]; 3391: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 3392: } 3393: } 3394: return; 3395: } 3396: 3397: function toggleProctoring(form,item) { 3398: var fieldsets = document.getElementsByClassName('proctoring_'+item); 3399: if (fieldsets.length) { 3400: var radioname = 'proctoring_available_'+item; 3401: var num = form.elements[radioname].length; 3402: if (num) { 3403: var setvis = ''; 3404: for (var i=0; i<num; i++) { 3405: if (form.elements[radioname][i].checked) { 3406: if (form.elements[radioname][i].value == '1') { 3407: setvis = 1; 3408: break; 3409: } 3410: } 3411: } 3412: for (var j=0; j<fieldsets.length; j++) { 3413: if (setvis) { 3414: fieldsets[j].style.display = 'block'; 3415: } else { 3416: fieldsets[j].style.display = 'none'; 3417: } 3418: } 3419: } 3420: } 3421: return; 3422: } 3423: 3424: // ]]> 3425: </script> 3426: 3427: ENDSCRIPT 3428: } 3429: 3430: 3431: sub lti_javascript { 3432: my ($dom,$settings) = @_; 3433: my $togglejs = <i_toggle_js($dom); 3434: unless (ref($settings) eq 'HASH') { 3435: return $togglejs; 3436: } 3437: my (%ordered,$total,%jstext); 3438: $total = scalar(keys(%{$settings})); 3439: foreach my $item (keys(%{$settings})) { 3440: if (ref($settings->{$item}) eq 'HASH') { 3441: my $num = $settings->{$item}{'order'}; 3442: if ($num eq '') { 3443: $num = $total - 1; 3444: } 3445: $ordered{$num} = $item; 3446: } 3447: } 3448: my @jsarray = (); 3449: foreach my $item (sort {$a <=> $b } (keys(%ordered))) { 3450: push(@jsarray,$ordered{$item}); 3451: } 3452: my $jstext = ' var lti = Array('."'".join("','",@jsarray)."'".');'."\n"; 3453: my $linkprot_js = &Apache::courseprefs::linkprot_javascript(); 3454: return <<"ENDSCRIPT"; 3455: <script type="text/javascript"> 3456: // <![CDATA[ 3457: function reorderLTI(form,item) { 3458: var changedVal; 3459: $jstext 3460: var newpos = 'lti_pos_add'; 3461: var maxh = 1 + $total; 3462: var current = new Array; 3463: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 3464: if (item == newpos) { 3465: changedVal = newitemVal; 3466: } else { 3467: changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 3468: current[newitemVal] = newpos; 3469: } 3470: for (var i=0; i<lti.length; i++) { 3471: var elementName = 'lti_pos_'+lti[i]; 3472: if (elementName != item) { 3473: if (form.elements[elementName]) { 3474: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 3475: current[currVal] = elementName; 3476: } 3477: } 3478: } 3479: var oldVal; 3480: for (var j=0; j<maxh; j++) { 3481: if (current[j] == undefined) { 3482: oldVal = j; 3483: } 3484: } 3485: if (oldVal < changedVal) { 3486: for (var k=oldVal+1; k<=changedVal ; k++) { 3487: var elementName = current[k]; 3488: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 3489: } 3490: } else { 3491: for (var k=changedVal; k<oldVal; k++) { 3492: var elementName = current[k]; 3493: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 3494: } 3495: } 3496: return; 3497: } 3498: 3499: $linkprot_js 3500: 3501: // ]]> 3502: </script> 3503: 3504: $togglejs 3505: 3506: ENDSCRIPT 3507: } 3508: 3509: sub lti_toggle_js { 3510: my ($dom) = @_; 3511: my %lcauthparmtext = &Apache::lonlocal::texthash ( 3512: localauth => 'Local auth argument', 3513: krb => 'Kerberos domain', 3514: ); 3515: my $crsincalert = &mt('"User\'s identity sent" needs to be set to "Yes" first,[_1] before setting "Course\'s identity sent" to "Yes"',"\n"); 3516: &js_escape(\$crsincalert); 3517: my %servers = &Apache::lonnet::get_servers($dom,'library'); 3518: my $primary = &Apache::lonnet::domain($dom,'primary'); 3519: my $course_servers = "'".join("','",keys(%servers))."'"; 3520: 3521: return <<"ENDSCRIPT"; 3522: <script type="text/javascript"> 3523: // <![CDATA[ 3524: 3525: function toggleLTI(form,setting,item) { 3526: if ((setting == 'requser') || (setting == 'crsinc')) { 3527: var usrfieldsets = document.getElementsByClassName('ltioption_usr_'+item); 3528: var setvis = ''; 3529: var radioname = 'lti_requser_'+item; 3530: var num = form.elements[radioname].length; 3531: if (num) { 3532: for (var i=0; i<num; i++) { 3533: if (form.elements[radioname][i].checked) { 3534: if (form.elements[radioname][i].value == '1') { 3535: setvis = 1; 3536: break; 3537: } 3538: } 3539: } 3540: } 3541: if (usrfieldsets.length) { 3542: for (var j=0; j<usrfieldsets.length; j++) { 3543: if (setvis) { 3544: usrfieldsets[j].style.display = 'block'; 3545: } else { 3546: usrfieldsets[j].style.display = 'none'; 3547: } 3548: } 3549: } 3550: var crsfieldsets = document.getElementsByClassName('ltioption_crs_'+item); 3551: if (crsfieldsets.length) { 3552: radioname = 'lti_crsinc_'+item; 3553: var num = form.elements[radioname].length; 3554: if (num) { 3555: var crsvis = ''; 3556: for (var i=0; i<num; i++) { 3557: if (form.elements[radioname][i].checked) { 3558: if (form.elements[radioname][i].value == '1') { 3559: if (setvis == '') { 3560: if (setting == 'crsinc'){ 3561: alert("$crsincalert"); 3562: form.elements[radioname][0].checked = true; 3563: } 3564: } else { 3565: crsvis = 1; 3566: } 3567: break; 3568: } 3569: } 3570: } 3571: setvis = crsvis; 3572: } 3573: for (var j=0; j<crsfieldsets.length; j++) { 3574: if (setvis) { 3575: crsfieldsets[j].style.display = 'block'; 3576: } else { 3577: crsfieldsets[j].style.display = 'none'; 3578: } 3579: } 3580: } 3581: } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) { 3582: var radioname = ''; 3583: var divid = ''; 3584: if (setting == 'user') { 3585: radioname = 'lti_mapuser_'+item; 3586: divid = 'lti_userfield_'+item; 3587: } else if (setting == 'crs') { 3588: radioname = 'lti_mapcrs_'+item; 3589: divid = 'lti_crsfield_'+item; 3590: } else if (setting == 'callback') { 3591: radioname = 'lti_callback_'+item; 3592: divid = 'lti_callbackfield_'+item; 3593: } else { 3594: radioname = 'lti_passback_'+item; 3595: divid = 'lti_passback_'+item; 3596: } 3597: var num = form.elements[radioname].length; 3598: if (num) { 3599: var setvis = ''; 3600: for (var i=0; i<num; i++) { 3601: if (form.elements[radioname][i].checked) { 3602: if ((setting == 'passback') || (setting == 'callback')) { 3603: if (form.elements[radioname][i].value == '1') { 3604: if (document.getElementById(divid)) { 3605: document.getElementById(divid).style.display = 'inline-block'; 3606: } 3607: setvis = 1; 3608: break; 3609: } 3610: } else { 3611: if (form.elements[radioname][i].value == 'other') { 3612: if (document.getElementById(divid)) { 3613: document.getElementById(divid).style.display = 'inline-block'; 3614: } 3615: setvis = 1; 3616: break; 3617: } 3618: } 3619: } 3620: } 3621: if (!setvis) { 3622: if (document.getElementById(divid)) { 3623: document.getElementById(divid).style.display = 'none'; 3624: } 3625: } 3626: } 3627: } else if ((setting == 'sec') || (setting == 'secsrc')) { 3628: var numsec = form.elements['lti_crssec_'+item].length; 3629: if (numsec) { 3630: var setvis = ''; 3631: for (var i=0; i<numsec; i++) { 3632: if (form.elements['lti_crssec_'+item][i].checked) { 3633: if (form.elements['lti_crssec_'+item][i].value == '1') { 3634: if (document.getElementById('lti_crssecfield_'+item)) { 3635: document.getElementById('lti_crssecfield_'+item).style.display = 'inline-block'; 3636: setvis = 1; 3637: var numsrcsec = form.elements['lti_crssecsrc_'+item].length; 3638: if (numsrcsec) { 3639: var setsrcvis = ''; 3640: for (var j=0; j<numsrcsec; j++) { 3641: if (form.elements['lti_crssecsrc_'+item][j].checked) { 3642: if (form.elements['lti_crssecsrc_'+item][j].value == 'other') { 3643: if (document.getElementById('lti_secsrcfield_'+item)) { 3644: document.getElementById('lti_secsrcfield_'+item).style.display = 'inline-block'; 3645: setsrcvis = 1; 3646: } 3647: } 3648: } 3649: } 3650: if (!setsrcvis) { 3651: if (document.getElementById('lti_secsrcfield_'+item)) { 3652: document.getElementById('lti_secsrcfield_'+item).style.display = 'none'; 3653: } 3654: } 3655: } 3656: } 3657: } 3658: } 3659: } 3660: if (!setvis) { 3661: if (document.getElementById('lti_crssecfield_'+item)) { 3662: document.getElementById('lti_crssecfield_'+item).style.display = 'none'; 3663: } 3664: if (document.getElementById('lti_secsrcfield_'+item)) { 3665: document.getElementById('lti_secsrcfield_'+item).style.display = 'none'; 3666: } 3667: } 3668: } 3669: } else if (setting == 'lcauth') { 3670: var numauth = form.elements['lti_lcauth_'+item].length; 3671: if (numauth) { 3672: for (var i=0; i<numauth; i++) { 3673: if (form.elements['lti_lcauth_'+item][i].checked) { 3674: if (document.getElementById('lti_'+setting+'_parmrow_'+item)) { 3675: if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) { 3676: document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none'; 3677: } else { 3678: document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row'; 3679: if (document.getElementById('lti_'+setting+'_parmtext_'+item)) { 3680: if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') { 3681: document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}"; 3682: } else { 3683: document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}"; 3684: } 3685: } 3686: } 3687: } 3688: } 3689: } 3690: } 3691: } else if (setting == 'lcmenu') { 3692: var menus = new Array('lti_topmenu_'+item,'lti_inlinemenu_'+item); 3693: var divid = 'lti_menufield_'+item; 3694: var setvis = ''; 3695: for (var i=0; i<menus.length; i++) { 3696: var radioname = menus[i]; 3697: var num = form.elements[radioname].length; 3698: if (num) { 3699: for (var j=0; j<num; j++) { 3700: if (form.elements[radioname][j].checked) { 3701: if (form.elements[radioname][j].value == '1') { 3702: if (document.getElementById(divid)) { 3703: document.getElementById(divid).style.display = 'inline-block'; 3704: } 3705: setvis = 1; 3706: break; 3707: } 3708: } 3709: } 3710: } 3711: if (setvis == 1) { 3712: break; 3713: } 3714: } 3715: if (!setvis) { 3716: if (document.getElementById(divid)) { 3717: document.getElementById(divid).style.display = 'none'; 3718: } 3719: } 3720: } 3721: return; 3722: } 3723: 3724: function toggleLTIEncKey(form) { 3725: var shownhosts = new Array(); 3726: var hiddenhosts = new Array(); 3727: var forcourse = new Array($course_servers); 3728: var fromdomain = '$primary'; 3729: var crsradio = form.elements['ltisec_crslinkprot']; 3730: if (crsradio.length) { 3731: for (var i=0; i<crsradio.length; i++) { 3732: if (crsradio[i].checked) { 3733: if (crsradio[i].value == 1) { 3734: if (forcourse.length > 0) { 3735: for (var j=0; j<forcourse.length; j++) { 3736: if (!shownhosts.includes(forcourse[j])) { 3737: shownhosts.push(forcourse[j]); 3738: } 3739: } 3740: } 3741: } else { 3742: if (forcourse.length > 0) { 3743: for (var j=0; j<forcourse.length; j++) { 3744: if (!hiddenhosts.includes(forcourse[j])) { 3745: hiddenhosts.push(forcourse[j]); 3746: } 3747: } 3748: } 3749: } 3750: } 3751: } 3752: } 3753: var domradio = form.elements['ltisec_domlinkprot']; 3754: if (domradio.length) { 3755: for (var i=0; i<domradio.length; i++) { 3756: if (domradio[i].checked) { 3757: if (domradio[i].value == 1) { 3758: if (!shownhosts.includes(fromdomain)) { 3759: shownhosts.push(fromdomain); 3760: } 3761: } else { 3762: if (!hiddenhosts.includes(fromdomain)) { 3763: hiddenhosts.push(fromdomain); 3764: } 3765: } 3766: } 3767: } 3768: } 3769: var consumersradio = form.elements['ltisec_consumers']; 3770: if (consumersradio.length) { 3771: for (var i=0; i<consumersradio.length; i++) { 3772: if (consumersradio[i].checked) { 3773: if (consumersradio[i].value == 1) { 3774: if (!shownhosts.includes(fromdomain)) { 3775: shownhosts.push(fromdomain); 3776: } 3777: } else { 3778: if (!hiddenhosts.includes(fromdomain)) { 3779: hiddenhosts.push(fromdomain); 3780: } 3781: } 3782: } 3783: } 3784: } 3785: if (shownhosts.length > 0) { 3786: for (var i=0; i<shownhosts.length; i++) { 3787: if (document.getElementById('ltisec_info_'+shownhosts[i])) { 3788: document.getElementById('ltisec_info_'+shownhosts[i]).style.display = 'block'; 3789: } 3790: } 3791: if (document.getElementById('ltisec_noprivkey')) { 3792: document.getElementById('ltisec_noprivkey').style.display = 'none'; 3793: } 3794: } else { 3795: if (document.getElementById('ltisec_noprivkey')) { 3796: document.getElementById('ltisec_noprivkey').style.display = 'inline-block'; 3797: } 3798: } 3799: if (hiddenhosts.length > 0) { 3800: for (var i=0; i<hiddenhosts.length; i++) { 3801: if (!shownhosts.includes(hiddenhosts[i])) { 3802: if (document.getElementById('ltisec_info_'+hiddenhosts[i])) { 3803: document.getElementById('ltisec_info_'+hiddenhosts[i]).style.display = 'none'; 3804: } 3805: } 3806: } 3807: } 3808: return; 3809: } 3810: 3811: function togglePrivKey(form,hostid) { 3812: var radioname = ''; 3813: var currdivid = ''; 3814: var newdivid = ''; 3815: if ((document.getElementById('ltisec_divcurrprivkey_'+hostid)) && 3816: (document.getElementById('ltisec_divchgprivkey_'+hostid))) { 3817: currdivid = document.getElementById('ltisec_divcurrprivkey_'+hostid); 3818: newdivid = document.getElementById('ltisec_divchgprivkey_'+hostid); 3819: radioname = form.elements['ltisec_changeprivkey_'+hostid]; 3820: if (radioname) { 3821: if (radioname.length > 0) { 3822: var setvis; 3823: for (var i=0; i<radioname.length; i++) { 3824: if (radioname[i].checked == true) { 3825: if (radioname[i].value == 1) { 3826: newdivid.style.display = 'inline-block'; 3827: currdivid.style.display = 'none'; 3828: setvis = 1; 3829: } 3830: break; 3831: } 3832: } 3833: if (!setvis) { 3834: newdivid.style.display = 'none'; 3835: currdivid.style.display = 'inline-block'; 3836: } 3837: } 3838: } 3839: } 3840: } 3841: 3842: // ]]> 3843: </script> 3844: 3845: ENDSCRIPT 3846: } 3847: 3848: sub autoupdate_javascript { 3849: return <<"ENDSCRIPT"; 3850: <script type="text/javascript"> 3851: // <![CDATA[ 3852: function toggleLastActiveDays(form) { 3853: var radioname = 'lastactive'; 3854: var divid = 'lastactive_div'; 3855: var num = form.elements[radioname].length; 3856: if (num) { 3857: var setvis = ''; 3858: for (var i=0; i<num; i++) { 3859: if (form.elements[radioname][i].checked) { 3860: if (form.elements[radioname][i].value == '1') { 3861: if (document.getElementById(divid)) { 3862: document.getElementById(divid).style.display = 'inline-block'; 3863: } 3864: setvis = 1; 3865: } 3866: break; 3867: } 3868: } 3869: if (!setvis) { 3870: if (document.getElementById(divid)) { 3871: document.getElementById(divid).style.display = 'none'; 3872: } 3873: } 3874: } 3875: return; 3876: } 3877: // ]]> 3878: </script> 3879: 3880: ENDSCRIPT 3881: } 3882: 3883: sub autoenroll_javascript { 3884: return <<"ENDSCRIPT"; 3885: <script type="text/javascript"> 3886: // <![CDATA[ 3887: function toggleFailsafe(form) { 3888: var radioname = 'autoenroll_failsafe'; 3889: var divid = 'autoenroll_failsafe_div'; 3890: var num = form.elements[radioname].length; 3891: if (num) { 3892: var setvis = ''; 3893: for (var i=0; i<num; i++) { 3894: if (form.elements[radioname][i].checked) { 3895: if ((form.elements[radioname][i].value == 'zero') || (form.elements[radioname][i].value == 'any')) { 3896: if (document.getElementById(divid)) { 3897: document.getElementById(divid).style.display = 'inline-block'; 3898: } 3899: setvis = 1; 3900: } 3901: break; 3902: } 3903: } 3904: if (!setvis) { 3905: if (document.getElementById(divid)) { 3906: document.getElementById(divid).style.display = 'none'; 3907: } 3908: } 3909: } 3910: return; 3911: } 3912: // ]]> 3913: </script> 3914: 3915: ENDSCRIPT 3916: } 3917: 3918: sub saml_javascript { 3919: return <<"ENDSCRIPT"; 3920: <script type="text/javascript"> 3921: // <![CDATA[ 3922: function toggleSamlOptions(form,hostid) { 3923: var radioname = 'saml_'+hostid; 3924: var tablecellon = 'samloptionson_'+hostid; 3925: var tablecelloff = 'samloptionsoff_'+hostid; 3926: var num = form.elements[radioname].length; 3927: if (num) { 3928: var setvis = ''; 3929: for (var i=0; i<num; i++) { 3930: if (form.elements[radioname][i].checked) { 3931: if (form.elements[radioname][i].value == '1') { 3932: if (document.getElementById(tablecellon)) { 3933: document.getElementById(tablecellon).style.display=''; 3934: } 3935: if (document.getElementById(tablecelloff)) { 3936: document.getElementById(tablecelloff).style.display='none'; 3937: } 3938: setvis = 1; 3939: } 3940: break; 3941: } 3942: } 3943: if (!setvis) { 3944: if (document.getElementById(tablecellon)) { 3945: document.getElementById(tablecellon).style.display='none'; 3946: } 3947: if (document.getElementById(tablecelloff)) { 3948: document.getElementById(tablecelloff).style.display=''; 3949: } 3950: } 3951: } 3952: return; 3953: } 3954: // ]]> 3955: </script> 3956: 3957: ENDSCRIPT 3958: } 3959: 3960: sub ipaccess_javascript { 3961: my ($settings) = @_; 3962: my (%ordered,$total,%jstext); 3963: $total = 0; 3964: if (ref($settings) eq 'HASH') { 3965: foreach my $item (keys(%{$settings})) { 3966: if (ref($settings->{$item}) eq 'HASH') { 3967: my $num = $settings->{$item}{'order'}; 3968: $ordered{$num} = $item; 3969: } 3970: } 3971: $total = scalar(keys(%{$settings})); 3972: } 3973: my @jsarray = (); 3974: foreach my $item (sort {$a <=> $b } (keys(%ordered))) { 3975: push(@jsarray,$ordered{$item}); 3976: } 3977: my $jstext = ' var ipaccess = Array('."'".join("','",@jsarray)."'".');'."\n"; 3978: return <<"ENDSCRIPT"; 3979: <script type="text/javascript"> 3980: // <![CDATA[ 3981: function reorderIPaccess(form,item) { 3982: var changedVal; 3983: $jstext 3984: var newpos = 'ipaccess_pos_add'; 3985: var maxh = 1 + $total; 3986: var current = new Array; 3987: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 3988: if (item == newpos) { 3989: changedVal = newitemVal; 3990: } else { 3991: changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 3992: current[newitemVal] = newpos; 3993: } 3994: for (var i=0; i<ipaccess.length; i++) { 3995: var elementName = 'ipaccess_pos_'+ipaccess[i]; 3996: if (elementName != item) { 3997: if (form.elements[elementName]) { 3998: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 3999: current[currVal] = elementName; 4000: } 4001: } 4002: } 4003: var oldVal; 4004: for (var j=0; j<maxh; j++) { 4005: if (current[j] == undefined) { 4006: oldVal = j; 4007: } 4008: } 4009: if (oldVal < changedVal) { 4010: for (var k=oldVal+1; k<=changedVal ; k++) { 4011: var elementName = current[k]; 4012: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 4013: } 4014: } else { 4015: for (var k=changedVal; k<oldVal; k++) { 4016: var elementName = current[k]; 4017: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 4018: } 4019: } 4020: return; 4021: } 4022: // ]]> 4023: </script> 4024: 4025: ENDSCRIPT 4026: } 4027: 4028: sub print_autoenroll { 4029: my ($dom,$settings,$rowtotal) = @_; 4030: my $autorun = &Apache::lonnet::auto_run(undef,$dom), 4031: my ($defdom,$runon,$runoff,$coownerson,$coownersoff, 4032: $failsafe,$autofailsafe,$failsafesty,%failsafechecked); 4033: $failsafesty = 'none'; 4034: %failsafechecked = ( 4035: off => ' checked="checked"', 4036: ); 4037: if (ref($settings) eq 'HASH') { 4038: if (exists($settings->{'run'})) { 4039: if ($settings->{'run'} eq '0') { 4040: $runoff = ' checked="checked" '; 4041: $runon = ' '; 4042: } else { 4043: $runon = ' checked="checked" '; 4044: $runoff = ' '; 4045: } 4046: } else { 4047: if ($autorun) { 4048: $runon = ' checked="checked" '; 4049: $runoff = ' '; 4050: } else { 4051: $runoff = ' checked="checked" '; 4052: $runon = ' '; 4053: } 4054: } 4055: if (exists($settings->{'co-owners'})) { 4056: if ($settings->{'co-owners'} eq '0') { 4057: $coownersoff = ' checked="checked" '; 4058: $coownerson = ' '; 4059: } else { 4060: $coownerson = ' checked="checked" '; 4061: $coownersoff = ' '; 4062: } 4063: } else { 4064: $coownersoff = ' checked="checked" '; 4065: $coownerson = ' '; 4066: } 4067: if (exists($settings->{'sender_domain'})) { 4068: $defdom = $settings->{'sender_domain'}; 4069: } 4070: if (exists($settings->{'failsafe'})) { 4071: $failsafe = $settings->{'failsafe'}; 4072: if ($failsafe eq 'zero') { 4073: $failsafechecked{'zero'} = ' checked="checked"'; 4074: $failsafechecked{'off'} = ''; 4075: $failsafesty = 'inline-block'; 4076: } elsif ($failsafe eq 'any') { 4077: $failsafechecked{'any'} = ' checked="checked"'; 4078: $failsafechecked{'off'} = ''; 4079: } 4080: $autofailsafe = $settings->{'autofailsafe'}; 4081: } elsif (exists($settings->{'autofailsafe'})) { 4082: $autofailsafe = $settings->{'autofailsafe'}; 4083: if ($autofailsafe ne '') { 4084: $failsafechecked{'zero'} = ' checked="checked"'; 4085: $failsafe = 'zero'; 4086: $failsafechecked{'off'} = ''; 4087: } 4088: } 4089: } else { 4090: if ($autorun) { 4091: $runon = ' checked="checked" '; 4092: $runoff = ' '; 4093: } else { 4094: $runoff = ' checked="checked" '; 4095: $runon = ' '; 4096: } 4097: } 4098: my $domform = &Apache::loncommon::select_dom_form($defdom,'sender_domain',1); 4099: my $notif_sender; 4100: if (ref($settings) eq 'HASH') { 4101: $notif_sender = $settings->{'sender_uname'}; 4102: } 4103: my $datatable='<tr class="LC_odd_row">'. 4104: '<td>'.&mt('Auto-enrollment active?').'</td>'. 4105: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4106: '<input type="radio" name="autoenroll_run"'. 4107: $runon.' value="1" />'.&mt('Yes').'</label> '. 4108: '<label><input type="radio" name="autoenroll_run"'. 4109: $runoff.' value="0" />'.&mt('No').'</label></span></td>'. 4110: '</tr><tr>'. 4111: '<td>'.&mt('Notification messages - sender'). 4112: '</td><td class="LC_right_item"><span class="LC_nobreak">'. 4113: &mt('username').': '. 4114: '<input type="text" name="sender_uname" value="'. 4115: $notif_sender.'" size="10" /> '.&mt('domain'). 4116: ': '.$domform.'</span></td></tr>'. 4117: '<tr class="LC_odd_row">'. 4118: '<td>'.&mt('Automatically assign co-ownership').'</td>'. 4119: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4120: '<input type="radio" name="autoassign_coowners"'. 4121: $coownerson.' value="1" />'.&mt('Yes').'</label> '. 4122: '<label><input type="radio" name="autoassign_coowners"'. 4123: $coownersoff.' value="0" />'.&mt('No').'</label></span></td>'. 4124: '</tr><tr>'. 4125: '<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'. 4126: '<td class="LC_left_item"><span class="LC_nobreak">'. 4127: '<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> '. 4128: '<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 />'. 4129: '<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>'. 4130: '<div class="LC_floatleft" style="display:'.$failsafesty.';" id="autoenroll_failsafe_div">'. 4131: '<span class="LC_nobreak">'. 4132: &mt('Threshold for number of students in section to drop: [_1]', 4133: '<input type="text" name="autoenroll_autofailsafe" value="'.$autofailsafe.'" size="4" />'). 4134: '</span></div></td></tr>'; 4135: $$rowtotal += 4; 4136: return $datatable; 4137: } 4138: 4139: sub print_autoupdate { 4140: my ($position,$dom,$settings,$rowtotal) = @_; 4141: my ($enable,$datatable); 4142: if ($position eq 'top') { 4143: my %choices = &Apache::lonlocal::texthash ( 4144: run => 'Auto-update active?', 4145: classlists => 'Update information in classlists?', 4146: unexpired => 'Skip updates for users without active or future roles?', 4147: lastactive => 'Skip updates for inactive users?', 4148: ); 4149: my $itemcount = 0; 4150: my $updateon = ' '; 4151: my $updateoff = ' checked="checked" '; 4152: if (ref($settings) eq 'HASH') { 4153: if ($settings->{'run'} eq '1') { 4154: $updateon = $updateoff; 4155: $updateoff = ' '; 4156: } 4157: } 4158: $enable = '<tr class="LC_odd_row">'. 4159: '<td>'.$choices{'run'}.'</td>'. 4160: '<td class="LC_left_item"><span class="LC_nobreak"><label>'. 4161: '<input type="radio" name="autoupdate_run"'. 4162: $updateoff.'value="0" />'.&mt('No').'</label> '. 4163: '<label><input type="radio" name="autoupdate_run"'. 4164: $updateon.'value="1" />'.&mt('Yes').'</label></span></td>'. 4165: '</tr>'; 4166: my @toggles = ('classlists','unexpired'); 4167: my %defaultchecked = ('classlists' => 'off', 4168: 'unexpired' => 'off' 4169: ); 4170: $$rowtotal ++; 4171: ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, 4172: \%choices,$itemcount,'','','left','no'); 4173: $datatable = $enable.$datatable; 4174: $$rowtotal += $itemcount; 4175: my $lastactiveon = ' '; 4176: my $lastactiveoff = ' checked="checked" '; 4177: my $lastactivestyle = 'none'; 4178: my $lastactivedays; 4179: my $onclick = ' onclick="javascript:toggleLastActiveDays(this.form);"'; 4180: if (ref($settings) eq 'HASH') { 4181: if ($settings->{'lastactive'} =~ /^\d+$/) { 4182: $lastactiveon = $lastactiveoff; 4183: $lastactiveoff = ' '; 4184: $lastactivestyle = 'inline-block'; 4185: $lastactivedays = $settings->{'lastactive'}; 4186: } 4187: } 4188: my $css_class = $itemcount%2?' class="LC_odd_row"':''; 4189: $datatable .= '<tr'.$css_class.'>'. 4190: '<td>'.$choices{'lastactive'}.'</td>'. 4191: '<td class="LC_left_item"><span class="LC_nobreak"><label>'. 4192: '<input type="radio" name="lastactive"'. 4193: $lastactiveoff.'value="0"'.$onclick.' />'.&mt('No').'</label>'. 4194: ' <label>'. 4195: '<input type="radio" name="lastactive"'. 4196: $lastactiveon.' value="1"'.$onclick.' />'.&mt('Yes').'</label>'. 4197: '<div id="lastactive_div" style="display:'.$lastactivestyle.';">'. 4198: ': '.&mt('inactive = no activity in last [_1] days', 4199: '<input type="text" size="5" name="lastactivedays" value="'. 4200: $lastactivedays.'" />'). 4201: '</span></td>'. 4202: '</tr>'; 4203: $$rowtotal ++; 4204: } elsif ($position eq 'middle') { 4205: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 4206: my $numinrow = 3; 4207: my $locknamesettings; 4208: $datatable .= &insttypes_row($settings,$types,$usertypes, 4209: $dom,$numinrow,$othertitle, 4210: 'lockablenames',$rowtotal); 4211: $$rowtotal ++; 4212: } else { 4213: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 4214: my @fields = ('lastname','firstname','middlename','generation', 4215: 'permanentemail','id'); 4216: my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 4217: my $numrows = 0; 4218: if (ref($types) eq 'ARRAY') { 4219: if (@{$types} > 0) { 4220: $datatable = 4221: &usertype_update_row($settings,$usertypes,\%fieldtitles, 4222: \@fields,$types,\$numrows); 4223: $$rowtotal += @{$types}; 4224: } 4225: } 4226: $datatable .= 4227: &usertype_update_row($settings,{'default' => $othertitle}, 4228: \%fieldtitles,\@fields,['default'], 4229: \$numrows); 4230: $$rowtotal ++; 4231: } 4232: return $datatable; 4233: } 4234: 4235: sub print_autocreate { 4236: my ($dom,$settings,$rowtotal) = @_; 4237: my (%createon,%createoff,%currhash); 4238: my @types = ('xml','req'); 4239: if (ref($settings) eq 'HASH') { 4240: foreach my $item (@types) { 4241: $createoff{$item} = ' checked="checked" '; 4242: $createon{$item} = ' '; 4243: if (exists($settings->{$item})) { 4244: if ($settings->{$item}) { 4245: $createon{$item} = ' checked="checked" '; 4246: $createoff{$item} = ' '; 4247: } 4248: } 4249: } 4250: if ($settings->{'xmldc'} ne '') { 4251: $currhash{$settings->{'xmldc'}} = 1; 4252: } 4253: } else { 4254: foreach my $item (@types) { 4255: $createoff{$item} = ' checked="checked" '; 4256: $createon{$item} = ' '; 4257: } 4258: } 4259: $$rowtotal += 2; 4260: my $numinrow = 2; 4261: my $datatable='<tr class="LC_odd_row">'. 4262: '<td>'.&mt('Create pending official courses from XML files').'</td>'. 4263: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4264: '<input type="radio" name="autocreate_xml"'. 4265: $createon{'xml'}.' value="1" />'.&mt('Yes').'</label> '. 4266: '<label><input type="radio" name="autocreate_xml"'. 4267: $createoff{'xml'}.' value="0" />'.&mt('No').'</label></span>'. 4268: '</td></tr><tr>'. 4269: '<td>'.&mt('Create pending requests for official courses (if validated)').'</td>'. 4270: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4271: '<input type="radio" name="autocreate_req"'. 4272: $createon{'req'}.' value="1" />'.&mt('Yes').'</label> '. 4273: '<label><input type="radio" name="autocreate_req"'. 4274: $createoff{'req'}.' value="0" />'.&mt('No').'</label></span>'; 4275: my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio', 4276: 'autocreate_xmldc',%currhash); 4277: $datatable .= '</td></tr><tr class="LC_odd_row"><td>'; 4278: if ($numdc > 1) { 4279: $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)'). 4280: '</td><td class="LC_left_item">'; 4281: } else { 4282: $datatable .= &mt('Course creation processed as:'). 4283: '</td><td class="LC_right_item">'; 4284: } 4285: $datatable .= $dctable.'</td></tr>'; 4286: $$rowtotal += $rows; 4287: return $datatable; 4288: } 4289: 4290: sub print_directorysrch { 4291: my ($position,$dom,$settings,$rowtotal) = @_; 4292: my $datatable; 4293: if ($position eq 'top') { 4294: my $instsrchon = ' '; 4295: my $instsrchoff = ' checked="checked" '; 4296: my ($exacton,$containson,$beginson); 4297: my $instlocalon = ' '; 4298: my $instlocaloff = ' checked="checked" '; 4299: if (ref($settings) eq 'HASH') { 4300: if ($settings->{'available'} eq '1') { 4301: $instsrchon = $instsrchoff; 4302: $instsrchoff = ' '; 4303: } 4304: if ($settings->{'localonly'} eq '1') { 4305: $instlocalon = $instlocaloff; 4306: $instlocaloff = ' '; 4307: } 4308: if (ref($settings->{'searchtypes'}) eq 'ARRAY') { 4309: foreach my $type (@{$settings->{'searchtypes'}}) { 4310: if ($type eq 'exact') { 4311: $exacton = ' checked="checked" '; 4312: } elsif ($type eq 'contains') { 4313: $containson = ' checked="checked" '; 4314: } elsif ($type eq 'begins') { 4315: $beginson = ' checked="checked" '; 4316: } 4317: } 4318: } else { 4319: if ($settings->{'searchtypes'} eq 'exact') { 4320: $exacton = ' checked="checked" '; 4321: } elsif ($settings->{'searchtypes'} eq 'contains') { 4322: $containson = ' checked="checked" '; 4323: } elsif ($settings->{'searchtypes'} eq 'specify') { 4324: $exacton = ' checked="checked" '; 4325: $containson = ' checked="checked" '; 4326: } 4327: } 4328: } 4329: my ($searchtitles,$titleorder) = &sorted_searchtitles(); 4330: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 4331: 4332: my $numinrow = 4; 4333: my $cansrchrow = 0; 4334: $datatable='<tr class="LC_odd_row">'. 4335: '<td colspan="2"><span class ="LC_nobreak">'.&mt('Institutional directory search available?').'</span></td>'. 4336: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4337: '<input type="radio" name="dirsrch_available"'. 4338: $instsrchon.' value="1" />'.&mt('Yes').'</label> '. 4339: '<label><input type="radio" name="dirsrch_available"'. 4340: $instsrchoff.' value="0" />'.&mt('No').'</label></span></td>'. 4341: '</tr><tr>'. 4342: '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search institution?').'</span></td>'. 4343: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4344: '<input type="radio" name="dirsrch_instlocalonly"'. 4345: $instlocaloff.' value="0" />'.&mt('Yes').'</label> '. 4346: '<label><input type="radio" name="dirsrch_instlocalonly"'. 4347: $instlocalon.' value="1" />'.&mt('No').'</label></span></td>'. 4348: '</tr>'; 4349: $$rowtotal += 2; 4350: if (ref($usertypes) eq 'HASH') { 4351: if (keys(%{$usertypes}) > 0) { 4352: $datatable .= &insttypes_row($settings,$types,$usertypes,$dom, 4353: $numinrow,$othertitle,'cansearch', 4354: $rowtotal); 4355: $cansrchrow = 1; 4356: } 4357: } 4358: if ($cansrchrow) { 4359: $$rowtotal ++; 4360: $datatable .= '<tr>'; 4361: } else { 4362: $datatable .= '<tr class="LC_odd_row">'; 4363: } 4364: $datatable .= '<td><span class ="LC_nobreak">'.&mt('Supported search methods'). 4365: '</span></td><td class="LC_left_item" colspan="2"><table><tr>'; 4366: foreach my $title (@{$titleorder}) { 4367: if (defined($searchtitles->{$title})) { 4368: my $check = ' '; 4369: if (ref($settings) eq 'HASH') { 4370: if (ref($settings->{'searchby'}) eq 'ARRAY') { 4371: if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) { 4372: $check = ' checked="checked" '; 4373: } 4374: } 4375: } 4376: $datatable .= '<td class="LC_left_item">'. 4377: '<span class="LC_nobreak"><label>'. 4378: '<input type="checkbox" name="searchby" '. 4379: 'value="'.$title.'"'.$check.'/>'. 4380: $searchtitles->{$title}.'</label></span></td>'; 4381: } 4382: } 4383: $datatable .= '</tr></table></td></tr>'; 4384: $$rowtotal ++; 4385: if ($cansrchrow) { 4386: $datatable .= '<tr class="LC_odd_row">'; 4387: } else { 4388: $datatable .= '<tr>'; 4389: } 4390: $datatable .= '<td><span class ="LC_nobreak">'.&mt('Search latitude').'</span></td>'. 4391: '<td class="LC_left_item" colspan="2">'. 4392: '<span class="LC_nobreak"><label>'. 4393: '<input type="checkbox" name="searchtypes" '. 4394: $exacton.' value="exact" />'.&mt('Exact match'). 4395: '</label> '. 4396: '<label><input type="checkbox" name="searchtypes" '. 4397: $beginson.' value="begins" />'.&mt('Begins with'). 4398: '</label> '. 4399: '<label><input type="checkbox" name="searchtypes" '. 4400: $containson.' value="contains" />'.&mt('Contains'). 4401: '</label></span></td></tr>'; 4402: $$rowtotal ++; 4403: } else { 4404: my $domsrchon = ' checked="checked" '; 4405: my $domsrchoff = ' '; 4406: my $domlocalon = ' '; 4407: my $domlocaloff = ' checked="checked" '; 4408: if (ref($settings) eq 'HASH') { 4409: if ($settings->{'lclocalonly'} eq '1') { 4410: $domlocalon = $domlocaloff; 4411: $domlocaloff = ' '; 4412: } 4413: if ($settings->{'lcavailable'} eq '0') { 4414: $domsrchoff = $domsrchon; 4415: $domsrchon = ' '; 4416: } 4417: } 4418: $datatable='<tr class="LC_odd_row">'. 4419: '<td colspan="2"><span class ="LC_nobreak">'.&mt('LON-CAPA directory search available?').'</span></td>'. 4420: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4421: '<input type="radio" name="dirsrch_domavailable"'. 4422: $domsrchon.' value="1" />'.&mt('Yes').'</label> '. 4423: '<label><input type="radio" name="dirsrch_domavailable"'. 4424: $domsrchoff.' value="0" />'.&mt('No').'</label></span></td>'. 4425: '</tr><tr>'. 4426: '<td colspan="2"><span class ="LC_nobreak">'.&mt('Other domains can search LON-CAPA domain?').'</span></td>'. 4427: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 4428: '<input type="radio" name="dirsrch_domlocalonly"'. 4429: $domlocaloff.' value="0" />'.&mt('Yes').'</label> '. 4430: '<label><input type="radio" name="dirsrch_domlocalonly"'. 4431: $domlocalon.' value="1" />'.&mt('No').'</label></span></td>'. 4432: '</tr>'; 4433: $$rowtotal += 2; 4434: } 4435: return $datatable; 4436: } 4437: 4438: sub print_contacts { 4439: my ($position,$dom,$settings,$rowtotal) = @_; 4440: my $datatable; 4441: my @contacts = ('adminemail','supportemail'); 4442: my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield, 4443: $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus); 4444: if ($position eq 'top') { 4445: if (ref($settings) eq 'HASH') { 4446: foreach my $item (@contacts) { 4447: if (exists($settings->{$item})) { 4448: $to{$item} = $settings->{$item}; 4449: } 4450: } 4451: } 4452: } elsif ($position eq 'middle') { 4453: @mailings = ('errormail','packagesmail','lonstatusmail','requestsmail', 4454: 'updatesmail','idconflictsmail','hostipmail'); 4455: foreach my $type (@mailings) { 4456: $otheremails{$type} = ''; 4457: } 4458: } elsif ($position eq 'lower') { 4459: if (ref($settings) eq 'HASH') { 4460: if (ref($settings->{'lonstatus'}) eq 'HASH') { 4461: %lonstatus = %{$settings->{'lonstatus'}}; 4462: } 4463: } 4464: } else { 4465: @mailings = ('helpdeskmail','otherdomsmail'); 4466: foreach my $type (@mailings) { 4467: $otheremails{$type} = ''; 4468: } 4469: $bccemails{'helpdeskmail'} = ''; 4470: $bccemails{'otherdomsmail'} = ''; 4471: $includestr{'helpdeskmail'} = ''; 4472: $includestr{'otherdomsmail'} = ''; 4473: ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields(); 4474: } 4475: if (ref($settings) eq 'HASH') { 4476: unless (($position eq 'top') || ($position eq 'lower')) { 4477: foreach my $type (@mailings) { 4478: if (exists($settings->{$type})) { 4479: if (ref($settings->{$type}) eq 'HASH') { 4480: foreach my $item (@contacts) { 4481: if ($settings->{$type}{$item}) { 4482: $checked{$type}{$item} = ' checked="checked" '; 4483: } 4484: } 4485: $otheremails{$type} = $settings->{$type}{'others'}; 4486: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 4487: $bccemails{$type} = $settings->{$type}{'bcc'}; 4488: if ($settings->{$type}{'include'} ne '') { 4489: ($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2); 4490: $includestr{$type} = &unescape($includestr{$type}); 4491: } 4492: } 4493: } 4494: } elsif ($type eq 'lonstatusmail') { 4495: $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; 4496: } 4497: } 4498: } 4499: if ($position eq 'bottom') { 4500: foreach my $type (@mailings) { 4501: $bccemails{$type} = $settings->{$type}{'bcc'}; 4502: if ($settings->{$type}{'include'} ne '') { 4503: ($includeloc{$type},$includestr{$type}) = split(/:/,$settings->{$type}{'include'},2); 4504: $includestr{$type} = &unescape($includestr{$type}); 4505: } 4506: } 4507: if (ref($settings->{'helpform'}) eq 'HASH') { 4508: if (ref($fields) eq 'ARRAY') { 4509: foreach my $field (@{$fields}) { 4510: $currfield{$field} = $settings->{'helpform'}{$field}; 4511: } 4512: } 4513: if (exists($settings->{'helpform'}{'maxsize'})) { 4514: $maxsize = $settings->{'helpform'}{'maxsize'}; 4515: } else { 4516: $maxsize = '1.0'; 4517: } 4518: } else { 4519: if (ref($fields) eq 'ARRAY') { 4520: foreach my $field (@{$fields}) { 4521: $currfield{$field} = 'yes'; 4522: } 4523: } 4524: $maxsize = '1.0'; 4525: } 4526: } 4527: } else { 4528: if ($position eq 'top') { 4529: $to{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'}; 4530: $to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'}; 4531: $checked{'errormail'}{'adminemail'} = ' checked="checked" '; 4532: $checked{'packagesmail'}{'adminemail'} = ' checked="checked" '; 4533: $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; 4534: $checked{'requestsmail'}{'adminemail'} = ' checked="checked" '; 4535: $checked{'updatesmail'}{'adminemail'} = ' checked="checked" '; 4536: $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" '; 4537: $checked{'hostipmail'}{'adminemail'} = ' checked="checked" '; 4538: } elsif ($position eq 'bottom') { 4539: $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" '; 4540: $checked{'otherdomsmail'}{'supportemail'} = ' checked="checked" '; 4541: if (ref($fields) eq 'ARRAY') { 4542: foreach my $field (@{$fields}) { 4543: $currfield{$field} = 'yes'; 4544: } 4545: } 4546: $maxsize = '1.0'; 4547: } 4548: } 4549: my ($titles,$short_titles) = &contact_titles(); 4550: my $rownum = 0; 4551: my $css_class; 4552: if ($position eq 'top') { 4553: foreach my $item (@contacts) { 4554: $css_class = $rownum%2?' class="LC_odd_row"':''; 4555: $datatable .= '<tr'.$css_class.'>'. 4556: '<td><span class="LC_nobreak">'.$titles->{$item}. 4557: '</span></td><td class="LC_right_item">'. 4558: '<input type="text" name="'.$item.'" value="'. 4559: $to{$item}.'" /></td></tr>'; 4560: $rownum ++; 4561: } 4562: } elsif ($position eq 'bottom') { 4563: $css_class = $rownum%2?' class="LC_odd_row"':''; 4564: $datatable .= '<tr'.$css_class.'>'. 4565: '<td>'.&mt('Extra helpdesk form fields:').'<br />'. 4566: &mt('(e-mail, subject, and description always shown)'). 4567: '</td><td class="LC_left_item">'; 4568: if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') && 4569: (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) { 4570: $datatable .= '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Status').'</th></tr>'; 4571: foreach my $field (@{$fields}) { 4572: $datatable .= '<tr><td>'.$fieldtitles->{$field}; 4573: if (($field eq 'screenshot') || ($field eq 'cc')) { 4574: $datatable .= ' '.&mt('(logged-in users)'); 4575: } 4576: $datatable .='</td><td>'; 4577: my $clickaction; 4578: if ($field eq 'screenshot') { 4579: $clickaction = ' onclick="screenshotSize(this);"'; 4580: } 4581: if (ref($possoptions->{$field}) eq 'ARRAY') { 4582: foreach my $option (@{$possoptions->{$field}}) { 4583: my $checked; 4584: if ($currfield{$field} eq $option) { 4585: $checked = ' checked="checked"'; 4586: } 4587: $datatable .= '<span class="LC_nobreak"><label>'. 4588: '<input type="radio" name="helpform_'.$field.'" '. 4589: 'value="'.$option.'"'.$checked.$clickaction.' />'.$fieldoptions->{$option}. 4590: '</label></span>'.(' 'x2); 4591: } 4592: } 4593: if ($field eq 'screenshot') { 4594: my $display; 4595: if ($currfield{$field} eq 'no') { 4596: $display = ' style="display:none"'; 4597: } 4598: $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.'>'. 4599: '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'. 4600: '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />'; 4601: } 4602: $datatable .= '</td></tr>'; 4603: } 4604: $datatable .= '</table>'; 4605: } 4606: $datatable .= '</td></tr>'."\n"; 4607: $rownum ++; 4608: } 4609: unless (($position eq 'top') || ($position eq 'lower')) { 4610: foreach my $type (@mailings) { 4611: $css_class = $rownum%2?' class="LC_odd_row"':''; 4612: $datatable .= '<tr'.$css_class.'>'. 4613: '<td><span class="LC_nobreak">'. 4614: $titles->{$type}.': </span></td>'. 4615: '<td class="LC_left_item">'; 4616: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 4617: $datatable .= '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>'; 4618: } 4619: $datatable .= '<span class="LC_nobreak">'; 4620: foreach my $item (@contacts) { 4621: $datatable .= '<label>'. 4622: '<input type="checkbox" name="'.$type.'"'. 4623: $checked{$type}{$item}. 4624: ' value="'.$item.'" />'.$short_titles->{$item}. 4625: '</label> '; 4626: } 4627: $datatable .= '</span><br />'.&mt('Others').': '. 4628: '<input type="text" name="'.$type.'_others" '. 4629: 'value="'.$otheremails{$type}.'" />'; 4630: my %locchecked; 4631: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 4632: foreach my $loc ('s','b') { 4633: if ($includeloc{$type} eq $loc) { 4634: $locchecked{$loc} = ' checked="checked"'; 4635: last; 4636: } 4637: } 4638: $datatable .= '<br />'.&mt('Bcc:').(' 'x6). 4639: '<input type="text" name="'.$type.'_bcc" '. 4640: 'value="'.$bccemails{$type}.'" /></fieldset>'. 4641: '<fieldset><legend>'.&mt('Optional added text').'</legend>'. 4642: &mt('Text automatically added to e-mail:').' '. 4643: '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br />'. 4644: '<span class="LC_nobreak">'.&mt('Location:').' '. 4645: '<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'. 4646: (' 'x2). 4647: '<label><input type="radio" name="'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'. 4648: '</span></fieldset>'; 4649: } 4650: $datatable .= '</td></tr>'."\n"; 4651: $rownum ++; 4652: } 4653: } 4654: if ($position eq 'middle') { 4655: my %choices; 4656: my $corelink = &core_link_msu(); 4657: $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink); 4658: $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]', 4659: $corelink); 4660: $choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink); 4661: my @toggles = ('reporterrors','reportupdates','reportstatus'); 4662: my %defaultchecked = ('reporterrors' => 'on', 4663: 'reportupdates' => 'on', 4664: 'reportstatus' => 'on'); 4665: (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, 4666: \%choices,$rownum); 4667: $datatable .= $reports; 4668: } elsif ($position eq 'lower') { 4669: my (%current,%excluded,%weights); 4670: my ($defaults,$names) = &Apache::loncommon::lon_status_items(); 4671: if ($lonstatus{'threshold'} =~ /^\d+$/) { 4672: $current{'errorthreshold'} = $lonstatus{'threshold'}; 4673: } else { 4674: $current{'errorthreshold'} = $defaults->{'threshold'}; 4675: } 4676: if ($lonstatus{'sysmail'} =~ /^\d+$/) { 4677: $current{'errorsysmail'} = $lonstatus{'sysmail'}; 4678: } else { 4679: $current{'errorsysmail'} = $defaults->{'sysmail'}; 4680: } 4681: if (ref($lonstatus{'weights'}) eq 'HASH') { 4682: foreach my $type ('E','W','N','U') { 4683: if ($lonstatus{'weights'}{$type} =~ /^\d+$/) { 4684: $weights{$type} = $lonstatus{'weights'}{$type}; 4685: } else { 4686: $weights{$type} = $defaults->{$type}; 4687: } 4688: } 4689: } else { 4690: foreach my $type ('E','W','N','U') { 4691: $weights{$type} = $defaults->{$type}; 4692: } 4693: } 4694: if (ref($lonstatus{'excluded'}) eq 'ARRAY') { 4695: if (@{$lonstatus{'excluded'}} > 0) { 4696: map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}}; 4697: } 4698: } 4699: foreach my $item ('errorthreshold','errorsysmail') { 4700: $css_class = $rownum%2?' class="LC_odd_row"':''; 4701: $datatable .= '<tr'.$css_class.'>'. 4702: '<td class="LC_left_item"><span class="LC_nobreak">'. 4703: $titles->{$item}. 4704: '</span></td><td class="LC_left_item">'. 4705: '<input type="text" name="'.$item.'" value="'. 4706: $current{$item}.'" size="5" /></td></tr>'; 4707: $rownum ++; 4708: } 4709: $css_class = $rownum%2?' class="LC_odd_row"':''; 4710: $datatable .= '<tr'.$css_class.'>'. 4711: '<td class="LC_left_item">'. 4712: '<span class="LC_nobreak">'.$titles->{'errorweights'}. 4713: '</span></td><td class="LC_left_item"><table><tr>'; 4714: foreach my $type ('E','W','N','U') { 4715: $datatable .= '<td>'.$names->{$type}.'<br />'. 4716: '<input type="text" name="errorweights_'.$type.'" value="'. 4717: $weights{$type}.'" size="5" /></td>'; 4718: } 4719: $datatable .= '</tr></table></tr>'; 4720: $rownum ++; 4721: $css_class = $rownum%2?' class="LC_odd_row"':''; 4722: $datatable .= '<tr'.$css_class.'><td class="LC_left_item">'. 4723: $titles->{'errorexcluded'}.'</td>'. 4724: '<td class="LC_left_item"><table>'; 4725: my $numinrow = 4; 4726: my @ids = sort(values(%Apache::lonnet::serverhomeIDs)); 4727: for (my $i=0; $i<@ids; $i++) { 4728: my $rem = $i%($numinrow); 4729: if ($rem == 0) { 4730: if ($i > 0) { 4731: $datatable .= '</tr>'; 4732: } 4733: $datatable .= '<tr>'; 4734: } 4735: my $check; 4736: if ($excluded{$ids[$i]}) { 4737: $check = ' checked="checked" '; 4738: } 4739: $datatable .= '<td class="LC_left_item">'. 4740: '<span class="LC_nobreak"><label>'. 4741: '<input type="checkbox" name="errorexcluded" '. 4742: 'value="'.$ids[$i].'"'.$check.' />'. 4743: $ids[$i].'</label></span></td>'; 4744: } 4745: my $colsleft = $numinrow - @ids%($numinrow); 4746: if ($colsleft > 1 ) { 4747: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 4748: ' </td>'; 4749: } elsif ($colsleft == 1) { 4750: $datatable .= '<td class="LC_left_item"> </td>'; 4751: } 4752: $datatable .= '</tr></table></td></tr>'; 4753: $rownum ++; 4754: } elsif ($position eq 'bottom') { 4755: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 4756: my (@posstypes,%usertypeshash); 4757: if (ref($types) eq 'ARRAY') { 4758: @posstypes = @{$types}; 4759: } 4760: if (@posstypes) { 4761: if (ref($usertypes) eq 'HASH') { 4762: %usertypeshash = %{$usertypes}; 4763: } 4764: my @overridden; 4765: my $numinrow = 4; 4766: if (ref($settings) eq 'HASH') { 4767: if (ref($settings->{'overrides'}) eq 'HASH') { 4768: foreach my $key (sort(keys(%{$settings->{'overrides'}}))) { 4769: if (ref($settings->{'overrides'}{$key}) eq 'HASH') { 4770: push(@overridden,$key); 4771: foreach my $item (@contacts) { 4772: if ($settings->{'overrides'}{$key}{$item}) { 4773: $checked{'override_'.$key}{$item} = ' checked="checked" '; 4774: } 4775: } 4776: $otheremails{'override_'.$key} = $settings->{'overrides'}{$key}{'others'}; 4777: $bccemails{'override_'.$key} = $settings->{'overrides'}{$key}{'bcc'}; 4778: $includeloc{'override_'.$key} = ''; 4779: $includestr{'override_'.$key} = ''; 4780: if ($settings->{'overrides'}{$key}{'include'} ne '') { 4781: ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = 4782: split(/:/,$settings->{'overrides'}{$key}{'include'},2); 4783: $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key}); 4784: } 4785: } 4786: } 4787: } 4788: } 4789: my $customclass = 'LC_helpdesk_override'; 4790: my $optionsprefix = 'LC_options_helpdesk_'; 4791: 4792: my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');"; 4793: 4794: $datatable .= &insttypes_row($settings,$types,$usertypes,$dom, 4795: $numinrow,$othertitle,'overrides', 4796: \$rownum,$onclicktypes,$customclass); 4797: $rownum ++; 4798: $usertypeshash{'default'} = $othertitle; 4799: foreach my $status (@posstypes) { 4800: my $css_class; 4801: if ($rownum%2) { 4802: $css_class = 'LC_odd_row '; 4803: } 4804: $css_class .= $customclass; 4805: my $rowid = $optionsprefix.$status; 4806: my $hidden = 1; 4807: my $currstyle = 'display:none'; 4808: if (grep(/^\Q$status\E$/,@overridden)) { 4809: $currstyle = 'display:table-row'; 4810: $hidden = 0; 4811: } 4812: my $key = 'override_'.$status; 4813: $datatable .= &overridden_helpdesk($checked{$key},$otheremails{$key},$bccemails{$key}, 4814: $includeloc{$key},$includestr{$key},$status,$rowid, 4815: $usertypeshash{$status},$css_class,$currstyle, 4816: \@contacts,$short_titles); 4817: unless ($hidden) { 4818: $rownum ++; 4819: } 4820: } 4821: } 4822: } 4823: $$rowtotal += $rownum; 4824: return $datatable; 4825: } 4826: 4827: sub core_link_msu { 4828: return &Apache::loncommon::modal_link('http://loncapa.org/core.html', 4829: &mt('LON-CAPA core group - MSU'),600,500); 4830: } 4831: 4832: sub overridden_helpdesk { 4833: my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid, 4834: $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_; 4835: my $class = 'LC_left_item'; 4836: if ($css_class) { 4837: $css_class = ' class="'.$css_class.'"'; 4838: } 4839: if ($rowid) { 4840: $rowid = ' id="'.$rowid.'"'; 4841: } 4842: if ($rowstyle) { 4843: $rowstyle = ' style="'.$rowstyle.'"'; 4844: } 4845: my ($output,$description); 4846: $description = &mt('Helpdesk requests from: [_1] in this domain (overrides default)',"<b>$typetitle</b>"); 4847: $output = '<tr'.$css_class.$rowid.$rowstyle.'>'. 4848: "<td>$description</td>\n". 4849: '<td class="'.$class.'" colspan="2">'. 4850: '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>'. 4851: '<span class="LC_nobreak">'; 4852: if (ref($contacts) eq 'ARRAY') { 4853: foreach my $item (@{$contacts}) { 4854: my $check; 4855: if (ref($checked) eq 'HASH') { 4856: $check = $checked->{$item}; 4857: } 4858: my $title; 4859: if (ref($short_titles) eq 'HASH') { 4860: $title = $short_titles->{$item}; 4861: } 4862: $output .= '<label>'. 4863: '<input type="checkbox" name="override_'.$type.'"'.$check. 4864: ' value="'.$item.'" />'.$title.'</label> '; 4865: } 4866: } 4867: $output .= '</span><br />'.&mt('Others').': '. 4868: '<input type="text" name="override_'.$type.'_others" '. 4869: 'value="'.$otheremails.'" />'; 4870: my %locchecked; 4871: foreach my $loc ('s','b') { 4872: if ($includeloc eq $loc) { 4873: $locchecked{$loc} = ' checked="checked"'; 4874: last; 4875: } 4876: } 4877: $output .= '<br />'.&mt('Bcc:').(' 'x6). 4878: '<input type="text" name="override_'.$type.'_bcc" '. 4879: 'value="'.$bccemails.'" /></fieldset>'. 4880: '<fieldset><legend>'.&mt('Optional added text').'</legend>'. 4881: &mt('Text automatically added to e-mail:').' '. 4882: '<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br />'. 4883: '<span class="LC_nobreak">'.&mt('Location:').' '. 4884: '<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'. 4885: (' 'x2). 4886: '<label><input type="radio" name="override_'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'. 4887: '</span></fieldset>'. 4888: '</td></tr>'."\n"; 4889: return $output; 4890: } 4891: 4892: sub contacts_javascript { 4893: return <<"ENDSCRIPT"; 4894: 4895: <script type="text/javascript"> 4896: // <![CDATA[ 4897: 4898: function screenshotSize(field) { 4899: if (document.getElementById('help_screenshotsize')) { 4900: if (field.value == 'no') { 4901: document.getElementById('help_screenshotsize').style.display="none"; 4902: } else { 4903: document.getElementById('help_screenshotsize').style.display=""; 4904: } 4905: } 4906: return; 4907: } 4908: 4909: function toggleHelpdeskRow(form,checkbox,target,prefix,docount) { 4910: if (form.elements[checkbox].length != undefined) { 4911: var count = 0; 4912: if (docount) { 4913: for (var i=0; i<form.elements[checkbox].length; i++) { 4914: if (form.elements[checkbox][i].checked) { 4915: count ++; 4916: } 4917: } 4918: } 4919: for (var i=0; i<form.elements[checkbox].length; i++) { 4920: var type = form.elements[checkbox][i].value; 4921: if (document.getElementById(prefix+type)) { 4922: if (form.elements[checkbox][i].checked) { 4923: document.getElementById(prefix+type).style.display = 'table-row'; 4924: if (count % 2 == 1) { 4925: document.getElementById(prefix+type).className = target+' LC_odd_row'; 4926: } else { 4927: document.getElementById(prefix+type).className = target; 4928: } 4929: count ++; 4930: } else { 4931: document.getElementById(prefix+type).style.display = 'none'; 4932: } 4933: } 4934: } 4935: } 4936: return; 4937: } 4938: 4939: 4940: // ]]> 4941: </script> 4942: 4943: ENDSCRIPT 4944: } 4945: 4946: sub print_helpsettings { 4947: my ($position,$dom,$settings,$rowtotal) = @_; 4948: my $confname = $dom.'-domainconfig'; 4949: my $formname = 'display'; 4950: my ($datatable,$itemcount); 4951: if ($position eq 'top') { 4952: $itemcount = 1; 4953: my (%choices,%defaultchecked,@toggles); 4954: $choices{'submitbugs'} = &mt('Display link to: [_1]?', 4955: &Apache::loncommon::modal_link('http://bugs.loncapa.org', 4956: &mt('LON-CAPA bug tracker'),600,500)); 4957: %defaultchecked = ('submitbugs' => 'on'); 4958: @toggles = ('submitbugs'); 4959: ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, 4960: \%choices,$itemcount); 4961: $$rowtotal ++; 4962: } else { 4963: my $css_class; 4964: my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_'); 4965: my (%customroles,%ordered,%current); 4966: if (ref($settings) eq 'HASH') { 4967: if (ref($settings->{'adhoc'}) eq 'HASH') { 4968: %current = %{$settings->{'adhoc'}}; 4969: } 4970: } 4971: my $count = 0; 4972: foreach my $key (sort(keys(%existing))) { 4973: if ($key=~/^rolesdef\_(\w+)$/) { 4974: my $rolename = $1; 4975: my (%privs,$order); 4976: ($privs{'system'},$privs{'domain'},$privs{'course'}) = split(/\_/,$existing{$key}); 4977: $customroles{$rolename} = \%privs; 4978: if (ref($current{$rolename}) eq 'HASH') { 4979: $order = $current{$rolename}{'order'}; 4980: } 4981: if ($order eq '') { 4982: $order = $count; 4983: } 4984: $ordered{$order} = $rolename; 4985: $count++; 4986: } 4987: } 4988: my $maxnum = scalar(keys(%ordered)); 4989: my @roles_by_num = (); 4990: foreach my $item (sort {$a <=> $b } (keys(%ordered))) { 4991: push(@roles_by_num,$item); 4992: } 4993: my $context = 'domprefs'; 4994: my $crstype = 'Course'; 4995: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 4996: my @accesstypes = ('all','dh','da','none'); 4997: my ($numstatustypes,@jsarray); 4998: if (ref($types) eq 'ARRAY') { 4999: if (@{$types} > 0) { 5000: $numstatustypes = scalar(@{$types}); 5001: push(@accesstypes,'status'); 5002: @jsarray = ('bystatus'); 5003: } 5004: } 5005: my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']); 5006: if (keys(%domhelpdesk)) { 5007: push(@accesstypes,('inc','exc')); 5008: push(@jsarray,('notinc','notexc')); 5009: } 5010: my $hiddenstr = join("','",@jsarray); 5011: my $context = 'domprefs'; 5012: my $crstype = 'Course'; 5013: my $prefix = 'helproles_'; 5014: my $add_class = 'LC_hidden'; 5015: foreach my $num (@roles_by_num) { 5016: my $role = $ordered{$num}; 5017: my ($desc,$access,@statuses); 5018: if (ref($current{$role}) eq 'HASH') { 5019: $desc = $current{$role}{'desc'}; 5020: $access = $current{$role}{'access'}; 5021: if (ref($current{$role}{'insttypes'}) eq 'ARRAY') { 5022: @statuses = @{$current{$role}{'insttypes'}}; 5023: } 5024: } 5025: if ($desc eq '') { 5026: $desc = $role; 5027: } 5028: my $identifier = 'custhelp'.$num; 5029: my %full=(); 5030: my %levels= ( 5031: course => {}, 5032: domain => {}, 5033: system => {}, 5034: ); 5035: my %levelscurrent=( 5036: course => {}, 5037: domain => {}, 5038: system => {}, 5039: ); 5040: &Apache::lonuserutils::custom_role_privs($customroles{$role},\%full,\%levels,\%levelscurrent); 5041: my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype); 5042: $css_class = $itemcount%2?' class="LC_odd_row"':''; 5043: my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"'; 5044: $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'. 5045: '<select name="helproles_'.$num.'_pos"'.$chgstr.'>'; 5046: for (my $k=0; $k<=$maxnum; $k++) { 5047: my $vpos = $k+1; 5048: my $selstr; 5049: if ($k == $num) { 5050: $selstr = ' selected="selected" '; 5051: } 5052: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 5053: } 5054: $datatable .= '</select>'.(' 'x2). 5055: '<input type="hidden" name="helproles_'.$num.'" value="'.$role.'" />'. 5056: '</td>'. 5057: '<td><fieldset><legend>'.&mt('Role name').'</legend>'. 5058: &mt('Name shown to users:'). 5059: '<input type="text" name="helproles_'.$num.'_desc" value="'.$desc.'" />'. 5060: '</fieldset>'. 5061: &helpdeskroles_access($dom,$prefix,$num,$add_class,$current{$role},\@accesstypes, 5062: $othertitle,$usertypes,$types,\%domhelpdesk). 5063: '<fieldset>'. 5064: '<legend>'.&mt('Role privileges').&adhocbutton($prefix,$num,'privs','show').'</legend>'. 5065: &Apache::lonuserutils::custom_role_table($crstype,\%full,\%levels, 5066: \%levelscurrent,$identifier, 5067: 'LC_hidden',$prefix.$num.'_privs'). 5068: '</fieldset></td>'; 5069: $itemcount ++; 5070: } 5071: $css_class = $itemcount%2?' class="LC_odd_row"':''; 5072: my $newcust = 'custhelp'.$count; 5073: my (%privs,%levelscurrent); 5074: my %full=(); 5075: my %levels= ( 5076: course => {}, 5077: domain => {}, 5078: system => {}, 5079: ); 5080: &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent); 5081: my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype); 5082: my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"'; 5083: $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'. 5084: '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n". 5085: '<select name="helproles_'.$count.'_pos"'.$chgstr.'>'; 5086: for (my $k=0; $k<$maxnum+1; $k++) { 5087: my $vpos = $k+1; 5088: my $selstr; 5089: if ($k == $maxnum) { 5090: $selstr = ' selected="selected" '; 5091: } 5092: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 5093: } 5094: $datatable .= '</select> '."\n". 5095: '<input type="checkbox" name="newcusthelp" value="'.$count.'" />'. &mt('Add'). 5096: '</label></span></td>'. 5097: '<td><fieldset><legend>'.&mt('Role name').'</legend>'. 5098: '<span class="LC_nobreak">'. 5099: &mt('Internal name:'). 5100: '<input type="text" size="10" name="custhelpname'.$count.'" value="" />'. 5101: '</span>'.(' 'x4). 5102: '<span class="LC_nobreak">'. 5103: &mt('Name shown to users:'). 5104: '<input type="text" size="20" name="helproles_'.$count.'_desc" value="" />'. 5105: '</span></fieldset>'. 5106: &helpdeskroles_access($dom,$prefix,$count,'',undef,\@accesstypes,$othertitle, 5107: $usertypes,$types,\%domhelpdesk). 5108: '<fieldset><legend>'.&mt('Role privileges').'</legend>'. 5109: &Apache::lonuserutils::custom_role_header($context,$crstype, 5110: \@templateroles,$newcust). 5111: &Apache::lonuserutils::custom_role_table('Course',\%full,\%levels, 5112: \%levelscurrent,$newcust). 5113: '</fieldset>'. 5114: &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname). 5115: '</td></tr>'; 5116: $count ++; 5117: $$rowtotal += $count; 5118: } 5119: return $datatable; 5120: } 5121: 5122: sub adhocbutton { 5123: my ($prefix,$num,$field,$visibility) = @_; 5124: my %lt = &Apache::lonlocal::texthash( 5125: show => 'Show details', 5126: hide => 'Hide details', 5127: ); 5128: return '<span style="text-decoration:line-through; font-weight: normal;">'.(' 'x10). 5129: '</span>'.(' 'x2).'<input type="button" id="'.$prefix.$num.'_'.$field.'_vis"'. 5130: ' value="'.$lt{$visibility}.'" style="height:20px;" '. 5131: 'onclick="toggleHelpdeskItem('."'$num','$field'".');" />'.(' 'x2); 5132: } 5133: 5134: sub helpsettings_javascript { 5135: my ($roles_by_num,$total,$hiddenstr,$formname) = @_; 5136: return unless(ref($roles_by_num) eq 'ARRAY'); 5137: my %html_js_lt = &Apache::lonlocal::texthash( 5138: show => 'Show details', 5139: hide => 'Hide details', 5140: ); 5141: &html_escape(\%html_js_lt); 5142: my $jstext = ' var helproles = Array('."'".join("','",@{$roles_by_num})."'".');'."\n"; 5143: return <<"ENDSCRIPT"; 5144: <script type="text/javascript"> 5145: // <![CDATA[ 5146: 5147: function reorderHelpRoles(form,item) { 5148: var changedVal; 5149: $jstext 5150: var newpos = 'helproles_${total}_pos'; 5151: var maxh = 1 + $total; 5152: var current = new Array(); 5153: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 5154: if (item == newpos) { 5155: changedVal = newitemVal; 5156: } else { 5157: changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 5158: current[newitemVal] = newpos; 5159: } 5160: for (var i=0; i<helproles.length; i++) { 5161: var elementName = 'helproles_'+helproles[i]+'_pos'; 5162: if (elementName != item) { 5163: if (form.elements[elementName]) { 5164: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 5165: current[currVal] = elementName; 5166: } 5167: } 5168: } 5169: var oldVal; 5170: for (var j=0; j<maxh; j++) { 5171: if (current[j] == undefined) { 5172: oldVal = j; 5173: } 5174: } 5175: if (oldVal < changedVal) { 5176: for (var k=oldVal+1; k<=changedVal ; k++) { 5177: var elementName = current[k]; 5178: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 5179: } 5180: } else { 5181: for (var k=changedVal; k<oldVal; k++) { 5182: var elementName = current[k]; 5183: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 5184: } 5185: } 5186: return; 5187: } 5188: 5189: function helpdeskAccess(num) { 5190: var curraccess = null; 5191: if (document.$formname.elements['helproles_'+num+'_access'].length) { 5192: for (var i=0; i<document.$formname.elements['helproles_'+num+'_access'].length; i++) { 5193: if (document.$formname.elements['helproles_'+num+'_access'][i].checked) { 5194: curraccess = document.$formname.elements['helproles_'+num+'_access'][i].value; 5195: } 5196: } 5197: } 5198: var shown = Array(); 5199: var hidden = Array(); 5200: if (curraccess == 'none') { 5201: hidden = Array('$hiddenstr'); 5202: } else { 5203: if (curraccess == 'status') { 5204: shown = Array('bystatus'); 5205: hidden = Array('notinc','notexc'); 5206: } else { 5207: if (curraccess == 'exc') { 5208: shown = Array('notexc'); 5209: hidden = Array('notinc','bystatus'); 5210: } 5211: if (curraccess == 'inc') { 5212: shown = Array('notinc'); 5213: hidden = Array('notexc','bystatus'); 5214: } 5215: if ((curraccess == 'all') || (curraccess == 'dh') || (curraccess == 'da')) { 5216: hidden = Array('notinc','notexc','bystatus'); 5217: } 5218: } 5219: } 5220: if (hidden.length > 0) { 5221: for (var i=0; i<hidden.length; i++) { 5222: if (document.getElementById('helproles_'+num+'_'+hidden[i])) { 5223: document.getElementById('helproles_'+num+'_'+hidden[i]).style.display = 'none'; 5224: } 5225: } 5226: } 5227: if (shown.length > 0) { 5228: for (var i=0; i<shown.length; i++) { 5229: if (document.getElementById('helproles_'+num+'_'+shown[i])) { 5230: if (shown[i] == 'privs') { 5231: document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'block'; 5232: } else { 5233: document.getElementById('helproles_'+num+'_'+shown[i]).style.display = 'inline-block'; 5234: } 5235: } 5236: } 5237: } 5238: return; 5239: } 5240: 5241: function toggleHelpdeskItem(num,field) { 5242: if (document.getElementById('helproles_'+num+'_'+field)) { 5243: if (document.getElementById('helproles_'+num+'_'+field).className.match(/(?:^|\\s)LC_hidden(?!\\S)/)) { 5244: document.getElementById('helproles_'+num+'_'+field).className = 5245: document.getElementById('helproles_'+num+'_'+field).className.replace(/(?:^|\\s)LC_hidden(?!\\S)/g ,''); 5246: if (document.getElementById('helproles_'+num+'_'+field+'_vis')) { 5247: document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{hide}'; 5248: } 5249: } else { 5250: document.getElementById('helproles_'+num+'_'+field).className += ' LC_hidden'; 5251: if (document.getElementById('helproles_'+num+'_'+field+'_vis')) { 5252: document.getElementById('helproles_'+num+'_'+field+'_vis').value = '$html_js_lt{show}'; 5253: } 5254: } 5255: } 5256: return; 5257: } 5258: 5259: // ]]> 5260: </script> 5261: 5262: ENDSCRIPT 5263: } 5264: 5265: sub helpdeskroles_access { 5266: my ($dom,$prefix,$num,$add_class,$current,$accesstypes,$othertitle, 5267: $usertypes,$types,$domhelpdesk) = @_; 5268: return unless ((ref($accesstypes) eq 'ARRAY') && (ref($domhelpdesk) eq 'HASH')); 5269: my %lt = &Apache::lonlocal::texthash( 5270: 'rou' => 'Role usage', 5271: 'whi' => 'Which helpdesk personnel may use this role?', 5272: 'all' => 'All with domain helpdesk or helpdesk assistant role', 5273: 'dh' => 'All with domain helpdesk role', 5274: 'da' => 'All with domain helpdesk assistant role', 5275: 'none' => 'None', 5276: 'status' => 'Determined based on institutional status', 5277: 'inc' => 'Include all, but exclude specific personnel', 5278: 'exc' => 'Exclude all, but include specific personnel', 5279: ); 5280: my %usecheck = ( 5281: all => ' checked="checked"', 5282: ); 5283: my %displaydiv = ( 5284: status => 'none', 5285: inc => 'none', 5286: exc => 'none', 5287: priv => 'block', 5288: ); 5289: my $output; 5290: if (ref($current) eq 'HASH') { 5291: if (($current->{'access'} ne '') && ($current->{'access'} ne 'all')) { 5292: if (grep(/^\Q$current->{access}\E$/,@{$accesstypes})) { 5293: $usecheck{$current->{access}} = $usecheck{'all'}; 5294: delete($usecheck{'all'}); 5295: if ($current->{access} =~ /^(status|inc|exc)$/) { 5296: my $access = $1; 5297: $displaydiv{$access} = 'inline'; 5298: } elsif ($current->{access} eq 'none') { 5299: $displaydiv{'priv'} = 'none'; 5300: } 5301: } 5302: } 5303: } 5304: $output = '<fieldset id="'.$prefix.$num.'_usage"><legend>'.$lt{'rou'}.'</legend>'. 5305: '<p>'.$lt{'whi'}.'</p>'; 5306: foreach my $access (@{$accesstypes}) { 5307: $output .= '<p><label><input type="radio" name="'.$prefix.$num.'_access" value="'.$access.'" '.$usecheck{$access}. 5308: ' onclick="helpdeskAccess('."'$num'".');" />'. 5309: $lt{$access}.'</label>'; 5310: if ($access eq 'status') { 5311: $output .= '<div id="'.$prefix.$num.'_bystatus" style="display:'.$displaydiv{$access}.'">'. 5312: &Apache::lonuserutils::adhoc_status_types($dom,$prefix,$num,$current->{$access}, 5313: $othertitle,$usertypes,$types). 5314: '</div>'; 5315: } elsif (($access eq 'inc') && (keys(%{$domhelpdesk}) > 0)) { 5316: $output .= '<div id="'.$prefix.$num.'_notinc" style="display:'.$displaydiv{$access}.'">'. 5317: &Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk). 5318: '</div>'; 5319: } elsif (($access eq 'exc') && (keys(%{$domhelpdesk}) > 0)) { 5320: $output .= '<div id="'.$prefix.$num.'_notexc" style="display:'.$displaydiv{$access}.'">'. 5321: &Apache::lonuserutils::adhoc_staff($access,$prefix,$num,$current->{$access},$domhelpdesk). 5322: '</div>'; 5323: } 5324: $output .= '</p>'; 5325: } 5326: $output .= '</fieldset>'; 5327: return $output; 5328: } 5329: 5330: sub radiobutton_prefs { 5331: my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick, 5332: $additional,$align,$firstval) = @_; 5333: return unless ((ref($toggles) eq 'ARRAY') && (ref($defaultchecked) eq 'HASH') && 5334: (ref($choices) eq 'HASH')); 5335: 5336: my (%checkedon,%checkedoff,$datatable,$css_class); 5337: 5338: foreach my $item (@{$toggles}) { 5339: if ($defaultchecked->{$item} eq 'on') { 5340: $checkedon{$item} = ' checked="checked" '; 5341: $checkedoff{$item} = ' '; 5342: } elsif ($defaultchecked->{$item} eq 'off') { 5343: $checkedoff{$item} = ' checked="checked" '; 5344: $checkedon{$item} = ' '; 5345: } 5346: } 5347: if (ref($settings) eq 'HASH') { 5348: foreach my $item (@{$toggles}) { 5349: if ($settings->{$item} eq '1') { 5350: $checkedon{$item} = ' checked="checked" '; 5351: $checkedoff{$item} = ' '; 5352: } elsif ($settings->{$item} eq '0') { 5353: $checkedoff{$item} = ' checked="checked" '; 5354: $checkedon{$item} = ' '; 5355: } 5356: } 5357: } 5358: if ($onclick) { 5359: $onclick = ' onclick="'.$onclick.'"'; 5360: } 5361: foreach my $item (@{$toggles}) { 5362: $css_class = $itemcount%2?' class="LC_odd_row"':''; 5363: $datatable .= 5364: '<tr'.$css_class.'><td style="vertical-align: top">'. 5365: '<span class="LC_nobreak">'.$choices->{$item}. 5366: '</span></td>'; 5367: if ($align eq 'left') { 5368: $datatable .= '<td class="LC_left_item">'; 5369: } else { 5370: $datatable .= '<td class="LC_right_item">'; 5371: } 5372: $datatable .= '<span class="LC_nobreak">'; 5373: if ($firstval eq 'no') { 5374: $datatable .= 5375: '<label><input type="radio" name="'. 5376: $item.'" '.$checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No'). 5377: '</label> <label><input type="radio" name="'.$item.'" '. 5378: $checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes').'</label>'; 5379: } else { 5380: $datatable .= 5381: '<label><input type="radio" name="'. 5382: $item.'" '.$checkedon{$item}.' value="1"'.$onclick.' />'.&mt('Yes'). 5383: '</label> <label><input type="radio" name="'.$item.'" '. 5384: $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').'</label>'; 5385: } 5386: $datatable .= '</span>'.$additional.'</td></tr>'; 5387: $itemcount ++; 5388: } 5389: return ($datatable,$itemcount); 5390: } 5391: 5392: sub print_ltitools { 5393: my ($dom,$settings,$rowtotal) = @_; 5394: my $rownum = 0; 5395: my $css_class; 5396: my $itemcount = 1; 5397: my $maxnum = 0; 5398: my %ordered; 5399: if (ref($settings) eq 'HASH') { 5400: foreach my $item (keys(%{$settings})) { 5401: if (ref($settings->{$item}) eq 'HASH') { 5402: my $num = $settings->{$item}{'order'}; 5403: $ordered{$num} = $item; 5404: } 5405: } 5406: } 5407: my $confname = $dom.'-domainconfig'; 5408: my $switchserver = &check_switchserver($dom,$confname); 5409: my $maxnum = scalar(keys(%ordered)); 5410: my $datatable; 5411: my %lt = <itools_names(); 5412: my @courseroles = ('cc','in','ta','ep','st'); 5413: my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner); 5414: my @fields = ('fullname','firstname','lastname','email','roles','user'); 5415: if (keys(%ordered)) { 5416: my @items = sort { $a <=> $b } keys(%ordered); 5417: for (my $i=0; $i<@items; $i++) { 5418: $css_class = $itemcount%2?' class="LC_odd_row"':''; 5419: my $item = $ordered{$items[$i]}; 5420: my ($title,$key,$secret,$url,$lifetime,$imgsrc,%sigsel); 5421: if (ref($settings->{$item}) eq 'HASH') { 5422: $title = $settings->{$item}->{'title'}; 5423: $url = $settings->{$item}->{'url'}; 5424: $key = $settings->{$item}->{'key'}; 5425: $secret = $settings->{$item}->{'secret'}; 5426: $lifetime = $settings->{$item}->{'lifetime'}; 5427: my $image = $settings->{$item}->{'image'}; 5428: if ($image ne '') { 5429: $imgsrc = '<img src="'.$image.'" alt="'.&mt('Tool Provider icon').'" />'; 5430: } 5431: if ($settings->{$item}->{'sigmethod'} eq 'HMAC-256') { 5432: $sigsel{'HMAC-256'} = ' selected="selected"'; 5433: } else { 5434: $sigsel{'HMAC-SHA1'} = ' selected="selected"'; 5435: } 5436: } 5437: my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_".$item."'".');"'; 5438: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 5439: .'<select name="ltitools_'.$item.'"'.$chgstr.'>'; 5440: for (my $k=0; $k<=$maxnum; $k++) { 5441: my $vpos = $k+1; 5442: my $selstr; 5443: if ($k == $i) { 5444: $selstr = ' selected="selected" '; 5445: } 5446: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 5447: } 5448: $datatable .= '</select>'.(' 'x2). 5449: '<label><input type="checkbox" name="ltitools_del" value="'.$item.'" />'. 5450: &mt('Delete?').'</label></span></td>'. 5451: '<td colspan="2">'. 5452: '<fieldset><legend>'.&mt('Required settings').'</legend>'. 5453: '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_title_'.$i.'" value="'.$title.'" /></span> '. 5454: (' 'x2). 5455: '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_version_'.$i.'">'. 5456: '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '. 5457: (' 'x2). 5458: '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_msgtype_'.$i.'">'. 5459: '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '. 5460: (' 'x2). 5461: '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_sigmethod_'.$i.'">'. 5462: '<option value="HMAC-SHA1"'.$sigsel{'HMAC-SHA1'}.'>HMAC-SHA1</option>'. 5463: '<option value="HMAC-SHA256"'.$sigsel{'HMAC-SHA256'}.'>HMAC-SHA256</option></select></span>'. 5464: '<br /><br />'. 5465: '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_url_'.$i.'"'. 5466: ' value="'.$url.'" /></span>'. 5467: (' 'x2). 5468: '<span class="LC_nobreak">'.$lt{'key'}.':'. 5469: '<input type="text" size="25" name="ltitools_key_'.$i.'" value="'.$key.'" /></span> '. 5470: (' 'x2). 5471: '<span class="LC_nobreak">'.$lt{'lifetime'}.':'. 5472: '<input type="text" size="5" name="ltitools_lifetime_'.$i.'" value="'.$lifetime.'" /></span> '. 5473: (' 'x2). 5474: '<span class="LC_nobreak">'.$lt{'secret'}.':'. 5475: '<input type="password" size="20" name="ltitools_secret_'.$i.'" value="'.$secret.'" />'. 5476: '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_secret_'.$i.'.type='."'text'".' } else { this.form.ltitools_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'. 5477: '<input type="hidden" name="ltitools_id_'.$i.'" value="'.$item.'" /></span>'. 5478: '</fieldset>'. 5479: '<fieldset><legend>'.&mt('Optional settings').'</legend>'. 5480: '<span class="LC_nobreak">'.&mt('Display target:'); 5481: my %currdisp; 5482: if (ref($settings->{$item}->{'display'}) eq 'HASH') { 5483: if ($settings->{$item}->{'display'}->{'target'} eq 'window') { 5484: $currdisp{'window'} = ' checked="checked"'; 5485: } elsif ($settings->{$item}->{'display'}->{'target'} eq 'tab') { 5486: $currdisp{'tab'} = ' checked="checked"'; 5487: } else { 5488: $currdisp{'iframe'} = ' checked="checked"'; 5489: } 5490: if ($settings->{$item}->{'display'}->{'width'} =~ /^(\d+)$/) { 5491: $currdisp{'width'} = $1; 5492: } 5493: if ($settings->{$item}->{'display'}->{'height'} =~ /^(\d+)$/) { 5494: $currdisp{'height'} = $1; 5495: } 5496: $currdisp{'linktext'} = $settings->{$item}->{'display'}->{'linktext'}; 5497: $currdisp{'explanation'} = $settings->{$item}->{'display'}->{'explanation'}; 5498: } else { 5499: $currdisp{'iframe'} = ' checked="checked"'; 5500: } 5501: foreach my $disp ('iframe','tab','window') { 5502: $datatable .= '<label><input type="radio" name="ltitools_target_'.$i.'" value="'.$disp.'"'.$currdisp{$disp}.' />'. 5503: $lt{$disp}.'</label>'.(' 'x2); 5504: } 5505: $datatable .= (' 'x4); 5506: foreach my $dimen ('width','height') { 5507: $datatable .= '<label>'.$lt{$dimen}.' '. 5508: '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'. 5509: (' 'x2); 5510: } 5511: $datatable .= '</span><br />'. 5512: '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'. 5513: '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></div>'. 5514: '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'. 5515: '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}. 5516: '</textarea></div><div style=""></div><br />'; 5517: my %units = ( 5518: 'passback' => 'days', 5519: 'roster' => 'seconds', 5520: ); 5521: foreach my $extra ('passback','roster') { 5522: my $validsty = 'none'; 5523: my $currvalid; 5524: my $checkedon = ''; 5525: my $checkedoff = ' checked="checked"'; 5526: if ($settings->{$item}->{$extra}) { 5527: $checkedon = $checkedoff; 5528: $checkedoff = ''; 5529: $validsty = 'inline-block'; 5530: if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) { 5531: $currvalid = $settings->{$item}->{$extra.'valid'}; 5532: } 5533: } 5534: my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','$i'".');"'; 5535: $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.' '. 5536: '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.$onclick.' />'. 5537: &mt('No').'</label>'.(' 'x2). 5538: '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.$onclick.' />'. 5539: &mt('Yes').'</label></span></div>'. 5540: '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_'.$extra.'time_'.$i.'">'. 5541: '<span class="LC_nobreak">'. 5542: &mt("at least [_1] $units{$extra} after launch", 5543: '<input type="text" name="ltitools_'.$extra.'valid_'.$i.'" value="'.$currvalid.'" />'). 5544: '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>'; 5545: } 5546: $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': '; 5547: if ($imgsrc) { 5548: $datatable .= $imgsrc. 5549: '<label><input type="checkbox" name="ltitools_image_del"'. 5550: ' value="'.$item.'" />'.&mt('Delete?').'</label></span> '. 5551: '<span class="LC_nobreak"> '.&mt('Replace:').' '; 5552: } else { 5553: $datatable .= '('.&mt('if larger than 21x21 pixels, image will be scaled').') '; 5554: } 5555: if ($switchserver) { 5556: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 5557: } else { 5558: $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />'; 5559: } 5560: $datatable .= '</span></fieldset>'; 5561: my (%checkedfields,%rolemaps,$userincdom); 5562: if (ref($settings->{$item}) eq 'HASH') { 5563: if (ref($settings->{$item}->{'fields'}) eq 'HASH') { 5564: %checkedfields = %{$settings->{$item}->{'fields'}}; 5565: } 5566: $userincdom = $settings->{$item}->{'incdom'}; 5567: if (ref($settings->{$item}->{'roles'}) eq 'HASH') { 5568: %rolemaps = %{$settings->{$item}->{'roles'}}; 5569: $checkedfields{'roles'} = 1; 5570: } 5571: } 5572: $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'. 5573: '<span class="LC_nobreak">'; 5574: my $userfieldstyle = 'display:none;'; 5575: my $seluserdom = ''; 5576: my $unseluserdom = ' selected="selected"'; 5577: foreach my $field (@fields) { 5578: my ($checked,$onclick,$id,$spacer); 5579: if ($checkedfields{$field}) { 5580: $checked = ' checked="checked"'; 5581: } 5582: if ($field eq 'user') { 5583: $id = ' id="ltitools_user_field_'.$i.'"'; 5584: $onclick = ' onclick="toggleLTITools(this.form,'."'$field','$i'".')"'; 5585: if ($checked) { 5586: $userfieldstyle = 'display:inline-block'; 5587: if ($userincdom) { 5588: $seluserdom = $unseluserdom; 5589: $unseluserdom = ''; 5590: } 5591: } 5592: } else { 5593: $spacer = (' ' x2); 5594: } 5595: $datatable .= '<label>'. 5596: '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$id.$checked.$onclick.' />'. 5597: $lt{$field}.'</label>'.$spacer; 5598: } 5599: $datatable .= '</span>'; 5600: $datatable .= '<div style="'.$userfieldstyle.'" id="ltitools_user_div_'.$i.'">'. 5601: '<span class="LC_nobreak"> : '. 5602: '<select name="ltitools_userincdom_'.$i.'">'. 5603: '<option value="">'.&mt('Select').'</option>'. 5604: '<option value="0"'.$unseluserdom.'>'.&mt('username').'</option>'. 5605: '<option value="1"'.$seluserdom.'>'.&mt('username:domain').'</option>'. 5606: '</select></span></div>'; 5607: $datatable .= '</fieldset>'. 5608: '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>'; 5609: foreach my $role (@courseroles) { 5610: my ($selected,$selectnone); 5611: if (!$rolemaps{$role}) { 5612: $selectnone = ' selected="selected"'; 5613: } 5614: $datatable .= '<td style="text-align: center">'. 5615: &Apache::lonnet::plaintext($role,'Course').'<br />'. 5616: '<select name="ltitools_roles_'.$role.'_'.$i.'">'. 5617: '<option value=""'.$selectnone.'>'.&mt('Select').'</option>'; 5618: foreach my $ltirole (@ltiroles) { 5619: unless ($selectnone) { 5620: if ($rolemaps{$role} eq $ltirole) { 5621: $selected = ' selected="selected"'; 5622: } else { 5623: $selected = ''; 5624: } 5625: } 5626: $datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>'; 5627: } 5628: $datatable .= '</select></td>'; 5629: } 5630: $datatable .= '</tr></table></fieldset>'; 5631: my %courseconfig; 5632: if (ref($settings->{$item}) eq 'HASH') { 5633: if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') { 5634: %courseconfig = %{$settings->{$item}->{'crsconf'}}; 5635: } 5636: } 5637: $datatable .= '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">'; 5638: foreach my $item ('label','title','target','linktext','explanation','append') { 5639: my $checked; 5640: if ($courseconfig{$item}) { 5641: $checked = ' checked="checked"'; 5642: } 5643: $datatable .= '<label>'. 5644: '<input type="checkbox" name="ltitools_courseconfig_'.$i.'" value="'.$item.'"'.$checked.' />'. 5645: $lt{'crs'.$item}.'</label> '."\n"; 5646: } 5647: $datatable .= '</span></fieldset>'. 5648: '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'. 5649: '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'; 5650: if (ref($settings->{$item}->{'custom'}) eq 'HASH') { 5651: my %custom = %{$settings->{$item}->{'custom'}}; 5652: if (keys(%custom) > 0) { 5653: foreach my $key (sort(keys(%custom))) { 5654: $datatable .= '<tr><td><span class="LC_nobreak">'. 5655: '<label><input type="checkbox" name="ltitools_customdel_'.$i.'" value="'. 5656: $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'. 5657: '<td><input type="text" name="ltitools_customval_'.$key.'_'.$i.'"'. 5658: ' value="'.$custom{$key}.'" /></td></tr>'; 5659: } 5660: } 5661: } 5662: $datatable .= '<tr><td><span class="LC_nobreak">'. 5663: '<label><input type="checkbox" name="ltitools_customadd" value="'.$i.'" />'. 5664: &mt('Add').'</label></span></td><td><input type="text" name="ltitools_custom_name_'.$i.'" />'. 5665: '</td><td><input type="text" name="ltitools_custom_value_'.$i.'" /></td></tr>'; 5666: $datatable .= '</table></fieldset></td></tr>'."\n"; 5667: $itemcount ++; 5668: } 5669: } 5670: $css_class = $itemcount%2?' class="LC_odd_row"':''; 5671: my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_add_pos'".');"'; 5672: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". 5673: '<input type="hidden" name="ltitools_maxnum" value="'.$maxnum.'" />'."\n". 5674: '<select name="ltitools_add_pos"'.$chgstr.'>'; 5675: for (my $k=0; $k<$maxnum+1; $k++) { 5676: my $vpos = $k+1; 5677: my $selstr; 5678: if ($k == $maxnum) { 5679: $selstr = ' selected="selected" '; 5680: } 5681: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 5682: } 5683: $datatable .= '</select> '."\n". 5684: '<input type="checkbox" name="ltitools_add" value="1" />'.&mt('Add').'</span></td>'."\n". 5685: '<td colspan="2">'. 5686: '<fieldset><legend>'.&mt('Required settings').'</legend>'. 5687: '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_add_title" value="" /></span> '."\n". 5688: (' 'x2). 5689: '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_add_version">'. 5690: '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n". 5691: (' 'x2). 5692: '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_add_msgtype">'. 5693: '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '. 5694: '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_add_sigmethod">'. 5695: '<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'. 5696: '<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'. 5697: '<br />'. 5698: '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_add_url" value="" /></span> '."\n". 5699: (' 'x2). 5700: '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="ltitools_add_key" value="" /></span> '."\n". 5701: (' 'x2). 5702: '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="ltitools_add_lifetime" value="300" /></span> '."\n". 5703: (' 'x2). 5704: '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="ltitools_add_secret" value="" />'. 5705: '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltitools_add_secret.type='."'text'".' } else { this.form.ltitools_add_secret.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n". 5706: '</fieldset>'. 5707: '<fieldset><legend>'.&mt('Optional settings').'</legend>'. 5708: '<span class="LC_nobreak">'.&mt('Display target:'); 5709: my %defaultdisp; 5710: $defaultdisp{'iframe'} = ' checked="checked"'; 5711: foreach my $disp ('iframe','tab','window') { 5712: $datatable .= '<label><input type="radio" name="ltitools_add_target" value="'.$disp.'"'.$defaultdisp{$disp}.' />'. 5713: $lt{$disp}.'</label>'.(' 'x2); 5714: } 5715: $datatable .= (' 'x4); 5716: foreach my $dimen ('width','height') { 5717: $datatable .= '<label>'.$lt{$dimen}.' '. 5718: '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'. 5719: (' 'x2); 5720: } 5721: $datatable .= '</span><br />'. 5722: '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'. 5723: '<input type="text" name="ltitools_add_linktext" size="5" /></div>'. 5724: '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'. 5725: '<textarea name="ltitools_add_explanation" rows="5" cols="40"></textarea>'. 5726: '</div><div style=""></div><br />'; 5727: my %units = ( 5728: 'passback' => 'days', 5729: 'roster' => 'seconds', 5730: ); 5731: my %defaulttimes = ( 5732: 'passback' => '7', 5733: 'roster' => '300', 5734: ); 5735: foreach my $extra ('passback','roster') { 5736: my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"'; 5737: $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.' '. 5738: '<label><input type="radio" name="ltitools_'.$extra.'_add" value="0" checked="checked"'.$onclick.' />'. 5739: &mt('No').'</label></span>'.(' 'x2).'<span class="LC_nobreak">'. 5740: '<label><input type="radio" name="ltitools_'.$extra.'_add" value="1"'.$onclick.' />'. 5741: &mt('Yes').'</label></span></div>'. 5742: '<div class="LC_floatleft" style="display:none;" id="ltitools_'.$extra.'time_add">'. 5743: '<span class="LC_nobreak">'. 5744: &mt("at least [_1] $units{$extra} after launch", 5745: '<input type="text" name="ltitools_'.$extra.'valid_add" value="'.$defaulttimes{$extra}.'" />'). 5746: '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>'; 5747: } 5748: $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': '. 5749: '('.&mt('if larger than 21x21 pixels, image will be scaled').') '; 5750: if ($switchserver) { 5751: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 5752: } else { 5753: $datatable .= '<input type="file" name="ltitools_add_image" value="" />'; 5754: } 5755: $datatable .= '</span></fieldset>'. 5756: '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'. 5757: '<span class="LC_nobreak">'; 5758: foreach my $field (@fields) { 5759: my ($id,$onclick,$spacer); 5760: if ($field eq 'user') { 5761: $id = ' id="ltitools_user_field_add"'; 5762: $onclick = ' onclick="toggleLTITools(this.form,'."'$field','add'".')"'; 5763: } else { 5764: $spacer = (' ' x2); 5765: } 5766: $datatable .= '<label>'. 5767: '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'"'.$id.$onclick.' />'. 5768: $lt{$field}.'</label>'.$spacer; 5769: } 5770: $datatable .= '</span>'. 5771: '<div style="display:none;" id="ltitools_user_div_add">'. 5772: '<span class="LC_nobreak"> : '. 5773: '<select name="ltitools_userincdom_add">'. 5774: '<option value="" selected="selected">'.&mt('Select').'</option>'. 5775: '<option value="0">'.&mt('username').'</option>'. 5776: '<option value="1">'.&mt('username:domain').'</option>'. 5777: '</select></span></div></fieldset>'; 5778: $datatable .= '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>'; 5779: foreach my $role (@courseroles) { 5780: my ($checked,$checkednone); 5781: $datatable .= '<td style="text-align: center">'. 5782: &Apache::lonnet::plaintext($role,'Course').'<br />'. 5783: '<select name="ltitools_add_roles_'.$role.'">'. 5784: '<option value="" selected="selected">'.&mt('Select').'</option>'; 5785: foreach my $ltirole (@ltiroles) { 5786: $datatable .= '<option value="'.$ltirole.'">'.$ltirole.'</option>'; 5787: } 5788: $datatable .= '</select></td>'; 5789: } 5790: $datatable .= '</tr></table></fieldset>'. 5791: '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">'; 5792: foreach my $item ('label','title','target','linktext','explanation','append') { 5793: $datatable .= '<label>'. 5794: '<input type="checkbox" name="ltitools_courseconfig" value="'.$item.'" checked="checked" />'. 5795: $lt{'crs'.$item}.'</label>'.(' ' x2)."\n"; 5796: } 5797: $datatable .= '</span></fieldset>'. 5798: '<fieldset><legend>'.&mt('Custom items sent on launch').'</legend>'. 5799: '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'. 5800: '<tr><td><span class="LC_nobreak">'. 5801: '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'. 5802: &mt('Add').'</label></span></td><td><input type="text" name="ltitools_add_custom_name" />'. 5803: '</td><td><input type="text" name="ltitools_add_custom_value" /></td></tr>'. 5804: '</table></fieldset>'."\n". 5805: '</td>'."\n". 5806: '</tr>'."\n"; 5807: $itemcount ++; 5808: return $datatable; 5809: } 5810: 5811: sub ltitools_names { 5812: my %lt = &Apache::lonlocal::texthash( 5813: 'title' => 'Title', 5814: 'version' => 'Version', 5815: 'msgtype' => 'Message Type', 5816: 'sigmethod' => 'Signature Method', 5817: 'url' => 'URL', 5818: 'key' => 'Key', 5819: 'lifetime' => 'Nonce lifetime (s)', 5820: 'secret' => 'Secret', 5821: 'icon' => 'Icon', 5822: 'user' => 'User', 5823: 'fullname' => 'Full Name', 5824: 'firstname' => 'First Name', 5825: 'lastname' => 'Last Name', 5826: 'email' => 'E-mail', 5827: 'roles' => 'Role', 5828: 'window' => 'Window', 5829: 'tab' => 'Tab', 5830: 'iframe' => 'iFrame', 5831: 'height' => 'Height', 5832: 'width' => 'Width', 5833: 'linktext' => 'Default Link Text', 5834: 'explanation' => 'Default Explanation', 5835: 'passback' => 'Tool can return grades:', 5836: 'roster' => 'Tool can retrieve roster:', 5837: 'crstarget' => 'Display target', 5838: 'crslabel' => 'Course label', 5839: 'crstitle' => 'Course title', 5840: 'crslinktext' => 'Link Text', 5841: 'crsexplanation' => 'Explanation', 5842: 'crsappend' => 'Provider URL', 5843: ); 5844: return %lt; 5845: } 5846: 5847: sub print_proctoring { 5848: my ($dom,$settings,$rowtotal) = @_; 5849: my $itemcount = 1; 5850: my (%ordered,%providernames,%current,%currentdef); 5851: my $confname = $dom.'-domainconfig'; 5852: my $switchserver = &check_switchserver($dom,$confname); 5853: if (ref($settings) eq 'HASH') { 5854: foreach my $item (keys(%{$settings})) { 5855: if (ref($settings->{$item}) eq 'HASH') { 5856: my $num = $settings->{$item}{'order'}; 5857: $ordered{$num} = $item; 5858: } 5859: } 5860: } else { 5861: %ordered = ( 5862: 1 => 'proctorio', 5863: 2 => 'examity', 5864: ); 5865: } 5866: %providernames = &proctoring_providernames(); 5867: my $maxnum = scalar(keys(%ordered)); 5868: my (%requserfields,%optuserfields,%defaults,%extended,%crsconf,@courseroles,@ltiroles); 5869: my ($requref,$opturef,$defref,$extref,$crsref,$rolesref,$ltiref) = &proctoring_data(); 5870: if (ref($requref) eq 'HASH') { 5871: %requserfields = %{$requref}; 5872: } 5873: if (ref($opturef) eq 'HASH') { 5874: %optuserfields = %{$opturef}; 5875: } 5876: if (ref($defref) eq 'HASH') { 5877: %defaults = %{$defref}; 5878: } 5879: if (ref($extref) eq 'HASH') { 5880: %extended = %{$extref}; 5881: } 5882: if (ref($crsref) eq 'HASH') { 5883: %crsconf = %{$crsref}; 5884: } 5885: if (ref($rolesref) eq 'ARRAY') { 5886: @courseroles = @{$rolesref}; 5887: } 5888: if (ref($ltiref) eq 'ARRAY') { 5889: @ltiroles = @{$ltiref}; 5890: } 5891: my $datatable; 5892: my $css_class; 5893: if (keys(%ordered)) { 5894: my @items = sort { $a <=> $b } keys(%ordered); 5895: for (my $i=0; $i<@items; $i++) { 5896: $css_class = $itemcount%2?' class="LC_odd_row"':''; 5897: my $provider = $ordered{$items[$i]}; 5898: my $optionsty = 'none'; 5899: my ($available,$version,$lifetime,$imgsrc,$userincdom,$showroles, 5900: %checkedfields,%rolemaps,%inuse,%crsconfig,%current); 5901: if (ref($settings) eq 'HASH') { 5902: if (ref($settings->{$provider}) eq 'HASH') { 5903: %current = %{$settings->{$provider}}; 5904: if ($current{'available'}) { 5905: $optionsty = 'block'; 5906: $available = 1; 5907: } 5908: if ($current{'lifetime'} =~ /^\d+$/) { 5909: $lifetime = $current{'lifetime'}; 5910: } 5911: if ($current{'version'} =~ /^\d+\.\d+$/) { 5912: $version = $current{'version'}; 5913: } 5914: if ($current{'image'} ne '') { 5915: $imgsrc = '<img src="'.$current{'image'}.'" alt="'.&mt('Proctoring service icon').'" />'; 5916: } 5917: if (ref($current{'fields'}) eq 'ARRAY') { 5918: map { $checkedfields{$_} = 1; } @{$current{'fields'}}; 5919: } 5920: $userincdom = $current{'incdom'}; 5921: if (ref($current{'roles'}) eq 'HASH') { 5922: %rolemaps = %{$current{'roles'}}; 5923: $checkedfields{'roles'} = 1; 5924: } 5925: if (ref($current{'defaults'}) eq 'ARRAY') { 5926: foreach my $val (@{$current{'defaults'}}) { 5927: if (grep(/^\Q$val\E$/,@{$defaults{$provider}})) { 5928: $inuse{$val} = 1; 5929: } else { 5930: foreach my $poss (keys(%{$extended{$provider}})) { 5931: if (ref($extended{$provider}{$poss}) eq 'ARRAY') { 5932: if (grep(/^\Q$val\E$/,@{$extended{$provider}{$poss}})) { 5933: $inuse{$poss} = $val; 5934: last; 5935: } 5936: } 5937: } 5938: } 5939: } 5940: } elsif (ref($current{'defaults'}) eq 'HASH') { 5941: foreach my $key (keys(%{$current{'defaults'}})) { 5942: my $currval = $current{'defaults'}{$key}; 5943: if (grep(/^\Q$key\E$/,@{$defaults{$provider}})) { 5944: $inuse{$key} = 1; 5945: } else { 5946: my $match; 5947: foreach my $poss (keys(%{$extended{$provider}})) { 5948: if (ref($extended{$provider}{$poss}) eq 'ARRAY') { 5949: if (grep(/^\Q$key\E$/,@{$extended{$provider}{$poss}})) { 5950: $inuse{$poss} = $key; 5951: last; 5952: } 5953: } elsif (ref($extended{$provider}{$poss}) eq 'HASH') { 5954: foreach my $inner (sort(keys(%{$extended{$provider}{$poss}}))) { 5955: if (ref($extended{$provider}{$poss}{$inner}) eq 'ARRAY') { 5956: if (grep(/^\Q$currval\E$/,@{$extended{$provider}{$poss}{$inner}})) { 5957: $currentdef{$inner} = $currval; 5958: $match = 1; 5959: last; 5960: } 5961: } elsif ($inner eq $key) { 5962: $currentdef{$key} = $currval; 5963: $match = 1; 5964: last; 5965: } 5966: } 5967: } 5968: last if ($match); 5969: } 5970: } 5971: } 5972: } 5973: if (ref($current{'crsconf'}) eq 'ARRAY') { 5974: map { $crsconfig{$_} = 1; } @{$current{'crsconf'}}; 5975: } 5976: } 5977: } 5978: my %lt = &proctoring_titles($provider); 5979: my %fieldtitles = &proctoring_fieldtitles($provider); 5980: my $onclickavailable = ' onclick="toggleProctoring(this.form,'."'$provider'".');"'; 5981: my %checkedavailable = ( 5982: yes => '', 5983: no => ' checked="checked"', 5984: ); 5985: if ($available) { 5986: $checkedavailable{'yes'} = $checkedavailable{'no'}; 5987: $checkedavailable{'no'} = ''; 5988: } 5989: my $chgstr = ' onchange="javascript:reorderProctoring(this.form,'."'proctoring_pos_".$provider."'".');"'; 5990: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 5991: .'<select name="proctoring_pos_'.$provider.'"'.$chgstr.'>'; 5992: for (my $k=0; $k<$maxnum; $k++) { 5993: my $vpos = $k+1; 5994: my $selstr; 5995: if ($k == $i) { 5996: $selstr = ' selected="selected" '; 5997: } 5998: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 5999: } 6000: if ($version eq '') { 6001: if ($provider eq 'proctorio') { 6002: $version = '1.0'; 6003: } elsif ($provider eq 'examity') { 6004: $version = '1.1'; 6005: } 6006: } 6007: if ($lifetime eq '') { 6008: $lifetime = '300'; 6009: } 6010: $datatable .= 6011: '</select>'.(' 'x2).'<b>'.$providernames{$provider}.'</b></span><br />'. 6012: '<span class="LC_nobreak">'.$lt{'avai'}.' '. 6013: '<label><input type="radio" name="proctoring_available_'.$provider.'" value="1"'.$onclickavailable.$checkedavailable{yes}.' />'.&mt('Yes').'</label> '."\n". 6014: '<label><input type="radio" name="proctoring_available_'.$provider.'" value="0"'.$onclickavailable.$checkedavailable{no}.' />'.&mt('No').'</label></span>'."\n". 6015: '</td>'. 6016: '<td colspan="2">'. 6017: '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'base'}.'</legend>'. 6018: '<span class="LC_nobreak">'.$lt{'version'}.':<select name="proctoring_'.$provider.'_version">'. 6019: '<option value="'.$version.'" selected="selected">'.$version.'</option></select></span> '."\n". 6020: (' 'x2). 6021: '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="proctoring_'.$provider.'_sigmethod">'. 6022: '<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'. 6023: '<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'. 6024: (' 'x2). 6025: '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="proctoring_'.$provider.'_lifetime" value="'.$lifetime.'" /></span> '."\n". 6026: '<br />'. 6027: '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="proctoring_'.$provider.'_url" value="'.$current{'url'}.'" /></span> '."\n". 6028: '<br />'. 6029: '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="proctoring_'.$provider.'_key" value="'.$current{'key'}.'" /></span> '."\n". 6030: (' 'x2). 6031: '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="proctoring_'.$provider.'_secret" value="'.$current{'secret'}.'" />'. 6032: '<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"; 6033: $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': '; 6034: if ($imgsrc) { 6035: $datatable .= $imgsrc. 6036: '<label><input type="checkbox" name="proctoring_image_del"'. 6037: ' value="'.$provider.'" />'.&mt('Delete?').'</label></span> '. 6038: '<span class="LC_nobreak"> '.&mt('Replace:'); 6039: } 6040: $datatable .= ' '; 6041: if ($switchserver) { 6042: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 6043: } else { 6044: $datatable .= '<input type="file" name="proctoring_image_'.$provider.'" value="" />'; 6045: } 6046: unless ($imgsrc) { 6047: $datatable .= '<br />('.&mt('if larger than 21x21 pixels, image will be scaled').')'; 6048: } 6049: $datatable .= '</fieldset>'."\n"; 6050: if (ref($requserfields{$provider}) eq 'ARRAY') { 6051: if (@{$requserfields{$provider}} > 0) { 6052: $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'requ'}.'</legend>'; 6053: foreach my $field (@{$requserfields{$provider}}) { 6054: $datatable .= '<span class="LC_nobreak">'. 6055: '<label><input type="checkbox" name="proctoring_reqd_'.$provider.'" value="'.$field.'" checked="checked" disabled="disabled" />'. 6056: $lt{$field}.'</label>'; 6057: if ($field eq 'user') { 6058: my $seluserdom = ''; 6059: my $unseluserdom = ' selected="selected"'; 6060: if ($userincdom) { 6061: $seluserdom = $unseluserdom; 6062: $unseluserdom = ''; 6063: } 6064: $datatable .= ': '. 6065: '<select name="proctoring_userincdom_'.$provider.'">'. 6066: '<option value="0"'.$unseluserdom.'>'.$lt{'username'}.'</option>'. 6067: '<option value="1"'.$seluserdom.'>'.$lt{'uname:dom'}.'</option>'. 6068: '</select> '; 6069: } else { 6070: $datatable .= ' '; 6071: if ($field eq 'roles') { 6072: $showroles = 1; 6073: } 6074: } 6075: $datatable .= '</span> '; 6076: } 6077: } 6078: $datatable .= '</fieldset>'."\n"; 6079: } 6080: if (ref($optuserfields{$provider}) eq 'ARRAY') { 6081: if (@{$optuserfields{$provider}} > 0) { 6082: $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'optu'}.'</legend>'; 6083: foreach my $field (@{$optuserfields{$provider}}) { 6084: my $checked; 6085: if ($checkedfields{$field}) { 6086: $checked = ' checked="checked"'; 6087: } 6088: $datatable .= '<span class="LC_nobreak">'. 6089: '<label><input type="checkbox" name="proctoring_optional_'.$provider.'" value="'.$field.'"'.$checked.' />'.$lt{$field}.'</label></span> '; 6090: } 6091: $datatable .= '</fieldset>'."\n"; 6092: } 6093: } 6094: if (ref($defaults{$provider}) eq 'ARRAY') { 6095: if (@{$defaults{$provider}}) { 6096: my (%options,@selectboxes); 6097: if (ref($extended{$provider}) eq 'HASH') { 6098: %options = %{$extended{$provider}}; 6099: } 6100: $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'defa'}.'</legend>'; 6101: my ($rem,$numinrow,$dropdowns); 6102: if ($provider eq 'proctorio') { 6103: $datatable .= '<table>'; 6104: $numinrow = 4; 6105: } 6106: my $i = 0; 6107: foreach my $field (@{$defaults{$provider}}) { 6108: my $checked; 6109: if ($inuse{$field}) { 6110: $checked = ' checked="checked"'; 6111: } 6112: if ($provider eq 'examity') { 6113: if ($field eq 'display') { 6114: $datatable .= '<span class="LC_nobreak">'.&mt('Display target:'); 6115: foreach my $option ('iframe','tab','window') { 6116: my $checkdisp; 6117: if ($currentdef{'target'} eq $option) { 6118: $checkdisp = ' checked="checked"'; 6119: } 6120: $datatable .= '<label><input type="radio" name="proctoring_target_'.$provider.'" value="'.$option.'"'.$checkdisp.' />'. 6121: $fieldtitles{$option}.'</label>'.(' 'x2); 6122: } 6123: $datatable .= (' 'x4); 6124: foreach my $dimen ('width','height') { 6125: $datatable .= '<label>'.$fieldtitles{$dimen}.' '. 6126: '<input type="text" name="proctoring_'.$dimen.'_'.$provider.'" size="5" '. 6127: 'value="'.$currentdef{$dimen}.'" /></label>'. 6128: (' 'x2); 6129: } 6130: $datatable .= '</span><br />'. 6131: '<div class="LC_left_float">'.$fieldtitles{'linktext'}.'<br />'. 6132: '<input type="text" name="proctoring_linktext_'.$provider.'" '. 6133: 'size="25" value="'.$currentdef{'linktext'}.'" /></div>'. 6134: '<div class="LC_left_float">'.$fieldtitles{'explanation'}.'<br />'. 6135: '<textarea name="proctoring_explanation_'.$provider.'" rows="5" cols="40">'. 6136: $currentdef{'explanation'}. 6137: '</textarea></div><div style=""></div><br />'; 6138: } 6139: } else { 6140: if ((exists($options{$field})) && (ref($options{$field}) eq 'ARRAY')) { 6141: my ($output,$selnone); 6142: unless ($checked) { 6143: $selnone = ' selected="selected"'; 6144: } 6145: $output .= '<span class="LC_nobreak">'.$fieldtitles{$field}.': '. 6146: '<select name="proctoring_defaults_'.$field.'_'.$provider.'">'. 6147: '<option value=""'.$selnone.'>'.&mt('Not in use').'</option>'; 6148: foreach my $option (@{$options{$field}}) { 6149: my $sel; 6150: if ($inuse{$field} eq $option) { 6151: $sel = ' selected="selected"'; 6152: } 6153: $output .= '<option value="'.$option.'"'.$sel.'>'.$fieldtitles{$option}.'</option>'; 6154: } 6155: $output .= '</select></span>'; 6156: push(@selectboxes,$output); 6157: } else { 6158: $rem = $i%($numinrow); 6159: if ($rem == 0) { 6160: if ($i > 0) { 6161: $datatable .= '</tr>'; 6162: } 6163: $datatable .= '<tr>'; 6164: } 6165: $datatable .= '<td class="LC_left_item">'. 6166: '<span class="LC_nobreak">'. 6167: '<label><input type="checkbox" name="proctoring_defaults_'.$provider.'" value="'.$field.'"'.$checked.' />'. 6168: $fieldtitles{$field}.'</label></span></td>'; 6169: $i++; 6170: } 6171: } 6172: } 6173: if ($provider eq 'proctorio') { 6174: if ($numinrow) { 6175: $rem = $i%$numinrow; 6176: } 6177: my $colsleft = $numinrow - $rem; 6178: if ($colsleft > 1) { 6179: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; 6180: } else { 6181: $datatable .= '<td class="LC_left_item">'; 6182: } 6183: $datatable .= ' '. 6184: '</td></tr></table>'; 6185: if (@selectboxes) { 6186: $datatable .= '<hr /><table>'; 6187: $numinrow = 2; 6188: for (my $i=0; $i<@selectboxes; $i++) { 6189: $rem = $i%($numinrow); 6190: if ($rem == 0) { 6191: if ($i > 0) { 6192: $datatable .= '</tr>'; 6193: } 6194: $datatable .= '<tr>'; 6195: } 6196: $datatable .= '<td class="LC_left_item">'. 6197: $selectboxes[$i].'</td>'; 6198: } 6199: if ($numinrow) { 6200: $rem = $i%$numinrow; 6201: } 6202: $colsleft = $numinrow - $rem; 6203: if ($colsleft > 1) { 6204: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; 6205: } else { 6206: $datatable .= '<td class="LC_left_item">'; 6207: } 6208: $datatable .= ' '. 6209: '</td></tr></table>'; 6210: } 6211: } 6212: $datatable .= '</fieldset>'; 6213: } 6214: if (ref($crsconf{$provider}) eq 'ARRAY') { 6215: $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'. 6216: '<legend>'.&mt('Configurable in course').'</legend>'; 6217: my ($rem,$numinrow); 6218: if ($provider eq 'proctorio') { 6219: $datatable .= '<table>'; 6220: $numinrow = 4; 6221: } 6222: my $i = 0; 6223: foreach my $item (@{$crsconf{$provider}}) { 6224: my $name; 6225: if ($provider eq 'examity') { 6226: $name = $lt{'crs'.$item}; 6227: } elsif ($provider eq 'proctorio') { 6228: $name = $fieldtitles{$item}; 6229: $rem = $i%($numinrow); 6230: if ($rem == 0) { 6231: if ($i > 0) { 6232: $datatable .= '</tr>'; 6233: } 6234: $datatable .= '<tr>'; 6235: } 6236: $datatable .= '<td class="LC_left_item>'; 6237: } 6238: my $checked; 6239: if ($crsconfig{$item}) { 6240: $checked = ' checked="checked"'; 6241: } 6242: $datatable .= '<span class="LC_nobreak"><label>'. 6243: '<input type="checkbox" name="proctoring_crsconf_'.$provider.'" value="'.$item.'"'.$checked.' />'. 6244: $name.'</label></span>'; 6245: if ($provider eq 'examity') { 6246: $datatable .= ' '; 6247: } 6248: $datatable .= "\n"; 6249: $i++; 6250: } 6251: if ($provider eq 'proctorio') { 6252: if ($numinrow) { 6253: $rem = $i%$numinrow; 6254: } 6255: my $colsleft = $numinrow - $rem; 6256: if ($colsleft > 1) { 6257: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; 6258: } else { 6259: $datatable .= '<td class="LC_left_item">'; 6260: } 6261: $datatable .= ' '. 6262: '</td></tr></table>'; 6263: } 6264: $datatable .= '</fieldset>'; 6265: } 6266: if ($showroles) { 6267: $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'. 6268: '<legend>'.&mt('Role mapping').'</legend><table><tr>'; 6269: foreach my $role (@courseroles) { 6270: my ($selected,$selectnone); 6271: if (!$rolemaps{$role}) { 6272: $selectnone = ' selected="selected"'; 6273: } 6274: $datatable .= '<td style="text-align: center">'. 6275: &Apache::lonnet::plaintext($role,'Course').'<br />'. 6276: '<select name="proctoring_roles_'.$role.'_'.$provider.'">'. 6277: '<option value=""'.$selectnone.'>'.&mt('Select').'</option>'; 6278: foreach my $ltirole (@ltiroles) { 6279: unless ($selectnone) { 6280: if ($rolemaps{$role} eq $ltirole) { 6281: $selected = ' selected="selected"'; 6282: } else { 6283: $selected = ''; 6284: } 6285: } 6286: $datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>'; 6287: } 6288: $datatable .= '</select></td>'; 6289: } 6290: $datatable .= '</tr></table></fieldset>'. 6291: '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'. 6292: '<legend>'.&mt('Custom items sent on launch').'</legend>'. 6293: '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'. 6294: '<tr><td></td><td>lms</td>'. 6295: '<td><input type="text" name="proctoring_customval_lms_'.$provider.'"'. 6296: ' value="Loncapa" disabled="disabled"/></td></tr>'; 6297: if ((ref($settings) eq 'HASH') && (ref($settings->{$provider}) eq 'HASH') && 6298: (ref($settings->{$provider}->{'custom'}) eq 'HASH')) { 6299: my %custom = %{$settings->{$provider}->{'custom'}}; 6300: if (keys(%custom) > 0) { 6301: foreach my $key (sort(keys(%custom))) { 6302: next if ($key eq 'lms'); 6303: $datatable .= '<tr><td><span class="LC_nobreak">'. 6304: '<label><input type="checkbox" name="proctoring_customdel_'.$provider.'" value="'. 6305: $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'. 6306: '<td><input type="text" name="proctoring_customval_'.$key.'_'.$provider.'"'. 6307: ' value="'.$custom{$key}.'" /></td></tr>'; 6308: } 6309: } 6310: } 6311: $datatable .= '<tr><td><span class="LC_nobreak">'. 6312: '<label><input type="checkbox" name="proctoring_customadd" value="'.$provider.'" />'. 6313: &mt('Add more').'</label></span></td><td><input type="text" name="proctoring_custom_name_'.$provider.'" />'. 6314: '</td><td><input type="text" name="proctoring_custom_value_'.$provider.'" /></td></tr>'. 6315: '</table></fieldset></td></tr>'."\n"; 6316: } 6317: $datatable .= '</td></tr>'; 6318: } 6319: $itemcount ++; 6320: } 6321: } 6322: return $datatable; 6323: } 6324: 6325: sub proctoring_data { 6326: my $requserfields = { 6327: proctorio => ['user'], 6328: examity => ['roles','user'], 6329: }; 6330: my $optuserfields = { 6331: proctorio => ['fullname'], 6332: examity => ['fullname','firstname','lastname','email'], 6333: }; 6334: my $defaults = { 6335: proctorio => ['recordvideo','recordaudio','recordscreen','recordwebtraffic', 6336: 'recordroomstart','verifyvideo','verifyaudio','verifydesktop', 6337: 'verifyid','verifysignature','fullscreen','clipboard','tabslinks', 6338: 'closetabs','onescreen','print','downloads','cache','rightclick', 6339: 'reentry','calculator','whiteboard'], 6340: examity => ['display'], 6341: }; 6342: my $extended = { 6343: proctorio => { 6344: verifyid => ['verifyidauto','verifyidlive'], 6345: fullscreen => ['fullscreenlenient','fullscreenmoderate','fullscreensever'], 6346: tabslinks => ['notabs','linksonly'], 6347: reentry => ['noreentry','agentreentry'], 6348: calculator => ['calculatorbasic','calculatorsci'], 6349: }, 6350: examity => { 6351: display => { 6352: target => ['iframe','tab','window'], 6353: width => '', 6354: height => '', 6355: linktext => '', 6356: explanation => '', 6357: }, 6358: }, 6359: }; 6360: my $crsconf = { 6361: proctorio => ['recordvideo','recordaudio','recordscreen','recordwebtraffic', 6362: 'recordroomstart','verifyvideo','verifyaudio','verifydesktop', 6363: 'verifyid','verifysignature','fullscreen','clipboard','tabslinks', 6364: 'closetabs','onescreen','print','downloads','cache','rightclick', 6365: 'reentry','calculator','whiteboard'], 6366: examity => ['label','title','target','linktext','explanation','append'], 6367: }; 6368: my $courseroles = ['cc','in','ta','ep','st']; 6369: my $ltiroles = ['Instructor','ContentDeveloper','TeachingAssistant','Learner']; 6370: return ($requserfields,$optuserfields,$defaults,$extended,$crsconf,$courseroles,$ltiroles); 6371: } 6372: 6373: sub proctoring_titles { 6374: my ($item) = @_; 6375: my (%common_lt,%custom_lt); 6376: %common_lt = &Apache::lonlocal::texthash ( 6377: 'avai' => 'Available?', 6378: 'base' => 'Basic Settings', 6379: 'requ' => 'User data required to be sent on launch', 6380: 'optu' => 'User data optionally sent on launch', 6381: 'udsl' => 'User data sent on launch', 6382: 'defa' => 'Defaults for items configurable in course', 6383: 'sigmethod' => 'Signature Method', 6384: 'key' => 'Key', 6385: 'lifetime' => 'Nonce lifetime (s)', 6386: 'secret' => 'Secret', 6387: 'icon' => 'Icon', 6388: 'fullname' => 'Full Name', 6389: 'visible' => 'Visible input', 6390: 'username' => 'username', 6391: 'user' => 'User', 6392: ); 6393: if ($item eq 'proctorio') { 6394: %custom_lt = &Apache::lonlocal::texthash ( 6395: 'version' => 'OAuth version', 6396: 'url' => 'API URL', 6397: 'uname:dom' => 'username-domain', 6398: ); 6399: } elsif ($item eq 'examity') { 6400: %custom_lt = &Apache::lonlocal::texthash ( 6401: 'version' => 'LTI Version', 6402: 'url' => 'URL', 6403: 'uname:dom' => 'username:domain', 6404: 'msgtype' => 'Message Type', 6405: 'firstname' => 'First Name', 6406: 'lastname' => 'Last Name', 6407: 'email' => 'E-mail', 6408: 'roles' => 'Role', 6409: 'crstarget' => 'Display target', 6410: 'crslabel' => 'Course label', 6411: 'crstitle' => 'Course title', 6412: 'crslinktext' => 'Link Text', 6413: 'crsexplanation' => 'Explanation', 6414: 'crsappend' => 'Provider URL', 6415: ); 6416: } 6417: my %lt = (%common_lt,%custom_lt); 6418: return %lt; 6419: } 6420: 6421: sub proctoring_fieldtitles { 6422: my ($item) = @_; 6423: if ($item eq 'proctorio') { 6424: return &Apache::lonlocal::texthash ( 6425: 'recordvideo' => 'Record video', 6426: 'recordaudio' => 'Record audio', 6427: 'recordscreen' => 'Record screen', 6428: 'recordwebtraffic' => 'Record web traffic', 6429: 'recordroomstart' => 'Record room scan', 6430: 'verifyvideo' => 'Verify webcam', 6431: 'verifyaudio' => 'Verify microphone', 6432: 'verifydesktop' => 'Verify desktop recording', 6433: 'verifyid' => 'Photo ID verification', 6434: 'verifysignature' => 'Require signature', 6435: 'fullscreen' => 'Fullscreen', 6436: 'clipboard' => 'Disable copy/paste', 6437: 'tabslinks' => 'New tabs/windows', 6438: 'closetabs' => 'Close other tabs', 6439: 'onescreen' => 'Limit to single screen', 6440: 'print' => 'Disable Printing', 6441: 'downloads' => 'Disable Downloads', 6442: 'cache' => 'Empty cache after exam', 6443: 'rightclick' => 'Disable right click', 6444: 'reentry' => 'Re-entry to exam', 6445: 'calculator' => 'Onscreen calculator', 6446: 'whiteboard' => 'Onscreen whiteboard', 6447: 'verifyidauto' => 'Automated verification', 6448: 'verifyidlive' => 'Live agent verification', 6449: 'fullscreenlenient' => 'Forced, but can navigate away for up to 30s', 6450: 'fullscreenmoderate' => 'Forced, but can navigate away for up to 15s', 6451: 'fullscreensever' => 'Forced, navigation away ends exam', 6452: 'notabs' => 'Disaallowed', 6453: 'linksonly' => 'Allowed from links in exam', 6454: 'noreentry' => 'Disallowed', 6455: 'agentreentry' => 'Agent required for re-entry', 6456: 'calculatorbasic' => 'Basic', 6457: 'calculatorsci' => 'Scientific', 6458: ); 6459: } elsif ($item eq 'examity') { 6460: return &Apache::lonlocal::texthash ( 6461: 'target' => 'Display target', 6462: 'window' => 'Window', 6463: 'tab' => 'Tab', 6464: 'iframe' => 'iFrame', 6465: 'height' => 'Height (pixels)', 6466: 'width' => 'Width (pixels)', 6467: 'linktext' => 'Default Link Text', 6468: 'explanation' => 'Default Explanation', 6469: 'append' => 'Provider URL', 6470: ); 6471: } 6472: } 6473: 6474: sub proctoring_providernames { 6475: return ( 6476: proctorio => 'Proctorio', 6477: examity => 'Examity', 6478: ); 6479: } 6480: 6481: sub print_lti { 6482: my ($position,$dom,$settings,$rowtotal) = @_; 6483: my $itemcount = 1; 6484: my ($datatable,$css_class); 6485: my (%rules,%encrypt,%privkeys,%linkprot); 6486: if (ref($settings) eq 'HASH') { 6487: if ($position eq 'top') { 6488: if (exists($settings->{'encrypt'})) { 6489: if (ref($settings->{'encrypt'}) eq 'HASH') { 6490: foreach my $key (keys(%{$settings->{'encrypt'}})) { 6491: if ($key eq 'consumers') { 6492: $encrypt{'ltisec_'.$key} = $settings->{'encrypt'}{$key}; 6493: } else { 6494: $encrypt{'ltisec_'.$key.'linkprot'} = $settings->{'encrypt'}{$key}; 6495: } 6496: } 6497: } 6498: } 6499: if (exists($settings->{'private'})) { 6500: if (ref($settings->{'private'}) eq 'HASH') { 6501: if (ref($settings->{'private'}) eq 'HASH') { 6502: if (ref($settings->{'private'}{'keys'}) eq 'ARRAY') { 6503: map { $privkeys{$_} = 1; } (@{$settings->{'private'}{'keys'}}); 6504: } 6505: } 6506: } 6507: } 6508: } elsif ($position eq 'middle') { 6509: if (exists($settings->{'rules'})) { 6510: if (ref($settings->{'rules'}) eq 'HASH') { 6511: %rules = %{$settings->{'rules'}}; 6512: } 6513: } 6514: } elsif ($position eq 'lower') { 6515: if (exists($settings->{'linkprot'})) { 6516: if (ref($settings->{'linkprot'}) eq 'HASH') { 6517: %linkprot = %{$settings->{'linkprot'}}; 6518: if ($linkprot{'lock'}) { 6519: delete($linkprot{'lock'}); 6520: } 6521: } 6522: } 6523: } else { 6524: foreach my $key ('encrypt','private','rules','linkprot') { 6525: if (exists($settings->{$key})) { 6526: delete($settings->{$key}); 6527: } 6528: } 6529: } 6530: } 6531: if ($position eq 'top') { 6532: my @ids=&Apache::lonnet::current_machine_ids(); 6533: my %servers = &Apache::lonnet::get_servers($dom,'library'); 6534: my $primary = &Apache::lonnet::domain($dom,'primary'); 6535: my ($extra,$numshown); 6536: foreach my $hostid (sort(keys(%servers))) { 6537: my ($showextra,$divsty,$switch); 6538: if ($hostid eq $primary) { 6539: if (($encrypt{'ltisec_consumers'}) || ($encrypt{'ltisec_domlinkprot'})) { 6540: $showextra = 1; 6541: } 6542: } 6543: if ($encrypt{'ltisec_crslinkprot'}) { 6544: $showextra = 1; 6545: } 6546: unless (grep(/^\Q$hostid\E$/,@ids)) { 6547: $switch = 1; 6548: } 6549: if ($showextra) { 6550: $numshown ++; 6551: $divsty = 'display:inline-block'; 6552: } else { 6553: $divsty = 'display:none'; 6554: } 6555: $extra .= '<fieldset id="ltisec_info_'.$hostid.'" style="'.$divsty.'">'. 6556: '<legend>'.$hostid.'</legend>'; 6557: if ($switch) { 6558: my $switchserver = '<a href="/adm/switchserver?otherserver='.$hostid.'&role='. 6559: &HTML::Entities::encode($env{'request.role'},'\'<>"&'). 6560: '&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>'; 6561: if (exists($privkeys{$hostid})) { 6562: $extra .= '<div id="ltisec_divcurrprivkey_'.$hostid.'" style="display:inline-block" />'. 6563: '<span class="LC_nobreak">'. 6564: &mt('Encryption Key').': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'. 6565: '<span class="LC_nobreak">'.&mt('Change?'). 6566: '<label><input type="radio" value="0" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'. 6567: (' 'x2). 6568: '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes'). 6569: '</label> </span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'. 6570: '<span class="LC_nobreak"> - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver). 6571: '</span></div>'; 6572: } else { 6573: $extra .= '<span class="LC_nobreak">'. 6574: &mt('Key required').' - '.&mt('submit from server ([_1]): [_2].',$hostid,$switchserver). 6575: '</span>'."\n"; 6576: } 6577: } elsif (exists($privkeys{$hostid})) { 6578: $extra .= '<div id="ltisec_divcurrprivkey_'.$hostid.'" style="display:inline-block" /><span class="LC_nobreak">'. 6579: &mt('Encryption Key').': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'. 6580: '<span class="LC_nobreak">'.&mt('Change?'). 6581: '<label><input type="radio" value="0" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" checked="checked" />'.&mt('No').'</label>'. 6582: (' 'x2). 6583: '<label><input type="radio" value="1" name="ltisec_changeprivkey_'.$hostid.'" onclick="javascript:togglePrivKey(this.form,'."'$hostid'".');" />'.&mt('Yes'). 6584: '</label> </span><div id="ltisec_divchgprivkey_'.$hostid.'" style="display:none" />'. 6585: '<span class="LC_nobreak">'.&mt('New Key').':'. 6586: '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="new-password" />'. 6587: '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'. 6588: '</span></div>'; 6589: } else { 6590: $extra .= '<span class="LC_nobreak">'.&mt('Encryption Key').':'. 6591: '<input type="password" size="20" name="ltisec_privkey_'.$hostid.'" value="" autocomplete="new-password" />'. 6592: '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.ltisec_privkey_'.$hostid.'.type='."'text'".' } else { this.form.ltisec_privkey_'.$hostid.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'; 6593: } 6594: $extra .= '</fieldset>'; 6595: } 6596: my %choices = &Apache::lonlocal::texthash ( 6597: ltisec_crslinkprot => 'Encrypt stored link protection secrets defined in courses', 6598: ltisec_domlinkprot => 'Encrypt stored link protection secrets defined in domain', 6599: ltisec_consumers => 'Encrypt stored consumer secrets defined in domain', 6600: ); 6601: my @toggles = qw(ltisec_crslinkprot ltisec_domlinkprot ltisec_consumers); 6602: my %defaultchecked = ( 6603: 'ltisec_crslinkprot' => 'off', 6604: 'ltisec_domlinkprot' => 'off', 6605: 'ltisec_consumers' => 'off', 6606: ); 6607: my ($onclick,$itemcount); 6608: $onclick = 'javascript:toggleLTIEncKey(this.form);'; 6609: ($datatable,$itemcount) = &radiobutton_prefs(\%encrypt,\@toggles,\%defaultchecked, 6610: \%choices,$itemcount,$onclick,'','left','no'); 6611: 6612: $css_class = $itemcount%2?' class="LC_odd_row"':''; 6613: my $noprivkeysty = 'display:inline-block'; 6614: if ($numshown) { 6615: $noprivkeysty = 'display:none'; 6616: } 6617: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.&mt('Encryption Key(s)').'</td>'. 6618: '<td><div id="ltisec_noprivkey" style="'.$noprivkeysty.'" >'. 6619: '<span class="LC_nobreak">'.&mt('Not in use').'</span></div>'. 6620: $extra. 6621: '</td></tr>'; 6622: $itemcount ++; 6623: $$rowtotal += $itemcount; 6624: } elsif ($position eq 'middle') { 6625: $datatable = &password_rules('secrets',\$itemcount,\%rules); 6626: $$rowtotal += $itemcount; 6627: } elsif ($position eq 'lower') { 6628: $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain'); 6629: } else { 6630: my $maxnum = 0; 6631: my %ordered; 6632: if (ref($settings) eq 'HASH') { 6633: foreach my $item (keys(%{$settings})) { 6634: if (ref($settings->{$item}) eq 'HASH') { 6635: my $num = $settings->{$item}{'order'}; 6636: if ($num eq '') { 6637: $num = scalar(keys(%{$settings})); 6638: } 6639: $ordered{$num} = $item; 6640: } 6641: } 6642: } 6643: $maxnum = scalar(keys(%ordered)); 6644: my %lt = <i_names(); 6645: if (keys(%ordered)) { 6646: my @items = sort { $a <=> $b } keys(%ordered); 6647: for (my $i=0; $i<@items; $i++) { 6648: $css_class = $itemcount%2?' class="LC_odd_row"':''; 6649: my $item = $ordered{$items[$i]}; 6650: my ($key,$secret,$lifetime,$consumer,$requser,$crsinc,$current); 6651: if (ref($settings->{$item}) eq 'HASH') { 6652: $key = $settings->{$item}->{'key'}; 6653: $secret = $settings->{$item}->{'secret'}; 6654: $lifetime = $settings->{$item}->{'lifetime'}; 6655: $consumer = $settings->{$item}->{'consumer'}; 6656: $requser = $settings->{$item}->{'requser'}; 6657: $crsinc = $settings->{$item}->{'crsinc'}; 6658: $current = $settings->{$item}; 6659: } 6660: my $onclickrequser = ' onclick="toggleLTI(this.form,'."'requser','$i'".');"'; 6661: my %checkedrequser = ( 6662: yes => ' checked="checked"', 6663: no => '', 6664: ); 6665: if (!$requser) { 6666: $checkedrequser{'no'} = $checkedrequser{'yes'}; 6667: $checkedrequser{'yes'} = ''; 6668: } 6669: my $onclickcrsinc = ' onclick="toggleLTI(this.form,'."'crsinc','$i'".');"'; 6670: my %checkedcrsinc = ( 6671: yes => ' checked="checked"', 6672: no => '', 6673: ); 6674: if (!$crsinc) { 6675: $checkedcrsinc{'no'} = $checkedcrsinc{'yes'}; 6676: $checkedcrsinc{'yes'} = ''; 6677: } 6678: my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"'; 6679: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 6680: .'<select name="lti_pos_'.$item.'"'.$chgstr.'>'; 6681: for (my $k=0; $k<=$maxnum; $k++) { 6682: my $vpos = $k+1; 6683: my $selstr; 6684: if ($k == $i) { 6685: $selstr = ' selected="selected" '; 6686: } 6687: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 6688: } 6689: $datatable .= '</select>'.(' 'x2). 6690: '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'. 6691: &mt('Delete?').'</label></span></td>'. 6692: '<td colspan="2">'. 6693: '<fieldset><legend>'.&mt('Required settings').'</legend>'. 6694: '<span class="LC_nobreak">'.$lt{'consumer'}. 6695: ':<input type="text" size="15" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '. 6696: (' 'x2). 6697: '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'. 6698: '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '. 6699: (' 'x2). 6700: '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'. 6701: 'value="'.$lifetime.'" size="3" /></span>'. 6702: (' 'x2). 6703: '<span class="LC_nobreak">'.$lt{'requser'}.':'. 6704: '<label><input type="radio" name="lti_requser_'.$i.'" value="1"'.$onclickrequser.$checkedrequser{yes}.' />'.&mt('Yes').'</label> '."\n". 6705: '<label><input type="radio" name="lti_requser_'.$i.'" value="0"'.$onclickrequser.$checkedrequser{no}.' />'.&mt('No').'</label></span>'."\n". 6706: '<br /><br />'. 6707: '<span class="LC_nobreak">'.$lt{'crsinc'}.':'. 6708: '<label><input type="radio" name="lti_crsinc_'.$i.'" value="1"'.$onclickcrsinc.$checkedcrsinc{yes}.' />'.&mt('Yes').'</label> '."\n". 6709: '<label><input type="radio" name="lti_crsinc_'.$i.'" value="0"'.$onclickcrsinc.$checkedcrsinc{no}.' />'.&mt('No').'</label></span>'."\n". 6710: (' 'x4). 6711: '<span class="LC_nobreak">'.$lt{'key'}. 6712: ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '. 6713: (' 'x2). 6714: '<span class="LC_nobreak">'.$lt{'secret'}.':'. 6715: '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'. 6716: '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'. 6717: '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'. 6718: '</fieldset>'.<i_options($i,$current,$itemcount,%lt).'</td></tr>'; 6719: $itemcount ++; 6720: } 6721: } 6722: $css_class = $itemcount%2?' class="LC_odd_row"':''; 6723: my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"'; 6724: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". 6725: '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n". 6726: '<select name="lti_pos_add"'.$chgstr.'>'; 6727: for (my $k=0; $k<$maxnum+1; $k++) { 6728: my $vpos = $k+1; 6729: my $selstr; 6730: if ($k == $maxnum) { 6731: $selstr = ' selected="selected" '; 6732: } 6733: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 6734: } 6735: $datatable .= '</select> '."\n". 6736: '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n". 6737: '<td colspan="2">'. 6738: '<fieldset><legend>'.&mt('Required settings').'</legend>'. 6739: '<span class="LC_nobreak">'.$lt{'consumer'}. 6740: ':<input type="text" size="15" name="lti_consumer_add" value="" /></span> '."\n". 6741: (' 'x2). 6742: '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'. 6743: '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n". 6744: (' 'x2). 6745: '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="lti_lifetime_add" value="300" /></span> '."\n". 6746: (' 'x2). 6747: '<span class="LC_nobreak">'.$lt{'requser'}.':'. 6748: '<label><input type="radio" name="lti_requser_add" value="1" onclick="toggleLTI(this.form,'."'requser','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n". 6749: '<label><input type="radio" name="lti_requser_add" value="0" onclick="toggleLTI(this.form,'."'requser','add'".');" />'.&mt('No').'</label></span>'."\n". 6750: '<br /><br />'. 6751: '<span class="LC_nobreak">'.$lt{'crsinc'}.':'. 6752: '<label><input type="radio" name="lti_crsinc_add" value="1" onclick="toggleLTI(this.form,'."'crsinc','add'".');" checked="checked" />'.&mt('Yes').'</label> '."\n". 6753: '<label><input type="radio" name="lti_crsinc_add" value="0" onclick="toggleLTI(this.form,'."'crsinc','add'".');" />'.&mt('No').'</label></span>'."\n". 6754: (' 'x4). 6755: '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n". 6756: (' 'x2). 6757: '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'. 6758: '<label><input type="checkbox" name="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". 6759: '</fieldset>'.<i_options('add',undef,$itemcount,%lt). 6760: '</td>'."\n". 6761: '</tr>'."\n"; 6762: $itemcount ++; 6763: } 6764: $$rowtotal += $itemcount; 6765: return $datatable; 6766: } 6767: 6768: sub lti_names { 6769: my %lt = &Apache::lonlocal::texthash( 6770: 'version' => 'LTI Version', 6771: 'url' => 'URL', 6772: 'key' => 'Key', 6773: 'lifetime' => 'Nonce lifetime (s)', 6774: 'consumer' => 'Consumer', 6775: 'secret' => 'Secret', 6776: 'requser' => "User's identity sent", 6777: 'crsinc' => "Course's identity sent", 6778: 'email' => 'Email address', 6779: 'sourcedid' => 'User ID', 6780: 'other' => 'Other', 6781: 'passback' => 'Can return grades to Consumer:', 6782: 'roster' => 'Can retrieve roster from Consumer:', 6783: 'topmenu' => 'Display LON-CAPA page header', 6784: 'inlinemenu'=> 'Display LON-CAPA inline menu', 6785: ); 6786: return %lt; 6787: } 6788: 6789: sub lti_options { 6790: my ($num,$current,$itemcount,%lt) = @_; 6791: my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback); 6792: $checked{'mapuser'}{'sourcedid'} = ' checked="checked"'; 6793: $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"'; 6794: $checked{'storecrs'}{'Y'} = ' checked="checked"'; 6795: $checked{'makecrs'}{'N'} = ' checked="checked"'; 6796: $checked{'mapcrstype'} = {}; 6797: $checked{'makeuser'} = {}; 6798: $checked{'selfenroll'} = {}; 6799: $checked{'crssec'} = {}; 6800: $checked{'crssecsrc'} = {}; 6801: $checked{'lcauth'} = {}; 6802: $checked{'menuitem'} = {}; 6803: if ($num eq 'add') { 6804: $checked{'lcauth'}{'lti'} = ' checked="checked"'; 6805: } 6806: my $userfieldsty = 'none'; 6807: my $crsfieldsty = 'none'; 6808: my $crssecfieldsty = 'none'; 6809: my $secsrcfieldsty = 'none'; 6810: my $callbacksty = 'none'; 6811: my $passbacksty = 'none'; 6812: my $optionsty = 'block'; 6813: my $crssty = 'block'; 6814: my $lcauthparm; 6815: my $lcauthparmstyle = 'display:none'; 6816: my $lcauthparmtext; 6817: my $menusty; 6818: my $numinrow = 4; 6819: my %menutitles = <imenu_titles(); 6820: 6821: if (ref($current) eq 'HASH') { 6822: if (!$current->{'requser'}) { 6823: $optionsty = 'none'; 6824: $crssty = 'none'; 6825: } elsif (!$current->{'crsinc'}) { 6826: $crssty = 'none'; 6827: } 6828: if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) { 6829: $checked{'mapuser'}{'sourcedid'} = ''; 6830: if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') { 6831: $checked{'mapuser'}{'email'} = ' checked="checked"'; 6832: } else { 6833: $checked{'mapuser'}{'other'} = ' checked="checked"'; 6834: $userfield = $current->{'mapuser'}; 6835: $userfieldsty = 'inline-block'; 6836: } 6837: } 6838: if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) { 6839: $checked{'mapcrs'}{'course_offering_sourcedid'} = ''; 6840: if ($current->{'mapcrs'} eq 'context_id') { 6841: $checked{'mapcrs'}{'context_id'} = ' checked="checked"'; 6842: } else { 6843: $checked{'mapcrs'}{'other'} = ' checked="checked"'; 6844: $cidfield = $current->{'mapcrs'}; 6845: $crsfieldsty = 'inline-block'; 6846: } 6847: } 6848: if (ref($current->{'mapcrstype'}) eq 'ARRAY') { 6849: foreach my $type (@{$current->{'mapcrstype'}}) { 6850: $checked{'mapcrstype'}{$type} = ' checked="checked"'; 6851: } 6852: } 6853: if (!$current->{'storecrs'}) { 6854: $checked{'storecrs'}{'N'} = $checked{'storecrs'}{'Y'}; 6855: $checked{'storecrs'}{'Y'} = ''; 6856: } 6857: if ($current->{'makecrs'}) { 6858: $checked{'makecrs'}{'Y'} = ' checked="checked"'; 6859: } 6860: if (ref($current->{'makeuser'}) eq 'ARRAY') { 6861: foreach my $role (@{$current->{'makeuser'}}) { 6862: $checked{'makeuser'}{$role} = ' checked="checked"'; 6863: } 6864: } 6865: if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) { 6866: $checked{'lcauth'}{$1} = ' checked="checked"'; 6867: unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) { 6868: $lcauthparm = $current->{'lcauthparm'}; 6869: $lcauthparmstyle = 'display:table-row'; 6870: if ($current->{'lcauth'} eq 'localauth') { 6871: $lcauthparmtext = &mt('Local auth argument'); 6872: } else { 6873: $lcauthparmtext = &mt('Kerberos domain'); 6874: } 6875: } 6876: } 6877: if (ref($current->{'selfenroll'}) eq 'ARRAY') { 6878: foreach my $role (@{$current->{'selfenroll'}}) { 6879: $checked{'selfenroll'}{$role} = ' checked="checked"'; 6880: } 6881: } 6882: if (ref($current->{'maproles'}) eq 'HASH') { 6883: %rolemaps = %{$current->{'maproles'}}; 6884: } 6885: if ($current->{'section'} ne '') { 6886: $checked{'crssec'}{'Y'} = ' checked="checked"'; 6887: $crssecfieldsty = 'inline-block'; 6888: if ($current->{'section'} eq 'course_section_sourcedid') { 6889: $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"'; 6890: } else { 6891: $checked{'crssecsrc'}{'other'} = ' checked="checked"'; 6892: $crssecsrc = $current->{'section'}; 6893: $secsrcfieldsty = 'inline-block'; 6894: } 6895: } else { 6896: $checked{'crssec'}{'N'} = ' checked="checked"'; 6897: } 6898: if ($current->{'callback'} ne '') { 6899: $callback = $current->{'callback'}; 6900: $checked{'callback'}{'Y'} = ' checked="checked"'; 6901: $callbacksty = 'inline-block'; 6902: } else { 6903: $checked{'callback'}{'N'} = ' checked="checked"'; 6904: } 6905: if ($current->{'topmenu'}) { 6906: $checked{'topmenu'}{'Y'} = ' checked="checked"'; 6907: } else { 6908: $checked{'topmenu'}{'N'} = ' checked="checked"'; 6909: } 6910: if ($current->{'inlinemenu'}) { 6911: $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; 6912: } else { 6913: $checked{'inlinemenu'}{'N'} = ' checked="checked"'; 6914: } 6915: if (($current->{'topmenu'}) || ($current->{'inlinemenu'})) { 6916: $menusty = 'inline-block'; 6917: if (ref($current->{'lcmenu'}) eq 'ARRAY') { 6918: foreach my $item (@{$current->{'lcmenu'}}) { 6919: if (exists($menutitles{$item})) { 6920: $checked{'menuitem'}{$item} = ' checked="checked"'; 6921: } 6922: } 6923: } 6924: } else { 6925: $menusty = 'none'; 6926: } 6927: } else { 6928: $checked{'makecrs'}{'N'} = ' checked="checked"'; 6929: $checked{'crssec'}{'N'} = ' checked="checked"'; 6930: $checked{'callback'}{'N'} = ' checked="checked"'; 6931: $checked{'topmenu'}{'N'} = ' checked="checked"'; 6932: $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; 6933: $checked{'menuitem'}{'grades'} = ' checked="checked"'; 6934: $menusty = 'inline-block'; 6935: } 6936: my @coursetypes = ('official','unofficial','community','textbook','placement','lti'); 6937: my %coursetypetitles = &Apache::lonlocal::texthash ( 6938: official => 'Official', 6939: unofficial => 'Unofficial', 6940: community => 'Community', 6941: textbook => 'Textbook', 6942: placement => 'Placement Test', 6943: lti => 'LTI Provider', 6944: ); 6945: my @authtypes = ('internal','krb4','krb5','localauth'); 6946: my %shortauth = ( 6947: internal => 'int', 6948: krb4 => 'krb4', 6949: krb5 => 'krb5', 6950: localauth => 'loc' 6951: ); 6952: my %authnames = &authtype_names(); 6953: my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator); 6954: my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor); 6955: my @courseroles = ('cc','in','ta','ep','st'); 6956: my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"'; 6957: my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"'; 6958: my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"'; 6959: my $onclickcallback = ' onclick="toggleLTI(this.form,'."'callback','$num'".');"'; 6960: my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"'; 6961: my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"'; 6962: my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"'; 6963: my $output = '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Logout options').'</legend>'. 6964: '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback to logout LON-CAPA on log out from Consumer').': '. 6965: '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'. 6966: $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.(' 'x2). 6967: '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'. 6968: $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'. 6969: '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'. 6970: '<span class="LC_nobreak">'.&mt('Parameter').': '. 6971: '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'. 6972: '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'. 6973: '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Mapping users').'</legend>'. 6974: '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').': '; 6975: foreach my $option ('sourcedid','email','other') { 6976: $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'. 6977: $checked{'mapuser'}{$option}.$onclickuser.' />'.$lt{$option}.'</label>'. 6978: ($option eq 'other' ? '' : (' 'x2) ); 6979: } 6980: $output .= '</span></div>'. 6981: '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'. 6982: '<input type="text" name="lti_customuser_'.$num.'" '. 6983: 'value="'.$userfield.'" /></div></fieldset>'. 6984: '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Roles which may create user accounts').'</legend>'; 6985: foreach my $ltirole (@ltiroles) { 6986: $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'. 6987: $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label> </span> '; 6988: } 6989: $output .= '</fieldset>'. 6990: '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('New user accounts created for LTI users').'</legend>'. 6991: '<table>'. 6992: &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount). 6993: '</table>'. 6994: '<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'. 6995: '<td class="LC_left_item">'; 6996: foreach my $auth ('lti',@authtypes) { 6997: my $authtext; 6998: if ($auth eq 'lti') { 6999: $authtext = &mt('None'); 7000: } else { 7001: $authtext = $authnames{$shortauth{$auth}}; 7002: } 7003: $output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num. 7004: '" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'. 7005: $authtext.'</label></span> '; 7006: } 7007: $output .= '</td></tr>'. 7008: '<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'. 7009: '<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'. 7010: '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'. 7011: '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'. 7012: '</table></fieldset>'. 7013: '<fieldset class="ltioption_usr_'.$num.'" style="display:'.$optionsty.'"><legend>'. 7014: &mt('LON-CAPA menu items (Course Coordinator can override)').'</legend>'. 7015: '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.': '. 7016: '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'. 7017: $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.(' 'x2). 7018: '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'. 7019: $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'. 7020: '<div style="padding:0;clear:both;margin:0;border:0"></div>'. 7021: '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.': '. 7022: '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'. 7023: $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.(' 'x2). 7024: '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'. 7025: $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'; 7026: $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'. 7027: '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'. 7028: '<span class="LC_nobreak">'.&mt('Menu items').': '; 7029: foreach my $type ('fullname','coursetitle','role','logout','grades') { 7030: $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'. 7031: $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'. 7032: (' 'x2); 7033: } 7034: $output .= '</span></div></fieldset>'. 7035: '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping courses').'</legend>'. 7036: '<div class="LC_floatleft"><span class="LC_nobreak">'. 7037: &mt('Unique course identifier').': '; 7038: foreach my $option ('course_offering_sourcedid','context_id','other') { 7039: $output .= '<label><input type="radio" name="lti_mapcrs_'.$num.'" value="'.$option.'"'. 7040: $checked{'mapcrs'}{$option}.$onclickcrs.' />'.$option.'</label>'. 7041: ($option eq 'other' ? '' : (' 'x2) ); 7042: } 7043: $output .= '</span></div><div class="LC_floatleft" style="display:'.$crsfieldsty.';" id="lti_crsfield_'.$num.'">'. 7044: '<input type="text" name="lti_mapcrsfield_'.$num.'" value="'.$cidfield.'" />'. 7045: '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'. 7046: '<span class="LC_nobreak">'.&mt('LON-CAPA course type(s)').': '; 7047: foreach my $type (@coursetypes) { 7048: $output .= '<label><input type="checkbox" name="lti_mapcrstype_'.$num.'" value="'.$type.'"'. 7049: $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'. 7050: (' 'x2); 7051: } 7052: $output .= '</span><br /><br />'. 7053: '<span class="LC_nobreak">'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '. 7054: '<label><input type="radio" name="lti_storecrs_'.$num.'" value="0"'. 7055: $checked{'storecrs'}{'N'}.' />'.&mt('No').'</label>'.(' 'x2). 7056: '<label><input type="radio" name="lti_storecrs_'.$num.'" value="1"'. 7057: $checked{'storecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'. 7058: '</fieldset>'. 7059: '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Mapping course roles').'</legend><table><tr>'; 7060: foreach my $ltirole (@lticourseroles) { 7061: my ($selected,$selectnone); 7062: if ($rolemaps{$ltirole} eq '') { 7063: $selectnone = ' selected="selected"'; 7064: } 7065: $output .= '<td style="text-align: center">'.$ltirole.'<br />'. 7066: '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'. 7067: '<option value=""'.$selectnone.'>'.&mt('Select').'</option>'; 7068: foreach my $role (@courseroles) { 7069: unless ($selectnone) { 7070: if ($rolemaps{$ltirole} eq $role) { 7071: $selected = ' selected="selected"'; 7072: } else { 7073: $selected = ''; 7074: } 7075: } 7076: $output .= '<option value="'.$role.'"'.$selected.'>'. 7077: &Apache::lonnet::plaintext($role,'Course'). 7078: '</option>'; 7079: } 7080: $output .= '</select></td>'; 7081: } 7082: $output .= '</tr></table></fieldset>'. 7083: '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Creating courses').'</legend>'. 7084: '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').': '. 7085: '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'. 7086: $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.(' 'x2). 7087: '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'. 7088: $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'. 7089: '</fieldset>'. 7090: '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Roles which may self-enroll').'</legend>'; 7091: foreach my $lticrsrole (@lticourseroles) { 7092: $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'. 7093: $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label> </span> '; 7094: } 7095: $output .= '</fieldset>'. 7096: '<fieldset class="ltioption_crs_'.$num.'" style="display:'.$crssty.'"><legend>'.&mt('Course options').'</legend>'. 7097: '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').': '. 7098: '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'. 7099: $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.(' 'x2). 7100: '<label><input type="radio" name="lti_crssec_'.$num.'" value="1"'. 7101: $checked{'crssec'}{'Y'}.$onclicksec.' />'.&mt('Yes').'</label></span></div>'. 7102: '<div class="LC_floatleft" style="display:'.$crssecfieldsty.';" id="lti_crssecfield_'.$num.'">'. 7103: '<span class="LC_nobreak">'.&mt('From').':<label>'. 7104: '<input type="radio" name="lti_crssecsrc_'.$num.'" value="course_section_sourcedid"'. 7105: $checked{'crssecsrc'}{'sourcedid'}.$onclicksecsrc.' />'. 7106: &mt('Standard field').'</label>'.(' 'x2). 7107: '<label><input type="radio" name="lti_crssecsrc_'.$num.'" value="other"'. 7108: $checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other'). 7109: '</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'. 7110: '<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'. 7111: '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'; 7112: my ($pb1p1chk,$pb1p0chk,$onclickpb); 7113: foreach my $extra ('roster','passback') { 7114: my $checkedon = ''; 7115: my $checkedoff = ' checked="checked"'; 7116: if ($extra eq 'passback') { 7117: $pb1p1chk = ' checked="checked"'; 7118: $pb1p0chk = ''; 7119: $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"'; 7120: } else { 7121: $onclickpb = ''; 7122: } 7123: if (ref($current) eq 'HASH') { 7124: if (($current->{$extra})) { 7125: $checkedon = $checkedoff; 7126: $checkedoff = ''; 7127: if ($extra eq 'passback') { 7128: $passbacksty = 'inline-block'; 7129: } 7130: if ($current->{'passbackformat'} eq '1.0') { 7131: $pb1p0chk = ' checked="checked"'; 7132: $pb1p1chk = ''; 7133: } 7134: } 7135: } 7136: $output .= $lt{$extra}.' '. 7137: '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'. 7138: &mt('No').'</label>'.(' 'x2). 7139: '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb.' />'. 7140: &mt('Yes').'</label><br />'; 7141: } 7142: $output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'. 7143: '<span class="LC_nobreak">'.&mt('Grade format'). 7144: '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'. 7145: &mt('Outcomes Service (1.1)').'</label>'.(' 'x2). 7146: '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'. 7147: &mt('Outcomes Extension (1.0)').'</label></span></div>'. 7148: '<div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'; 7149: $output .= '</span></div></fieldset>'; 7150: # '<fieldset><legend>'.&mt('Assigning author roles').'</legend>'; 7151: # 7152: # $output .= '</fieldset>'. 7153: # '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>'; 7154: return $output; 7155: } 7156: 7157: sub ltimenu_titles { 7158: return &Apache::lonlocal::texthash( 7159: fullname => 'Full name', 7160: coursetitle => 'Course title', 7161: role => 'Role', 7162: logout => 'Logout', 7163: grades => 'Grades', 7164: ); 7165: } 7166: 7167: sub check_switchserver { 7168: my ($home) = @_; 7169: my $switchserver; 7170: if ($home ne '') { 7171: my $allowed; 7172: my @ids=&Apache::lonnet::current_machine_ids(); 7173: foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } 7174: if (!$allowed) { 7175: $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&role='. 7176: &HTML::Entities::encode($env{'request.role'},'\'<>"&'). 7177: '&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>'; 7178: } 7179: } 7180: return $switchserver; 7181: } 7182: 7183: sub print_coursedefaults { 7184: my ($position,$dom,$settings,$rowtotal) = @_; 7185: my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles); 7186: my $itemcount = 1; 7187: my %choices = &Apache::lonlocal::texthash ( 7188: canuse_pdfforms => 'Course/Community users can create/upload PDF forms', 7189: uploadquota => 'Default quota for files uploaded directly to course/community using Course Editor (MB)', 7190: anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys', 7191: coursecredits => 'Credits can be specified for courses', 7192: uselcmath => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)', 7193: usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)', 7194: inline_chem => 'Use inline previewer for chemical reaction response in place of pop-up', 7195: texengine => 'Default method to display mathematics', 7196: postsubmit => 'Disable submit button/keypress following student submission', 7197: canclone => "People who may clone a course (besides course's owner and coordinators)", 7198: mysqltables => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver', 7199: ltiauth => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication', 7200: ); 7201: my %staticdefaults = ( 7202: anonsurvey_threshold => 10, 7203: uploadquota => 500, 7204: postsubmit => 60, 7205: mysqltables => 172800, 7206: ); 7207: if ($position eq 'top') { 7208: %defaultchecked = ( 7209: 'canuse_pdfforms' => 'off', 7210: 'uselcmath' => 'on', 7211: 'usejsme' => 'on', 7212: 'inline_chem' => 'on', 7213: 'canclone' => 'none', 7214: ); 7215: @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem'); 7216: my $deftex = $Apache::lonnet::deftex; 7217: if (ref($settings) eq 'HASH') { 7218: if ($settings->{'texengine'}) { 7219: if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) { 7220: $deftex = $settings->{'texengine'}; 7221: } 7222: } 7223: } 7224: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7225: my $mathdisp = '<tr'.$css_class.'><td style="vertical-align: top">'. 7226: '<span class="LC_nobreak">'.$choices{'texengine'}. 7227: '</span></td><td class="LC_right_item">'. 7228: '<select name="texengine">'."\n"; 7229: my %texoptions = ( 7230: MathJax => 'MathJax', 7231: mimetex => &mt('Convert to Images'), 7232: tth => &mt('TeX to HTML'), 7233: ); 7234: foreach my $renderer ('MathJax','mimetex','tth') { 7235: my $selected = ''; 7236: if ($renderer eq $deftex) { 7237: $selected = ' selected="selected"'; 7238: } 7239: $mathdisp .= '<option value="'.$renderer.'"'.$selected.'>'.$texoptions{$renderer}.'</option>'."\n"; 7240: } 7241: $mathdisp .= '</select></td></tr>'."\n"; 7242: $itemcount ++; 7243: ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, 7244: \%choices,$itemcount); 7245: $datatable = $mathdisp.$datatable; 7246: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7247: $datatable .= 7248: '<tr'.$css_class.'><td style="vertical-align: top">'. 7249: '<span class="LC_nobreak">'.$choices{'canclone'}. 7250: '</span></td><td class="LC_left_item">'; 7251: my $currcanclone = 'none'; 7252: my $onclick; 7253: my @cloneoptions = ('none','domain'); 7254: my %clonetitles = &Apache::lonlocal::texthash ( 7255: none => 'No additional course requesters', 7256: domain => "Any course requester in course's domain", 7257: instcode => 'Course requests for official courses ...', 7258: ); 7259: my (%codedefaults,@code_order,@posscodes); 7260: if (&Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults, 7261: \@code_order) eq 'ok') { 7262: if (@code_order > 0) { 7263: push(@cloneoptions,'instcode'); 7264: $onclick = ' onclick="toggleDisplay(this.form,'."'cloneinstcode'".');"'; 7265: } 7266: } 7267: if (ref($settings) eq 'HASH') { 7268: if ($settings->{'canclone'}) { 7269: if (ref($settings->{'canclone'}) eq 'HASH') { 7270: if (ref($settings->{'canclone'}{'instcode'}) eq 'ARRAY') { 7271: if (@code_order > 0) { 7272: $currcanclone = 'instcode'; 7273: @posscodes = @{$settings->{'canclone'}{'instcode'}}; 7274: } 7275: } 7276: } elsif ($settings->{'canclone'} eq 'domain') { 7277: $currcanclone = $settings->{'canclone'}; 7278: } 7279: } 7280: } 7281: foreach my $option (@cloneoptions) { 7282: my ($checked,$additional); 7283: if ($currcanclone eq $option) { 7284: $checked = ' checked="checked"'; 7285: } 7286: if ($option eq 'instcode') { 7287: if (@code_order) { 7288: my $show = 'none'; 7289: if ($checked) { 7290: $show = 'block'; 7291: } 7292: $additional = '<div id="cloneinstcode" style="display:'.$show.';" />'. 7293: &mt('Institutional codes for new and cloned course have identical:'). 7294: '<br />'; 7295: foreach my $item (@code_order) { 7296: my $codechk; 7297: if ($checked) { 7298: if (grep(/^\Q$item\E$/,@posscodes)) { 7299: $codechk = ' checked="checked"'; 7300: } 7301: } 7302: $additional .= '<label>'. 7303: '<input type="checkbox" name="clonecode" value="'.$item.'"'.$codechk.' />'. 7304: $item.'</label>'; 7305: } 7306: $additional .= (' 'x2).'('.&mt('check as many as needed').')</div>'; 7307: } 7308: } 7309: $datatable .= 7310: '<span class="LC_nobreak"><label><input type="radio" name="canclone"'.$checked. 7311: ' value="'.$option.'"'.$onclick.' />'.$clonetitles{$option}. 7312: '</label> '.$additional.'</span><br />'; 7313: } 7314: $datatable .= '</td>'. 7315: '</tr>'; 7316: $itemcount ++; 7317: } else { 7318: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 7319: my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql); 7320: my $currusecredits = 0; 7321: my $postsubmitclient = 1; 7322: my $ltiauth = 0; 7323: my @types = ('official','unofficial','community','textbook','placement'); 7324: if (ref($settings) eq 'HASH') { 7325: if ($settings->{'ltiauth'}) { 7326: $ltiauth = 1; 7327: } 7328: $currdefresponder = $settings->{'anonsurvey_threshold'}; 7329: if (ref($settings->{'uploadquota'}) eq 'HASH') { 7330: foreach my $type (keys(%{$settings->{'uploadquota'}})) { 7331: $curruploadquota{$type} = $settings->{'uploadquota'}{$type}; 7332: } 7333: } 7334: if (ref($settings->{'coursecredits'}) eq 'HASH') { 7335: foreach my $type (@types) { 7336: next if ($type eq 'community'); 7337: $defcredits{$type} = $settings->{'coursecredits'}->{$type}; 7338: if ($defcredits{$type} ne '') { 7339: $currusecredits = 1; 7340: } 7341: } 7342: } 7343: if (ref($settings->{'postsubmit'}) eq 'HASH') { 7344: if ($settings->{'postsubmit'}->{'client'} eq 'off') { 7345: $postsubmitclient = 0; 7346: foreach my $type (@types) { 7347: $deftimeout{$type} = $staticdefaults{'postsubmit'}; 7348: } 7349: } else { 7350: foreach my $type (@types) { 7351: if (ref($settings->{'postsubmit'}->{'timeout'}) eq 'HASH') { 7352: if ($settings->{'postsubmit'}->{'timeout'}->{$type} =~ /^\d+$/) { 7353: $deftimeout{$type} = $settings->{'postsubmit'}->{'timeout'}->{$type}; 7354: } else { 7355: $deftimeout{$type} = $staticdefaults{'postsubmit'}; 7356: } 7357: } else { 7358: $deftimeout{$type} = $staticdefaults{'postsubmit'}; 7359: } 7360: } 7361: } 7362: } else { 7363: foreach my $type (@types) { 7364: $deftimeout{$type} = $staticdefaults{'postsubmit'}; 7365: } 7366: } 7367: if (ref($settings->{'mysqltables'}) eq 'HASH') { 7368: foreach my $type (keys(%{$settings->{'mysqltables'}})) { 7369: $currmysql{$type} = $settings->{'mysqltables'}{$type}; 7370: } 7371: } else { 7372: foreach my $type (@types) { 7373: $currmysql{$type} = $staticdefaults{'mysqltables'}; 7374: } 7375: } 7376: } else { 7377: foreach my $type (@types) { 7378: $deftimeout{$type} = $staticdefaults{'postsubmit'}; 7379: } 7380: } 7381: if (!$currdefresponder) { 7382: $currdefresponder = $staticdefaults{'anonsurvey_threshold'}; 7383: } elsif ($currdefresponder < 1) { 7384: $currdefresponder = 1; 7385: } 7386: foreach my $type (@types) { 7387: if ($curruploadquota{$type} eq '') { 7388: $curruploadquota{$type} = $staticdefaults{'uploadquota'}; 7389: } 7390: } 7391: $datatable .= 7392: '<tr'.$css_class.'><td><span class="LC_nobreak">'. 7393: $choices{'anonsurvey_threshold'}. 7394: '</span></td>'. 7395: '<td class="LC_right_item"><span class="LC_nobreak">'. 7396: '<input type="text" name="anonsurvey_threshold"'. 7397: ' value="'.$currdefresponder.'" size="5" /></span>'. 7398: '</td></tr>'."\n"; 7399: $itemcount ++; 7400: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 7401: $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'. 7402: $choices{'uploadquota'}. 7403: '</span></td>'. 7404: '<td style="text-align: right" class="LC_right_item">'. 7405: '<table><tr>'; 7406: foreach my $type (@types) { 7407: $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'. 7408: '<input type="text" name="uploadquota_'.$type.'"'. 7409: ' value="'.$curruploadquota{$type}.'" size="5" /></td>'; 7410: } 7411: $datatable .= '</tr></table></td></tr>'."\n"; 7412: $itemcount ++; 7413: my $onclick = "toggleDisplay(this.form,'credits');"; 7414: my $display = 'none'; 7415: if ($currusecredits) { 7416: $display = 'block'; 7417: } 7418: my $additional = '<div id="credits" style="display: '.$display.'">'. 7419: '<i>'.&mt('Default credits').'</i><br /><table><tr>'; 7420: foreach my $type (@types) { 7421: next if ($type eq 'community'); 7422: $additional .= '<td style="text-align: center">'.&mt($type).'<br />'. 7423: '<input type="text" name="'.$type.'_credits"'. 7424: ' value="'.$defcredits{$type}.'" size="3" /></td>'; 7425: } 7426: $additional .= '</tr></table></div>'."\n"; 7427: %defaultchecked = ('coursecredits' => 'off'); 7428: @toggles = ('coursecredits'); 7429: my $current = { 7430: 'coursecredits' => $currusecredits, 7431: }; 7432: (my $table,$itemcount) = 7433: &radiobutton_prefs($current,\@toggles,\%defaultchecked, 7434: \%choices,$itemcount,$onclick,$additional,'left'); 7435: $datatable .= $table; 7436: $onclick = "toggleDisplay(this.form,'studentsubmission');"; 7437: my $display = 'none'; 7438: if ($postsubmitclient) { 7439: $display = 'block'; 7440: } 7441: $additional = '<div id="studentsubmission" style="display: '.$display.'">'. 7442: &mt('Number of seconds submit is disabled').'<br />'. 7443: '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'. 7444: '<table><tr>'; 7445: foreach my $type (@types) { 7446: $additional .= '<td style="text-align: center">'.&mt($type).'<br />'. 7447: '<input type="text" name="'.$type.'_timeout" value="'. 7448: $deftimeout{$type}.'" size="5" /></td>'; 7449: } 7450: $additional .= '</tr></table></div>'."\n"; 7451: %defaultchecked = ('postsubmit' => 'on'); 7452: @toggles = ('postsubmit'); 7453: $current = { 7454: 'postsubmit' => $postsubmitclient, 7455: }; 7456: ($table,$itemcount) = 7457: &radiobutton_prefs($current,\@toggles,\%defaultchecked, 7458: \%choices,$itemcount,$onclick,$additional,'left'); 7459: $datatable .= $table; 7460: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 7461: $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'. 7462: $choices{'mysqltables'}. 7463: '</span></td>'. 7464: '<td style="text-align: right" class="LC_right_item">'. 7465: '<table><tr>'; 7466: foreach my $type (@types) { 7467: $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'. 7468: '<input type="text" name="mysqltables_'.$type.'"'. 7469: ' value="'.$currmysql{$type}.'" size="8" /></td>'; 7470: } 7471: $datatable .= '</tr></table></td></tr>'."\n"; 7472: $itemcount ++; 7473: %defaultchecked = ('ltiauth' => 'off'); 7474: @toggles = ('ltiauth'); 7475: $current = { 7476: 'ltiauth' => $ltiauth, 7477: }; 7478: ($table,$itemcount) = 7479: &radiobutton_prefs($current,\@toggles,\%defaultchecked, 7480: \%choices,$itemcount,undef,undef,'left'); 7481: $datatable .= $table; 7482: $itemcount ++; 7483: } 7484: $$rowtotal += $itemcount; 7485: return $datatable; 7486: } 7487: 7488: sub print_selfenrollment { 7489: my ($position,$dom,$settings,$rowtotal) = @_; 7490: my ($css_class,$datatable); 7491: my $itemcount = 1; 7492: my @types = ('official','unofficial','community','textbook','placement'); 7493: if (($position eq 'top') || ($position eq 'middle')) { 7494: my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles(); 7495: my %descs = &Apache::lonuserutils::selfenroll_default_descs(); 7496: my @rows; 7497: my $key; 7498: if ($position eq 'top') { 7499: $key = 'admin'; 7500: if (ref($rowsref) eq 'ARRAY') { 7501: @rows = @{$rowsref}; 7502: } 7503: } elsif ($position eq 'middle') { 7504: $key = 'default'; 7505: @rows = ('types','registered','approval','limit'); 7506: } 7507: foreach my $row (@rows) { 7508: if (defined($titlesref->{$row})) { 7509: $itemcount ++; 7510: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7511: $datatable .= '<tr'.$css_class.'>'. 7512: '<td>'.$titlesref->{$row}.'</td>'. 7513: '<td class="LC_left_item">'. 7514: '<table><tr>'; 7515: my (%current,%currentcap); 7516: if (ref($settings) eq 'HASH') { 7517: if (ref($settings->{$key}) eq 'HASH') { 7518: foreach my $type (@types) { 7519: if (ref($settings->{$key}->{$type}) eq 'HASH') { 7520: $current{$type} = $settings->{$key}->{$type}->{$row}; 7521: } 7522: if (($row eq 'limit') && ($key eq 'default')) { 7523: if (ref($settings->{$key}->{$type}) eq 'HASH') { 7524: $currentcap{$type} = $settings->{$key}->{$type}->{'cap'}; 7525: } 7526: } 7527: } 7528: } 7529: } 7530: my %roles = ( 7531: '0' => &Apache::lonnet::plaintext('dc'), 7532: ); 7533: 7534: foreach my $type (@types) { 7535: unless (($row eq 'registered') && ($key eq 'default')) { 7536: $datatable .= '<th>'.&mt($type).'</th>'; 7537: } 7538: } 7539: unless (($row eq 'registered') && ($key eq 'default')) { 7540: $datatable .= '</tr><tr>'; 7541: } 7542: foreach my $type (@types) { 7543: if ($type eq 'community') { 7544: $roles{'1'} = &mt('Community personnel'); 7545: } else { 7546: $roles{'1'} = &mt('Course personnel'); 7547: } 7548: $datatable .= '<td style="vertical-align: top">'; 7549: if ($position eq 'top') { 7550: my %checked; 7551: if ($current{$type} eq '0') { 7552: $checked{'0'} = ' checked="checked"'; 7553: } else { 7554: $checked{'1'} = ' checked="checked"'; 7555: } 7556: foreach my $role ('1','0') { 7557: $datatable .= '<span class="LC_nobreak"><label>'. 7558: '<input type="radio" name="selfenrolladmin_'.$row.'_'.$type.'" '. 7559: 'value="'.$role.'"'.$checked{$role}.' />'. 7560: $roles{$role}.'</label></span> '; 7561: } 7562: } else { 7563: if ($row eq 'types') { 7564: my %checked; 7565: if ($current{$type} =~ /^(all|dom)$/) { 7566: $checked{$1} = ' checked="checked"'; 7567: } else { 7568: $checked{''} = ' checked="checked"'; 7569: } 7570: foreach my $val ('','dom','all') { 7571: $datatable .= '<span class="LC_nobreak"><label>'. 7572: '<input type ="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '. 7573: 'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> '; 7574: } 7575: } elsif ($row eq 'registered') { 7576: my %checked; 7577: if ($current{$type} eq '1') { 7578: $checked{'1'} = ' checked="checked"'; 7579: } else { 7580: $checked{'0'} = ' checked="checked"'; 7581: } 7582: foreach my $val ('0','1') { 7583: $datatable .= '<span class="LC_nobreak"><label>'. 7584: '<input type ="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '. 7585: 'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> '; 7586: } 7587: } elsif ($row eq 'approval') { 7588: my %checked; 7589: if ($current{$type} =~ /^([12])$/) { 7590: $checked{$1} = ' checked="checked"'; 7591: } else { 7592: $checked{'0'} = ' checked="checked"'; 7593: } 7594: for my $val (0..2) { 7595: $datatable .= '<span class="LC_nobreak"><label>'. 7596: '<input type="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '. 7597: 'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> '; 7598: } 7599: } elsif ($row eq 'limit') { 7600: my %checked; 7601: if ($current{$type} =~ /^(allstudents|selfenrolled)$/) { 7602: $checked{$1} = ' checked="checked"'; 7603: } else { 7604: $checked{'none'} = ' checked="checked"'; 7605: } 7606: my $cap; 7607: if ($currentcap{$type} =~ /^\d+$/) { 7608: $cap = $currentcap{$type}; 7609: } 7610: foreach my $val ('none','allstudents','selfenrolled') { 7611: $datatable .= '<span class="LC_nobreak"><label>'. 7612: '<input type="radio" name="selfenrolldefault_'.$row.'_'.$type.'" '. 7613: 'value="'.$val.'"'.$checked{$val}.' />'.$descs{$row}{$val}.'</label></span> '; 7614: } 7615: $datatable .= '<br />'. 7616: '<span class="LC_nobreak">'.&mt('Maximum allowed: '). 7617: '<input type="text" name="selfenrolldefault_cap_'.$type.'" size = "5" value="'.$cap.'" />'. 7618: '</span>'; 7619: } 7620: } 7621: $datatable .= '</td>'; 7622: } 7623: $datatable .= '</tr>'; 7624: } 7625: $datatable .= '</table></td></tr>'; 7626: } 7627: } elsif ($position eq 'bottom') { 7628: $datatable .= &print_validation_rows('selfenroll',$dom,$settings,\$itemcount); 7629: } 7630: $$rowtotal += $itemcount; 7631: return $datatable; 7632: } 7633: 7634: sub print_validation_rows { 7635: my ($caller,$dom,$settings,$rowtotal) = @_; 7636: my ($itemsref,$namesref,$fieldsref); 7637: if ($caller eq 'selfenroll') { 7638: ($itemsref,$namesref,$fieldsref) = &Apache::lonuserutils::selfenroll_validation_types(); 7639: } elsif ($caller eq 'requestcourses') { 7640: ($itemsref,$namesref,$fieldsref) = &Apache::loncoursequeueadmin::requestcourses_validation_types(); 7641: } 7642: my %currvalidation; 7643: if (ref($settings) eq 'HASH') { 7644: if (ref($settings->{'validation'}) eq 'HASH') { 7645: %currvalidation = %{$settings->{'validation'}}; 7646: } 7647: } 7648: my $datatable; 7649: my $itemcount = 0; 7650: foreach my $item (@{$itemsref}) { 7651: my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 7652: $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'. 7653: $namesref->{$item}. 7654: '</span></td>'. 7655: '<td class="LC_left_item">'; 7656: if (($item eq 'url') || ($item eq 'button')) { 7657: $datatable .= '<span class="LC_nobreak">'. 7658: '<input type="text" name="'.$caller.'_validation_'.$item.'"'. 7659: ' value="'.$currvalidation{$item}.'" size="50" /></span>'; 7660: } elsif ($item eq 'fields') { 7661: my @currfields; 7662: if (ref($currvalidation{$item}) eq 'ARRAY') { 7663: @currfields = @{$currvalidation{$item}}; 7664: } 7665: foreach my $field (@{$fieldsref}) { 7666: my $check = ''; 7667: if (grep(/^\Q$field\E$/,@currfields)) { 7668: $check = ' checked="checked"'; 7669: } 7670: $datatable .= '<span class="LC_nobreak"><label>'. 7671: '<input type="checkbox" name="'.$caller.'_validation_fields"'. 7672: ' value="'.$field.'"'.$check.' />'.$field. 7673: '</label></span> '; 7674: } 7675: } elsif ($item eq 'markup') { 7676: $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5">'. 7677: $currvalidation{$item}. 7678: '</textarea>'; 7679: } 7680: $datatable .= '</td></tr>'."\n"; 7681: if (ref($rowtotal)) { 7682: $itemcount ++; 7683: } 7684: } 7685: if ($caller eq 'requestcourses') { 7686: my %currhash; 7687: if (ref($settings) eq 'HASH') { 7688: if (ref($settings->{'validation'}) eq 'HASH') { 7689: if ($settings->{'validation'}{'dc'} ne '') { 7690: $currhash{$settings->{'validation'}{'dc'}} = 1; 7691: } 7692: } 7693: } 7694: my $numinrow = 2; 7695: my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio', 7696: 'validationdc',%currhash); 7697: my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 7698: $datatable .= '<tr'.$css_class.'><td>'; 7699: if ($numdc > 1) { 7700: $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)'); 7701: } else { 7702: $datatable .= &mt('Course creation processed as: '); 7703: } 7704: $datatable .= '</td><td class="LC_left_item">'.$dctable.'</td></tr>'; 7705: $itemcount ++; 7706: } 7707: if (ref($rowtotal)) { 7708: $$rowtotal += $itemcount; 7709: } 7710: return $datatable; 7711: } 7712: 7713: sub print_privacy { 7714: my ($position,$dom,$settings,$rowtotal) = @_; 7715: my ($datatable,$css_class,$numinrow,@items,%names,$othertitle,$usertypes,$types); 7716: my $itemcount = 0; 7717: unless ($position eq 'top') { 7718: @items = ('domain','author','course','community'); 7719: %names = &Apache::lonlocal::texthash ( 7720: domain => 'Assigned domain role(s)', 7721: author => 'Assigned co-author role(s)', 7722: course => 'Assigned course role(s)', 7723: community => 'Assigned community role(s)', 7724: ); 7725: $numinrow = 4; 7726: ($othertitle,$usertypes,$types) = 7727: &Apache::loncommon::sorted_inst_types($dom); 7728: } 7729: if (($position eq 'top') || ($position eq 'middle')) { 7730: my (%by_ip,%by_location,@intdoms,@instdoms); 7731: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 7732: if ($position eq 'top') { 7733: my %curr; 7734: my @options = ('none','user','domain','auto'); 7735: my %titles = &Apache::lonlocal::texthash ( 7736: none => 'Not allowed', 7737: user => 'User authorizes', 7738: domain => 'DC authorizes', 7739: auto => 'Unrestricted', 7740: instdom => 'Other domain shares institution/provider', 7741: extdom => 'Other domain has different institution/provider', 7742: ); 7743: my %names = &Apache::lonlocal::texthash ( 7744: domain => 'Domain role', 7745: author => 'Co-author role', 7746: course => 'Course role', 7747: community => 'Community role', 7748: ); 7749: my $primary_id = &Apache::lonnet::domain($dom,'primary'); 7750: my $intdom = &Apache::lonnet::internet_dom($primary_id); 7751: foreach my $domtype ('instdom','extdom') { 7752: my (%checked,$skip); 7753: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7754: $datatable .= '<tr'.$css_class.'><td>'.$titles{$domtype}.'</td>'. 7755: '<td class="LC_left_item">'; 7756: if ($domtype eq 'instdom') { 7757: unless (@instdoms > 1) { 7758: $datatable .= &mt('Nothing to set, as no domains besides [_1] are hosted by [_2]',$dom,$intdom); 7759: $skip = 1; 7760: } 7761: } elsif ($domtype eq 'extdom') { 7762: if (keys(%by_location) == 0) { 7763: $datatable .= &mt('Nothing to set, as no other hosts besides [_1]',$intdom); 7764: $skip = 1; 7765: } 7766: } 7767: unless ($skip) { 7768: foreach my $roletype ('domain','author','course','community') { 7769: $checked{'auto'} = ' checked="checked"'; 7770: if (ref($settings) eq 'HASH') { 7771: if (ref($settings->{approval}) eq 'HASH') { 7772: if (ref($settings->{approval}->{$domtype}) eq 'HASH') { 7773: if ($settings->{approval}->{$domtype}->{$roletype}=~ /^(none|user|domain)$/) { 7774: $checked{$1} = ' checked="checked"'; 7775: $checked{'auto'} = ''; 7776: } 7777: } 7778: } 7779: } 7780: $datatable .= '<fieldset><legend>'.$names{$roletype}.'</legend>'; 7781: foreach my $option (@options) { 7782: $datatable .= '<span class="LC_nobreak"><label>'. 7783: '<input type="radio" name="privacy_approval_'.$domtype.'_'.$roletype.'" '. 7784: 'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}. 7785: '</label></span> '; 7786: } 7787: $datatable .= '</fieldset>'; 7788: } 7789: } 7790: $datatable .= '</td></tr>'; 7791: $itemcount ++; 7792: } 7793: } elsif ($position eq 'middle') { 7794: if ((@instdoms > 1) || (keys(%by_location) > 0)) { 7795: if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) { 7796: foreach my $item (@{$types}) { 7797: $datatable .= &modifiable_userdata_row('privacy','othdom_'.$item,$settings, 7798: $numinrow,$itemcount,'','','','','', 7799: '',$usertypes->{$item}); 7800: $itemcount ++; 7801: } 7802: } 7803: $datatable .= &modifiable_userdata_row('privacy','othdom_default',$settings, 7804: $numinrow,$itemcount,'','','','','', 7805: '',$othertitle); 7806: $itemcount ++; 7807: } else { 7808: my (@insttypes,%insttitles); 7809: if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) { 7810: @insttypes = @{$types}; 7811: %insttitles = %{$usertypes}; 7812: } 7813: foreach my $item (@insttypes,'default') { 7814: my $title; 7815: if ($item eq 'default') { 7816: $title = $othertitle; 7817: } else { 7818: $title = $insttitles{$item}; 7819: } 7820: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7821: $datatable .= '<tr'.$css_class.'>'. 7822: '<td class="LC_left_item">'.$title.'</td>'. 7823: '<td class="LC_left_item">'. 7824: &mt('Nothing to set here, as there are no other domains'). 7825: '</td></tr>'; 7826: $itemcount ++; 7827: } 7828: } 7829: } 7830: } else { 7831: my $prefix; 7832: if ($position eq 'lower') { 7833: $prefix = 'priv'; 7834: } else { 7835: $prefix = 'unpriv'; 7836: } 7837: foreach my $item (@items) { 7838: $datatable .= &modifiable_userdata_row('privacy',$prefix.'_'.$item,$settings, 7839: $numinrow,$itemcount,'','','','','', 7840: '',$names{$item}); 7841: $itemcount ++; 7842: } 7843: } 7844: if (ref($rowtotal)) { 7845: $$rowtotal += $itemcount; 7846: } 7847: return $datatable; 7848: } 7849: 7850: sub print_passwords { 7851: my ($position,$dom,$confname,$settings,$rowtotal) = @_; 7852: my ($datatable,$css_class); 7853: my $itemcount = 0; 7854: my %titles = &Apache::lonlocal::texthash ( 7855: captcha => '"Forgot Password" CAPTCHA validation', 7856: link => 'Reset link expiration (hours)', 7857: case => 'Case-sensitive usernames/e-mail', 7858: prelink => 'Information required (form 1)', 7859: postlink => 'Information required (form 2)', 7860: emailsrc => 'LON-CAPA e-mail address type(s)', 7861: customtext => 'Domain specific text (HTML)', 7862: intauth_cost => 'Encryption cost for bcrypt (positive integer)', 7863: intauth_check => 'Check bcrypt cost if authenticated', 7864: intauth_switch => 'Existing crypt-based switched to bcrypt on authentication', 7865: permanent => 'Permanent e-mail address', 7866: critical => 'Critical notification address', 7867: notify => 'Notification address', 7868: min => 'Minimum password length', 7869: max => 'Maximum password length', 7870: chars => 'Required characters', 7871: expire => 'Password expiration (days)', 7872: numsaved => 'Number of previous passwords to save and disallow reuse', 7873: ); 7874: if ($position eq 'top') { 7875: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 7876: my $shownlinklife = 2; 7877: my $prelink = 'both'; 7878: my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl); 7879: if (ref($settings) eq 'HASH') { 7880: if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) { 7881: $shownlinklife = $settings->{resetlink}; 7882: } 7883: if (ref($settings->{resetcase}) eq 'ARRAY') { 7884: map { $casesens{$_} = 1; } (@{$settings->{resetcase}}); 7885: } 7886: if ($settings->{resetprelink} =~ /^(both|either)$/) { 7887: $prelink = $settings->{resetprelink}; 7888: } 7889: if (ref($settings->{resetpostlink}) eq 'HASH') { 7890: %postlink = %{$settings->{resetpostlink}}; 7891: } 7892: if (ref($settings->{resetemail}) eq 'ARRAY') { 7893: map { $emailsrc{$_} = 1; } (@{$settings->{resetemail}}); 7894: } 7895: if ($settings->{resetremove}) { 7896: $nostdtext = 1; 7897: } 7898: if ($settings->{resetcustom}) { 7899: $customurl = $settings->{resetcustom}; 7900: } 7901: } else { 7902: if (ref($types) eq 'ARRAY') { 7903: foreach my $item (@{$types}) { 7904: $casesens{$item} = 1; 7905: $postlink{$item} = ['username','email']; 7906: } 7907: } 7908: $casesens{'default'} = 1; 7909: $postlink{'default'} = ['username','email']; 7910: $prelink = 'both'; 7911: %emailsrc = ( 7912: permanent => 1, 7913: critical => 1, 7914: notify => 1, 7915: ); 7916: } 7917: $datatable = &captcha_choice('passwords',$settings,$$rowtotal); 7918: $itemcount ++; 7919: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7920: $datatable .= '<tr'.$css_class.'><td>'.$titles{'link'}.'</td>'. 7921: '<td class="LC_left_item">'. 7922: '<input type="textbox" value="'.$shownlinklife.'" '. 7923: 'name="passwords_link" size="3" /></td></tr>'; 7924: $itemcount ++; 7925: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7926: $datatable .= '<tr'.$css_class.'><td>'.$titles{'case'}.'</td>'. 7927: '<td class="LC_left_item">'; 7928: if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) { 7929: foreach my $item (@{$types}) { 7930: my $checkedcase; 7931: if ($casesens{$item}) { 7932: $checkedcase = ' checked="checked"'; 7933: } 7934: $datatable .= '<span class="LC_nobreak"><label>'. 7935: '<input type="checkbox" name="passwords_case_sensitive" value="'. 7936: $item.'"'.$checkedcase.' />'.$usertypes->{$item}.'</label>'. 7937: '</span> '; 7938: } 7939: } 7940: my $checkedcase; 7941: if ($casesens{'default'}) { 7942: $checkedcase = ' checked="checked"'; 7943: } 7944: $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '. 7945: 'name="passwords_case_sensitive" value="default"'.$checkedcase.' />'. 7946: $othertitle.'</label></span></td>'; 7947: $itemcount ++; 7948: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7949: my %checkedpre = ( 7950: both => ' checked="checked"', 7951: either => '', 7952: ); 7953: if ($prelink eq 'either') { 7954: $checkedpre{either} = ' checked="checked"'; 7955: $checkedpre{both} = ''; 7956: } 7957: $datatable .= '<tr'.$css_class.'><td>'.$titles{'prelink'}.'</td>'. 7958: '<td class="LC_left_item"><span class="LC_nobreak">'. 7959: '<label><input type="radio" name="passwords_prelink" value="both"'.$checkedpre{'both'}.' />'. 7960: &mt('Both username and e-mail address').'</label></span> '. 7961: '<span class="LC_nobreak"><label>'. 7962: '<input type="radio" name="passwords_prelink" value="either"'.$checkedpre{'either'}.' />'. 7963: &mt('Either username or e-mail address').'</label></span></td></tr>'; 7964: $itemcount ++; 7965: $css_class = $itemcount%2?' class="LC_odd_row"':''; 7966: $datatable .= '<tr'.$css_class.'><td>'.$titles{'postlink'}.'</td>'. 7967: '<td class="LC_left_item">'; 7968: my %postlinked; 7969: if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) { 7970: foreach my $item (@{$types}) { 7971: undef(%postlinked); 7972: $datatable .= '<fieldset style="display: inline-block;">'. 7973: '<legend>'.$usertypes->{$item}.'</legend>'; 7974: if (ref($postlink{$item}) eq 'ARRAY') { 7975: map { $postlinked{$_} = 1; } (@{$postlink{$item}}); 7976: } 7977: foreach my $field ('email','username') { 7978: my $checked; 7979: if ($postlinked{$field}) { 7980: $checked = ' checked="checked"'; 7981: } 7982: $datatable .= '<span class="LC_nobreak"><label>'. 7983: '<input type="checkbox" name="passwords_postlink_'.$item.'" value="'. 7984: $field.'"'.$checked.' />'.$field.'</label>'. 7985: '<span> '; 7986: } 7987: $datatable .= '</fieldset>'; 7988: } 7989: } 7990: if (ref($postlink{'default'}) eq 'ARRAY') { 7991: map { $postlinked{$_} = 1; } (@{$postlink{'default'}}); 7992: } 7993: $datatable .= '<fieldset style="display: inline-block;">'. 7994: '<legend>'.$othertitle.'</legend>'; 7995: foreach my $field ('email','username') { 7996: my $checked; 7997: if ($postlinked{$field}) { 7998: $checked = ' checked="checked"'; 7999: } 8000: $datatable .= '<span class="LC_nobreak"><label>'. 8001: '<input type="checkbox" name="passwords_postlink_default" value="'. 8002: $field.'"'.$checked.' />'.$field.'</label>'. 8003: '<span> '; 8004: } 8005: $datatable .= '</fieldset></td></tr>'; 8006: $itemcount ++; 8007: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8008: $datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'. 8009: '<td class="LC_left_item">'; 8010: foreach my $type ('permanent','critical','notify') { 8011: my $checkedemail; 8012: if ($emailsrc{$type}) { 8013: $checkedemail = ' checked="checked"'; 8014: } 8015: $datatable .= '<span class="LC_nobreak"><label>'. 8016: '<input type="checkbox" name="passwords_emailsrc" value="'. 8017: $type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'. 8018: '<span> '; 8019: } 8020: $datatable .= '</td></tr>'; 8021: $itemcount ++; 8022: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8023: my $switchserver = &check_switchserver($dom,$confname); 8024: my ($showstd,$noshowstd); 8025: if ($nostdtext) { 8026: $noshowstd = ' checked="checked"'; 8027: } else { 8028: $showstd = ' checked="checked"'; 8029: } 8030: $datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'. 8031: '<td class="LC_left_item"><span class="LC_nobreak">'. 8032: &mt('Retain standard text:'). 8033: '<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'. 8034: &mt('Yes').'</label>'.' '. 8035: '<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'. 8036: &mt('No').'</label></span><br />'. 8037: '<span class="LC_fontsize_small">'. 8038: &mt('(If you use the same account ... reset a password from this page.)').'</span><br /><br />'. 8039: &mt('Include custom text:'); 8040: if ($customurl) { 8041: my $link = &Apache::loncommon::modal_link($customurl,&mt('custom text'),600,500, 8042: undef,undef,undef,undef,'background-color:#ffffff'); 8043: $datatable .= '<span class="LC_nobreak"> '.$link. 8044: '<label><input type="checkbox" name="passwords_custom_del"'. 8045: ' value="1" />'.&mt('Delete?').'</label></span>'. 8046: ' <span class="LC_nobreak"> '.&mt('Replace:').'</span>'; 8047: } 8048: if ($switchserver) { 8049: $datatable .= '<span class="LC_nobreak"> '.&mt('Upload to library server: [_1]',$switchserver).'</span>'; 8050: } else { 8051: $datatable .='<span class="LC_nobreak"> '. 8052: '<input type="file" name="passwords_customfile" /></span>'; 8053: } 8054: $datatable .= '</td></tr>'; 8055: } elsif ($position eq 'middle') { 8056: my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom); 8057: my @items = ('intauth_cost','intauth_check','intauth_switch'); 8058: my %defaults; 8059: if (ref($domconf{'defaults'}) eq 'HASH') { 8060: %defaults = %{$domconf{'defaults'}}; 8061: if ($defaults{'intauth_cost'} !~ /^\d+$/) { 8062: $defaults{'intauth_cost'} = 10; 8063: } 8064: if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) { 8065: $defaults{'intauth_check'} = 0; 8066: } 8067: if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) { 8068: $defaults{'intauth_switch'} = 0; 8069: } 8070: } else { 8071: %defaults = ( 8072: 'intauth_cost' => 10, 8073: 'intauth_check' => 0, 8074: 'intauth_switch' => 0, 8075: ); 8076: } 8077: foreach my $item (@items) { 8078: if ($itemcount%2) { 8079: $css_class = ''; 8080: } else { 8081: $css_class = ' class="LC_odd_row" '; 8082: } 8083: $datatable .= '<tr'.$css_class.'>'. 8084: '<td><span class="LC_nobreak">'.$titles{$item}. 8085: '</span></td><td class="LC_left_item" colspan="3">'; 8086: if ($item eq 'intauth_switch') { 8087: my @options = (0,1,2); 8088: my %optiondesc = &Apache::lonlocal::texthash ( 8089: 0 => 'No', 8090: 1 => 'Yes', 8091: 2 => 'Yes, and copy existing passwd file to passwd.bak file', 8092: ); 8093: $datatable .= '<table width="100%">'; 8094: foreach my $option (@options) { 8095: my $checked = ' '; 8096: if ($defaults{$item} eq $option) { 8097: $checked = ' checked="checked"'; 8098: } 8099: $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'. 8100: '<label><input type="radio" name="'.$item. 8101: '" value="'.$option.'"'.$checked.' />'. 8102: $optiondesc{$option}.'</label></span></td></tr>'; 8103: } 8104: $datatable .= '</table>'; 8105: } elsif ($item eq 'intauth_check') { 8106: my @options = (0,1,2); 8107: my %optiondesc = &Apache::lonlocal::texthash ( 8108: 0 => 'No', 8109: 1 => 'Yes, allow login then update passwd file using default cost (if higher)', 8110: 2 => 'Yes, disallow login if stored cost is less than domain default', 8111: ); 8112: $datatable .= '<table width="100%">'; 8113: foreach my $option (@options) { 8114: my $checked = ' '; 8115: my $onclick; 8116: if ($defaults{$item} eq $option) { 8117: $checked = ' checked="checked"'; 8118: } 8119: if ($option == 2) { 8120: $onclick = ' onclick="javascript:warnIntAuth(this);"'; 8121: } 8122: $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'. 8123: '<label><input type="radio" name="'.$item. 8124: '" value="'.$option.'"'.$checked.$onclick.' />'. 8125: $optiondesc{$option}.'</label></span></td></tr>'; 8126: } 8127: $datatable .= '</table>'; 8128: } else { 8129: $datatable .= '<input type="text" name="'.$item.'" value="'. 8130: $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />'; 8131: } 8132: $datatable .= '</td></tr>'; 8133: $itemcount ++; 8134: } 8135: } elsif ($position eq 'lower') { 8136: $datatable .= &password_rules('passwords',\$itemcount,$settings); 8137: } else { 8138: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 8139: my %ownerchg = ( 8140: by => {}, 8141: for => {}, 8142: ); 8143: my %ownertitles = &Apache::lonlocal::texthash ( 8144: by => 'Course owner status(es) allowed', 8145: for => 'Student status(es) allowed', 8146: ); 8147: if (ref($settings) eq 'HASH') { 8148: if (ref($settings->{crsownerchg}) eq 'HASH') { 8149: if (ref($settings->{crsownerchg}{'by'}) eq 'ARRAY') { 8150: map { $ownerchg{by}{$_} = 1; } (@{$settings->{crsownerchg}{'by'}}); 8151: } 8152: if (ref($settings->{crsownerchg}{'for'}) eq 'ARRAY') { 8153: map { $ownerchg{for}{$_} = 1; } (@{$settings->{crsownerchg}{'for'}}); 8154: } 8155: } 8156: } 8157: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8158: $datatable .= '<tr '.$css_class.'>'. 8159: '<td>'. 8160: &mt('Requirements').'<ul>'. 8161: '<li>'.&mt("Course 'type' is not a Community or Placement Test").'</li>'. 8162: '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'. 8163: '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'. 8164: '<li>'.&mt('User, course, and student share same domain').'</li>'. 8165: '</ul>'. 8166: '</td>'. 8167: '<td class="LC_left_item">'; 8168: foreach my $item ('by','for') { 8169: $datatable .= '<fieldset style="display: inline-block;">'. 8170: '<legend>'.$ownertitles{$item}.'</legend>'; 8171: if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) { 8172: foreach my $type (@{$types}) { 8173: my $checked; 8174: if ($ownerchg{$item}{$type}) { 8175: $checked = ' checked="checked"'; 8176: } 8177: $datatable .= '<span class="LC_nobreak"><label>'. 8178: '<input type="checkbox" name="passwords_crsowner_'.$item.'" value="'. 8179: $type.'"'.$checked.' />'.$usertypes->{$type}.'</label>'. 8180: '</span> '; 8181: } 8182: } 8183: my $checked; 8184: if ($ownerchg{$item}{'default'}) { 8185: $checked = ' checked="checked"'; 8186: } 8187: $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '. 8188: 'name="passwords_crsowner_'.$item.'" value="default"'.$checked.' />'. 8189: $othertitle.'</label></span></fieldset>'; 8190: } 8191: $datatable .= '</td></tr>'; 8192: } 8193: return $datatable; 8194: } 8195: 8196: sub password_rules { 8197: my ($prefix,$itemcountref,$settings) = @_; 8198: my ($min,$max,%chars,$expire,$numsaved,$numinrow); 8199: my %titles; 8200: if ($prefix eq 'passwords') { 8201: %titles = &Apache::lonlocal::texthash ( 8202: min => 'Minimum password length', 8203: max => 'Maximum password length', 8204: chars => 'Required characters', 8205: ); 8206: } elsif ($prefix eq 'secrets') { 8207: %titles = &Apache::lonlocal::texthash ( 8208: min => 'Minimum secret length', 8209: max => 'Maximum secret length', 8210: chars => 'Required characters', 8211: ); 8212: } 8213: $min = $Apache::lonnet::passwdmin; 8214: my $datatable; 8215: my $itemcount; 8216: if (ref($itemcountref)) { 8217: $itemcount = $$itemcountref; 8218: } 8219: if (ref($settings) eq 'HASH') { 8220: if ($settings->{min}) { 8221: $min = $settings->{min}; 8222: } 8223: if ($settings->{max}) { 8224: $max = $settings->{max}; 8225: } 8226: if (ref($settings->{chars}) eq 'ARRAY') { 8227: map { $chars{$_} = 1; } (@{$settings->{chars}}); 8228: } 8229: if ($prefix eq 'passwords') { 8230: if ($settings->{expire}) { 8231: $expire = $settings->{expire}; 8232: } 8233: if ($settings->{numsaved}) { 8234: $numsaved = $settings->{numsaved}; 8235: } 8236: } 8237: } 8238: my %rulenames = &Apache::lonlocal::texthash( 8239: uc => 'At least one upper case letter', 8240: lc => 'At least one lower case letter', 8241: num => 'At least one number', 8242: spec => 'At least one non-alphanumeric', 8243: ); 8244: my $css_class = $itemcount%2?' class="LC_odd_row"':''; 8245: $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'. 8246: '<td class="LC_left_item"><span class="LC_nobreak">'. 8247: '<input type="text" name="'.$prefix.'_min" value="'.$min.'" size="3" '. 8248: 'onblur="javascript:warnInt'.$prefix.'(this);" />'. 8249: '<span class="LC_fontsize_small"> '.&mt('(Enter an integer: 7 or larger)').'</span>'. 8250: '</span></td></tr>'; 8251: $itemcount ++; 8252: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8253: $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'. 8254: '<td class="LC_left_item"><span class="LC_nobreak">'. 8255: '<input type="text" name="'.$prefix.'_max" value="'.$max.'" size="3" '. 8256: 'onblur="javascript:warnInt'.$prefix.'(this);" />'. 8257: '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'. 8258: '</span></td></tr>'; 8259: $itemcount ++; 8260: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8261: $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'. 8262: '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)'). 8263: '</span></td>'; 8264: my $numinrow = 2; 8265: my @possrules = ('uc','lc','num','spec'); 8266: $datatable .= '<td class="LC_left_item"><table>'; 8267: for (my $i=0; $i<@possrules; $i++) { 8268: my ($rem,$checked); 8269: if ($chars{$possrules[$i]}) { 8270: $checked = ' checked="checked"'; 8271: } 8272: $rem = $i%($numinrow); 8273: if ($rem == 0) { 8274: if ($i > 0) { 8275: $datatable .= '</tr>'; 8276: } 8277: $datatable .= '<tr>'; 8278: } 8279: $datatable .= '<td><span class="LC_nobreak"><label>'. 8280: '<input type="checkbox" name="'.$prefix.'_chars" value="'.$possrules[$i].'"'.$checked.' />'. 8281: $rulenames{$possrules[$i]}.'</label></span></td>'; 8282: } 8283: my $rem = @possrules%($numinrow); 8284: my $colsleft = $numinrow - $rem; 8285: if ($colsleft > 1 ) { 8286: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 8287: ' </td>'; 8288: } elsif ($colsleft == 1) { 8289: $datatable .= '<td class="LC_left_item"> </td>'; 8290: } 8291: $datatable .='</table></td></tr>'; 8292: $itemcount ++; 8293: if ($prefix eq 'passwords') { 8294: $titles{'expire'} = &mt('Password expiration (days)'); 8295: $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse'); 8296: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8297: $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'. 8298: '<td class="LC_left_item"><span class="LC_nobreak">'. 8299: '<input type="text" name="'.$prefix.'_expire" value="'.$expire.'" size="4" '. 8300: 'onblur="javascript:warnInt'.$prefix.'(this);" />'. 8301: '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'. 8302: '</span></td></tr>'; 8303: $itemcount ++; 8304: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8305: $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'. 8306: '<td class="LC_left_item"><span class="LC_nobreak">'. 8307: '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '. 8308: 'onblur="javascript:warnInt'.$prefix.'(this);" />'. 8309: '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'. 8310: '</span></td></tr>'; 8311: $itemcount ++; 8312: } 8313: if (ref($itemcountref)) { 8314: $$itemcountref += $itemcount; 8315: } 8316: return $datatable; 8317: } 8318: 8319: sub print_wafproxy { 8320: my ($position,$dom,$settings,$rowtotal) = @_; 8321: my $css_class; 8322: my $itemcount = 0; 8323: my $datatable; 8324: my %servers = &Apache::lonnet::internet_dom_servers($dom); 8325: my (%othercontrol,%otherdoms,%aliases,%saml,%values,$setdom,$showdom); 8326: my %lt = &wafproxy_titles(); 8327: foreach my $server (sort(keys(%servers))) { 8328: my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server}); 8329: next if ($serverhome eq ''); 8330: my $serverdom; 8331: if ($serverhome ne $server) { 8332: $serverdom = &Apache::lonnet::host_domain($serverhome); 8333: if (($serverdom ne '') && (&Apache::lonnet::domain($serverdom) ne '')) { 8334: $othercontrol{$server} = $serverdom; 8335: } 8336: } else { 8337: $serverdom = &Apache::lonnet::host_domain($server); 8338: next if (($serverdom eq '') || (&Apache::lonnet::domain($serverdom) eq '')); 8339: if ($serverdom ne $dom) { 8340: $othercontrol{$server} = $serverdom; 8341: } else { 8342: $setdom = 1; 8343: if (ref($settings) eq 'HASH') { 8344: if (ref($settings->{'alias'}) eq 'HASH') { 8345: $aliases{$dom} = $settings->{'alias'}; 8346: if ($aliases{$dom} ne '') { 8347: $showdom = 1; 8348: } 8349: } 8350: if (ref($settings->{'saml'}) eq 'HASH') { 8351: $saml{$dom} = $settings->{'saml'}; 8352: } 8353: } 8354: } 8355: } 8356: } 8357: if ($setdom) { 8358: %{$values{$dom}} = (); 8359: if (ref($settings) eq 'HASH') { 8360: foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') { 8361: $values{$dom}{$item} = $settings->{$item}; 8362: } 8363: } 8364: } 8365: if (keys(%othercontrol)) { 8366: %otherdoms = reverse(%othercontrol); 8367: foreach my $domain (keys(%otherdoms)) { 8368: %{$values{$domain}} = (); 8369: my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain); 8370: if (ref($config{'wafproxy'}) eq 'HASH') { 8371: $aliases{$domain} = $config{'wafproxy'}{'alias'}; 8372: if (exists($config{'wafproxy'}{'saml'})) { 8373: $saml{$domain} = $config{'wafproxy'}{'saml'}; 8374: } 8375: foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') { 8376: $values{$domain}{$item} = $config{'wafproxy'}{$item}; 8377: } 8378: } 8379: } 8380: } 8381: if ($position eq 'top') { 8382: my %servers = &Apache::lonnet::internet_dom_servers($dom); 8383: my %aliasinfo; 8384: foreach my $server (sort(keys(%servers))) { 8385: $itemcount ++; 8386: my $dom_in_effect; 8387: my $aliasrows = '<tr>'. 8388: '<td class="LC_left_item" style="vertical-align: baseline;">'. 8389: &mt('Hostname').': '. 8390: '<i>'.&Apache::lonnet::hostname($server).'</i></td><td> </td>'; 8391: if ($othercontrol{$server}) { 8392: $dom_in_effect = $othercontrol{$server}; 8393: my ($current,$forsaml); 8394: if (ref($aliases{$dom_in_effect}) eq 'HASH') { 8395: $current = $aliases{$dom_in_effect}{$server}; 8396: } 8397: if (ref($saml{$dom_in_effect}) eq 'HASH') { 8398: if ($saml{$dom_in_effect}{$server}) { 8399: $forsaml = 1; 8400: } 8401: } 8402: $aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'. 8403: &mt('Alias').': '; 8404: if ($current) { 8405: $aliasrows .= $current; 8406: if ($forsaml) { 8407: $aliasrows .= ' ('.&mt('also for SSO Auth').')'; 8408: } 8409: } else { 8410: $aliasrows .= &mt('None'); 8411: } 8412: $aliasrows .= ' <span class="LC_small">('. 8413: &mt('controlled by domain: [_1]', 8414: '<b>'.$dom_in_effect.'</b>').')</span></td>'; 8415: } else { 8416: $dom_in_effect = $dom; 8417: my ($current,$samlon,$samloff); 8418: $samloff = ' checked="checked"'; 8419: if (ref($aliases{$dom}) eq 'HASH') { 8420: if ($aliases{$dom}{$server}) { 8421: $current = $aliases{$dom}{$server}; 8422: } 8423: } 8424: if (ref($saml{$dom}) eq 'HASH') { 8425: if ($saml{$dom}{$server}) { 8426: $samlon = $samloff; 8427: undef($samloff); 8428: } 8429: } 8430: $aliasrows .= '<td class="LC_left_item" style="vertical-align: baseline;">'. 8431: &mt('Alias').': '. 8432: '<input type="text" name="wafproxy_alias_'.$server.'" '. 8433: 'value="'.$current.'" size="30" />'. 8434: (' 'x2).'<span class="LC_nobreak">'. 8435: &mt('Alias used for SSO Auth').': <label>'. 8436: '<input type="radio" value="0"'.$samloff.' name="wafproxy_alias_saml_'.$server.'" />'. 8437: &mt('No').'</label> <label>'. 8438: '<input type="radio" value="1"'.$samlon.' name="wafproxy_alias_saml_'.$server.'" />'. 8439: &mt('Yes').'</label></span>'. 8440: '</td>'; 8441: } 8442: $aliasrows .= '</tr>'; 8443: $aliasinfo{$dom_in_effect} .= $aliasrows; 8444: } 8445: if ($aliasinfo{$dom}) { 8446: my ($onclick,$wafon,$wafoff,$showtable); 8447: $onclick = ' onclick="javascript:toggleWAF();"'; 8448: $wafoff = ' checked="checked"'; 8449: $showtable = ' style="display:none";'; 8450: if ($showdom) { 8451: $wafon = $wafoff; 8452: $wafoff = ''; 8453: $showtable = ' style="display:inline;"'; 8454: } 8455: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 8456: $datatable = '<tr'.$css_class.'>'. 8457: '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br />'. 8458: '<span class="LC_nobreak">'.&mt('WAF in use?').' <label>'. 8459: '<input type="radio" name="wafproxy_'.$dom.'" value="1"'.$wafon.$onclick.' />'. 8460: &mt('Yes').'</label>'.(' 'x2).'<label>'. 8461: '<input type="radio" name="wafproxy_'.$dom.'" value="0"'.$wafoff.$onclick.' />'. 8462: &mt('No').'</label></span></td>'. 8463: '<td class="LC_left_item">'. 8464: '<table id="wafproxy_table"'.$showtable.'>'.$aliasinfo{$dom}. 8465: '</table></td></tr>'; 8466: $itemcount++; 8467: } 8468: if (keys(%otherdoms)) { 8469: foreach my $key (sort(keys(%otherdoms))) { 8470: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 8471: $datatable .= '<tr'.$css_class.'>'. 8472: '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$key.'</b>').'</td>'. 8473: '<td class="LC_left_item"><table>'.$aliasinfo{$key}. 8474: '</table></td></tr>'; 8475: $itemcount++; 8476: } 8477: } 8478: } else { 8479: my %ip_methods = &remoteip_methods(); 8480: if ($setdom) { 8481: $itemcount ++; 8482: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 8483: my ($nowafstyle,$wafstyle,$curr_remotip,$currwafdisplay,$vpndircheck,$vpnaliascheck, 8484: $currwafvpn,$wafrangestyle,$alltossl,$ssltossl); 8485: $wafstyle = ' style="display:none;"'; 8486: $nowafstyle = ' style="display:table-row;"'; 8487: $currwafdisplay = ' style="display: none"'; 8488: $wafrangestyle = ' style="display: none"'; 8489: $curr_remotip = 'n'; 8490: $ssltossl = ' checked="checked"'; 8491: if ($showdom) { 8492: $wafstyle = ' style="display:table-row;"'; 8493: $nowafstyle = ' style="display:none;"'; 8494: if (keys(%{$values{$dom}})) { 8495: if ($values{$dom}{remoteip} =~ /^[nmh]$/) { 8496: $curr_remotip = $values{$dom}{remoteip}; 8497: } 8498: if ($curr_remotip eq 'h') { 8499: $currwafdisplay = ' style="display:table-row"'; 8500: $wafrangestyle = ' style="display:inline-block;"'; 8501: } 8502: if ($values{$dom}{'sslopt'}) { 8503: $alltossl = ' checked="checked"'; 8504: $ssltossl = ''; 8505: } 8506: } 8507: if (($values{$dom}{'vpnint'} ne '') || ($values{$dom}{'vpnext'} ne '')) { 8508: $vpndircheck = ' checked="checked"'; 8509: $currwafvpn = ' style="display:table-row;"'; 8510: $wafrangestyle = ' style="display:inline-block;"'; 8511: } else { 8512: $vpnaliascheck = ' checked="checked"'; 8513: $currwafvpn = ' style="display:none;"'; 8514: } 8515: } 8516: $datatable .= '<tr'.$css_class.' id="nowafproxyrow_'.$dom.'"'.$wafstyle.'>'. 8517: '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'</td>'. 8518: '<td class="LC_right_item">'.&mt('WAF not in use, nothing to set').'</td>'. 8519: '</tr>'. 8520: '<tr'.$css_class.' id="wafproxyrow_'.$dom.'"'.$wafstyle.'>'. 8521: '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$dom.'</b>').'<br /><br />'. 8522: '<div id="wafproxyranges_'.$dom.'">'.&mt('Format for comma separated IP ranges').':<br />'. 8523: &mt('A.B.C.D/N or A.B.C.D-E.F.G.H').'<br />'. 8524: &mt('Range(s) stored in CIDR notation').'</div></td>'. 8525: '<td class="LC_left_item"><table>'. 8526: '<tr>'. 8527: '<td valign="top">'.$lt{'remoteip'}.': '. 8528: '<select name="wafproxy_remoteip" id="wafproxy_remoteip" onchange="javascript:updateWAF();">'; 8529: foreach my $option ('m','h','n') { 8530: my $sel; 8531: if ($option eq $curr_remotip) { 8532: $sel = ' selected="selected"'; 8533: } 8534: $datatable .= '<option value="'.$option.'"'.$sel.'>'. 8535: $ip_methods{$option}.'</option>'; 8536: } 8537: $datatable .= '</select></td></tr>'."\n". 8538: '<tr id="wafproxy_header"'.$currwafdisplay.'><td>'. 8539: $lt{'ipheader'}.': '. 8540: '<input type="text" value="'.$values{$dom}{'ipheader'}.'" '. 8541: 'name="wafproxy_ipheader" />'. 8542: '</td></tr>'."\n". 8543: '<tr id="wafproxy_trust"'.$currwafdisplay.'><td>'. 8544: $lt{'trusted'}.':<br />'. 8545: '<textarea name="wafproxy_trusted" rows="3" cols="80">'. 8546: $values{$dom}{'trusted'}.'</textarea>'. 8547: '</td></tr>'."\n". 8548: '<tr><td><hr /></td></tr>'."\n". 8549: '<tr>'. 8550: '<td valign="top">'.$lt{'vpnaccess'}.':<br /><span class="LC_nobreak">'. 8551: '<label><input type="radio" name="wafproxy_vpnaccess"'.$vpndircheck.' value="1" onclick="javascript:checkWAF();" />'. 8552: $lt{'vpndirect'}.'</label>'.(' 'x2). 8553: '<label><input type="radio" name="wafproxy_vpnaccess"'.$vpnaliascheck.' value="0" onclick="javascript:checkWAF();" />'. 8554: $lt{'vpnaliased'}.'</label></span></td></tr>'; 8555: foreach my $item ('vpnint','vpnext') { 8556: $datatable .= '<tr id="wafproxy_show_'.$item.'"'.$currwafvpn.'>'. 8557: '<td valign="top">'.$lt{$item}.':<br />'. 8558: '<textarea name="wafproxy_'.$item.'" rows="3" cols="80">'. 8559: $values{$dom}{$item}.'</textarea>'. 8560: '</td></tr>'."\n"; 8561: } 8562: $datatable .= '<tr><td><hr /></td></tr>'."\n". 8563: '<tr>'. 8564: '<td valign="top">'.$lt{'sslopt'}.':<br /><span class="LC_nobreak">'. 8565: '<label><input type="radio" name="wafproxy_sslopt"'.$alltossl.' value="1" />'. 8566: $lt{'alltossl'}.'</label>'.(' 'x2). 8567: '<label><input type="radio" name="wafproxy_sslopt"'.$ssltossl.' value="0" />'. 8568: $lt{'ssltossl'}.'</label></span></td></tr>'."\n". 8569: '</table></td></tr>'; 8570: } 8571: if (keys(%otherdoms)) { 8572: foreach my $domain (sort(keys(%otherdoms))) { 8573: $itemcount ++; 8574: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 8575: $datatable .= '<tr'.$css_class.'>'. 8576: '<td class="LC_left_item">'.&mt('Domain: [_1]','<b>'.$domain.'</b>').'</td>'. 8577: '<td class="LC_left_item"><table>'; 8578: foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') { 8579: my $showval = &mt('None'); 8580: if ($item eq 'ssl') { 8581: $showval = $lt{'ssltossl'}; 8582: } 8583: if ($values{$domain}{$item}) { 8584: $showval = $values{$domain}{$item}; 8585: if ($item eq 'ssl') { 8586: $showval = $lt{'alltossl'}; 8587: } elsif ($item eq 'remoteip') { 8588: $showval = $ip_methods{$values{$domain}{$item}}; 8589: } 8590: } 8591: $datatable .= '<tr>'. 8592: '<td>'.$lt{$item}.': '.$showval.'</td></tr>'; 8593: } 8594: $datatable .= '</table></td></tr>'; 8595: } 8596: } 8597: } 8598: $$rowtotal += $itemcount; 8599: return $datatable; 8600: } 8601: 8602: sub wafproxy_titles { 8603: return &Apache::lonlocal::texthash( 8604: remoteip => "Method for determining user's IP", 8605: ipheader => 'Request header containing remote IP', 8606: trusted => 'Trusted IP range(s)', 8607: vpnaccess => 'Access from institutional VPN', 8608: vpndirect => 'via regular hostname (no WAF)', 8609: vpnaliased => 'via aliased hostname (WAF)', 8610: vpnint => 'Internal IP Range(s) for VPN sessions', 8611: vpnext => 'IP Range(s) for backend WAF connections', 8612: sslopt => 'Forwarding http/https', 8613: alltossl => 'WAF forwards both http and https requests to https', 8614: ssltossl => 'WAF forwards http requests to http and https to https', 8615: ); 8616: } 8617: 8618: sub remoteip_methods { 8619: return &Apache::lonlocal::texthash( 8620: m => 'Use Apache mod_remoteip', 8621: h => 'Use headers parsed by LON-CAPA', 8622: n => 'Not in use', 8623: ); 8624: } 8625: 8626: sub print_usersessions { 8627: my ($position,$dom,$settings,$rowtotal) = @_; 8628: my ($css_class,$datatable,$itemcount,%checked,%choices); 8629: my (%by_ip,%by_location,@intdoms,@instdoms); 8630: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 8631: 8632: my @alldoms = &Apache::lonnet::all_domains(); 8633: my %serverhomes = %Apache::lonnet::serverhomeIDs; 8634: my %servers = &Apache::lonnet::internet_dom_servers($dom); 8635: my %altids = &id_for_thisdom(%servers); 8636: if ($position eq 'top') { 8637: if (keys(%serverhomes) > 1) { 8638: my %spareid = ¤t_offloads_to($dom,$settings,\%servers); 8639: my ($curroffloadnow,$curroffloadoth); 8640: if (ref($settings) eq 'HASH') { 8641: if (ref($settings->{'offloadnow'}) eq 'HASH') { 8642: $curroffloadnow = $settings->{'offloadnow'}; 8643: } 8644: if (ref($settings->{'offloadoth'}) eq 'HASH') { 8645: $curroffloadoth = $settings->{'offloadoth'}; 8646: } 8647: } 8648: my $other_insts = scalar(keys(%by_location)); 8649: $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids, 8650: $other_insts,$curroffloadnow,$curroffloadoth,$rowtotal); 8651: } else { 8652: $datatable .= '<tr'.$css_class.'><td colspan="2">'. 8653: &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.'). 8654: '</td></tr>'; 8655: } 8656: } else { 8657: my %titles = &usersession_titles(); 8658: my ($prefix,@types); 8659: if ($position eq 'bottom') { 8660: $prefix = 'remote'; 8661: @types = ('version','excludedomain','includedomain'); 8662: } else { 8663: $prefix = 'hosted'; 8664: @types = ('excludedomain','includedomain'); 8665: } 8666: ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles); 8667: } 8668: $$rowtotal += $itemcount; 8669: return $datatable; 8670: } 8671: 8672: sub rules_by_location { 8673: my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_; 8674: my ($datatable,$itemcount,$css_class); 8675: if (keys(%{$by_location}) == 0) { 8676: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 8677: $datatable = '<tr'.$css_class.'><td colspan="2">'. 8678: &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.'). 8679: '</td></tr>'; 8680: $itemcount = 1; 8681: } else { 8682: $itemcount = 0; 8683: my $numinrow = 5; 8684: my (%current,%checkedon,%checkedoff); 8685: my @locations = sort(keys(%{$by_location})); 8686: foreach my $type (@{$types}) { 8687: $checkedon{$type} = ''; 8688: $checkedoff{$type} = ' checked="checked"'; 8689: } 8690: if (ref($settings) eq 'HASH') { 8691: if (ref($settings->{$prefix}) eq 'HASH') { 8692: foreach my $key (keys(%{$settings->{$prefix}})) { 8693: $current{$key} = $settings->{$prefix}{$key}; 8694: if ($key eq 'version') { 8695: if ($current{$key} ne '') { 8696: $checkedon{$key} = ' checked="checked"'; 8697: $checkedoff{$key} = ''; 8698: } 8699: } elsif (ref($current{$key}) eq 'ARRAY') { 8700: $checkedon{$key} = ' checked="checked"'; 8701: $checkedoff{$key} = ''; 8702: } 8703: } 8704: } 8705: } 8706: foreach my $type (@{$types}) { 8707: next if ($type ne 'version' && !@locations); 8708: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 8709: $datatable .= '<tr'.$css_class.'> 8710: <td><span class="LC_nobreak">'.$titles->{$type}.'</span><br /> 8711: <span class="LC_nobreak"> 8712: <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label> 8713: <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>'; 8714: if ($type eq 'version') { 8715: my @lcversions = &Apache::lonnet::all_loncaparevs(); 8716: my $selector = '<select name="'.$prefix.'_version">'; 8717: foreach my $version (@lcversions) { 8718: my $selected = ''; 8719: if ($current{'version'} eq $version) { 8720: $selected = ' selected="selected"'; 8721: } 8722: $selector .= ' <option value="'.$version.'"'. 8723: $selected.'>'.$version.'</option>'; 8724: } 8725: $selector .= '</select> '; 8726: $datatable .= &mt('remote server must be version: [_1] or later',$selector); 8727: } else { 8728: $datatable.= '<div><input type="button" value="'.&mt('check all').'" '. 8729: 'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'. 8730: ' />'.(' 'x2). 8731: '<input type="button" value="'.&mt('uncheck all').'" '. 8732: 'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'. 8733: "\n". 8734: '</div><div><table>'; 8735: my $rem; 8736: for (my $i=0; $i<@locations; $i++) { 8737: my ($showloc,$value,$checkedtype); 8738: if (ref($by_location->{$locations[$i]}) eq 'ARRAY') { 8739: my $ip = $by_location->{$locations[$i]}->[0]; 8740: if (ref($by_ip->{$ip}) eq 'ARRAY') { 8741: $value = join(':',@{$by_ip->{$ip}}); 8742: $showloc = join(', ',@{$by_ip->{$ip}}); 8743: if (ref($current{$type}) eq 'ARRAY') { 8744: foreach my $loc (@{$by_ip->{$ip}}) { 8745: if (grep(/^\Q$loc\E$/,@{$current{$type}})) { 8746: $checkedtype = ' checked="checked"'; 8747: last; 8748: } 8749: } 8750: } 8751: } 8752: } 8753: $rem = $i%($numinrow); 8754: if ($rem == 0) { 8755: if ($i > 0) { 8756: $datatable .= '</tr>'; 8757: } 8758: $datatable .= '<tr>'; 8759: } 8760: $datatable .= '<td class="LC_left_item">'. 8761: '<span class="LC_nobreak"><label>'. 8762: '<input type="checkbox" name="'.$prefix.'_'.$type. 8763: '" value="'.$value.'"'.$checkedtype.' />'.$showloc. 8764: '</label></span></td>'; 8765: } 8766: $rem = @locations%($numinrow); 8767: my $colsleft = $numinrow - $rem; 8768: if ($colsleft > 1 ) { 8769: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 8770: ' </td>'; 8771: } elsif ($colsleft == 1) { 8772: $datatable .= '<td class="LC_left_item"> </td>'; 8773: } 8774: $datatable .= '</tr></table>'; 8775: } 8776: $datatable .= '</td></tr>'; 8777: $itemcount ++; 8778: } 8779: } 8780: return ($datatable,$itemcount); 8781: } 8782: 8783: sub print_ssl { 8784: my ($position,$dom,$settings,$rowtotal) = @_; 8785: my ($css_class,$datatable); 8786: my $itemcount = 1; 8787: if ($position eq 'top') { 8788: my $primary_id = &Apache::lonnet::domain($dom,'primary'); 8789: my $intdom = &Apache::lonnet::internet_dom($primary_id); 8790: my $same_institution; 8791: if ($intdom ne '') { 8792: my $internet_names = &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'}); 8793: if (ref($internet_names) eq 'ARRAY') { 8794: if (grep(/^\Q$intdom\E$/,@{$internet_names})) { 8795: $same_institution = 1; 8796: } 8797: } 8798: } 8799: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8800: $datatable = '<tr'.$css_class.'><td colspan="2">'; 8801: if ($same_institution) { 8802: my %domservers = &Apache::lonnet::get_servers($dom); 8803: $datatable .= &LONCAPA::SSL::print_certstatus(\%domservers,'web','domprefs'); 8804: } else { 8805: $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."); 8806: } 8807: $datatable .= '</td></tr>'; 8808: $itemcount ++; 8809: } else { 8810: my %titles = &ssl_titles(); 8811: my (%by_ip,%by_location,@intdoms,@instdoms); 8812: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 8813: my @alldoms = &Apache::lonnet::all_domains(); 8814: my %serverhomes = %Apache::lonnet::serverhomeIDs; 8815: my @domservers = &Apache::lonnet::get_servers($dom); 8816: my %servers = &Apache::lonnet::internet_dom_servers($dom); 8817: my %altids = &id_for_thisdom(%servers); 8818: if (($position eq 'connto') || ($position eq 'connfrom')) { 8819: my $legacy; 8820: unless (ref($settings) eq 'HASH') { 8821: my $name; 8822: if ($position eq 'connto') { 8823: $name = 'loncAllowInsecure'; 8824: } else { 8825: $name = 'londAllowInsecure'; 8826: } 8827: my $primarylibserv = &Apache::lonnet::domain($dom,'primary'); 8828: my @ids=&Apache::lonnet::current_machine_ids(); 8829: if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) { 8830: my %what = ( 8831: $name => 1, 8832: ); 8833: my ($result,$returnhash) = 8834: &Apache::lonnet::get_remote_globals($primarylibserv,\%what); 8835: if ($result eq 'ok') { 8836: if (ref($returnhash) eq 'HASH') { 8837: $legacy = $returnhash->{$name}; 8838: } 8839: } 8840: } else { 8841: $legacy = $Apache::lonnet::perlvar{$name}; 8842: } 8843: } 8844: foreach my $type ('dom','intdom','other') { 8845: my %checked; 8846: $css_class = $itemcount%2?' class="LC_odd_row"':''; 8847: $datatable .= '<tr'.$css_class.'><td>'.$titles{$type}.'</td>'. 8848: '<td class="LC_right_item">'; 8849: my $skip; 8850: if ($type eq 'dom') { 8851: unless (keys(%servers) > 1) { 8852: $datatable .= &mt('Nothing to set here, as there are no other servers/VMs'); 8853: $skip = 1; 8854: } 8855: } 8856: if ($type eq 'intdom') { 8857: unless (@instdoms > 1) { 8858: $datatable .= &mt('Nothing to set here, as there are no other domains for this institution'); 8859: $skip = 1; 8860: } 8861: } elsif ($type eq 'other') { 8862: if (keys(%by_location) == 0) { 8863: $datatable .= &mt('Nothing to set here, as there are no other institutions'); 8864: $skip = 1; 8865: } 8866: } 8867: unless ($skip) { 8868: $checked{'yes'} = ' checked="checked"'; 8869: if (ref($settings) eq 'HASH') { 8870: if (ref($settings->{$position}) eq 'HASH') { 8871: if ($settings->{$position}->{$type} =~ /^(no|req)$/) { 8872: $checked{$1} = $checked{'yes'}; 8873: delete($checked{'yes'}); 8874: } 8875: } 8876: } else { 8877: if ($legacy == 0) { 8878: $checked{'req'} = $checked{'yes'}; 8879: delete($checked{'yes'}); 8880: } 8881: } 8882: foreach my $option ('no','yes','req') { 8883: $datatable .= '<span class="LC_nobreak"><label>'. 8884: '<input type="radio" name="'.$position.'_'.$type.'" '. 8885: 'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}. 8886: '</label></span>'.(' 'x2); 8887: } 8888: } 8889: $datatable .= '</td></tr>'; 8890: $itemcount ++; 8891: } 8892: } else { 8893: my $prefix = 'replication'; 8894: my @types = ('certreq','nocertreq'); 8895: if (keys(%by_location) == 0) { 8896: $datatable .= '<tr'.$css_class.'><td>'. 8897: &mt('Nothing to set here, as there are no other institutions'). 8898: '</td></tr>'; 8899: $itemcount ++; 8900: } else { 8901: ($datatable,$itemcount) = 8902: &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles); 8903: } 8904: } 8905: } 8906: $$rowtotal += $itemcount; 8907: return $datatable; 8908: } 8909: 8910: sub ssl_titles { 8911: return &Apache::lonlocal::texthash ( 8912: dom => 'LON-CAPA servers/VMs from same domain', 8913: intdom => 'LON-CAPA servers/VMs from same "internet" domain', 8914: other => 'External LON-CAPA servers/VMs', 8915: connto => 'Connections to other servers', 8916: connfrom => 'Connections from other servers', 8917: replication => 'Replicating content to other institutions', 8918: certreq => 'Client certificate required, but specific domains exempt', 8919: nocertreq => 'No client certificate required, except for specific domains', 8920: no => 'SSL not used', 8921: yes => 'SSL Optional (used if available)', 8922: req => 'SSL Required', 8923: ); 8924: } 8925: 8926: sub print_trust { 8927: my ($prefix,$dom,$settings,$rowtotal) = @_; 8928: my ($css_class,$datatable,%checked,%choices); 8929: my (%by_ip,%by_location,@intdoms,@instdoms); 8930: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 8931: my $itemcount = 1; 8932: my %titles = &trust_titles(); 8933: my @types = ('exc','inc'); 8934: if ($prefix eq 'top') { 8935: $prefix = 'content'; 8936: } elsif ($prefix eq 'bottom') { 8937: $prefix = 'msg'; 8938: } 8939: ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles); 8940: $$rowtotal += $itemcount; 8941: return $datatable; 8942: } 8943: 8944: sub trust_titles { 8945: return &Apache::lonlocal::texthash( 8946: content => "Access to this domain's content by others", 8947: shared => "Access to other domain's content by this domain", 8948: enroll => "Enrollment in this domain's courses by others", 8949: othcoau => "Co-author roles in this domain for others", 8950: coaurem => "Co-author roles for this domain's users elsewhere", 8951: domroles => "Domain roles in this domain assignable to others", 8952: catalog => "Course Catalog for this domain displayed elsewhere", 8953: reqcrs => "Requests for creation of courses in this domain by others", 8954: msg => "Users in other domains can send messages to this domain", 8955: exc => "Allow all, but exclude specific domains", 8956: inc => "Deny all, but include specific domains", 8957: ); 8958: } 8959: 8960: sub build_location_hashes { 8961: my ($intdoms,$by_ip,$by_location,$instdoms) = @_; 8962: return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') && 8963: (ref($by_location) eq 'HASH') && (ref($instdoms) eq 'ARRAY')); 8964: my %iphost = &Apache::lonnet::get_iphost(); 8965: my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary'); 8966: my $primary_ip = &Apache::lonnet::get_host_ip($primary_id); 8967: if (ref($iphost{$primary_ip}) eq 'ARRAY') { 8968: foreach my $id (@{$iphost{$primary_ip}}) { 8969: my $intdom = &Apache::lonnet::internet_dom($id); 8970: unless(grep(/^\Q$intdom\E$/,@{$intdoms})) { 8971: push(@{$intdoms},$intdom); 8972: } 8973: } 8974: } 8975: foreach my $ip (keys(%iphost)) { 8976: if (ref($iphost{$ip}) eq 'ARRAY') { 8977: foreach my $id (@{$iphost{$ip}}) { 8978: my $location = &Apache::lonnet::internet_dom($id); 8979: if ($location) { 8980: if (grep(/^\Q$location\E$/,@{$intdoms})) { 8981: my $dom = &Apache::lonnet::host_domain($id); 8982: unless (grep(/^\Q$dom\E/,@{$instdoms})) { 8983: push(@{$instdoms},$dom); 8984: } 8985: next; 8986: } 8987: if (ref($by_ip->{$ip}) eq 'ARRAY') { 8988: unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) { 8989: push(@{$by_ip->{$ip}},$location); 8990: } 8991: } else { 8992: $by_ip->{$ip} = [$location]; 8993: } 8994: } 8995: } 8996: } 8997: } 8998: foreach my $ip (sort(keys(%{$by_ip}))) { 8999: if (ref($by_ip->{$ip}) eq 'ARRAY') { 9000: @{$by_ip->{$ip}} = sort(@{$by_ip->{$ip}}); 9001: my $first = $by_ip->{$ip}->[0]; 9002: if (ref($by_location->{$first}) eq 'ARRAY') { 9003: unless (grep(/^\Q$ip\E$/,@{$by_location->{$first}})) { 9004: push(@{$by_location->{$first}},$ip); 9005: } 9006: } else { 9007: $by_location->{$first} = [$ip]; 9008: } 9009: } 9010: } 9011: return; 9012: } 9013: 9014: sub current_offloads_to { 9015: my ($dom,$settings,$servers) = @_; 9016: my (%spareid,%otherdomconfigs); 9017: if (ref($servers) eq 'HASH') { 9018: foreach my $lonhost (sort(keys(%{$servers}))) { 9019: my $gotspares; 9020: if (ref($settings) eq 'HASH') { 9021: if (ref($settings->{'spares'}) eq 'HASH') { 9022: if (ref($settings->{'spares'}{$lonhost}) eq 'HASH') { 9023: $spareid{$lonhost}{'primary'} = $settings->{'spares'}{$lonhost}{'primary'}; 9024: $spareid{$lonhost}{'default'} = $settings->{'spares'}{$lonhost}{'default'}; 9025: $gotspares = 1; 9026: } 9027: } 9028: } 9029: unless ($gotspares) { 9030: my $gotspares; 9031: my $serverhomeID = 9032: &Apache::lonnet::get_server_homeID($servers->{$lonhost}); 9033: my $serverhomedom = 9034: &Apache::lonnet::host_domain($serverhomeID); 9035: if ($serverhomedom ne $dom) { 9036: if (ref($otherdomconfigs{$serverhomedom} eq 'HASH')) { 9037: if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') { 9038: if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') { 9039: $spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'}; 9040: $spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'}; 9041: $gotspares = 1; 9042: } 9043: } 9044: } else { 9045: $otherdomconfigs{$serverhomedom} = 9046: &Apache::lonnet::get_dom('configuration',['usersessions'],$serverhomedom); 9047: if (ref($otherdomconfigs{$serverhomedom}) eq 'HASH') { 9048: if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') { 9049: if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') { 9050: if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{$lonhost}) eq 'HASH') { 9051: $spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'}; 9052: $spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'}; 9053: $gotspares = 1; 9054: } 9055: } 9056: } 9057: } 9058: } 9059: } 9060: } 9061: unless ($gotspares) { 9062: if ($lonhost eq $Apache::lonnet::perlvar{'lonHostID'}) { 9063: $spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'}; 9064: $spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'}; 9065: } else { 9066: my $server_hostname = &Apache::lonnet::hostname($lonhost); 9067: my $server_homeID = &Apache::lonnet::get_server_homeID($server_hostname); 9068: if ($server_homeID eq $Apache::lonnet::perlvar{'lonHostID'}) { 9069: $spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'}; 9070: $spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'}; 9071: } else { 9072: my %what = ( 9073: spareid => 1, 9074: ); 9075: my ($result,$returnhash) = 9076: &Apache::lonnet::get_remote_globals($lonhost,\%what); 9077: if ($result eq 'ok') { 9078: if (ref($returnhash) eq 'HASH') { 9079: if (ref($returnhash->{'spareid'}) eq 'HASH') { 9080: $spareid{$lonhost}{'primary'} = $returnhash->{'spareid'}->{'primary'}; 9081: $spareid{$lonhost}{'default'} = $returnhash->{'spareid'}->{'default'}; 9082: } 9083: } 9084: } 9085: } 9086: } 9087: } 9088: } 9089: } 9090: return %spareid; 9091: } 9092: 9093: sub spares_row { 9094: my ($dom,$servers,$spareid,$serverhomes,$altids,$other_insts, 9095: $curroffloadnow,$curroffloadoth,$rowtotal) = @_; 9096: my $css_class; 9097: my $numinrow = 4; 9098: my $itemcount = 1; 9099: my $datatable; 9100: my %typetitles = &sparestype_titles(); 9101: if ((ref($servers) eq 'HASH') && (ref($spareid) eq 'HASH') && (ref($altids) eq 'HASH')) { 9102: foreach my $server (sort(keys(%{$servers}))) { 9103: my $serverhome = &Apache::lonnet::get_server_homeID($servers->{$server}); 9104: my ($othercontrol,$serverdom); 9105: if ($serverhome ne $server) { 9106: $serverdom = &Apache::lonnet::host_domain($serverhome); 9107: $othercontrol = &mt('Session offloading controlled by domain: [_1]','<b>'.$serverdom.'</b>'); 9108: } else { 9109: $serverdom = &Apache::lonnet::host_domain($server); 9110: if ($serverdom ne $dom) { 9111: $othercontrol = &mt('Session offloading controlled by domain: [_1]','<b>'.$serverdom.'</b>'); 9112: } 9113: } 9114: next unless (ref($spareid->{$server}) eq 'HASH'); 9115: my ($checkednow,$checkedoth); 9116: if (ref($curroffloadnow) eq 'HASH') { 9117: if ($curroffloadnow->{$server}) { 9118: $checkednow = ' checked="checked"'; 9119: } 9120: } 9121: if (ref($curroffloadoth) eq 'HASH') { 9122: if ($curroffloadoth->{$server}) { 9123: $checkedoth = ' checked="checked"'; 9124: } 9125: } 9126: $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; 9127: $datatable .= '<tr'.$css_class.'> 9128: <td rowspan="2"> 9129: <span class="LC_nobreak">'. 9130: &mt('[_1] when busy, offloads to:' 9131: ,'<b>'.$server.'</b>').'</span><br />'. 9132: '<span class="LC_nobreak">'."\n". 9133: '<label><input type="checkbox" name="offloadnow" value="'.$server.'"'.$checkednow.' />'. 9134: ' '.&mt('Switch any active user on next access').'</label></span>'. 9135: "\n"; 9136: if ($other_insts) { 9137: $datatable .= '<br />'. 9138: '<span class="LC_nobreak">'."\n". 9139: '<label><input type="checkbox" name="offloadoth" value="'.$server.'"'.$checkedoth.' />'. 9140: ' '.&mt('Switch other institutions on next access').'</label></span>'. 9141: "\n"; 9142: } 9143: my (%current,%canselect); 9144: my @choices = 9145: &possible_newspares($server,$spareid->{$server},$serverhomes,$altids); 9146: foreach my $type ('primary','default') { 9147: if (ref($spareid->{$server}) eq 'HASH') { 9148: if (ref($spareid->{$server}{$type}) eq 'ARRAY') { 9149: my @spares = @{$spareid->{$server}{$type}}; 9150: if (@spares > 0) { 9151: if ($othercontrol) { 9152: $current{$type} = join(', ',@spares); 9153: } else { 9154: $current{$type} .= '<table>'; 9155: my $numspares = scalar(@spares); 9156: for (my $i=0; $i<@spares; $i++) { 9157: my $rem = $i%($numinrow); 9158: if ($rem == 0) { 9159: if ($i > 0) { 9160: $current{$type} .= '</tr>'; 9161: } 9162: $current{$type} .= '<tr>'; 9163: } 9164: $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'".');" /> '. 9165: $spareid->{$server}{$type}[$i]. 9166: '</label></td>'."\n"; 9167: } 9168: my $rem = @spares%($numinrow); 9169: my $colsleft = $numinrow - $rem; 9170: if ($colsleft > 1 ) { 9171: $current{$type} .= '<td colspan="'.$colsleft. 9172: '" class="LC_left_item">'. 9173: ' </td>'; 9174: } elsif ($colsleft == 1) { 9175: $current{$type} .= '<td class="LC_left_item"> </td>'."\n"; 9176: } 9177: $current{$type} .= '</tr></table>'; 9178: } 9179: } 9180: } 9181: if ($current{$type} eq '') { 9182: $current{$type} = &mt('None specified'); 9183: } 9184: if ($othercontrol) { 9185: if ($type eq 'primary') { 9186: $canselect{$type} = $othercontrol; 9187: } 9188: } else { 9189: $canselect{$type} = 9190: &mt('Add new [_1]'.$type.'[_2]:','<i>','</i>').' '. 9191: '<select name="newspare_'.$type.'_'.$server.'" '. 9192: 'id="newspare_'.$type.'_'.$server.'" onchange="checkNewSpares('."'$server','$type'".');">'."\n". 9193: '<option value="" selected ="selected">'.&mt('Select').'</option>'."\n"; 9194: if (@choices > 0) { 9195: foreach my $lonhost (@choices) { 9196: $canselect{$type} .= '<option value="'.$lonhost.'">'.$lonhost.'</option>'."\n"; 9197: } 9198: } 9199: $canselect{$type} .= '</select>'."\n"; 9200: } 9201: } else { 9202: $current{$type} = &mt('Could not be determined'); 9203: if ($type eq 'primary') { 9204: $canselect{$type} = $othercontrol; 9205: } 9206: } 9207: if ($type eq 'default') { 9208: $datatable .= '<tr'.$css_class.'>'; 9209: } 9210: $datatable .= '<td><i>'.$typetitles{$type}.'</i></td>'."\n". 9211: '<td>'.$current{$type}.'</td>'."\n". 9212: '<td>'.$canselect{$type}.'</td></tr>'."\n"; 9213: } 9214: $itemcount ++; 9215: } 9216: } 9217: $$rowtotal += $itemcount; 9218: return $datatable; 9219: } 9220: 9221: sub possible_newspares { 9222: my ($server,$currspares,$serverhomes,$altids) = @_; 9223: my $serverhostname = &Apache::lonnet::hostname($server); 9224: my %excluded; 9225: if ($serverhostname ne '') { 9226: %excluded = ( 9227: $serverhostname => 1, 9228: ); 9229: } 9230: if (ref($currspares) eq 'HASH') { 9231: foreach my $type (keys(%{$currspares})) { 9232: if (ref($currspares->{$type}) eq 'ARRAY') { 9233: if (@{$currspares->{$type}} > 0) { 9234: foreach my $curr (@{$currspares->{$type}}) { 9235: my $hostname = &Apache::lonnet::hostname($curr); 9236: $excluded{$hostname} = 1; 9237: } 9238: } 9239: } 9240: } 9241: } 9242: my @choices; 9243: if ((ref($serverhomes) eq 'HASH') && (ref($altids) eq 'HASH')) { 9244: if (keys(%{$serverhomes}) > 1) { 9245: foreach my $name (sort(keys(%{$serverhomes}))) { 9246: unless ($excluded{$name}) { 9247: if (exists($altids->{$serverhomes->{$name}})) { 9248: push(@choices,$altids->{$serverhomes->{$name}}); 9249: } else { 9250: push(@choices,$serverhomes->{$name}); 9251: } 9252: } 9253: } 9254: } 9255: } 9256: return sort(@choices); 9257: } 9258: 9259: sub print_loadbalancing { 9260: my ($dom,$settings,$rowtotal) = @_; 9261: my $primary_id = &Apache::lonnet::domain($dom,'primary'); 9262: my $intdom = &Apache::lonnet::internet_dom($primary_id); 9263: my $numinrow = 1; 9264: my $datatable; 9265: my %servers = &Apache::lonnet::internet_dom_servers($dom); 9266: my (%currbalancer,%currtargets,%currrules,%existing,%currcookies); 9267: if (ref($settings) eq 'HASH') { 9268: %existing = %{$settings}; 9269: } 9270: if ((keys(%servers) > 1) || (keys(%existing) > 0)) { 9271: &get_loadbalancers_config(\%servers,\%existing,\%currbalancer, 9272: \%currtargets,\%currrules,\%currcookies); 9273: } else { 9274: return; 9275: } 9276: my ($othertitle,$usertypes,$types) = 9277: &Apache::loncommon::sorted_inst_types($dom); 9278: my $rownum = 8; 9279: if (ref($types) eq 'ARRAY') { 9280: $rownum += scalar(@{$types}); 9281: } 9282: my @css_class = ('LC_odd_row','LC_even_row'); 9283: my $balnum = 0; 9284: my $islast; 9285: my (@toshow,$disabledtext); 9286: if (keys(%currbalancer) > 0) { 9287: @toshow = sort(keys(%currbalancer)); 9288: if (scalar(@toshow) < scalar(keys(%servers)) + 1) { 9289: push(@toshow,''); 9290: } 9291: } else { 9292: @toshow = (''); 9293: $disabledtext = &mt('No existing load balancer'); 9294: } 9295: foreach my $lonhost (@toshow) { 9296: if ($balnum == scalar(@toshow)-1) { 9297: $islast = 1; 9298: } else { 9299: $islast = 0; 9300: } 9301: my $cssidx = $balnum%2; 9302: my $targets_div_style = 'display: none'; 9303: my $disabled_div_style = 'display: block'; 9304: my $homedom_div_style = 'display: none'; 9305: $datatable .= '<tr class="'.$css_class[$cssidx].'">'. 9306: '<td rowspan="'.$rownum.'" style="vertical-align: top">'. 9307: '<p>'; 9308: if ($lonhost eq '') { 9309: $datatable .= '<span class="LC_nobreak">'; 9310: if (keys(%currbalancer) > 0) { 9311: $datatable .= &mt('Add balancer:'); 9312: } else { 9313: $datatable .= &mt('Enable balancer:'); 9314: } 9315: $datatable .= ' '. 9316: '<select name="loadbalancing_lonhost_'.$balnum.'"'. 9317: ' id="loadbalancing_lonhost_'.$balnum.'"'. 9318: ' onchange="toggleTargets('."'$balnum'".');">'."\n". 9319: '<option value="" selected="selected">'.&mt('None'). 9320: '</option>'."\n"; 9321: foreach my $server (sort(keys(%servers))) { 9322: next if ($currbalancer{$server}); 9323: $datatable .= '<option value="'.$server.'">'.$server.'</option>'."\n"; 9324: } 9325: $datatable .= 9326: '</select>'."\n". 9327: '<input type="hidden" name="loadbalancing_prevlonhost_'.$balnum.'" id="loadbalancing_prevlonhost_'.$balnum.'" value="" /> </span>'."\n"; 9328: } else { 9329: $datatable .= '<i>'.$lonhost.'</i><br /><span class="LC_nobreak">'. 9330: '<label><input type="checkbox" name="loadbalancing_delete" value="'.$balnum.'" id="loadbalancing_delete_'.$balnum.'" onclick="javascript:balancerDeleteChange('."'$balnum'".');" /> '. 9331: &mt('Stop balancing').'</label>'. 9332: '<input type="hidden" name="loadbalancing_lonhost_'.$balnum.'" value="'.$lonhost.'" id="loadbalancing_lonhost_'.$balnum.'" /></span>'; 9333: $targets_div_style = 'display: block'; 9334: $disabled_div_style = 'display: none'; 9335: if ($dom eq &Apache::lonnet::host_domain($lonhost)) { 9336: $homedom_div_style = 'display: block'; 9337: } 9338: } 9339: $datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'. 9340: '<div id="loadbalancing_disabled_'.$balnum.'" style="'. 9341: $disabled_div_style.'">'.$disabledtext.'</div>'."\n". 9342: '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />'; 9343: my ($numspares,@spares) = &count_servers($lonhost,%servers); 9344: my @sparestypes = ('primary','default'); 9345: my %typetitles = &sparestype_titles(); 9346: my %hostherechecked = ( 9347: no => ' checked="checked"', 9348: ); 9349: my %balcookiechecked = ( 9350: no => ' checked="checked"', 9351: ); 9352: foreach my $sparetype (@sparestypes) { 9353: my $targettable; 9354: for (my $i=0; $i<$numspares; $i++) { 9355: my $checked; 9356: if (ref($currtargets{$lonhost}) eq 'HASH') { 9357: if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') { 9358: if (grep(/^\Q$spares[$i]\E$/,@{$currtargets{$lonhost}{$sparetype}})) { 9359: $checked = ' checked="checked"'; 9360: } 9361: } 9362: } 9363: my ($chkboxval,$disabled); 9364: if (($lonhost ne '') && (exists($servers{$lonhost}))) { 9365: $chkboxval = $spares[$i]; 9366: } 9367: if (exists($currbalancer{$spares[$i]})) { 9368: $disabled = ' disabled="disabled"'; 9369: } 9370: $targettable .= 9371: '<td><span class="LC_nobreak"><label>'. 9372: '<input type="checkbox" name="loadbalancing_target_'.$balnum.'_'.$sparetype.'"'. 9373: $checked.$disabled.' value="'.$chkboxval.'" id="loadbalancing_target_'.$balnum.'_'.$sparetype.'_'.$i.'" onclick="checkOffloads('."this,'$balnum','$sparetype'".');" /><span id="loadbalancing_targettxt_'.$balnum.'_'.$sparetype.'_'.$i.'"> '.$chkboxval. 9374: '</span></label></span></td>'; 9375: my $rem = $i%($numinrow); 9376: if ($rem == 0) { 9377: if (($i > 0) && ($i < $numspares-1)) { 9378: $targettable .= '</tr>'; 9379: } 9380: if ($i < $numspares-1) { 9381: $targettable .= '<tr>'; 9382: } 9383: } 9384: } 9385: if ($targettable ne '') { 9386: my $rem = $numspares%($numinrow); 9387: my $colsleft = $numinrow - $rem; 9388: if ($colsleft > 1 ) { 9389: $targettable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 9390: ' </td>'; 9391: } elsif ($colsleft == 1) { 9392: $targettable .= '<td class="LC_left_item"> </td>'; 9393: } 9394: $datatable .= '<i>'.$typetitles{$sparetype}.'</i><br />'. 9395: '<table><tr>'.$targettable.'</tr></table><br />'; 9396: } 9397: $hostherechecked{$sparetype} = ''; 9398: if (ref($currtargets{$lonhost}) eq 'HASH') { 9399: if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') { 9400: if (grep(/^\Q$lonhost\E$/,@{$currtargets{$lonhost}{$sparetype}})) { 9401: $hostherechecked{$sparetype} = ' checked="checked"'; 9402: $hostherechecked{'no'} = ''; 9403: } 9404: } 9405: } 9406: } 9407: if ($currcookies{$lonhost}) { 9408: %balcookiechecked = ( 9409: yes => ' checked="checked"', 9410: ); 9411: } 9412: $datatable .= &mt('Hosting on balancer itself').'<br />'. 9413: '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'. 9414: $hostherechecked{'no'}.' />'.&mt('No').'</label><br />'; 9415: foreach my $sparetype (@sparestypes) { 9416: $datatable .= '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" '. 9417: 'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}. 9418: '</i></label><br />'; 9419: } 9420: $datatable .= &mt('Use balancer cookie').'<br />'. 9421: '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="1"'. 9422: $balcookiechecked{'yes'}.' />'.&mt('Yes').'</label><br />'. 9423: '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="0"'. 9424: $balcookiechecked{'no'}.' />'.&mt('No').'</label><br />'. 9425: '</div></td></tr>'. 9426: &loadbalancing_rules($dom,$intdom,$currrules{$lonhost}, 9427: $othertitle,$usertypes,$types,\%servers, 9428: \%currbalancer,$lonhost, 9429: $targets_div_style,$homedom_div_style, 9430: $css_class[$cssidx],$balnum,$islast); 9431: $$rowtotal += $rownum; 9432: $balnum ++; 9433: } 9434: $datatable .= '<input type="hidden" name="loadbalancing_total" id="loadbalancing_total" value="'.$balnum.'" />'; 9435: return $datatable; 9436: } 9437: 9438: sub get_loadbalancers_config { 9439: my ($servers,$existing,$currbalancer,$currtargets,$currrules,$currcookies) = @_; 9440: return unless ((ref($servers) eq 'HASH') && 9441: (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') && 9442: (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH') && 9443: (ref($currcookies) eq 'HASH')); 9444: if (keys(%{$existing}) > 0) { 9445: my $oldlonhost; 9446: foreach my $key (sort(keys(%{$existing}))) { 9447: if ($key eq 'lonhost') { 9448: $oldlonhost = $existing->{'lonhost'}; 9449: $currbalancer->{$oldlonhost} = 1; 9450: } elsif ($key eq 'targets') { 9451: if ($oldlonhost) { 9452: $currtargets->{$oldlonhost} = $existing->{'targets'}; 9453: } 9454: } elsif ($key eq 'rules') { 9455: if ($oldlonhost) { 9456: $currrules->{$oldlonhost} = $existing->{'rules'}; 9457: } 9458: } elsif (ref($existing->{$key}) eq 'HASH') { 9459: $currbalancer->{$key} = 1; 9460: $currtargets->{$key} = $existing->{$key}{'targets'}; 9461: $currrules->{$key} = $existing->{$key}{'rules'}; 9462: if ($existing->{$key}{'cookie'}) { 9463: $currcookies->{$key} = 1; 9464: } 9465: } 9466: } 9467: } else { 9468: my ($balancerref,$targetsref) = 9469: &Apache::lonnet::get_lonbalancer_config($servers); 9470: if ((ref($balancerref) eq 'HASH') && (ref($targetsref) eq 'HASH')) { 9471: foreach my $server (sort(keys(%{$balancerref}))) { 9472: $currbalancer->{$server} = 1; 9473: $currtargets->{$server} = $targetsref->{$server}; 9474: } 9475: } 9476: } 9477: return; 9478: } 9479: 9480: sub loadbalancing_rules { 9481: my ($dom,$intdom,$currrules,$othertitle,$usertypes,$types,$servers, 9482: $currbalancer,$lonhost,$targets_div_style,$homedom_div_style, 9483: $css_class,$balnum,$islast) = @_; 9484: my $output; 9485: my $num = 0; 9486: my ($alltypes,$othertypes,$titles) = 9487: &loadbalancing_titles($dom,$intdom,$usertypes,$types); 9488: if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) { 9489: foreach my $type (@{$alltypes}) { 9490: $num ++; 9491: my $current; 9492: if (ref($currrules) eq 'HASH') { 9493: $current = $currrules->{$type}; 9494: } 9495: if (($type eq '_LC_external') || ($type eq '_LC_internetdom')) { 9496: if ($dom ne &Apache::lonnet::host_domain($lonhost)) { 9497: $current = ''; 9498: } 9499: } 9500: $output .= &loadbalance_rule_row($type,$titles->{$type},$current, 9501: $servers,$currbalancer,$lonhost,$dom, 9502: $targets_div_style,$homedom_div_style, 9503: $css_class,$balnum,$num,$islast); 9504: } 9505: } 9506: return $output; 9507: } 9508: 9509: sub loadbalancing_titles { 9510: my ($dom,$intdom,$usertypes,$types) = @_; 9511: my %othertypes = ( 9512: '_LC_adv' => &mt('Advanced users from [_1]',$dom), 9513: '_LC_author' => &mt('Users from [_1] with author role',$dom), 9514: '_LC_internetdom' => &mt('Users not from [_1], but from [_2]',$dom,$intdom), 9515: '_LC_external' => &mt('Users not from [_1]',$intdom), 9516: '_LC_ipchangesso' => &mt('SSO users from [_1], with IP mismatch',$dom), 9517: '_LC_ipchange' => &mt('Non-SSO users with IP mismatch'), 9518: ); 9519: my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange'); 9520: my @available; 9521: if (ref($types) eq 'ARRAY') { 9522: @available = @{$types}; 9523: } 9524: unless (grep(/^default$/,@available)) { 9525: push(@available,'default'); 9526: } 9527: unshift(@alltypes,@available); 9528: my %titles; 9529: foreach my $type (@alltypes) { 9530: if ($type =~ /^_LC_/) { 9531: $titles{$type} = $othertypes{$type}; 9532: } elsif ($type eq 'default') { 9533: $titles{$type} = &mt('All users from [_1]',$dom); 9534: if (ref($types) eq 'ARRAY') { 9535: if (@{$types} > 0) { 9536: $titles{$type} = &mt('Other users from [_1]',$dom); 9537: } 9538: } 9539: } elsif (ref($usertypes) eq 'HASH') { 9540: $titles{$type} = $usertypes->{$type}; 9541: } 9542: } 9543: return (\@alltypes,\%othertypes,\%titles); 9544: } 9545: 9546: sub loadbalance_rule_row { 9547: my ($type,$title,$current,$servers,$currbalancer,$lonhost,$dom, 9548: $targets_div_style,$homedom_div_style,$css_class,$balnum,$num,$islast) = @_; 9549: my @rulenames; 9550: my %ruletitles = &offloadtype_text(); 9551: if (($type eq '_LC_ipchangesso') || ($type eq '_LC_ipchange')) { 9552: @rulenames = ('balancer','offloadedto','specific'); 9553: } else { 9554: @rulenames = ('default','homeserver'); 9555: if ($type eq '_LC_external') { 9556: push(@rulenames,'externalbalancer'); 9557: } else { 9558: push(@rulenames,'specific'); 9559: } 9560: push(@rulenames,'none'); 9561: } 9562: my $style = $targets_div_style; 9563: if (($type eq '_LC_external') || ($type eq '_LC_internetdom')) { 9564: $style = $homedom_div_style; 9565: } 9566: my $space; 9567: if ($islast && $num == 1) { 9568: $space = '<div style="display:inline-block;"> </div>'; 9569: } 9570: my $output = 9571: '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td style="vertical-align: top">'.$space. 9572: '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n". 9573: '<td valaign="top">'.$space. 9574: '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n"; 9575: for (my $i=0; $i<@rulenames; $i++) { 9576: my $rule = $rulenames[$i]; 9577: my ($checked,$extra); 9578: if ($rulenames[$i] eq 'default') { 9579: $rule = ''; 9580: } 9581: if ($rulenames[$i] eq 'specific') { 9582: if (ref($servers) eq 'HASH') { 9583: my $default; 9584: if (($current ne '') && (exists($servers->{$current}))) { 9585: $checked = ' checked="checked"'; 9586: } 9587: unless ($checked) { 9588: $default = ' selected="selected"'; 9589: } 9590: $extra = 9591: ': <select name="loadbalancing_singleserver_'.$balnum.'_'.$type. 9592: '" id="loadbalancing_singleserver_'.$balnum.'_'.$type. 9593: '" onchange="singleServerToggle('."'$balnum','$type'".')">'."\n". 9594: '<option value=""'.$default.'></option>'."\n"; 9595: foreach my $server (sort(keys(%{$servers}))) { 9596: if (ref($currbalancer) eq 'HASH') { 9597: next if (exists($currbalancer->{$server})); 9598: } 9599: my $selected; 9600: if ($server eq $current) { 9601: $selected = ' selected="selected"'; 9602: } 9603: $extra .= '<option value="'.$server.'"'.$selected.'>'.$server.'</option>'; 9604: } 9605: $extra .= '</select>'; 9606: } 9607: } elsif ($rule eq $current) { 9608: $checked = ' checked="checked"'; 9609: } 9610: $output .= '<span class="LC_nobreak"><label>'. 9611: '<input type="radio" name="loadbalancing_rules_'.$balnum.'_'.$type. 9612: '" id="loadbalancing_rules_'.$balnum.'_'.$type.'_'.$i.'" value="'. 9613: $rule.'" onclick="balanceruleChange('."this.form,'$balnum','$type'". 9614: ')"'.$checked.' /> '; 9615: if (($rulenames[$i] eq 'specific') && ($type =~ /^_LC_ipchange/)) { 9616: $output .= $ruletitles{'particular'}; 9617: } else { 9618: $output .= $ruletitles{$rulenames[$i]}; 9619: } 9620: $output .= '</label>'.$extra.'</span><br />'."\n"; 9621: } 9622: $output .= '</div></td></tr>'."\n"; 9623: return $output; 9624: } 9625: 9626: sub offloadtype_text { 9627: my %ruletitles = &Apache::lonlocal::texthash ( 9628: 'default' => 'Offloads to default destinations', 9629: 'homeserver' => "Offloads to user's home server", 9630: 'externalbalancer' => "Offloads to Load Balancer in user's domain", 9631: 'specific' => 'Offloads to specific server', 9632: 'none' => 'No offload', 9633: 'balancer' => 'Session hosted on Load Balancer, after re-authentication', 9634: 'offloadedto' => 'Session hosted on offload server, after re-authentication', 9635: 'particular' => 'Session hosted (after re-auth) on server:', 9636: ); 9637: return %ruletitles; 9638: } 9639: 9640: sub sparestype_titles { 9641: my %typestitles = &Apache::lonlocal::texthash ( 9642: 'primary' => 'primary', 9643: 'default' => 'default', 9644: ); 9645: return %typestitles; 9646: } 9647: 9648: sub contact_titles { 9649: my %titles = &Apache::lonlocal::texthash ( 9650: 'supportemail' => 'Support E-mail address', 9651: 'adminemail' => 'Default Server Admin E-mail address', 9652: 'errormail' => 'Error reports to be e-mailed to', 9653: 'packagesmail' => 'Package update alerts to be e-mailed to', 9654: 'helpdeskmail' => "Helpdesk requests from all users in this domain", 9655: 'otherdomsmail' => 'Helpdesk requests from users in other (unconfigured) domains', 9656: 'lonstatusmail' => 'E-mail from nightly status check (warnings/errors)', 9657: 'requestsmail' => 'E-mail from course requests requiring approval', 9658: 'updatesmail' => 'E-mail from nightly check of LON-CAPA module integrity/updates', 9659: 'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID', 9660: 'hostipmail' => 'E-mail from nightly check of hostname/IP network changes', 9661: 'errorthreshold' => 'Error count threshold for status e-mail to admin(s)', 9662: 'errorsysmail' => 'Error count threshold for e-mail to developer group', 9663: 'errorweights' => 'Weights used to compute error count', 9664: 'errorexcluded' => 'Servers with unsent updates excluded from count', 9665: ); 9666: my %short_titles = &Apache::lonlocal::texthash ( 9667: adminemail => 'Admin E-mail address', 9668: supportemail => 'Support E-mail', 9669: ); 9670: return (\%titles,\%short_titles); 9671: } 9672: 9673: sub helpform_fields { 9674: my %titles = &Apache::lonlocal::texthash ( 9675: 'username' => 'Name', 9676: 'user' => 'Username/domain', 9677: 'phone' => 'Phone', 9678: 'cc' => 'Cc e-mail', 9679: 'course' => 'Course Details', 9680: 'section' => 'Sections', 9681: 'screenshot' => 'File upload', 9682: ); 9683: my @fields = ('username','phone','user','course','section','cc','screenshot'); 9684: my %possoptions = ( 9685: username => ['yes','no','req'], 9686: phone => ['yes','no','req'], 9687: user => ['yes','no'], 9688: cc => ['yes','no'], 9689: course => ['yes','no'], 9690: section => ['yes','no'], 9691: screenshot => ['yes','no'], 9692: ); 9693: my %fieldoptions = &Apache::lonlocal::texthash ( 9694: 'yes' => 'Optional', 9695: 'req' => 'Required', 9696: 'no' => "Not shown", 9697: ); 9698: return (\@fields,\%titles,\%fieldoptions,\%possoptions); 9699: } 9700: 9701: sub tool_titles { 9702: my %titles = &Apache::lonlocal::texthash ( 9703: aboutme => 'Personal web page', 9704: blog => 'Blog', 9705: webdav => 'WebDAV', 9706: portfolio => 'Portfolio', 9707: timezone => 'Can set time zone', 9708: official => 'Official courses (with institutional codes)', 9709: unofficial => 'Unofficial courses', 9710: community => 'Communities', 9711: textbook => 'Textbook courses', 9712: placement => 'Placement tests', 9713: ); 9714: return %titles; 9715: } 9716: 9717: sub courserequest_titles { 9718: my %titles = &Apache::lonlocal::texthash ( 9719: official => 'Official', 9720: unofficial => 'Unofficial', 9721: community => 'Communities', 9722: textbook => 'Textbook', 9723: placement => 'Placement tests', 9724: lti => 'LTI Provider', 9725: norequest => 'Not allowed', 9726: approval => 'Approval by DC', 9727: validate => 'With validation', 9728: autolimit => 'Numerical limit', 9729: unlimited => '(blank for unlimited)', 9730: ); 9731: return %titles; 9732: } 9733: 9734: sub authorrequest_titles { 9735: my %titles = &Apache::lonlocal::texthash ( 9736: norequest => 'Not allowed', 9737: approval => 'Approval by Dom. Coord.', 9738: automatic => 'Automatic approval', 9739: ); 9740: return %titles; 9741: } 9742: 9743: sub courserequest_conditions { 9744: my %conditions = &Apache::lonlocal::texthash ( 9745: approval => '(Processing of request subject to approval by Domain Coordinator).', 9746: validate => '(Processing of request subject to institutional validation).', 9747: ); 9748: return %conditions; 9749: } 9750: 9751: 9752: sub print_usercreation { 9753: my ($position,$dom,$settings,$rowtotal) = @_; 9754: my $numinrow = 4; 9755: my $datatable; 9756: if ($position eq 'top') { 9757: $$rowtotal ++; 9758: my $rowcount = 0; 9759: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($dom,'username'); 9760: if (ref($rules) eq 'HASH') { 9761: if (keys(%{$rules}) > 0) { 9762: $datatable .= &user_formats_row('username',$settings,$rules, 9763: $ruleorder,$numinrow,$rowcount); 9764: $$rowtotal ++; 9765: $rowcount ++; 9766: } 9767: } 9768: my ($idrules,$idruleorder) = &Apache::lonnet::inst_userrules($dom,'id'); 9769: if (ref($idrules) eq 'HASH') { 9770: if (keys(%{$idrules}) > 0) { 9771: $datatable .= &user_formats_row('id',$settings,$idrules, 9772: $idruleorder,$numinrow,$rowcount); 9773: $$rowtotal ++; 9774: $rowcount ++; 9775: } 9776: } 9777: if ($rowcount == 0) { 9778: $datatable .= '<tr><td colspan="2">'.&mt('No format rules have been defined for usernames or IDs in this domain.').'</td></tr>'; 9779: $$rowtotal ++; 9780: $rowcount ++; 9781: } 9782: } elsif ($position eq 'middle') { 9783: my @creators = ('author','course','requestcrs'); 9784: my ($rules,$ruleorder) = 9785: &Apache::lonnet::inst_userrules($dom,'username'); 9786: my %lt = &usercreation_types(); 9787: my %checked; 9788: if (ref($settings) eq 'HASH') { 9789: if (ref($settings->{'cancreate'}) eq 'HASH') { 9790: foreach my $item (@creators) { 9791: $checked{$item} = $settings->{'cancreate'}{$item}; 9792: } 9793: } elsif (ref($settings->{'cancreate'}) eq 'ARRAY') { 9794: foreach my $item (@creators) { 9795: if (grep(/^\Q$item\E$/,@{$settings->{'cancreate'}})) { 9796: $checked{$item} = 'none'; 9797: } 9798: } 9799: } 9800: } 9801: my $rownum = 0; 9802: foreach my $item (@creators) { 9803: $rownum ++; 9804: if ($checked{$item} eq '') { 9805: $checked{$item} = 'any'; 9806: } 9807: my $css_class; 9808: if ($rownum%2) { 9809: $css_class = ''; 9810: } else { 9811: $css_class = ' class="LC_odd_row" '; 9812: } 9813: $datatable .= '<tr'.$css_class.'>'. 9814: '<td><span class="LC_nobreak">'.$lt{$item}. 9815: '</span></td><td style="text-align: right">'; 9816: my @options = ('any'); 9817: if (ref($rules) eq 'HASH') { 9818: if (keys(%{$rules}) > 0) { 9819: push(@options,('official','unofficial')); 9820: } 9821: } 9822: push(@options,'none'); 9823: foreach my $option (@options) { 9824: my $type = 'radio'; 9825: my $check = ' '; 9826: if ($checked{$item} eq $option) { 9827: $check = ' checked="checked" '; 9828: } 9829: $datatable .= '<span class="LC_nobreak"><label>'. 9830: '<input type="'.$type.'" name="can_createuser_'. 9831: $item.'" value="'.$option.'"'.$check.'/> '. 9832: $lt{$option}.'</label> </span>'; 9833: } 9834: $datatable .= '</td></tr>'; 9835: } 9836: } else { 9837: my @contexts = ('author','course','domain'); 9838: my @authtypes = ('int','krb4','krb5','loc','lti'); 9839: my %checked; 9840: if (ref($settings) eq 'HASH') { 9841: if (ref($settings->{'authtypes'}) eq 'HASH') { 9842: foreach my $item (@contexts) { 9843: if (ref($settings->{'authtypes'}{$item}) eq 'HASH') { 9844: foreach my $auth (@authtypes) { 9845: if ($settings->{'authtypes'}{$item}{$auth}) { 9846: $checked{$item}{$auth} = ' checked="checked" '; 9847: } 9848: } 9849: } 9850: } 9851: } 9852: } else { 9853: foreach my $item (@contexts) { 9854: foreach my $auth (@authtypes) { 9855: $checked{$item}{$auth} = ' checked="checked" '; 9856: } 9857: } 9858: } 9859: my %title = &context_names(); 9860: my %authname = &authtype_names(); 9861: my $rownum = 0; 9862: my $css_class; 9863: foreach my $item (@contexts) { 9864: if ($rownum%2) { 9865: $css_class = ''; 9866: } else { 9867: $css_class = ' class="LC_odd_row" '; 9868: } 9869: $datatable .= '<tr'.$css_class.'>'. 9870: '<td>'.$title{$item}. 9871: '</td><td class="LC_left_item">'. 9872: '<span class="LC_nobreak">'; 9873: foreach my $auth (@authtypes) { 9874: $datatable .= '<label>'. 9875: '<input type="checkbox" name="'.$item.'_auth" '. 9876: $checked{$item}{$auth}.' value="'.$auth.'" />'. 9877: $authname{$auth}.'</label> '; 9878: } 9879: $datatable .= '</span></td></tr>'; 9880: $rownum ++; 9881: } 9882: $$rowtotal += $rownum; 9883: } 9884: return $datatable; 9885: } 9886: 9887: sub print_selfcreation { 9888: my ($position,$dom,$settings,$rowtotal) = @_; 9889: my (@selfcreate,$createsettings,$processing,$emailoptions,$emailverified, 9890: $emaildomain,$datatable); 9891: if (ref($settings) eq 'HASH') { 9892: if (ref($settings->{'cancreate'}) eq 'HASH') { 9893: $createsettings = $settings->{'cancreate'}; 9894: if (ref($createsettings) eq 'HASH') { 9895: if (ref($createsettings->{'selfcreate'}) eq 'ARRAY') { 9896: @selfcreate = @{$createsettings->{'selfcreate'}}; 9897: } elsif ($createsettings->{'selfcreate'} ne '') { 9898: if ($settings->{'cancreate'}{'selfcreate'} eq 'any') { 9899: @selfcreate = ('email','login','sso'); 9900: } elsif ($createsettings->{'selfcreate'} ne 'none') { 9901: @selfcreate = ($createsettings->{'selfcreate'}); 9902: } 9903: } 9904: if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') { 9905: $processing = $createsettings->{'selfcreateprocessing'}; 9906: } 9907: if (ref($createsettings->{'emailoptions'}) eq 'HASH') { 9908: $emailoptions = $createsettings->{'emailoptions'}; 9909: } 9910: if (ref($createsettings->{'emailverified'}) eq 'HASH') { 9911: $emailverified = $createsettings->{'emailverified'}; 9912: } 9913: if (ref($createsettings->{'emaildomain'}) eq 'HASH') { 9914: $emaildomain = $createsettings->{'emaildomain'}; 9915: } 9916: } 9917: } 9918: } 9919: my %radiohash; 9920: my $numinrow = 4; 9921: map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate; 9922: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 9923: if ($position eq 'top') { 9924: my %choices = &Apache::lonlocal::texthash ( 9925: cancreate_login => 'Institutional Login', 9926: cancreate_sso => 'Institutional Single Sign On', 9927: ); 9928: my @toggles = sort(keys(%choices)); 9929: my %defaultchecked = ( 9930: 'cancreate_login' => 'off', 9931: 'cancreate_sso' => 'off', 9932: ); 9933: my ($onclick,$itemcount); 9934: ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked, 9935: \%choices,$itemcount,$onclick); 9936: $$rowtotal += $itemcount; 9937: 9938: if (ref($usertypes) eq 'HASH') { 9939: if (keys(%{$usertypes}) > 0) { 9940: $datatable .= &insttypes_row($createsettings,$types,$usertypes, 9941: $dom,$numinrow,$othertitle, 9942: 'statustocreate',$rowtotal); 9943: $$rowtotal ++; 9944: } 9945: } 9946: my @fields = ('lastname','firstname','middlename','permanentemail','id','inststatus'); 9947: my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 9948: $fieldtitles{'inststatus'} = &mt('Institutional status'); 9949: my $rem; 9950: my $numperrow = 2; 9951: my $css_class = $$rowtotal%2?' class="LC_odd_row"':''; 9952: $datatable .= '<tr'.$css_class.'>'. 9953: '<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'. 9954: '<td class="LC_left_item">'."\n". 9955: '<table>'."\n"; 9956: for (my $i=0; $i<@fields; $i++) { 9957: $rem = $i%($numperrow); 9958: if ($rem == 0) { 9959: if ($i > 0) { 9960: $datatable .= '</tr>'; 9961: } 9962: $datatable .= '<tr>'; 9963: } 9964: my $currval; 9965: if (ref($createsettings) eq 'HASH') { 9966: if (ref($createsettings->{'shibenv'}) eq 'HASH') { 9967: $currval = $createsettings->{'shibenv'}{$fields[$i]}; 9968: } 9969: } 9970: $datatable .= '<td class="LC_left_item">'. 9971: '<span class="LC_nobreak">'. 9972: '<input type="text" name="shibenv_'.$fields[$i].'" '. 9973: 'value="'.$currval.'" size="10" /> '. 9974: $fieldtitles{$fields[$i]}.'</span></td>'; 9975: } 9976: my $colsleft = $numperrow - $rem; 9977: if ($colsleft > 1 ) { 9978: $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 9979: ' </td>'; 9980: } elsif ($colsleft == 1) { 9981: $datatable .= '<td class="LC_left_item"> </td>'; 9982: } 9983: $datatable .= '</tr></table></td></tr>'; 9984: $$rowtotal ++; 9985: } elsif ($position eq 'middle') { 9986: my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom); 9987: my @posstypes; 9988: if (ref($types) eq 'ARRAY') { 9989: @posstypes = @{$types}; 9990: } 9991: unless (grep(/^default$/,@posstypes)) { 9992: push(@posstypes,'default'); 9993: } 9994: my %usertypeshash; 9995: if (ref($usertypes) eq 'HASH') { 9996: %usertypeshash = %{$usertypes}; 9997: } 9998: $usertypeshash{'default'} = $othertitle; 9999: foreach my $status (@posstypes) { 10000: $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'}, 10001: $numinrow,$$rowtotal,\%usertypeshash); 10002: $$rowtotal ++; 10003: } 10004: } else { 10005: my %choices = &Apache::lonlocal::texthash ( 10006: 'cancreate_email' => 'Non-institutional username (via e-mail verification)', 10007: ); 10008: my @toggles = sort(keys(%choices)); 10009: my %defaultchecked = ( 10010: 'cancreate_email' => 'off', 10011: ); 10012: my $customclass = 'LC_selfcreate_email'; 10013: my $classprefix = 'LC_canmodify_emailusername_'; 10014: my $optionsprefix = 'LC_options_emailusername_'; 10015: my $display = 'none'; 10016: my $rowstyle = 'display:none'; 10017: if (grep(/^\Qemail\E$/,@selfcreate)) { 10018: $display = 'block'; 10019: $rowstyle = 'display:table-row'; 10020: } 10021: my $onclick = "toggleRows(this.form,'cancreate_email','selfassign','$customclass','$classprefix','$optionsprefix');"; 10022: ($datatable,$$rowtotal) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked, 10023: \%choices,$$rowtotal,$onclick); 10024: $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal,$customclass, 10025: $rowstyle); 10026: $$rowtotal ++; 10027: $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal,$customclass, 10028: $rowstyle); 10029: $$rowtotal ++; 10030: my (@ordered,@posstypes,%usertypeshash); 10031: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); 10032: my ($emailrules,$emailruleorder) = 10033: &Apache::lonnet::inst_userrules($dom,'email'); 10034: my $primary_id = &Apache::lonnet::domain($dom,'primary'); 10035: my $intdom = &Apache::lonnet::internet_dom($primary_id); 10036: if (ref($types) eq 'ARRAY') { 10037: @posstypes = @{$types}; 10038: } 10039: if (@posstypes) { 10040: unless (grep(/^default$/,@posstypes)) { 10041: push(@posstypes,'default'); 10042: } 10043: if (ref($usertypes) eq 'HASH') { 10044: %usertypeshash = %{$usertypes}; 10045: } 10046: my $currassign; 10047: if (ref($domdefaults{'inststatusguest'}) eq 'ARRAY') { 10048: $currassign = { 10049: selfassign => $domdefaults{'inststatusguest'}, 10050: }; 10051: @ordered = @{$domdefaults{'inststatusguest'}}; 10052: } else { 10053: $currassign = { selfassign => [] }; 10054: } 10055: my $onclicktypes = "toggleDataRow(this.form,'selfassign','$customclass','$optionsprefix',);". 10056: "toggleDataRow(this.form,'selfassign','$customclass','$classprefix',1);"; 10057: $datatable .= &insttypes_row($currassign,$types,$usertypes,$dom, 10058: $numinrow,$othertitle,'selfassign', 10059: $rowtotal,$onclicktypes,$customclass, 10060: $rowstyle); 10061: $$rowtotal ++; 10062: $usertypeshash{'default'} = $othertitle; 10063: foreach my $status (@posstypes) { 10064: my $css_class; 10065: if ($$rowtotal%2) { 10066: $css_class = 'LC_odd_row '; 10067: } 10068: $css_class .= $customclass; 10069: my $rowid = $optionsprefix.$status; 10070: my $hidden = 1; 10071: my $currstyle = 'display:none'; 10072: if (grep(/^\Q$status\E$/,@ordered)) { 10073: $currstyle = $rowstyle; 10074: $hidden = 0; 10075: } 10076: $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain, 10077: $emailrules,$emailruleorder,$settings,$status,$rowid, 10078: $usertypeshash{$status},$css_class,$currstyle,$intdom); 10079: unless ($hidden) { 10080: $$rowtotal ++; 10081: } 10082: } 10083: } else { 10084: my $css_class; 10085: if ($$rowtotal%2) { 10086: $css_class = 'LC_odd_row '; 10087: } 10088: $css_class .= $customclass; 10089: $usertypeshash{'default'} = $othertitle; 10090: $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain, 10091: $emailrules,$emailruleorder,$settings,'default','', 10092: $othertitle,$css_class,$rowstyle,$intdom); 10093: $$rowtotal ++; 10094: } 10095: my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info(); 10096: $numinrow = 1; 10097: if (@posstypes) { 10098: foreach my $status (@posstypes) { 10099: my $rowid = $classprefix.$status; 10100: my $datarowstyle = 'display:none'; 10101: if (grep(/^\Q$status\E$/,@ordered)) { 10102: $datarowstyle = $rowstyle; 10103: } 10104: $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings, 10105: $numinrow,$$rowtotal,\%usertypeshash,$infofields, 10106: $infotitles,$rowid,$customclass,$datarowstyle); 10107: unless ($datarowstyle eq 'display:none') { 10108: $$rowtotal ++; 10109: } 10110: } 10111: } else { 10112: $datatable .= &modifiable_userdata_row('cancreate','emailusername_default',$settings, 10113: $numinrow,$$rowtotal,\%usertypeshash,$infofields, 10114: $infotitles,'',$customclass,$rowstyle); 10115: } 10116: } 10117: return $datatable; 10118: } 10119: 10120: sub selfcreate_javascript { 10121: return <<"ENDSCRIPT"; 10122: 10123: <script type="text/javascript"> 10124: // <![CDATA[ 10125: 10126: function toggleRows(form,radio,checkbox,target,prefix,altprefix) { 10127: var x = document.getElementsByClassName(target); 10128: var insttypes = 0; 10129: var insttypeRegExp = new RegExp(prefix); 10130: if ((x.length != undefined) && (x.length > 0)) { 10131: if (form.elements[radio].length != undefined) { 10132: for (var i=0; i<form.elements[radio].length; i++) { 10133: if (form.elements[radio][i].checked) { 10134: if (form.elements[radio][i].value == 1) { 10135: for (var j=0; j<x.length; j++) { 10136: if (x[j].id == 'undefined') { 10137: x[j].style.display = 'table-row'; 10138: } else if (insttypeRegExp.test(x[j].id)) { 10139: insttypes ++; 10140: } else { 10141: x[j].style.display = 'table-row'; 10142: } 10143: } 10144: } else { 10145: for (var j=0; j<x.length; j++) { 10146: x[j].style.display = 'none'; 10147: } 10148: } 10149: break; 10150: } 10151: } 10152: if (insttypes > 0) { 10153: toggleDataRow(form,checkbox,target,altprefix); 10154: toggleDataRow(form,checkbox,target,prefix,1); 10155: } 10156: } 10157: } 10158: return; 10159: } 10160: 10161: function toggleDataRow(form,checkbox,target,prefix,docount) { 10162: if (form.elements[checkbox].length != undefined) { 10163: var count = 0; 10164: if (docount) { 10165: for (var i=0; i<form.elements[checkbox].length; i++) { 10166: if (form.elements[checkbox][i].checked) { 10167: count ++; 10168: } 10169: } 10170: } 10171: for (var i=0; i<form.elements[checkbox].length; i++) { 10172: var type = form.elements[checkbox][i].value; 10173: if (document.getElementById(prefix+type)) { 10174: if (form.elements[checkbox][i].checked) { 10175: document.getElementById(prefix+type).style.display = 'table-row'; 10176: if (count % 2 == 1) { 10177: document.getElementById(prefix+type).className = target+' LC_odd_row'; 10178: } else { 10179: document.getElementById(prefix+type).className = target; 10180: } 10181: count ++; 10182: } else { 10183: document.getElementById(prefix+type).style.display = 'none'; 10184: } 10185: } 10186: } 10187: } 10188: return; 10189: } 10190: 10191: function toggleEmailOptions(form,radio,prefix,altprefix,status) { 10192: var caller = radio+'_'+status; 10193: if (form.elements[caller].length != undefined) { 10194: for (var i=0; i<form.elements[caller].length; i++) { 10195: if (form.elements[caller][i].checked) { 10196: if (document.getElementById(altprefix+'_inst_'+status)) { 10197: var curr = form.elements[caller][i].value; 10198: if (prefix) { 10199: document.getElementById(prefix+'_'+status).style.display = 'none'; 10200: } 10201: document.getElementById(altprefix+'_inst_'+status).style.display = 'none'; 10202: document.getElementById(altprefix+'_noninst_'+status).style.display = 'none'; 10203: if (curr == 'custom') { 10204: if (prefix) { 10205: document.getElementById(prefix+'_'+status).style.display = 'inline'; 10206: } 10207: } else if (curr == 'inst') { 10208: document.getElementById(altprefix+'_inst_'+status).style.display = 'inline'; 10209: } else if (curr == 'noninst') { 10210: document.getElementById(altprefix+'_noninst_'+status).style.display = 'inline'; 10211: } 10212: break; 10213: } 10214: } 10215: } 10216: } 10217: } 10218: 10219: // ]]> 10220: </script> 10221: 10222: ENDSCRIPT 10223: } 10224: 10225: sub noninst_users { 10226: my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules, 10227: $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; 10228: my $class = 'LC_left_item'; 10229: if ($css_class) { 10230: $css_class = ' class="'.$css_class.'"'; 10231: } 10232: if ($rowid) { 10233: $rowid = ' id="'.$rowid.'"'; 10234: } 10235: if ($rowstyle) { 10236: $rowstyle = ' style="'.$rowstyle.'"'; 10237: } 10238: my ($output,$description); 10239: if ($type eq 'default') { 10240: $description = &mt('Requests for: [_1]',$typetitle); 10241: } else { 10242: $description = &mt('Requests for: [_1] (status self-reported)',$typetitle); 10243: } 10244: $output = '<tr'.$css_class.$rowid.$rowstyle.'>'. 10245: "<td>$description</td>\n". 10246: '<td class="'.$class.'" colspan="2">'. 10247: '<table><tr>'; 10248: my %headers = &Apache::lonlocal::texthash( 10249: approve => 'Processing', 10250: email => 'E-mail', 10251: username => 'Username', 10252: ); 10253: foreach my $item ('approve','email','username') { 10254: $output .= '<th>'.$headers{$item}.'</th>'; 10255: } 10256: $output .= '</tr><tr>'; 10257: foreach my $item ('approve','email','username') { 10258: $output .= '<td style="vertical-align: top">'; 10259: my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom); 10260: if ($item eq 'approve') { 10261: %choices = &Apache::lonlocal::texthash ( 10262: automatic => 'Automatically approved', 10263: approval => 'Queued for approval', 10264: ); 10265: @options = ('automatic','approval'); 10266: $hashref = $processing; 10267: $defoption = 'automatic'; 10268: $name = 'cancreate_emailprocess_'.$type; 10269: } elsif ($item eq 'email') { 10270: %choices = &Apache::lonlocal::texthash ( 10271: any => 'Any e-mail', 10272: inst => 'Institutional only', 10273: noninst => 'Non-institutional only', 10274: custom => 'Custom restrictions', 10275: ); 10276: @options = ('any','inst','noninst'); 10277: my $showcustom; 10278: if (ref($emailrules) eq 'HASH') { 10279: if (keys(%{$emailrules}) > 0) { 10280: push(@options,'custom'); 10281: $showcustom = 'cancreate_emailrule'; 10282: if (ref($settings) eq 'HASH') { 10283: if (ref($settings->{'email_rule'}) eq 'ARRAY') { 10284: foreach my $rule (@{$settings->{'email_rule'}}) { 10285: if (exists($emailrules->{$rule})) { 10286: $hascustom ++; 10287: } 10288: } 10289: } elsif (ref($settings->{'email_rule'}) eq 'HASH') { 10290: if (ref($settings->{'email_rule'}{$type}) eq 'ARRAY') { 10291: foreach my $rule (@{$settings->{'email_rule'}{$type}}) { 10292: if (exists($emailrules->{$rule})) { 10293: $hascustom ++; 10294: } 10295: } 10296: } 10297: } 10298: } 10299: } 10300: } 10301: $onclick = ' onclick="toggleEmailOptions(this.form,'."'cancreate_emailoptions','$showcustom',". 10302: "'cancreate_emaildomain','$type'".');"'; 10303: $hashref = $emailoptions; 10304: $defoption = 'any'; 10305: $name = 'cancreate_emailoptions_'.$type; 10306: } elsif ($item eq 'username') { 10307: %choices = &Apache::lonlocal::texthash ( 10308: all => 'Same as e-mail', 10309: first => 'Omit @domain', 10310: free => 'Free to choose', 10311: ); 10312: @options = ('all','first','free'); 10313: $hashref = $emailverified; 10314: $defoption = 'all'; 10315: $name = 'cancreate_usernameoptions_'.$type; 10316: } 10317: foreach my $option (@options) { 10318: my $checked; 10319: if (ref($hashref) eq 'HASH') { 10320: if ($type eq '') { 10321: if (!exists($hashref->{'default'})) { 10322: if ($option eq $defoption) { 10323: $checked = ' checked="checked"'; 10324: } 10325: } else { 10326: if ($hashref->{'default'} eq $option) { 10327: $checked = ' checked="checked"'; 10328: } 10329: } 10330: } else { 10331: if (!exists($hashref->{$type})) { 10332: if ($option eq $defoption) { 10333: $checked = ' checked="checked"'; 10334: } 10335: } else { 10336: if ($hashref->{$type} eq $option) { 10337: $checked = ' checked="checked"'; 10338: } 10339: } 10340: } 10341: } elsif (($item eq 'email') && ($hascustom)) { 10342: if ($option eq 'custom') { 10343: $checked = ' checked="checked"'; 10344: } 10345: } elsif ($option eq $defoption) { 10346: $checked = ' checked="checked"'; 10347: } 10348: $output .= '<span class="LC_nobreak"><label>'. 10349: '<input type="radio" name="'.$name.'"'. 10350: $checked.' value="'.$option.'"'.$onclick.' />'. 10351: $choices{$option}.'</label></span><br />'; 10352: if ($item eq 'email') { 10353: if ($option eq 'custom') { 10354: my $id = 'cancreate_emailrule_'.$type; 10355: my $display = 'none'; 10356: if ($checked) { 10357: $display = 'inline'; 10358: } 10359: my $numinrow = 2; 10360: $output .= '<fieldset id="'.$id.'" style="display:'.$display.';">'. 10361: '<legend>'.&mt('Disallow').'</legend><table>'. 10362: &user_formats_row('email',$settings,$emailrules, 10363: $emailruleorder,$numinrow,'',$type); 10364: '</table></fieldset>'; 10365: } elsif (($option eq 'inst') || ($option eq 'noninst')) { 10366: my %text = &Apache::lonlocal::texthash ( 10367: inst => 'must end:', 10368: noninst => 'cannot end:', 10369: ); 10370: my $value; 10371: if (ref($emaildomain) eq 'HASH') { 10372: if (ref($emaildomain->{$type}) eq 'HASH') { 10373: $value = $emaildomain->{$type}->{$option}; 10374: } 10375: } 10376: if ($value eq '') { 10377: $value = '@'.$intdom; 10378: } 10379: my $condition = 'cancreate_emaildomain_'.$option.'_'.$type; 10380: my $display = 'none'; 10381: if ($checked) { 10382: $display = 'inline'; 10383: } 10384: $output .= '<div id="'.$condition.'" style="display:'.$display.';">'. 10385: '<span class="LC_domprefs_email">'.$text{$option}.'</span> '. 10386: '<input type="text" name="'.$condition.'" value="'.$value.'" size="10" />'. 10387: '</div>'; 10388: } 10389: } 10390: } 10391: $output .= '</td>'."\n"; 10392: } 10393: $output .= "</tr></table></td></tr>\n"; 10394: return $output; 10395: } 10396: 10397: sub captcha_choice { 10398: my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_; 10399: my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext, 10400: $vertext,$currver); 10401: my %lt = &captcha_phrases(); 10402: $keyentry = 'hidden'; 10403: my $colspan=2; 10404: if ($context eq 'cancreate') { 10405: $rowname = &mt('CAPTCHA validation'); 10406: } elsif ($context eq 'login') { 10407: $rowname = &mt('"Contact helpdesk" CAPTCHA validation'); 10408: } elsif ($context eq 'passwords') { 10409: $rowname = &mt('"Forgot Password" CAPTCHA validation'); 10410: $colspan=1; 10411: } 10412: if (ref($settings) eq 'HASH') { 10413: if ($settings->{'captcha'}) { 10414: $checked{$settings->{'captcha'}} = ' checked="checked"'; 10415: } else { 10416: $checked{'original'} = ' checked="checked"'; 10417: } 10418: if ($settings->{'captcha'} eq 'recaptcha') { 10419: $pubtext = $lt{'pub'}; 10420: $privtext = $lt{'priv'}; 10421: $keyentry = 'text'; 10422: $vertext = $lt{'ver'}; 10423: $currver = $settings->{'recaptchaversion'}; 10424: if ($currver ne '2') { 10425: $currver = 1; 10426: } 10427: } 10428: if (ref($settings->{'recaptchakeys'}) eq 'HASH') { 10429: $currpub = $settings->{'recaptchakeys'}{'public'}; 10430: $currpriv = $settings->{'recaptchakeys'}{'private'}; 10431: } 10432: } else { 10433: $checked{'original'} = ' checked="checked"'; 10434: } 10435: my $css_class; 10436: if ($itemcount%2) { 10437: $css_class = 'LC_odd_row'; 10438: } 10439: if ($customcss) { 10440: $css_class .= " $customcss"; 10441: } 10442: $css_class =~ s/^\s+//; 10443: if ($css_class) { 10444: $css_class = ' class="'.$css_class.'"'; 10445: } 10446: if ($rowstyle) { 10447: $css_class .= ' style="'.$rowstyle.'"'; 10448: } 10449: my $output = '<tr'.$css_class.'>'. 10450: '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="'.$colspan.'">'."\n". 10451: '<table><tr><td>'."\n"; 10452: foreach my $option ('original','recaptcha','notused') { 10453: $output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'. 10454: $option.'" '.$checked{$option}.' onchange="javascript:updateCaptcha('."this,'$context'".');" />'. 10455: $lt{$option}.'</label></span>'; 10456: unless ($option eq 'notused') { 10457: $output .= (' 'x2)."\n"; 10458: } 10459: } 10460: # 10461: # Note: If reCAPTCHA is to be used for LON-CAPA servers in a domain, a domain coordinator should visit: 10462: # https://www.google.com/recaptcha and generate a Public and Private key. For domains with multiple 10463: # servers a single key pair will be used for all servers, so the internet domain (e.g., yourcollege.edu) 10464: # specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain. 10465: # 10466: $output .= '</td></tr>'."\n". 10467: '<tr><td class="LC_zero_height">'."\n". 10468: '<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span> '."\n". 10469: '<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'. 10470: $currpub.'" size="40" /></span><br />'."\n". 10471: '<span class="LC_nobreak"><span id="'.$context.'_recaptchaprivtxt">'.$privtext.'</span> '."\n". 10472: '<input type="'.$keyentry.'" id="'.$context.'_recaptchapriv" name="'.$context.'_recaptchapriv" value="'. 10473: $currpriv.'" size="40" /></span><br />'. 10474: '<span class="LC_nobreak"><span id="'.$context.'_recaptchavertxt">'.$vertext.'</span> '."\n". 10475: '<input type="'.$keyentry.'" id="'.$context.'_recaptchaversion" name="'.$context.'_recaptchaversion" value="'. 10476: $currver.'" size="3" /></span><br />'. 10477: '</td></tr></table>'."\n". 10478: '</td></tr>'; 10479: return $output; 10480: } 10481: 10482: sub user_formats_row { 10483: my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount,$status) = @_; 10484: my $output; 10485: my %text = ( 10486: 'username' => 'new usernames', 10487: 'id' => 'IDs', 10488: ); 10489: unless (($type eq 'email') || ($type eq 'unamemap')) { 10490: my $css_class = $rowcount%2?' class="LC_odd_row"':''; 10491: $output = '<tr '.$css_class.'>'. 10492: '<td><span class="LC_nobreak">'. 10493: &mt("Format rules to check for $text{$type}: "). 10494: '</td><td class="LC_left_item" colspan="2"><table>'; 10495: } 10496: my $rem; 10497: if (ref($ruleorder) eq 'ARRAY') { 10498: for (my $i=0; $i<@{$ruleorder}; $i++) { 10499: if (ref($rules->{$ruleorder->[$i]}) eq 'HASH') { 10500: my $rem = $i%($numinrow); 10501: if ($rem == 0) { 10502: if ($i > 0) { 10503: $output .= '</tr>'; 10504: } 10505: $output .= '<tr>'; 10506: } 10507: my $check = ' '; 10508: if (ref($settings) eq 'HASH') { 10509: if (ref($settings->{$type.'_rule'}) eq 'ARRAY') { 10510: if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) { 10511: $check = ' checked="checked" '; 10512: } 10513: } elsif ((ref($settings->{$type.'_rule'}) eq 'HASH') && ($status ne '')) { 10514: if (ref($settings->{$type.'_rule'}->{$status}) eq 'ARRAY') { 10515: if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}->{$status}})) { 10516: $check = ' checked="checked" '; 10517: } 10518: } 10519: } 10520: } 10521: my $name = $type.'_rule'; 10522: if ($type eq 'email') { 10523: $name .= '_'.$status; 10524: } 10525: $output .= '<td class="LC_left_item">'. 10526: '<span class="LC_nobreak"><label>'. 10527: '<input type="checkbox" name="'.$name.'" '. 10528: 'value="'.$ruleorder->[$i].'"'.$check.'/>'. 10529: $rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>'; 10530: } 10531: } 10532: $rem = @{$ruleorder}%($numinrow); 10533: } 10534: my $colsleft; 10535: if ($rem) { 10536: $colsleft = $numinrow - $rem; 10537: } 10538: if ($colsleft > 1 ) { 10539: $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 10540: ' </td>'; 10541: } elsif ($colsleft == 1) { 10542: $output .= '<td class="LC_left_item"> </td>'; 10543: } 10544: $output .= '</tr>'; 10545: unless (($type eq 'email') || ($type eq 'unamemap')) { 10546: $output .= '</table></td></tr>'; 10547: } 10548: return $output; 10549: } 10550: 10551: sub usercreation_types { 10552: my %lt = &Apache::lonlocal::texthash ( 10553: author => 'When adding a co-author', 10554: course => 'When adding a user to a course', 10555: requestcrs => 'When requesting a course', 10556: any => 'Any', 10557: official => 'Institutional only ', 10558: unofficial => 'Non-institutional only', 10559: none => 'None', 10560: ); 10561: return %lt; 10562: } 10563: 10564: sub selfcreation_types { 10565: my %lt = &Apache::lonlocal::texthash ( 10566: selfcreate => 'User creates own account', 10567: any => 'Any', 10568: official => 'Institutional only ', 10569: unofficial => 'Non-institutional only', 10570: email => 'E-mail address', 10571: login => 'Institutional Login', 10572: sso => 'SSO', 10573: ); 10574: } 10575: 10576: sub authtype_names { 10577: my %lt = &Apache::lonlocal::texthash( 10578: int => 'Internal', 10579: krb4 => 'Kerberos 4', 10580: krb5 => 'Kerberos 5', 10581: loc => 'Local', 10582: lti => 'LTI', 10583: ); 10584: return %lt; 10585: } 10586: 10587: sub context_names { 10588: my %context_title = &Apache::lonlocal::texthash( 10589: author => 'Creating users when an Author', 10590: course => 'Creating users when in a course', 10591: domain => 'Creating users when a Domain Coordinator', 10592: ); 10593: return %context_title; 10594: } 10595: 10596: sub print_usermodification { 10597: my ($position,$dom,$settings,$rowtotal) = @_; 10598: my $numinrow = 4; 10599: my ($context,$datatable,$rowcount); 10600: if ($position eq 'top') { 10601: $rowcount = 0; 10602: $context = 'author'; 10603: foreach my $role ('ca','aa') { 10604: $datatable .= &modifiable_userdata_row($context,$role,$settings, 10605: $numinrow,$rowcount); 10606: $$rowtotal ++; 10607: $rowcount ++; 10608: } 10609: } elsif ($position eq 'bottom') { 10610: $context = 'course'; 10611: $rowcount = 0; 10612: foreach my $role ('st','ep','ta','in','cr') { 10613: $datatable .= &modifiable_userdata_row($context,$role,$settings, 10614: $numinrow,$rowcount); 10615: $$rowtotal ++; 10616: $rowcount ++; 10617: } 10618: } 10619: return $datatable; 10620: } 10621: 10622: sub print_defaults { 10623: my ($position,$dom,$settings,$rowtotal) = @_; 10624: my $rownum = 0; 10625: my ($datatable,$css_class,$titles); 10626: unless ($position eq 'bottom') { 10627: $titles = &defaults_titles($dom); 10628: } 10629: if ($position eq 'top') { 10630: my @items = ('auth_def','auth_arg_def','lang_def','timezone_def', 10631: 'datelocale_def','portal_def'); 10632: my %defaults; 10633: if (ref($settings) eq 'HASH') { 10634: %defaults = %{$settings}; 10635: } else { 10636: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 10637: foreach my $item (@items) { 10638: $defaults{$item} = $domdefaults{$item}; 10639: } 10640: } 10641: foreach my $item (@items) { 10642: if ($rownum%2) { 10643: $css_class = ''; 10644: } else { 10645: $css_class = ' class="LC_odd_row" '; 10646: } 10647: $datatable .= '<tr'.$css_class.'>'. 10648: '<td><span class="LC_nobreak">'.$titles->{$item}. 10649: '</span></td><td class="LC_right_item" colspan="3">'; 10650: if ($item eq 'auth_def') { 10651: my @authtypes = ('internal','krb4','krb5','localauth','lti'); 10652: my %shortauth = ( 10653: internal => 'int', 10654: krb4 => 'krb4', 10655: krb5 => 'krb5', 10656: localauth => 'loc', 10657: lti => 'lti', 10658: ); 10659: my %authnames = &authtype_names(); 10660: foreach my $auth (@authtypes) { 10661: my $checked = ' '; 10662: if ($defaults{$item} eq $auth) { 10663: $checked = ' checked="checked" '; 10664: } 10665: $datatable .= '<label><input type="radio" name="'.$item. 10666: '" value="'.$auth.'"'.$checked.'/>'. 10667: $authnames{$shortauth{$auth}}.'</label> '; 10668: } 10669: } elsif ($item eq 'timezone_def') { 10670: my $includeempty = 1; 10671: $datatable .= &Apache::loncommon::select_timezone($item,$defaults{$item},undef,$includeempty); 10672: } elsif ($item eq 'datelocale_def') { 10673: my $includeempty = 1; 10674: $datatable .= &Apache::loncommon::select_datelocale($item,$defaults{$item},undef,$includeempty); 10675: } elsif ($item eq 'lang_def') { 10676: my $includeempty = 1; 10677: $datatable .= &Apache::loncommon::select_language($item,$defaults{$item},$includeempty); 10678: } elsif ($item eq 'portal_def') { 10679: $datatable .= '<input type="text" name="'.$item.'" value="'. 10680: $defaults{$item}.'" size="25" onkeyup="portalExtras(this);" />'; 10681: my $portalsty = 'none'; 10682: if ($defaults{$item}) { 10683: $portalsty = 'block'; 10684: } 10685: foreach my $field ('email','web') { 10686: my $checkedoff = ' checked="checked"'; 10687: my $checkedon; 10688: if ($defaults{$item.'_'.$field}) { 10689: $checkedon = $checkedoff; 10690: $checkedoff = ''; 10691: } 10692: $datatable .= '<div id="'.$item.'_'.$field.'_div" style="display:'.$portalsty.'">'. 10693: '<span class="LC_nobreak">'.$titles->{$field}.' '. 10694: '<label><input type="radio" name="'.$item.'_'.$field.'" value="1"'.$checkedon.'/>'.&mt('Yes').'</label>'. 10695: (' 'x2). 10696: '<label><input type="radio" name="'.$item.'_'.$field.'" value="0"'.$checkedoff.'/>'.&mt('No').'</label>'. 10697: '</div>'; 10698: } 10699: } else { 10700: $datatable .= '<input type="text" name="'.$item.'" value="'.$defaults{$item}.'" />'; 10701: } 10702: $datatable .= '</td></tr>'; 10703: $rownum ++; 10704: } 10705: } elsif ($position eq 'middle') { 10706: my %defaults; 10707: if (ref($settings) eq 'HASH') { 10708: if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) { 10709: my $maxnum = @{$settings->{'inststatusorder'}}; 10710: for (my $i=0; $i<$maxnum; $i++) { 10711: $css_class = $rownum%2?' class="LC_odd_row"':''; 10712: my $item = $settings->{'inststatusorder'}->[$i]; 10713: my $title = $settings->{'inststatustypes'}->{$item}; 10714: my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"'; 10715: $datatable .= '<tr'.$css_class.'>'. 10716: '<td><span class="LC_nobreak">'. 10717: '<select name="inststatus_pos_'.$item.'"'.$chgstr.'>'; 10718: for (my $k=0; $k<=$maxnum; $k++) { 10719: my $vpos = $k+1; 10720: my $selstr; 10721: if ($k == $i) { 10722: $selstr = ' selected="selected" '; 10723: } 10724: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 10725: } 10726: $datatable .= '</select> '.&mt('Internal ID:').' <b>'.$item.'</b> '. 10727: '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'. 10728: &mt('delete').'</span></td>'. 10729: '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed').':'. 10730: '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'. 10731: '</span></td></tr>'; 10732: } 10733: $css_class = $rownum%2?' class="LC_odd_row"':''; 10734: my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"'; 10735: $datatable .= '<tr '.$css_class.'>'. 10736: '<td><span class="LC_nobreak"><select name="addinststatus_pos"'.$chgstr.'>'; 10737: for (my $k=0; $k<=$maxnum; $k++) { 10738: my $vpos = $k+1; 10739: my $selstr; 10740: if ($k == $maxnum) { 10741: $selstr = ' selected="selected" '; 10742: } 10743: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 10744: } 10745: $datatable .= '</select> '.&mt('Internal ID:'). 10746: '<input type="text" size="10" name="addinststatus" value="" />'. 10747: ' '.&mt('(new)'). 10748: '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'. 10749: &mt('Name displayed').':'. 10750: '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'. 10751: '</tr>'."\n"; 10752: $rownum ++; 10753: } 10754: } 10755: } else { 10756: my ($unamemaprules,$ruleorder) = 10757: &Apache::lonnet::inst_userrules($dom,'unamemap'); 10758: $css_class = $rownum%2?' class="LC_odd_row"':''; 10759: if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) { 10760: my $numinrow = 2; 10761: $datatable .= '<tr'.$css_class.'><td>'.&mt('Available conversions').'</td><td><table>'. 10762: &user_formats_row('unamemap',$settings,$unamemaprules, 10763: $ruleorder,$numinrow). 10764: '</table></td></tr>'; 10765: } 10766: if ($datatable eq '') { 10767: $datatable .= '<tr'.$css_class.'><td colspan="2">'. 10768: &mt('No rules set for domain in customized localenroll.pm'). 10769: '</td></tr>'; 10770: } 10771: } 10772: $$rowtotal += $rownum; 10773: return $datatable; 10774: } 10775: 10776: sub get_languages_hash { 10777: my %langchoices; 10778: foreach my $id (&Apache::loncommon::languageids()) { 10779: my $code = &Apache::loncommon::supportedlanguagecode($id); 10780: if ($code ne '') { 10781: $langchoices{$code} = &Apache::loncommon::plainlanguagedescription($id); 10782: } 10783: } 10784: return %langchoices; 10785: } 10786: 10787: sub defaults_titles { 10788: my ($dom) = @_; 10789: my %titles = &Apache::lonlocal::texthash ( 10790: 'auth_def' => 'Default authentication type', 10791: 'auth_arg_def' => 'Default authentication argument', 10792: 'lang_def' => 'Default language', 10793: 'timezone_def' => 'Default timezone', 10794: 'datelocale_def' => 'Default locale for dates', 10795: 'portal_def' => 'Portal/Default URL', 10796: 'email' => 'Email links use portal URL', 10797: 'web' => 'Public web links use portal URL', 10798: 'intauth_cost' => 'Encryption cost for bcrypt (positive integer)', 10799: 'intauth_check' => 'Check bcrypt cost if authenticated', 10800: 'intauth_switch' => 'Existing crypt-based switched to bcrypt on authentication', 10801: ); 10802: if ($dom) { 10803: my $uprimary_id = &Apache::lonnet::domain($dom,'primary'); 10804: my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id); 10805: my $protocol = $Apache::lonnet::protocol{$uprimary_id}; 10806: $protocol = 'http' if ($protocol ne 'https'); 10807: if ($uint_dom) { 10808: $titles{'portal_def'} .= ' '.&mt('(for example: [_1])',$protocol.'://loncapa.'. 10809: $uint_dom); 10810: } 10811: } 10812: return (\%titles); 10813: } 10814: 10815: sub print_scantron { 10816: my ($r,$position,$dom,$confname,$settings,$rowtotal) = @_; 10817: if ($position eq 'top') { 10818: return &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal); 10819: } else { 10820: return &print_scantronconfig($dom,$settings,\$rowtotal); 10821: } 10822: } 10823: 10824: sub scantron_javascript { 10825: return <<"ENDSCRIPT"; 10826: 10827: <script type="text/javascript"> 10828: // <![CDATA[ 10829: 10830: function toggleScantron(form) { 10831: var csvfieldset = new Array(); 10832: if (document.getElementById('scantroncsv_cols')) { 10833: csvfieldset.push(document.getElementById('scantroncsv_cols')); 10834: } 10835: if (document.getElementById('scantroncsv_options')) { 10836: csvfieldset.push(document.getElementById('scantroncsv_options')); 10837: } 10838: if (csvfieldset.length) { 10839: if (document.getElementById('scantronconfcsv')) { 10840: var scantroncsv = document.getElementById('scantronconfcsv'); 10841: if (scantroncsv.checked) { 10842: for (var i=0; i<csvfieldset.length; i++) { 10843: csvfieldset[i].style.display = 'block'; 10844: } 10845: } else { 10846: for (var i=0; i<csvfieldset.length; i++) { 10847: csvfieldset[i].style.display = 'none'; 10848: } 10849: var csvselects = document.getElementsByClassName('scantronconfig_csv'); 10850: if (csvselects.length) { 10851: for (var j=0; j<csvselects.length; j++) { 10852: csvselects[j].selectedIndex = 0; 10853: } 10854: } 10855: } 10856: } 10857: } 10858: return; 10859: } 10860: // ]]> 10861: </script> 10862: 10863: ENDSCRIPT 10864: 10865: } 10866: 10867: sub print_scantronformat { 10868: my ($r,$dom,$confname,$settings,$rowtotal) = @_; 10869: my $itemcount = 1; 10870: my ($datatable,$css_class,$scantronurl,$is_custom,%error,%scantronurls, 10871: %confhash); 10872: my $switchserver = &check_switchserver($dom,$confname); 10873: my %lt = &Apache::lonlocal::texthash ( 10874: default => 'Default bubblesheet format file error', 10875: custom => 'Custom bubblesheet format file error', 10876: ); 10877: my %scantronfiles = ( 10878: default => 'default.tab', 10879: custom => 'custom.tab', 10880: ); 10881: foreach my $key (keys(%scantronfiles)) { 10882: $scantronurls{$key} = '/res/'.$dom.'/'.$confname.'/scantron/' 10883: .$scantronfiles{$key}; 10884: } 10885: my @defaultinfo = &Apache::lonnet::stat_file($scantronurls{'default'}); 10886: if ((!@defaultinfo) || ($defaultinfo[0] eq 'no_such_dir')) { 10887: if (!$switchserver) { 10888: my $servadm = $r->dir_config('lonAdmEMail'); 10889: my ($configuserok,$author_ok) = &config_check($dom,$confname,$servadm); 10890: if ($configuserok eq 'ok') { 10891: if ($author_ok eq 'ok') { 10892: my %legacyfile = ( 10893: default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab', 10894: custom => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab', 10895: ); 10896: my %md5chk; 10897: foreach my $type (keys(%legacyfile)) { 10898: ($md5chk{$type}) = split(/ /,`md5sum $legacyfile{$type}`); 10899: chomp($md5chk{$type}); 10900: } 10901: if ($md5chk{'default'} ne $md5chk{'custom'}) { 10902: foreach my $type (keys(%legacyfile)) { 10903: ($scantronurls{$type},my $error) = 10904: &legacy_scantronformat($r,$dom,$confname, 10905: $type,$legacyfile{$type}, 10906: $scantronurls{$type}, 10907: $scantronfiles{$type}); 10908: if ($error ne '') { 10909: $error{$type} = $error; 10910: } 10911: } 10912: if (keys(%error) == 0) { 10913: $is_custom = 1; 10914: $confhash{'scantron'}{'scantronformat'} = 10915: $scantronurls{'custom'}; 10916: my $putresult = 10917: &Apache::lonnet::put_dom('configuration', 10918: \%confhash,$dom); 10919: if ($putresult ne 'ok') { 10920: $error{'custom'} = 10921: '<span class="LC_error">'. 10922: &mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>'; 10923: } 10924: } 10925: } else { 10926: ($scantronurls{'default'},my $error) = 10927: &legacy_scantronformat($r,$dom,$confname, 10928: 'default',$legacyfile{'default'}, 10929: $scantronurls{'default'}, 10930: $scantronfiles{'default'}); 10931: if ($error eq '') { 10932: $confhash{'scantron'}{'scantronformat'} = ''; 10933: my $putresult = 10934: &Apache::lonnet::put_dom('configuration', 10935: \%confhash,$dom); 10936: if ($putresult ne 'ok') { 10937: $error{'default'} = 10938: '<span class="LC_error">'. 10939: &mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>'; 10940: } 10941: } else { 10942: $error{'default'} = $error; 10943: } 10944: } 10945: } 10946: } 10947: } else { 10948: $error{'default'} = &mt("Unable to copy default bubblesheet formatfile to domain's RES space: [_1]",$switchserver); 10949: } 10950: } 10951: if (ref($settings) eq 'HASH') { 10952: if ($settings->{'scantronformat'} eq "/res/$dom/$confname/scantron/custom.tab") { 10953: my @info = &Apache::lonnet::stat_file($settings->{'scantronformat'}); 10954: if ((!@info) || ($info[0] eq 'no_such_dir')) { 10955: $scantronurl = ''; 10956: } else { 10957: $scantronurl = $settings->{'scantronformat'}; 10958: } 10959: $is_custom = 1; 10960: } else { 10961: $scantronurl = $scantronurls{'default'}; 10962: } 10963: } else { 10964: if ($is_custom) { 10965: $scantronurl = $scantronurls{'custom'}; 10966: } else { 10967: $scantronurl = $scantronurls{'default'}; 10968: } 10969: } 10970: $css_class = $itemcount%2?' class="LC_odd_row"':''; 10971: $datatable .= '<tr'.$css_class.'>'; 10972: if (!$is_custom) { 10973: $datatable .= '<td>'.&mt('Default in use:').'<br />'. 10974: '<span class="LC_nobreak">'; 10975: if ($scantronurl) { 10976: $datatable .= &Apache::loncommon::modal_link($scantronurl,&mt('Default bubblesheet format file'),600,500, 10977: undef,undef,undef,undef,'background-color:#ffffff'); 10978: } else { 10979: $datatable = &mt('File unavailable for display'); 10980: } 10981: $datatable .= '</span></td>'; 10982: if (keys(%error) == 0) { 10983: $datatable .= '<td style="vertical-align: bottom">'; 10984: if (!$switchserver) { 10985: $datatable .= &mt('Upload:').'<br />'; 10986: } 10987: } else { 10988: my $errorstr; 10989: foreach my $key (sort(keys(%error))) { 10990: $errorstr .= $lt{$key}.': '.$error{$key}.'<br />'; 10991: } 10992: $datatable .= '<td>'.$errorstr; 10993: } 10994: } else { 10995: if (keys(%error) > 0) { 10996: my $errorstr; 10997: foreach my $key (sort(keys(%error))) { 10998: $errorstr .= $lt{$key}.': '.$error{$key}.'<br />'; 10999: } 11000: $datatable .= '<td>'.$errorstr.'</td><td> '; 11001: } elsif ($scantronurl) { 11002: my $link = &Apache::loncommon::modal_link($scantronurl,&mt('Custom bubblesheet format file'),600,500, 11003: undef,undef,undef,undef,'background-color:#ffffff'); 11004: $datatable .= '<td><span class="LC_nobreak">'. 11005: $link. 11006: '<label><input type="checkbox" name="scantronformat_del"'. 11007: ' value="1" />'.&mt('Delete?').'</label></span></td>'. 11008: '<td><span class="LC_nobreak"> '. 11009: &mt('Replace:').'</span><br />'; 11010: } 11011: } 11012: if (keys(%error) == 0) { 11013: if ($switchserver) { 11014: $datatable .= &mt('Upload to library server: [_1]',$switchserver); 11015: } else { 11016: $datatable .='<span class="LC_nobreak"> '. 11017: '<input type="file" name="scantronformat" /></span>'; 11018: } 11019: } 11020: $datatable .= '</td></tr>'; 11021: $$rowtotal ++; 11022: return $datatable; 11023: } 11024: 11025: sub legacy_scantronformat { 11026: my ($r,$dom,$confname,$file,$legacyfile,$newurl,$newfile) = @_; 11027: my ($url,$error); 11028: my @statinfo = &Apache::lonnet::stat_file($newurl); 11029: if ((!@statinfo) || ($statinfo[0] eq 'no_such_dir')) { 11030: (my $result,$url) = 11031: &publishlogo($r,'copy',$legacyfile,$dom,$confname,'scantron', 11032: '','',$newfile); 11033: if ($result ne 'ok') { 11034: $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result); 11035: } 11036: } 11037: return ($url,$error); 11038: } 11039: 11040: sub print_scantronconfig { 11041: my ($dom,$settings,$rowtotal) = @_; 11042: my $itemcount = 2; 11043: my $is_checked = ' checked="checked"'; 11044: my %optionson = ( 11045: hdr => ' checked="checked"', 11046: pad => ' checked="checked"', 11047: rem => ' checked="checked"', 11048: ); 11049: my %optionsoff = ( 11050: hdr => '', 11051: pad => '', 11052: rem => '', 11053: ); 11054: my $currcsvsty = 'none'; 11055: my ($datatable,%csvfields,%checked,%onclick,%csvoptions); 11056: my @fields = &scantroncsv_fields(); 11057: my %titles = &scantronconfig_titles(); 11058: if (ref($settings) eq 'HASH') { 11059: if (ref($settings->{config}) eq 'HASH') { 11060: if ($settings->{config}->{dat}) { 11061: $checked{'dat'} = $is_checked; 11062: } 11063: if (ref($settings->{config}->{csv}) eq 'HASH') { 11064: if (ref($settings->{config}->{csv}->{fields}) eq 'HASH') { 11065: %csvfields = %{$settings->{config}->{csv}->{fields}}; 11066: if (keys(%csvfields) > 0) { 11067: $checked{'csv'} = $is_checked; 11068: $currcsvsty = 'block'; 11069: } 11070: } 11071: if (ref($settings->{config}->{csv}->{options}) eq 'HASH') { 11072: %csvoptions = %{$settings->{config}->{csv}->{options}}; 11073: foreach my $option (keys(%optionson)) { 11074: unless ($csvoptions{$option}) { 11075: $optionsoff{$option} = $optionson{$option}; 11076: $optionson{$option} = ''; 11077: } 11078: } 11079: } 11080: } 11081: } else { 11082: $checked{'dat'} = $is_checked; 11083: } 11084: } else { 11085: $checked{'dat'} = $is_checked; 11086: } 11087: $onclick{'csv'} = ' onclick="toggleScantron(this.form);"'; 11088: my $css_class = $itemcount%2? ' class="LC_odd_row"':''; 11089: $datatable = '<tr '.$css_class.'><td>'.&mt('Supported formats').'</td>'. 11090: '<td class="LC_left_item" valign="top"><span class="LC_nobreak">'; 11091: foreach my $item ('dat','csv') { 11092: my $id; 11093: if ($item eq 'csv') { 11094: $id = 'id="scantronconfcsv" '; 11095: } 11096: $datatable .= '<label><input type="checkbox" name="scantronconfig" '.$id.'value="'.$item.'"'.$checked{$item}.$onclick{$item}.' />'. 11097: $titles{$item}.'</label>'.(' 'x3); 11098: if ($item eq 'csv') { 11099: $datatable .= '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_cols">'. 11100: '<legend>'.&mt('CSV Column Mapping').'</legend>'. 11101: '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Location').'</th></tr>'."\n"; 11102: foreach my $col (@fields) { 11103: my $selnone; 11104: if ($csvfields{$col} eq '') { 11105: $selnone = ' selected="selected"'; 11106: } 11107: $datatable .= '<tr><td>'.$titles{$col}.'</td>'. 11108: '<td><select name="scantronconfig_csv_'.$col.'" class="scantronconfig_csv">'. 11109: '<option value=""'.$selnone.'></option>'; 11110: for (my $i=0; $i<20; $i++) { 11111: my $shown = $i+1; 11112: my $sel; 11113: unless ($selnone) { 11114: if (exists($csvfields{$col})) { 11115: if ($csvfields{$col} == $i) { 11116: $sel = ' selected="selected"'; 11117: } 11118: } 11119: } 11120: $datatable .= '<option value="'.$i.'"'.$sel.'>'.$shown.'</option>'; 11121: } 11122: $datatable .= '</select></td></tr>'; 11123: } 11124: $datatable .= '</table></fieldset>'. 11125: '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_options">'. 11126: '<legend>'.&mt('CSV Options').'</legend>'; 11127: foreach my $option ('hdr','pad','rem') { 11128: $datatable .= '<span class="LC_nobreak">'.$titles{$option}.':'. 11129: '<label><input type="radio" name="scantroncsv_'.$option.'" value="1"'.$optionson{$option}.' />'. 11130: &mt('Yes').'</label>'.(' 'x2)."\n". 11131: '<label><input type="radio" name="scantroncsv_'.$option.'" value="0"'.$optionsoff{$option}.' />'.&mt('No').'</label></span><br />'; 11132: } 11133: $datatable .= '</fieldset>'; 11134: $itemcount ++; 11135: } 11136: } 11137: $datatable .= '</td></tr>'; 11138: $$rowtotal ++; 11139: return $datatable; 11140: } 11141: 11142: sub scantronconfig_titles { 11143: return &Apache::lonlocal::texthash( 11144: dat => 'Standard format (.dat)', 11145: csv => 'Comma separated values (.csv)', 11146: hdr => 'Remove first line in file (contains column titles)', 11147: pad => 'Prepend 0s to PaperID', 11148: rem => 'Remove leading spaces (except Question Response columns)', 11149: CODE => 'CODE', 11150: ID => 'Student ID', 11151: PaperID => 'Paper ID', 11152: FirstName => 'First Name', 11153: LastName => 'Last Name', 11154: FirstQuestion => 'First Question Response', 11155: Section => 'Section', 11156: ); 11157: } 11158: 11159: sub scantroncsv_fields { 11160: return ('PaperID','LastName','FirstName','ID','Section','CODE','FirstQuestion'); 11161: } 11162: 11163: sub print_coursecategories { 11164: my ($position,$dom,$hdritem,$settings,$rowtotal) = @_; 11165: my $datatable; 11166: if ($position eq 'top') { 11167: my (%checked); 11168: my @catitems = ('unauth','auth'); 11169: my @cattypes = ('std','domonly','codesrch','none'); 11170: $checked{'unauth'} = 'std'; 11171: $checked{'auth'} = 'std'; 11172: if (ref($settings) eq 'HASH') { 11173: foreach my $type (@cattypes) { 11174: if ($type eq $settings->{'unauth'}) { 11175: $checked{'unauth'} = $type; 11176: } 11177: if ($type eq $settings->{'auth'}) { 11178: $checked{'auth'} = $type; 11179: } 11180: } 11181: } 11182: my %lt = &Apache::lonlocal::texthash ( 11183: unauth => 'Catalog type for unauthenticated users', 11184: auth => 'Catalog type for authenticated users', 11185: none => 'No catalog', 11186: std => 'Standard catalog', 11187: domonly => 'Domain-only catalog', 11188: codesrch => "Code search form", 11189: ); 11190: my $itemcount = 0; 11191: foreach my $item (@catitems) { 11192: my $css_class = $itemcount%2? ' class="LC_odd_row"':''; 11193: $datatable .= '<tr '.$css_class.'>'. 11194: '<td>'.$lt{$item}.'</td>'. 11195: '<td class="LC_right_item"><span class="LC_nobreak">'; 11196: foreach my $type (@cattypes) { 11197: my $ischecked; 11198: if ($checked{$item} eq $type) { 11199: $ischecked=' checked="checked"'; 11200: } 11201: $datatable .= '<label>'. 11202: '<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked. 11203: ' />'.$lt{$type}.'</label> '; 11204: } 11205: $datatable .= '</span></td></tr>'; 11206: $itemcount ++; 11207: } 11208: $$rowtotal += $itemcount; 11209: } elsif ($position eq 'middle') { 11210: my $toggle_cats_crs = ' '; 11211: my $toggle_cats_dom = ' checked="checked" '; 11212: my $can_cat_crs = ' '; 11213: my $can_cat_dom = ' checked="checked" '; 11214: my $toggle_catscomm_comm = ' '; 11215: my $toggle_catscomm_dom = ' checked="checked" '; 11216: my $can_catcomm_comm = ' '; 11217: my $can_catcomm_dom = ' checked="checked" '; 11218: my $toggle_catsplace_place = ' '; 11219: my $toggle_catsplace_dom = ' checked="checked" '; 11220: my $can_catplace_place = ' '; 11221: my $can_catplace_dom = ' checked="checked" '; 11222: 11223: if (ref($settings) eq 'HASH') { 11224: if ($settings->{'togglecats'} eq 'crs') { 11225: $toggle_cats_crs = $toggle_cats_dom; 11226: $toggle_cats_dom = ' '; 11227: } 11228: if ($settings->{'categorize'} eq 'crs') { 11229: $can_cat_crs = $can_cat_dom; 11230: $can_cat_dom = ' '; 11231: } 11232: if ($settings->{'togglecatscomm'} eq 'comm') { 11233: $toggle_catscomm_comm = $toggle_catscomm_dom; 11234: $toggle_catscomm_dom = ' '; 11235: } 11236: if ($settings->{'categorizecomm'} eq 'comm') { 11237: $can_catcomm_comm = $can_catcomm_dom; 11238: $can_catcomm_dom = ' '; 11239: } 11240: if ($settings->{'togglecatsplace'} eq 'place') { 11241: $toggle_catsplace_place = $toggle_catsplace_dom; 11242: $toggle_catsplace_dom = ' '; 11243: } 11244: if ($settings->{'categorizeplace'} eq 'place') { 11245: $can_catplace_place = $can_catplace_dom; 11246: $can_catplace_dom = ' '; 11247: } 11248: } 11249: my %title = &Apache::lonlocal::texthash ( 11250: togglecats => 'Show/Hide a course in catalog', 11251: togglecatscomm => 'Show/Hide a community in catalog', 11252: togglecatsplace => 'Show/Hide a placement test in catalog', 11253: categorize => 'Assign a category to a course', 11254: categorizecomm => 'Assign a category to a community', 11255: categorizeplace => 'Assign a category to a placement test', 11256: ); 11257: my %level = &Apache::lonlocal::texthash ( 11258: dom => 'Set in Domain', 11259: crs => 'Set in Course', 11260: comm => 'Set in Community', 11261: place => 'Set in Placement Test', 11262: ); 11263: $datatable = '<tr class="LC_odd_row">'. 11264: '<td>'.$title{'togglecats'}.'</td>'. 11265: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 11266: '<input type="radio" name="togglecats"'. 11267: $toggle_cats_dom.' value="dom" />'.$level{'dom'}.'</label> '. 11268: '<label><input type="radio" name="togglecats"'. 11269: $toggle_cats_crs.' value="crs" />'.$level{'crs'}.'</label></span></td>'. 11270: '</tr><tr>'. 11271: '<td>'.$title{'categorize'}.'</td>'. 11272: '<td class="LC_right_item"><span class="LC_nobreak">'. 11273: '<label><input type="radio" name="categorize"'. 11274: $can_cat_dom.' value="dom" />'.$level{'dom'}.'</label> '. 11275: '<label><input type="radio" name="categorize"'. 11276: $can_cat_crs.'value="crs" />'.$level{'crs'}.'</label></span></td>'. 11277: '</tr><tr class="LC_odd_row">'. 11278: '<td>'.$title{'togglecatscomm'}.'</td>'. 11279: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 11280: '<input type="radio" name="togglecatscomm"'. 11281: $toggle_catscomm_dom.' value="dom" />'.$level{'dom'}.'</label> '. 11282: '<label><input type="radio" name="togglecatscomm"'. 11283: $toggle_catscomm_comm.' value="comm" />'.$level{'comm'}.'</label></span></td>'. 11284: '</tr><tr>'. 11285: '<td>'.$title{'categorizecomm'}.'</td>'. 11286: '<td class="LC_right_item"><span class="LC_nobreak">'. 11287: '<label><input type="radio" name="categorizecomm"'. 11288: $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label> '. 11289: '<label><input type="radio" name="categorizecomm"'. 11290: $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'. 11291: '</tr><tr class="LC_odd_row">'. 11292: '<td>'.$title{'togglecatsplace'}.'</td>'. 11293: '<td class="LC_right_item"><span class="LC_nobreak"><label>'. 11294: '<input type="radio" name="togglecatsplace"'. 11295: $toggle_catsplace_dom.' value="dom" />'.$level{'dom'}.'</label> '. 11296: '<label><input type="radio" name="togglecatscomm"'. 11297: $toggle_catsplace_place.' value="comm" />'.$level{'place'}.'</label></span></td>'. 11298: '</tr><tr>'. 11299: '<td>'.$title{'categorizeplace'}.'</td>'. 11300: '<td class="LC_right_item"><span class="LC_nobreak">'. 11301: '<label><input type="radio" name="categorizeplace"'. 11302: $can_catplace_dom.' value="dom" />'.$level{'dom'}.'</label> '. 11303: '<label><input type="radio" name="categorizeplace"'. 11304: $can_catplace_place.'value="place" />'.$level{'place'}.'</label></span></td>'. 11305: '</tr>'; 11306: $$rowtotal += 6; 11307: } else { 11308: my $css_class; 11309: my $itemcount = 1; 11310: my $cathash; 11311: if (ref($settings) eq 'HASH') { 11312: $cathash = $settings->{'cats'}; 11313: } 11314: if (ref($cathash) eq 'HASH') { 11315: my (@cats,@trails,%allitems,%idx,@jsarray); 11316: &Apache::loncommon::extract_categories($cathash,\@cats,\@trails, 11317: \%allitems,\%idx,\@jsarray); 11318: my $maxdepth = scalar(@cats); 11319: my $colattrib = ''; 11320: if ($maxdepth > 2) { 11321: $colattrib = ' colspan="2" '; 11322: } 11323: my @path; 11324: if (@cats > 0) { 11325: if (ref($cats[0]) eq 'ARRAY') { 11326: my $numtop = @{$cats[0]}; 11327: my $maxnum = $numtop; 11328: my %default_names = ( 11329: instcode => &mt('Official courses'), 11330: communities => &mt('Communities'), 11331: placement => &mt('Placement Tests'), 11332: ); 11333: 11334: if ((!grep(/^instcode$/,@{$cats[0]})) || 11335: ($cathash->{'instcode::0'} eq '') || 11336: (!grep(/^communities$/,@{$cats[0]})) || 11337: ($cathash->{'communities::0'} eq '') || 11338: (!grep(/^placement$/,@{$cats[0]})) || 11339: ($cathash->{'placement::0'} eq '')) { 11340: $maxnum ++; 11341: } 11342: my $lastidx; 11343: for (my $i=0; $i<$numtop; $i++) { 11344: my $parent = $cats[0][$i]; 11345: $css_class = $itemcount%2?' class="LC_odd_row"':''; 11346: my $item = &escape($parent).'::0'; 11347: my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$item','$idx{$item}'".');"'; 11348: $lastidx = $idx{$item}; 11349: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 11350: .'<select name="'.$item.'"'.$chgstr.'>'; 11351: for (my $k=0; $k<=$maxnum; $k++) { 11352: my $vpos = $k+1; 11353: my $selstr; 11354: if ($k == $i) { 11355: $selstr = ' selected="selected" '; 11356: } 11357: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 11358: } 11359: $datatable .= '</select></span></td><td>'; 11360: if ($parent eq 'instcode' || $parent eq 'communities' || $parent eq 'placement') { 11361: $datatable .= '<span class="LC_nobreak">' 11362: .$default_names{$parent}.'</span>'; 11363: if ($parent eq 'instcode') { 11364: $datatable .= '<br /><span class="LC_nobreak">(' 11365: .&mt('with institutional codes') 11366: .')</span></td><td'.$colattrib.'>'; 11367: } else { 11368: $datatable .= '<table><tr><td>'; 11369: } 11370: $datatable .= '<span class="LC_nobreak">' 11371: .'<label><input type="radio" name="' 11372: .$parent.'" value="1" checked="checked" />' 11373: .&mt('Display').'</label>'; 11374: if ($parent eq 'instcode') { 11375: $datatable .= ' '; 11376: } else { 11377: $datatable .= '</span></td></tr><tr><td>' 11378: .'<span class="LC_nobreak">'; 11379: } 11380: $datatable .= '<label><input type="radio" name="' 11381: .$parent.'" value="0" />' 11382: .&mt('Do not display').'</label></span>'; 11383: if (($parent eq 'communities') || ($parent eq 'placement')) { 11384: $datatable .= '</td></tr></table>'; 11385: } 11386: $datatable .= '</td>'; 11387: } else { 11388: $datatable .= $parent 11389: .' <span class="LC_nobreak"><label>' 11390: .'<input type="checkbox" name="deletecategory" ' 11391: .'value="'.$item.'" />'.&mt('Delete').'</label></span></td>'; 11392: } 11393: my $depth = 1; 11394: push(@path,$parent); 11395: $datatable .= &build_category_rows($itemcount,\@cats,$depth,$parent,\@path,\%idx); 11396: pop(@path); 11397: $datatable .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>'; 11398: $itemcount ++; 11399: } 11400: $css_class = $itemcount%2?' class="LC_odd_row"':''; 11401: my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','addcategory_pos','$lastidx'".');"'; 11402: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak"><select name="addcategory_pos"'.$chgstr.'>'; 11403: for (my $k=0; $k<=$maxnum; $k++) { 11404: my $vpos = $k+1; 11405: my $selstr; 11406: if ($k == $numtop) { 11407: $selstr = ' selected="selected" '; 11408: } 11409: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 11410: } 11411: $datatable .= '</select></span></td><td colspan="2">'.&mt('Add category:').' ' 11412: .'<input type="text" size="20" name="addcategory_name" value="" /></td>' 11413: .'</tr>'."\n"; 11414: $itemcount ++; 11415: foreach my $default ('instcode','communities','placement') { 11416: if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) { 11417: $css_class = $itemcount%2?' class="LC_odd_row"':''; 11418: my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"'; 11419: $datatable .= '<tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr><tr '.$css_class.'><td>'. 11420: '<span class="LC_nobreak"><select name="'.$default.'_pos"'.$chgstr.'>'; 11421: for (my $k=0; $k<=$maxnum; $k++) { 11422: my $vpos = $k+1; 11423: my $selstr; 11424: if ($k == $maxnum) { 11425: $selstr = ' selected="selected" '; 11426: } 11427: $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; 11428: } 11429: $datatable .= '</select></span></td>'. 11430: '<td><span class="LC_nobreak">'. 11431: $default_names{$default}.'</span>'; 11432: if ($default eq 'instcode') { 11433: $datatable .= '<br /><span class="LC_nobreak">(' 11434: .&mt('with institutional codes').')</span>'; 11435: } 11436: $datatable .= '</td>' 11437: .'<td><span class="LC_nobreak"><label><input type="radio" name="'.$default.'" value="1" />' 11438: .&mt('Display').'</label> ' 11439: .'<label><input type="radio" name="'.$default.'" value="0" checked="checked"/>' 11440: .&mt('Do not display').'</label></span></td></tr>'; 11441: } 11442: } 11443: } 11444: } else { 11445: $datatable .= &initialize_categories($itemcount); 11446: } 11447: } else { 11448: $datatable .= '<tr><td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td></tr>' 11449: .&initialize_categories($itemcount); 11450: } 11451: $$rowtotal += $itemcount; 11452: } 11453: return $datatable; 11454: } 11455: 11456: sub print_serverstatuses { 11457: my ($dom,$settings,$rowtotal) = @_; 11458: my $datatable; 11459: my @pages = &serverstatus_pages(); 11460: my (%namedaccess,%machineaccess); 11461: foreach my $type (@pages) { 11462: $namedaccess{$type} = ''; 11463: $machineaccess{$type}= ''; 11464: } 11465: if (ref($settings) eq 'HASH') { 11466: foreach my $type (@pages) { 11467: if (exists($settings->{$type})) { 11468: if (ref($settings->{$type}) eq 'HASH') { 11469: foreach my $key (keys(%{$settings->{$type}})) { 11470: if ($key eq 'namedusers') { 11471: $namedaccess{$type} = $settings->{$type}->{$key}; 11472: } elsif ($key eq 'machines') { 11473: $machineaccess{$type} = $settings->{$type}->{$key}; 11474: } 11475: } 11476: } 11477: } 11478: } 11479: } 11480: my $titles= &LONCAPA::lonauthcgi::serverstatus_titles(); 11481: my $rownum = 0; 11482: my $css_class; 11483: foreach my $type (@pages) { 11484: $rownum ++; 11485: $css_class = $rownum%2?' class="LC_odd_row"':''; 11486: $datatable .= '<tr'.$css_class.'>'. 11487: '<td><span class="LC_nobreak">'. 11488: $titles->{$type}.'</span></td>'. 11489: '<td class="LC_left_item">'. 11490: '<input type="text" name="'.$type.'_namedusers" '. 11491: 'value="'.$namedaccess{$type}.'" size="30" /></td>'. 11492: '<td class="LC_right_item">'. 11493: '<span class="LC_nobreak">'. 11494: '<input type="text" name="'.$type.'_machines" '. 11495: 'value="'.$machineaccess{$type}.'" size="10" />'. 11496: '</span></td></tr>'."\n"; 11497: } 11498: $$rowtotal += $rownum; 11499: return $datatable; 11500: } 11501: 11502: sub serverstatus_pages { 11503: return ('userstatus','lonstatus','loncron','server-status','codeversions', 11504: 'checksums','clusterstatus','certstatus','metadata_keywords', 11505: 'metadata_harvest','takeoffline','takeonline','showenv','toggledebug', 11506: 'ping','domconf','uniquecodes','diskusage','coursecatalog'); 11507: } 11508: 11509: sub defaults_javascript { 11510: my ($settings) = @_; 11511: return unless (ref($settings) eq 'HASH'); 11512: my $portal_js = <<"ENDPORTAL"; 11513: 11514: function portalExtras(caller) { 11515: var x = caller.value; 11516: var y = new Array('email','web'); 11517: for (var i=0; i<y.length; i++) { 11518: if (document.getElementById('portal_def_'+y[i]+'_div')) { 11519: var z = document.getElementById('portal_def_'+y[i]+'_div'); 11520: if (x.length > 0) { 11521: z.style.display = 'block'; 11522: } else { 11523: z.style.display = 'none'; 11524: } 11525: } 11526: } 11527: } 11528: ENDPORTAL 11529: if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) { 11530: my $maxnum = scalar(@{$settings->{'inststatusorder'}}); 11531: if ($maxnum eq '') { 11532: $maxnum = 0; 11533: } 11534: $maxnum ++; 11535: my $jstext = ' var inststatuses = Array('."'".join("','",@{$settings->{'inststatusorder'}})."'".');'; 11536: return <<"ENDSCRIPT"; 11537: <script type="text/javascript"> 11538: // <![CDATA[ 11539: function reorderTypes(form,caller) { 11540: var changedVal; 11541: $jstext 11542: var newpos = 'addinststatus_pos'; 11543: var current = new Array; 11544: var maxh = $maxnum; 11545: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 11546: var oldVal; 11547: if (caller == newpos) { 11548: changedVal = newitemVal; 11549: } else { 11550: var curritem = 'inststatus_pos_'+caller; 11551: changedVal = form.elements[curritem].options[form.elements[curritem].selectedIndex].value; 11552: current[newitemVal] = newpos; 11553: } 11554: for (var i=0; i<inststatuses.length; i++) { 11555: if (inststatuses[i] != caller) { 11556: var elementName = 'inststatus_pos_'+inststatuses[i]; 11557: if (form.elements[elementName]) { 11558: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 11559: current[currVal] = elementName; 11560: } 11561: } 11562: } 11563: for (var j=0; j<maxh; j++) { 11564: if (current[j] == undefined) { 11565: oldVal = j; 11566: } 11567: } 11568: if (oldVal < changedVal) { 11569: for (var k=oldVal+1; k<=changedVal ; k++) { 11570: var elementName = current[k]; 11571: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 11572: } 11573: } else { 11574: for (var k=changedVal; k<oldVal; k++) { 11575: var elementName = current[k]; 11576: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 11577: } 11578: } 11579: return; 11580: } 11581: 11582: $portal_js 11583: 11584: // ]]> 11585: </script> 11586: 11587: ENDSCRIPT 11588: } else { 11589: return <<"ENDSCRIPT"; 11590: <script type="text/javascript"> 11591: // <![CDATA[ 11592: $portal_js 11593: // ]]> 11594: </script> 11595: 11596: ENDSCRIPT 11597: } 11598: return; 11599: } 11600: 11601: sub passwords_javascript { 11602: my ($prefix) = @_; 11603: my %intalert; 11604: if ($prefix eq 'passwords') { 11605: %intalert = &Apache::lonlocal::texthash ( 11606: 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.', 11607: authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.', 11608: passmin => 'Warning: minimum password length must be a positive integer greater than 6.', 11609: passmax => 'Warning: maximum password length must be a positive integer (or blank).', 11610: passexp => 'Warning: days before password expiration must be a positive integer (or blank).', 11611: passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).', 11612: ); 11613: } elsif ($prefix eq 'secrets') { 11614: %intalert = &Apache::lonlocal::texthash ( 11615: passmin => 'Warning: minimum secret length must be a positive integer greater than 6.', 11616: passmax => 'Warning: maximum secret length must be a positive integer (or blank).', 11617: ); 11618: } 11619: &js_escape(\%intalert); 11620: my $defmin = $Apache::lonnet::passwdmin; 11621: my $intauthjs; 11622: if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT"; 11623: 11624: function warnIntAuth(field) { 11625: if (field.name == 'intauth_check') { 11626: if (field.value == '2') { 11627: alert('$intalert{authcheck}'); 11628: } 11629: } 11630: if (field.name == 'intauth_cost') { 11631: field.value.replace(/\s/g,''); 11632: if (field.value != '') { 11633: var regexdigit=/^\\d+\$/; 11634: if (!regexdigit.test(field.value)) { 11635: alert('$intalert{authcost}'); 11636: } 11637: } 11638: } 11639: return; 11640: } 11641: 11642: ENDSCRIPT 11643: 11644: } 11645: 11646: $intauthjs .= <<"ENDSCRIPT"; 11647: 11648: function warnInt$prefix(field) { 11649: field.value.replace(/^\s+/,''); 11650: field.value.replace(/\s+\$/,''); 11651: var regexdigit=/^\\d+\$/; 11652: if (field.name == '${prefix}_min') { 11653: if (field.value == '') { 11654: alert('$intalert{passmin}'); 11655: field.value = '$defmin'; 11656: } else { 11657: if (!regexdigit.test(field.value)) { 11658: alert('$intalert{passmin}'); 11659: field.value = '$defmin'; 11660: } 11661: var minval = parseInt(field.value,10); 11662: if (minval < $defmin) { 11663: alert('$intalert{passmin}'); 11664: field.value = '$defmin'; 11665: } 11666: } 11667: } else { 11668: if (field.value == '0') { 11669: field.value = ''; 11670: } 11671: if (field.value != '') { 11672: if (field.name == '${prefix}_expire') { 11673: var regexpposnum=/^\\d+(|\\.\\d*)\$/; 11674: if (!regexpposnum.test(field.value)) { 11675: alert('$intalert{passexp}'); 11676: field.value = ''; 11677: } else { 11678: var expval = parseFloat(field.value); 11679: if (expval == 0) { 11680: alert('$intalert{passexp}'); 11681: field.value = ''; 11682: } 11683: } 11684: } else { 11685: if (!regexdigit.test(field.value)) { 11686: if (field.name == '${prefix}_max') { 11687: alert('$intalert{passmax}'); 11688: } else { 11689: if (field.name == '${prefix}_numsaved') { 11690: alert('$intalert{passnum}'); 11691: } 11692: } 11693: field.value = ''; 11694: } 11695: } 11696: } 11697: } 11698: return; 11699: } 11700: 11701: ENDSCRIPT 11702: return &Apache::lonhtmlcommon::scripttag($intauthjs); 11703: } 11704: 11705: sub coursecategories_javascript { 11706: my ($settings) = @_; 11707: my ($output,$jstext,$cathash); 11708: if (ref($settings) eq 'HASH') { 11709: $cathash = $settings->{'cats'}; 11710: } 11711: if (ref($cathash) eq 'HASH') { 11712: my (@cats,@jsarray,%idx); 11713: &Apache::loncommon::gather_categories($cathash,\@cats,\%idx,\@jsarray); 11714: if (@jsarray > 0) { 11715: $jstext = ' var categories = Array('.scalar(@jsarray).');'."\n"; 11716: for (my $i=0; $i<@jsarray; $i++) { 11717: if (ref($jsarray[$i]) eq 'ARRAY') { 11718: my $catstr = join('","',@{$jsarray[$i]}); 11719: $jstext .= ' categories['.$i.'] = Array("'.$catstr.'");'."\n"; 11720: } 11721: } 11722: } 11723: } else { 11724: $jstext = ' var categories = Array(1);'."\n". 11725: ' categories[0] = Array("instcode_pos");'."\n"; 11726: } 11727: my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"'); 11728: my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"'); 11729: my $placement_reserved = &mt('The name: [_1] is a reserved category.','"placement"'); 11730: my $choose_again = "\n".&mt('Please use a different name for the new top level category.'); 11731: &js_escape(\$instcode_reserved); 11732: &js_escape(\$communities_reserved); 11733: &js_escape(\$placement_reserved); 11734: &js_escape(\$choose_again); 11735: $output = <<"ENDSCRIPT"; 11736: <script type="text/javascript"> 11737: // <![CDATA[ 11738: function reorderCats(form,parent,item,idx) { 11739: var changedVal; 11740: $jstext 11741: var newpos = 'addcategory_pos'; 11742: if (parent == '') { 11743: var has_instcode = 0; 11744: var maxtop = categories[idx].length; 11745: for (var j=0; j<maxtop; j++) { 11746: if (categories[idx][j] == 'instcode::0') { 11747: has_instcode == 1; 11748: } 11749: } 11750: if (has_instcode == 0) { 11751: categories[idx][maxtop] = 'instcode_pos'; 11752: } 11753: } else { 11754: newpos += '_'+parent; 11755: } 11756: var maxh = 1 + categories[idx].length; 11757: var current = new Array; 11758: var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; 11759: if (item == newpos) { 11760: changedVal = newitemVal; 11761: } else { 11762: changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; 11763: current[newitemVal] = newpos; 11764: } 11765: for (var i=0; i<categories[idx].length; i++) { 11766: var elementName = categories[idx][i]; 11767: if (elementName != item) { 11768: if (form.elements[elementName]) { 11769: var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; 11770: current[currVal] = elementName; 11771: } 11772: } 11773: } 11774: var oldVal; 11775: for (var j=0; j<maxh; j++) { 11776: if (current[j] == undefined) { 11777: oldVal = j; 11778: } 11779: } 11780: if (oldVal < changedVal) { 11781: for (var k=oldVal+1; k<=changedVal ; k++) { 11782: var elementName = current[k]; 11783: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; 11784: } 11785: } else { 11786: for (var k=changedVal; k<oldVal; k++) { 11787: var elementName = current[k]; 11788: form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; 11789: } 11790: } 11791: return; 11792: } 11793: 11794: function categoryCheck(form) { 11795: if (form.elements['addcategory_name'].value == 'instcode') { 11796: alert('$instcode_reserved\\n$choose_again'); 11797: return false; 11798: } 11799: if (form.elements['addcategory_name'].value == 'communities') { 11800: alert('$communities_reserved\\n$choose_again'); 11801: return false; 11802: } 11803: if (form.elements['addcategory_name'].value == 'placement') { 11804: alert('$placement_reserved\\n$choose_again'); 11805: return false; 11806: } 11807: return true; 11808: } 11809: 11810: // ]]> 11811: </script> 11812: 11813: ENDSCRIPT 11814: return $output; 11815: } 11816: 11817: sub initialize_categories { 11818: my ($itemcount) = @_; 11819: my ($datatable,$css_class,$chgstr); 11820: my %default_names = &Apache::lonlocal::texthash ( 11821: instcode => 'Official courses (with institutional codes)', 11822: communities => 'Communities', 11823: placement => 'Placement Tests', 11824: ); 11825: my %selnum = ( 11826: instcode => '0', 11827: communities => '1', 11828: placement => '2', 11829: ); 11830: my %selected; 11831: foreach my $default ('instcode','communities','placement') { 11832: $css_class = $itemcount%2?' class="LC_odd_row"':''; 11833: $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"'; 11834: map { $selected{$selnum{$_}} = '' } keys(%selnum); 11835: $selected{$selnum{$default}} = ' selected="selected"'; 11836: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 11837: .'<select name="'.$default.'_pos"'.$chgstr.'>' 11838: .'<option value="0"'.$selected{'0'}.'>1</option>' 11839: .'<option value="1"'.$selected{'1'}.'>2</option>' 11840: .'<option value="2"'.$selected{'2'}.'>3</option>' 11841: .'<option value="3">4</option></select> ' 11842: .$default_names{$default} 11843: .'</span></td><td><span class="LC_nobreak">' 11844: .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />' 11845: .&mt('Display').'</label> <label>' 11846: .'<input type="radio" name="'.$default.'" value="0" />'.&mt('Do not display') 11847: .'</label></span></td></tr>'; 11848: $itemcount ++; 11849: } 11850: $css_class = $itemcount%2?' class="LC_odd_row"':''; 11851: $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','addcategory_pos','0'".');"'; 11852: $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' 11853: .'<select name="addcategory_pos"'.$chgstr.'>' 11854: .'<option value="0">1</option>' 11855: .'<option value="1">2</option>' 11856: .'<option value="2">3</option>' 11857: .'<option value="3" selected="selected">4</option></select> ' 11858: .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:') 11859: .' <input type="text" size="20" name="addcategory_name" value="" /></span>' 11860: .'</td></tr>'; 11861: return $datatable; 11862: } 11863: 11864: sub build_category_rows { 11865: my ($itemcount,$cats,$depth,$parent,$path,$idx) = @_; 11866: my ($text,$name,$item,$chgstr); 11867: if (ref($cats) eq 'ARRAY') { 11868: my $maxdepth = scalar(@{$cats}); 11869: if (ref($cats->[$depth]) eq 'HASH') { 11870: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') { 11871: my $numchildren = @{$cats->[$depth]{$parent}}; 11872: my $css_class = $itemcount%2?' class="LC_odd_row"':''; 11873: $text .= '<td><table class="LC_data_table">'; 11874: my ($idxnum,$parent_name,$parent_item); 11875: my $higher = $depth - 1; 11876: if ($higher == 0) { 11877: $parent_name = &escape($parent).'::'.$higher; 11878: } else { 11879: if (ref($path) eq 'ARRAY') { 11880: $parent_name = &escape($parent).':'.&escape($path->[-2]).':'.$higher; 11881: } 11882: } 11883: $parent_item = 'addcategory_pos_'.$parent_name; 11884: for (my $j=0; $j<=$numchildren; $j++) { 11885: if ($j < $numchildren) { 11886: $name = $cats->[$depth]{$parent}[$j]; 11887: $item = &escape($name).':'.&escape($parent).':'.$depth; 11888: $idxnum = $idx->{$item}; 11889: } else { 11890: $name = $parent_name; 11891: $item = $parent_item; 11892: } 11893: $chgstr = ' onchange="javascript:reorderCats(this.form,'."'$parent_name','$item','$idxnum'".');"'; 11894: $text .= '<tr '.$css_class.'><td><span class="LC_nobreak"><select name="'.$item.'"'.$chgstr.'>'; 11895: for (my $i=0; $i<=$numchildren; $i++) { 11896: my $vpos = $i+1; 11897: my $selstr; 11898: if ($j == $i) { 11899: $selstr = ' selected="selected" '; 11900: } 11901: $text .= '<option value="'.$i.'"'.$selstr.'>'.$vpos.'</option>'; 11902: } 11903: $text .= '</select> '; 11904: if ($j < $numchildren) { 11905: my $deeper = $depth+1; 11906: $text .= $name.' ' 11907: .'<label><input type="checkbox" name="deletecategory" value="' 11908: .$item.'" />'.&mt('Delete').'</label></span></td><td>'; 11909: if(ref($path) eq 'ARRAY') { 11910: push(@{$path},$name); 11911: $text .= &build_category_rows($itemcount,$cats,$deeper,$name,$path,$idx); 11912: pop(@{$path}); 11913: } 11914: } else { 11915: $text .= &mt('Add subcategory:').' </span><input type="text" size="20" name="addcategory_name_'; 11916: if ($j == $numchildren) { 11917: $text .= $name; 11918: } else { 11919: $text .= $item; 11920: } 11921: $text .= '" value="" />'; 11922: } 11923: $text .= '</td></tr>'; 11924: } 11925: $text .= '</table></td>'; 11926: } else { 11927: my $higher = $depth-1; 11928: if ($higher == 0) { 11929: $name = &escape($parent).'::'.$higher; 11930: } else { 11931: if (ref($path) eq 'ARRAY') { 11932: $name = &escape($parent).':'.&escape($path->[-2]).':'.$higher; 11933: } 11934: } 11935: my $colspan; 11936: if ($parent ne 'instcode') { 11937: $colspan = $maxdepth - $depth - 1; 11938: $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="text" size="20" name="subcat_'.$name.'" value="" /></td>'; 11939: } 11940: } 11941: } 11942: } 11943: return $text; 11944: } 11945: 11946: sub modifiable_userdata_row { 11947: my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref, 11948: $rowid,$customcss,$rowstyle,$itemdesc) = @_; 11949: my ($role,$rolename,$statustype); 11950: $role = $item; 11951: if ($context eq 'cancreate') { 11952: if ($item =~ /^(emailusername)_(.+)$/) { 11953: $role = $1; 11954: $statustype = $2; 11955: if (ref($usertypes) eq 'HASH') { 11956: if ($usertypes->{$statustype}) { 11957: $rolename = &mt('Data provided by [_1]',$usertypes->{$statustype}); 11958: } else { 11959: $rolename = &mt('Data provided by user'); 11960: } 11961: } 11962: } 11963: } elsif ($context eq 'selfcreate') { 11964: if (ref($usertypes) eq 'HASH') { 11965: $rolename = $usertypes->{$role}; 11966: } else { 11967: $rolename = $role; 11968: } 11969: } elsif ($context eq 'lti') { 11970: $rolename = &mt('Institutional data used (if available)'); 11971: } elsif ($context eq 'privacy') { 11972: $rolename = $itemdesc; 11973: } else { 11974: if ($role eq 'cr') { 11975: $rolename = &mt('Custom role'); 11976: } else { 11977: $rolename = &Apache::lonnet::plaintext($role); 11978: } 11979: } 11980: my (@fields,%fieldtitles); 11981: if (ref($fieldsref) eq 'ARRAY') { 11982: @fields = @{$fieldsref}; 11983: } else { 11984: @fields = ('lastname','firstname','middlename','generation', 11985: 'permanentemail','id'); 11986: } 11987: if ((ref($titlesref) eq 'HASH')) { 11988: %fieldtitles = %{$titlesref}; 11989: } else { 11990: %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 11991: } 11992: my $output; 11993: my $css_class; 11994: if ($rowcount%2) { 11995: $css_class = 'LC_odd_row'; 11996: } 11997: if ($customcss) { 11998: $css_class .= " $customcss"; 11999: } 12000: $css_class =~ s/^\s+//; 12001: if ($css_class) { 12002: $css_class = ' class="'.$css_class.'"'; 12003: } 12004: if ($rowstyle) { 12005: $css_class .= ' style="'.$rowstyle.'"'; 12006: } 12007: if ($rowid) { 12008: $rowid = ' id="'.$rowid.'"'; 12009: } 12010: $output = '<tr '.$css_class.$rowid.'>'. 12011: '<td><span class="LC_nobreak">'.$rolename.'</span></td>'. 12012: '<td class="LC_left_item" colspan="2"><table>'; 12013: my $rem; 12014: my %checks; 12015: my %current; 12016: if (ref($settings) eq 'HASH') { 12017: my $hashref; 12018: if ($context eq 'lti') { 12019: if (ref($settings) eq 'HASH') { 12020: $hashref = $settings->{'instdata'}; 12021: } 12022: } elsif ($context eq 'privacy') { 12023: my ($key,$inner) = split(/_/,$role); 12024: if (ref($settings) eq 'HASH') { 12025: if (ref($settings->{$key}) eq 'HASH') { 12026: $hashref = $settings->{$key}->{$inner}; 12027: } 12028: } 12029: } elsif (ref($settings->{$context}) eq 'HASH') { 12030: if (ref($settings->{$context}->{$role}) eq 'HASH') { 12031: $hashref = $settings->{'lti_instdata'}; 12032: } 12033: if ($role eq 'emailusername') { 12034: if ($statustype) { 12035: if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') { 12036: $hashref = $settings->{$context}->{$role}->{$statustype}; 12037: } 12038: } 12039: } 12040: } 12041: if (ref($hashref) eq 'HASH') { 12042: foreach my $field (@fields) { 12043: if ($hashref->{$field}) { 12044: if ($role eq 'emailusername') { 12045: $checks{$field} = $hashref->{$field}; 12046: } else { 12047: $checks{$field} = ' checked="checked" '; 12048: } 12049: } 12050: } 12051: } 12052: } 12053: 12054: my $total = scalar(@fields); 12055: for (my $i=0; $i<$total; $i++) { 12056: $rem = $i%($numinrow); 12057: if ($rem == 0) { 12058: if ($i > 0) { 12059: $output .= '</tr>'; 12060: } 12061: $output .= '<tr>'; 12062: } 12063: my $check = ' '; 12064: unless ($role eq 'emailusername') { 12065: if (exists($checks{$fields[$i]})) { 12066: $check = $checks{$fields[$i]}; 12067: } elsif ($context eq 'privacy') { 12068: if ($role =~ /^priv_(domain|course)$/) { 12069: if (ref($settings) ne 'HASH') { 12070: $check = ' checked="checked" '; 12071: } 12072: } elsif ($role =~ /^priv_(author|community)$/) { 12073: if (ref($settings) ne 'HASH') { 12074: unless ($fields[$i] eq 'id') { 12075: $check = ' checked="checked" '; 12076: } 12077: } 12078: } elsif ($role =~ /^(unpriv|othdom)_/) { 12079: if (ref($settings) ne 'HASH') { 12080: if (($fields[$i] eq 'lastname') || ($fields[$i] eq 'firstname')) { 12081: $check = ' checked="checked" '; 12082: } 12083: } 12084: } 12085: } elsif ($context ne 'lti') { 12086: if ($role eq 'st') { 12087: if (ref($settings) ne 'HASH') { 12088: $check = ' checked="checked" '; 12089: } 12090: } 12091: } 12092: } 12093: $output .= '<td class="LC_left_item">'. 12094: '<span class="LC_nobreak">'; 12095: my $prefix = 'canmodify'; 12096: if ($role eq 'emailusername') { 12097: unless ($checks{$fields[$i]} =~ /^(required|optional)$/) { 12098: $checks{$fields[$i]} = 'omit'; 12099: } 12100: foreach my $option ('required','optional','omit') { 12101: my $checked=''; 12102: if ($checks{$fields[$i]} eq $option) { 12103: $checked='checked="checked" '; 12104: } 12105: $output .= '<label>'. 12106: '<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'. 12107: &mt($option).'</label>'.(' ' x2); 12108: } 12109: $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>'; 12110: } else { 12111: if ($context eq 'lti') { 12112: $prefix = 'lti'; 12113: } elsif ($context eq 'privacy') { 12114: $prefix = 'privacy'; 12115: } 12116: $output .= '<label>'. 12117: '<input type="checkbox" name="'.$prefix.'_'.$role.'" '. 12118: 'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}. 12119: '</label>'; 12120: } 12121: $output .= '</span></td>'; 12122: } 12123: $rem = $total%$numinrow; 12124: my $colsleft; 12125: if ($rem) { 12126: $colsleft = $numinrow - $rem; 12127: } 12128: if ($colsleft > 1) { 12129: $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. 12130: ' </td>'; 12131: } elsif ($colsleft == 1) { 12132: $output .= '<td class="LC_left_item"> </td>'; 12133: } 12134: $output .= '</tr></table></td></tr>'; 12135: return $output; 12136: } 12137: 12138: sub insttypes_row { 12139: my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick, 12140: $customcss,$rowstyle) = @_; 12141: my %lt = &Apache::lonlocal::texthash ( 12142: cansearch => 'Users allowed to search', 12143: statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)', 12144: lockablenames => 'User preference to lock name', 12145: selfassign => 'Self-reportable affiliations', 12146: overrides => "Override domain's helpdesk settings based on requester's affiliation", 12147: ); 12148: my $showdom; 12149: if ($context eq 'cansearch') { 12150: $showdom = ' ('.$dom.')'; 12151: } 12152: my $class = 'LC_left_item'; 12153: if ($context eq 'statustocreate') { 12154: $class = 'LC_right_item'; 12155: } 12156: my $css_class; 12157: if ($$rowtotal%2) { 12158: $css_class = 'LC_odd_row'; 12159: } 12160: if ($customcss) { 12161: $css_class .= ' '.$customcss; 12162: } 12163: $css_class =~ s/^\s+//; 12164: if ($css_class) { 12165: $css_class = ' class="'.$css_class.'"'; 12166: } 12167: if ($rowstyle) { 12168: $css_class .= ' style="'.$rowstyle.'"'; 12169: } 12170: if ($onclick) { 12171: $onclick = 'onclick="'.$onclick.'" '; 12172: } 12173: my $output = '<tr'.$css_class.'>'. 12174: '<td>'.$lt{$context}.$showdom. 12175: '</td><td class="'.$class.'" colspan="2"><table>'; 12176: my $rem; 12177: if (ref($types) eq 'ARRAY') { 12178: for (my $i=0; $i<@{$types}; $i++) { 12179: if (defined($usertypes->{$types->[$i]})) { 12180: my $rem = $i%($numinrow); 12181: if ($rem == 0) { 12182: if ($i > 0) { 12183: $output .= '</tr>'; 12184: } 12185: $output .= '<tr>'; 12186: } 12187: my $check = ' '; 12188: if (ref($settings) eq 'HASH') { 12189: if (ref($settings->{$context}) eq 'ARRAY') { 12190: if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) { 12191: $check = ' checked="checked" '; 12192: } 12193: } elsif (ref($settings->{$context}) eq 'HASH') { 12194: if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') { 12195: $check = ' checked="checked" '; 12196: } 12197: } elsif ($context eq 'statustocreate') { 12198: $check = ' checked="checked" '; 12199: } 12200: } 12201: $output .= '<td class="LC_left_item">'. 12202: '<span class="LC_nobreak"><label>'. 12203: '<input type="checkbox" name="'.$context.'" '. 12204: 'value="'.$types->[$i].'"'.$check.$onclick.' />'. 12205: $usertypes->{$types->[$i]}.'</label></span></td>'; 12206: } 12207: } 12208: $rem = @{$types}%($numinrow); 12209: } 12210: my $colsleft = $numinrow - $rem; 12211: if ($context eq 'overrides') { 12212: if ($colsleft > 1) { 12213: $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; 12214: } else { 12215: $output .= '<td class="LC_left_item">'; 12216: } 12217: $output .= ' '; 12218: } else { 12219: if ($rem == 0) { 12220: $output .= '<tr>'; 12221: } 12222: if ($colsleft > 1) { 12223: $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; 12224: } else { 12225: $output .= '<td class="LC_left_item">'; 12226: } 12227: my $defcheck = ' '; 12228: if (ref($settings) eq 'HASH') { 12229: if (ref($settings->{$context}) eq 'ARRAY') { 12230: if (grep(/^default$/,@{$settings->{$context}})) { 12231: $defcheck = ' checked="checked" '; 12232: } 12233: } elsif ($context eq 'statustocreate') { 12234: $defcheck = ' checked="checked" '; 12235: } 12236: } 12237: $output .= '<span class="LC_nobreak"><label>'. 12238: '<input type="checkbox" name="'.$context.'" '. 12239: 'value="default"'.$defcheck.$onclick.' />'. 12240: $othertitle.'</label></span>'; 12241: } 12242: $output .= '</td></tr></table></td></tr>'; 12243: return $output; 12244: } 12245: 12246: sub sorted_searchtitles { 12247: my %searchtitles = &Apache::lonlocal::texthash( 12248: 'uname' => 'username', 12249: 'lastname' => 'last name', 12250: 'lastfirst' => 'last name, first name', 12251: ); 12252: my @titleorder = ('uname','lastname','lastfirst'); 12253: return (\%searchtitles,\@titleorder); 12254: } 12255: 12256: sub sorted_searchtypes { 12257: my %srchtypes_desc = ( 12258: exact => 'is exact match', 12259: contains => 'contains ..', 12260: begins => 'begins with ..', 12261: ); 12262: my @srchtypeorder = ('exact','begins','contains'); 12263: return (\%srchtypes_desc,\@srchtypeorder); 12264: } 12265: 12266: sub usertype_update_row { 12267: my ($settings,$usertypes,$fieldtitles,$fields,$types,$rownums) = @_; 12268: my $datatable; 12269: my $numinrow = 4; 12270: foreach my $type (@{$types}) { 12271: if (defined($usertypes->{$type})) { 12272: $$rownums ++; 12273: my $css_class = $$rownums%2?' class="LC_odd_row"':''; 12274: $datatable .= '<tr'.$css_class.'><td>'.$usertypes->{$type}. 12275: '</td><td class="LC_left_item"><table>'; 12276: for (my $i=0; $i<@{$fields}; $i++) { 12277: my $rem = $i%($numinrow); 12278: if ($rem == 0) { 12279: if ($i > 0) { 12280: $datatable .= '</tr>'; 12281: } 12282: $datatable .= '<tr>'; 12283: } 12284: my $check = ' '; 12285: if (ref($settings) eq 'HASH') { 12286: if (ref($settings->{'fields'}) eq 'HASH') { 12287: if (ref($settings->{'fields'}{$type}) eq 'ARRAY') { 12288: if (grep(/^\Q$fields->[$i]\E$/,@{$settings->{'fields'}{$type}})) { 12289: $check = ' checked="checked" '; 12290: } 12291: } 12292: } 12293: } 12294: 12295: if ($i == @{$fields}-1) { 12296: my $colsleft = $numinrow - $rem; 12297: if ($colsleft > 1) { 12298: $datatable .= '<td colspan="'.$colsleft.'">'; 12299: } else { 12300: $datatable .= '<td>'; 12301: } 12302: } else { 12303: $datatable .= '<td>'; 12304: } 12305: $datatable .= '<span class="LC_nobreak"><label>'. 12306: '<input type="checkbox" name="updateable_'.$type. 12307: '_'.$fields->[$i].'" value="1"'.$check.'/>'. 12308: $fieldtitles->{$fields->[$i]}.'</label></span></td>'; 12309: } 12310: $datatable .= '</tr></table></td></tr>'; 12311: } 12312: } 12313: return $datatable; 12314: } 12315: 12316: sub modify_login { 12317: my ($r,$dom,$confname,$lastactref,%domconfig) = @_; 12318: my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl, 12319: %curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon, 12320: %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso); 12321: %title = ( coursecatalog => 'Display course catalog', 12322: adminmail => 'Display administrator E-mail address', 12323: helpdesk => 'Display "Contact Helpdesk" link', 12324: newuser => 'Link for visitors to create a user account', 12325: loginheader => 'Log-in box header', 12326: saml => 'Dual SSO and non-SSO login'); 12327: @offon = ('off','on'); 12328: if (ref($domconfig{login}) eq 'HASH') { 12329: if (ref($domconfig{login}{loginvia}) eq 'HASH') { 12330: foreach my $lonhost (keys(%{$domconfig{login}{loginvia}})) { 12331: $curr_loginvia{$lonhost} = $domconfig{login}{loginvia}{$lonhost}; 12332: } 12333: } 12334: if (ref($domconfig{login}{'saml'}) eq 'HASH') { 12335: foreach my $lonhost (keys(%{$domconfig{login}{'saml'}})) { 12336: if (ref($domconfig{login}{'saml'}{$lonhost}) eq 'HASH') { 12337: $currsaml{$lonhost} = $domconfig{login}{'saml'}{$lonhost}; 12338: $saml{$lonhost} = 1; 12339: $samltext{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'text'}; 12340: $samlurl{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'url'}; 12341: $samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'}; 12342: $samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'}; 12343: $samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'}; 12344: $samlwindow{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'window'}; 12345: $samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'}; 12346: } 12347: } 12348: } 12349: } 12350: ($errors,%colchanges) = &modify_colors($r,$dom,$confname,['login'], 12351: \%domconfig,\%loginhash); 12352: my @toggles = ('coursecatalog','adminmail','helpdesk','newuser'); 12353: foreach my $item (@toggles) { 12354: $loginhash{login}{$item} = $env{'form.'.$item}; 12355: } 12356: $loginhash{login}{loginheader} = $env{'form.loginheader'}; 12357: if (ref($colchanges{'login'}) eq 'HASH') { 12358: $colchgtext = &display_colorchgs($dom,\%colchanges,['login'], 12359: \%loginhash); 12360: } 12361: 12362: my %servers = &Apache::lonnet::internet_dom_servers($dom); 12363: my %domservers = &Apache::lonnet::get_servers($dom); 12364: my @loginvia_attribs = ('serverpath','custompath','exempt'); 12365: if (keys(%servers) > 1) { 12366: foreach my $lonhost (keys(%servers)) { 12367: next if ($env{'form.'.$lonhost.'_server'} eq $lonhost); 12368: if (ref($curr_loginvia{$lonhost}) eq 'HASH') { 12369: if ($env{'form.'.$lonhost.'_server'} eq $curr_loginvia{$lonhost}{'server'}) { 12370: $loginhash{login}{loginvia}{$lonhost}{'server'} = $curr_loginvia{$lonhost}{'server'}; 12371: } elsif ($curr_loginvia{$lonhost}{'server'} ne '') { 12372: if (defined($servers{$env{'form.'.$lonhost.'_server'}})) { 12373: $loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'}; 12374: $changes{'loginvia'}{$lonhost} = 1; 12375: } else { 12376: $loginhash{login}{loginvia}{$lonhost}{'server'} = ''; 12377: $changes{'loginvia'}{$lonhost} = 1; 12378: } 12379: } else { 12380: if (defined($servers{$env{'form.'.$lonhost.'_server'}})) { 12381: $loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'}; 12382: $changes{'loginvia'}{$lonhost} = 1; 12383: } 12384: } 12385: if ($loginhash{login}{loginvia}{$lonhost}{'server'} eq '') { 12386: foreach my $item (@loginvia_attribs) { 12387: $loginhash{login}{loginvia}{$lonhost}{$item} = ''; 12388: } 12389: } else { 12390: foreach my $item (@loginvia_attribs) { 12391: my $new = $env{'form.'.$lonhost.'_'.$item}; 12392: if (($item eq 'serverpath') && ($new eq 'custom')) { 12393: $env{'form.'.$lonhost.'_custompath'} =~ s/\s+//g; 12394: if ($env{'form.'.$lonhost.'_custompath'} eq '') { 12395: $new = '/'; 12396: } 12397: } 12398: if (($item eq 'custompath') && 12399: ($env{'form.'.$lonhost.'_serverpath'} ne 'custom')) { 12400: $new = ''; 12401: } 12402: if ($new ne $curr_loginvia{$lonhost}{$item}) { 12403: $changes{'loginvia'}{$lonhost} = 1; 12404: } 12405: if ($item eq 'exempt') { 12406: $new = &check_exempt_addresses($new); 12407: } 12408: $loginhash{login}{loginvia}{$lonhost}{$item} = $new; 12409: } 12410: } 12411: } else { 12412: if (defined($servers{$env{'form.'.$lonhost.'_server'}})) { 12413: $loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'}; 12414: $changes{'loginvia'}{$lonhost} = 1; 12415: foreach my $item (@loginvia_attribs) { 12416: my $new = $env{'form.'.$lonhost.'_'.$item}; 12417: if (($item eq 'serverpath') && ($new eq 'custom')) { 12418: if ($env{'form.'.$lonhost.'_custompath'} eq '') { 12419: $new = '/'; 12420: } 12421: } 12422: if (($item eq 'custompath') && 12423: ($env{'form.'.$lonhost.'_serverpath'} ne 'custom')) { 12424: $new = ''; 12425: } 12426: $loginhash{login}{loginvia}{$lonhost}{$item} = $new; 12427: } 12428: } 12429: } 12430: } 12431: } 12432: 12433: my $servadm = $r->dir_config('lonAdmEMail'); 12434: my %langchoices = &Apache::lonlocal::texthash(&get_languages_hash()); 12435: if (ref($domconfig{'login'}) eq 'HASH') { 12436: if (ref($domconfig{'login'}{'helpurl'}) eq 'HASH') { 12437: foreach my $lang (sort(keys(%{$domconfig{'login'}{'helpurl'}}))) { 12438: if ($lang eq 'nolang') { 12439: push(@currlangs,$lang); 12440: } elsif (defined($langchoices{$lang})) { 12441: push(@currlangs,$lang); 12442: } else { 12443: next; 12444: } 12445: } 12446: } 12447: } 12448: my @delurls = &Apache::loncommon::get_env_multiple('form.loginhelpurl_del'); 12449: if (@currlangs > 0) { 12450: foreach my $lang (@currlangs) { 12451: if (grep(/^\Q$lang\E$/,@delurls)) { 12452: $changes{'helpurl'}{$lang} = 1; 12453: } elsif ($env{'form.loginhelpurl_'.$lang.'.filename'}) { 12454: $changes{'helpurl'}{$lang} = 1; 12455: $newfile{$lang} = $env{'form.loginhelpurl_'.$lang.'.filename'}; 12456: push(@newlangs,$lang); 12457: } else { 12458: $loginhash{'login'}{'helpurl'}{$lang} = $domconfig{'login'}{'helpurl'}{$lang}; 12459: } 12460: } 12461: } 12462: unless (grep(/^nolang$/,@currlangs)) { 12463: if ($env{'form.loginhelpurl_nolang.filename'}) { 12464: $changes{'helpurl'}{'nolang'} = 1; 12465: $newfile{'nolang'} = $env{'form.loginhelpurl_nolang.filename'}; 12466: push(@newlangs,'nolang'); 12467: } 12468: } 12469: if ($env{'form.loginhelpurl_add_lang'}) { 12470: if ((defined($langchoices{$env{'form.loginhelpurl_add_lang'}})) && 12471: ($env{'form.loginhelpurl_add_file.filename'})) { 12472: $newfile{$env{'form.loginhelpurl_add_lang'}} = $env{'form.loginhelpurl_add_file.filename'}; 12473: $addedfile = $env{'form.loginhelpurl_add_lang'}; 12474: } 12475: } 12476: if ((@newlangs > 0) || ($addedfile)) { 12477: my $error; 12478: my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); 12479: if ($configuserok eq 'ok') { 12480: if ($switchserver) { 12481: $error = &mt("Upload of custom help file is not permitted to this server: [_1]",$switchserver); 12482: } elsif ($author_ok eq 'ok') { 12483: my @allnew = @newlangs; 12484: if ($addedfile ne '') { 12485: push(@allnew,$addedfile); 12486: } 12487: foreach my $lang (@allnew) { 12488: my $formelem = 'loginhelpurl_'.$lang; 12489: if ($lang eq $env{'form.loginhelpurl_add_lang'}) { 12490: $formelem = 'loginhelpurl_add_file'; 12491: } 12492: (my $result,$newurl{$lang}) = &publishlogo($r,'upload',$formelem,$dom,$confname, 12493: "help/$lang",'','',$newfile{$lang}); 12494: if ($result eq 'ok') { 12495: $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang}; 12496: $changes{'helpurl'}{$lang} = 1; 12497: } else { 12498: my $puberror = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$newfile{$lang},$result); 12499: $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>'; 12500: if ((grep(/^\Q$lang\E$/,@currlangs)) && 12501: (!grep(/^\Q$lang\E$/,@delurls))) { 12502: $loginhash{'login'}{'helpurl'}{$lang} = $domconfig{'login'}{'helpurl'}{$lang}; 12503: } 12504: } 12505: } 12506: } else { 12507: $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); 12508: } 12509: } else { 12510: $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); 12511: } 12512: if ($error) { 12513: &Apache::lonnet::logthis($error); 12514: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 12515: } 12516: } 12517: 12518: my (%currheadtagurls,%currexempt,@newhosts,%newheadtagurls,%possexempt); 12519: if (ref($domconfig{'login'}) eq 'HASH') { 12520: if (ref($domconfig{'login'}{'headtag'}) eq 'HASH') { 12521: foreach my $lonhost (keys(%{$domconfig{'login'}{'headtag'}})) { 12522: if ($domservers{$lonhost}) { 12523: if (ref($domconfig{'login'}{'headtag'}{$lonhost}) eq 'HASH') { 12524: $currheadtagurls{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'url'}; 12525: $currexempt{$lonhost} = $domconfig{'login'}{'headtag'}{$lonhost}{'exempt'}; 12526: } 12527: } 12528: } 12529: } 12530: } 12531: my @delheadtagurls = &Apache::loncommon::get_env_multiple('form.loginheadtag_del'); 12532: foreach my $lonhost (sort(keys(%domservers))) { 12533: if (grep(/^\Q$lonhost\E$/,@delheadtagurls)) { 12534: $changes{'headtag'}{$lonhost} = 1; 12535: } else { 12536: if ($env{'form.loginheadtagexempt_'.$lonhost}) { 12537: $possexempt{$lonhost} = &check_exempt_addresses($env{'form.loginheadtagexempt_'.$lonhost}); 12538: } 12539: if ($env{'form.loginheadtag_'.$lonhost.'.filename'}) { 12540: push(@newhosts,$lonhost); 12541: } elsif ($currheadtagurls{$lonhost}) { 12542: $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $currheadtagurls{$lonhost}; 12543: if ($currexempt{$lonhost}) { 12544: if ((!exists($possexempt{$lonhost})) || ($possexempt{$lonhost} ne $currexempt{$lonhost})) { 12545: $changes{'headtag'}{$lonhost} = 1; 12546: } 12547: } elsif ($possexempt{$lonhost}) { 12548: $changes{'headtag'}{$lonhost} = 1; 12549: } 12550: if ($possexempt{$lonhost}) { 12551: $loginhash{'login'}{'headtag'}{$lonhost}{'exempt'} = $possexempt{$lonhost}; 12552: } 12553: } 12554: } 12555: } 12556: if (@newhosts) { 12557: my $error; 12558: my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); 12559: if ($configuserok eq 'ok') { 12560: if ($switchserver) { 12561: $error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver); 12562: } elsif ($author_ok eq 'ok') { 12563: foreach my $lonhost (@newhosts) { 12564: my $formelem = 'loginheadtag_'.$lonhost; 12565: (my $result,$newheadtagurls{$lonhost}) = &publishlogo($r,'upload',$formelem,$dom,$confname, 12566: "login/headtag/$lonhost",'','', 12567: $env{'form.loginheadtag_'.$lonhost.'.filename'}); 12568: if ($result eq 'ok') { 12569: $loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost}; 12570: $changes{'headtag'}{$lonhost} = 1; 12571: if ($possexempt{$lonhost}) { 12572: $loginhash{'login'}{'headtag'}{$lonhost}{'exempt'} = $possexempt{$lonhost}; 12573: } 12574: } else { 12575: my $puberror = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].", 12576: $newheadtagurls{$lonhost},$result); 12577: $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>'; 12578: if ((grep(/^\Q$lonhost\E$/,keys(%currheadtagurls))) && 12579: (!grep(/^\Q$lonhost\E$/,@delheadtagurls))) { 12580: $loginhash{'login'}{'headtag'}{$lonhost} = $currheadtagurls{$lonhost}; 12581: } 12582: } 12583: } 12584: } else { 12585: $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); 12586: } 12587: } else { 12588: $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); 12589: } 12590: if ($error) { 12591: &Apache::lonnet::logthis($error); 12592: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 12593: } 12594: } 12595: my @delsamlimg = &Apache::loncommon::get_env_multiple('form.saml_img_del'); 12596: my @newsamlimgs; 12597: foreach my $lonhost (keys(%domservers)) { 12598: if ($env{'form.saml_'.$lonhost}) { 12599: if ($env{'form.saml_img_'.$lonhost.'.filename'}) { 12600: push(@newsamlimgs,$lonhost); 12601: } 12602: foreach my $item ('text','alt','url','title','window','notsso') { 12603: $env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g; 12604: } 12605: if ($saml{$lonhost}) { 12606: if ($env{'form.saml_window_'.$lonhost} ne '1') { 12607: $env{'form.saml_window_'.$lonhost} = ''; 12608: } 12609: if (grep(/^\Q$lonhost\E$/,@delsamlimg)) { 12610: #FIXME Need to obsolete published image 12611: delete($currsaml{$lonhost}{'img'}); 12612: $changes{'saml'}{$lonhost} = 1; 12613: } 12614: if ($env{'form.saml_alt_'.$lonhost} ne $samlalt{$lonhost}) { 12615: $changes{'saml'}{$lonhost} = 1; 12616: } 12617: if ($env{'form.saml_text_'.$lonhost} ne $samltext{$lonhost}) { 12618: $changes{'saml'}{$lonhost} = 1; 12619: } 12620: if ($env{'form.saml_url_'.$lonhost} ne $samlurl{$lonhost}) { 12621: $changes{'saml'}{$lonhost} = 1; 12622: } 12623: if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) { 12624: $changes{'saml'}{$lonhost} = 1; 12625: } 12626: if ($env{'form.saml_window_'.$lonhost} ne $samlwindow{$lonhost}) { 12627: $changes{'saml'}{$lonhost} = 1; 12628: } 12629: if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) { 12630: $changes{'saml'}{$lonhost} = 1; 12631: } 12632: } else { 12633: $changes{'saml'}{$lonhost} = 1; 12634: } 12635: foreach my $item ('text','alt','url','title','window','notsso') { 12636: $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost}; 12637: } 12638: } else { 12639: if ($saml{$lonhost}) { 12640: $changes{'saml'}{$lonhost} = 1; 12641: delete($currsaml{$lonhost}); 12642: } 12643: } 12644: } 12645: foreach my $posshost (keys(%currsaml)) { 12646: unless (exists($domservers{$posshost})) { 12647: delete($currsaml{$posshost}); 12648: } 12649: } 12650: %{$loginhash{'login'}{'saml'}} = %currsaml; 12651: if (@newsamlimgs) { 12652: my $error; 12653: my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); 12654: if ($configuserok eq 'ok') { 12655: if ($switchserver) { 12656: $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver); 12657: } elsif ($author_ok eq 'ok') { 12658: foreach my $lonhost (@newsamlimgs) { 12659: my $formelem = 'saml_img_'.$lonhost; 12660: my ($result,$imgurl) = &publishlogo($r,'upload',$formelem,$dom,$confname, 12661: "login/saml/$lonhost",'','', 12662: $env{'form.saml_img_'.$lonhost.'.filename'}); 12663: if ($result eq 'ok') { 12664: $currsaml{$lonhost}{'img'} = $imgurl; 12665: $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl; 12666: $changes{'saml'}{$lonhost} = 1; 12667: } else { 12668: my $puberror = &mt("Upload of SSO button image failed for [_1] because an error occurred publishing the file in RES space. Error was: [_2].", 12669: $lonhost,$result); 12670: $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>'; 12671: } 12672: } 12673: } else { 12674: $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); 12675: } 12676: } else { 12677: $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); 12678: } 12679: if ($error) { 12680: &Apache::lonnet::logthis($error); 12681: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 12682: } 12683: } 12684: &process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'}); 12685: 12686: my $defaulthelpfile = '/adm/loginproblems.html'; 12687: my $defaulttext = &mt('Default in use'); 12688: 12689: my $putresult = &Apache::lonnet::put_dom('configuration',\%loginhash, 12690: $dom); 12691: if ($putresult eq 'ok') { 12692: my @toggles = ('coursecatalog','adminmail','helpdesk','newuser'); 12693: my %defaultchecked = ( 12694: 'coursecatalog' => 'on', 12695: 'helpdesk' => 'on', 12696: 'adminmail' => 'off', 12697: 'newuser' => 'off', 12698: ); 12699: if (ref($domconfig{'login'}) eq 'HASH') { 12700: foreach my $item (@toggles) { 12701: if ($defaultchecked{$item} eq 'on') { 12702: if (($domconfig{'login'}{$item} eq '0') && 12703: ($env{'form.'.$item} eq '1')) { 12704: $changes{$item} = 1; 12705: } elsif (($domconfig{'login'}{$item} eq '' || 12706: $domconfig{'login'}{$item} eq '1') && 12707: ($env{'form.'.$item} eq '0')) { 12708: $changes{$item} = 1; 12709: } 12710: } elsif ($defaultchecked{$item} eq 'off') { 12711: if (($domconfig{'login'}{$item} eq '1') && 12712: ($env{'form.'.$item} eq '0')) { 12713: $changes{$item} = 1; 12714: } elsif (($domconfig{'login'}{$item} eq '' || 12715: $domconfig{'login'}{$item} eq '0') && 12716: ($env{'form.'.$item} eq '1')) { 12717: $changes{$item} = 1; 12718: } 12719: } 12720: } 12721: } 12722: if (keys(%changes) > 0 || $colchgtext) { 12723: &Apache::loncommon::devalidate_domconfig_cache($dom); 12724: if (exists($changes{'saml'})) { 12725: my $hostid_in_use; 12726: my @hosts = &Apache::lonnet::current_machine_ids(); 12727: if (@hosts > 1) { 12728: foreach my $hostid (@hosts) { 12729: if (&Apache::lonnet::host_domain($hostid) eq $dom) { 12730: $hostid_in_use = $hostid; 12731: last; 12732: } 12733: } 12734: } else { 12735: $hostid_in_use = $r->dir_config('lonHostID'); 12736: } 12737: if (($hostid_in_use) && 12738: (&Apache::lonnet::host_domain($hostid_in_use) eq $dom)) { 12739: &Apache::lonnet::devalidate_cache_new('samllanding',$hostid_in_use); 12740: } 12741: if (ref($lastactref) eq 'HASH') { 12742: if (ref($changes{'saml'}) eq 'HASH') { 12743: my %updates; 12744: map { $updates{$_} = 1; } keys(%{$changes{'saml'}}); 12745: $lastactref->{'samllanding'} = \%updates; 12746: } 12747: } 12748: } 12749: if (ref($lastactref) eq 'HASH') { 12750: $lastactref->{'domainconfig'} = 1; 12751: } 12752: $resulttext = &mt('Changes made:').'<ul>'; 12753: foreach my $item (sort(keys(%changes))) { 12754: if ($item eq 'loginvia') { 12755: if (ref($changes{$item}) eq 'HASH') { 12756: $resulttext .= '<li>'.&mt('Log-in page availability:').'<ul>'; 12757: foreach my $lonhost (sort(keys(%{$changes{$item}}))) { 12758: if (defined($servers{$loginhash{login}{loginvia}{$lonhost}{'server'}})) { 12759: if (ref($loginhash{login}{loginvia}{$lonhost}) eq 'HASH') { 12760: my $protocol = $Apache::lonnet::protocol{$env{'form.'.$lonhost.'_server'}}; 12761: $protocol = 'http' if ($protocol ne 'https'); 12762: my $target = $protocol.'://'.$servers{$env{'form.'.$lonhost.'_server'}}; 12763: 12764: if ($loginhash{login}{loginvia}{$lonhost}{'serverpath'} eq 'custom') { 12765: $target .= $loginhash{login}{loginvia}{$lonhost}{'custompath'}; 12766: } else { 12767: $target .= $loginhash{login}{loginvia}{$lonhost}{'serverpath'}; 12768: } 12769: $resulttext .= '<li>'.&mt('Server: [_1] log-in page redirects to [_2].',$servers{$lonhost},'<a href="'.$target.'">'.$target.'</a>'); 12770: if ($loginhash{login}{loginvia}{$lonhost}{'exempt'} ne '') { 12771: $resulttext .= ' '.&mt('No redirection for clients from following IPs:').' '.$loginhash{login}{loginvia}{$lonhost}{'exempt'}; 12772: } 12773: $resulttext .= '</li>'; 12774: } else { 12775: $resulttext .= '<li>'.&mt('Server: [_1] has standard log-in page.',$lonhost).'</li>'; 12776: } 12777: } else { 12778: $resulttext .= '<li>'.&mt('Server: [_1] has standard log-in page.',$servers{$lonhost}).'</li>'; 12779: } 12780: } 12781: $resulttext .= '</ul></li>'; 12782: } 12783: } elsif ($item eq 'helpurl') { 12784: if (ref($changes{$item}) eq 'HASH') { 12785: foreach my $lang (sort(keys(%{$changes{$item}}))) { 12786: if (grep(/^\Q$lang\E$/,@delurls)) { 12787: my ($chg,$link); 12788: $link = &Apache::loncommon::modal_link($defaulthelpfile,$defaulttext,600,500); 12789: if ($lang eq 'nolang') { 12790: $chg = &mt('custom log-in help file removed for no preferred language; [_1]',$link); 12791: } else { 12792: $chg = &mt('custom log-in help file removed for specific language: [_1]; [_2]',$langchoices{$lang},$link); 12793: } 12794: $resulttext .= '<li>'.$chg.'</li>'; 12795: } else { 12796: my $chg; 12797: if ($lang eq 'nolang') { 12798: $chg = &mt('custom log-in help file for no preferred language'); 12799: } else { 12800: $chg = &mt('custom log-in help file for specific language: [_1]',$langchoices{$lang}); 12801: } 12802: $resulttext .= '<li>'.&Apache::loncommon::modal_link( 12803: $loginhash{'login'}{'helpurl'}{$lang}. 12804: '?inhibitmenu=yes',$chg,600,500). 12805: '</li>'; 12806: } 12807: } 12808: } 12809: } elsif ($item eq 'headtag') { 12810: if (ref($changes{$item}) eq 'HASH') { 12811: foreach my $lonhost (sort(keys(%{$changes{$item}}))) { 12812: if (grep(/^\Q$lonhost\E$/,@delheadtagurls)) { 12813: $resulttext .= '<li>'.&mt('custom markup file removed for [_1]',$domservers{$lonhost}).'</li>'; 12814: } elsif (ref($loginhash{'login'}{'headtag'}{$lonhost}) eq 'HASH') { 12815: $resulttext .= '<li><a href="'. 12816: "javascript:void(open('$loginhash{'login'}{'headtag'}{$lonhost}{'url'}?inhibitmenu=yes','Custom_HeadTag', 12817: 'menubar=0,toolbar=1,scrollbars=1,width=600,height=500,resizable=yes'))". 12818: '">'.&mt('custom markup').'</a> '.&mt('(for [_1])',$servers{$lonhost}).' '; 12819: if ($possexempt{$lonhost}) { 12820: $resulttext .= &mt('not included for client IP(s): [_1]',$possexempt{$lonhost}); 12821: } else { 12822: $resulttext .= &mt('included for any client IP'); 12823: } 12824: $resulttext .= '</li>'; 12825: } 12826: } 12827: } 12828: } elsif ($item eq 'saml') { 12829: if (ref($changes{$item}) eq 'HASH') { 12830: my %notlt = ( 12831: text => 'Text for log-in by SSO', 12832: img => 'SSO button image', 12833: alt => 'Alt text for button image', 12834: url => 'SSO URL', 12835: title => 'Tooltip for SSO link', 12836: window => 'Pop-up window if iframe', 12837: notsso => 'Text for non-SSO log-in', 12838: ); 12839: foreach my $lonhost (sort(keys(%{$changes{$item}}))) { 12840: if (ref($currsaml{$lonhost}) eq 'HASH') { 12841: $resulttext .= '<li>'.&mt("$title{$item} in use for [_1]","<b>$lonhost</b>"). 12842: '<ul>'; 12843: foreach my $key ('text','img','alt','url','title','window','notsso') { 12844: if ($currsaml{$lonhost}{$key} eq '') { 12845: $resulttext .= '<li>'.&mt("$notlt{$key} not in use").'</li>'; 12846: } else { 12847: my $value = "'$currsaml{$lonhost}{$key}'"; 12848: if ($key eq 'img') { 12849: $value = '<img src="'.$currsaml{$lonhost}{$key}.'" />'; 12850: } elsif ($key eq 'window') { 12851: $value = 'On'; 12852: } 12853: $resulttext .= '<li>'.&mt("$notlt{$key} set to: [_1]", 12854: $value).'</li>'; 12855: } 12856: } 12857: $resulttext .= '</ul></li>'; 12858: } else { 12859: $resulttext .= '<li>'.&mt("$title{$item} not in use for [_1]",$lonhost).'</li>'; 12860: } 12861: } 12862: } 12863: } elsif ($item eq 'captcha') { 12864: if (ref($loginhash{'login'}) eq 'HASH') { 12865: my $chgtxt; 12866: if ($loginhash{'login'}{$item} eq 'notused') { 12867: $chgtxt .= &mt('No CAPTCHA validation in use for helpdesk form.'); 12868: } else { 12869: my %captchas = &captcha_phrases(); 12870: if ($captchas{$loginhash{'login'}{$item}}) { 12871: $chgtxt .= &mt("Validation for helpdesk form set to $captchas{$loginhash{'login'}{$item}}."); 12872: } else { 12873: $chgtxt .= &mt('Validation for helpdesk form set to unknown type.'); 12874: } 12875: } 12876: $resulttext .= '<li>'.$chgtxt.'</li>'; 12877: } 12878: } elsif ($item eq 'recaptchakeys') { 12879: if (ref($loginhash{'login'}) eq 'HASH') { 12880: my ($privkey,$pubkey); 12881: if (ref($loginhash{'login'}{$item}) eq 'HASH') { 12882: $pubkey = $loginhash{'login'}{$item}{'public'}; 12883: $privkey = $loginhash{'login'}{$item}{'private'}; 12884: } 12885: my $chgtxt .= &mt('ReCAPTCHA keys changes').'<ul>'; 12886: if (!$pubkey) { 12887: $chgtxt .= '<li>'.&mt('Public key deleted').'</li>'; 12888: } else { 12889: $chgtxt .= '<li>'.&mt('Public key set to [_1]',$pubkey).'</li>'; 12890: } 12891: if (!$privkey) { 12892: $chgtxt .= '<li>'.&mt('Private key deleted').'</li>'; 12893: } else { 12894: $chgtxt .= '<li>'.&mt('Private key set to [_1]',$privkey).'</li>'; 12895: } 12896: $chgtxt .= '</ul>'; 12897: $resulttext .= '<li>'.$chgtxt.'</li>'; 12898: } 12899: } elsif ($item eq 'recaptchaversion') { 12900: if (ref($loginhash{'login'}) eq 'HASH') { 12901: if ($loginhash{'login'}{'captcha'} eq 'recaptcha') { 12902: $resulttext .= '<li>'.&mt('ReCAPTCHA for helpdesk form set to version [_1]',$loginhash{'login'}{'recaptchaversion'}). 12903: '</li>'; 12904: } 12905: } 12906: } else { 12907: $resulttext .= '<li>'.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'</li>'; 12908: } 12909: } 12910: $resulttext .= $colchgtext.'</ul>'; 12911: } else { 12912: $resulttext = &mt('No changes made to log-in page settings'); 12913: } 12914: } else { 12915: $resulttext = '<span class="LC_error">'. 12916: &mt('An error occurred: [_1]',$putresult).'</span>'; 12917: } 12918: if ($errors) { 12919: $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'. 12920: $errors.'</ul>'; 12921: } 12922: return $resulttext; 12923: } 12924: 12925: sub check_exempt_addresses { 12926: my ($iplist) = @_; 12927: $iplist =~ s/^\s+//; 12928: $iplist =~ s/\s+$//; 12929: my @poss_ips = split(/\s*[,:]\s*/,$iplist); 12930: my (@okips,$new); 12931: foreach my $ip (@poss_ips) { 12932: if ($ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { 12933: if (($1 <= 255) && ($2 <= 255) && ($3 <= 255) && ($4 <= 255)) { 12934: push(@okips,$ip); 12935: } 12936: } 12937: } 12938: if (@okips > 0) { 12939: $new = join(',',@okips); 12940: } else { 12941: $new = ''; 12942: } 12943: return $new; 12944: } 12945: 12946: sub color_font_choices { 12947: my %choices = 12948: &Apache::lonlocal::texthash ( 12949: img => "Header", 12950: bgs => "Background colors", 12951: links => "Link colors", 12952: images => "Images", 12953: font => "Font color", 12954: fontmenu => "Font menu", 12955: pgbg => "Page", 12956: tabbg => "Header", 12957: sidebg => "Border", 12958: link => "Link", 12959: alink => "Active link", 12960: vlink => "Visited link", 12961: ); 12962: return %choices; 12963: } 12964: 12965: sub modify_ipaccess { 12966: my ($dom,$lastactref,%domconfig) = @_; 12967: my (@allpos,%changes,%confhash,$errors,$resulttext); 12968: my (@items,%deletions,%itemids,@warnings); 12969: my ($typeorder,$types) = &commblocktype_text(); 12970: if ($env{'form.ipaccess_add'}) { 12971: my $name = $env{'form.ipaccess_name_add'}; 12972: my ($newid,$error) = &get_ipaccess_id($dom,$name); 12973: if ($newid) { 12974: $itemids{'add'} = $newid; 12975: push(@items,'add'); 12976: $changes{$newid} = 1; 12977: } else { 12978: $error = &mt('Failed to acquire unique ID for new IP access control item'); 12979: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 12980: } 12981: } 12982: if (ref($domconfig{'ipaccess'}) eq 'HASH') { 12983: my @todelete = &Apache::loncommon::get_env_multiple('form.ipaccess_del'); 12984: if (@todelete) { 12985: map { $deletions{$_} = 1; } @todelete; 12986: } 12987: my $maxnum = $env{'form.ipaccess_maxnum'}; 12988: for (my $i=0; $i<$maxnum; $i++) { 12989: my $itemid = $env{'form.ipaccess_id_'.$i}; 12990: $itemid =~ s/\D+//g; 12991: if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') { 12992: if ($deletions{$itemid}) { 12993: $changes{$itemid} = $domconfig{'ipaccess'}{$itemid}{'name'}; 12994: } else { 12995: push(@items,$i); 12996: $itemids{$i} = $itemid; 12997: } 12998: } 12999: } 13000: } 13001: foreach my $idx (@items) { 13002: my $itemid = $itemids{$idx}; 13003: next unless ($itemid); 13004: my %current; 13005: unless ($idx eq 'add') { 13006: if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') { 13007: %current = %{$domconfig{'ipaccess'}{$itemid}}; 13008: } 13009: } 13010: my $position = $env{'form.ipaccess_pos_'.$itemid}; 13011: $position =~ s/\D+//g; 13012: if ($position ne '') { 13013: $allpos[$position] = $itemid; 13014: } 13015: my $name = $env{'form.ipaccess_name_'.$idx}; 13016: $name =~ s/^\s+|\s+$//g; 13017: $confhash{$itemid}{'name'} = $name; 13018: my $possrange = $env{'form.ipaccess_range_'.$idx}; 13019: $possrange =~ s/^\s+|\s+$//g; 13020: unless ($possrange eq '') { 13021: $possrange =~ s/[\r\n]+/\s/g; 13022: $possrange =~ s/\s*-\s*/-/g; 13023: $possrange =~ s/\s+/,/g; 13024: $possrange =~ s/,+/,/g; 13025: if ($possrange ne '') { 13026: my (@ok,$count); 13027: $count = 0; 13028: foreach my $poss (split(/\,/,$possrange)) { 13029: $count ++; 13030: $poss = &validate_ip_pattern($poss); 13031: if ($poss ne '') { 13032: push(@ok,$poss); 13033: } 13034: } 13035: my $diff = $count - scalar(@ok); 13036: if ($diff) { 13037: $errors .= '<li><span class="LC_error">'. 13038: &mt('[quant,_1,IP] invalid and excluded from saved value for IP range(s) for [_2]', 13039: $diff,$name). 13040: '</span></li>'; 13041: } 13042: if (@ok) { 13043: my @cidr_list; 13044: foreach my $item (@ok) { 13045: @cidr_list = &Net::CIDR::cidradd($item,@cidr_list); 13046: } 13047: $confhash{$itemid}{'ip'} = join(',',@cidr_list); 13048: } 13049: } 13050: } 13051: foreach my $field ('name','ip') { 13052: unless (($idx eq 'add') || ($changes{$itemid})) { 13053: if ($current{$field} ne $confhash{$itemid}{$field}) { 13054: $changes{$itemid} = 1; 13055: last; 13056: } 13057: } 13058: } 13059: $confhash{$itemid}{'commblocks'} = {}; 13060: 13061: my %commblocks; 13062: map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx); 13063: foreach my $type (@{$typeorder}) { 13064: if ($commblocks{$type}) { 13065: $confhash{$itemid}{'commblocks'}{$type} = 'on'; 13066: } 13067: unless (($idx eq 'add') || ($changes{$itemid})) { 13068: if (ref($current{'commblocks'}) eq 'HASH') { 13069: if ($confhash{$itemid}{'commblocks'}{$type} ne $current{'commblocks'}{$type}) { 13070: $changes{$itemid} = 1; 13071: } 13072: } elsif ($confhash{$itemid}{'commblocks'}{$type}) { 13073: $changes{$itemid} = 1; 13074: } 13075: } 13076: } 13077: $confhash{$itemid}{'courses'} = {}; 13078: my %crsdeletions; 13079: my @delcrs = &Apache::loncommon::get_env_multiple('form.ipaccess_course_delete_'.$idx); 13080: if (@delcrs) { 13081: map { $crsdeletions{$_} = 1; } @delcrs; 13082: } 13083: if (ref($current{'courses'}) eq 'HASH') { 13084: foreach my $cid (sort(keys(%{$current{'courses'}}))) { 13085: if ($crsdeletions{$cid}) { 13086: $changes{$itemid} = 1; 13087: } else { 13088: $confhash{$itemid}{'courses'}{$cid} = 1; 13089: } 13090: } 13091: } 13092: $env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g; 13093: $env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g; 13094: if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) && 13095: ($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) { 13096: if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx}, 13097: $env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') { 13098: $errors .= '<li><span class="LC_error">'. 13099: &mt('Invalid courseID [_1] omitted from list of allowed courses', 13100: $env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}). 13101: '</span></li>'; 13102: } else { 13103: $confhash{$itemid}{'courses'}{$env{'form.ipaccess_cdom_'.$idx}.'_'.$env{'form.ipaccess_cnum_'.$idx}} = 1; 13104: $changes{$itemid} = 1; 13105: } 13106: } 13107: } 13108: if (@allpos > 0) { 13109: my $idx = 0; 13110: foreach my $itemid (@allpos) { 13111: if ($itemid ne '') { 13112: $confhash{$itemid}{'order'} = $idx; 13113: unless ($changes{$itemid}) { 13114: if (ref($domconfig{'ipaccess'}) eq 'HASH') { 13115: if (ref($domconfig{'ipaccess'}{$itemid}) eq 'HASH') { 13116: if ($domconfig{'ipaccess'}{$itemid}{'order'} ne $idx) { 13117: $changes{$itemid} = 1; 13118: } 13119: } 13120: } 13121: } 13122: $idx ++; 13123: } 13124: } 13125: } 13126: if (keys(%changes)) { 13127: my %defaultshash = ( 13128: ipaccess => \%confhash, 13129: ); 13130: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, 13131: $dom); 13132: if ($putresult eq 'ok') { 13133: my $cachetime = 1800; 13134: &Apache::lonnet::do_cache_new('ipaccess',$dom,\%confhash,$cachetime); 13135: if (ref($lastactref) eq 'HASH') { 13136: $lastactref->{'ipaccess'} = 1; 13137: } 13138: $resulttext = &mt('Changes made:').'<ul>'; 13139: my %bynum; 13140: foreach my $itemid (sort(keys(%changes))) { 13141: if (ref($confhash{$itemid}) eq 'HASH') { 13142: my $position = $confhash{$itemid}{'order'}; 13143: if ($position =~ /^\d+$/) { 13144: $bynum{$position} = $itemid; 13145: } 13146: } 13147: } 13148: if (keys(%deletions)) { 13149: foreach my $itemid (sort { $a <=> $b } keys(%deletions)) { 13150: $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>'; 13151: } 13152: } 13153: foreach my $pos (sort { $a <=> $b } keys(%bynum)) { 13154: my $itemid = $bynum{$pos}; 13155: if (ref($confhash{$itemid}) eq 'HASH') { 13156: $resulttext .= '<li><b>'.$confhash{$itemid}{'name'}.'</b><ul>'; 13157: my $position = $pos + 1; 13158: $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>'; 13159: if ($confhash{$itemid}{'ip'} eq '') { 13160: $resulttext .= '<li>'.&mt('No IP Range(s) set').'</li>'; 13161: } else { 13162: $resulttext .= '<li>'.&mt('IP Range(s): [_1]',$confhash{$itemid}{'ip'}).'</li>'; 13163: } 13164: if (keys(%{$confhash{$itemid}{'commblocks'}})) { 13165: $resulttext .= '<li>'.&mt('Functionality Blocked: [_1]', 13166: join(', ', map { $types->{$_}; } sort(keys(%{$confhash{$itemid}{'commblocks'}})))). 13167: '</li>'; 13168: } else { 13169: $resulttext .= '<li>'.&mt('No functionality blocked').'</li>'; 13170: } 13171: if (keys(%{$confhash{$itemid}{'courses'}})) { 13172: my @courses; 13173: foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) { 13174: my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1}); 13175: push(@courses,$courseinfo{'description'}.' ('.$cid.')'); 13176: } 13177: $resulttext .= '<li>'.&mt('Courses/Communities allowed').':<ul><li>'. 13178: join('</li><li>',@courses).'</li></ul>'; 13179: } else { 13180: $resulttext .= '<li>'.&mt('No courses allowed').'</li>'; 13181: } 13182: $resulttext .= '</ul></li>'; 13183: } 13184: } 13185: $resulttext .= '</ul>'; 13186: } else { 13187: $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>'; 13188: } 13189: } else { 13190: $resulttext = &mt('No changes made'); 13191: } 13192: if ($errors) { 13193: $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'. 13194: $errors.'</ul></p>'; 13195: } 13196: return $resulttext; 13197: } 13198: 13199: sub get_ipaccess_id { 13200: my ($domain,$location) = @_; 13201: # get lock on ipaccess db 13202: my $lockhash = { 13203: lock => $env{'user.name'}. 13204: ':'.$env{'user.domain'}, 13205: }; 13206: my $tries = 0; 13207: my $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain); 13208: my ($id,$error); 13209: 13210: while (($gotlock ne 'ok') && ($tries<10)) { 13211: $tries ++; 13212: sleep (0.1); 13213: $gotlock = &Apache::lonnet::newput_dom('ipaccess',$lockhash,$domain); 13214: } 13215: if ($gotlock eq 'ok') { 13216: my %currids = &Apache::lonnet::dump_dom('ipaccess',$domain); 13217: if ($currids{'lock'}) { 13218: delete($currids{'lock'}); 13219: if (keys(%currids)) { 13220: my @curr = sort { $a <=> $b } keys(%currids); 13221: if ($curr[-1] =~ /^\d+$/) { 13222: $id = 1 + $curr[-1]; 13223: } 13224: } else { 13225: $id = 1; 13226: } 13227: if ($id) { 13228: unless (&Apache::lonnet::newput_dom('ipaccess',{ $id => $location },$domain) eq 'ok') { 13229: $error = 'nostore'; 13230: } 13231: } else { 13232: $error = 'nonumber'; 13233: } 13234: } 13235: my $dellockoutcome = &Apache::lonnet::del_dom('ipaccess',['lock'],$domain); 13236: } else { 13237: $error = 'nolock'; 13238: } 13239: return ($id,$error); 13240: } 13241: 13242: sub modify_rolecolors { 13243: my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_; 13244: my ($resulttext,%rolehash); 13245: $rolehash{'rolecolors'} = {}; 13246: if (ref($domconfig{'rolecolors'}) ne 'HASH') { 13247: if ($domconfig{'rolecolors'} eq '') { 13248: $domconfig{'rolecolors'} = {}; 13249: } 13250: } 13251: my ($errors,%changes) = &modify_colors($r,$dom,$confname,$roles, 13252: $domconfig{'rolecolors'},$rolehash{'rolecolors'}); 13253: my $putresult = &Apache::lonnet::put_dom('configuration',\%rolehash, 13254: $dom); 13255: if ($putresult eq 'ok') { 13256: if (keys(%changes) > 0) { 13257: &Apache::loncommon::devalidate_domconfig_cache($dom); 13258: if (ref($lastactref) eq 'HASH') { 13259: $lastactref->{'domainconfig'} = 1; 13260: } 13261: $resulttext = &display_colorchgs($dom,\%changes,$roles, 13262: $rolehash{'rolecolors'}); 13263: } else { 13264: $resulttext = &mt('No changes made to default color schemes'); 13265: } 13266: } else { 13267: $resulttext = '<span class="LC_error">'. 13268: &mt('An error occurred: [_1]',$putresult).'</span>'; 13269: } 13270: if ($errors) { 13271: $resulttext .= &mt('The following errors occurred: ').'<ul>'. 13272: $errors.'</ul>'; 13273: } 13274: return $resulttext; 13275: } 13276: 13277: sub modify_colors { 13278: my ($r,$dom,$confname,$roles,$domconfig,$confhash) = @_; 13279: my (%changes,%choices); 13280: my @bgs; 13281: my @links = ('link','alink','vlink'); 13282: my @logintext; 13283: my @images; 13284: my $servadm = $r->dir_config('lonAdmEMail'); 13285: my $errors; 13286: my %defaults; 13287: foreach my $role (@{$roles}) { 13288: if ($role eq 'login') { 13289: %choices = &login_choices(); 13290: @logintext = ('textcol','bgcol'); 13291: } else { 13292: %choices = &color_font_choices(); 13293: } 13294: if ($role eq 'login') { 13295: @images = ('img','logo','domlogo','login'); 13296: @bgs = ('pgbg','mainbg','sidebg'); 13297: } else { 13298: @images = ('img'); 13299: @bgs = ('pgbg','tabbg','sidebg'); 13300: } 13301: my %defaults = &role_defaults($role,\@bgs,\@links,\@images,\@logintext); 13302: unless ($env{'form.'.$role.'_font'} eq $defaults{'font'}) { 13303: $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'}; 13304: } 13305: if ($role eq 'login') { 13306: foreach my $item (@logintext) { 13307: $env{'form.'.$role.'_'.$item} = lc($env{'form.'.$role.'_'.$item}); 13308: if ($env{'form.'.$role.'_'.$item} =~ /^\w+/) { 13309: $env{'form.'.$role.'_'.$item} = '#'.$env{'form.'.$role.'_'.$item}; 13310: } 13311: unless ($env{'form.'.$role.'_'.$item} eq lc($defaults{'logintext'}{$item})) { 13312: $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; 13313: } 13314: } 13315: } else { 13316: $env{'form.'.$role.'_fontmenu'} = lc($env{'form.'.$role.'_fontmenu'}); 13317: if ($env{'form.'.$role.'_fontmenu'} =~ /^\w+/) { 13318: $env{'form.'.$role.'_fontmenu'} = '#'.$env{'form.'.$role.'_fontmenu'}; 13319: } 13320: unless($env{'form.'.$role.'_fontmenu'} eq lc($defaults{'fontmenu'})) { 13321: $confhash->{$role}{'fontmenu'} = $env{'form.'.$role.'_fontmenu'}; 13322: } 13323: } 13324: foreach my $item (@bgs) { 13325: $env{'form.'.$role.'_'.$item} = lc($env{'form.'.$role.'_'.$item}); 13326: if ($env{'form.'.$role.'_'.$item} =~ /^\w+/) { 13327: $env{'form.'.$role.'_'.$item} = '#'.$env{'form.'.$role.'_'.$item}; 13328: } 13329: unless ($env{'form.'.$role.'_'.$item} eq lc($defaults{'bgs'}{$item})) { 13330: $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; 13331: } 13332: } 13333: foreach my $item (@links) { 13334: $env{'form.'.$role.'_'.$item} = lc($env{'form.'.$role.'_'.$item}); 13335: if ($env{'form.'.$role.'_'.$item} =~ /^\w+/) { 13336: $env{'form.'.$role.'_'.$item} = '#'.$env{'form.'.$role.'_'.$item}; 13337: } 13338: unless ($env{'form.'.$role.'_'.$item} eq lc($defaults{'links'}{$item})) { 13339: $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; 13340: } 13341: } 13342: my ($configuserok,$author_ok,$switchserver) = 13343: &config_check($dom,$confname,$servadm); 13344: my ($width,$height) = &thumb_dimensions(); 13345: if (ref($domconfig->{$role}) ne 'HASH') { 13346: $domconfig->{$role} = {}; 13347: } 13348: foreach my $img (@images) { 13349: if ($role eq 'login') { 13350: if (($img eq 'img') || ($img eq 'logo')) { 13351: if (defined($env{'form.login_showlogo_'.$img})) { 13352: $confhash->{$role}{'showlogo'}{$img} = 1; 13353: } else { 13354: $confhash->{$role}{'showlogo'}{$img} = 0; 13355: } 13356: } 13357: if ($env{'form.login_alt_'.$img} ne '') { 13358: $confhash->{$role}{'alttext'}{$img} = $env{'form.login_alt_'.$img}; 13359: } 13360: } 13361: if ( ! $env{'form.'.$role.'_'.$img.'.filename'} 13362: && !defined($domconfig->{$role}{$img}) 13363: && !$env{'form.'.$role.'_del_'.$img} 13364: && $env{'form.'.$role.'_import_'.$img}) { 13365: # import the old configured image from the .tab setting 13366: # if they haven't provided a new one 13367: $domconfig->{$role}{$img} = 13368: $env{'form.'.$role.'_import_'.$img}; 13369: } 13370: if ($env{'form.'.$role.'_'.$img.'.filename'} ne '') { 13371: my $error; 13372: if ($configuserok eq 'ok') { 13373: if ($switchserver) { 13374: $error = &mt("Upload of [_1] image for $role page(s) is not permitted to this server: [_2]",$choices{$img},$switchserver); 13375: } else { 13376: if ($author_ok eq 'ok') { 13377: my ($result,$logourl) = 13378: &publishlogo($r,'upload',$role.'_'.$img, 13379: $dom,$confname,$img,$width,$height); 13380: if ($result eq 'ok') { 13381: $confhash->{$role}{$img} = $logourl; 13382: $changes{$role}{'images'}{$img} = 1; 13383: } else { 13384: $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); 13385: } 13386: } else { 13387: $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); 13388: } 13389: } 13390: } else { 13391: $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); 13392: } 13393: if ($error) { 13394: &Apache::lonnet::logthis($error); 13395: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 13396: } 13397: } elsif ($domconfig->{$role}{$img} ne '') { 13398: if ($domconfig->{$role}{$img} !~ m-^(/res/\Q$dom\E/\Q$confname\E/\Q$img\E)/([^/]+)$-) { 13399: my $error; 13400: if ($configuserok eq 'ok') { 13401: # is confname an author? 13402: if ($switchserver eq '') { 13403: if ($author_ok eq 'ok') { 13404: my ($result,$logourl) = 13405: &publishlogo($r,'copy',$domconfig->{$role}{$img}, 13406: $dom,$confname,$img,$width,$height); 13407: if ($result eq 'ok') { 13408: $confhash->{$role}{$img} = $logourl; 13409: $changes{$role}{'images'}{$img} = 1; 13410: } 13411: } 13412: } 13413: } 13414: } 13415: } 13416: } 13417: if (ref($domconfig) eq 'HASH') { 13418: if (ref($domconfig->{$role}) eq 'HASH') { 13419: foreach my $img (@images) { 13420: if ($domconfig->{$role}{$img} ne '') { 13421: if ($env{'form.'.$role.'_del_'.$img}) { 13422: $confhash->{$role}{$img} = ''; 13423: $changes{$role}{'images'}{$img} = 1; 13424: } else { 13425: if ($confhash->{$role}{$img} eq '') { 13426: $confhash->{$role}{$img} = $domconfig->{$role}{$img}; 13427: } 13428: } 13429: } else { 13430: if ($env{'form.'.$role.'_del_'.$img}) { 13431: $confhash->{$role}{$img} = ''; 13432: $changes{$role}{'images'}{$img} = 1; 13433: } 13434: } 13435: if ($role eq 'login') { 13436: if (($img eq 'logo') || ($img eq 'img')) { 13437: if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') { 13438: if ($confhash->{$role}{'showlogo'}{$img} ne 13439: $domconfig->{$role}{'showlogo'}{$img}) { 13440: $changes{$role}{'showlogo'}{$img} = 1; 13441: } 13442: } else { 13443: if ($confhash->{$role}{'showlogo'}{$img} == 0) { 13444: $changes{$role}{'showlogo'}{$img} = 1; 13445: } 13446: } 13447: } 13448: if ($img ne 'login') { 13449: if (ref($domconfig->{$role}{'alttext'}) eq 'HASH') { 13450: if ($confhash->{$role}{'alttext'}{$img} ne 13451: $domconfig->{$role}{'alttext'}{$img}) { 13452: $changes{$role}{'alttext'}{$img} = 1; 13453: } 13454: } else { 13455: if ($confhash->{$role}{'alttext'}{$img} ne '') { 13456: $changes{$role}{'alttext'}{$img} = 1; 13457: } 13458: } 13459: } 13460: } 13461: } 13462: if ($domconfig->{$role}{'font'} ne '') { 13463: if ($confhash->{$role}{'font'} ne $domconfig->{$role}{'font'}) { 13464: $changes{$role}{'font'} = 1; 13465: } 13466: } else { 13467: if ($confhash->{$role}{'font'}) { 13468: $changes{$role}{'font'} = 1; 13469: } 13470: } 13471: if ($role ne 'login') { 13472: if ($domconfig->{$role}{'fontmenu'} ne '') { 13473: if ($confhash->{$role}{'fontmenu'} ne $domconfig->{$role}{'fontmenu'}) { 13474: $changes{$role}{'fontmenu'} = 1; 13475: } 13476: } else { 13477: if ($confhash->{$role}{'fontmenu'}) { 13478: $changes{$role}{'fontmenu'} = 1; 13479: } 13480: } 13481: } 13482: foreach my $item (@bgs) { 13483: if ($domconfig->{$role}{$item} ne '') { 13484: if ($confhash->{$role}{$item} ne $domconfig->{$role}{$item}) { 13485: $changes{$role}{'bgs'}{$item} = 1; 13486: } 13487: } else { 13488: if ($confhash->{$role}{$item}) { 13489: $changes{$role}{'bgs'}{$item} = 1; 13490: } 13491: } 13492: } 13493: foreach my $item (@links) { 13494: if ($domconfig->{$role}{$item} ne '') { 13495: if ($confhash->{$role}{$item} ne $domconfig->{$role}{$item}) { 13496: $changes{$role}{'links'}{$item} = 1; 13497: } 13498: } else { 13499: if ($confhash->{$role}{$item}) { 13500: $changes{$role}{'links'}{$item} = 1; 13501: } 13502: } 13503: } 13504: foreach my $item (@logintext) { 13505: if ($domconfig->{$role}{$item} ne '') { 13506: if ($confhash->{$role}{$item} ne $domconfig->{$role}{$item}) { 13507: $changes{$role}{'logintext'}{$item} = 1; 13508: } 13509: } else { 13510: if ($confhash->{$role}{$item}) { 13511: $changes{$role}{'logintext'}{$item} = 1; 13512: } 13513: } 13514: } 13515: } else { 13516: &default_change_checker($role,\@images,\@links,\@bgs, 13517: \@logintext,$confhash,\%changes); 13518: } 13519: } else { 13520: &default_change_checker($role,\@images,\@links,\@bgs, 13521: \@logintext,$confhash,\%changes); 13522: } 13523: } 13524: return ($errors,%changes); 13525: } 13526: 13527: sub config_check { 13528: my ($dom,$confname,$servadm) = @_; 13529: my ($configuserok,$author_ok,$switchserver,%currroles); 13530: my $uhome = &Apache::lonnet::homeserver($confname,$dom,1); 13531: ($configuserok,%currroles) = &check_configuser($uhome,$dom, 13532: $confname,$servadm); 13533: if ($configuserok eq 'ok') { 13534: $switchserver = &check_switchserver($dom,$confname); 13535: if ($switchserver eq '') { 13536: $author_ok = &check_authorstatus($dom,$confname,%currroles); 13537: } 13538: } 13539: return ($configuserok,$author_ok,$switchserver); 13540: } 13541: 13542: sub default_change_checker { 13543: my ($role,$images,$links,$bgs,$logintext,$confhash,$changes) = @_; 13544: foreach my $item (@{$links}) { 13545: if ($confhash->{$role}{$item}) { 13546: $changes->{$role}{'links'}{$item} = 1; 13547: } 13548: } 13549: foreach my $item (@{$bgs}) { 13550: if ($confhash->{$role}{$item}) { 13551: $changes->{$role}{'bgs'}{$item} = 1; 13552: } 13553: } 13554: foreach my $item (@{$logintext}) { 13555: if ($confhash->{$role}{$item}) { 13556: $changes->{$role}{'logintext'}{$item} = 1; 13557: } 13558: } 13559: foreach my $img (@{$images}) { 13560: if ($env{'form.'.$role.'_del_'.$img}) { 13561: $confhash->{$role}{$img} = ''; 13562: $changes->{$role}{'images'}{$img} = 1; 13563: } 13564: if ($role eq 'login') { 13565: if ($confhash->{$role}{'showlogo'}{$img} == 0) { 13566: $changes->{$role}{'showlogo'}{$img} = 1; 13567: } 13568: if (ref($confhash->{$role}{'alttext'}) eq 'HASH') { 13569: if ($confhash->{$role}{'alttext'}{$img} ne '') { 13570: $changes->{$role}{'alttext'}{$img} = 1; 13571: } 13572: } 13573: } 13574: } 13575: if ($confhash->{$role}{'font'}) { 13576: $changes->{$role}{'font'} = 1; 13577: } 13578: } 13579: 13580: sub display_colorchgs { 13581: my ($dom,$changes,$roles,$confhash) = @_; 13582: my (%choices,$resulttext); 13583: if (!grep(/^login$/,@{$roles})) { 13584: $resulttext = &mt('Changes made:').'<br />'; 13585: } 13586: foreach my $role (@{$roles}) { 13587: if ($role eq 'login') { 13588: %choices = &login_choices(); 13589: } else { 13590: %choices = &color_font_choices(); 13591: } 13592: if (ref($changes->{$role}) eq 'HASH') { 13593: if ($role ne 'login') { 13594: $resulttext .= '<h4>'.&mt($role).'</h4>'; 13595: } 13596: foreach my $key (sort(keys(%{$changes->{$role}}))) { 13597: if ($role ne 'login') { 13598: $resulttext .= '<ul>'; 13599: } 13600: if (ref($changes->{$role}{$key}) eq 'HASH') { 13601: if ($role ne 'login') { 13602: $resulttext .= '<li>'.&mt($choices{$key}).':<ul>'; 13603: } 13604: foreach my $item (sort(keys(%{$changes->{$role}{$key}}))) { 13605: if (($role eq 'login') && ($key eq 'showlogo')) { 13606: if ($confhash->{$role}{$key}{$item}) { 13607: $resulttext .= '<li>'.&mt("$choices{$item} set to be displayed").'</li>'; 13608: } else { 13609: $resulttext .= '<li>'.&mt("$choices{$item} set to not be displayed").'</li>'; 13610: } 13611: } elsif (($role eq 'login') && ($key eq 'alttext')) { 13612: if ($confhash->{$role}{$key}{$item} ne '') { 13613: $resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} set to [_1].", 13614: $confhash->{$role}{$key}{$item}).'</li>'; 13615: } else { 13616: $resulttext .= '<li>'.&mt("$choices{$key} for $choices{$item} deleted.").'</li>'; 13617: } 13618: } elsif ($confhash->{$role}{$item} eq '') { 13619: $resulttext .= '<li>'.&mt("$choices{$item} set to default").'</li>'; 13620: } else { 13621: my $newitem = $confhash->{$role}{$item}; 13622: if ($key eq 'images') { 13623: $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />'; 13624: } 13625: $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>'; 13626: } 13627: } 13628: if ($role ne 'login') { 13629: $resulttext .= '</ul></li>'; 13630: } 13631: } else { 13632: if ($confhash->{$role}{$key} eq '') { 13633: $resulttext .= '<li>'.&mt("$choices{$key} set to default").'</li>'; 13634: } else { 13635: $resulttext .= '<li>'.&mt("$choices{$key} set to [_1]",$confhash->{$role}{$key}).'</li>'; 13636: } 13637: } 13638: if ($role ne 'login') { 13639: $resulttext .= '</ul>'; 13640: } 13641: } 13642: } 13643: } 13644: return $resulttext; 13645: } 13646: 13647: sub thumb_dimensions { 13648: return ('200','50'); 13649: } 13650: 13651: sub check_dimensions { 13652: my ($inputfile) = @_; 13653: my ($fullwidth,$fullheight); 13654: if ($inputfile =~ m|^[/\w.\-]+$|) { 13655: if (open(PIPE,"identify $inputfile 2>&1 |")) { 13656: my $imageinfo = <PIPE>; 13657: if (!close(PIPE)) { 13658: &Apache::lonnet::logthis("Failed to close PIPE opened to retrieve image information for $inputfile"); 13659: } 13660: chomp($imageinfo); 13661: my ($fullsize) = 13662: ($imageinfo =~ /^\Q$inputfile\E\s+\w+\s+(\d+x\d+)/); 13663: if ($fullsize) { 13664: ($fullwidth,$fullheight) = split(/x/,$fullsize); 13665: } 13666: } 13667: } 13668: return ($fullwidth,$fullheight); 13669: } 13670: 13671: sub check_configuser { 13672: my ($uhome,$dom,$confname,$servadm) = @_; 13673: my ($configuserok,%currroles); 13674: if ($uhome eq 'no_host') { 13675: srand( time() ^ ($$ + ($$ << 15)) ); # Seed rand. 13676: my $configpass = &LONCAPA::Enrollment::create_password($dom); 13677: $configuserok = 13678: &Apache::lonnet::modifyuser($dom,$confname,'','internal', 13679: $configpass,'','','','','',undef,$servadm); 13680: } else { 13681: $configuserok = 'ok'; 13682: %currroles = 13683: &Apache::lonnet::get_my_roles($confname,$dom,'userroles'); 13684: } 13685: return ($configuserok,%currroles); 13686: } 13687: 13688: sub check_authorstatus { 13689: my ($dom,$confname,%currroles) = @_; 13690: my $author_ok; 13691: if (!$currroles{':'.$dom.':au'}) { 13692: my $start = time; 13693: my $end = 0; 13694: $author_ok = 13695: &Apache::lonnet::assignrole($dom,$confname,'/'.$dom.'/', 13696: 'au',$end,$start,'','','domconfig'); 13697: } else { 13698: $author_ok = 'ok'; 13699: } 13700: return $author_ok; 13701: } 13702: 13703: sub publishlogo { 13704: my ($r,$action,$formname,$dom,$confname,$subdir,$thumbwidth,$thumbheight,$savefileas) = @_; 13705: my ($output,$fname,$logourl,$madethumb); 13706: if ($action eq 'upload') { 13707: $fname=$env{'form.'.$formname.'.filename'}; 13708: chop($env{'form.'.$formname}); 13709: } else { 13710: ($fname) = ($formname =~ /([^\/]+)$/); 13711: } 13712: if ($savefileas ne '') { 13713: $fname = $savefileas; 13714: } 13715: $fname=&Apache::lonnet::clean_filename($fname); 13716: # See if there is anything left 13717: unless ($fname) { return ('error: no uploaded file'); } 13718: $fname="$subdir/$fname"; 13719: my $docroot=$r->dir_config('lonDocRoot'); 13720: my $filepath="$docroot/priv"; 13721: my $relpath = "$dom/$confname"; 13722: my ($fnamepath,$file,$fetchthumb); 13723: $file=$fname; 13724: if ($fname=~m|/|) { 13725: ($fnamepath,$file) = ($fname =~ m|^(.*)/([^/]+)$|); 13726: } 13727: my @parts=split(/\//,"$filepath/$relpath/$fnamepath"); 13728: my $count; 13729: for ($count=5;$count<=$#parts;$count++) { 13730: $filepath.="/$parts[$count]"; 13731: if ((-e $filepath)!=1) { 13732: mkdir($filepath,02770); 13733: } 13734: } 13735: # Check for bad extension and disallow upload 13736: if ($file=~/\.(\w+)$/ && 13737: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) { 13738: $output = 13739: &mt('Invalid file extension ([_1]) - reserved for internal use.',$1); 13740: } elsif ($file=~/\.(\w+)$/ && 13741: !defined(&Apache::loncommon::fileembstyle($1))) { 13742: $output = &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1); 13743: } elsif ($file=~/\.(\d+)\.(\w+)$/) { 13744: $output = &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2); 13745: } elsif (-d "$filepath/$file") { 13746: $output = &mt('Filename is a directory name - rename the file and re-upload'); 13747: } else { 13748: my $source = $filepath.'/'.$file; 13749: my $logfile; 13750: if (!open($logfile,">>",$source.'.log')) { 13751: return (&mt('No write permission to Authoring Space')); 13752: } 13753: print $logfile 13754: "\n================= Publish ".localtime()." ================\n". 13755: $env{'user.name'}.':'.$env{'user.domain'}."\n"; 13756: # Save the file 13757: if (!open(FH,">",$source)) { 13758: &Apache::lonnet::logthis('Failed to create '.$source); 13759: return (&mt('Failed to create file')); 13760: } 13761: if ($action eq 'upload') { 13762: if (!print FH ($env{'form.'.$formname})) { 13763: &Apache::lonnet::logthis('Failed to write to '.$source); 13764: return (&mt('Failed to write file')); 13765: } 13766: } else { 13767: my $original = &Apache::lonnet::filelocation('',$formname); 13768: if(!copy($original,$source)) { 13769: &Apache::lonnet::logthis('Failed to copy '.$original.' to '.$source); 13770: return (&mt('Failed to write file')); 13771: } 13772: } 13773: close(FH); 13774: chmod(0660, $source); # Permissions to rw-rw---. 13775: 13776: my $targetdir=$docroot.'/res/'.$dom.'/'.$confname .'/'.$fnamepath; 13777: my $copyfile=$targetdir.'/'.$file; 13778: 13779: my @parts=split(/\//,$targetdir); 13780: my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]"; 13781: for (my $count=5;$count<=$#parts;$count++) { 13782: $path.="/$parts[$count]"; 13783: if (!-e $path) { 13784: print $logfile "\nCreating directory ".$path; 13785: mkdir($path,02770); 13786: } 13787: } 13788: my $versionresult; 13789: if (-e $copyfile) { 13790: $versionresult = &logo_versioning($targetdir,$file,$logfile); 13791: } else { 13792: $versionresult = 'ok'; 13793: } 13794: if ($versionresult eq 'ok') { 13795: if (copy($source,$copyfile)) { 13796: print $logfile "\nCopied original source to ".$copyfile."\n"; 13797: $output = 'ok'; 13798: $logourl = '/res/'.$dom.'/'.$confname.'/'.$fname; 13799: push(@{$modified_urls},[$copyfile,$source]); 13800: my $metaoutput = 13801: &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile); 13802: unless ($registered_cleanup) { 13803: my $handlers = $r->get_handlers('PerlCleanupHandler'); 13804: $r->set_handlers('PerlCleanupHandler' => [\¬ifysubscribed,@{$handlers}]); 13805: $registered_cleanup=1; 13806: } 13807: } else { 13808: print $logfile "\nUnable to write ".$copyfile.':'.$!."\n"; 13809: $output = &mt('Failed to copy file to RES space').", $!"; 13810: } 13811: if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) { 13812: my $inputfile = $filepath.'/'.$file; 13813: my $outfile = $filepath.'/'.'tn-'.$file; 13814: my ($fullwidth,$fullheight) = &check_dimensions($inputfile); 13815: if ($fullwidth ne '' && $fullheight ne '') { 13816: if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) { 13817: my $thumbsize = $thumbwidth.'x'.$thumbheight; 13818: my @args = ('convert','-sample',$thumbsize,$inputfile,$outfile); 13819: system({$args[0]} @args); 13820: chmod(0660, $filepath.'/tn-'.$file); 13821: if (-e $outfile) { 13822: my $copyfile=$targetdir.'/tn-'.$file; 13823: if (copy($outfile,$copyfile)) { 13824: print $logfile "\nCopied source to ".$copyfile."\n"; 13825: my $thumb_metaoutput = 13826: &write_metadata($dom,$confname,$formname, 13827: $targetdir,'tn-'.$file,$logfile); 13828: push(@{$modified_urls},[$copyfile,$outfile]); 13829: unless ($registered_cleanup) { 13830: my $handlers = $r->get_handlers('PerlCleanupHandler'); 13831: $r->set_handlers('PerlCleanupHandler' => [\¬ifysubscribed,@{$handlers}]); 13832: $registered_cleanup=1; 13833: } 13834: $madethumb = 1; 13835: } else { 13836: print $logfile "\nUnable to write ".$copyfile. 13837: ':'.$!."\n"; 13838: } 13839: } 13840: } 13841: } 13842: } 13843: } else { 13844: $output = $versionresult; 13845: } 13846: } 13847: return ($output,$logourl,$madethumb); 13848: } 13849: 13850: sub logo_versioning { 13851: my ($targetdir,$file,$logfile) = @_; 13852: my $target = $targetdir.'/'.$file; 13853: my ($maxversion,$fn,$extn,$output); 13854: $maxversion = 0; 13855: if ($file =~ /^(.+)\.(\w+)$/) { 13856: $fn=$1; 13857: $extn=$2; 13858: } 13859: opendir(DIR,$targetdir); 13860: while (my $filename=readdir(DIR)) { 13861: if ($filename=~/\Q$fn\E\.(\d+)\.\Q$extn\E$/) { 13862: $maxversion=($1>$maxversion)?$1:$maxversion; 13863: } 13864: } 13865: $maxversion++; 13866: print $logfile "\nCreating old version ".$maxversion."\n"; 13867: my $copyfile=$targetdir.'/'.$fn.'.'.$maxversion.'.'.$extn; 13868: if (copy($target,$copyfile)) { 13869: print $logfile "Copied old target to ".$copyfile."\n"; 13870: $copyfile=$copyfile.'.meta'; 13871: if (copy($target.'.meta',$copyfile)) { 13872: print $logfile "Copied old target metadata to ".$copyfile."\n"; 13873: $output = 'ok'; 13874: } else { 13875: print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n"; 13876: $output = &mt('Failed to copy old meta').", $!, "; 13877: } 13878: } else { 13879: print $logfile "Unable to write ".$copyfile.':'.$!."\n"; 13880: $output = &mt('Failed to copy old target').", $!, "; 13881: } 13882: return $output; 13883: } 13884: 13885: sub write_metadata { 13886: my ($dom,$confname,$formname,$targetdir,$file,$logfile) = @_; 13887: my (%metadatafields,%metadatakeys,$output); 13888: $metadatafields{'title'}=$formname; 13889: $metadatafields{'creationdate'}=time; 13890: $metadatafields{'lastrevisiondate'}=time; 13891: $metadatafields{'copyright'}='public'; 13892: $metadatafields{'modifyinguser'}=$env{'user.name'}.':'. 13893: $env{'user.domain'}; 13894: $metadatafields{'authorspace'}=$confname.':'.$dom; 13895: $metadatafields{'domain'}=$dom; 13896: { 13897: print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file; 13898: my $mfh; 13899: if (open($mfh,">",$targetdir.'/'.$file.'.meta')) { 13900: foreach (sort(keys(%metadatafields))) { 13901: unless ($_=~/\./) { 13902: my $unikey=$_; 13903: $unikey=~/^([A-Za-z]+)/; 13904: my $tag=$1; 13905: $tag=~tr/A-Z/a-z/; 13906: print $mfh "\n\<$tag"; 13907: foreach (split(/\,/,$metadatakeys{$unikey})) { 13908: my $value=$metadatafields{$unikey.'.'.$_}; 13909: $value=~s/\"/\'\'/g; 13910: print $mfh ' '.$_.'="'.$value.'"'; 13911: } 13912: print $mfh '>'. 13913: &HTML::Entities::encode($metadatafields{$unikey},'<>&"') 13914: .'</'.$tag.'>'; 13915: } 13916: } 13917: $output = 'ok'; 13918: print $logfile "\nWrote metadata"; 13919: close($mfh); 13920: } else { 13921: print $logfile "\nFailed to open metadata file"; 13922: $output = &mt('Could not write metadata'); 13923: } 13924: } 13925: return $output; 13926: } 13927: 13928: sub notifysubscribed { 13929: foreach my $targetsource (@{$modified_urls}){ 13930: next unless (ref($targetsource) eq 'ARRAY'); 13931: my ($target,$source)=@{$targetsource}; 13932: if ($source ne '') { 13933: if (open(my $logfh,">>",$source.'.log')) { 13934: print $logfh "\nCleanup phase: Notifications\n"; 13935: my @subscribed=&subscribed_hosts($target); 13936: foreach my $subhost (@subscribed) { 13937: print $logfh "\nNotifying host ".$subhost.':'; 13938: my $reply=&Apache::lonnet::critical('update:'.$target,$subhost); 13939: print $logfh $reply; 13940: } 13941: my @subscribedmeta=&subscribed_hosts("$target.meta"); 13942: foreach my $subhost (@subscribedmeta) { 13943: print $logfh "\nNotifying host for metadata only ".$subhost.':'; 13944: my $reply=&Apache::lonnet::critical('update:'.$target.'.meta', 13945: $subhost); 13946: print $logfh $reply; 13947: } 13948: print $logfh "\n============ Done ============\n"; 13949: close($logfh); 13950: } 13951: } 13952: } 13953: return OK; 13954: } 13955: 13956: sub subscribed_hosts { 13957: my ($target) = @_; 13958: my @subscribed; 13959: if (open(my $fh,"<","$target.subscription")) { 13960: while (my $subline=<$fh>) { 13961: if ($subline =~ /^($match_lonid):/) { 13962: my $host = $1; 13963: if ($host ne $Apache::lonnet::perlvar{'lonHostID'}) { 13964: unless (grep(/^\Q$host\E$/,@subscribed)) { 13965: push(@subscribed,$host); 13966: } 13967: } 13968: } 13969: } 13970: } 13971: return @subscribed; 13972: } 13973: 13974: sub check_switchserver { 13975: my ($dom,$confname) = @_; 13976: my ($allowed,$switchserver); 13977: my $home = &Apache::lonnet::homeserver($confname,$dom); 13978: if ($home eq 'no_host') { 13979: $home = &Apache::lonnet::domain($dom,'primary'); 13980: } 13981: my @ids=&Apache::lonnet::current_machine_ids(); 13982: foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } 13983: if (!$allowed) { 13984: $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&role=dc./'.$dom.'/&destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>'; 13985: } 13986: return $switchserver; 13987: } 13988: 13989: sub modify_quotas { 13990: my ($r,$dom,$action,$lastactref,%domconfig) = @_; 13991: my ($context,@usertools,@options,%validations,%titles,%confhash,%toolshash, 13992: %limithash,$toolregexp,%conditions,$resulttext,%changes,$confname,$configuserok, 13993: $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref, 13994: $validationfieldsref); 13995: if ($action eq 'quotas') { 13996: $context = 'tools'; 13997: } else { 13998: $context = $action; 13999: } 14000: if ($context eq 'requestcourses') { 14001: @usertools = ('official','unofficial','community','textbook','placement','lti'); 14002: @options =('norequest','approval','validate','autolimit'); 14003: %validations = &Apache::lonnet::auto_courserequest_checks($dom); 14004: %titles = &courserequest_titles(); 14005: $toolregexp = join('|',@usertools); 14006: %conditions = &courserequest_conditions(); 14007: $confname = $dom.'-domainconfig'; 14008: my $servadm = $r->dir_config('lonAdmEMail'); 14009: ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); 14010: ($validationitemsref,$validationnamesref,$validationfieldsref) = 14011: &Apache::loncoursequeueadmin::requestcourses_validation_types(); 14012: } elsif ($context eq 'requestauthor') { 14013: @usertools = ('author'); 14014: %titles = &authorrequest_titles(); 14015: } else { 14016: @usertools = ('aboutme','blog','webdav','portfolio','timezone'); 14017: %titles = &tool_titles(); 14018: } 14019: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 14020: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 14021: foreach my $key (keys(%env)) { 14022: if ($context eq 'requestcourses') { 14023: if ($key =~ /^form\.crsreq_($toolregexp)_(.+)$/) { 14024: my $item = $1; 14025: my $type = $2; 14026: if ($type =~ /^limit_(.+)/) { 14027: $limithash{$item}{$1} = $env{$key}; 14028: } else { 14029: $confhash{$item}{$type} = $env{$key}; 14030: } 14031: } 14032: } elsif ($context eq 'requestauthor') { 14033: if ($key =~ /^\Qform.authorreq_\E(.+)$/) { 14034: $confhash{$1} = $env{$key}; 14035: } 14036: } else { 14037: if ($key =~ /^form\.quota_(.+)$/) { 14038: $confhash{'defaultquota'}{$1} = $env{$key}; 14039: } elsif ($key =~ /^form\.authorquota_(.+)$/) { 14040: $confhash{'authorquota'}{$1} = $env{$key}; 14041: } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) { 14042: @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key); 14043: } 14044: } 14045: } 14046: if (($context eq 'requestcourses') || ($context eq 'requestauthor')) { 14047: my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval'); 14048: @approvalnotify = sort(@approvalnotify); 14049: $confhash{'notify'}{'approval'} = join(',',@approvalnotify); 14050: my @crstypes = ('official','unofficial','community','textbook','placement','lti'); 14051: my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode'); 14052: foreach my $type (@hasuniquecode) { 14053: if (grep(/^\Q$type\E$/,@crstypes)) { 14054: $confhash{'uniquecode'}{$type} = 1; 14055: } 14056: } 14057: my (%newbook,%allpos); 14058: if ($context eq 'requestcourses') { 14059: foreach my $type ('textbooks','templates') { 14060: @{$allpos{$type}} = (); 14061: my $invalid; 14062: if ($type eq 'textbooks') { 14063: $invalid = &mt('Invalid LON-CAPA course for textbook'); 14064: } else { 14065: $invalid = &mt('Invalid LON-CAPA course for template'); 14066: } 14067: if ($env{'form.'.$type.'_addbook'}) { 14068: if (($env{'form.'.$type.'_addbook_cnum'} =~ /^$match_courseid$/) && 14069: ($env{'form.'.$type.'_addbook_cdom'} =~ /^$match_domain$/)) { 14070: if (&Apache::lonnet::homeserver($env{'form.'.$type.'_addbook_cnum'}, 14071: $env{'form.'.$type.'_addbook_cdom'}) eq 'no_host') { 14072: $errors .= '<li><span class="LC_error">'.$invalid.'</span></li>'; 14073: } else { 14074: $newbook{$type} = $env{'form.'.$type.'_addbook_cdom'}.'_'.$env{'form.'.$type.'_addbook_cnum'}; 14075: my $position = $env{'form.'.$type.'_addbook_pos'}; 14076: $position =~ s/\D+//g; 14077: if ($position ne '') { 14078: $allpos{$type}[$position] = $newbook{$type}; 14079: } 14080: } 14081: } else { 14082: $errors .= '<li><span class="LC_error">'.$invalid.'</span></li>'; 14083: } 14084: } 14085: } 14086: } 14087: if (ref($domconfig{$action}) eq 'HASH') { 14088: if (ref($domconfig{$action}{'notify'}) eq 'HASH') { 14089: if ($domconfig{$action}{'notify'}{'approval'} ne $confhash{'notify'}{'approval'}) { 14090: $changes{'notify'}{'approval'} = 1; 14091: } 14092: } else { 14093: if ($confhash{'notify'}{'approval'}) { 14094: $changes{'notify'}{'approval'} = 1; 14095: } 14096: } 14097: if (ref($domconfig{$action}{'uniquecode'}) eq 'HASH') { 14098: if (ref($confhash{'uniquecode'}) eq 'HASH') { 14099: foreach my $crstype (keys(%{$domconfig{$action}{'uniquecode'}})) { 14100: unless ($confhash{'uniquecode'}{$crstype}) { 14101: $changes{'uniquecode'} = 1; 14102: } 14103: } 14104: unless ($changes{'uniquecode'}) { 14105: foreach my $crstype (keys(%{$confhash{'uniquecode'}})) { 14106: unless ($domconfig{$action}{'uniquecode'}{$crstype}) { 14107: $changes{'uniquecode'} = 1; 14108: } 14109: } 14110: } 14111: } else { 14112: $changes{'uniquecode'} = 1; 14113: } 14114: } elsif (ref($confhash{'uniquecode'}) eq 'HASH') { 14115: $changes{'uniquecode'} = 1; 14116: } 14117: if ($context eq 'requestcourses') { 14118: foreach my $type ('textbooks','templates') { 14119: if (ref($domconfig{$action}{$type}) eq 'HASH') { 14120: my %deletions; 14121: my @todelete = &Apache::loncommon::get_env_multiple('form.'.$type.'_del'); 14122: if (@todelete) { 14123: map { $deletions{$_} = 1; } @todelete; 14124: } 14125: my %imgdeletions; 14126: my @todeleteimages = &Apache::loncommon::get_env_multiple('form.'.$type.'_image_del'); 14127: if (@todeleteimages) { 14128: map { $imgdeletions{$_} = 1; } @todeleteimages; 14129: } 14130: my $maxnum = $env{'form.'.$type.'_maxnum'}; 14131: for (my $i=0; $i<=$maxnum; $i++) { 14132: my $itemid = $env{'form.'.$type.'_id_'.$i}; 14133: my ($key) = ($itemid =~ /^\Q$type\E_(\w+)$/); 14134: if (ref($domconfig{$action}{$type}{$key}) eq 'HASH') { 14135: if ($deletions{$key}) { 14136: if ($domconfig{$action}{$type}{$key}{'image'}) { 14137: #FIXME need to obsolete item in RES space 14138: } 14139: next; 14140: } else { 14141: my $newpos = $env{'form.'.$itemid}; 14142: $newpos =~ s/\D+//g; 14143: foreach my $item ('subject','title','publisher','author') { 14144: next if ((($item eq 'author') || ($item eq 'publisher')) && 14145: ($type eq 'templates')); 14146: $confhash{$type}{$key}{$item} = $env{'form.'.$type.'_'.$item.'_'.$i}; 14147: if ($domconfig{$action}{$type}{$key}{$item} ne $confhash{$type}{$key}{$item}) { 14148: $changes{$type}{$key} = 1; 14149: } 14150: } 14151: $allpos{$type}[$newpos] = $key; 14152: } 14153: if ($imgdeletions{$key}) { 14154: $changes{$type}{$key} = 1; 14155: #FIXME need to obsolete item in RES space 14156: } elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) { 14157: my ($cdom,$cnum) = split(/_/,$key); 14158: if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') { 14159: $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>'; 14160: } else { 14161: my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i, 14162: $cdom,$cnum,$type,$configuserok, 14163: $switchserver,$author_ok); 14164: if ($imgurl) { 14165: $confhash{$type}{$key}{'image'} = $imgurl; 14166: $changes{$type}{$key} = 1; 14167: } 14168: if ($error) { 14169: &Apache::lonnet::logthis($error); 14170: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 14171: } 14172: } 14173: } elsif ($domconfig{$action}{$type}{$key}{'image'}) { 14174: $confhash{$type}{$key}{'image'} = 14175: $domconfig{$action}{$type}{$key}{'image'}; 14176: } 14177: } 14178: } 14179: } 14180: } 14181: } 14182: } else { 14183: if ($confhash{'notify'}{'approval'}) { 14184: $changes{'notify'}{'approval'} = 1; 14185: } 14186: if (ref($confhash{'uniquecode'} eq 'HASH')) { 14187: $changes{'uniquecode'} = 1; 14188: } 14189: } 14190: if ($context eq 'requestcourses') { 14191: foreach my $type ('textbooks','templates') { 14192: if ($newbook{$type}) { 14193: $changes{$type}{$newbook{$type}} = 1; 14194: foreach my $item ('subject','title','publisher','author') { 14195: next if ((($item eq 'author') || ($item eq 'publisher')) && 14196: ($type eq 'template')); 14197: $env{'form.'.$type.'_addbook_'.$item} =~ s/(`)/'/g; 14198: if ($env{'form.'.$type.'_addbook_'.$item}) { 14199: $confhash{$type}{$newbook{$type}}{$item} = $env{'form.'.$type.'_addbook_'.$item}; 14200: } 14201: } 14202: if ($type eq 'textbooks') { 14203: if ($env{'form.'.$type.'_addbook_image.filename'} ne '') { 14204: my ($cdom,$cnum) = split(/_/,$newbook{$type}); 14205: if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') { 14206: $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>'; 14207: } else { 14208: my ($imageurl,$error) = 14209: &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type, 14210: $configuserok,$switchserver,$author_ok); 14211: if ($imageurl) { 14212: $confhash{$type}{$newbook{$type}}{'image'} = $imageurl; 14213: } 14214: if ($error) { 14215: &Apache::lonnet::logthis($error); 14216: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 14217: } 14218: } 14219: } 14220: } 14221: } 14222: if (@{$allpos{$type}} > 0) { 14223: my $idx = 0; 14224: foreach my $item (@{$allpos{$type}}) { 14225: if ($item ne '') { 14226: $confhash{$type}{$item}{'order'} = $idx; 14227: if (ref($domconfig{$action}) eq 'HASH') { 14228: if (ref($domconfig{$action}{$type}) eq 'HASH') { 14229: if (ref($domconfig{$action}{$type}{$item}) eq 'HASH') { 14230: if ($domconfig{$action}{$type}{$item}{'order'} ne $idx) { 14231: $changes{$type}{$item} = 1; 14232: } 14233: } 14234: } 14235: } 14236: $idx ++; 14237: } 14238: } 14239: } 14240: } 14241: if (ref($validationitemsref) eq 'ARRAY') { 14242: foreach my $item (@{$validationitemsref}) { 14243: if ($item eq 'fields') { 14244: my @changed; 14245: @{$confhash{'validation'}{$item}} = &Apache::loncommon::get_env_multiple('form.requestcourses_validation_'.$item); 14246: if (@{$confhash{'validation'}{$item}} > 0) { 14247: @{$confhash{'validation'}{$item}} = sort(@{$confhash{'validation'}{$item}}); 14248: } 14249: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 14250: if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') { 14251: if (ref($domconfig{'requestcourses'}{'validation'}{$item}) eq 'ARRAY') { 14252: @changed = &Apache::loncommon::compare_arrays($confhash{'validation'}{$item}, 14253: $domconfig{'requestcourses'}{'validation'}{$item}); 14254: } else { 14255: @changed = @{$confhash{'validation'}{$item}}; 14256: } 14257: } else { 14258: @changed = @{$confhash{'validation'}{$item}}; 14259: } 14260: } else { 14261: @changed = @{$confhash{'validation'}{$item}}; 14262: } 14263: if (@changed) { 14264: if ($confhash{'validation'}{$item}) { 14265: $changes{'validation'}{$item} = join(', ',@{$confhash{'validation'}{$item}}); 14266: } else { 14267: $changes{'validation'}{$item} = &mt('None'); 14268: } 14269: } 14270: } else { 14271: $confhash{'validation'}{$item} = $env{'form.requestcourses_validation_'.$item}; 14272: if ($item eq 'markup') { 14273: if ($env{'form.requestcourses_validation_'.$item}) { 14274: $env{'form.requestcourses_validation_'.$item} =~ s/[\n\r\f]+/\s/gs; 14275: } 14276: } 14277: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 14278: if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') { 14279: if ($domconfig{'requestcourses'}{'validation'}{$item} ne $confhash{'validation'}{$item}) { 14280: $changes{'validation'}{$item} = $confhash{'validation'}{$item}; 14281: } 14282: } else { 14283: if ($confhash{'validation'}{$item} ne '') { 14284: $changes{'validation'}{$item} = $confhash{'validation'}{$item}; 14285: } 14286: } 14287: } else { 14288: if ($confhash{'validation'}{$item} ne '') { 14289: $changes{'validation'}{$item} = $confhash{'validation'}{$item}; 14290: } 14291: } 14292: } 14293: } 14294: } 14295: if ($env{'form.validationdc'}) { 14296: my $newval = $env{'form.validationdc'}; 14297: my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']); 14298: if (exists($domcoords{$newval})) { 14299: $confhash{'validation'}{'dc'} = $newval; 14300: } 14301: } 14302: if (ref($confhash{'validation'}) eq 'HASH') { 14303: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 14304: if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') { 14305: if ($domconfig{'requestcourses'}{'validation'}{'dc'}) { 14306: unless ($confhash{'validation'}{'dc'} eq $domconfig{'requestcourses'}{'validation'}{'dc'}) { 14307: if ($confhash{'validation'}{'dc'} eq '') { 14308: $changes{'validation'}{'dc'} = &mt('None'); 14309: } else { 14310: $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'}; 14311: } 14312: } 14313: } elsif ($confhash{'validation'}{'dc'} ne '') { 14314: $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'}; 14315: } 14316: } elsif ($confhash{'validation'}{'dc'} ne '') { 14317: $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'}; 14318: } 14319: } elsif ($confhash{'validation'}{'dc'} ne '') { 14320: $changes{'validation'}{'dc'} = $confhash{'validation'}{'dc'}; 14321: } 14322: } else { 14323: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 14324: if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') { 14325: if ($domconfig{'requestcourses'}{'validation'}{'dc'}) { 14326: $changes{'validation'}{'dc'} = &mt('None'); 14327: } 14328: } 14329: } 14330: } 14331: } 14332: } else { 14333: $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'}; 14334: $confhash{'authorquota'}{'default'} = $env{'form.authorquota'}; 14335: } 14336: foreach my $item (@usertools) { 14337: foreach my $type (@{$types},'default','_LC_adv') { 14338: my $unset; 14339: if ($context eq 'requestcourses') { 14340: $unset = '0'; 14341: if ($type eq '_LC_adv') { 14342: $unset = ''; 14343: } 14344: if ($confhash{$item}{$type} eq 'autolimit') { 14345: $confhash{$item}{$type} .= '='; 14346: unless ($limithash{$item}{$type} =~ /\D/) { 14347: $confhash{$item}{$type} .= $limithash{$item}{$type}; 14348: } 14349: } 14350: } elsif ($context eq 'requestauthor') { 14351: $unset = '0'; 14352: if ($type eq '_LC_adv') { 14353: $unset = ''; 14354: } 14355: } else { 14356: if (grep(/^\Q$type\E$/,@{$toolshash{$item}})) { 14357: $confhash{$item}{$type} = 1; 14358: } else { 14359: $confhash{$item}{$type} = 0; 14360: } 14361: } 14362: if (ref($domconfig{$action}) eq 'HASH') { 14363: if ($action eq 'requestauthor') { 14364: if ($domconfig{$action}{$type} ne $confhash{$type}) { 14365: $changes{$type} = 1; 14366: } 14367: } elsif (ref($domconfig{$action}{$item}) eq 'HASH') { 14368: if ($domconfig{$action}{$item}{$type} ne $confhash{$item}{$type}) { 14369: $changes{$item}{$type} = 1; 14370: } 14371: } else { 14372: if ($context eq 'requestcourses') { 14373: if ($confhash{$item}{$type} ne $unset) { 14374: $changes{$item}{$type} = 1; 14375: } 14376: } else { 14377: if (!$confhash{$item}{$type}) { 14378: $changes{$item}{$type} = 1; 14379: } 14380: } 14381: } 14382: } else { 14383: if ($context eq 'requestcourses') { 14384: if ($confhash{$item}{$type} ne $unset) { 14385: $changes{$item}{$type} = 1; 14386: } 14387: } elsif ($context eq 'requestauthor') { 14388: if ($confhash{$type} ne $unset) { 14389: $changes{$type} = 1; 14390: } 14391: } else { 14392: if (!$confhash{$item}{$type}) { 14393: $changes{$item}{$type} = 1; 14394: } 14395: } 14396: } 14397: } 14398: } 14399: unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { 14400: if (ref($domconfig{'quotas'}) eq 'HASH') { 14401: if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') { 14402: foreach my $key (keys(%{$domconfig{'quotas'}{'defaultquota'}})) { 14403: if (exists($confhash{'defaultquota'}{$key})) { 14404: if ($confhash{'defaultquota'}{$key} ne $domconfig{'quotas'}{'defaultquota'}{$key}) { 14405: $changes{'defaultquota'}{$key} = 1; 14406: } 14407: } else { 14408: $confhash{'defaultquota'}{$key} = $domconfig{'quotas'}{'defaultquota'}{$key}; 14409: } 14410: } 14411: } else { 14412: foreach my $key (keys(%{$domconfig{'quotas'}})) { 14413: if (exists($confhash{'defaultquota'}{$key})) { 14414: if ($confhash{'defaultquota'}{$key} ne $domconfig{'quotas'}{$key}) { 14415: $changes{'defaultquota'}{$key} = 1; 14416: } 14417: } else { 14418: $confhash{'defaultquota'}{$key} = $domconfig{'quotas'}{$key}; 14419: } 14420: } 14421: } 14422: if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') { 14423: foreach my $key (keys(%{$domconfig{'quotas'}{'authorquota'}})) { 14424: if (exists($confhash{'authorquota'}{$key})) { 14425: if ($confhash{'authorquota'}{$key} ne $domconfig{'quotas'}{'authorquota'}{$key}) { 14426: $changes{'authorquota'}{$key} = 1; 14427: } 14428: } else { 14429: $confhash{'authorquota'}{$key} = $domconfig{'quotas'}{'authorquota'}{$key}; 14430: } 14431: } 14432: } 14433: } 14434: if (ref($confhash{'defaultquota'}) eq 'HASH') { 14435: foreach my $key (keys(%{$confhash{'defaultquota'}})) { 14436: if (ref($domconfig{'quotas'}) eq 'HASH') { 14437: if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') { 14438: if (!exists($domconfig{'quotas'}{'defaultquota'}{$key})) { 14439: $changes{'defaultquota'}{$key} = 1; 14440: } 14441: } else { 14442: if (!exists($domconfig{'quotas'}{$key})) { 14443: $changes{'defaultquota'}{$key} = 1; 14444: } 14445: } 14446: } else { 14447: $changes{'defaultquota'}{$key} = 1; 14448: } 14449: } 14450: } 14451: if (ref($confhash{'authorquota'}) eq 'HASH') { 14452: foreach my $key (keys(%{$confhash{'authorquota'}})) { 14453: if (ref($domconfig{'quotas'}) eq 'HASH') { 14454: if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') { 14455: if (!exists($domconfig{'quotas'}{'authorquota'}{$key})) { 14456: $changes{'authorquota'}{$key} = 1; 14457: } 14458: } else { 14459: $changes{'authorquota'}{$key} = 1; 14460: } 14461: } else { 14462: $changes{'authorquota'}{$key} = 1; 14463: } 14464: } 14465: } 14466: } 14467: 14468: if ($context eq 'requestauthor') { 14469: $domdefaults{'requestauthor'} = \%confhash; 14470: } else { 14471: foreach my $key (keys(%confhash)) { 14472: unless (($context eq 'requestcourses') && (($key eq 'textbooks') || ($key eq 'templates'))) { 14473: $domdefaults{$key} = $confhash{$key}; 14474: } 14475: } 14476: } 14477: 14478: my %quotahash = ( 14479: $action => { %confhash } 14480: ); 14481: my $putresult = &Apache::lonnet::put_dom('configuration',\%quotahash, 14482: $dom); 14483: if ($putresult eq 'ok') { 14484: if (keys(%changes) > 0) { 14485: my $cachetime = 24*60*60; 14486: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 14487: if (ref($lastactref) eq 'HASH') { 14488: $lastactref->{'domdefaults'} = 1; 14489: } 14490: $resulttext = &mt('Changes made:').'<ul>'; 14491: unless (($context eq 'requestcourses') || 14492: ($context eq 'requestauthor')) { 14493: if (ref($changes{'defaultquota'}) eq 'HASH') { 14494: $resulttext .= '<li>'.&mt('Portfolio default quotas').'<ul>'; 14495: foreach my $type (@{$types},'default') { 14496: if (defined($changes{'defaultquota'}{$type})) { 14497: my $typetitle = $usertypes->{$type}; 14498: if ($type eq 'default') { 14499: $typetitle = $othertitle; 14500: } 14501: $resulttext .= '<li>'.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'defaultquota'}{$type}).'</li>'; 14502: } 14503: } 14504: $resulttext .= '</ul></li>'; 14505: } 14506: if (ref($changes{'authorquota'}) eq 'HASH') { 14507: $resulttext .= '<li>'.&mt('Authoring Space default quotas').'<ul>'; 14508: foreach my $type (@{$types},'default') { 14509: if (defined($changes{'authorquota'}{$type})) { 14510: my $typetitle = $usertypes->{$type}; 14511: if ($type eq 'default') { 14512: $typetitle = $othertitle; 14513: } 14514: $resulttext .= '<li>'.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'authorquota'}{$type}).'</li>'; 14515: } 14516: } 14517: $resulttext .= '</ul></li>'; 14518: } 14519: } 14520: my %newenv; 14521: foreach my $item (@usertools) { 14522: my (%haschgs,%inconf); 14523: if ($context eq 'requestauthor') { 14524: %haschgs = %changes; 14525: %inconf = %confhash; 14526: } else { 14527: if (ref($changes{$item}) eq 'HASH') { 14528: %haschgs = %{$changes{$item}}; 14529: } 14530: if (ref($confhash{$item}) eq 'HASH') { 14531: %inconf = %{$confhash{$item}}; 14532: } 14533: } 14534: if (keys(%haschgs) > 0) { 14535: my $newacc = 14536: &Apache::lonnet::usertools_access($env{'user.name'}, 14537: $env{'user.domain'}, 14538: $item,'reload',$context); 14539: if (($context eq 'requestcourses') || 14540: ($context eq 'requestauthor')) { 14541: if ($env{'environment.canrequest.'.$item} ne $newacc) { 14542: $newenv{'environment.canrequest.'.$item} = $newacc; 14543: } 14544: } else { 14545: if ($env{'environment.availabletools.'.$item} ne $newacc) { 14546: $newenv{'environment.availabletools.'.$item} = $newacc; 14547: } 14548: } 14549: unless ($context eq 'requestauthor') { 14550: $resulttext .= '<li>'.$titles{$item}.'<ul>'; 14551: } 14552: foreach my $type (@{$types},'default','_LC_adv') { 14553: if ($haschgs{$type}) { 14554: my $typetitle = $usertypes->{$type}; 14555: if ($type eq 'default') { 14556: $typetitle = $othertitle; 14557: } elsif ($type eq '_LC_adv') { 14558: $typetitle = 'LON-CAPA Advanced Users'; 14559: } 14560: if ($inconf{$type}) { 14561: if ($context eq 'requestcourses') { 14562: my $cond; 14563: if ($inconf{$type} =~ /^autolimit=(\d*)$/) { 14564: if ($1 eq '') { 14565: $cond = &mt('(Automatic processing of any request).'); 14566: } else { 14567: $cond = &mt('(Automatic processing of requests up to limit of [quant,_1,request] per user).',$1); 14568: } 14569: } else { 14570: $cond = $conditions{$inconf{$type}}; 14571: } 14572: $resulttext .= '<li>'.&mt('Set to be available to [_1].',$typetitle).' '.$cond.'</li>'; 14573: } elsif ($context eq 'requestauthor') { 14574: $resulttext .= '<li>'.&mt('Set to "[_1]" for "[_2]".', 14575: $titles{$inconf{$type}},$typetitle); 14576: 14577: } else { 14578: $resulttext .= '<li>'.&mt('Set to be available to [_1]',$typetitle).'</li>'; 14579: } 14580: } else { 14581: if ($type eq '_LC_adv') { 14582: if ($inconf{$type} eq '0') { 14583: $resulttext .= '<li>'.&mt('Set to be unavailable to [_1]',$typetitle).'</li>'; 14584: } else { 14585: $resulttext .= '<li>'.&mt('No override set for [_1]',$typetitle).'</li>'; 14586: } 14587: } else { 14588: $resulttext .= '<li>'.&mt('Set to be unavailable to [_1]',$typetitle).'</li>'; 14589: } 14590: } 14591: } 14592: } 14593: unless ($context eq 'requestauthor') { 14594: $resulttext .= '</ul></li>'; 14595: } 14596: } 14597: } 14598: if (($action eq 'requestcourses') || ($action eq 'requestauthor')) { 14599: if (ref($changes{'notify'}) eq 'HASH') { 14600: if ($changes{'notify'}{'approval'}) { 14601: if (ref($confhash{'notify'}) eq 'HASH') { 14602: if ($confhash{'notify'}{'approval'}) { 14603: $resulttext .= '<li>'.&mt('Notification of requests requiring approval will be sent to: ').$confhash{'notify'}{'approval'}.'</li>'; 14604: } else { 14605: $resulttext .= '<li>'.&mt('No Domain Coordinators will receive notification of requests requiring approval.').'</li>'; 14606: } 14607: } 14608: } 14609: } 14610: } 14611: if ($action eq 'requestcourses') { 14612: my @offon = ('off','on'); 14613: if ($changes{'uniquecode'}) { 14614: if (ref($confhash{'uniquecode'}) eq 'HASH') { 14615: my $codestr = join(' ',map{ &mt($_); } sort(keys(%{$confhash{'uniquecode'}}))); 14616: $resulttext .= '<li>'. 14617: &mt('Generation of six character code as course identifier for distribution to students set to on for: [_1].','<b>'.$codestr.'</b>'). 14618: '</li>'; 14619: } else { 14620: $resulttext .= '<li>'.&mt('Generation of six character code as course identifier for distribution to students set to off.'). 14621: '</li>'; 14622: } 14623: } 14624: foreach my $type ('textbooks','templates') { 14625: if (ref($changes{$type}) eq 'HASH') { 14626: $resulttext .= '<li>'.&mt("Available $type updated").'<ul>'; 14627: foreach my $key (sort(keys(%{$changes{$type}}))) { 14628: my %coursehash = &Apache::lonnet::coursedescription($key); 14629: my $coursetitle = $coursehash{'description'}; 14630: my $position = $confhash{$type}{$key}{'order'} + 1; 14631: $resulttext .= '<li>'; 14632: foreach my $item ('subject','title','publisher','author') { 14633: next if ((($item eq 'author') || ($item eq 'publisher')) && 14634: ($type eq 'templates')); 14635: my $name = $item.':'; 14636: $name =~ s/^(\w)/\U$1/; 14637: $resulttext .= &mt($name).' '.$confhash{$type}{$key}{$item}.'<br />'; 14638: } 14639: $resulttext .= ' '.&mt('Order: [_1]',$position).'<br />'; 14640: if ($type eq 'textbooks') { 14641: if ($confhash{$type}{$key}{'image'}) { 14642: $resulttext .= ' '.&mt('Image: [_1]', 14643: '<img src="'.$confhash{$type}{$key}{'image'}.'"'. 14644: ' alt="Textbook cover" />').'<br />'; 14645: } 14646: } 14647: $resulttext .= ' '.&mt('LON-CAPA Course: [_1]',$coursetitle).'</li>'; 14648: } 14649: $resulttext .= '</ul></li>'; 14650: } 14651: } 14652: if (ref($changes{'validation'}) eq 'HASH') { 14653: if ((ref($validationitemsref) eq 'ARRAY') && (ref($validationnamesref) eq 'HASH')) { 14654: $resulttext .= '<li>'.&mt('Validation of courses/communities updated').'<ul>'; 14655: foreach my $item (@{$validationitemsref}) { 14656: if (exists($changes{'validation'}{$item})) { 14657: if ($item eq 'markup') { 14658: $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$validationnamesref->{$item}, 14659: '<br /><pre>'.$changes{'validation'}{$item}.'</pre>').'</li>'; 14660: } else { 14661: $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$validationnamesref->{$item}, 14662: '<b>'.$changes{'validation'}{$item}.'</b>').'</li>'; 14663: } 14664: } 14665: } 14666: if (exists($changes{'validation'}{'dc'})) { 14667: $resulttext .= '<li>'.&mt('Validated course requests identified as processed by: [_1]', 14668: '<b>'.$changes{'validation'}{'dc'}.'</b>').'</li>'; 14669: } 14670: } 14671: } 14672: } 14673: $resulttext .= '</ul>'; 14674: if (keys(%newenv)) { 14675: &Apache::lonnet::appenv(\%newenv); 14676: } 14677: } else { 14678: if ($context eq 'requestcourses') { 14679: $resulttext = &mt('No changes made to rights to request creation of courses.'); 14680: } elsif ($context eq 'requestauthor') { 14681: $resulttext = &mt('No changes made to rights to request author space.'); 14682: } else { 14683: $resulttext = &mt('No changes made to availability of personal information pages, blogs, portfolios or default quotas'); 14684: } 14685: } 14686: } else { 14687: $resulttext = '<span class="LC_error">'. 14688: &mt('An error occurred: [_1]',$putresult).'</span>'; 14689: } 14690: if ($errors) { 14691: $resulttext .= '<p>'.&mt('The following errors occurred when modifying Textbook settings.'). 14692: '<ul>'.$errors.'</ul></p>'; 14693: } 14694: return $resulttext; 14695: } 14696: 14697: sub process_textbook_image { 14698: my ($r,$dom,$confname,$caller,$cdom,$cnum,$type,$configuserok,$switchserver,$author_ok) = @_; 14699: my $filename = $env{'form.'.$caller.'.filename'}; 14700: my ($error,$url); 14701: my ($width,$height) = (50,50); 14702: if ($configuserok eq 'ok') { 14703: if ($switchserver) { 14704: $error = &mt('Upload of textbook image is not permitted to this server: [_1]', 14705: $switchserver); 14706: } elsif ($author_ok eq 'ok') { 14707: my ($result,$imageurl) = 14708: &publishlogo($r,'upload',$caller,$dom,$confname, 14709: "$type/$cdom/$cnum/cover",$width,$height); 14710: if ($result eq 'ok') { 14711: $url = $imageurl; 14712: } else { 14713: $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result); 14714: } 14715: } else { 14716: $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); 14717: } 14718: } else { 14719: $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); 14720: } 14721: return ($url,$error); 14722: } 14723: 14724: sub modify_ltitools { 14725: my ($r,$dom,$action,$lastactref,%domconfig) = @_; 14726: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 14727: my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext); 14728: my $confname = $dom.'-domainconfig'; 14729: my $servadm = $r->dir_config('lonAdmEMail'); 14730: my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); 14731: my (%posslti,%possfield); 14732: my @courseroles = ('cc','in','ta','ep','st'); 14733: my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner); 14734: map { $posslti{$_} = 1; } @ltiroles; 14735: my @allfields = ('fullname','firstname','lastname','email','user','roles'); 14736: map { $possfield{$_} = 1; } @allfields; 14737: my %lt = <itools_names(); 14738: if ($env{'form.ltitools_add'}) { 14739: my $title = $env{'form.ltitools_add_title'}; 14740: $title =~ s/(`)/'/g; 14741: ($newid,my $error) = &get_ltitools_id($dom,$title); 14742: if ($newid) { 14743: my $position = $env{'form.ltitools_add_pos'}; 14744: $position =~ s/\D+//g; 14745: if ($position ne '') { 14746: $allpos[$position] = $newid; 14747: } 14748: $changes{$newid} = 1; 14749: foreach my $item ('title','url','key','secret','lifetime') { 14750: $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g; 14751: if ($item eq 'lifetime') { 14752: $env{'form.ltitools_add_'.$item} =~ s/[^\d.]//g; 14753: } 14754: if ($env{'form.ltitools_add_'.$item}) { 14755: if (($item eq 'key') || ($item eq 'secret')) { 14756: $encconfig{$newid}{$item} = $env{'form.ltitools_add_'.$item}; 14757: } else { 14758: $confhash{$newid}{$item} = $env{'form.ltitools_add_'.$item}; 14759: } 14760: } 14761: } 14762: if ($env{'form.ltitools_add_version'} eq 'LTI-1p0') { 14763: $confhash{$newid}{'version'} = $env{'form.ltitools_add_version'}; 14764: } 14765: if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') { 14766: $confhash{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'}; 14767: } 14768: if ($env{'form.ltitools_add_sigmethod'} eq 'HMAC-SHA256') { 14769: $confhash{$newid}{'sigmethod'} = $env{'form.ltitools_add_sigmethod'}; 14770: } else { 14771: $confhash{$newid}{'sigmethod'} = 'HMAC-SHA1'; 14772: } 14773: foreach my $item ('width','height','linktext','explanation') { 14774: $env{'form.ltitools_add_'.$item} =~ s/^\s+//; 14775: $env{'form.ltitools_add_'.$item} =~ s/\s+$//; 14776: if (($item eq 'width') || ($item eq 'height')) { 14777: if ($env{'form.ltitools_add_'.$item} =~ /^\d+$/) { 14778: $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item}; 14779: } 14780: } else { 14781: if ($env{'form.ltitools_add_'.$item} ne '') { 14782: $confhash{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item}; 14783: } 14784: } 14785: } 14786: if ($env{'form.ltitools_add_target'} eq 'window') { 14787: $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'}; 14788: } elsif ($env{'form.ltitools_add_target'} eq 'tab') { 14789: $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'}; 14790: } else { 14791: $confhash{$newid}{'display'}{'target'} = 'iframe'; 14792: } 14793: foreach my $item ('passback','roster') { 14794: if ($env{'form.ltitools_'.$item.'_add'}) { 14795: $confhash{$newid}{$item} = 1; 14796: if ($env{'form.ltitools_'.$item.'valid_add'} ne '') { 14797: my $lifetime = $env{'form.ltitools_'.$item.'valid_add'}; 14798: $lifetime =~ s/^\s+|\s+$//g; 14799: if ($lifetime =~ /^\d+\.?\d*$/) { 14800: $confhash{$newid}{$item.'valid'} = $lifetime; 14801: } 14802: } 14803: } 14804: } 14805: if ($env{'form.ltitools_add_image.filename'} ne '') { 14806: my ($imageurl,$error) = 14807: &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid, 14808: $configuserok,$switchserver,$author_ok); 14809: if ($imageurl) { 14810: $confhash{$newid}{'image'} = $imageurl; 14811: } 14812: if ($error) { 14813: &Apache::lonnet::logthis($error); 14814: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 14815: } 14816: } 14817: my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_add_fields'); 14818: foreach my $field (@fields) { 14819: if ($possfield{$field}) { 14820: if ($field eq 'roles') { 14821: foreach my $role (@courseroles) { 14822: my $choice = $env{'form.ltitools_add_roles_'.$role}; 14823: if (($choice ne '') && ($posslti{$choice})) { 14824: $confhash{$newid}{'roles'}{$role} = $choice; 14825: if ($role eq 'cc') { 14826: $confhash{$newid}{'roles'}{'co'} = $choice; 14827: } 14828: } 14829: } 14830: } else { 14831: $confhash{$newid}{'fields'}{$field} = 1; 14832: } 14833: } 14834: } 14835: if (ref($confhash{$newid}{'fields'}) eq 'HASH') { 14836: if ($confhash{$newid}{'fields'}{'user'}) { 14837: if ($env{'form.ltitools_userincdom_add'}) { 14838: $confhash{$newid}{'incdom'} = 1; 14839: } 14840: } 14841: } 14842: my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig'); 14843: foreach my $item (@courseconfig) { 14844: $confhash{$newid}{'crsconf'}{$item} = 1; 14845: } 14846: if ($env{'form.ltitools_add_custom'}) { 14847: my $name = $env{'form.ltitools_add_custom_name'}; 14848: my $value = $env{'form.ltitools_add_custom_value'}; 14849: $value =~ s/(`)/'/g; 14850: $name =~ s/(`)/'/g; 14851: $confhash{$newid}{'custom'}{$name} = $value; 14852: } 14853: } else { 14854: my $error = &mt('Failed to acquire unique ID for new external tool'); 14855: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 14856: } 14857: } 14858: if (ref($domconfig{$action}) eq 'HASH') { 14859: my %deletions; 14860: my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del'); 14861: if (@todelete) { 14862: map { $deletions{$_} = 1; } @todelete; 14863: } 14864: my %customadds; 14865: my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd'); 14866: if (@newcustom) { 14867: map { $customadds{$_} = 1; } @newcustom; 14868: } 14869: my %imgdeletions; 14870: my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del'); 14871: if (@todeleteimages) { 14872: map { $imgdeletions{$_} = 1; } @todeleteimages; 14873: } 14874: my $maxnum = $env{'form.ltitools_maxnum'}; 14875: for (my $i=0; $i<=$maxnum; $i++) { 14876: my $itemid = $env{'form.ltitools_id_'.$i}; 14877: $itemid =~ s/\D+//g; 14878: if (ref($domconfig{$action}{$itemid}) eq 'HASH') { 14879: if ($deletions{$itemid}) { 14880: if ($domconfig{$action}{$itemid}{'image'}) { 14881: #FIXME need to obsolete item in RES space 14882: } 14883: $changes{$itemid} = $domconfig{$action}{$itemid}{'title'}; 14884: next; 14885: } else { 14886: my $newpos = $env{'form.ltitools_'.$itemid}; 14887: $newpos =~ s/\D+//g; 14888: foreach my $item ('title','url','lifetime') { 14889: $confhash{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i}; 14890: if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) { 14891: $changes{$itemid} = 1; 14892: } 14893: } 14894: foreach my $item ('key','secret') { 14895: $encconfig{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i}; 14896: if ($domconfig{$action}{$itemid}{$item} ne $encconfig{$itemid}{$item}) { 14897: $changes{$itemid} = 1; 14898: } 14899: } 14900: if ($env{'form.ltitools_version_'.$i} eq 'LTI-1p0') { 14901: $confhash{$itemid}{'version'} = $env{'form.ltitools_version_'.$i}; 14902: } 14903: if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') { 14904: $confhash{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i}; 14905: } 14906: if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') { 14907: $confhash{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i}; 14908: } else { 14909: $confhash{$itemid}{'sigmethod'} = 'HMAC-SHA1'; 14910: } 14911: if ($domconfig{$action}{$itemid}{'sigmethod'} eq '') { 14912: if ($confhash{$itemid}{'sigmethod'} ne 'HMAC-SHA1') { 14913: $changes{$itemid} = 1; 14914: } 14915: } elsif ($domconfig{$action}{$itemid}{'sigmethod'} ne $confhash{$itemid}{'sigmethod'}) { 14916: $changes{$itemid} = 1; 14917: } 14918: foreach my $size ('width','height') { 14919: $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//; 14920: $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//; 14921: if ($env{'form.ltitools_'.$size.'_'.$i} =~ /^\d+$/) { 14922: $confhash{$itemid}{'display'}{$size} = $env{'form.ltitools_'.$size.'_'.$i}; 14923: if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') { 14924: if ($domconfig{$action}{$itemid}{'display'}{$size} ne $confhash{$itemid}{'display'}{$size}) { 14925: $changes{$itemid} = 1; 14926: } 14927: } else { 14928: $changes{$itemid} = 1; 14929: } 14930: } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') { 14931: if ($domconfig{$action}{$itemid}{'display'}{$size} ne '') { 14932: $changes{$itemid} = 1; 14933: } 14934: } 14935: } 14936: foreach my $item ('linktext','explanation') { 14937: $env{'form.ltitools_'.$item.'_'.$i} =~ s/^\s+//; 14938: $env{'form.ltitools_'.$item.'_'.$i} =~ s/\s+$//; 14939: if ($env{'form.ltitools_'.$item.'_'.$i} ne '') { 14940: $confhash{$itemid}{'display'}{$item} = $env{'form.ltitools_'.$item.'_'.$i}; 14941: if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') { 14942: if ($domconfig{$action}{$itemid}{'display'}{$item} ne $confhash{$itemid}{'display'}{$item}) { 14943: $changes{$itemid} = 1; 14944: } 14945: } else { 14946: $changes{$itemid} = 1; 14947: } 14948: } elsif (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') { 14949: if ($domconfig{$action}{$itemid}{'display'}{$item} ne '') { 14950: $changes{$itemid} = 1; 14951: } 14952: } 14953: } 14954: if ($env{'form.ltitools_target_'.$i} eq 'window') { 14955: $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i}; 14956: } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') { 14957: $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i}; 14958: } else { 14959: $confhash{$itemid}{'display'}{'target'} = 'iframe'; 14960: } 14961: if (ref($domconfig{$action}{$itemid}{'display'}) eq 'HASH') { 14962: if ($domconfig{$action}{$itemid}{'display'}{'target'} ne $confhash{$itemid}{'display'}{'target'}) { 14963: $changes{$itemid} = 1; 14964: } 14965: } else { 14966: $changes{$itemid} = 1; 14967: } 14968: foreach my $extra ('passback','roster') { 14969: if ($env{'form.ltitools_'.$extra.'_'.$i}) { 14970: $confhash{$itemid}{$extra} = 1; 14971: if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') { 14972: my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i}; 14973: $lifetime =~ s/^\s+|\s+$//g; 14974: if ($lifetime =~ /^\d+\.?\d*$/) { 14975: $confhash{$itemid}{$extra.'valid'} = $lifetime; 14976: } 14977: } 14978: } 14979: if ($domconfig{$action}{$itemid}{$extra} ne $confhash{$itemid}{$extra}) { 14980: $changes{$itemid} = 1; 14981: } 14982: if ($domconfig{$action}{$itemid}{$extra.'valid'} ne $confhash{$itemid}{$extra.'valid'}) { 14983: $changes{$itemid} = 1; 14984: } 14985: } 14986: my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i); 14987: foreach my $item ('label','title','target','linktext','explanation','append') { 14988: if (grep(/^\Q$item\E$/,@courseconfig)) { 14989: $confhash{$itemid}{'crsconf'}{$item} = 1; 14990: if (ref($domconfig{$action}{$itemid}{'crsconf'}) eq 'HASH') { 14991: if ($domconfig{$action}{$itemid}{'crsconf'}{$item} ne $confhash{$itemid}{'crsconf'}{$item}) { 14992: $changes{$itemid} = 1; 14993: } 14994: } else { 14995: $changes{$itemid} = 1; 14996: } 14997: } 14998: } 14999: my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_fields_'.$i); 15000: foreach my $field (@fields) { 15001: if ($possfield{$field}) { 15002: if ($field eq 'roles') { 15003: foreach my $role (@courseroles) { 15004: my $choice = $env{'form.ltitools_roles_'.$role.'_'.$i}; 15005: if (($choice ne '') && ($posslti{$choice})) { 15006: $confhash{$itemid}{'roles'}{$role} = $choice; 15007: if ($role eq 'cc') { 15008: $confhash{$itemid}{'roles'}{'co'} = $choice; 15009: } 15010: } 15011: if (ref($domconfig{$action}{$itemid}{'roles'}) eq 'HASH') { 15012: if ($domconfig{$action}{$itemid}{'roles'}{$role} ne $confhash{$itemid}{'roles'}{$role}) { 15013: $changes{$itemid} = 1; 15014: } 15015: } elsif ($confhash{$itemid}{'roles'}{$role}) { 15016: $changes{$itemid} = 1; 15017: } 15018: } 15019: } else { 15020: $confhash{$itemid}{'fields'}{$field} = 1; 15021: if (ref($domconfig{$action}{$itemid}{'fields'}) eq 'HASH') { 15022: if ($domconfig{$action}{$itemid}{'fields'}{$field} ne $confhash{$itemid}{'fields'}{$field}) { 15023: $changes{$itemid} = 1; 15024: } 15025: } else { 15026: $changes{$itemid} = 1; 15027: } 15028: } 15029: } 15030: } 15031: if (ref($confhash{$itemid}{'fields'}) eq 'HASH') { 15032: if ($confhash{$itemid}{'fields'}{'user'}) { 15033: if ($env{'form.ltitools_userincdom_'.$i}) { 15034: $confhash{$itemid}{'incdom'} = 1; 15035: } 15036: if ($domconfig{$action}{$itemid}{'incdom'} ne $confhash{$itemid}{'incdom'}) { 15037: $changes{$itemid} = 1; 15038: } 15039: } 15040: } 15041: $allpos[$newpos] = $itemid; 15042: } 15043: if ($imgdeletions{$itemid}) { 15044: $changes{$itemid} = 1; 15045: #FIXME need to obsolete item in RES space 15046: } elsif ($env{'form.ltitools_image_'.$i.'.filename'}) { 15047: my ($imgurl,$error) = &process_ltitools_image($r,$dom,$confname,'ltitools_image_'.$i, 15048: $itemid,$configuserok,$switchserver, 15049: $author_ok); 15050: if ($imgurl) { 15051: $confhash{$itemid}{'image'} = $imgurl; 15052: $changes{$itemid} = 1; 15053: } 15054: if ($error) { 15055: &Apache::lonnet::logthis($error); 15056: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 15057: } 15058: } elsif ($domconfig{$action}{$itemid}{'image'}) { 15059: $confhash{$itemid}{'image'} = 15060: $domconfig{$action}{$itemid}{'image'}; 15061: } 15062: if ($customadds{$i}) { 15063: my $name = $env{'form.ltitools_custom_name_'.$i}; 15064: $name =~ s/(`)/'/g; 15065: $name =~ s/^\s+//; 15066: $name =~ s/\s+$//; 15067: my $value = $env{'form.ltitools_custom_value_'.$i}; 15068: $value =~ s/(`)/'/g; 15069: $value =~ s/^\s+//; 15070: $value =~ s/\s+$//; 15071: if ($name ne '') { 15072: $confhash{$itemid}{'custom'}{$name} = $value; 15073: $changes{$itemid} = 1; 15074: } 15075: } 15076: my %customdels; 15077: my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i); 15078: if (@customdeletions) { 15079: $changes{$itemid} = 1; 15080: } 15081: map { $customdels{$_} = 1; } @customdeletions; 15082: if (ref($domconfig{$action}{$itemid}{'custom'}) eq 'HASH') { 15083: foreach my $key (keys(%{$domconfig{$action}{$itemid}{'custom'}})) { 15084: unless ($customdels{$key}) { 15085: if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') { 15086: $confhash{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i}; 15087: } 15088: if ($domconfig{$action}{$itemid}{'custom'}{$key} ne $env{'form.ltitools_customval_'.$key.'_'.$i}) { 15089: $changes{$itemid} = 1; 15090: } 15091: } 15092: } 15093: } 15094: unless ($changes{$itemid}) { 15095: foreach my $key (keys(%{$domconfig{$action}{$itemid}})) { 15096: if (ref($domconfig{$action}{$itemid}{$key}) eq 'HASH') { 15097: if (ref($confhash{$itemid}{$key}) eq 'HASH') { 15098: foreach my $innerkey (keys(%{$domconfig{$action}{$itemid}{$key}})) { 15099: unless (exists($confhash{$itemid}{$key}{$innerkey})) { 15100: $changes{$itemid} = 1; 15101: last; 15102: } 15103: } 15104: } elsif (keys(%{$domconfig{$action}{$itemid}{$key}}) > 0) { 15105: $changes{$itemid} = 1; 15106: } 15107: } 15108: last if ($changes{$itemid}); 15109: } 15110: } 15111: } 15112: } 15113: } 15114: if (@allpos > 0) { 15115: my $idx = 0; 15116: foreach my $itemid (@allpos) { 15117: if ($itemid ne '') { 15118: $confhash{$itemid}{'order'} = $idx; 15119: if (ref($domconfig{$action}) eq 'HASH') { 15120: if (ref($domconfig{$action}{$itemid}) eq 'HASH') { 15121: if ($domconfig{$action}{$itemid}{'order'} ne $idx) { 15122: $changes{$itemid} = 1; 15123: } 15124: } 15125: } 15126: $idx ++; 15127: } 15128: } 15129: } 15130: my %ltitoolshash = ( 15131: $action => { %confhash } 15132: ); 15133: my $putresult = &Apache::lonnet::put_dom('configuration',\%ltitoolshash, 15134: $dom); 15135: if ($putresult eq 'ok') { 15136: my %ltienchash = ( 15137: $action => { %encconfig } 15138: ); 15139: &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1); 15140: if (keys(%changes) > 0) { 15141: my $cachetime = 24*60*60; 15142: my %ltiall = %confhash; 15143: foreach my $id (keys(%ltiall)) { 15144: if (ref($encconfig{$id}) eq 'HASH') { 15145: foreach my $item ('key','secret') { 15146: $ltiall{$id}{$item} = $encconfig{$id}{$item}; 15147: } 15148: } 15149: } 15150: &Apache::lonnet::do_cache_new('ltitools',$dom,\%ltiall,$cachetime); 15151: if (ref($lastactref) eq 'HASH') { 15152: $lastactref->{'ltitools'} = 1; 15153: } 15154: $resulttext = &mt('Changes made:').'<ul>'; 15155: my %bynum; 15156: foreach my $itemid (sort(keys(%changes))) { 15157: my $position = $confhash{$itemid}{'order'}; 15158: $bynum{$position} = $itemid; 15159: } 15160: foreach my $pos (sort { $a <=> $b } keys(%bynum)) { 15161: my $itemid = $bynum{$pos}; 15162: if (ref($confhash{$itemid}) ne 'HASH') { 15163: $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>'; 15164: } else { 15165: $resulttext .= '<li><b>'.$confhash{$itemid}{'title'}.'</b>'; 15166: if ($confhash{$itemid}{'image'}) { 15167: $resulttext .= ' '. 15168: '<img src="'.$confhash{$itemid}{'image'}.'"'. 15169: ' alt="'.&mt('Tool Provider icon').'" />'; 15170: } 15171: $resulttext .= '</li><ul>'; 15172: my $position = $pos + 1; 15173: $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>'; 15174: foreach my $item ('version','msgtype','sigmethod','url','lifetime') { 15175: if ($confhash{$itemid}{$item} ne '') { 15176: $resulttext .= '<li>'.$lt{$item}.': '.$confhash{$itemid}{$item}.'</li>'; 15177: } 15178: } 15179: if ($encconfig{$itemid}{'key'} ne '') { 15180: $resulttext .= '<li>'.$lt{'key'}.': '.$encconfig{$itemid}{'key'}.'</li>'; 15181: } 15182: if ($encconfig{$itemid}{'secret'} ne '') { 15183: $resulttext .= '<li>'.$lt{'secret'}.': '; 15184: my $num = length($encconfig{$itemid}{'secret'}); 15185: $resulttext .= ('*'x$num).'</li>'; 15186: } 15187: $resulttext .= '<li>'.&mt('Configurable in course:'); 15188: my @possconfig = ('label','title','target','linktext','explanation','append'); 15189: my $numconfig = 0; 15190: if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') { 15191: foreach my $item (@possconfig) { 15192: if ($confhash{$itemid}{'crsconf'}{$item}) { 15193: $numconfig ++; 15194: $resulttext .= ' "'.$lt{'crs'.$item}.'"'; 15195: } 15196: } 15197: } 15198: if (!$numconfig) { 15199: $resulttext .= ' '.&mt('None'); 15200: } 15201: $resulttext .= '</li>'; 15202: foreach my $item ('passback','roster') { 15203: $resulttext .= '<li>'.$lt{$item}.' '; 15204: if ($confhash{$itemid}{$item}) { 15205: $resulttext .= &mt('Yes'); 15206: if ($confhash{$itemid}{$item.'valid'}) { 15207: if ($item eq 'passback') { 15208: $resulttext .= ' '.&mt('valid for at least [quant,_1,day] after launch', 15209: $confhash{$itemid}{$item.'valid'}); 15210: } else { 15211: $resulttext .= ' '.&mt('valid for at least [quant,_1,second] after launch', 15212: $confhash{$itemid}{$item.'valid'}); 15213: } 15214: } 15215: } else { 15216: $resulttext .= &mt('No'); 15217: } 15218: $resulttext .= '</li>'; 15219: } 15220: if (ref($confhash{$itemid}{'display'}) eq 'HASH') { 15221: my $displaylist; 15222: if ($confhash{$itemid}{'display'}{'target'}) { 15223: $displaylist = &mt('Display target').': '. 15224: $confhash{$itemid}{'display'}{'target'}.','; 15225: } 15226: foreach my $size ('width','height') { 15227: if ($confhash{$itemid}{'display'}{$size}) { 15228: $displaylist .= (' 'x2).$lt{$size}.': '. 15229: $confhash{$itemid}{'display'}{$size}.','; 15230: } 15231: } 15232: if ($displaylist) { 15233: $displaylist =~ s/,$//; 15234: $resulttext .= '<li>'.$displaylist.'</li>'; 15235: } 15236: foreach my $item ('linktext','explanation') { 15237: if ($confhash{$itemid}{'display'}{$item}) { 15238: $resulttext .= '<li>'.$lt{$item}.': '.$confhash{$itemid}{'display'}{$item}.'</li>'; 15239: } 15240: } 15241: } 15242: if (ref($confhash{$itemid}{'fields'}) eq 'HASH') { 15243: my $fieldlist; 15244: foreach my $field (@allfields) { 15245: if ($confhash{$itemid}{'fields'}{$field}) { 15246: $fieldlist .= (' 'x2).$lt{$field}.','; 15247: } 15248: } 15249: if ($fieldlist) { 15250: $fieldlist =~ s/,$//; 15251: if ($confhash{$itemid}{'fields'}{'user'}) { 15252: if ($confhash{$itemid}{'incdom'}) { 15253: $fieldlist .= ' ('.&mt('username:domain').')'; 15254: } else { 15255: $fieldlist .= ' ('.&mt('username').')'; 15256: } 15257: } 15258: $resulttext .= '<li>'.&mt('Data sent').':'.$fieldlist.'</li>'; 15259: } 15260: } 15261: if (ref($confhash{$itemid}{'roles'}) eq 'HASH') { 15262: my $rolemaps; 15263: foreach my $role (@courseroles) { 15264: if ($confhash{$itemid}{'roles'}{$role}) { 15265: $rolemaps .= (' 'x2).&Apache::lonnet::plaintext($role,'Course').'='. 15266: $confhash{$itemid}{'roles'}{$role}.','; 15267: } 15268: } 15269: if ($rolemaps) { 15270: $rolemaps =~ s/,$//; 15271: $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>'; 15272: } 15273: } 15274: if (ref($confhash{$itemid}{'custom'}) eq 'HASH') { 15275: my $customlist; 15276: if (keys(%{$confhash{$itemid}{'custom'}})) { 15277: foreach my $key (sort(keys(%{$confhash{$itemid}{'custom'}}))) { 15278: $customlist .= $key.':'.$confhash{$itemid}{'custom'}{$key}.(' 'x2); 15279: } 15280: } 15281: if ($customlist) { 15282: $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>'; 15283: } 15284: } 15285: $resulttext .= '</ul></li>'; 15286: } 15287: } 15288: $resulttext .= '</ul>'; 15289: } else { 15290: $resulttext = &mt('No changes made.'); 15291: } 15292: } else { 15293: $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>'; 15294: } 15295: if ($errors) { 15296: $resulttext .= &mt('The following errors occurred: ').'<ul>'. 15297: $errors.'</ul>'; 15298: } 15299: return $resulttext; 15300: } 15301: 15302: sub process_ltitools_image { 15303: my ($r,$dom,$confname,$caller,$itemid,$configuserok,$switchserver,$author_ok) = @_; 15304: my $filename = $env{'form.'.$caller.'.filename'}; 15305: my ($error,$url); 15306: my ($width,$height) = (21,21); 15307: if ($configuserok eq 'ok') { 15308: if ($switchserver) { 15309: $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]', 15310: $switchserver); 15311: } elsif ($author_ok eq 'ok') { 15312: my ($result,$imageurl,$madethumb) = 15313: &publishlogo($r,'upload',$caller,$dom,$confname, 15314: "ltitools/$itemid/icon",$width,$height); 15315: if ($result eq 'ok') { 15316: if ($madethumb) { 15317: my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$}); 15318: my $imagethumb = "$path/tn-".$imagefile; 15319: $url = $imagethumb; 15320: } else { 15321: $url = $imageurl; 15322: } 15323: } else { 15324: $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result); 15325: } 15326: } else { 15327: $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); 15328: } 15329: } else { 15330: $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); 15331: } 15332: return ($url,$error); 15333: } 15334: 15335: sub get_ltitools_id { 15336: my ($cdom,$title) = @_; 15337: # get lock on ltitools db 15338: my $lockhash = { 15339: lock => $env{'user.name'}. 15340: ':'.$env{'user.domain'}, 15341: }; 15342: my $tries = 0; 15343: my $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom); 15344: my ($id,$error); 15345: 15346: while (($gotlock ne 'ok') && ($tries<10)) { 15347: $tries ++; 15348: sleep (0.1); 15349: $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom); 15350: } 15351: if ($gotlock eq 'ok') { 15352: my %currids = &Apache::lonnet::dump_dom('ltitools',$cdom); 15353: if ($currids{'lock'}) { 15354: delete($currids{'lock'}); 15355: if (keys(%currids)) { 15356: my @curr = sort { $a <=> $b } keys(%currids); 15357: if ($curr[-1] =~ /^\d+$/) { 15358: $id = 1 + $curr[-1]; 15359: } 15360: } else { 15361: $id = 1; 15362: } 15363: if ($id) { 15364: unless (&Apache::lonnet::newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') { 15365: $error = 'nostore'; 15366: } 15367: } else { 15368: $error = 'nonumber'; 15369: } 15370: } 15371: my $dellockoutcome = &Apache::lonnet::del_dom('ltitools',['lock'],$cdom); 15372: } else { 15373: $error = 'nolock'; 15374: } 15375: return ($id,$error); 15376: } 15377: 15378: sub modify_proctoring { 15379: my ($r,$dom,$action,$lastactref,%domconfig) = @_; 15380: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 15381: my (@allpos,%changes,%confhash,%encconfhash,$errors,$resulttext,%imgdeletions); 15382: my $confname = $dom.'-domainconfig'; 15383: my $servadm = $r->dir_config('lonAdmEMail'); 15384: my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); 15385: my %providernames = &proctoring_providernames(); 15386: my $maxnum = scalar(keys(%providernames)); 15387: 15388: my (%requserfields,%optuserfields,%defaults,%extended,%crsconf,@courseroles,@ltiroles); 15389: my ($requref,$opturef,$defref,$extref,$crsref,$rolesref,$ltiref) = &proctoring_data(); 15390: if (ref($requref) eq 'HASH') { 15391: %requserfields = %{$requref}; 15392: } 15393: if (ref($opturef) eq 'HASH') { 15394: %optuserfields = %{$opturef}; 15395: } 15396: if (ref($defref) eq 'HASH') { 15397: %defaults = %{$defref}; 15398: } 15399: if (ref($extref) eq 'HASH') { 15400: %extended = %{$extref}; 15401: } 15402: if (ref($crsref) eq 'HASH') { 15403: %crsconf = %{$crsref}; 15404: } 15405: if (ref($rolesref) eq 'ARRAY') { 15406: @courseroles = @{$rolesref}; 15407: } 15408: if (ref($ltiref) eq 'ARRAY') { 15409: @ltiroles = @{$ltiref}; 15410: } 15411: 15412: if (ref($domconfig{$action}) eq 'HASH') { 15413: my @todeleteimages = &Apache::loncommon::get_env_multiple('form.proctoring_image_del'); 15414: if (@todeleteimages) { 15415: map { $imgdeletions{$_} = 1; } @todeleteimages; 15416: } 15417: } 15418: my %customadds; 15419: my @newcustom = &Apache::loncommon::get_env_multiple('form.proctoring_customadd'); 15420: if (@newcustom) { 15421: map { $customadds{$_} = 1; } @newcustom; 15422: } 15423: foreach my $provider (sort(keys(%providernames))) { 15424: $confhash{$provider} = {}; 15425: my $pos = $env{'form.proctoring_pos_'.$provider}; 15426: $pos =~ s/\D+//g; 15427: $allpos[$pos] = $provider; 15428: my (%current,%currentenc); 15429: my $showroles = 0; 15430: if (ref($domconfig{$action}) eq 'HASH') { 15431: if (ref($domconfig{$action}{$provider}) eq 'HASH') { 15432: %current = %{$domconfig{$action}{$provider}}; 15433: foreach my $item ('key','secret') { 15434: $currentenc{$item} = $current{$item}; 15435: delete($current{$item}); 15436: } 15437: } 15438: } 15439: if ($env{'form.proctoring_available_'.$provider}) { 15440: $confhash{$provider}{'available'} = 1; 15441: unless ($current{'available'}) { 15442: $changes{$provider} = 1; 15443: } 15444: } else { 15445: %{$confhash{$provider}} = %current; 15446: %{$encconfhash{$provider}} = %currentenc; 15447: $confhash{$provider}{'available'} = 0; 15448: if ($current{'available'}) { 15449: $changes{$provider} = 1; 15450: } 15451: } 15452: if ($confhash{$provider}{'available'}) { 15453: foreach my $field ('lifetime','version','sigmethod','url','key','secret') { 15454: my $possval = $env{'form.proctoring_'.$provider.'_'.$field}; 15455: if ($field eq 'lifetime') { 15456: if ($possval =~ /^\d+$/) { 15457: $confhash{$provider}{$field} = $possval; 15458: } 15459: } elsif ($field eq 'version') { 15460: if ($possval =~ /^\d+\.\d+$/) { 15461: $confhash{$provider}{$field} = $possval; 15462: } 15463: } elsif ($field eq 'sigmethod') { 15464: if ($possval =~ /^\QHMAC-SHA\E(1|256)$/) { 15465: $confhash{$provider}{$field} = $possval; 15466: } 15467: } elsif ($field eq 'url') { 15468: $confhash{$provider}{$field} = $possval; 15469: } elsif (($field eq 'key') || ($field eq 'secret')) { 15470: $encconfhash{$provider}{$field} = $possval; 15471: unless ($currentenc{$field} eq $possval) { 15472: $changes{$provider} = 1; 15473: } 15474: } 15475: unless (($field eq 'key') || ($field eq 'secret')) { 15476: unless ($current{$field} eq $confhash{$provider}{$field}) { 15477: $changes{$provider} = 1; 15478: } 15479: } 15480: } 15481: if ($imgdeletions{$provider}) { 15482: $changes{$provider} = 1; 15483: } elsif ($env{'form.proctoring_image_'.$provider.'.filename'} ne '') { 15484: my ($imageurl,$error) = 15485: &process_proctoring_image($r,$dom,$confname,'proctoring_image_'.$provider,$provider, 15486: $configuserok,$switchserver,$author_ok); 15487: if ($imageurl) { 15488: $confhash{$provider}{'image'} = $imageurl; 15489: $changes{$provider} = 1; 15490: } 15491: if ($error) { 15492: &Apache::lonnet::logthis($error); 15493: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 15494: } 15495: } elsif (exists($current{'image'})) { 15496: $confhash{$provider}{'image'} = $current{'image'}; 15497: } 15498: if (ref($requserfields{$provider}) eq 'ARRAY') { 15499: if (@{$requserfields{$provider}} > 0) { 15500: if (grep(/^user$/,@{$requserfields{$provider}})) { 15501: if ($env{'form.proctoring_userincdom_'.$provider}) { 15502: $confhash{$provider}{'incdom'} = 1; 15503: } 15504: unless ($current{'incdom'} eq $confhash{$provider}{'incdom'}) { 15505: $changes{$provider} = 1; 15506: } 15507: } 15508: if (grep(/^roles$/,@{$requserfields{$provider}})) { 15509: $showroles = 1; 15510: } 15511: } 15512: } 15513: $confhash{$provider}{'fields'} = []; 15514: if (ref($optuserfields{$provider}) eq 'ARRAY') { 15515: if (@{$optuserfields{$provider}} > 0) { 15516: my @optfields = &Apache::loncommon::get_env_multiple('form.proctoring_optional_'.$provider); 15517: foreach my $field (@{$optuserfields{$provider}}) { 15518: if (grep(/^\Q$field\E$/,@optfields)) { 15519: push(@{$confhash{$provider}{'fields'}},$field); 15520: } 15521: } 15522: } 15523: if (ref($current{'fields'}) eq 'ARRAY') { 15524: unless ($changes{$provider}) { 15525: my @new = sort(@{$confhash{$provider}{'fields'}}); 15526: my @old = sort(@{$current{'fields'}}); 15527: my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old); 15528: if (@diffs) { 15529: $changes{$provider} = 1; 15530: } 15531: } 15532: } elsif (@{$confhash{$provider}{'fields'}}) { 15533: $changes{$provider} = 1; 15534: } 15535: } 15536: if (ref($defaults{$provider}) eq 'ARRAY') { 15537: if (@{$defaults{$provider}} > 0) { 15538: my %options; 15539: if (ref($extended{$provider}) eq 'HASH') { 15540: %options = %{$extended{$provider}}; 15541: } 15542: my @checked = &Apache::loncommon::get_env_multiple('form.proctoring_defaults_'.$provider); 15543: foreach my $field (@{$defaults{$provider}}) { 15544: if ((exists($options{$field})) && (ref($options{$field}) eq 'ARRAY')) { 15545: my $poss = $env{'form.proctoring_defaults_'.$field.'_'.$provider}; 15546: if (grep(/^\Q$poss\E$/,@{$options{$field}})) { 15547: push(@{$confhash{$provider}{'defaults'}},$poss); 15548: } 15549: } elsif ((exists($options{$field})) && (ref($options{$field}) eq 'HASH')) { 15550: foreach my $inner (keys(%{$options{$field}})) { 15551: if (ref($options{$field}{$inner}) eq 'ARRAY') { 15552: my $poss = $env{'form.proctoring_'.$inner.'_'.$provider}; 15553: if (grep(/^\Q$poss\E$/,@{$options{$field}{$inner}})) { 15554: $confhash{$provider}{'defaults'}{$inner} = $poss; 15555: } 15556: } else { 15557: $confhash{$provider}{'defaults'}{$inner} = $env{'form.proctoring_'.$inner.'_'.$provider}; 15558: } 15559: } 15560: } else { 15561: if (grep(/^\Q$field\E$/,@checked)) { 15562: push(@{$confhash{$provider}{'defaults'}},$field); 15563: } 15564: } 15565: } 15566: if (ref($confhash{$provider}{'defaults'}) eq 'ARRAY') { 15567: if (ref($current{'defaults'}) eq 'ARRAY') { 15568: unless ($changes{$provider}) { 15569: my @new = sort(@{$confhash{$provider}{'defaults'}}); 15570: my @old = sort(@{$current{'defaults'}}); 15571: my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old); 15572: if (@diffs) { 15573: $changes{$provider} = 1; 15574: } 15575: } 15576: } elsif (ref($current{'defaults'}) eq 'ARRAY') { 15577: if (@{$current{'defaults'}}) { 15578: $changes{$provider} = 1; 15579: } 15580: } 15581: } elsif (ref($confhash{$provider}{'defaults'}) eq 'HASH') { 15582: if (ref($current{'defaults'}) eq 'HASH') { 15583: unless ($changes{$provider}) { 15584: foreach my $key (keys(%{$confhash{$provider}{'defaults'}})) { 15585: unless ($confhash{$provider}{'defaults'}{$key} eq $current{'defaults'}{$key}) { 15586: $changes{$provider} = 1; 15587: last; 15588: } 15589: } 15590: } 15591: unless ($changes{$provider}) { 15592: foreach my $key (keys(%{$current{'defaults'}})) { 15593: unless ($current{'defaults'}{$key} eq $confhash{$provider}{'defaults'}{$key}) { 15594: $changes{$provider} = 1; 15595: last; 15596: } 15597: } 15598: } 15599: } elsif (keys(%{$confhash{$provider}{'defaults'}})) { 15600: $changes{$provider} = 1; 15601: } 15602: } 15603: } 15604: } 15605: if (ref($crsconf{$provider}) eq 'ARRAY') { 15606: if (@{$crsconf{$provider}} > 0) { 15607: $confhash{$provider}{'crsconf'} = []; 15608: my @checked = &Apache::loncommon::get_env_multiple('form.proctoring_crsconf_'.$provider); 15609: foreach my $crsfield (@{$crsconf{$provider}}) { 15610: if (grep(/^\Q$crsfield\E$/,@checked)) { 15611: push(@{$confhash{$provider}{'crsconf'}},$crsfield); 15612: } 15613: } 15614: if (ref($current{'crsconf'}) eq 'ARRAY') { 15615: unless ($changes{$provider}) { 15616: my @new = sort(@{$confhash{$provider}{'crsconf'}}); 15617: my @old = sort(@{$current{'crsconf'}}); 15618: my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old); 15619: if (@diffs) { 15620: $changes{$provider} = 1; 15621: } 15622: } 15623: } elsif (@{$confhash{$provider}{'crsconf'}}) { 15624: $changes{$provider} = 1; 15625: } 15626: } 15627: } 15628: if ($showroles) { 15629: $confhash{$provider}{'roles'} = {}; 15630: foreach my $role (@courseroles) { 15631: my $poss = $env{'form.proctoring_roles_'.$role.'_'.$provider}; 15632: if (grep(/^\Q$poss\E$/,@ltiroles)) { 15633: $confhash{$provider}{'roles'}{$role} = $poss; 15634: } 15635: } 15636: unless ($changes{$provider}) { 15637: if (ref($current{'roles'}) eq 'HASH') { 15638: foreach my $role (keys(%{$current{'roles'}})) { 15639: unless ($current{'roles'}{$role} eq $confhash{$provider}{'roles'}{$role}) { 15640: $changes{$provider} = 1; 15641: last 15642: } 15643: } 15644: unless ($changes{$provider}) { 15645: foreach my $role (keys(%{$confhash{$provider}{'roles'}})) { 15646: unless ($confhash{$provider}{'roles'}{$role} eq $current{'roles'}{$role}) { 15647: $changes{$provider} = 1; 15648: last; 15649: } 15650: } 15651: } 15652: } elsif (keys(%{$confhash{$provider}{'roles'}})) { 15653: $changes{$provider} = 1; 15654: } 15655: } 15656: } 15657: if (ref($current{'custom'}) eq 'HASH') { 15658: my @customdels = &Apache::loncommon::get_env_multiple('form.proctoring_customdel_'.$provider); 15659: foreach my $key (keys(%{$current{'custom'}})) { 15660: if (grep(/^\Q$key\E$/,@customdels)) { 15661: $changes{$provider} = 1; 15662: } else { 15663: $confhash{$provider}{'custom'}{$key} = $env{'form.proctoring_customval_'.$key.'_'.$provider}; 15664: if ($confhash{$provider}{'custom'}{$key} ne $current{'custom'}{$key}) { 15665: $changes{$provider} = 1; 15666: } 15667: } 15668: } 15669: } 15670: if ($customadds{$provider}) { 15671: my $name = $env{'form.proctoring_custom_name_'.$provider}; 15672: $name =~ s/(`)/'/g; 15673: $name =~ s/^\s+//; 15674: $name =~ s/\s+$//; 15675: my $value = $env{'form.proctoring_custom_value_'.$provider}; 15676: $value =~ s/(`)/'/g; 15677: $value =~ s/^\s+//; 15678: $value =~ s/\s+$//; 15679: if ($name ne '') { 15680: $confhash{$provider}{'custom'}{$name} = $value; 15681: $changes{$provider} = 1; 15682: } 15683: } 15684: } 15685: } 15686: if (@allpos > 0) { 15687: my $idx = 0; 15688: foreach my $provider (@allpos) { 15689: if ($provider ne '') { 15690: $confhash{$provider}{'order'} = $idx; 15691: unless ($changes{$provider}) { 15692: if (ref($domconfig{$action}) eq 'HASH') { 15693: if (ref($domconfig{$action}{$provider}) eq 'HASH') { 15694: if ($domconfig{$action}{$provider}{'order'} ne $idx) { 15695: $changes{$provider} = 1; 15696: } 15697: } 15698: } 15699: } 15700: $idx ++; 15701: } 15702: } 15703: } 15704: my %proc_hash = ( 15705: $action => { %confhash } 15706: ); 15707: my $putresult = &Apache::lonnet::put_dom('configuration',\%proc_hash, 15708: $dom); 15709: if ($putresult eq 'ok') { 15710: my %proc_enchash = ( 15711: $action => { %encconfhash } 15712: ); 15713: &Apache::lonnet::put_dom('encconfig',\%proc_enchash,$dom,undef,1); 15714: if (keys(%changes) > 0) { 15715: my $cachetime = 24*60*60; 15716: my %procall = %confhash; 15717: foreach my $provider (keys(%procall)) { 15718: if (ref($encconfhash{$provider}) eq 'HASH') { 15719: foreach my $key ('key','secret') { 15720: $procall{$provider}{$key} = $encconfhash{$provider}{$key}; 15721: } 15722: } 15723: } 15724: &Apache::lonnet::do_cache_new('proctoring',$dom,\%procall,$cachetime); 15725: if (ref($lastactref) eq 'HASH') { 15726: $lastactref->{'proctoring'} = 1; 15727: } 15728: $resulttext = &mt('Configuration for Provider(s) with changes:').'<ul>'; 15729: my %bynum; 15730: foreach my $provider (sort(keys(%changes))) { 15731: my $position = $confhash{$provider}{'order'}; 15732: $bynum{$position} = $provider; 15733: } 15734: foreach my $pos (sort { $a <=> $b } keys(%bynum)) { 15735: my $provider = $bynum{$pos}; 15736: my %lt = &proctoring_titles($provider); 15737: my %fieldtitles = &proctoring_fieldtitles($provider); 15738: if (!$confhash{$provider}{'available'}) { 15739: $resulttext .= '<li>'.&mt('Proctoring integration unavailable for: [_1]','<b>'.$providernames{$provider}.'</b>').'</li>'; 15740: } else { 15741: $resulttext .= '<li>'.&mt('Proctoring integration available for: [_1]','<b>'.$providernames{$provider}.'</b>'); 15742: if ($confhash{$provider}{'image'}) { 15743: $resulttext .= ' '. 15744: '<img src="'.$confhash{$provider}{'image'}.'"'. 15745: ' alt="'.&mt('Proctoring icon').'" />'; 15746: } 15747: $resulttext .= '<ul>'; 15748: my $position = $pos + 1; 15749: $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>'; 15750: foreach my $key ('version','sigmethod','url','lifetime') { 15751: if ($confhash{$provider}{$key} ne '') { 15752: $resulttext .= '<li>'.$lt{$key}.': '.$confhash{$provider}{$key}.'</li>'; 15753: } 15754: } 15755: if ($encconfhash{$provider}{'key'} ne '') { 15756: $resulttext .= '<li>'.$lt{'key'}.': '.$encconfhash{$provider}{'key'}.'</li>'; 15757: } 15758: if ($encconfhash{$provider}{'secret'} ne '') { 15759: $resulttext .= '<li>'.$lt{'secret'}.': '; 15760: my $num = length($encconfhash{$provider}{'secret'}); 15761: $resulttext .= ('*'x$num).'</li>'; 15762: } 15763: my (@fields,$showroles); 15764: if (ref($requserfields{$provider}) eq 'ARRAY') { 15765: push(@fields,@{$requserfields{$provider}}); 15766: } 15767: if (ref($confhash{$provider}{'fields'}) eq 'ARRAY') { 15768: push(@fields,@{$confhash{$provider}{'fields'}}); 15769: } elsif (ref($confhash{$provider}{'fields'}) eq 'HASH') { 15770: push(@fields,(keys(%{$confhash{$provider}{'fields'}}))); 15771: } 15772: if (@fields) { 15773: if (grep(/^roles$/,@fields)) { 15774: $showroles = 1; 15775: } 15776: $resulttext .= '<li>'.$lt{'udsl'}.': "'. 15777: join('", "', map { $lt{$_}; } @fields).'"</li>'; 15778: } 15779: if (ref($requserfields{$provider}) eq 'ARRAY') { 15780: if (grep(/^user$/,@{$requserfields{$provider}})) { 15781: if ($confhash{$provider}{'incdom'}) { 15782: $resulttext .= '<li>'.&mt('[_1] sent as [_2]',$lt{'user'},$lt{'uname:dom'}).'</li>'; 15783: } else { 15784: $resulttext .= '<li>'.&mt('[_1] sent as [_2]',$lt{'user'},$lt{'username'}).'</li>'; 15785: } 15786: } 15787: } 15788: if (ref($confhash{$provider}{'defaults'}) eq 'ARRAY') { 15789: if (@{$confhash{$provider}{'defaults'}} > 0) { 15790: $resulttext .= '<li>'.$lt{'defa'}; 15791: foreach my $field (@{$confhash{$provider}{'defaults'}}) { 15792: $resulttext .= ' "'.$fieldtitles{$field}.'",'; 15793: } 15794: $resulttext =~ s/,$//; 15795: $resulttext .= '</li>'; 15796: } 15797: } elsif (ref($confhash{$provider}{'defaults'}) eq 'HASH') { 15798: if (keys(%{$confhash{$provider}{'defaults'}})) { 15799: $resulttext .= '<li>'.$lt{'defa'}.': <ul>'; 15800: foreach my $key (sort(keys(%{$confhash{$provider}{'defaults'}}))) { 15801: if ($confhash{$provider}{'defaults'}{$key} ne '') { 15802: $resulttext .= '<li>'.$fieldtitles{$key}.' = '.$confhash{$provider}{'defaults'}{$key}.'</li>'; 15803: } 15804: } 15805: $resulttext .= '</ul></li>'; 15806: } 15807: } 15808: if (ref($crsconf{$provider}) eq 'ARRAY') { 15809: if (@{$crsconf{$provider}} > 0) { 15810: $resulttext .= '<li>'.&mt('Configurable in course:'); 15811: my $numconfig = 0; 15812: if (ref($confhash{$provider}{'crsconf'}) eq 'ARRAY') { 15813: if (@{$confhash{$provider}{'crsconf'}} > 0) { 15814: foreach my $field (@{$confhash{$provider}{'crsconf'}}) { 15815: $numconfig ++; 15816: if ($provider eq 'examity') { 15817: $resulttext .= ' "'.$lt{'crs'.$field}.'",'; 15818: } else { 15819: $resulttext .= ' "'.$fieldtitles{$field}.'",'; 15820: } 15821: } 15822: $resulttext =~ s/,$//; 15823: } 15824: } 15825: if (!$numconfig) { 15826: $resulttext .= ' '.&mt('None'); 15827: } 15828: $resulttext .= '</li>'; 15829: } 15830: } 15831: if ($showroles) { 15832: if (ref($confhash{$provider}{'roles'}) eq 'HASH') { 15833: my $rolemaps; 15834: foreach my $role (@courseroles) { 15835: if ($confhash{$provider}{'roles'}{$role}) { 15836: $rolemaps .= (' 'x2).&Apache::lonnet::plaintext($role,'Course').'='. 15837: $confhash{$provider}{'roles'}{$role}.','; 15838: } 15839: } 15840: if ($rolemaps) { 15841: $rolemaps =~ s/,$//; 15842: $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>'; 15843: } 15844: } 15845: } 15846: if (ref($confhash{$provider}{'custom'}) eq 'HASH') { 15847: my $customlist; 15848: if (keys(%{$confhash{$provider}{'custom'}})) { 15849: foreach my $key (sort(keys(%{$confhash{$provider}{'custom'}}))) { 15850: $customlist .= $key.'='.$confhash{$provider}{'custom'}{$key}.', '; 15851: } 15852: $customlist =~ s/,$//; 15853: } 15854: if ($customlist) { 15855: $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>'; 15856: } 15857: } 15858: $resulttext .= '</ul></li>'; 15859: } 15860: } 15861: $resulttext .= '</ul>'; 15862: } else { 15863: $resulttext = &mt('No changes made.'); 15864: } 15865: } else { 15866: $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>'; 15867: } 15868: if ($errors) { 15869: $resulttext .= &mt('The following errors occurred: ').'<ul>'. 15870: $errors.'</ul>'; 15871: } 15872: return $resulttext; 15873: } 15874: 15875: sub process_proctoring_image { 15876: my ($r,$dom,$confname,$caller,$provider,$configuserok,$switchserver,$author_ok) = @_; 15877: my $filename = $env{'form.'.$caller.'.filename'}; 15878: my ($error,$url); 15879: my ($width,$height) = (21,21); 15880: if ($configuserok eq 'ok') { 15881: if ($switchserver) { 15882: $error = &mt('Upload of Remote Proctoring Provider icon is not permitted to this server: [_1]', 15883: $switchserver); 15884: } elsif ($author_ok eq 'ok') { 15885: my ($result,$imageurl,$madethumb) = 15886: &publishlogo($r,'upload',$caller,$dom,$confname, 15887: "proctoring/$provider/icon",$width,$height); 15888: if ($result eq 'ok') { 15889: if ($madethumb) { 15890: my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$}); 15891: my $imagethumb = "$path/tn-".$imagefile; 15892: $url = $imagethumb; 15893: } else { 15894: $url = $imageurl; 15895: } 15896: } else { 15897: $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result); 15898: } 15899: } else { 15900: $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); 15901: } 15902: } else { 15903: $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); 15904: } 15905: return ($url,$error); 15906: } 15907: 15908: sub modify_lti { 15909: my ($r,$dom,$action,$lastactref,%domconfig) = @_; 15910: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 15911: my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext); 15912: my (%posslti,%posslticrs,%posscrstype); 15913: my @courseroles = ('cc','in','ta','ep','st'); 15914: my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator); 15915: my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner); 15916: my @coursetypes = ('official','unofficial','community','textbook','placement','lti'); 15917: my %coursetypetitles = &Apache::lonlocal::texthash ( 15918: official => 'Official', 15919: unofficial => 'Unofficial', 15920: community => 'Community', 15921: textbook => 'Textbook', 15922: placement => 'Placement Test', 15923: lti => 'LTI Provider', 15924: ); 15925: my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 15926: my %lt = <i_names(); 15927: map { $posslti{$_} = 1; } @ltiroles; 15928: map { $posslticrs{$_} = 1; } @lticourseroles; 15929: map { $posscrstype{$_} = 1; } @coursetypes; 15930: 15931: my %menutitles = <imenu_titles(); 15932: 15933: my (%currltisec,%secchanges,%newltisec,%newltienc,%keyset,%newkeyset); 15934: $newltisec{'private'}{'keys'} = []; 15935: $newltisec{'encrypt'} = {}; 15936: $newltisec{'rules'} = {}; 15937: $newltisec{'linkprot'} = {}; 15938: if (ref($domconfig{'ltisec'}) eq 'HASH') { 15939: %currltisec = %{$domconfig{'ltisec'}}; 15940: if (ref($currltisec{'linkprot'}) eq 'HASH') { 15941: foreach my $id (keys(%{$currltisec{'linkprot'}})) { 15942: unless ($id =~ /^\d+$/) { 15943: delete($currltisec{'linkprot'}{$id}); 15944: } 15945: } 15946: } 15947: if (ref($currltisec{'private'}) eq 'HASH') { 15948: if (ref($currltisec{'private'}{'keys'}) eq 'ARRAY') { 15949: $newltisec{'private'}{'keys'} = $currltisec{'private'}{'keys'}; 15950: map { $keyset{$_} = 1; } @{$currltisec{'private'}{'keys'}}; 15951: } 15952: } 15953: } 15954: foreach my $item ('crs','dom','consumers') { 15955: my $formelement; 15956: if ($item eq 'consumers') { 15957: $formelement = 'form.ltisec_'.$item; 15958: } else { 15959: $formelement = 'form.ltisec_'.$item.'linkprot'; 15960: } 15961: if ($env{$formelement}) { 15962: $newltisec{'encrypt'}{$item} = 1; 15963: if (ref($currltisec{'encrypt'}) eq 'HASH') { 15964: unless ($currltisec{'encrypt'}{$item}) { 15965: $secchanges{'encrypt'} = 1; 15966: } 15967: } else { 15968: $secchanges{'encrypt'} = 1; 15969: } 15970: } elsif (ref($currltisec{'encrypt'}) eq 'HASH') { 15971: if ($currltisec{'encrypt'}{$item}) { 15972: $secchanges{'encrypt'} = 1; 15973: } 15974: } 15975: } 15976: unless (exists($currltisec{'rules'})) { 15977: $currltisec{'rules'} = {}; 15978: } 15979: &password_rule_changes('secrets',$newltisec{'rules'},$currltisec{'rules'},\%secchanges); 15980: 15981: my @ids=&Apache::lonnet::current_machine_ids(); 15982: my %servers = &Apache::lonnet::get_servers($dom,'library'); 15983: 15984: foreach my $hostid (keys(%servers)) { 15985: if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) { 15986: my $newkey; 15987: my $keyitem = 'form.ltisec_privkey_'.$hostid; 15988: if (exists($env{$keyitem})) { 15989: $env{$keyitem} =~ s/(`)/'/g; 15990: if ($keyset{$hostid}) { 15991: if ($env{'form.ltisec_changeprivkey_'.$hostid}) { 15992: if ($env{$keyitem} ne '') { 15993: $secchanges{'private'} = 1; 15994: $newkeyset{$hostid} = $env{$keyitem}; 15995: } 15996: } 15997: } elsif ($env{$keyitem} ne '') { 15998: unless (grep(/^\Q$hostid\E$/,@{$newltisec{'private'}{'keys'}})) { 15999: push(@{$newltisec{'private'}{'keys'}},$hostid); 16000: } 16001: $secchanges{'private'} = 1; 16002: $newkeyset{$hostid} = $env{$keyitem}; 16003: } 16004: } 16005: } 16006: } 16007: 16008: my (%linkprotchg,$linkprotoutput,$is_home); 16009: my $proterror = &Apache::courseprefs::process_linkprot($dom,'',$currltisec{'linkprot'}, 16010: \%linkprotchg,'domain'); 16011: my $home = &Apache::lonnet::domain($dom,'primary'); 16012: unless (($home eq 'no_host') || ($home eq '')) { 16013: my @ids=&Apache::lonnet::current_machine_ids(); 16014: foreach my $id (@ids) { if ($id eq $home) { $is_home=1; } } 16015: } 16016: 16017: if (keys(%linkprotchg)) { 16018: $secchanges{'linkprot'} = 1; 16019: my %oldlinkprot; 16020: if (ref($currltisec{'linkprot'}) eq 'HASH') { 16021: %oldlinkprot = %{$currltisec{'linkprot'}}; 16022: } 16023: foreach my $id (keys(%linkprotchg)) { 16024: if (ref($linkprotchg{$id}) eq 'HASH') { 16025: foreach my $inner (keys(%{$linkprotchg{$id}})) { 16026: if (($inner eq 'secret') || ($inner eq 'key')) { 16027: if ($is_home) { 16028: $newltienc{$id}{$inner} = $linkprotchg{$id}{$inner}; 16029: } 16030: } 16031: } 16032: } else { 16033: $newltisec{'linkprot'}{$id} = $linkprotchg{$id}; 16034: } 16035: } 16036: $linkprotoutput = &Apache::courseprefs::store_linkprot($dom,'','domain',\%linkprotchg,\%oldlinkprot); 16037: if (keys(%linkprotchg)) { 16038: %{$newltisec{'linkprot'}} = %linkprotchg; 16039: } 16040: } 16041: if (ref($currltisec{'linkprot'}) eq 'HASH') { 16042: foreach my $id (%{$currltisec{'linkprot'}}) { 16043: next if ($id !~ /^\d+$/); 16044: unless (exists($linkprotchg{$id})) { 16045: if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') { 16046: foreach my $inner (keys(%{$currltisec{'linkprot'}{$id}})) { 16047: if (($inner eq 'secret') || ($inner eq 'key')) { 16048: if ($is_home) { 16049: $newltienc{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner}; 16050: } 16051: } else { 16052: $newltisec{'linkprot'}{$id}{$inner} = $currltisec{'linkprot'}{$id}{$inner}; 16053: } 16054: } 16055: } else { 16056: $newltisec{'linkprot'}{$id} = $currltisec{'linkprot'}{$id}; 16057: } 16058: } 16059: } 16060: } 16061: if ($proterror) { 16062: $errors .= '<li>'.$proterror.'</li>'; 16063: } 16064: my (@items,%deletions,%itemids); 16065: if ($env{'form.lti_add'}) { 16066: my $consumer = $env{'form.lti_consumer_add'}; 16067: $consumer =~ s/(`)/'/g; 16068: ($newid,my $error) = &get_lti_id($dom,$consumer); 16069: if ($newid) { 16070: $itemids{'add'} = $newid; 16071: push(@items,'add'); 16072: $changes{$newid} = 1; 16073: } else { 16074: my $error = &mt('Failed to acquire unique ID for new LTI configuration'); 16075: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 16076: } 16077: } 16078: if (ref($domconfig{$action}) eq 'HASH') { 16079: my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del'); 16080: if (@todelete) { 16081: map { $deletions{$_} = 1; } @todelete; 16082: } 16083: my $maxnum = $env{'form.lti_maxnum'}; 16084: for (my $i=0; $i<$maxnum; $i++) { 16085: my $itemid = $env{'form.lti_id_'.$i}; 16086: $itemid =~ s/\D+//g; 16087: if (ref($domconfig{$action}{$itemid}) eq 'HASH') { 16088: if ($deletions{$itemid}) { 16089: $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'}; 16090: } else { 16091: push(@items,$i); 16092: $itemids{$i} = $itemid; 16093: } 16094: } 16095: } 16096: } 16097: foreach my $idx (@items) { 16098: my $itemid = $itemids{$idx}; 16099: next unless ($itemid); 16100: my $position = $env{'form.lti_pos_'.$itemid}; 16101: $position =~ s/\D+//g; 16102: if ($position ne '') { 16103: $allpos[$position] = $itemid; 16104: } 16105: foreach my $item ('consumer','key','secret','lifetime','requser','crsinc') { 16106: my $formitem = 'form.lti_'.$item.'_'.$idx; 16107: $env{$formitem} =~ s/(`)/'/g; 16108: if ($item eq 'lifetime') { 16109: $env{$formitem} =~ s/[^\d.]//g; 16110: } 16111: if ($env{$formitem} ne '') { 16112: if (($item eq 'key') || ($item eq 'secret')) { 16113: $encconfig{$itemid}{$item} = $env{$formitem}; 16114: } else { 16115: $confhash{$itemid}{$item} = $env{$formitem}; 16116: unless (($idx eq 'add') || ($changes{$itemid})) { 16117: if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) { 16118: $changes{$itemid} = 1; 16119: } 16120: } 16121: } 16122: } 16123: } 16124: if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') { 16125: $confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx}; 16126: } 16127: if ($confhash{$itemid}{'requser'}) { 16128: if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') { 16129: $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid'; 16130: } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') { 16131: $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary'; 16132: } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') { 16133: my $mapuser = $env{'form.lti_customuser_'.$idx}; 16134: $mapuser =~ s/(`)/'/g; 16135: $mapuser =~ s/^\s+|\s+$//g; 16136: $confhash{$itemid}{'mapuser'} = $mapuser; 16137: } 16138: my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx); 16139: my @makeuser; 16140: foreach my $ltirole (sort(@possmakeuser)) { 16141: if ($posslti{$ltirole}) { 16142: push(@makeuser,$ltirole); 16143: } 16144: } 16145: $confhash{$itemid}{'makeuser'} = \@makeuser; 16146: if (@makeuser) { 16147: my $lcauth = $env{'form.lti_lcauth_'.$idx}; 16148: if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) { 16149: $confhash{$itemid}{'lcauth'} = $lcauth; 16150: if ($lcauth ne 'internal') { 16151: my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx}; 16152: $lcauthparm =~ s/^(\s+|\s+)$//g; 16153: $lcauthparm =~ s/`//g; 16154: if ($lcauthparm ne '') { 16155: $confhash{$itemid}{'lcauthparm'} = $lcauthparm; 16156: } 16157: } 16158: } else { 16159: $confhash{$itemid}{'lcauth'} = 'lti'; 16160: } 16161: } 16162: my @possinstdata = &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx); 16163: if (@possinstdata) { 16164: foreach my $field (@possinstdata) { 16165: if (exists($fieldtitles{$field})) { 16166: push(@{$confhash{$itemid}{'instdata'}}); 16167: } 16168: } 16169: } 16170: if ($env{'form.lti_callback_'.$idx}) { 16171: if ($env{'form.lti_callbackparam_'.$idx}) { 16172: my $callback = $env{'form.lti_callbackparam_'.$idx}; 16173: $callback =~ s/^\s+|\s+$//g; 16174: $confhash{$itemid}{'callback'} = $callback; 16175: } 16176: } 16177: foreach my $field ('topmenu','inlinemenu') { 16178: if ($env{'form.lti_'.$field.'_'.$idx}) { 16179: $confhash{$itemid}{$field} = 1; 16180: } 16181: } 16182: if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) { 16183: $confhash{$itemid}{lcmenu} = []; 16184: my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx); 16185: foreach my $field (@possmenu) { 16186: if (exists($menutitles{$field})) { 16187: if ($field eq 'grades') { 16188: next unless ($env{'form.lti_inlinemenu_'.$idx}); 16189: } 16190: push(@{$confhash{$itemid}{lcmenu}},$field); 16191: } 16192: } 16193: } 16194: if ($confhash{$itemid}{'crsinc'}) { 16195: if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') || 16196: ($env{'form.lti_mapcrs_'.$idx} eq 'context_id')) { 16197: $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx}; 16198: } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') { 16199: my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx}; 16200: $mapcrs =~ s/(`)/'/g; 16201: $mapcrs =~ s/^\s+|\s+$//g; 16202: $confhash{$itemid}{'mapcrs'} = $mapcrs; 16203: } 16204: my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx); 16205: my @crstypes; 16206: foreach my $type (sort(@posstypes)) { 16207: if ($posscrstype{$type}) { 16208: push(@crstypes,$type); 16209: } 16210: } 16211: $confhash{$itemid}{'mapcrstype'} = \@crstypes; 16212: if ($env{'form.lti_storecrs_'.$idx}) { 16213: $confhash{$itemid}{'storecrs'} = 1; 16214: } 16215: if ($env{'form.lti_makecrs_'.$idx}) { 16216: $confhash{$itemid}{'makecrs'} = 1; 16217: } 16218: foreach my $ltirole (@lticourseroles) { 16219: my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx}; 16220: if (grep(/^\Q$possrole\E$/,@courseroles)) { 16221: $confhash{$itemid}{'maproles'}{$ltirole} = $possrole; 16222: } 16223: } 16224: my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx); 16225: my @selfenroll; 16226: foreach my $type (sort(@possenroll)) { 16227: if ($posslticrs{$type}) { 16228: push(@selfenroll,$type); 16229: } 16230: } 16231: $confhash{$itemid}{'selfenroll'} = \@selfenroll; 16232: if ($env{'form.lti_crssec_'.$idx}) { 16233: if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') { 16234: $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx}; 16235: } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') { 16236: my $section = $env{'form.lti_customsection_'.$idx}; 16237: $section =~ s/(`)/'/g; 16238: $section =~ s/^\s+|\s+$//g; 16239: if ($section ne '') { 16240: $confhash{$itemid}{'section'} = $section; 16241: } 16242: } 16243: } 16244: foreach my $field ('passback','roster') { 16245: if ($env{'form.lti_'.$field.'_'.$idx}) { 16246: $confhash{$itemid}{$field} = 1; 16247: } 16248: } 16249: if ($env{'form.lti_passback_'.$idx}) { 16250: if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') { 16251: $confhash{$itemid}{'passbackformat'} = '1.0'; 16252: } else { 16253: $confhash{$itemid}{'passbackformat'} = '1.1'; 16254: } 16255: } 16256: } 16257: unless (($idx eq 'add') || ($changes{$itemid})) { 16258: if ($confhash{$itemid}{'crsinc'}) { 16259: foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') { 16260: if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) { 16261: $changes{$itemid} = 1; 16262: } 16263: } 16264: unless ($changes{$itemid}) { 16265: if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) { 16266: if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) { 16267: $changes{$itemid} = 1; 16268: } 16269: } 16270: } 16271: foreach my $field ('mapcrstype','selfenroll') { 16272: unless ($changes{$itemid}) { 16273: if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') { 16274: if (ref($confhash{$itemid}{$field}) eq 'ARRAY') { 16275: my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field}, 16276: $confhash{$itemid}{$field}); 16277: if (@diffs) { 16278: $changes{$itemid} = 1; 16279: } 16280: } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) { 16281: $changes{$itemid} = 1; 16282: } 16283: } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') { 16284: if (@{$confhash{$itemid}{$field}} > 0) { 16285: $changes{$itemid} = 1; 16286: } 16287: } 16288: } 16289: } 16290: unless ($changes{$itemid}) { 16291: if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') { 16292: if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { 16293: foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) { 16294: if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne 16295: $confhash{$itemid}{'maproles'}{$ltirole}) { 16296: $changes{$itemid} = 1; 16297: last; 16298: } 16299: } 16300: unless ($changes{$itemid}) { 16301: foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) { 16302: if ($confhash{$itemid}{'maproles'}{$ltirole} ne 16303: $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) { 16304: $changes{$itemid} = 1; 16305: last; 16306: } 16307: } 16308: } 16309: } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) { 16310: $changes{$itemid} = 1; 16311: } 16312: } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { 16313: unless ($changes{$itemid}) { 16314: if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) { 16315: $changes{$itemid} = 1; 16316: } 16317: } 16318: } 16319: } 16320: } 16321: unless ($changes{$itemid}) { 16322: foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') { 16323: if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) { 16324: $changes{$itemid} = 1; 16325: } 16326: } 16327: unless ($changes{$itemid}) { 16328: foreach my $field ('makeuser','lcmenu') { 16329: if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') { 16330: if (ref($confhash{$itemid}{$field}) eq 'ARRAY') { 16331: my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field}, 16332: $confhash{$itemid}{$field}); 16333: if (@diffs) { 16334: $changes{$itemid} = 1; 16335: } 16336: } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) { 16337: $changes{$itemid} = 1; 16338: } 16339: } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') { 16340: if (@{$confhash{$itemid}{$field}} > 0) { 16341: $changes{$itemid} = 1; 16342: } 16343: } 16344: } 16345: } 16346: } 16347: } 16348: } 16349: } 16350: if (@allpos > 0) { 16351: my $idx = 0; 16352: foreach my $itemid (@allpos) { 16353: if ($itemid ne '') { 16354: $confhash{$itemid}{'order'} = $idx; 16355: if (ref($domconfig{$action}) eq 'HASH') { 16356: if (ref($domconfig{$action}{$itemid}) eq 'HASH') { 16357: if ($domconfig{$action}{$itemid}{'order'} ne $idx) { 16358: $changes{$itemid} = 1; 16359: } 16360: } 16361: } 16362: $idx ++; 16363: } 16364: } 16365: } 16366: my %ltihash = ( 16367: $action => { %confhash } 16368: ); 16369: my %ltienchash = ( 16370: $action => { %encconfig } 16371: ); 16372: if (keys(%secchanges)) { 16373: $ltihash{'ltisec'} = \%newltisec; 16374: if ($secchanges{'linkprot'}) { 16375: if ($is_home) { 16376: $ltienchash{'linkprot'} = \%newltienc; 16377: } 16378: } 16379: } 16380: my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom); 16381: if ($putresult eq 'ok') { 16382: my %keystore; 16383: if (keys(%secchanges)) { 16384: if ($secchanges{'private'}) { 16385: my $who = &escape($env{'user.name'}.':'.$env{'user.domain'}); 16386: foreach my $hostid (keys(%newkeyset)) { 16387: my $storehash = { 16388: key => $newkeyset{$hostid}, 16389: who => $env{'user.name'}.':'.$env{'user.domain'}, 16390: }; 16391: $keystore{$hostid} = &Apache::lonnet::store_dom($storehash,'lti','private', 16392: $dom,$hostid); 16393: } 16394: } 16395: if (ref($lastactref) eq 'HASH') { 16396: if (($secchanges{'encrypt'}) || ($secchanges{'private'})) { 16397: $lastactref->{'domdefaults'} = 1; 16398: } 16399: } 16400: } 16401: &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1); 16402: if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) { 16403: return &mt('No changes made.'); 16404: } 16405: $resulttext = &mt('Changes made:').'<ul>'; 16406: if (keys(%secchanges) > 0) { 16407: foreach my $item (keys(%secchanges)) { 16408: if ($item eq 'encrypt') { 16409: my %encrypted = ( 16410: crs => { 16411: on => &mt('Encryption of stored link protection secrets defined in courses enabled'), 16412: off => &mt('Encryption of stored link protection secrets defined in courses disabled'), 16413: }, 16414: dom => { 16415: on => &mt('Encryption of stored link protection secrets defined in domain enabled'), 16416: off => &mt('Encryption of stored link protection secrets defined in domain disabled'), 16417: }, 16418: consumers => { 16419: on => &mt('Encryption of stored consumer secrets defined in domain enabled'), 16420: off => &mt('Encryption of stored consumer secrets defined in domain disabled'), 16421: }, 16422: ); 16423: foreach my $type ('crs','dom','consumers') { 16424: my $shown = $encrypted{$type}{'off'}; 16425: if (ref($newltisec{$item}) eq 'HASH') { 16426: if ($newltisec{$item}{$type}) { 16427: $shown = $encrypted{$type}{'on'}; 16428: } 16429: } 16430: $resulttext .= '<li>'.$shown.'</li>'; 16431: } 16432: } elsif ($item eq 'rules') { 16433: my %titles = &Apache::lonlocal::texthash( 16434: min => 'Minimum password length', 16435: max => 'Maximum password length', 16436: chars => 'Required characters', 16437: ); 16438: foreach my $rule ('min','max') { 16439: if ($newltisec{rules}{$rule} eq '') { 16440: if ($rule eq 'min') { 16441: $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule}); 16442: ' '.&mt('Default of [_1] will be used', 16443: $Apache::lonnet::passwdmin).'</li>'; 16444: } else { 16445: $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>'; 16446: } 16447: } else { 16448: $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$newltisec{rules}{$rule}).'</li>'; 16449: } 16450: } 16451: if (ref($newltisec{'rules'}{'chars'}) eq 'ARRAY') { 16452: if (@{$newltisec{'rules'}{'chars'}} > 0) { 16453: my %rulenames = &Apache::lonlocal::texthash( 16454: uc => 'At least one upper case letter', 16455: lc => 'At least one lower case letter', 16456: num => 'At least one number', 16457: spec => 'At least one non-alphanumeric', 16458: ); 16459: my $needed = '<ul><li>'. 16460: join('</li><li>',map {$rulenames{$_} } @{$newltisec{'rules'}{'chars'}}). 16461: '</li></ul>'; 16462: $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>'; 16463: } else { 16464: $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>'; 16465: } 16466: } else { 16467: $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>'; 16468: } 16469: } elsif ($item eq 'private') { 16470: if (keys(%newkeyset)) { 16471: foreach my $hostid (sort(keys(%newkeyset))) { 16472: if ($keystore{$hostid} eq 'ok') { 16473: $resulttext .= '<li>'.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'</li>'; 16474: } 16475: } 16476: } 16477: } elsif ($item eq 'linkprot') { 16478: $resulttext .= $linkprotoutput; 16479: } 16480: } 16481: } 16482: if (keys(%changes) > 0) { 16483: my $cachetime = 24*60*60; 16484: my %ltiall = %confhash; 16485: foreach my $id (keys(%ltiall)) { 16486: if (ref($encconfig{$id}) eq 'HASH') { 16487: foreach my $item ('key','secret') { 16488: $ltiall{$id}{$item} = $encconfig{$id}{$item}; 16489: } 16490: } 16491: } 16492: &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime); 16493: if (ref($lastactref) eq 'HASH') { 16494: $lastactref->{'lti'} = 1; 16495: } 16496: my %bynum; 16497: foreach my $itemid (sort(keys(%changes))) { 16498: my $position = $confhash{$itemid}{'order'}; 16499: $bynum{$position} = $itemid; 16500: } 16501: foreach my $pos (sort { $a <=> $b } keys(%bynum)) { 16502: my $itemid = $bynum{$pos}; 16503: if (ref($confhash{$itemid}) ne 'HASH') { 16504: $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>'; 16505: } else { 16506: $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b><ul>'; 16507: my $position = $pos + 1; 16508: $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>'; 16509: foreach my $item ('version','lifetime') { 16510: if ($confhash{$itemid}{$item} ne '') { 16511: $resulttext .= '<li>'.$lt{$item}.': '.$confhash{$itemid}{$item}.'</li>'; 16512: } 16513: } 16514: if ($encconfig{$itemid}{'key'} ne '') { 16515: $resulttext .= '<li>'.$lt{'key'}.': '.$encconfig{$itemid}{'key'}.'</li>'; 16516: } 16517: if ($encconfig{$itemid}{'secret'} ne '') { 16518: $resulttext .= '<li>'.$lt{'secret'}.': '; 16519: my $num = length($encconfig{$itemid}{'secret'}); 16520: $resulttext .= ('*'x$num).'</li>'; 16521: } 16522: if ($confhash{$itemid}{'requser'}) { 16523: if ($confhash{$itemid}{'callback'}) { 16524: $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>'; 16525: } else { 16526: $resulttext .= '<li>'.&mt('Callback to logout LON-CAPA on log out from Consumer').'</li>'; 16527: } 16528: if ($confhash{$itemid}{'mapuser'}) { 16529: my $shownmapuser; 16530: if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') { 16531: $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)'; 16532: } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') { 16533: $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)'; 16534: } else { 16535: $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')'; 16536: } 16537: $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>'; 16538: } 16539: if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') { 16540: if (@{$confhash{$itemid}{'makeuser'}} > 0) { 16541: $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]', 16542: join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />'; 16543: if ($confhash{$itemid}{'lcauth'} eq 'lti') { 16544: $resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>'; 16545: } else { 16546: $resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]', 16547: $confhash{$itemid}{'lcauth'}); 16548: if ($confhash{$itemid}{'lcauth'} eq 'internal') { 16549: $resulttext .= '; '.&mt('a randomly generated password will be created'); 16550: } elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') { 16551: if ($confhash{$itemid}{'lcauthparm'} ne '') { 16552: $resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'}); 16553: } 16554: } else { 16555: $resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'}); 16556: } 16557: } 16558: $resulttext .= '</li>'; 16559: } else { 16560: $resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>'; 16561: } 16562: } 16563: if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') { 16564: if (@{$confhash{$itemid}{'instdata'}} > 0) { 16565: $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]', 16566: join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>'; 16567: } else { 16568: $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>'; 16569: } 16570: } 16571: foreach my $item ('topmenu','inlinemenu') { 16572: $resulttext .= '<li>'.$lt{$item}.': '; 16573: if ($confhash{$itemid}{$item}) { 16574: $resulttext .= &mt('Yes'); 16575: } else { 16576: $resulttext .= &mt('No'); 16577: } 16578: $resulttext .= '</li>'; 16579: } 16580: if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') { 16581: if (@{$confhash{$itemid}{'lcmenu'}} > 0) { 16582: $resulttext .= '<li>'.&mt('Menu items:').' '. 16583: join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>'; 16584: } else { 16585: $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>'; 16586: } 16587: } 16588: if ($confhash{$itemid}{'crsinc'}) { 16589: if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { 16590: my $rolemaps; 16591: foreach my $role (@ltiroles) { 16592: if ($confhash{$itemid}{'maproles'}{$role}) { 16593: $rolemaps .= (' 'x2).$role.'='. 16594: &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role}, 16595: 'Course').','; 16596: } 16597: } 16598: if ($rolemaps) { 16599: $rolemaps =~ s/,$//; 16600: $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>'; 16601: } 16602: } 16603: if ($confhash{$itemid}{'mapcrs'}) { 16604: $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>'; 16605: } 16606: if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') { 16607: if (@{$confhash{$itemid}{'mapcrstype'}} > 0) { 16608: $resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]', 16609: join(', ',map { $coursetypetitles{$_}; } @coursetypes)). 16610: '</li>'; 16611: } else { 16612: $resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>'; 16613: } 16614: } 16615: if ($confhash{$itemid}{'storecrs'}) { 16616: $resulttext .= '<li>'.&mt('Store mapping of course identifier to LON-CAPA CourseID').': '.$confhash{$itemid}{'storecrs'}.'</li>'; 16617: } 16618: if ($confhash{$itemid}{'makecrs'}) { 16619: $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>'; 16620: } else { 16621: $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>'; 16622: } 16623: if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') { 16624: if (@{$confhash{$itemid}{'selfenroll'}} > 0) { 16625: $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]', 16626: join(', ',@{$confhash{$itemid}{'selfenroll'}})). 16627: '</li>'; 16628: } else { 16629: $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>'; 16630: } 16631: } 16632: if ($confhash{$itemid}{'section'}) { 16633: if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') { 16634: $resulttext .= '<li>'.&mt('User section from standard field:'). 16635: ' (course_section_sourcedid)'.'</li>'; 16636: } else { 16637: $resulttext .= '<li>'.&mt('User section from:').' '. 16638: $confhash{$itemid}{'section'}.'</li>'; 16639: } 16640: } else { 16641: $resulttext .= '<li>'.&mt('No section assignment').'</li>'; 16642: } 16643: foreach my $item ('passback','roster','topmenu','inlinemenu') { 16644: $resulttext .= '<li>'.$lt{$item}.': '; 16645: if ($confhash{$itemid}{$item}) { 16646: $resulttext .= &mt('Yes'); 16647: if ($item eq 'passback') { 16648: if ($confhash{$itemid}{'passbackformat'} eq '1.0') { 16649: $resulttext .= ' ('.&mt('Outcomes Extension (1.0)').')'; 16650: } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') { 16651: $resulttext .= ' ('.&mt('Outcomes Service (1.1)').')'; 16652: } 16653: } 16654: } else { 16655: $resulttext .= &mt('No'); 16656: } 16657: $resulttext .= '</li>'; 16658: } 16659: if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') { 16660: if (@{$confhash{$itemid}{'lcmenu'}} > 0) { 16661: $resulttext .= '<li>'.&mt('Menu items:').' '. 16662: join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>'; 16663: } else { 16664: $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>'; 16665: } 16666: } 16667: } 16668: } 16669: $resulttext .= '</ul></li>'; 16670: } 16671: } 16672: } 16673: $resulttext .= '</ul>'; 16674: } else { 16675: $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>'; 16676: } 16677: if ($errors) { 16678: $resulttext .= &mt('The following errors occurred: ').'<ul>'. 16679: $errors.'</ul>'; 16680: } 16681: return $resulttext; 16682: } 16683: 16684: sub get_lti_id { 16685: my ($domain,$consumer) = @_; 16686: # get lock on lti db 16687: my $lockhash = { 16688: lock => $env{'user.name'}. 16689: ':'.$env{'user.domain'}, 16690: }; 16691: my $tries = 0; 16692: my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain); 16693: my ($id,$error); 16694: 16695: while (($gotlock ne 'ok') && ($tries<10)) { 16696: $tries ++; 16697: sleep (0.1); 16698: $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain); 16699: } 16700: if ($gotlock eq 'ok') { 16701: my %currids = &Apache::lonnet::dump_dom('lti',$domain); 16702: if ($currids{'lock'}) { 16703: delete($currids{'lock'}); 16704: if (keys(%currids)) { 16705: my @curr = sort { $a <=> $b } keys(%currids); 16706: if ($curr[-1] =~ /^\d+$/) { 16707: $id = 1 + $curr[-1]; 16708: } 16709: } else { 16710: $id = 1; 16711: } 16712: if ($id) { 16713: unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') { 16714: $error = 'nostore'; 16715: } 16716: } else { 16717: $error = 'nonumber'; 16718: } 16719: } 16720: my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain); 16721: } else { 16722: $error = 'nolock'; 16723: } 16724: return ($id,$error); 16725: } 16726: 16727: sub modify_autoenroll { 16728: my ($dom,$lastactref,%domconfig) = @_; 16729: my ($resulttext,%changes); 16730: my %currautoenroll; 16731: if (ref($domconfig{'autoenroll'}) eq 'HASH') { 16732: foreach my $key (keys(%{$domconfig{'autoenroll'}})) { 16733: $currautoenroll{$key} = $domconfig{'autoenroll'}{$key}; 16734: } 16735: } 16736: my $autorun = &Apache::lonnet::auto_run(undef,$dom), 16737: my %title = ( run => 'Auto-enrollment active', 16738: sender => 'Sender for notification messages', 16739: coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)', 16740: autofailsafe => 'Failsafe for no drops if institutional data missing for a section'); 16741: my @offon = ('off','on'); 16742: my $sender_uname = $env{'form.sender_uname'}; 16743: my $sender_domain = $env{'form.sender_domain'}; 16744: if ($sender_domain eq '') { 16745: $sender_uname = ''; 16746: } elsif ($sender_uname eq '') { 16747: $sender_domain = ''; 16748: } 16749: my $coowners = $env{'form.autoassign_coowners'}; 16750: my $autofailsafe = $env{'form.autoenroll_autofailsafe'}; 16751: $autofailsafe =~ s{^\s+|\s+$}{}g; 16752: if ($autofailsafe =~ /\D/) { 16753: undef($autofailsafe); 16754: } 16755: my $failsafe = $env{'form.autoenroll_failsafe'}; 16756: unless (($failsafe eq 'zero') || ($failsafe eq 'any')) { 16757: $failsafe = 'off'; 16758: undef($autofailsafe); 16759: } 16760: my %autoenrollhash = ( 16761: autoenroll => { 'run' => $env{'form.autoenroll_run'}, 16762: 'sender_uname' => $sender_uname, 16763: 'sender_domain' => $sender_domain, 16764: 'co-owners' => $coowners, 16765: 'autofailsafe' => $autofailsafe, 16766: 'failsafe' => $failsafe, 16767: } 16768: ); 16769: my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash, 16770: $dom); 16771: if ($putresult eq 'ok') { 16772: if (exists($currautoenroll{'run'})) { 16773: if ($currautoenroll{'run'} ne $env{'form.autoenroll_run'}) { 16774: $changes{'run'} = 1; 16775: } 16776: } elsif ($autorun) { 16777: if ($env{'form.autoenroll_run'} ne '1') { 16778: $changes{'run'} = 1; 16779: } 16780: } 16781: if ($currautoenroll{'sender_uname'} ne $sender_uname) { 16782: $changes{'sender'} = 1; 16783: } 16784: if ($currautoenroll{'sender_domain'} ne $sender_domain) { 16785: $changes{'sender'} = 1; 16786: } 16787: if ($currautoenroll{'co-owners'} ne '') { 16788: if ($currautoenroll{'co-owners'} ne $coowners) { 16789: $changes{'coowners'} = 1; 16790: } 16791: } elsif ($coowners) { 16792: $changes{'coowners'} = 1; 16793: } 16794: if ($currautoenroll{'autofailsafe'} ne $autofailsafe) { 16795: $changes{'autofailsafe'} = 1; 16796: } 16797: if ($currautoenroll{'failsafe'} ne $failsafe) { 16798: $changes{'failsafe'} = 1; 16799: } 16800: if (keys(%changes) > 0) { 16801: $resulttext = &mt('Changes made:').'<ul>'; 16802: if ($changes{'run'}) { 16803: $resulttext .= '<li>'.&mt("$title{'run'} set to $offon[$env{'form.autoenroll_run'}]").'</li>'; 16804: } 16805: if ($changes{'sender'}) { 16806: if ($sender_uname eq '' || $sender_domain eq '') { 16807: $resulttext .= '<li>'.&mt("$title{'sender'} set to default (course owner).").'</li>'; 16808: } else { 16809: $resulttext .= '<li>'.&mt("$title{'sender'} set to [_1]",$sender_uname.':'.$sender_domain).'</li>'; 16810: } 16811: } 16812: if ($changes{'coowners'}) { 16813: $resulttext .= '<li>'.&mt("$title{'coowners'} set to $offon[$env{'form.autoassign_coowners'}]").'</li>'; 16814: &Apache::loncommon::devalidate_domconfig_cache($dom); 16815: if (ref($lastactref) eq 'HASH') { 16816: $lastactref->{'domainconfig'} = 1; 16817: } 16818: } 16819: if ($changes{'autofailsafe'}) { 16820: if ($autofailsafe ne '') { 16821: $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$autofailsafe).'</li>'; 16822: } else { 16823: $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>'; 16824: } 16825: } 16826: if ($changes{'failsafe'}) { 16827: if ($failsafe eq 'off') { 16828: unless ($changes{'autofailsafe'}) { 16829: $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section not in use').'</li>'; 16830: } 16831: } elsif ($failsafe eq 'zero') { 16832: $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero').'</li>'; 16833: } else { 16834: $resulttext .= '<li>'.&mt('Failsafe applies if retrieved section enrollment is zero or greater').'</li>'; 16835: } 16836: } 16837: if (($changes{'autofailsafe'}) || ($changes{'failsafe'})) { 16838: &Apache::lonnet::get_domain_defaults($dom,1); 16839: if (ref($lastactref) eq 'HASH') { 16840: $lastactref->{'domdefaults'} = 1; 16841: } 16842: } 16843: $resulttext .= '</ul>'; 16844: } else { 16845: $resulttext = &mt('No changes made to auto-enrollment settings'); 16846: } 16847: } else { 16848: $resulttext = '<span class="LC_error">'. 16849: &mt('An error occurred: [_1]',$putresult).'</span>'; 16850: } 16851: return $resulttext; 16852: } 16853: 16854: sub modify_autoupdate { 16855: my ($dom,%domconfig) = @_; 16856: my ($resulttext,%currautoupdate,%fields,%changes); 16857: if (ref($domconfig{'autoupdate'}) eq 'HASH') { 16858: foreach my $key (keys(%{$domconfig{'autoupdate'}})) { 16859: $currautoupdate{$key} = $domconfig{'autoupdate'}{$key}; 16860: } 16861: } 16862: my @offon = ('off','on'); 16863: my %title = &Apache::lonlocal::texthash ( 16864: run => 'Auto-update:', 16865: classlists => 'Updates to user information in classlists?', 16866: unexpired => 'Skip updates for users without active or future roles?', 16867: lastactive => 'Skip updates for inactive users?', 16868: ); 16869: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 16870: my %fieldtitles = &Apache::lonlocal::texthash ( 16871: id => 'Student/Employee ID', 16872: permanentemail => 'E-mail address', 16873: lastname => 'Last Name', 16874: firstname => 'First Name', 16875: middlename => 'Middle Name', 16876: generation => 'Generation', 16877: ); 16878: $othertitle = &mt('All users'); 16879: if (keys(%{$usertypes}) > 0) { 16880: $othertitle = &mt('Other users'); 16881: } 16882: foreach my $key (keys(%env)) { 16883: if ($key =~ /^form\.updateable_(.+)_([^_]+)$/) { 16884: my ($usertype,$item) = ($1,$2); 16885: if (grep(/^\Q$item\E$/,keys(%fieldtitles))) { 16886: if ($usertype eq 'default') { 16887: push(@{$fields{$1}},$2); 16888: } elsif (ref($types) eq 'ARRAY') { 16889: if (grep(/^\Q$usertype\E$/,@{$types})) { 16890: push(@{$fields{$1}},$2); 16891: } 16892: } 16893: } 16894: } 16895: } 16896: my @lockablenames = &Apache::loncommon::get_env_multiple('form.lockablenames'); 16897: @lockablenames = sort(@lockablenames); 16898: if (ref($currautoupdate{'lockablenames'}) eq 'ARRAY') { 16899: my @changed = &Apache::loncommon::compare_arrays($currautoupdate{'lockablenames'},\@lockablenames); 16900: if (@changed) { 16901: $changes{'lockablenames'} = 1; 16902: } 16903: } else { 16904: if (@lockablenames) { 16905: $changes{'lockablenames'} = 1; 16906: } 16907: } 16908: my %updatehash = ( 16909: autoupdate => { run => $env{'form.autoupdate_run'}, 16910: classlists => $env{'form.classlists'}, 16911: unexpired => $env{'form.unexpired'}, 16912: fields => {%fields}, 16913: lockablenames => \@lockablenames, 16914: } 16915: ); 16916: my $lastactivedays; 16917: if ($env{'form.lastactive'}) { 16918: $lastactivedays = $env{'form.lastactivedays'}; 16919: $lastactivedays =~ s/^\s+|\s+$//g; 16920: unless ($lastactivedays =~ /^\d+$/) { 16921: undef($lastactivedays); 16922: $env{'form.lastactive'} = 0; 16923: } 16924: } 16925: $updatehash{'autoupdate'}{'lastactive'} = $lastactivedays; 16926: foreach my $key (keys(%currautoupdate)) { 16927: if (($key eq 'run') || ($key eq 'classlists') || ($key eq 'unexpired') || ($key eq 'lastactive')) { 16928: if (exists($updatehash{autoupdate}{$key})) { 16929: if ($currautoupdate{$key} ne $updatehash{autoupdate}{$key}) { 16930: $changes{$key} = 1; 16931: } 16932: } 16933: } elsif ($key eq 'fields') { 16934: if (ref($currautoupdate{$key}) eq 'HASH') { 16935: foreach my $item (@{$types},'default') { 16936: if (ref($currautoupdate{$key}{$item}) eq 'ARRAY') { 16937: my $change = 0; 16938: foreach my $type (@{$currautoupdate{$key}{$item}}) { 16939: if (!exists($fields{$item})) { 16940: $change = 1; 16941: last; 16942: } elsif (ref($fields{$item}) eq 'ARRAY') { 16943: if (!grep(/^\Q$type\E$/,@{$fields{$item}})) { 16944: $change = 1; 16945: last; 16946: } 16947: } 16948: } 16949: if ($change) { 16950: push(@{$changes{$key}},$item); 16951: } 16952: } 16953: } 16954: } 16955: } elsif ($key eq 'lockablenames') { 16956: if (ref($currautoupdate{$key}) eq 'ARRAY') { 16957: my @changed = &Apache::loncommon::compare_arrays($currautoupdate{'lockablenames'},\@lockablenames); 16958: if (@changed) { 16959: $changes{'lockablenames'} = 1; 16960: } 16961: } else { 16962: if (@lockablenames) { 16963: $changes{'lockablenames'} = 1; 16964: } 16965: } 16966: } 16967: } 16968: unless (grep(/^\Qlockablenames\E$/,keys(%currautoupdate))) { 16969: if (@lockablenames) { 16970: $changes{'lockablenames'} = 1; 16971: } 16972: } 16973: unless (grep(/^unexpired$/,keys(%currautoupdate))) { 16974: if ($updatehash{'autoupdate'}{'unexpired'}) { 16975: $changes{'unexpired'} = 1; 16976: } 16977: } 16978: unless (grep(/^lastactive$/,keys(%currautoupdate))) { 16979: if ($updatehash{'autoupdate'}{'lastactive'} ne '') { 16980: $changes{'lastactive'} = 1; 16981: } 16982: } 16983: foreach my $item (@{$types},'default') { 16984: if (defined($fields{$item})) { 16985: if (ref($currautoupdate{'fields'}) eq 'HASH') { 16986: if (ref($currautoupdate{'fields'}{$item}) eq 'ARRAY') { 16987: my $change = 0; 16988: if (ref($fields{$item}) eq 'ARRAY') { 16989: foreach my $type (@{$fields{$item}}) { 16990: if (!grep(/^\Q$type\E$/,@{$currautoupdate{'fields'}{$item}})) { 16991: $change = 1; 16992: last; 16993: } 16994: } 16995: } 16996: if ($change) { 16997: push(@{$changes{'fields'}},$item); 16998: } 16999: } else { 17000: push(@{$changes{'fields'}},$item); 17001: } 17002: } else { 17003: push(@{$changes{'fields'}},$item); 17004: } 17005: } 17006: } 17007: my $putresult = &Apache::lonnet::put_dom('configuration',\%updatehash, 17008: $dom); 17009: if ($putresult eq 'ok') { 17010: if (keys(%changes) > 0) { 17011: $resulttext = &mt('Changes made:').'<ul>'; 17012: foreach my $key (sort(keys(%changes))) { 17013: if ($key eq 'lockablenames') { 17014: $resulttext .= '<li>'; 17015: if (@lockablenames) { 17016: $usertypes->{'default'} = $othertitle; 17017: $resulttext .= &mt("User preference to disable replacement of user's name with institutional data (by auto-update), available for the following affiliations:").' '. 17018: join(', ', map { $usertypes->{$_}; } @lockablenames).'</li>'; 17019: } else { 17020: $resulttext .= &mt("User preference to disable replacement of user's name with institutional data (by auto-update) is unavailable."); 17021: } 17022: $resulttext .= '</li>'; 17023: } elsif (ref($changes{$key}) eq 'ARRAY') { 17024: foreach my $item (@{$changes{$key}}) { 17025: my @newvalues; 17026: foreach my $type (@{$fields{$item}}) { 17027: push(@newvalues,$fieldtitles{$type}); 17028: } 17029: my $newvaluestr; 17030: if (@newvalues > 0) { 17031: $newvaluestr = join(', ',@newvalues); 17032: } else { 17033: $newvaluestr = &mt('none'); 17034: } 17035: if ($item eq 'default') { 17036: $resulttext .= '<li>'.&mt("Updates for '[_1]' set to: '[_2]'",$othertitle,$newvaluestr).'</li>'; 17037: } else { 17038: $resulttext .= '<li>'.&mt("Updates for '[_1]' set to: '[_2]'",$usertypes->{$item},$newvaluestr).'</li>'; 17039: } 17040: } 17041: } else { 17042: my $newvalue; 17043: if ($key eq 'run') { 17044: $newvalue = $offon[$env{'form.autoupdate_run'}]; 17045: } elsif ($key eq 'lastactive') { 17046: $newvalue = $offon[$env{'form.lastactive'}]; 17047: unless ($lastactivedays eq '') { 17048: $newvalue .= '; '.&mt('inactive = no activity in last [quant,_1,day]',$lastactivedays); 17049: } 17050: } else { 17051: $newvalue = $offon[$env{'form.'.$key}]; 17052: } 17053: $resulttext .= '<li>'.&mt("[_1] set to $newvalue",$title{$key}).'</li>'; 17054: } 17055: } 17056: $resulttext .= '</ul>'; 17057: } else { 17058: $resulttext = &mt('No changes made to autoupdates'); 17059: } 17060: } else { 17061: $resulttext = '<span class="LC_error">'. 17062: &mt('An error occurred: [_1]',$putresult).'</span>'; 17063: } 17064: return $resulttext; 17065: } 17066: 17067: sub modify_autocreate { 17068: my ($dom,%domconfig) = @_; 17069: my ($resulttext,%changes,%currautocreate,%newvals,%autocreatehash); 17070: if (ref($domconfig{'autocreate'}) eq 'HASH') { 17071: foreach my $key (keys(%{$domconfig{'autocreate'}})) { 17072: $currautocreate{$key} = $domconfig{'autocreate'}{$key}; 17073: } 17074: } 17075: my %title= ( xml => 'Auto-creation of courses in XML course description files', 17076: req => 'Auto-creation of validated requests for official courses', 17077: xmldc => 'Identity of course creator of courses from XML files', 17078: ); 17079: my @types = ('xml','req'); 17080: foreach my $item (@types) { 17081: $newvals{$item} = $env{'form.autocreate_'.$item}; 17082: $newvals{$item} =~ s/\D//g; 17083: $newvals{$item} = 0 if ($newvals{$item} eq ''); 17084: } 17085: $newvals{'xmldc'} = $env{'form.autocreate_xmldc'}; 17086: my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']); 17087: unless (exists($domcoords{$newvals{'xmldc'}})) { 17088: $newvals{'xmldc'} = ''; 17089: } 17090: %autocreatehash = ( 17091: autocreate => { xml => $newvals{'xml'}, 17092: req => $newvals{'req'}, 17093: } 17094: ); 17095: if ($newvals{'xmldc'} ne '') { 17096: $autocreatehash{'autocreate'}{'xmldc'} = $newvals{'xmldc'}; 17097: } 17098: my $putresult = &Apache::lonnet::put_dom('configuration',\%autocreatehash, 17099: $dom); 17100: if ($putresult eq 'ok') { 17101: my @items = @types; 17102: if ($newvals{'xml'}) { 17103: push(@items,'xmldc'); 17104: } 17105: foreach my $item (@items) { 17106: if (exists($currautocreate{$item})) { 17107: if ($currautocreate{$item} ne $newvals{$item}) { 17108: $changes{$item} = 1; 17109: } 17110: } elsif ($newvals{$item}) { 17111: $changes{$item} = 1; 17112: } 17113: } 17114: if (keys(%changes) > 0) { 17115: my @offon = ('off','on'); 17116: $resulttext = &mt('Changes made:').'<ul>'; 17117: foreach my $item (@types) { 17118: if ($changes{$item}) { 17119: my $newtxt = $offon[$newvals{$item}]; 17120: $resulttext .= '<li>'. 17121: &mt("$title{$item} set to [_1]$newtxt [_2]", 17122: '<b>','</b>'). 17123: '</li>'; 17124: } 17125: } 17126: if ($changes{'xmldc'}) { 17127: my ($dcname,$dcdom) = split(':',$newvals{'xmldc'}); 17128: my $newtxt = &Apache::loncommon::plainname($dcname,$dcdom); 17129: $resulttext .= '<li>'.&mt("$title{'xmldc'} set to [_1]",'<b>'.$newtxt.'</b>').'</li>'; 17130: } 17131: $resulttext .= '</ul>'; 17132: } else { 17133: $resulttext = &mt('No changes made to auto-creation settings'); 17134: } 17135: } else { 17136: $resulttext = '<span class="LC_error">'. 17137: &mt('An error occurred: [_1]',$putresult).'</span>'; 17138: } 17139: return $resulttext; 17140: } 17141: 17142: sub modify_directorysrch { 17143: my ($dom,$lastactref,%domconfig) = @_; 17144: my ($resulttext,%changes); 17145: my %currdirsrch; 17146: if (ref($domconfig{'directorysrch'}) eq 'HASH') { 17147: foreach my $key (keys(%{$domconfig{'directorysrch'}})) { 17148: $currdirsrch{$key} = $domconfig{'directorysrch'}{$key}; 17149: } 17150: } 17151: my %title = ( available => 'Institutional directory search available', 17152: localonly => 'Other domains can search institution', 17153: lcavailable => 'LON-CAPA directory search available', 17154: lclocalonly => 'Other domains can search LON-CAPA domain', 17155: searchby => 'Search types', 17156: searchtypes => 'Search latitude'); 17157: my @offon = ('off','on'); 17158: my @otherdoms = ('Yes','No'); 17159: 17160: my @searchtypes = &Apache::loncommon::get_env_multiple('form.searchtypes'); 17161: my @cansearch = &Apache::loncommon::get_env_multiple('form.cansearch'); 17162: my @searchby = &Apache::loncommon::get_env_multiple('form.searchby'); 17163: 17164: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 17165: if (keys(%{$usertypes}) == 0) { 17166: @cansearch = ('default'); 17167: } else { 17168: if (ref($currdirsrch{'cansearch'}) eq 'ARRAY') { 17169: foreach my $type (@{$currdirsrch{'cansearch'}}) { 17170: if (!grep(/^\Q$type\E$/,@cansearch)) { 17171: push(@{$changes{'cansearch'}},$type); 17172: } 17173: } 17174: foreach my $type (@cansearch) { 17175: if (!grep(/^\Q$type\E$/,@{$currdirsrch{'cansearch'}})) { 17176: push(@{$changes{'cansearch'}},$type); 17177: } 17178: } 17179: } else { 17180: push(@{$changes{'cansearch'}},@cansearch); 17181: } 17182: } 17183: 17184: if (ref($currdirsrch{'searchby'}) eq 'ARRAY') { 17185: foreach my $by (@{$currdirsrch{'searchby'}}) { 17186: if (!grep(/^\Q$by\E$/,@searchby)) { 17187: push(@{$changes{'searchby'}},$by); 17188: } 17189: } 17190: foreach my $by (@searchby) { 17191: if (!grep(/^\Q$by\E$/,@{$currdirsrch{'searchby'}})) { 17192: push(@{$changes{'searchby'}},$by); 17193: } 17194: } 17195: } else { 17196: push(@{$changes{'searchby'}},@searchby); 17197: } 17198: 17199: if (ref($currdirsrch{'searchtypes'}) eq 'ARRAY') { 17200: foreach my $type (@{$currdirsrch{'searchtypes'}}) { 17201: if (!grep(/^\Q$type\E$/,@searchtypes)) { 17202: push(@{$changes{'searchtypes'}},$type); 17203: } 17204: } 17205: foreach my $type (@searchtypes) { 17206: if (!grep(/^\Q$type\E$/,@{$currdirsrch{'searchtypes'}})) { 17207: push(@{$changes{'searchtypes'}},$type); 17208: } 17209: } 17210: } else { 17211: if (exists($currdirsrch{'searchtypes'})) { 17212: foreach my $type (@searchtypes) { 17213: if ($type ne $currdirsrch{'searchtypes'}) { 17214: push(@{$changes{'searchtypes'}},$type); 17215: } 17216: } 17217: if (!grep(/^\Q$currdirsrch{'searchtypes'}\E/,@searchtypes)) { 17218: push(@{$changes{'searchtypes'}},$currdirsrch{'searchtypes'}); 17219: } 17220: } else { 17221: push(@{$changes{'searchtypes'}},@searchtypes); 17222: } 17223: } 17224: 17225: my %dirsrch_hash = ( 17226: directorysrch => { available => $env{'form.dirsrch_available'}, 17227: cansearch => \@cansearch, 17228: localonly => $env{'form.dirsrch_instlocalonly'}, 17229: lclocalonly => $env{'form.dirsrch_domlocalonly'}, 17230: lcavailable => $env{'form.dirsrch_domavailable'}, 17231: searchby => \@searchby, 17232: searchtypes => \@searchtypes, 17233: } 17234: ); 17235: my $putresult = &Apache::lonnet::put_dom('configuration',\%dirsrch_hash, 17236: $dom); 17237: if ($putresult eq 'ok') { 17238: if (exists($currdirsrch{'available'})) { 17239: if ($currdirsrch{'available'} ne $env{'form.dirsrch_available'}) { 17240: $changes{'available'} = 1; 17241: } 17242: } else { 17243: if ($env{'form.dirsrch_available'} eq '1') { 17244: $changes{'available'} = 1; 17245: } 17246: } 17247: if (exists($currdirsrch{'lcavailable'})) { 17248: if ($currdirsrch{'lcavailable'} ne $env{'form.dirsrch_domavailable'}) { 17249: $changes{'lcavailable'} = 1; 17250: } 17251: } else { 17252: if ($env{'form.dirsrch_lcavailable'} eq '1') { 17253: $changes{'lcavailable'} = 1; 17254: } 17255: } 17256: if (exists($currdirsrch{'localonly'})) { 17257: if ($currdirsrch{'localonly'} ne $env{'form.dirsrch_instlocalonly'}) { 17258: $changes{'localonly'} = 1; 17259: } 17260: } else { 17261: if ($env{'form.dirsrch_instlocalonly'} eq '1') { 17262: $changes{'localonly'} = 1; 17263: } 17264: } 17265: if (exists($currdirsrch{'lclocalonly'})) { 17266: if ($currdirsrch{'lclocalonly'} ne $env{'form.dirsrch_domlocalonly'}) { 17267: $changes{'lclocalonly'} = 1; 17268: } 17269: } else { 17270: if ($env{'form.dirsrch_domlocalonly'} eq '1') { 17271: $changes{'lclocalonly'} = 1; 17272: } 17273: } 17274: if (keys(%changes) > 0) { 17275: $resulttext = &mt('Changes made:').'<ul>'; 17276: if ($changes{'available'}) { 17277: $resulttext .= '<li>'.&mt("$title{'available'} set to: $offon[$env{'form.dirsrch_available'}]").'</li>'; 17278: } 17279: if ($changes{'lcavailable'}) { 17280: $resulttext .= '<li>'.&mt("$title{'lcavailable'} set to: $offon[$env{'form.dirsrch_domavailable'}]").'</li>'; 17281: } 17282: if ($changes{'localonly'}) { 17283: $resulttext .= '<li>'.&mt("$title{'localonly'} set to: $otherdoms[$env{'form.dirsrch_instlocalonly'}]").'</li>'; 17284: } 17285: if ($changes{'lclocalonly'}) { 17286: $resulttext .= '<li>'.&mt("$title{'lclocalonly'} set to: $otherdoms[$env{'form.dirsrch_domlocalonly'}]").'</li>'; 17287: } 17288: if (ref($changes{'cansearch'}) eq 'ARRAY') { 17289: my $chgtext; 17290: if (ref($usertypes) eq 'HASH') { 17291: if (keys(%{$usertypes}) > 0) { 17292: foreach my $type (@{$types}) { 17293: if (grep(/^\Q$type\E$/,@cansearch)) { 17294: $chgtext .= $usertypes->{$type}.'; '; 17295: } 17296: } 17297: if (grep(/^default$/,@cansearch)) { 17298: $chgtext .= $othertitle; 17299: } else { 17300: $chgtext =~ s/\; $//; 17301: } 17302: $resulttext .= 17303: '<li>'. 17304: &mt("Users from domain '[_1]' permitted to search the institutional directory set to: [_2]", 17305: '<span class="LC_cusr_emph">'.$dom.'</span>',$chgtext). 17306: '</li>'; 17307: } 17308: } 17309: } 17310: if (ref($changes{'searchby'}) eq 'ARRAY') { 17311: my ($searchtitles,$titleorder) = &sorted_searchtitles(); 17312: my $chgtext; 17313: foreach my $type (@{$titleorder}) { 17314: if (grep(/^\Q$type\E$/,@searchby)) { 17315: if (defined($searchtitles->{$type})) { 17316: $chgtext .= $searchtitles->{$type}.'; '; 17317: } 17318: } 17319: } 17320: $chgtext =~ s/\; $//; 17321: $resulttext .= '<li>'.&mt("$title{'searchby'} set to: [_1]",$chgtext).'</li>'; 17322: } 17323: if (ref($changes{'searchtypes'}) eq 'ARRAY') { 17324: my ($srchtypes_desc,$srchtypeorder) = &sorted_searchtypes(); 17325: my $chgtext; 17326: foreach my $type (@{$srchtypeorder}) { 17327: if (grep(/^\Q$type\E$/,@searchtypes)) { 17328: if (defined($srchtypes_desc->{$type})) { 17329: $chgtext .= $srchtypes_desc->{$type}.'; '; 17330: } 17331: } 17332: } 17333: $chgtext =~ s/\; $//; 17334: $resulttext .= '<li>'.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'</li>'; 17335: } 17336: $resulttext .= '</ul>'; 17337: &Apache::lonnet::do_cache_new('directorysrch',$dom,$dirsrch_hash{'directorysrch'},3600); 17338: if (ref($lastactref) eq 'HASH') { 17339: $lastactref->{'directorysrch'} = 1; 17340: } 17341: } else { 17342: $resulttext = &mt('No changes made to directory search settings'); 17343: } 17344: } else { 17345: $resulttext = '<span class="LC_error">'. 17346: &mt('An error occurred: [_1]',$putresult).'</span>'; 17347: } 17348: return $resulttext; 17349: } 17350: 17351: sub modify_contacts { 17352: my ($dom,$lastactref,%domconfig) = @_; 17353: my ($resulttext,%currsetting,%newsetting,%changes,%contacts_hash); 17354: if (ref($domconfig{'contacts'}) eq 'HASH') { 17355: foreach my $key (keys(%{$domconfig{'contacts'}})) { 17356: $currsetting{$key} = $domconfig{'contacts'}{$key}; 17357: } 17358: } 17359: my (%others,%to,%bcc,%includestr,%includeloc); 17360: my @contacts = ('supportemail','adminemail'); 17361: my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail', 17362: 'lonstatusmail','requestsmail','updatesmail','idconflictsmail','hostipmail'); 17363: my @toggles = ('reporterrors','reportupdates','reportstatus'); 17364: my @lonstatus = ('threshold','sysmail','weights','excluded'); 17365: my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields(); 17366: foreach my $type (@mailings) { 17367: @{$newsetting{$type}} = 17368: &Apache::loncommon::get_env_multiple('form.'.$type); 17369: foreach my $item (@contacts) { 17370: if (grep(/^\Q$item\E$/,@{$newsetting{$type}})) { 17371: $contacts_hash{contacts}{$type}{$item} = 1; 17372: } else { 17373: $contacts_hash{contacts}{$type}{$item} = 0; 17374: } 17375: } 17376: $others{$type} = $env{'form.'.$type.'_others'}; 17377: $contacts_hash{contacts}{$type}{'others'} = $others{$type}; 17378: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 17379: $bcc{$type} = $env{'form.'.$type.'_bcc'}; 17380: $contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type}; 17381: if (($env{'form.'.$type.'_includestr'} ne '') && ($env{'form.'.$type.'_includeloc'} =~ /^s|b$/)) { 17382: $includestr{$type} = $env{'form.'.$type.'_includestr'}; 17383: $includeloc{$type} = $env{'form.'.$type.'_includeloc'}; 17384: $contacts_hash{contacts}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type}); 17385: } 17386: } 17387: } 17388: foreach my $item (@contacts) { 17389: $to{$item} = $env{'form.'.$item}; 17390: $contacts_hash{'contacts'}{$item} = $to{$item}; 17391: } 17392: foreach my $item (@toggles) { 17393: if ($env{'form.'.$item} =~ /^(0|1)$/) { 17394: $contacts_hash{'contacts'}{$item} = $env{'form.'.$item}; 17395: } 17396: } 17397: my ($lonstatus_defs,$lonstatus_names) = &Apache::loncommon::lon_status_items(); 17398: foreach my $item (@lonstatus) { 17399: if ($item eq 'excluded') { 17400: my (%serverhomes,@excluded); 17401: map { $serverhomes{$_} = 1; } values(%Apache::lonnet::serverhomeIDs); 17402: my @possexcluded = &Apache::loncommon::get_env_multiple('form.errorexcluded'); 17403: if (@possexcluded) { 17404: foreach my $id (sort(@possexcluded)) { 17405: if ($serverhomes{$id}) { 17406: push(@excluded,$id); 17407: } 17408: } 17409: } 17410: if (@excluded) { 17411: $contacts_hash{'contacts'}{'lonstatus'}{$item} = \@excluded; 17412: } 17413: } elsif ($item eq 'weights') { 17414: foreach my $type ('E','W','N','U') { 17415: $env{'form.error'.$item.'_'.$type} =~ s/^\s+|\s+$//g; 17416: if ($env{'form.error'.$item.'_'.$type} =~ /^\d+$/) { 17417: unless ($env{'form.error'.$item.'_'.$type} == $lonstatus_defs->{$type}) { 17418: $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type} = 17419: $env{'form.error'.$item.'_'.$type}; 17420: } 17421: } 17422: } 17423: } elsif (($item eq 'threshold') || ($item eq 'sysmail')) { 17424: $env{'form.error'.$item} =~ s/^\s+|\s+$//g; 17425: if ($env{'form.error'.$item} =~ /^\d+$/) { 17426: unless ($env{'form.error'.$item} == $lonstatus_defs->{$item}) { 17427: $contacts_hash{'contacts'}{'lonstatus'}{$item} = $env{'form.error'.$item}; 17428: } 17429: } 17430: } 17431: } 17432: if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) { 17433: foreach my $field (@{$fields}) { 17434: if (ref($possoptions->{$field}) eq 'ARRAY') { 17435: my $value = $env{'form.helpform_'.$field}; 17436: $value =~ s/^\s+|\s+$//g; 17437: if (grep(/^\Q$value\E$/,@{$possoptions->{$field}})) { 17438: $contacts_hash{'contacts'}{'helpform'}{$field} = $value; 17439: if ($field eq 'screenshot') { 17440: $env{'form.helpform_maxsize'} =~ s/^\s+|\s+$//g; 17441: if ($env{'form.helpform_maxsize'} =~ /^\d+\.?\d*$/) { 17442: $contacts_hash{'contacts'}{'helpform'}{'maxsize'} = $env{'form.helpform_maxsize'}; 17443: } 17444: } 17445: } 17446: } 17447: } 17448: } 17449: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 17450: my (@statuses,%usertypeshash,@overrides); 17451: if ((ref($types) eq 'ARRAY') && (@{$types} > 0)) { 17452: @statuses = @{$types}; 17453: if (ref($usertypes) eq 'HASH') { 17454: %usertypeshash = %{$usertypes}; 17455: } 17456: } 17457: if (@statuses) { 17458: my @possoverrides = &Apache::loncommon::get_env_multiple('form.overrides'); 17459: foreach my $type (@possoverrides) { 17460: if (($type ne '') && (grep(/^\Q$type\E$/,@statuses))) { 17461: push(@overrides,$type); 17462: } 17463: } 17464: if (@overrides) { 17465: foreach my $type (@overrides) { 17466: my @standard = &Apache::loncommon::get_env_multiple('form.override_'.$type); 17467: foreach my $item (@contacts) { 17468: if (grep(/^\Q$item\E$/,@standard)) { 17469: $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 1; 17470: $newsetting{'override_'.$type}{$item} = 1; 17471: } else { 17472: $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 0; 17473: $newsetting{'override_'.$type}{$item} = 0; 17474: } 17475: } 17476: $contacts_hash{'contacts'}{'overrides'}{$type}{'others'} = $env{'form.override_'.$type.'_others'}; 17477: $contacts_hash{'contacts'}{'overrides'}{$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'}; 17478: $newsetting{'override_'.$type}{'others'} = $env{'form.override_'.$type.'_others'}; 17479: $newsetting{'override_'.$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'}; 17480: if (($env{'form.override_'.$type.'_includestr'} ne '') && ($env{'form.override_'.$type.'_includeloc'} =~ /^s|b$/)) { 17481: $includestr{$type} = $env{'form.override_'.$type.'_includestr'}; 17482: $includeloc{$type} = $env{'form.override_'.$type.'_includeloc'}; 17483: $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type}); 17484: $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'}; 17485: } 17486: } 17487: } 17488: } 17489: if (keys(%currsetting) > 0) { 17490: foreach my $item (@contacts) { 17491: if ($to{$item} ne $currsetting{$item}) { 17492: $changes{$item} = 1; 17493: } 17494: } 17495: foreach my $type (@mailings) { 17496: foreach my $item (@contacts) { 17497: if (ref($currsetting{$type}) eq 'HASH') { 17498: if ($currsetting{$type}{$item} ne $contacts_hash{contacts}{$type}{$item}) { 17499: push(@{$changes{$type}},$item); 17500: } 17501: } else { 17502: push(@{$changes{$type}},@{$newsetting{$type}}); 17503: } 17504: } 17505: if ($others{$type} ne $currsetting{$type}{'others'}) { 17506: push(@{$changes{$type}},'others'); 17507: } 17508: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 17509: if ($bcc{$type} ne $currsetting{$type}{'bcc'}) { 17510: push(@{$changes{$type}},'bcc'); 17511: } 17512: my ($currloc,$currstr) = split(/:/,$currsetting{$type}{'include'},2); 17513: if (($includeloc{$type} ne $currloc) || (&escape($includestr{$type}) ne $currstr)) { 17514: push(@{$changes{$type}},'include'); 17515: } 17516: } 17517: } 17518: if (ref($fields) eq 'ARRAY') { 17519: if (ref($currsetting{'helpform'}) eq 'HASH') { 17520: foreach my $field (@{$fields}) { 17521: if ($currsetting{'helpform'}{$field} ne $contacts_hash{'contacts'}{'helpform'}{$field}) { 17522: push(@{$changes{'helpform'}},$field); 17523: } 17524: if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) { 17525: if ($currsetting{'helpform'}{'maxsize'} ne $contacts_hash{'contacts'}{'helpform'}{'maxsize'}) { 17526: push(@{$changes{'helpform'}},'maxsize'); 17527: } 17528: } 17529: } 17530: } else { 17531: foreach my $field (@{$fields}) { 17532: if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') { 17533: push(@{$changes{'helpform'}},$field); 17534: } 17535: if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) { 17536: if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) { 17537: push(@{$changes{'helpform'}},'maxsize'); 17538: } 17539: } 17540: } 17541: } 17542: } 17543: if (@statuses) { 17544: if (ref($currsetting{'overrides'}) eq 'HASH') { 17545: foreach my $key (keys(%{$currsetting{'overrides'}})) { 17546: if (ref($currsetting{'overrides'}{$key}) eq 'HASH') { 17547: if (ref($newsetting{'override_'.$key}) eq 'HASH') { 17548: foreach my $item (@contacts,'bcc','others','include') { 17549: if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { 17550: push(@{$changes{'overrides'}},$key); 17551: last; 17552: } 17553: } 17554: } else { 17555: push(@{$changes{'overrides'}},$key); 17556: } 17557: } 17558: } 17559: foreach my $key (@overrides) { 17560: unless (exists($currsetting{'overrides'}{$key})) { 17561: push(@{$changes{'overrides'}},$key); 17562: } 17563: } 17564: } else { 17565: foreach my $key (@overrides) { 17566: push(@{$changes{'overrides'}},$key); 17567: } 17568: } 17569: } 17570: if (ref($currsetting{'lonstatus'}) eq 'HASH') { 17571: foreach my $key ('excluded','weights','threshold','sysmail') { 17572: if ($key eq 'excluded') { 17573: if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') && 17574: (ref($contacts_hash{contacts}{lonstatus}{excluded}) eq 'ARRAY')) { 17575: if ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') && 17576: (@{$currsetting{'lonstatus'}{$key}})) { 17577: my @diffs = 17578: &Apache::loncommon::compare_arrays($contacts_hash{contacts}{lonstatus}{excluded}, 17579: $currsetting{'lonstatus'}{$key}); 17580: if (@diffs) { 17581: push(@{$changes{'lonstatus'}},$key); 17582: } 17583: } elsif (@{$contacts_hash{contacts}{lonstatus}{excluded}}) { 17584: push(@{$changes{'lonstatus'}},$key); 17585: } 17586: } elsif ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') && 17587: (@{$currsetting{'lonstatus'}{$key}})) { 17588: push(@{$changes{'lonstatus'}},$key); 17589: } 17590: } elsif ($key eq 'weights') { 17591: if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') && 17592: (ref($contacts_hash{contacts}{lonstatus}{$key}) eq 'HASH')) { 17593: if (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') { 17594: foreach my $type ('E','W','N','U') { 17595: unless ($contacts_hash{contacts}{lonstatus}{$key}{$type} eq 17596: $currsetting{'lonstatus'}{$key}{$type}) { 17597: push(@{$changes{'lonstatus'}},$key); 17598: last; 17599: } 17600: } 17601: } else { 17602: foreach my $type ('E','W','N','U') { 17603: if ($contacts_hash{contacts}{lonstatus}{$key}{$type} ne '') { 17604: push(@{$changes{'lonstatus'}},$key); 17605: last; 17606: } 17607: } 17608: } 17609: } elsif (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') { 17610: foreach my $type ('E','W','N','U') { 17611: if ($currsetting{'lonstatus'}{$key}{$type} ne '') { 17612: push(@{$changes{'lonstatus'}},$key); 17613: last; 17614: } 17615: } 17616: } 17617: } elsif (($key eq 'threshold') || ($key eq 'sysmail')) { 17618: if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') { 17619: if ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) { 17620: if ($currsetting{'lonstatus'}{$key} != $contacts_hash{contacts}{lonstatus}{$key}) { 17621: push(@{$changes{'lonstatus'}},$key); 17622: } 17623: } elsif ($contacts_hash{contacts}{lonstatus}{$key} =~ /^\d+$/) { 17624: push(@{$changes{'lonstatus'}},$key); 17625: } 17626: } elsif ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) { 17627: push(@{$changes{'lonstatus'}},$key); 17628: } 17629: } 17630: } 17631: } else { 17632: if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') { 17633: foreach my $key ('excluded','weights','threshold','sysmail') { 17634: if (exists($contacts_hash{contacts}{lonstatus}{$key})) { 17635: push(@{$changes{'lonstatus'}},$key); 17636: } 17637: } 17638: } 17639: } 17640: } else { 17641: my %default; 17642: $default{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'}; 17643: $default{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'}; 17644: $default{'errormail'} = 'adminemail'; 17645: $default{'packagesmail'} = 'adminemail'; 17646: $default{'helpdeskmail'} = 'supportemail'; 17647: $default{'otherdomsmail'} = 'supportemail'; 17648: $default{'lonstatusmail'} = 'adminemail'; 17649: $default{'requestsmail'} = 'adminemail'; 17650: $default{'updatesmail'} = 'adminemail'; 17651: $default{'hostipmail'} = 'adminemail'; 17652: foreach my $item (@contacts) { 17653: if ($to{$item} ne $default{$item}) { 17654: $changes{$item} = 1; 17655: } 17656: } 17657: foreach my $type (@mailings) { 17658: if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) { 17659: push(@{$changes{$type}},@{$newsetting{$type}}); 17660: } 17661: if ($others{$type} ne '') { 17662: push(@{$changes{$type}},'others'); 17663: } 17664: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 17665: if ($bcc{$type} ne '') { 17666: push(@{$changes{$type}},'bcc'); 17667: } 17668: if (($includeloc{$type} =~ /^b|s$/) && ($includestr{$type} ne '')) { 17669: push(@{$changes{$type}},'include'); 17670: } 17671: } 17672: } 17673: if (ref($fields) eq 'ARRAY') { 17674: foreach my $field (@{$fields}) { 17675: if ($contacts_hash{'contacts'}{'helpform'}{$field} ne 'yes') { 17676: push(@{$changes{'helpform'}},$field); 17677: } 17678: if (($field eq 'screenshot') && ($contacts_hash{'contacts'}{'helpform'}{'screenshot'} ne 'no')) { 17679: if ($contacts_hash{'contacts'}{'helpform'}{'maxsize'} != 1) { 17680: push(@{$changes{'helpform'}},'maxsize'); 17681: } 17682: } 17683: } 17684: } 17685: if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') { 17686: foreach my $key ('excluded','weights','threshold','sysmail') { 17687: if (exists($contacts_hash{contacts}{lonstatus}{$key})) { 17688: push(@{$changes{'lonstatus'}},$key); 17689: } 17690: } 17691: } 17692: } 17693: foreach my $item (@toggles) { 17694: if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) { 17695: $changes{$item} = 1; 17696: } elsif ((!$env{'form.'.$item}) && 17697: (($currsetting{$item} eq '') || ($currsetting{$item} == 1))) { 17698: $changes{$item} = 1; 17699: } 17700: } 17701: my $putresult = &Apache::lonnet::put_dom('configuration',\%contacts_hash, 17702: $dom); 17703: if ($putresult eq 'ok') { 17704: if (keys(%changes) > 0) { 17705: &Apache::loncommon::devalidate_domconfig_cache($dom); 17706: if (ref($lastactref) eq 'HASH') { 17707: $lastactref->{'domainconfig'} = 1; 17708: } 17709: my ($titles,$short_titles) = &contact_titles(); 17710: $resulttext = &mt('Changes made:').'<ul>'; 17711: foreach my $item (@contacts) { 17712: if ($changes{$item}) { 17713: $resulttext .= '<li>'.$titles->{$item}. 17714: &mt(' set to: '). 17715: '<span class="LC_cusr_emph">'. 17716: $to{$item}.'</span></li>'; 17717: } 17718: } 17719: foreach my $type (@mailings) { 17720: if (ref($changes{$type}) eq 'ARRAY') { 17721: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 17722: $resulttext .= '<li>'.$titles->{$type}.' -- '.&mt('sent to').': '; 17723: } else { 17724: $resulttext .= '<li>'.$titles->{$type}.': '; 17725: } 17726: my @text; 17727: foreach my $item (@{$newsetting{$type}}) { 17728: push(@text,$short_titles->{$item}); 17729: } 17730: if ($others{$type} ne '') { 17731: push(@text,$others{$type}); 17732: } 17733: if (@text) { 17734: $resulttext .= '<span class="LC_cusr_emph">'. 17735: join(', ',@text).'</span>'; 17736: } 17737: if (($type eq 'helpdeskmail') || ($type eq 'otherdomsmail')) { 17738: if ($bcc{$type} ne '') { 17739: my $bcctext; 17740: if (@text) { 17741: $bcctext = ' '.&mt('with Bcc to'); 17742: } else { 17743: $bcctext = '(Bcc)'; 17744: } 17745: $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$bcc{$type}.'</span>'; 17746: } elsif (!@text) { 17747: $resulttext .= &mt('No one'); 17748: } 17749: if ($includestr{$type} ne '') { 17750: if ($includeloc{$type} eq 'b') { 17751: $resulttext .= '<br />'.&mt('Text automatically added to e-mail body:').' '.$includestr{$type}; 17752: } elsif ($includeloc{$type} eq 's') { 17753: $resulttext .= '<br />'.&mt('Text automatically added to e-mail subject:').' '.$includestr{$type}; 17754: } 17755: } 17756: } elsif (!@text) { 17757: $resulttext .= &mt('No recipients'); 17758: } 17759: $resulttext .= '</li>'; 17760: } 17761: } 17762: if (ref($changes{'overrides'}) eq 'ARRAY') { 17763: my @deletions; 17764: foreach my $type (@{$changes{'overrides'}}) { 17765: if ($usertypeshash{$type}) { 17766: if (grep(/^\Q$type\E/,@overrides)) { 17767: $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation set for [_1]", 17768: $usertypeshash{$type}).'<ul><li>'; 17769: if (ref($newsetting{'override_'.$type}) eq 'HASH') { 17770: my @text; 17771: foreach my $item (@contacts) { 17772: if ($newsetting{'override_'.$type}{$item}) { 17773: push(@text,$short_titles->{$item}); 17774: } 17775: } 17776: if ($newsetting{'override_'.$type}{'others'} ne '') { 17777: push(@text,$newsetting{'override_'.$type}{'others'}); 17778: } 17779: 17780: if (@text) { 17781: $resulttext .= &mt('Helpdesk e-mail sent to: [_1]', 17782: '<span class="LC_cusr_emph">'.join(', ',@text).'</span>'); 17783: } 17784: if ($newsetting{'override_'.$type}{'bcc'} ne '') { 17785: my $bcctext; 17786: if (@text) { 17787: $bcctext = ' '.&mt('with Bcc to'); 17788: } else { 17789: $bcctext = '(Bcc)'; 17790: } 17791: $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$newsetting{'override_'.$type}{'bcc'}.'</span>'; 17792: } elsif (!@text) { 17793: $resulttext .= &mt('Helpdesk e-mail sent to no one'); 17794: } 17795: $resulttext .= '</li>'; 17796: if ($newsetting{'override_'.$type}{'include'} ne '') { 17797: my ($loc,$str) = split(/:/,$newsetting{'override_'.$type}{'include'}); 17798: if ($loc eq 'b') { 17799: $resulttext .= '<li>'.&mt('Text automatically added to e-mail body:').' '.&unescape($str).'</li>'; 17800: } elsif ($loc eq 's') { 17801: $resulttext .= '<li>'.&mt('Text automatically added to e-mail subject:').' '.&unescape($str).'</li>'; 17802: } 17803: } 17804: } 17805: $resulttext .= '</li></ul></li>'; 17806: } else { 17807: push(@deletions,$usertypeshash{$type}); 17808: } 17809: } 17810: } 17811: if (@deletions) { 17812: $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation discontinued for: [_1]", 17813: join(', ',@deletions)).'</li>'; 17814: } 17815: } 17816: my @offon = ('off','on'); 17817: my $corelink = &core_link_msu(); 17818: if ($changes{'reporterrors'}) { 17819: $resulttext .= '<li>'. 17820: &mt('E-mail error reports to [_1] set to "'. 17821: $offon[$env{'form.reporterrors'}].'".', 17822: $corelink). 17823: '</li>'; 17824: } 17825: if ($changes{'reportupdates'}) { 17826: $resulttext .= '<li>'. 17827: &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'. 17828: $offon[$env{'form.reportupdates'}].'".', 17829: $corelink). 17830: '</li>'; 17831: } 17832: if ($changes{'reportstatus'}) { 17833: $resulttext .= '<li>'. 17834: &mt('E-mail status if errors above threshold to [_1] set to "'. 17835: $offon[$env{'form.reportstatus'}].'".', 17836: $corelink). 17837: '</li>'; 17838: } 17839: if (ref($changes{'lonstatus'}) eq 'ARRAY') { 17840: $resulttext .= '<li>'. 17841: &mt('Nightly status check e-mail settings').':<ul>'; 17842: my (%defval,%use_def,%shown); 17843: $defval{'threshold'} = $lonstatus_defs->{'threshold'}; 17844: $defval{'sysmail'} = $lonstatus_defs->{'sysmail'}; 17845: $defval{'weights'} = 17846: join(', ',map { $lonstatus_names->{$_}.'='.$lonstatus_defs->{$_}; } ('E','W','N','U')); 17847: $defval{'excluded'} = &mt('None'); 17848: if (ref($contacts_hash{'contacts'}{'lonstatus'}) eq 'HASH') { 17849: foreach my $item ('threshold','sysmail','weights','excluded') { 17850: if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item})) { 17851: if (($item eq 'threshold') || ($item eq 'sysmail')) { 17852: $shown{$item} = $contacts_hash{'contacts'}{'lonstatus'}{$item}; 17853: } elsif ($item eq 'weights') { 17854: if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'HASH') { 17855: foreach my $type ('E','W','N','U') { 17856: $shown{$item} .= $lonstatus_names->{$type}.'='; 17857: if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item}{$type})) { 17858: $shown{$item} .= $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type}; 17859: } else { 17860: $shown{$item} .= $lonstatus_defs->{$type}; 17861: } 17862: $shown{$item} .= ', '; 17863: } 17864: $shown{$item} =~ s/, $//; 17865: } else { 17866: $shown{$item} = $defval{$item}; 17867: } 17868: } elsif ($item eq 'excluded') { 17869: if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'ARRAY') { 17870: $shown{$item} = join(', ',@{$contacts_hash{'contacts'}{'lonstatus'}{$item}}); 17871: } else { 17872: $shown{$item} = $defval{$item}; 17873: } 17874: } 17875: } else { 17876: $shown{$item} = $defval{$item}; 17877: } 17878: } 17879: } else { 17880: foreach my $item ('threshold','weights','excluded','sysmail') { 17881: $shown{$item} = $defval{$item}; 17882: } 17883: } 17884: foreach my $item ('threshold','weights','excluded','sysmail') { 17885: $resulttext .= '<li>'.&mt($titles->{'error'.$item}.' -- [_1]', 17886: $shown{$item}).'</li>'; 17887: } 17888: $resulttext .= '</ul></li>'; 17889: } 17890: if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) { 17891: my (@optional,@required,@unused,$maxsizechg); 17892: foreach my $field (@{$changes{'helpform'}}) { 17893: if ($field eq 'maxsize') { 17894: $maxsizechg = 1; 17895: next; 17896: } 17897: if ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'yes') { 17898: push(@optional,$field); 17899: } elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'no') { 17900: push(@unused,$field); 17901: } elsif ($contacts_hash{'contacts'}{'helpform'}{$field} eq 'req') { 17902: push(@required,$field); 17903: } 17904: } 17905: if (@optional) { 17906: $resulttext .= '<li>'. 17907: &mt('Help form fields changed to "Optional": [_1].', 17908: '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @optional)).'</span>'. 17909: '</li>'; 17910: } 17911: if (@required) { 17912: $resulttext .= '<li>'. 17913: &mt('Help form fields changed to "Required": [_1].', 17914: '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @required)).'</span>'. 17915: '</li>'; 17916: } 17917: if (@unused) { 17918: $resulttext .= '<li>'. 17919: &mt('Help form fields changed to "Not shown": [_1].', 17920: '<span class="LC_cusr_emph">'.join(', ',map { $fieldtitles->{$_}; } @unused)).'</span>'. 17921: '</li>'; 17922: } 17923: if ($maxsizechg) { 17924: $resulttext .= '<li>'. 17925: &mt('Max size for file uploaded to help form by logged-in user set to [_1] MB.', 17926: $contacts_hash{'contacts'}{'helpform'}{'maxsize'}). 17927: '</li>'; 17928: } 17929: } 17930: $resulttext .= '</ul>'; 17931: } else { 17932: $resulttext = &mt('No changes made to contacts and form settings'); 17933: } 17934: } else { 17935: $resulttext = '<span class="LC_error">'. 17936: &mt('An error occurred: [_1].',$putresult).'</span>'; 17937: } 17938: return $resulttext; 17939: } 17940: 17941: sub modify_privacy { 17942: my ($dom,%domconfig) = @_; 17943: my ($resulttext,%current,%changes); 17944: if (ref($domconfig{'privacy'}) eq 'HASH') { 17945: %current = %{$domconfig{'privacy'}}; 17946: } 17947: my @fields = ('lastname','firstname','middlename','generation','permanentemail','id'); 17948: my @items = ('domain','author','course','community'); 17949: my %names = &Apache::lonlocal::texthash ( 17950: domain => 'Assigned domain role(s)', 17951: author => 'Assigned co-author role(s)', 17952: course => 'Assigned course role(s)', 17953: community => 'Assigned community role(s)', 17954: ); 17955: my %roles = &Apache::lonlocal::texthash ( 17956: domain => 'Domain role', 17957: author => 'Co-author role', 17958: course => 'Course role', 17959: community => 'Community role', 17960: ); 17961: my %titles = &Apache::lonlocal::texthash ( 17962: approval => 'Approval for role in different domain', 17963: othdom => 'User information available in other domain', 17964: priv => 'Information viewable by privileged user in same domain', 17965: unpriv => 'Information viewable by unprivileged user in same domain', 17966: instdom => 'Other domain shares institution/provider', 17967: extdom => 'Other domain has different institution/provider', 17968: none => 'Not allowed', 17969: user => 'User authorizes', 17970: domain => 'Domain Coordinator authorizes', 17971: auto => 'Unrestricted', 17972: ); 17973: my %fieldnames = &Apache::lonlocal::texthash ( 17974: id => 'Student/Employee ID', 17975: permanentemail => 'E-mail address', 17976: lastname => 'Last Name', 17977: firstname => 'First Name', 17978: middlename => 'Middle Name', 17979: generation => 'Generation', 17980: ); 17981: my ($othertitle,$usertypes,$types) = 17982: &Apache::loncommon::sorted_inst_types($dom); 17983: my (%by_ip,%by_location,@intdoms,@instdoms); 17984: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 17985: 17986: my %privacyhash = ( 17987: 'approval' => { 17988: instdom => {}, 17989: extdom => {}, 17990: }, 17991: 'othdom' => {}, 17992: 'priv' => {}, 17993: 'unpriv' => {}, 17994: ); 17995: foreach my $item (@items) { 17996: if (@instdoms > 1) { 17997: if ($env{'form.privacy_approval_instdom_'.$item} =~ /^(none|user|domain|auto)$/) { 17998: $privacyhash{'approval'}{'instdom'}{$item} = $env{'form.privacy_approval_instdom_'.$item}; 17999: } 18000: if (ref($current{'approval'}) eq 'HASH') { 18001: if (ref($current{'approval'}{'instdom'}) eq 'HASH') { 18002: unless ($privacyhash{'approval'}{'instdom'}{$item} eq $current{'approval'}{'instdom'}{$item}) { 18003: $changes{'approval'} = 1; 18004: } 18005: } 18006: } elsif ($privacyhash{'approval'}{'instdom'}{$item} ne 'auto') { 18007: $changes{'approval'} = 1; 18008: } 18009: } 18010: if (keys(%by_location) > 0) { 18011: if ($env{'form.privacy_approval_extdom_'.$item} =~ /^(none|user|domain|auto)$/) { 18012: $privacyhash{'approval'}{'extdom'}{$item} = $env{'form.privacy_approval_extdom_'.$item}; 18013: } 18014: if (ref($current{'approval'}) eq 'HASH') { 18015: if (ref($current{'approval'}{'extdom'}) eq 'HASH') { 18016: unless ($privacyhash{'approval'}{'extdom'}{$item} eq $current{'approval'}{'extdom'}{$item}) { 18017: $changes{'approval'} = 1; 18018: } 18019: } 18020: } elsif ($privacyhash{'approval'}{'extdom'}{$item} ne 'auto') { 18021: $changes{'approval'} = 1; 18022: } 18023: } 18024: foreach my $status ('priv','unpriv') { 18025: my @possibles = sort(&Apache::loncommon::get_env_multiple('form.privacy_'.$status.'_'.$item)); 18026: my @newvalues; 18027: foreach my $field (@possibles) { 18028: if (grep(/^\Q$field\E$/,@fields)) { 18029: $privacyhash{$status}{$item}{$field} = 1; 18030: push(@newvalues,$field); 18031: } 18032: } 18033: @newvalues = sort(@newvalues); 18034: if (ref($current{$status}) eq 'HASH') { 18035: if (ref($current{$status}{$item}) eq 'HASH') { 18036: my @currvalues = sort(keys(%{$current{$status}{$item}})); 18037: my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues); 18038: if (@diffs > 0) { 18039: $changes{$status} = 1; 18040: } 18041: } 18042: } else { 18043: my @stdfields; 18044: foreach my $field (@fields) { 18045: if ($field eq 'id') { 18046: next if ($status eq 'unpriv'); 18047: next if (($status eq 'priv') && ($item eq 'community')); 18048: } 18049: push(@stdfields,$field); 18050: } 18051: my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues); 18052: if (@diffs > 0) { 18053: $changes{$status} = 1; 18054: } 18055: } 18056: } 18057: } 18058: if ((@instdoms > 1) || (keys(%by_location) > 0)) { 18059: my @statuses; 18060: if (ref($types) eq 'ARRAY') { 18061: @statuses = @{$types}; 18062: } 18063: foreach my $type (@statuses,'default') { 18064: my @possfields = &Apache::loncommon::get_env_multiple('form.privacy_othdom_'.$type); 18065: my @newvalues; 18066: foreach my $field (sort(@possfields)) { 18067: if (grep(/^\Q$field\E$/,@fields)) { 18068: $privacyhash{'othdom'}{$type}{$field} = 1; 18069: push(@newvalues,$field); 18070: } 18071: } 18072: @newvalues = sort(@newvalues); 18073: if (ref($current{'othdom'}) eq 'HASH') { 18074: if (ref($current{'othdom'}{$type}) eq 'HASH') { 18075: my @currvalues = sort(keys(%{$current{'othdom'}{$type}})); 18076: my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues); 18077: if (@diffs > 0) { 18078: $changes{'othdom'} = 1; 18079: } 18080: } 18081: } else { 18082: my @stdfields = ('lastname','firstname','middlename','generation','permanentemail'); 18083: my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues); 18084: if (@diffs > 0) { 18085: $changes{'othdom'} = 1; 18086: } 18087: } 18088: } 18089: } 18090: my %confighash = ( 18091: privacy => \%privacyhash, 18092: ); 18093: my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom); 18094: if ($putresult eq 'ok') { 18095: if (keys(%changes) > 0) { 18096: $resulttext = &mt('Changes made: ').'<ul>'; 18097: foreach my $key ('approval','othdom','priv','unpriv') { 18098: if ($changes{$key}) { 18099: $resulttext .= '<li>'.$titles{$key}.':<ul>'; 18100: if ($key eq 'approval') { 18101: if (keys(%{$privacyhash{$key}{instdom}})) { 18102: $resulttext .= '<li>'.$titles{'instdom'}.'<ul>'; 18103: foreach my $item (@items) { 18104: $resulttext .= '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{instdom}{$item}}.'</li>'; 18105: } 18106: $resulttext .= '</ul></li>'; 18107: } 18108: if (keys(%{$privacyhash{$key}{extdom}})) { 18109: $resulttext .= '<li>'.$titles{'extdom'}.'<ul>'; 18110: foreach my $item (@items) { 18111: $resulttext .= '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{extdom}{$item}}.'</li>'; 18112: } 18113: $resulttext .= '</ul></li>'; 18114: } 18115: } elsif ($key eq 'othdom') { 18116: my @statuses; 18117: if (ref($types) eq 'ARRAY') { 18118: @statuses = @{$types}; 18119: } 18120: if (ref($privacyhash{$key}) eq 'HASH') { 18121: foreach my $status (@statuses,'default') { 18122: if ($status eq 'default') { 18123: $resulttext .= '<li>'.$othertitle.': '; 18124: } elsif (ref($usertypes) eq 'HASH') { 18125: $resulttext .= '<li>'.$usertypes->{$status}.': '; 18126: } else { 18127: next; 18128: } 18129: if (ref($privacyhash{$key}{$status}) eq 'HASH') { 18130: if (keys(%{$privacyhash{$key}{$status}})) { 18131: $resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$status}})))); 18132: } else { 18133: $resulttext .= &mt('none'); 18134: } 18135: } 18136: $resulttext .= '</li>'; 18137: } 18138: } 18139: } else { 18140: foreach my $item (@items) { 18141: if (ref($privacyhash{$key}{$item}) eq 'HASH') { 18142: $resulttext .= '<li>'.$names{$item}.': '; 18143: if (keys(%{$privacyhash{$key}{$item}})) { 18144: $resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$item}})))); 18145: } else { 18146: $resulttext .= &mt('none'); 18147: } 18148: $resulttext .= '</li>'; 18149: } 18150: } 18151: } 18152: $resulttext .= '</ul></li>'; 18153: } 18154: } 18155: } else { 18156: $resulttext = &mt('No changes made to user information settings'); 18157: } 18158: } else { 18159: $resulttext = '<span class="LC_error">'. 18160: &mt('An error occurred: [_1]',$putresult).'</span>'; 18161: } 18162: return $resulttext; 18163: } 18164: 18165: sub modify_passwords { 18166: my ($r,$dom,$confname,$lastactref,%domconfig) = @_; 18167: my ($resulttext,%current,%changes,%newvalues,@oktypes,$errors, 18168: $updatedefaults,$updateconf); 18169: my $customfn = 'resetpw.html'; 18170: if (ref($domconfig{'passwords'}) eq 'HASH') { 18171: %current = %{$domconfig{'passwords'}}; 18172: } 18173: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 18174: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 18175: if (ref($types) eq 'ARRAY') { 18176: @oktypes = @{$types}; 18177: } 18178: push(@oktypes,'default'); 18179: 18180: my %titles = &Apache::lonlocal::texthash ( 18181: intauth_cost => 'Encryption cost for bcrypt (positive integer)', 18182: intauth_check => 'Check bcrypt cost if authenticated', 18183: intauth_switch => 'Existing crypt-based switched to bcrypt on authentication', 18184: permanent => 'Permanent e-mail address', 18185: critical => 'Critical notification address', 18186: notify => 'Notification address', 18187: min => 'Minimum password length', 18188: max => 'Maximum password length', 18189: chars => 'Required characters', 18190: expire => 'Password expiration (days)', 18191: numsaved => 'Number of previous passwords to save', 18192: reset => 'Resetting Forgotten Password', 18193: intauth => 'Encryption of Stored Passwords (Internal Auth)', 18194: rules => 'Rules for LON-CAPA Passwords', 18195: crsownerchg => 'Course Owner Changing Student Passwords', 18196: username => 'Username', 18197: email => 'E-mail address', 18198: ); 18199: 18200: # 18201: # Retrieve current domain configuration for internal authentication from $domconfig{'defaults'}. 18202: # 18203: my (%curr_defaults,%save_defaults); 18204: if (ref($domconfig{'defaults'}) eq 'HASH') { 18205: foreach my $key (keys(%{$domconfig{'defaults'}})) { 18206: if ($key =~ /^intauth_(cost|check|switch)$/) { 18207: $curr_defaults{$key} = $domconfig{'defaults'}{$key}; 18208: } else { 18209: $save_defaults{$key} = $domconfig{'defaults'}{$key}; 18210: } 18211: } 18212: } 18213: my %staticdefaults = ( 18214: 'resetlink' => 2, 18215: 'resetcase' => \@oktypes, 18216: 'resetprelink' => 'both', 18217: 'resetemail' => ['critical','notify','permanent'], 18218: 'intauth_cost' => 10, 18219: 'intauth_check' => 0, 18220: 'intauth_switch' => 0, 18221: ); 18222: $staticdefaults{'min'} = $Apache::lonnet::passwdmin; 18223: foreach my $type (@oktypes) { 18224: $staticdefaults{'resetpostlink'}{$type} = ['email','username']; 18225: } 18226: my $linklife = $env{'form.passwords_link'}; 18227: $linklife =~ s/^\s+|\s+$//g; 18228: if (($linklife =~ /^\d+(|\.\d*)$/) && ($linklife > 0)) { 18229: $newvalues{'resetlink'} = $linklife; 18230: if ($current{'resetlink'}) { 18231: if ($current{'resetlink'} ne $linklife) { 18232: $changes{'reset'} = 1; 18233: } 18234: } elsif (!ref($domconfig{passwords}) eq 'HASH') { 18235: if ($staticdefaults{'resetlink'} ne $linklife) { 18236: $changes{'reset'} = 1; 18237: } 18238: } 18239: } elsif ($current{'resetlink'}) { 18240: $changes{'reset'} = 1; 18241: } 18242: my @casesens; 18243: my @posscase = &Apache::loncommon::get_env_multiple('form.passwords_case_sensitive'); 18244: foreach my $case (sort(@posscase)) { 18245: if (grep(/^\Q$case\E$/,@oktypes)) { 18246: push(@casesens,$case); 18247: } 18248: } 18249: $newvalues{'resetcase'} = \@casesens; 18250: if (ref($current{'resetcase'}) eq 'ARRAY') { 18251: my @diffs = &Apache::loncommon::compare_arrays($current{'resetcase'},\@casesens); 18252: if (@diffs > 0) { 18253: $changes{'reset'} = 1; 18254: } 18255: } elsif (!ref($domconfig{passwords}) eq 'HASH') { 18256: my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens); 18257: if (@diffs > 0) { 18258: $changes{'reset'} = 1; 18259: } 18260: } 18261: if ($env{'form.passwords_prelink'} =~ /^(both|either)$/) { 18262: $newvalues{'resetprelink'} = $env{'form.passwords_prelink'}; 18263: if (exists($current{'resetprelink'})) { 18264: if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) { 18265: $changes{'reset'} = 1; 18266: } 18267: } elsif (!ref($domconfig{passwords}) eq 'HASH') { 18268: if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) { 18269: $changes{'reset'} = 1; 18270: } 18271: } 18272: } elsif ($current{'resetprelink'}) { 18273: $changes{'reset'} = 1; 18274: } 18275: foreach my $type (@oktypes) { 18276: my @possplink = &Apache::loncommon::get_env_multiple('form.passwords_postlink_'.$type); 18277: my @postlink; 18278: foreach my $item (sort(@possplink)) { 18279: if ($item =~ /^(email|username)$/) { 18280: push(@postlink,$item); 18281: } 18282: } 18283: $newvalues{'resetpostlink'}{$type} = \@postlink; 18284: unless ($changes{'reset'}) { 18285: if (ref($current{'resetpostlink'}) eq 'HASH') { 18286: if (ref($current{'resetpostlink'}{$type}) eq 'ARRAY') { 18287: my @diffs = &Apache::loncommon::compare_arrays($current{'resetpostlink'}{$type},\@postlink); 18288: if (@diffs > 0) { 18289: $changes{'reset'} = 1; 18290: } 18291: } else { 18292: $changes{'reset'} = 1; 18293: } 18294: } elsif (!ref($domconfig{passwords}) eq 'HASH') { 18295: my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink); 18296: if (@diffs > 0) { 18297: $changes{'reset'} = 1; 18298: } 18299: } 18300: } 18301: } 18302: my @possemailsrc = &Apache::loncommon::get_env_multiple('form.passwords_emailsrc'); 18303: my @resetemail; 18304: foreach my $item (sort(@possemailsrc)) { 18305: if ($item =~ /^(permanent|critical|notify)$/) { 18306: push(@resetemail,$item); 18307: } 18308: } 18309: $newvalues{'resetemail'} = \@resetemail; 18310: unless ($changes{'reset'}) { 18311: if (ref($current{'resetemail'}) eq 'ARRAY') { 18312: my @diffs = &Apache::loncommon::compare_arrays($current{'resetemail'},\@resetemail); 18313: if (@diffs > 0) { 18314: $changes{'reset'} = 1; 18315: } 18316: } elsif (!ref($domconfig{passwords}) eq 'HASH') { 18317: my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail); 18318: if (@diffs > 0) { 18319: $changes{'reset'} = 1; 18320: } 18321: } 18322: } 18323: if ($env{'form.passwords_stdtext'} == 0) { 18324: $newvalues{'resetremove'} = 1; 18325: unless ($current{'resetremove'}) { 18326: $changes{'reset'} = 1; 18327: } 18328: } elsif ($current{'resetremove'}) { 18329: $changes{'reset'} = 1; 18330: } 18331: if ($env{'form.passwords_customfile.filename'} ne '') { 18332: my $servadm = $r->dir_config('lonAdmEMail'); 18333: my ($configuserok,$author_ok,$switchserver) = 18334: &config_check($dom,$confname,$servadm); 18335: my $error; 18336: if ($configuserok eq 'ok') { 18337: if ($switchserver) { 18338: $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver); 18339: } else { 18340: if ($author_ok eq 'ok') { 18341: my ($result,$customurl) = 18342: &publishlogo($r,'upload','passwords_customfile',$dom, 18343: $confname,'customtext/resetpw','','',$customfn); 18344: if ($result eq 'ok') { 18345: $newvalues{'resetcustom'} = $customurl; 18346: $changes{'reset'} = 1; 18347: } else { 18348: $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result); 18349: } 18350: } else { 18351: $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); 18352: } 18353: } 18354: } else { 18355: $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); 18356: } 18357: if ($error) { 18358: &Apache::lonnet::logthis($error); 18359: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 18360: } 18361: } elsif ($current{'resetcustom'}) { 18362: if ($env{'form.passwords_custom_del'}) { 18363: $changes{'reset'} = 1; 18364: } else { 18365: $newvalues{'resetcustom'} = $current{'resetcustom'}; 18366: } 18367: } 18368: $env{'form.intauth_cost'} =~ s/^\s+|\s+$//g; 18369: if (($env{'form.intauth_cost'} ne '') && ($env{'form.intauth_cost'} =~ /^\d+$/)) { 18370: $save_defaults{'intauth_cost'} = $env{'form.intauth_cost'}; 18371: if ($save_defaults{'intauth_cost'} ne $curr_defaults{'intauth_cost'}) { 18372: $changes{'intauth'} = 1; 18373: } 18374: } else { 18375: $save_defaults{'intauth_cost'} = $curr_defaults{'intauth_cost'}; 18376: } 18377: if ($env{'form.intauth_check'} =~ /^(0|1|2)$/) { 18378: $save_defaults{'intauth_check'} = $env{'form.intauth_check'}; 18379: if ($save_defaults{'intauth_check'} ne $curr_defaults{'intauth_check'}) { 18380: $changes{'intauth'} = 1; 18381: } 18382: } else { 18383: $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'}; 18384: } 18385: if ($env{'form.intauth_switch'} =~ /^(0|1|2)$/) { 18386: $save_defaults{'intauth_switch'} = $env{'form.intauth_switch'}; 18387: if ($save_defaults{'intauth_switch'} ne $curr_defaults{'intauth_switch'}) { 18388: $changes{'intauth'} = 1; 18389: } 18390: } else { 18391: $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'}; 18392: } 18393: foreach my $item ('cost','check','switch') { 18394: if ($save_defaults{'intauth_'.$item} ne $domdefaults{'intauth_'.$item}) { 18395: $domdefaults{'intauth_'.$item} = $save_defaults{'intauth_'.$item}; 18396: $updatedefaults = 1; 18397: } 18398: } 18399: &password_rule_changes('passwords',\%newvalues,\%current,\%changes); 18400: my %crsownerchg = ( 18401: by => [], 18402: for => [], 18403: ); 18404: foreach my $item ('by','for') { 18405: my @posstypes = &Apache::loncommon::get_env_multiple('form.passwords_crsowner_'.$item); 18406: foreach my $type (sort(@posstypes)) { 18407: if (grep(/^\Q$type\E$/,@oktypes)) { 18408: push(@{$crsownerchg{$item}},$type); 18409: } 18410: } 18411: } 18412: $newvalues{'crsownerchg'} = \%crsownerchg; 18413: if (ref($current{'crsownerchg'}) eq 'HASH') { 18414: foreach my $item ('by','for') { 18415: if (ref($current{'crsownerchg'}{$item}) eq 'ARRAY') { 18416: my @diffs = &Apache::loncommon::compare_arrays($current{'crsownerchg'}{$item},$crsownerchg{$item}); 18417: if (@diffs > 0) { 18418: $changes{'crsownerchg'} = 1; 18419: last; 18420: } 18421: } 18422: } 18423: } elsif (!(ref($domconfig{passwords}) eq 'HASH')) { 18424: foreach my $item ('by','for') { 18425: if (@{$crsownerchg{$item}} > 0) { 18426: $changes{'crsownerchg'} = 1; 18427: last; 18428: } 18429: } 18430: } 18431: 18432: my %confighash = ( 18433: defaults => \%save_defaults, 18434: passwords => \%newvalues, 18435: ); 18436: &process_captcha('passwords',\%changes,$confighash{'passwords'},$domconfig{'passwords'}); 18437: 18438: my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom); 18439: if ($putresult eq 'ok') { 18440: if (keys(%changes) > 0) { 18441: $resulttext = &mt('Changes made: ').'<ul>'; 18442: foreach my $key ('reset','intauth','rules','crsownerchg') { 18443: if ($changes{$key}) { 18444: unless ($key eq 'intauth') { 18445: $updateconf = 1; 18446: } 18447: $resulttext .= '<li>'.$titles{$key}.':<ul>'; 18448: if ($key eq 'reset') { 18449: if ($confighash{'passwords'}{'captcha'} eq 'original') { 18450: $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: original CAPTCHA').'</li>'; 18451: } elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') { 18452: $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: reCAPTCHA').' '. 18453: &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'<br />'; 18454: if (ref($confighash{'passwords'}{'recaptchakeys'}) eq 'HASH') { 18455: $resulttext .= &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'public'}).'</br>'. 18456: &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchakeys'}{'private'}).'</li>'; 18457: } 18458: } else { 18459: $resulttext .= '<li>'.&mt('No CAPTCHA validation').'</li>'; 18460: } 18461: if ($confighash{'passwords'}{'resetlink'}) { 18462: $resulttext .= '<li>'.&mt('Reset link expiration set to [quant,_1,hour]',$confighash{'passwords'}{'resetlink'}).'</li>'; 18463: } else { 18464: $resulttext .= '<li>'.&mt('No reset link expiration set.').' '. 18465: &mt('Will default to 2 hours').'</li>'; 18466: } 18467: if (ref($confighash{'passwords'}{'resetcase'}) eq 'ARRAY') { 18468: if (@{$confighash{'passwords'}{'resetcase'}} == 0) { 18469: $resulttext .= '<li>'.&mt('User input for username and/or e-mail address not case sensitive for "Forgot Password" web form').'</li>'; 18470: } else { 18471: my $casesens; 18472: foreach my $type (@{$confighash{'passwords'}{'resetcase'}}) { 18473: if ($type eq 'default') { 18474: $casesens .= $othertitle.', '; 18475: } elsif ($usertypes->{$type} ne '') { 18476: $casesens .= $usertypes->{$type}.', '; 18477: } 18478: } 18479: $casesens =~ s/\Q, \E$//; 18480: $resulttext .= '<li>'.&mt('"Forgot Password" web form input for username and/or e-mail address is case-sensitive for: [_1]',$casesens).'</li>'; 18481: } 18482: } else { 18483: $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>'; 18484: } 18485: if ($confighash{'passwords'}{'resetprelink'} eq 'either') { 18486: $resulttext .= '<li>'.&mt('Users can enter either a username or an e-mail address in "Forgot Password" web form').'</li>'; 18487: } else { 18488: $resulttext .= '<li>'.&mt('Users can enter both a username and an e-mail address in "Forgot Password" web form').'</li>'; 18489: } 18490: if (ref($confighash{'passwords'}{'resetpostlink'}) eq 'HASH') { 18491: my $output; 18492: if (ref($types) eq 'ARRAY') { 18493: foreach my $type (@{$types}) { 18494: if (ref($confighash{'passwords'}{'resetpostlink'}{$type}) eq 'ARRAY') { 18495: if (@{$confighash{'passwords'}{'resetpostlink'}{$type}} == 0) { 18496: $output .= $usertypes->{$type}.' -- '.&mt('none'); 18497: } else { 18498: $output .= $usertypes->{$type}.' -- '. 18499: join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{$type}})).'; '; 18500: } 18501: } 18502: } 18503: } 18504: if (ref($confighash{'passwords'}{'resetpostlink'}{'default'}) eq 'ARRAY') { 18505: if (@{$confighash{'passwords'}{'resetpostlink'}{'default'}} == 0) { 18506: $output .= $othertitle.' -- '.&mt('none'); 18507: } else { 18508: $output .= $othertitle.' -- '. 18509: join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{'default'}})); 18510: } 18511: } 18512: if ($output) { 18513: $resulttext .= '<li>'.&mt('Information required for new password form (by user type) set to: [_1]',$output).'</li>'; 18514: } else { 18515: $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>'; 18516: } 18517: } else { 18518: $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>'; 18519: } 18520: if (ref($confighash{'passwords'}{'resetemail'}) eq 'ARRAY') { 18521: if (@{$confighash{'passwords'}{'resetemail'}} > 0) { 18522: $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$confighash{'passwords'}{'resetemail'}})).'</li>'; 18523: } else { 18524: $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>'; 18525: } 18526: } else { 18527: $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>'; 18528: } 18529: if ($confighash{'passwords'}{'resetremove'}) { 18530: $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>'; 18531: } else { 18532: $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form is shown').'</li>'; 18533: } 18534: if ($confighash{'passwords'}{'resetcustom'}) { 18535: my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'}, 18536: &mt('custom text'),600,500,undef,undef, 18537: undef,undef,'background-color:#ffffff'); 18538: $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" form includes: [_1]',$customlink).'</li>'; 18539: } else { 18540: $resulttext .= '<li>'.&mt('No custom text included in preamble to "Forgot Password" form').'</li>'; 18541: } 18542: } elsif ($key eq 'intauth') { 18543: foreach my $item ('cost','switch','check') { 18544: my $value = $save_defaults{$key.'_'.$item}; 18545: if ($item eq 'switch') { 18546: my %optiondesc = &Apache::lonlocal::texthash ( 18547: 0 => 'No', 18548: 1 => 'Yes', 18549: 2 => 'Yes, and copy existing passwd file to passwd.bak file', 18550: ); 18551: if ($value =~ /^(0|1|2)$/) { 18552: $value = $optiondesc{$value}; 18553: } else { 18554: $value = &mt('none -- defaults to No'); 18555: } 18556: } elsif ($item eq 'check') { 18557: my %optiondesc = &Apache::lonlocal::texthash ( 18558: 0 => 'No', 18559: 1 => 'Yes, allow login then update passwd file using default cost (if higher)', 18560: 2 => 'Yes, disallow login if stored cost is less than domain default', 18561: ); 18562: if ($value =~ /^(0|1|2)$/) { 18563: $value = $optiondesc{$value}; 18564: } else { 18565: $value = &mt('none -- defaults to No'); 18566: } 18567: } 18568: $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>'; 18569: } 18570: } elsif ($key eq 'rules') { 18571: foreach my $rule ('min','max','expire','numsaved') { 18572: if ($confighash{'passwords'}{$rule} eq '') { 18573: if ($rule eq 'min') { 18574: $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule}); 18575: ' '.&mt('Default of [_1] will be used', 18576: $Apache::lonnet::passwdmin).'</li>'; 18577: } else { 18578: $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>'; 18579: } 18580: } else { 18581: $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>'; 18582: } 18583: } 18584: if (ref($confighash{'passwords'}{'chars'}) eq 'ARRAY') { 18585: if (@{$confighash{'passwords'}{'chars'}} > 0) { 18586: my %rulenames = &Apache::lonlocal::texthash( 18587: uc => 'At least one upper case letter', 18588: lc => 'At least one lower case letter', 18589: num => 'At least one number', 18590: spec => 'At least one non-alphanumeric', 18591: ); 18592: my $needed = '<ul><li>'. 18593: join('</li><li>',map {$rulenames{$_} } @{$confighash{'passwords'}{'chars'}}). 18594: '</li></ul>'; 18595: $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'</li>'; 18596: } else { 18597: $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>'; 18598: } 18599: } else { 18600: $resulttext .= '<li>'.&mt('[_1] set to none',$titles{'chars'}).'</li>'; 18601: } 18602: } elsif ($key eq 'crsownerchg') { 18603: if (ref($confighash{'passwords'}{'crsownerchg'}) eq 'HASH') { 18604: if ((@{$confighash{'passwords'}{'crsownerchg'}{'by'}} == 0) || 18605: (@{$confighash{'passwords'}{'crsownerchg'}{'for'}} == 0)) { 18606: $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>'; 18607: } else { 18608: my %crsownerstr; 18609: foreach my $item ('by','for') { 18610: if (ref($confighash{'passwords'}{'crsownerchg'}{$item}) eq 'ARRAY') { 18611: foreach my $type (@{$confighash{'passwords'}{'crsownerchg'}{$item}}) { 18612: if ($type eq 'default') { 18613: $crsownerstr{$item} .= $othertitle.', '; 18614: } elsif ($usertypes->{$type} ne '') { 18615: $crsownerstr{$item} .= $usertypes->{$type}.', '; 18616: } 18617: } 18618: $crsownerstr{$item} =~ s/\Q, \E$//; 18619: } 18620: } 18621: $resulttext .= '<li>'.&mt('Course owner (with status: [_1]) may change passwords for students (with status: [_2]).', 18622: $crsownerstr{'by'},$crsownerstr{'for'}).'</li>'; 18623: } 18624: } else { 18625: $resulttext .= '<li>'.&mt('Course owner may not change student passwords.').'</li>'; 18626: } 18627: } 18628: $resulttext .= '</ul></li>'; 18629: } 18630: } 18631: $resulttext .= '</ul>'; 18632: } else { 18633: $resulttext = &mt('No changes made to password settings'); 18634: } 18635: my $cachetime = 24*60*60; 18636: if ($updatedefaults) { 18637: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 18638: if (ref($lastactref) eq 'HASH') { 18639: $lastactref->{'domdefaults'} = 1; 18640: } 18641: } 18642: if ($updateconf) { 18643: &Apache::lonnet::do_cache_new('passwdconf',$dom,$confighash{'passwords'},$cachetime); 18644: if (ref($lastactref) eq 'HASH') { 18645: $lastactref->{'passwdconf'} = 1; 18646: } 18647: } 18648: } else { 18649: $resulttext = '<span class="LC_error">'. 18650: &mt('An error occurred: [_1]',$putresult).'</span>'; 18651: } 18652: if ($errors) { 18653: $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'. 18654: $errors.'</ul></p>'; 18655: } 18656: return $resulttext; 18657: } 18658: 18659: sub password_rule_changes { 18660: my ($prefix,$newvalues,$current,$changes) = @_; 18661: return unless ((ref($newvalues) eq 'HASH') && 18662: (ref($current) eq 'HASH') && 18663: (ref($changes) eq 'HASH')); 18664: my (@rules,%staticdefaults); 18665: if ($prefix eq 'passwords') { 18666: @rules = ('min','max','expire','numsaved'); 18667: } elsif ($prefix eq 'secrets') { 18668: @rules = ('min','max'); 18669: } 18670: $staticdefaults{'min'} = $Apache::lonnet::passwdmin; 18671: foreach my $rule (@rules) { 18672: $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g; 18673: my $ruleok; 18674: if ($rule eq 'expire') { 18675: if (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+(|\.\d*)$/) && 18676: ($env{'form.'.$prefix.'_'.$rule} ne '0')) { 18677: $ruleok = 1; 18678: } 18679: } elsif ($rule eq 'min') { 18680: if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) { 18681: if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) { 18682: $ruleok = 1; 18683: } 18684: } 18685: } elsif (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) && 18686: ($env{'form.'.$prefix.'_'.$rule} ne '0')) { 18687: $ruleok = 1; 18688: } 18689: if ($ruleok) { 18690: $newvalues->{$rule} = $env{'form.'.$prefix.'_'.$rule}; 18691: if (exists($current->{$rule})) { 18692: if ($newvalues->{$rule} ne $current->{$rule}) { 18693: $changes->{'rules'} = 1; 18694: } 18695: } elsif ($rule eq 'min') { 18696: if ($staticdefaults{$rule} ne $newvalues->{$rule}) { 18697: $changes->{'rules'} = 1; 18698: } 18699: } else { 18700: $changes->{'rules'} = 1; 18701: } 18702: } elsif (exists($current->{$rule})) { 18703: $changes->{'rules'} = 1; 18704: } 18705: } 18706: my @posschars = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_chars'); 18707: my @chars; 18708: foreach my $item (sort(@posschars)) { 18709: if ($item =~ /^(uc|lc|num|spec)$/) { 18710: push(@chars,$item); 18711: } 18712: } 18713: $newvalues->{'chars'} = \@chars; 18714: unless ($changes->{'rules'}) { 18715: if (ref($current->{'chars'}) eq 'ARRAY') { 18716: my @diffs = &Apache::loncommon::compare_arrays($current->{'chars'},\@chars); 18717: if (@diffs > 0) { 18718: $changes->{'rules'} = 1; 18719: } 18720: } else { 18721: if (@chars > 0) { 18722: $changes->{'rules'} = 1; 18723: } 18724: } 18725: } 18726: return; 18727: } 18728: 18729: sub modify_usercreation { 18730: my ($dom,%domconfig) = @_; 18731: my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate); 18732: my $warningmsg; 18733: if (ref($domconfig{'usercreation'}) eq 'HASH') { 18734: foreach my $key (keys(%{$domconfig{'usercreation'}})) { 18735: if ($key eq 'cancreate') { 18736: if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') { 18737: foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) { 18738: if (($item eq 'requestcrs') || ($item eq 'course') || ($item eq 'author')) { 18739: $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; 18740: } else { 18741: $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; 18742: } 18743: } 18744: } 18745: } elsif ($key eq 'email_rule') { 18746: $save_usercreate{$key} = $domconfig{'usercreation'}{$key}; 18747: } else { 18748: $curr_usercreation{$key} = $domconfig{'usercreation'}{$key}; 18749: } 18750: } 18751: } 18752: my @username_rule = &Apache::loncommon::get_env_multiple('form.username_rule'); 18753: my @id_rule = &Apache::loncommon::get_env_multiple('form.id_rule'); 18754: my @contexts = ('author','course','requestcrs'); 18755: foreach my $item(@contexts) { 18756: $cancreate{$item} = $env{'form.can_createuser_'.$item}; 18757: } 18758: if (ref($curr_usercreation{'cancreate'}) eq 'HASH') { 18759: foreach my $item (@contexts) { 18760: if ($curr_usercreation{'cancreate'}{$item} ne $cancreate{$item}) { 18761: push(@{$changes{'cancreate'}},$item); 18762: } 18763: } 18764: } elsif (ref($curr_usercreation{'cancreate'}) eq 'ARRAY') { 18765: foreach my $item (@contexts) { 18766: if (!grep(/^\Q$item\E$/,@{$curr_usercreation{'cancreate'}})) { 18767: if ($cancreate{$item} ne 'any') { 18768: push(@{$changes{'cancreate'}},$item); 18769: } 18770: } else { 18771: if ($cancreate{$item} ne 'none') { 18772: push(@{$changes{'cancreate'}},$item); 18773: } 18774: } 18775: } 18776: } else { 18777: foreach my $item (@contexts) { 18778: push(@{$changes{'cancreate'}},$item); 18779: } 18780: } 18781: 18782: if (ref($curr_usercreation{'username_rule'}) eq 'ARRAY') { 18783: foreach my $type (@{$curr_usercreation{'username_rule'}}) { 18784: if (!grep(/^\Q$type\E$/,@username_rule)) { 18785: push(@{$changes{'username_rule'}},$type); 18786: } 18787: } 18788: foreach my $type (@username_rule) { 18789: if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'username_rule'}})) { 18790: push(@{$changes{'username_rule'}},$type); 18791: } 18792: } 18793: } else { 18794: push(@{$changes{'username_rule'}},@username_rule); 18795: } 18796: 18797: if (ref($curr_usercreation{'id_rule'}) eq 'ARRAY') { 18798: foreach my $type (@{$curr_usercreation{'id_rule'}}) { 18799: if (!grep(/^\Q$type\E$/,@id_rule)) { 18800: push(@{$changes{'id_rule'}},$type); 18801: } 18802: } 18803: foreach my $type (@id_rule) { 18804: if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'id_rule'}})) { 18805: push(@{$changes{'id_rule'}},$type); 18806: } 18807: } 18808: } else { 18809: push(@{$changes{'id_rule'}},@id_rule); 18810: } 18811: 18812: my @authen_contexts = ('author','course','domain'); 18813: my @authtypes = ('int','krb4','krb5','loc','lti'); 18814: my %authhash; 18815: foreach my $item (@authen_contexts) { 18816: my @authallowed = &Apache::loncommon::get_env_multiple('form.'.$item.'_auth'); 18817: foreach my $auth (@authtypes) { 18818: if (grep(/^\Q$auth\E$/,@authallowed)) { 18819: $authhash{$item}{$auth} = 1; 18820: } else { 18821: $authhash{$item}{$auth} = 0; 18822: } 18823: } 18824: } 18825: if (ref($curr_usercreation{'authtypes'}) eq 'HASH') { 18826: foreach my $item (@authen_contexts) { 18827: if (ref($curr_usercreation{'authtypes'}{$item}) eq 'HASH') { 18828: foreach my $auth (@authtypes) { 18829: if ($authhash{$item}{$auth} ne $curr_usercreation{'authtypes'}{$item}{$auth}) { 18830: push(@{$changes{'authtypes'}},$item); 18831: last; 18832: } 18833: } 18834: } 18835: } 18836: } else { 18837: foreach my $item (@authen_contexts) { 18838: push(@{$changes{'authtypes'}},$item); 18839: } 18840: } 18841: 18842: $save_usercreate{'cancreate'}{'course'} = $cancreate{'course'}; 18843: $save_usercreate{'cancreate'}{'author'} = $cancreate{'author'}; 18844: $save_usercreate{'cancreate'}{'requestcrs'} = $cancreate{'requestcrs'}; 18845: $save_usercreate{'id_rule'} = \@id_rule; 18846: $save_usercreate{'username_rule'} = \@username_rule, 18847: $save_usercreate{'authtypes'} = \%authhash; 18848: 18849: my %usercreation_hash = ( 18850: usercreation => \%save_usercreate, 18851: ); 18852: 18853: my $putresult = &Apache::lonnet::put_dom('configuration',\%usercreation_hash, 18854: $dom); 18855: 18856: if ($putresult eq 'ok') { 18857: if (keys(%changes) > 0) { 18858: $resulttext = &mt('Changes made:').'<ul>'; 18859: if (ref($changes{'cancreate'}) eq 'ARRAY') { 18860: my %lt = &usercreation_types(); 18861: foreach my $type (@{$changes{'cancreate'}}) { 18862: my $chgtext = $lt{$type}.', '; 18863: if ($cancreate{$type} eq 'none') { 18864: $chgtext .= &mt('creation of new users is not permitted, except by a Domain Coordinator.'); 18865: } elsif ($cancreate{$type} eq 'any') { 18866: $chgtext .= &mt('creation of new users is permitted for both institutional and non-institutional usernames.'); 18867: } elsif ($cancreate{$type} eq 'official') { 18868: $chgtext .= &mt('creation of new users is only permitted for institutional usernames.'); 18869: } elsif ($cancreate{$type} eq 'unofficial') { 18870: $chgtext .= &mt('creation of new users is only permitted for non-institutional usernames.'); 18871: } 18872: $resulttext .= '<li>'.$chgtext.'</li>'; 18873: } 18874: } 18875: if (ref($changes{'username_rule'}) eq 'ARRAY') { 18876: my ($rules,$ruleorder) = 18877: &Apache::lonnet::inst_userrules($dom,'username'); 18878: my $chgtext = '<ul>'; 18879: foreach my $type (@username_rule) { 18880: if (ref($rules->{$type}) eq 'HASH') { 18881: $chgtext .= '<li>'.$rules->{$type}{'name'}.'</li>'; 18882: } 18883: } 18884: $chgtext .= '</ul>'; 18885: if (@username_rule > 0) { 18886: $resulttext .= '<li>'.&mt('Usernames with the following formats are restricted to verified users in the institutional directory: ').$chgtext.'</li>'; 18887: } else { 18888: $resulttext .= '<li>'.&mt('There are now no username formats restricted to verified users in the institutional directory.').'</li>'; 18889: } 18890: } 18891: if (ref($changes{'id_rule'}) eq 'ARRAY') { 18892: my ($idrules,$idruleorder) = 18893: &Apache::lonnet::inst_userrules($dom,'id'); 18894: my $chgtext = '<ul>'; 18895: foreach my $type (@id_rule) { 18896: if (ref($idrules->{$type}) eq 'HASH') { 18897: $chgtext .= '<li>'.$idrules->{$type}{'name'}.'</li>'; 18898: } 18899: } 18900: $chgtext .= '</ul>'; 18901: if (@id_rule > 0) { 18902: $resulttext .= '<li>'.&mt('IDs with the following formats are restricted to verified users in the institutional directory: ').$chgtext.'</li>'; 18903: } else { 18904: $resulttext .= '<li>'.&mt('There are now no ID formats restricted to verified users in the institutional directory.').'</li>'; 18905: } 18906: } 18907: my %authname = &authtype_names(); 18908: my %context_title = &context_names(); 18909: if (ref($changes{'authtypes'}) eq 'ARRAY') { 18910: my $chgtext = '<ul>'; 18911: foreach my $type (@{$changes{'authtypes'}}) { 18912: my @allowed; 18913: $chgtext .= '<li><span class="LC_cusr_emph">'.$context_title{$type}.'</span> - '.&mt('assignable authentication types: '); 18914: foreach my $auth (@authtypes) { 18915: if ($authhash{$type}{$auth}) { 18916: push(@allowed,$authname{$auth}); 18917: } 18918: } 18919: if (@allowed > 0) { 18920: $chgtext .= join(', ',@allowed).'</li>'; 18921: } else { 18922: $chgtext .= &mt('none').'</li>'; 18923: } 18924: } 18925: $chgtext .= '</ul>'; 18926: $resulttext .= '<li>'.&mt('Authentication types available for assignment to new users').'<br />'.$chgtext; 18927: $resulttext .= '</li>'; 18928: } 18929: $resulttext .= '</ul>'; 18930: } else { 18931: $resulttext = &mt('No changes made to user creation settings'); 18932: } 18933: } else { 18934: $resulttext = '<span class="LC_error">'. 18935: &mt('An error occurred: [_1]',$putresult).'</span>'; 18936: } 18937: if ($warningmsg ne '') { 18938: $resulttext .= '<br /><span class="LC_warning">'.$warningmsg.'</span><br />'; 18939: } 18940: return $resulttext; 18941: } 18942: 18943: sub modify_selfcreation { 18944: my ($dom,$lastactref,%domconfig) = @_; 18945: my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%curr_inststatus,%changes,%cancreate); 18946: my (%save_usercreate,%save_usermodify,%save_inststatus,@types,%usertypes); 18947: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 18948: my ($othertitle,$usertypesref,$typesref) = &Apache::loncommon::sorted_inst_types($dom); 18949: if (ref($typesref) eq 'ARRAY') { 18950: @types = @{$typesref}; 18951: } 18952: if (ref($usertypesref) eq 'HASH') { 18953: %usertypes = %{$usertypesref}; 18954: } 18955: $usertypes{'default'} = $othertitle; 18956: # 18957: # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}. 18958: # 18959: if (ref($domconfig{'usercreation'}) eq 'HASH') { 18960: foreach my $key (keys(%{$domconfig{'usercreation'}})) { 18961: if ($key eq 'cancreate') { 18962: if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') { 18963: foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) { 18964: if (($item eq 'selfcreate') || ($item eq 'statustocreate') || 18965: ($item eq 'captcha') || ($item eq 'recaptchakeys') || 18966: ($item eq 'recaptchaversion') || ($item eq 'notify') || 18967: ($item eq 'emailusername') || ($item eq 'shibenv') || 18968: ($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || 18969: ($item eq 'emailoptions') || ($item eq 'emaildomain')) { 18970: $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; 18971: } else { 18972: $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; 18973: } 18974: } 18975: } 18976: } elsif ($key eq 'email_rule') { 18977: $curr_usercreation{$key} = $domconfig{'usercreation'}{$key}; 18978: } else { 18979: $save_usercreate{$key} = $domconfig{'usercreation'}{$key}; 18980: } 18981: } 18982: } 18983: # 18984: # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usermodification'}. 18985: # 18986: if (ref($domconfig{'usermodification'}) eq 'HASH') { 18987: foreach my $key (keys(%{$domconfig{'usermodification'}})) { 18988: if ($key eq 'selfcreate') { 18989: $curr_usermodify{$key} = $domconfig{'usermodification'}{$key}; 18990: } else { 18991: $save_usermodify{$key} = $domconfig{'usermodification'}{$key}; 18992: } 18993: } 18994: } 18995: # 18996: # Retrieve current domain configuration for institutional status types from $domconfig{'inststatus'}. 18997: # 18998: if (ref($domconfig{'inststatus'}) eq 'HASH') { 18999: foreach my $key (keys(%{$domconfig{'inststatus'}})) { 19000: if ($key eq 'inststatusguest') { 19001: $curr_inststatus{$key} = $domconfig{'inststatus'}{$key}; 19002: } else { 19003: $save_inststatus{$key} = $domconfig{'inststatus'}{$key}; 19004: } 19005: } 19006: } 19007: 19008: my @contexts = ('selfcreate'); 19009: @{$cancreate{'selfcreate'}} = (); 19010: %{$cancreate{'emailusername'}} = (); 19011: if (@types) { 19012: @{$cancreate{'statustocreate'}} = (); 19013: } 19014: %{$cancreate{'selfcreateprocessing'}} = (); 19015: %{$cancreate{'shibenv'}} = (); 19016: %{$cancreate{'emailverified'}} = (); 19017: %{$cancreate{'emailoptions'}} = (); 19018: %{$cancreate{'emaildomain'}} = (); 19019: my %selfcreatetypes = ( 19020: sso => 'users authenticated by institutional single sign on', 19021: login => 'users authenticated by institutional log-in', 19022: email => 'users verified by e-mail', 19023: ); 19024: # 19025: # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts 19026: # is permitted. 19027: # 19028: my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email'); 19029: 19030: my (@statuses,%email_rule); 19031: foreach my $item ('login','sso','email') { 19032: if ($item eq 'email') { 19033: if ($env{'form.cancreate_email'}) { 19034: if (@types) { 19035: my @poss_statuses = &Apache::loncommon::get_env_multiple('form.selfassign'); 19036: foreach my $status (@poss_statuses) { 19037: if (grep(/^\Q$status\E$/,(@types,'default'))) { 19038: push(@statuses,$status); 19039: } 19040: } 19041: $save_inststatus{'inststatusguest'} = \@statuses; 19042: } else { 19043: push(@statuses,'default'); 19044: } 19045: if (@statuses) { 19046: my %curr_rule; 19047: if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') { 19048: foreach my $type (@statuses) { 19049: $curr_rule{$type} = $curr_usercreation{'email_rule'}; 19050: } 19051: } elsif (ref($curr_usercreation{'email_rule'}) eq 'HASH') { 19052: foreach my $type (@statuses) { 19053: $curr_rule{$type} = $curr_usercreation{'email_rule'}{$type}; 19054: } 19055: } 19056: push(@{$cancreate{'selfcreate'}},'email'); 19057: push(@contexts,('selfcreateprocessing','emailverified','emailoptions')); 19058: my %curremaildom; 19059: if (ref($curr_usercreation{'cancreate'}{'emaildomain'}) eq 'HASH') { 19060: %curremaildom = %{$curr_usercreation{'cancreate'}{'emaildomain'}}; 19061: } 19062: foreach my $type (@statuses) { 19063: if ($env{'form.cancreate_emailprocess_'.$type} =~ /^(?:approval|automatic)$/) { 19064: $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type}; 19065: } 19066: if ($env{'form.cancreate_usernameoptions_'.$type} =~ /^(?:all|first|free)$/) { 19067: $cancreate{'emailverified'}{$type} = $env{'form.cancreate_usernameoptions_'.$type}; 19068: } 19069: if ($env{'form.cancreate_emailoptions_'.$type} =~ /^(any|inst|noninst|custom)$/) { 19070: # 19071: # Retrieve rules (if any) governing types of e-mail address which may be used to verify a username. 19072: # 19073: my $chosen = $1; 19074: if (($chosen eq 'inst') || ($chosen eq 'noninst')) { 19075: my $emaildom; 19076: if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) { 19077: $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; 19078: $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom; 19079: if (ref($curremaildom{$type}) eq 'HASH') { 19080: if (exists($curremaildom{$type}{$chosen})) { 19081: if ($curremaildom{$type}{$chosen} ne $emaildom) { 19082: push(@{$changes{'cancreate'}},'emaildomain'); 19083: } 19084: } elsif ($emaildom ne '') { 19085: push(@{$changes{'cancreate'}},'emaildomain'); 19086: } 19087: } elsif ($emaildom ne '') { 19088: push(@{$changes{'cancreate'}},'emaildomain'); 19089: } 19090: } 19091: $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type}; 19092: } elsif ($chosen eq 'custom') { 19093: my @possemail_rules = &Apache::loncommon::get_env_multiple('form.email_rule_'.$type); 19094: $email_rule{$type} = []; 19095: if (ref($emailrules) eq 'HASH') { 19096: foreach my $rule (@possemail_rules) { 19097: if (exists($emailrules->{$rule})) { 19098: push(@{$email_rule{$type}},$rule); 19099: } 19100: } 19101: } 19102: if (@{$email_rule{$type}}) { 19103: $cancreate{'emailoptions'}{$type} = 'custom'; 19104: if (ref($curr_rule{$type}) eq 'ARRAY') { 19105: if (@{$curr_rule{$type}} > 0) { 19106: foreach my $rule (@{$curr_rule{$type}}) { 19107: if (!grep(/^\Q$rule\E$/,@{$email_rule{$type}})) { 19108: push(@{$changes{'email_rule'}},$type); 19109: } 19110: } 19111: } 19112: foreach my $type (@{$email_rule{$type}}) { 19113: if (!grep(/^\Q$type\E$/,@{$curr_rule{$type}})) { 19114: push(@{$changes{'email_rule'}},$type); 19115: } 19116: } 19117: } else { 19118: push(@{$changes{'email_rule'}},$type); 19119: } 19120: } 19121: } else { 19122: $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type}; 19123: } 19124: } 19125: } 19126: if (@types) { 19127: if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') { 19128: my @changed = &Apache::loncommon::compare_arrays(\@statuses,$curr_inststatus{'inststatusguest'}); 19129: if (@changed) { 19130: push(@{$changes{'inststatus'}},'inststatusguest'); 19131: } 19132: } else { 19133: push(@{$changes{'inststatus'}},'inststatusguest'); 19134: } 19135: } 19136: } else { 19137: delete($env{'form.cancreate_email'}); 19138: if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') { 19139: if (@{$curr_inststatus{'inststatusguest'}} > 0) { 19140: push(@{$changes{'inststatus'}},'inststatusguest'); 19141: } 19142: } 19143: } 19144: } else { 19145: $save_inststatus{'inststatusguest'} = []; 19146: if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') { 19147: if (@{$curr_inststatus{'inststatusguest'}} > 0) { 19148: push(@{$changes{'inststatus'}},'inststatusguest'); 19149: } 19150: } 19151: } 19152: } else { 19153: if ($env{'form.cancreate_'.$item}) { 19154: push(@{$cancreate{'selfcreate'}},$item); 19155: } 19156: } 19157: } 19158: my (%userinfo,%savecaptcha); 19159: my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info(); 19160: # 19161: # Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data 19162: # value set to one), if self-creation with e-mail address permitted, where $type is user type: faculty, staff, student etc. 19163: # 19164: 19165: if ($env{'form.cancreate_email'}) { 19166: push(@contexts,'emailusername'); 19167: if (@statuses) { 19168: foreach my $type (@statuses) { 19169: if (ref($infofields) eq 'ARRAY') { 19170: foreach my $field (@{$infofields}) { 19171: if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) { 19172: $cancreate{'emailusername'}{$type}{$field} = $1; 19173: } 19174: } 19175: } 19176: } 19177: } 19178: # 19179: # Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of 19180: # queued requests for self-creation of account verified by e-mail. 19181: # 19182: 19183: my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval'); 19184: @approvalnotify = sort(@approvalnotify); 19185: $cancreate{'notify'}{'approval'} = join(',',@approvalnotify); 19186: if (ref($curr_usercreation{'cancreate'}) eq 'HASH') { 19187: if (ref($curr_usercreation{'cancreate'}{'notify'}) eq 'HASH') { 19188: if ($curr_usercreation{'cancreate'}{'notify'}{'approval'} ne $cancreate{'notify'}{'approval'}) { 19189: push(@{$changes{'cancreate'}},'notify'); 19190: } 19191: } else { 19192: if ($cancreate{'notify'}{'approval'}) { 19193: push(@{$changes{'cancreate'}},'notify'); 19194: } 19195: } 19196: } elsif ($cancreate{'notify'}{'approval'}) { 19197: push(@{$changes{'cancreate'}},'notify'); 19198: } 19199: 19200: &process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'}); 19201: } 19202: # 19203: # Check if domain default is set appropriately, if self-creation of accounts is to be available for 19204: # institutional log-in. 19205: # 19206: if (grep(/^login$/,@{$cancreate{'selfcreate'}})) { 19207: if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) || 19208: ($domdefaults{'auth_def'} eq 'localauth'))) { 19209: $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.').' '. 19210: &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.'); 19211: } 19212: } 19213: my @fields = ('lastname','firstname','middlename','generation', 19214: 'permanentemail','id'); 19215: my @shibfields = (@fields,'inststatus'); 19216: my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 19217: # 19218: # Where usernames may created for institutional log-in and/or institutional single sign on: 19219: # (a) populate $cancreate{'statustocreate'} array reference with institutional status types who 19220: # may self-create accounts 19221: # (b) populate $save_usermodify{'selfcreate'} hash reference with status types, and information fields 19222: # which the user may supply, if institutional data is unavailable. 19223: # 19224: if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) { 19225: if (@types) { 19226: @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate'); 19227: push(@contexts,'statustocreate'); 19228: foreach my $type (@types) { 19229: my @modifiable = &Apache::loncommon::get_env_multiple('form.canmodify_'.$type); 19230: foreach my $field (@fields) { 19231: if (grep(/^\Q$field\E$/,@modifiable)) { 19232: $save_usermodify{'selfcreate'}{$type}{$field} = 1; 19233: } else { 19234: $save_usermodify{'selfcreate'}{$type}{$field} = 0; 19235: } 19236: } 19237: } 19238: if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') { 19239: foreach my $type (@types) { 19240: if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') { 19241: foreach my $field (@fields) { 19242: if ($save_usermodify{'selfcreate'}{$type}{$field} ne 19243: $curr_usermodify{'selfcreate'}{$type}{$field}) { 19244: push(@{$changes{'selfcreate'}},$type); 19245: last; 19246: } 19247: } 19248: } 19249: } 19250: } else { 19251: foreach my $type (@types) { 19252: push(@{$changes{'selfcreate'}},$type); 19253: } 19254: } 19255: } 19256: foreach my $field (@shibfields) { 19257: if ($env{'form.shibenv_'.$field} ne '') { 19258: $cancreate{'shibenv'}{$field} = $env{'form.shibenv_'.$field}; 19259: } 19260: } 19261: if (ref($curr_usercreation{'cancreate'}) eq 'HASH') { 19262: if (ref($curr_usercreation{'cancreate'}{'shibenv'}) eq 'HASH') { 19263: foreach my $field (@shibfields) { 19264: if ($env{'form.shibenv_'.$field} ne $curr_usercreation{'cancreate'}{'shibenv'}{$field}) { 19265: push(@{$changes{'cancreate'}},'shibenv'); 19266: } 19267: } 19268: } else { 19269: foreach my $field (@shibfields) { 19270: if ($env{'form.shibenv_'.$field}) { 19271: push(@{$changes{'cancreate'}},'shibenv'); 19272: last; 19273: } 19274: } 19275: } 19276: } 19277: } 19278: foreach my $item (@contexts) { 19279: if (ref($curr_usercreation{'cancreate'}{$item}) eq 'ARRAY') { 19280: foreach my $curr (@{$curr_usercreation{'cancreate'}{$item}}) { 19281: if (ref($cancreate{$item}) eq 'ARRAY') { 19282: if (!grep(/^$curr$/,@{$cancreate{$item}})) { 19283: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19284: push(@{$changes{'cancreate'}},$item); 19285: } 19286: } 19287: } 19288: } 19289: if (ref($cancreate{$item}) eq 'ARRAY') { 19290: foreach my $type (@{$cancreate{$item}}) { 19291: if (!grep(/^$type$/,@{$curr_usercreation{'cancreate'}{$item}})) { 19292: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19293: push(@{$changes{'cancreate'}},$item); 19294: } 19295: } 19296: } 19297: } 19298: } elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') { 19299: if (ref($cancreate{$item}) eq 'HASH') { 19300: foreach my $type (keys(%{$curr_usercreation{'cancreate'}{$item}})) { 19301: if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') { 19302: foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$type}})) { 19303: unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) { 19304: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19305: push(@{$changes{'cancreate'}},$item); 19306: } 19307: } 19308: } 19309: } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) { 19310: if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) { 19311: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19312: push(@{$changes{'cancreate'}},$item); 19313: } 19314: } 19315: } 19316: } 19317: foreach my $type (keys(%{$cancreate{$item}})) { 19318: if (ref($cancreate{$item}{$type}) eq 'HASH') { 19319: foreach my $field (keys(%{$cancreate{$item}{$type}})) { 19320: if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') { 19321: unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) { 19322: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19323: push(@{$changes{'cancreate'}},$item); 19324: } 19325: } 19326: } else { 19327: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19328: push(@{$changes{'cancreate'}},$item); 19329: } 19330: } 19331: } 19332: } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) { 19333: if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) { 19334: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19335: push(@{$changes{'cancreate'}},$item); 19336: } 19337: } 19338: } 19339: } 19340: } 19341: } elsif ($curr_usercreation{'cancreate'}{$item}) { 19342: if (ref($cancreate{$item}) eq 'ARRAY') { 19343: if (!grep(/^\Q$curr_usercreation{'cancreate'}{$item}\E$/,@{$cancreate{$item}})) { 19344: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19345: push(@{$changes{'cancreate'}},$item); 19346: } 19347: } 19348: } 19349: } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) { 19350: if (ref($cancreate{$item}) eq 'HASH') { 19351: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19352: push(@{$changes{'cancreate'}},$item); 19353: } 19354: } 19355: } elsif ($item eq 'emailusername') { 19356: if (ref($cancreate{$item}) eq 'HASH') { 19357: foreach my $type (keys(%{$cancreate{$item}})) { 19358: if (ref($cancreate{$item}{$type}) eq 'HASH') { 19359: foreach my $field (keys(%{$cancreate{$item}{$type}})) { 19360: if ($cancreate{$item}{$type}{$field}) { 19361: if (!grep(/^$item$/,@{$changes{'cancreate'}})) { 19362: push(@{$changes{'cancreate'}},$item); 19363: } 19364: last; 19365: } 19366: } 19367: } 19368: } 19369: } 19370: } 19371: } 19372: # 19373: # Populate %save_usercreate hash with updates to self-creation configuration. 19374: # 19375: $save_usercreate{'cancreate'}{'captcha'} = $savecaptcha{'captcha'}; 19376: $save_usercreate{'cancreate'}{'recaptchakeys'} = $savecaptcha{'recaptchakeys'}; 19377: $save_usercreate{'cancreate'}{'recaptchaversion'} = $savecaptcha{'recaptchaversion'}; 19378: $save_usercreate{'cancreate'}{'selfcreate'} = $cancreate{'selfcreate'}; 19379: if (ref($cancreate{'notify'}) eq 'HASH') { 19380: $save_usercreate{'cancreate'}{'notify'} = $cancreate{'notify'}; 19381: } 19382: if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') { 19383: $save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'}; 19384: } 19385: if (ref($cancreate{'emailverified'}) eq 'HASH') { 19386: $save_usercreate{'cancreate'}{'emailverified'} = $cancreate{'emailverified'}; 19387: } 19388: if (ref($cancreate{'emailoptions'}) eq 'HASH') { 19389: $save_usercreate{'cancreate'}{'emailoptions'} = $cancreate{'emailoptions'}; 19390: } 19391: if (ref($cancreate{'emaildomain'}) eq 'HASH') { 19392: $save_usercreate{'cancreate'}{'emaildomain'} = $cancreate{'emaildomain'}; 19393: } 19394: if (ref($cancreate{'statustocreate'}) eq 'ARRAY') { 19395: $save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'}; 19396: } 19397: if (ref($cancreate{'shibenv'}) eq 'HASH') { 19398: $save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'}; 19399: } 19400: $save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'}; 19401: $save_usercreate{'email_rule'} = \%email_rule; 19402: 19403: my %userconfig_hash = ( 19404: usercreation => \%save_usercreate, 19405: usermodification => \%save_usermodify, 19406: inststatus => \%save_inststatus, 19407: ); 19408: 19409: my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash, 19410: $dom); 19411: # 19412: # Accumulate details of changes to domain configuration for self-creation of usernames in $resulttext 19413: # 19414: if ($putresult eq 'ok') { 19415: if (keys(%changes) > 0) { 19416: $resulttext = &mt('Changes made:').'<ul>'; 19417: if (ref($changes{'cancreate'}) eq 'ARRAY') { 19418: my %lt = &selfcreation_types(); 19419: foreach my $type (@{$changes{'cancreate'}}) { 19420: my $chgtext = ''; 19421: if ($type eq 'selfcreate') { 19422: if (@{$cancreate{$type}} == 0) { 19423: $chgtext .= &mt('Self creation of a new user account is not permitted.'); 19424: } else { 19425: $chgtext .= &mt('Self-creation of a new account is permitted for:'). 19426: '<ul>'; 19427: foreach my $case (@{$cancreate{$type}}) { 19428: $chgtext .= '<li>'.$selfcreatetypes{$case}.'</li>'; 19429: } 19430: $chgtext .= '</ul>'; 19431: if (ref($cancreate{$type}) eq 'ARRAY') { 19432: if (grep(/^(login|sso)$/,@{$cancreate{$type}})) { 19433: if (ref($cancreate{'statustocreate'}) eq 'ARRAY') { 19434: if (@{$cancreate{'statustocreate'}} == 0) { 19435: $chgtext .= '<span class="LC_warning">'. 19436: &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts via log-in or single sign-on."). 19437: '</span><br />'; 19438: } 19439: } 19440: } 19441: if (grep(/^email$/,@{$cancreate{$type}})) { 19442: if (!@statuses) { 19443: $chgtext .= '<span class="LC_warning">'. 19444: &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."). 19445: '</span><br />'; 19446: 19447: } 19448: } 19449: } 19450: } 19451: } elsif ($type eq 'shibenv') { 19452: if (keys(%{$cancreate{$type}}) == 0) { 19453: $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information').'<br />'; 19454: } else { 19455: $chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:'). 19456: '<ul>'; 19457: foreach my $field (@shibfields) { 19458: next if ($cancreate{$type}{$field} eq ''); 19459: if ($field eq 'inststatus') { 19460: $chgtext .= '<li>'.&mt('Institutional status').' -- '.$cancreate{$type}{$field}.'</li>'; 19461: } else { 19462: $chgtext .= '<li>'.$fieldtitles{$field}.' -- '.$cancreate{$type}{$field}.'</li>'; 19463: } 19464: } 19465: $chgtext .= '</ul>'; 19466: } 19467: } elsif ($type eq 'statustocreate') { 19468: if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') && 19469: (ref($cancreate{'statustocreate'}) eq 'ARRAY')) { 19470: if (@{$cancreate{'selfcreate'}} > 0) { 19471: if (@{$cancreate{'statustocreate'}} == 0) { 19472: $chgtext .= &mt("Institutional affiliations permitted to create accounts set to 'None'."); 19473: if (!grep(/^email$/,@{$cancreate{'selfcreate'}})) { 19474: $chgtext .= '<br />'. 19475: '<span class="LC_warning">'. 19476: &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts."). 19477: '</span>'; 19478: } 19479: } elsif (keys(%usertypes) > 0) { 19480: if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) { 19481: $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):'); 19482: } else { 19483: $chgtext .= &mt('Institutional affiliations permitted to create accounts with institutional authentication were set as follows:'); 19484: } 19485: $chgtext .= '<ul>'; 19486: foreach my $case (@{$cancreate{$type}}) { 19487: if ($case eq 'default') { 19488: $chgtext .= '<li>'.$othertitle.'</li>'; 19489: } else { 19490: $chgtext .= '<li>'.$usertypes{$case}.'</li>'; 19491: } 19492: } 19493: $chgtext .= '</ul>'; 19494: if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) { 19495: $chgtext .= '<span class="LC_warning">'. 19496: &mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.'). 19497: '</span>'; 19498: } 19499: } 19500: } else { 19501: if (@{$cancreate{$type}} == 0) { 19502: $chgtext .= &mt("Institutional affiliations permitted to create accounts were set to 'none'."); 19503: } else { 19504: $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.'); 19505: } 19506: } 19507: $chgtext .= '<br />'; 19508: } 19509: } elsif ($type eq 'selfcreateprocessing') { 19510: my %choices = &Apache::lonlocal::texthash ( 19511: automatic => 'Automatic approval', 19512: approval => 'Queued for approval', 19513: ); 19514: if (@types) { 19515: if (@statuses) { 19516: $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). 19517: '<ul>'; 19518: foreach my $status (@statuses) { 19519: if ($status eq 'default') { 19520: $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>'; 19521: } else { 19522: $chgtext .= '<li>'.$usertypes{$status}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>'; 19523: } 19524: } 19525: $chgtext .= '</ul>'; 19526: } 19527: } else { 19528: $chgtext .= &mt('Processing of requests to create account with e-mail verification set to: "[_1]"', 19529: $choices{$cancreate{'selfcreateprocessing'}{'default'}}); 19530: } 19531: } elsif ($type eq 'emailverified') { 19532: my %options = &Apache::lonlocal::texthash ( 19533: all => 'Same as e-mail', 19534: first => 'Omit @domain', 19535: free => 'Free to choose', 19536: ); 19537: if (@types) { 19538: if (@statuses) { 19539: $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:'). 19540: '<ul>'; 19541: foreach my $status (@statuses) { 19542: if ($status eq 'default') { 19543: $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>'; 19544: } else { 19545: $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>'; 19546: } 19547: } 19548: $chgtext .= '</ul>'; 19549: } 19550: } else { 19551: $chgtext .= &mt("For self-created accounts verified by e-mail address, user's username is: '[_1]'", 19552: $options{$cancreate{'emailverified'}{'default'}}); 19553: } 19554: } elsif ($type eq 'emailoptions') { 19555: my %options = &Apache::lonlocal::texthash ( 19556: any => 'Any e-mail', 19557: inst => 'Institutional only', 19558: noninst => 'Non-institutional only', 19559: custom => 'Custom restrictions', 19560: ); 19561: if (@types) { 19562: if (@statuses) { 19563: $chgtext .= &mt('For self-created accounts verified by e-mail address, requirements for e-mail address are as follows:'). 19564: '<ul>'; 19565: foreach my $status (@statuses) { 19566: if ($type eq 'default') { 19567: $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>'; 19568: } else { 19569: $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>'; 19570: } 19571: } 19572: $chgtext .= '</ul>'; 19573: } 19574: } else { 19575: if ($cancreate{'emailoptions'}{'default'} eq 'any') { 19576: $chgtext .= &mt('For self-created accounts verified by e-mail address, any e-mail may be used'); 19577: } else { 19578: $chgtext .= &mt('For self-created accounts verified by e-mail address, e-mail restricted to: "[_1]"', 19579: $options{$cancreate{'emailoptions'}{'default'}}); 19580: } 19581: } 19582: } elsif ($type eq 'emaildomain') { 19583: my $output; 19584: if (@statuses) { 19585: foreach my $type (@statuses) { 19586: if (ref($cancreate{'emaildomain'}{$type}) eq 'HASH') { 19587: if ($cancreate{'emailoptions'}{$type} eq 'inst') { 19588: if ($type eq 'default') { 19589: if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || 19590: ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) { 19591: $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>'; 19592: } else { 19593: $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address needs to end: [_1]", 19594: $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; 19595: } 19596: } else { 19597: if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || 19598: ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) { 19599: $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>'; 19600: } else { 19601: $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]", 19602: $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; 19603: } 19604: } 19605: } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') { 19606: if ($type eq 'default') { 19607: if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || 19608: ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) { 19609: $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>'; 19610: } else { 19611: $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address must not end: [_1]", 19612: $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>'; 19613: } 19614: } else { 19615: if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || 19616: ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) { 19617: $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>'; 19618: } else { 19619: $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]", 19620: $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>'; 19621: } 19622: } 19623: } 19624: } 19625: } 19626: } 19627: if ($output ne '') { 19628: $chgtext .= &mt('For self-created accounts verified by e-mail address:'). 19629: '<ul>'.$output.'</ul>'; 19630: } 19631: } elsif ($type eq 'captcha') { 19632: if ($savecaptcha{$type} eq 'notused') { 19633: $chgtext .= &mt('No CAPTCHA validation in use for self-creation screen.'); 19634: } else { 19635: my %captchas = &captcha_phrases(); 19636: if ($captchas{$savecaptcha{$type}}) { 19637: $chgtext .= &mt("Validation for self-creation screen set to $captchas{$savecaptcha{$type}}."); 19638: } else { 19639: $chgtext .= &mt('Validation for self-creation screen set to unknown type.'); 19640: } 19641: } 19642: } elsif ($type eq 'recaptchakeys') { 19643: my ($privkey,$pubkey); 19644: if (ref($savecaptcha{$type}) eq 'HASH') { 19645: $pubkey = $savecaptcha{$type}{'public'}; 19646: $privkey = $savecaptcha{$type}{'private'}; 19647: } 19648: $chgtext .= &mt('ReCAPTCHA keys changes').'<ul>'; 19649: if (!$pubkey) { 19650: $chgtext .= '<li>'.&mt('Public key deleted').'</li>'; 19651: } else { 19652: $chgtext .= '<li>'.&mt('Public key set to [_1]',$pubkey).'</li>'; 19653: } 19654: if (!$privkey) { 19655: $chgtext .= '<li>'.&mt('Private key deleted').'</li>'; 19656: } else { 19657: $chgtext .= '<li>'.&mt('Private key set to [_1]',$pubkey).'</li>'; 19658: } 19659: $chgtext .= '</ul>'; 19660: } elsif ($type eq 'recaptchaversion') { 19661: if ($savecaptcha{'captcha'} eq 'recaptcha') { 19662: $chgtext .= &mt('ReCAPTCHA set to version [_1]',$savecaptcha{$type}); 19663: } 19664: } elsif ($type eq 'emailusername') { 19665: if (ref($cancreate{'emailusername'}) eq 'HASH') { 19666: if (@statuses) { 19667: foreach my $type (@statuses) { 19668: if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') { 19669: if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) { 19670: $chgtext .= &mt('When self-creating account with e-mail verification, the following information will be provided by [_1]:',"'$usertypes{$type}'"). 19671: '<ul>'; 19672: foreach my $field (@{$infofields}) { 19673: if ($cancreate{'emailusername'}{$type}{$field}) { 19674: $chgtext .= '<li>'.$infotitles->{$field}.'</li>'; 19675: } 19676: } 19677: $chgtext .= '</ul>'; 19678: } else { 19679: $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />'; 19680: } 19681: } else { 19682: $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />'; 19683: } 19684: } 19685: } 19686: } 19687: } elsif ($type eq 'notify') { 19688: my $numapprove = 0; 19689: if (ref($changes{'cancreate'}) eq 'ARRAY') { 19690: if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) { 19691: if ($cancreate{'notify'}{'approval'}) { 19692: $chgtext .= &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'}; 19693: $numapprove ++; 19694: } 19695: } 19696: } 19697: unless ($numapprove) { 19698: $chgtext .= &mt('No Domain Coordinators will receive notification of username requests requiring approval.'); 19699: } 19700: } 19701: if ($chgtext) { 19702: $resulttext .= '<li>'.$chgtext.'</li>'; 19703: } 19704: } 19705: } 19706: if ((ref($changes{'email_rule'}) eq 'ARRAY') && (@{$changes{'email_rule'}} > 0)) { 19707: my ($emailrules,$emailruleorder) = 19708: &Apache::lonnet::inst_userrules($dom,'email'); 19709: foreach my $type (@{$changes{'email_rule'}}) { 19710: if (ref($email_rule{$type}) eq 'ARRAY') { 19711: my $chgtext = '<ul>'; 19712: foreach my $rule (@{$email_rule{$type}}) { 19713: if (ref($emailrules->{$rule}) eq 'HASH') { 19714: $chgtext .= '<li>'.$emailrules->{$rule}{'name'}.'</li>'; 19715: } 19716: } 19717: $chgtext .= '</ul>'; 19718: my $typename; 19719: if (@types) { 19720: if ($type eq 'default') { 19721: $typename = $othertitle; 19722: } else { 19723: $typename = $usertypes{$type}; 19724: } 19725: $chgtext .= &mt('(Affiliation: [_1])',$typename); 19726: } 19727: if (@{$email_rule{$type}} > 0) { 19728: $resulttext .= '<li>'. 19729: &mt('Accounts may not be created by users verified by e-mail, for e-mail addresses of the following types: ', 19730: $usertypes{$type}). 19731: $chgtext. 19732: '</li>'; 19733: } else { 19734: $resulttext .= '<li>'. 19735: &mt('There are now no restrictions on e-mail addresses which may be used for verification when a user requests an account.'). 19736: '</li>'. 19737: &mt('(Affiliation: [_1])',$typename); 19738: } 19739: } 19740: } 19741: } 19742: if (ref($changes{'inststatus'}) eq 'ARRAY') { 19743: if (ref($save_inststatus{'inststatusguest'}) eq 'ARRAY') { 19744: if (@{$save_inststatus{'inststatusguest'}} > 0) { 19745: my $chgtext = '<ul>'; 19746: foreach my $type (@{$save_inststatus{'inststatusguest'}}) { 19747: $chgtext .= '<li>'.$usertypes{$type}.'</li>'; 19748: } 19749: $chgtext .= '</ul>'; 19750: $resulttext .= '<li>'. 19751: &mt('A user will self-report one of the following affiliations when requesting an account verified by e-mail: '). 19752: $chgtext. 19753: '</li>'; 19754: } else { 19755: $resulttext .= '<li>'. 19756: &mt('No affiliations available for self-reporting when requesting an account verified by e-mail.'). 19757: '</li>'; 19758: } 19759: } 19760: } 19761: if (ref($changes{'selfcreate'}) eq 'ARRAY') { 19762: $resulttext .= '<li>'.&mt('When self-creating institutional account:').'<ul>'; 19763: my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 19764: foreach my $type (@{$changes{'selfcreate'}}) { 19765: my $typename = $type; 19766: if (keys(%usertypes) > 0) { 19767: if ($usertypes{$type} ne '') { 19768: $typename = $usertypes{$type}; 19769: } 19770: } 19771: my @modifiable; 19772: $resulttext .= '<li>'. 19773: &mt('Self-creation of account by users with status: [_1]', 19774: '<span class="LC_cusr_emph">'.$typename.'</span>'). 19775: ' - '.&mt('modifiable fields (if institutional data blank): '); 19776: foreach my $field (@fields) { 19777: if ($save_usermodify{'selfcreate'}{$type}{$field}) { 19778: push(@modifiable,'<b>'.$fieldtitles{$field}.'</b>'); 19779: } 19780: } 19781: if (@modifiable > 0) { 19782: $resulttext .= join(', ',@modifiable); 19783: } else { 19784: $resulttext .= &mt('none'); 19785: } 19786: $resulttext .= '</li>'; 19787: } 19788: $resulttext .= '</ul></li>'; 19789: } 19790: $resulttext .= '</ul>'; 19791: my $cachetime = 24*60*60; 19792: $domdefaults{'inststatusguest'} = $save_inststatus{'inststatusguest'}; 19793: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 19794: if (ref($lastactref) eq 'HASH') { 19795: $lastactref->{'domdefaults'} = 1; 19796: } 19797: } else { 19798: $resulttext = &mt('No changes made to self-creation settings'); 19799: } 19800: } else { 19801: $resulttext = '<span class="LC_error">'. 19802: &mt('An error occurred: [_1]',$putresult).'</span>'; 19803: } 19804: if ($warningmsg ne '') { 19805: $resulttext .= '<br /><span class="LC_warning">'.$warningmsg.'</span><br />'; 19806: } 19807: return $resulttext; 19808: } 19809: 19810: sub process_captcha { 19811: my ($container,$changes,$newsettings,$currsettings) = @_; 19812: return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH')); 19813: $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'}; 19814: unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') { 19815: $newsettings->{'captcha'} = 'original'; 19816: } 19817: my %current; 19818: if (ref($currsettings) eq 'HASH') { 19819: %current = %{$currsettings}; 19820: } 19821: if ($current{'captcha'} ne $newsettings->{'captcha'}) { 19822: if ($container eq 'cancreate') { 19823: if (ref($changes->{'cancreate'}) eq 'ARRAY') { 19824: push(@{$changes->{'cancreate'}},'captcha'); 19825: } elsif (!defined($changes->{'cancreate'})) { 19826: $changes->{'cancreate'} = ['captcha']; 19827: } 19828: } elsif ($container eq 'passwords') { 19829: $changes->{'reset'} = 1; 19830: } else { 19831: $changes->{'captcha'} = 1; 19832: } 19833: } 19834: my ($newpub,$newpriv,$currpub,$currpriv,$newversion,$currversion); 19835: if ($newsettings->{'captcha'} eq 'recaptcha') { 19836: $newpub = $env{'form.'.$container.'_recaptchapub'}; 19837: $newpriv = $env{'form.'.$container.'_recaptchapriv'}; 19838: $newpub =~ s/[^\w\-]//g; 19839: $newpriv =~ s/[^\w\-]//g; 19840: $newsettings->{'recaptchakeys'} = { 19841: public => $newpub, 19842: private => $newpriv, 19843: }; 19844: $newversion = $env{'form.'.$container.'_recaptchaversion'}; 19845: $newversion =~ s/\D//g; 19846: if ($newversion ne '2') { 19847: $newversion = 1; 19848: } 19849: $newsettings->{'recaptchaversion'} = $newversion; 19850: } 19851: if (ref($current{'recaptchakeys'}) eq 'HASH') { 19852: $currpub = $current{'recaptchakeys'}{'public'}; 19853: $currpriv = $current{'recaptchakeys'}{'private'}; 19854: unless ($newsettings->{'captcha'} eq 'recaptcha') { 19855: $newsettings->{'recaptchakeys'} = { 19856: public => '', 19857: private => '', 19858: } 19859: } 19860: } 19861: if ($current{'captcha'} eq 'recaptcha') { 19862: $currversion = $current{'recaptchaversion'}; 19863: if ($currversion ne '2') { 19864: $currversion = 1; 19865: } 19866: } 19867: if ($currversion ne $newversion) { 19868: if ($container eq 'cancreate') { 19869: if (ref($changes->{'cancreate'}) eq 'ARRAY') { 19870: push(@{$changes->{'cancreate'}},'recaptchaversion'); 19871: } elsif (!defined($changes->{'cancreate'})) { 19872: $changes->{'cancreate'} = ['recaptchaversion']; 19873: } 19874: } elsif ($container eq 'passwords') { 19875: $changes->{'reset'} = 1; 19876: } else { 19877: $changes->{'recaptchaversion'} = 1; 19878: } 19879: } 19880: if (($newpub ne $currpub) || ($newpriv ne $currpriv)) { 19881: if ($container eq 'cancreate') { 19882: if (ref($changes->{'cancreate'}) eq 'ARRAY') { 19883: push(@{$changes->{'cancreate'}},'recaptchakeys'); 19884: } elsif (!defined($changes->{'cancreate'})) { 19885: $changes->{'cancreate'} = ['recaptchakeys']; 19886: } 19887: } elsif ($container eq 'passwords') { 19888: $changes->{'reset'} = 1; 19889: } else { 19890: $changes->{'recaptchakeys'} = 1; 19891: } 19892: } 19893: return; 19894: } 19895: 19896: sub modify_usermodification { 19897: my ($dom,%domconfig) = @_; 19898: my ($resulttext,%curr_usermodification,%changes,%modifyhash); 19899: if (ref($domconfig{'usermodification'}) eq 'HASH') { 19900: foreach my $key (keys(%{$domconfig{'usermodification'}})) { 19901: if ($key eq 'selfcreate') { 19902: $modifyhash{$key} = $domconfig{'usermodification'}{$key}; 19903: } else { 19904: $curr_usermodification{$key} = $domconfig{'usermodification'}{$key}; 19905: } 19906: } 19907: } 19908: my @contexts = ('author','course'); 19909: my %context_title = ( 19910: author => 'In author context', 19911: course => 'In course context', 19912: ); 19913: my @fields = ('lastname','firstname','middlename','generation', 19914: 'permanentemail','id'); 19915: my %roles = ( 19916: author => ['ca','aa'], 19917: course => ['st','ep','ta','in','cr'], 19918: ); 19919: my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); 19920: foreach my $context (@contexts) { 19921: foreach my $role (@{$roles{$context}}) { 19922: my @modifiable = &Apache::loncommon::get_env_multiple('form.canmodify_'.$role); 19923: foreach my $item (@fields) { 19924: if (grep(/^\Q$item\E$/,@modifiable)) { 19925: $modifyhash{$context}{$role}{$item} = 1; 19926: } else { 19927: $modifyhash{$context}{$role}{$item} = 0; 19928: } 19929: } 19930: } 19931: if (ref($curr_usermodification{$context}) eq 'HASH') { 19932: foreach my $role (@{$roles{$context}}) { 19933: if (ref($curr_usermodification{$context}{$role}) eq 'HASH') { 19934: foreach my $field (@fields) { 19935: if ($modifyhash{$context}{$role}{$field} ne 19936: $curr_usermodification{$context}{$role}{$field}) { 19937: push(@{$changes{$context}},$role); 19938: last; 19939: } 19940: } 19941: } 19942: } 19943: } else { 19944: foreach my $context (@contexts) { 19945: foreach my $role (@{$roles{$context}}) { 19946: push(@{$changes{$context}},$role); 19947: } 19948: } 19949: } 19950: } 19951: my %usermodification_hash = ( 19952: usermodification => \%modifyhash, 19953: ); 19954: my $putresult = &Apache::lonnet::put_dom('configuration', 19955: \%usermodification_hash,$dom); 19956: if ($putresult eq 'ok') { 19957: if (keys(%changes) > 0) { 19958: $resulttext = &mt('Changes made: ').'<ul>'; 19959: foreach my $context (@contexts) { 19960: if (ref($changes{$context}) eq 'ARRAY') { 19961: $resulttext .= '<li>'.$context_title{$context}.':<ul>'; 19962: if (ref($changes{$context}) eq 'ARRAY') { 19963: foreach my $role (@{$changes{$context}}) { 19964: my $rolename; 19965: if ($role eq 'cr') { 19966: $rolename = &mt('Custom'); 19967: } else { 19968: $rolename = &Apache::lonnet::plaintext($role); 19969: } 19970: my @modifiable; 19971: $resulttext .= '<li><span class="LC_cusr_emph">'.&mt('Target user with [_1] role',$rolename).'</span> - '.&mt('modifiable fields: '); 19972: foreach my $field (@fields) { 19973: if ($modifyhash{$context}{$role}{$field}) { 19974: push(@modifiable,$fieldtitles{$field}); 19975: } 19976: } 19977: if (@modifiable > 0) { 19978: $resulttext .= join(', ',@modifiable); 19979: } else { 19980: $resulttext .= &mt('none'); 19981: } 19982: $resulttext .= '</li>'; 19983: } 19984: $resulttext .= '</ul></li>'; 19985: } 19986: } 19987: } 19988: $resulttext .= '</ul>'; 19989: } else { 19990: $resulttext = &mt('No changes made to user modification settings'); 19991: } 19992: } else { 19993: $resulttext = '<span class="LC_error">'. 19994: &mt('An error occurred: [_1]',$putresult).'</span>'; 19995: } 19996: return $resulttext; 19997: } 19998: 19999: sub modify_defaults { 20000: my ($dom,$lastactref,%domconfig) = @_; 20001: my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors); 20002: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 20003: my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def', 20004: 'portal_def'); 20005: my @authtypes = ('internal','krb4','krb5','localauth','lti'); 20006: foreach my $item (@items) { 20007: $newvalues{$item} = $env{'form.'.$item}; 20008: if ($item eq 'auth_def') { 20009: if ($newvalues{$item} ne '') { 20010: if (!grep(/^\Q$newvalues{$item}\E$/,@authtypes)) { 20011: push(@errors,$item); 20012: } 20013: } 20014: } elsif ($item eq 'lang_def') { 20015: if ($newvalues{$item} ne '') { 20016: if ($newvalues{$item} =~ /^(\w+)/) { 20017: my $langcode = $1; 20018: if ($langcode ne 'x_chef') { 20019: if (code2language($langcode) eq '') { 20020: push(@errors,$item); 20021: } 20022: } 20023: } else { 20024: push(@errors,$item); 20025: } 20026: } 20027: } elsif ($item eq 'timezone_def') { 20028: if ($newvalues{$item} ne '') { 20029: if (!DateTime::TimeZone->is_valid_name($newvalues{$item})) { 20030: push(@errors,$item); 20031: } 20032: } 20033: } elsif ($item eq 'datelocale_def') { 20034: if ($newvalues{$item} ne '') { 20035: my @datelocale_ids = DateTime::Locale->ids(); 20036: if (!grep(/^\Q$newvalues{$item}\E$/,@datelocale_ids)) { 20037: push(@errors,$item); 20038: } 20039: } 20040: } elsif ($item eq 'portal_def') { 20041: if ($newvalues{$item} ne '') { 20042: 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])\/?$/) { 20043: foreach my $field ('email','web') { 20044: if ($env{'form.'.$item.'_'.$field}) { 20045: $newvalues{$item.'_'.$field} = $env{'form.'.$item.'_'.$field}; 20046: } 20047: } 20048: } else { 20049: push(@errors,$item); 20050: } 20051: } 20052: } 20053: if (grep(/^\Q$item\E$/,@errors)) { 20054: $newvalues{$item} = $domdefaults{$item}; 20055: if ($item eq 'portal_def') { 20056: if ($domdefaults{$item}) { 20057: foreach my $field ('email','web') { 20058: if (exists($domdefaults{$item.'_'.$field})) { 20059: $newvalues{$item.'_'.$field} = $domdefaults{$item.'_'.$field}; 20060: } 20061: } 20062: } 20063: } 20064: } elsif ($domdefaults{$item} ne $newvalues{$item}) { 20065: $changes{$item} = 1; 20066: } 20067: if ($item eq 'portal_def') { 20068: unless (grep(/^\Q$item\E$/,@errors)) { 20069: if ($newvalues{$item} eq '') { 20070: foreach my $field ('email','web') { 20071: if (exists($domdefaults{$item.'_'.$field})) { 20072: delete($domdefaults{$item.'_'.$field}); 20073: } 20074: } 20075: } else { 20076: unless ($changes{$item}) { 20077: foreach my $field ('email','web') { 20078: if ($domdefaults{$item.'_'.$field} ne $newvalues{$item.'_'.$field}) { 20079: $changes{$item} = 1; 20080: last; 20081: } 20082: } 20083: } 20084: foreach my $field ('email','web') { 20085: if ($newvalues{$item.'_'.$field}) { 20086: $domdefaults{$item.'_'.$field} = $newvalues{$item.'_'.$field}; 20087: } elsif (exists($domdefaults{$item.'_'.$field})) { 20088: delete($domdefaults{$item.'_'.$field}); 20089: } 20090: } 20091: } 20092: } 20093: } 20094: $domdefaults{$item} = $newvalues{$item}; 20095: } 20096: my %staticdefaults = ( 20097: 'intauth_cost' => 10, 20098: 'intauth_check' => 0, 20099: 'intauth_switch' => 0, 20100: ); 20101: foreach my $item ('intauth_cost','intauth_check','intauth_switch') { 20102: if (exists($domdefaults{$item})) { 20103: $newvalues{$item} = $domdefaults{$item}; 20104: } else { 20105: $newvalues{$item} = $staticdefaults{$item}; 20106: } 20107: } 20108: my ($unamemaprules,$ruleorder); 20109: my @possunamemaprules = &Apache::loncommon::get_env_multiple('form.unamemap_rule'); 20110: if (@possunamemaprules) { 20111: ($unamemaprules,$ruleorder) = 20112: &Apache::lonnet::inst_userrules($dom,'unamemap'); 20113: if ((ref($unamemaprules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) { 20114: if (@{$ruleorder} > 0) { 20115: my %possrules; 20116: map { $possrules{$_} = 1; } @possunamemaprules; 20117: foreach my $rule (@{$ruleorder}) { 20118: if ($possrules{$rule}) { 20119: push(@{$newvalues{'unamemap_rule'}},$rule); 20120: } 20121: } 20122: } 20123: } 20124: } 20125: if (ref($domdefaults{'unamemap_rule'}) eq 'ARRAY') { 20126: if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') { 20127: my @rulediffs = &Apache::loncommon::compare_arrays($domdefaults{'unamemap_rule'}, 20128: $newvalues{'unamemap_rule'}); 20129: if (@rulediffs) { 20130: $changes{'unamemap_rule'} = 1; 20131: $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'}; 20132: } 20133: } elsif (@{$domdefaults{'unamemap_rule'}} > 0) { 20134: $changes{'unamemap_rule'} = 1; 20135: delete($domdefaults{'unamemap_rule'}); 20136: } 20137: } elsif (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') { 20138: if (@{$newvalues{'unamemap_rule'}} > 0) { 20139: $changes{'unamemap_rule'} = 1; 20140: $domdefaults{'unamemap_rule'} = $newvalues{'unamemap_rule'}; 20141: } 20142: } 20143: my %defaults_hash = ( 20144: defaults => \%newvalues, 20145: ); 20146: my $title = &defaults_titles(); 20147: 20148: my $currinststatus; 20149: if (ref($domconfig{'inststatus'}) eq 'HASH') { 20150: $currinststatus = $domconfig{'inststatus'}; 20151: } else { 20152: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 20153: $currinststatus = { 20154: inststatustypes => $usertypes, 20155: inststatusorder => $types, 20156: inststatusguest => [], 20157: }; 20158: } 20159: my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete'); 20160: my @allpos; 20161: my %alltypes; 20162: my @inststatusguest; 20163: if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') { 20164: foreach my $type (@{$currinststatus->{'inststatusguest'}}) { 20165: unless (grep(/^\Q$type\E$/,@todelete)) { 20166: push(@inststatusguest,$type); 20167: } 20168: } 20169: } 20170: my ($currtitles,$currorder); 20171: if (ref($currinststatus) eq 'HASH') { 20172: if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') { 20173: foreach my $type (@{$currinststatus->{'inststatusorder'}}) { 20174: if (ref($currinststatus->{inststatustypes}) eq 'HASH') { 20175: if ($currinststatus->{inststatustypes}->{$type} ne '') { 20176: $currtitles .= $currinststatus->{inststatustypes}->{$type}.','; 20177: } 20178: } 20179: unless (grep(/^\Q$type\E$/,@todelete)) { 20180: my $position = $env{'form.inststatus_pos_'.$type}; 20181: $position =~ s/\D+//g; 20182: $allpos[$position] = $type; 20183: $alltypes{$type} = $env{'form.inststatus_title_'.$type}; 20184: $alltypes{$type} =~ s/`//g; 20185: } 20186: } 20187: $currorder = join(',',@{$currinststatus->{'inststatusorder'}}); 20188: $currtitles =~ s/,$//; 20189: } 20190: } 20191: if ($env{'form.addinststatus'}) { 20192: my $newtype = $env{'form.addinststatus'}; 20193: $newtype =~ s/\W//g; 20194: unless (exists($alltypes{$newtype})) { 20195: $alltypes{$newtype} = $env{'form.addinststatus_title'}; 20196: $alltypes{$newtype} =~ s/`//g; 20197: my $position = $env{'form.addinststatus_pos'}; 20198: $position =~ s/\D+//g; 20199: if ($position ne '') { 20200: $allpos[$position] = $newtype; 20201: } 20202: } 20203: } 20204: my @orderedstatus; 20205: foreach my $type (@allpos) { 20206: unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) { 20207: push(@orderedstatus,$type); 20208: } 20209: } 20210: foreach my $type (keys(%alltypes)) { 20211: unless (grep(/^\Q$type\E$/,@orderedstatus)) { 20212: delete($alltypes{$type}); 20213: } 20214: } 20215: $defaults_hash{'inststatus'} = { 20216: inststatustypes => \%alltypes, 20217: inststatusorder => \@orderedstatus, 20218: inststatusguest => \@inststatusguest, 20219: }; 20220: if (ref($defaults_hash{'inststatus'}) eq 'HASH') { 20221: foreach my $item ('inststatustypes','inststatusorder','inststatusguest') { 20222: $domdefaults{$item} = $defaults_hash{'inststatus'}{$item}; 20223: } 20224: } 20225: if ($currorder ne join(',',@orderedstatus)) { 20226: $changes{'inststatus'}{'inststatusorder'} = 1; 20227: } 20228: my $newtitles; 20229: foreach my $item (@orderedstatus) { 20230: $newtitles .= $alltypes{$item}.','; 20231: } 20232: $newtitles =~ s/,$//; 20233: if ($currtitles ne $newtitles) { 20234: $changes{'inststatus'}{'inststatustypes'} = 1; 20235: } 20236: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaults_hash, 20237: $dom); 20238: if ($putresult eq 'ok') { 20239: if (keys(%changes) > 0) { 20240: $resulttext = &mt('Changes made:').'<ul>'; 20241: my $version = &Apache::lonnet::get_server_loncaparev($dom); 20242: 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"; 20243: foreach my $item (sort(keys(%changes))) { 20244: if ($item eq 'inststatus') { 20245: if (ref($changes{'inststatus'}) eq 'HASH') { 20246: if (@orderedstatus) { 20247: $resulttext .= '<li>'.&mt('Institutional user status types set to:').' '; 20248: foreach my $type (@orderedstatus) { 20249: $resulttext .= $alltypes{$type}.', '; 20250: } 20251: $resulttext =~ s/, $//; 20252: $resulttext .= '</li>'; 20253: } else { 20254: $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>'; 20255: } 20256: } 20257: } elsif ($item eq 'unamemap_rule') { 20258: if (ref($newvalues{'unamemap_rule'}) eq 'ARRAY') { 20259: my @rulenames; 20260: if (ref($unamemaprules) eq 'HASH') { 20261: foreach my $rule (@{$newvalues{'unamemap_rule'}}) { 20262: if (ref($unamemaprules->{$rule}) eq 'HASH') { 20263: push(@rulenames,$unamemaprules->{$rule}->{'name'}); 20264: } 20265: } 20266: } 20267: if (@rulenames) { 20268: $resulttext .= '<li>'.&mt('Mapping for missing usernames includes: [_1]', 20269: '<ul><li>'.join('</li><li>',@rulenames).'</li></ul>'). 20270: '</li>'; 20271: } else { 20272: $resulttext .= '<li>'.&mt('No mapping for missing usernames via standard log-in').'</li>'; 20273: } 20274: } else { 20275: $resulttext .= '<li>'.&mt('Mapping for missing usernames via standard log-in deleted').'</li>'; 20276: } 20277: } else { 20278: my $value = $env{'form.'.$item}; 20279: if ($value eq '') { 20280: $value = &mt('none'); 20281: } elsif ($item eq 'auth_def') { 20282: my %authnames = &authtype_names(); 20283: my %shortauth = ( 20284: internal => 'int', 20285: krb4 => 'krb4', 20286: krb5 => 'krb5', 20287: localauth => 'loc', 20288: lti => 'lti', 20289: ); 20290: $value = $authnames{$shortauth{$value}}; 20291: } 20292: $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>'; 20293: $mailmsgtext .= "$title->{$item} set to $value\n"; 20294: if ($item eq 'portal_def') { 20295: if ($env{'form.'.$item} ne '') { 20296: foreach my $field ('email','web') { 20297: $value = $env{'form.'.$item.'_'.$field}; 20298: if ($value) { 20299: $value = &mt('Yes'); 20300: } else { 20301: $value = &mt('No'); 20302: } 20303: $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'</li>'; 20304: } 20305: } 20306: } 20307: } 20308: } 20309: $resulttext .= '</ul>'; 20310: $mailmsgtext .= "\n"; 20311: my $cachetime = 24*60*60; 20312: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 20313: if (ref($lastactref) eq 'HASH') { 20314: $lastactref->{'domdefaults'} = 1; 20315: } 20316: if ($changes{'auth_def'} || $changes{'auth_arg_def'} || $changes{'lang_def'} || $changes{'datelocale_def'}) { 20317: my $notify = 1; 20318: if (ref($domconfig{'contacts'}) eq 'HASH') { 20319: if ($domconfig{'contacts'}{'reportupdates'} == 0) { 20320: $notify = 0; 20321: } 20322: } 20323: if ($notify) { 20324: &Apache::lonmsg::sendemail('installrecord@loncapa.org', 20325: "LON-CAPA Domain Settings Change - $dom", 20326: $mailmsgtext); 20327: } 20328: } 20329: } else { 20330: $resulttext = &mt('No changes made to default authentication/language/timezone settings'); 20331: } 20332: } else { 20333: $resulttext = '<span class="LC_error">'. 20334: &mt('An error occurred: [_1]',$putresult).'</span>'; 20335: } 20336: if (@errors > 0) { 20337: $resulttext .= '<br />'.&mt('The following were left unchanged because the values entered were invalid:'); 20338: foreach my $item (@errors) { 20339: $resulttext .= ' "'.$title->{$item}.'",'; 20340: } 20341: $resulttext =~ s/,$//; 20342: } 20343: return $resulttext; 20344: } 20345: 20346: sub modify_scantron { 20347: my ($r,$dom,$confname,$lastactref,%domconfig) = @_; 20348: my ($resulttext,%confhash,%changes,$errors); 20349: my $custom = 'custom.tab'; 20350: my $default = 'default.tab'; 20351: my $servadm = $r->dir_config('lonAdmEMail'); 20352: my ($configuserok,$author_ok,$switchserver) = 20353: &config_check($dom,$confname,$servadm); 20354: if ($env{'form.scantronformat.filename'} ne '') { 20355: my $error; 20356: if ($configuserok eq 'ok') { 20357: if ($switchserver) { 20358: $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver); 20359: } else { 20360: if ($author_ok eq 'ok') { 20361: my ($result,$scantronurl) = 20362: &publishlogo($r,'upload','scantronformat',$dom, 20363: $confname,'scantron','','',$custom); 20364: if ($result eq 'ok') { 20365: $confhash{'scantron'}{'scantronformat'} = $scantronurl; 20366: $changes{'scantronformat'} = 1; 20367: } else { 20368: $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result); 20369: } 20370: } else { 20371: $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); 20372: } 20373: } 20374: } else { 20375: $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); 20376: } 20377: if ($error) { 20378: &Apache::lonnet::logthis($error); 20379: $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; 20380: } 20381: } 20382: if (ref($domconfig{'scantron'}) eq 'HASH') { 20383: if ($domconfig{'scantron'}{'scantronformat'} ne '') { 20384: if ($env{'form.scantronformat_del'}) { 20385: $confhash{'scantron'}{'scantronformat'} = ''; 20386: $changes{'scantronformat'} = 1; 20387: } else { 20388: $confhash{'scantron'}{'scantronformat'} = $domconfig{'scantron'}{'scantronformat'}; 20389: } 20390: } 20391: } 20392: my @options = ('hdr','pad','rem'); 20393: my @fields = &scantroncsv_fields(); 20394: my %titles = &scantronconfig_titles(); 20395: my @formats = &Apache::loncommon::get_env_multiple('form.scantronconfig'); 20396: my ($newdat,$currdat,%newcol,%currcol); 20397: if (grep(/^dat$/,@formats)) { 20398: $confhash{'scantron'}{config}{dat} = 1; 20399: $newdat = 1; 20400: } else { 20401: $newdat = 0; 20402: } 20403: if (grep(/^csv$/,@formats)) { 20404: my %bynum; 20405: foreach my $field (@fields) { 20406: if ($env{'form.scantronconfig_csv_'.$field} =~ /^(\d+)$/) { 20407: my $posscol = $1; 20408: if (($posscol < 20) && (!$bynum{$posscol})) { 20409: $confhash{'scantron'}{config}{csv}{fields}{$field} = $posscol; 20410: $bynum{$posscol} = $field; 20411: $newcol{$field} = $posscol; 20412: } 20413: } 20414: } 20415: if (keys(%newcol)) { 20416: foreach my $option (@options) { 20417: if ($env{'form.scantroncsv_'.$option}) { 20418: $confhash{'scantron'}{config}{csv}{options}{$option} = 1; 20419: } 20420: } 20421: } 20422: } 20423: $currdat = 1; 20424: if (ref($domconfig{'scantron'}) eq 'HASH') { 20425: if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') { 20426: unless (exists($domconfig{'scantron'}{'config'}{'dat'})) { 20427: $currdat = 0; 20428: } 20429: if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') { 20430: if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') { 20431: %currcol = %{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}}; 20432: } 20433: } 20434: } 20435: } 20436: if ($currdat != $newdat) { 20437: $changes{'config'} = 1; 20438: } else { 20439: foreach my $field (@fields) { 20440: if ($currcol{$field} ne '') { 20441: if ($currcol{$field} ne $newcol{$field}) { 20442: $changes{'config'} = 1; 20443: last; 20444: } 20445: } elsif ($newcol{$field} ne '') { 20446: $changes{'config'} = 1; 20447: last; 20448: } 20449: } 20450: } 20451: if (keys(%confhash) > 0) { 20452: my $putresult = &Apache::lonnet::put_dom('configuration',\%confhash, 20453: $dom); 20454: if ($putresult eq 'ok') { 20455: if (keys(%changes) > 0) { 20456: if (ref($confhash{'scantron'}) eq 'HASH') { 20457: $resulttext = &mt('Changes made:').'<ul>'; 20458: if ($changes{'scantronformat'}) { 20459: if ($confhash{'scantron'}{'scantronformat'} eq '') { 20460: $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>'; 20461: } else { 20462: $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>'; 20463: } 20464: } 20465: if ($changes{'config'}) { 20466: if (ref($confhash{'scantron'}{'config'}) eq 'HASH') { 20467: if ($confhash{'scantron'}{'config'}{'dat'}) { 20468: $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .dat format').'</li>'; 20469: } 20470: if (ref($confhash{'scantron'}{'config'}{'csv'}) eq 'HASH') { 20471: if (ref($confhash{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') { 20472: if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'fields'}})) { 20473: $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following fields/column numbers supported:').'<ul>'; 20474: foreach my $field (@fields) { 20475: if ($confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} ne '') { 20476: my $showcol = $confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} + 1; 20477: $resulttext .= '<li>'.$titles{$field}.': '.$showcol.'</li>'; 20478: } 20479: } 20480: $resulttext .= '</ul></li>'; 20481: if (ref($confhash{'scantron'}{'config'}{'csv'}{'options'}) eq 'HASH') { 20482: if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'options'}})) { 20483: $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following options:').'<ul>'; 20484: foreach my $option (@options) { 20485: if ($confhash{'scantron'}{'config'}{'csv'}{'options'}{$option} ne '') { 20486: $resulttext .= '<li>'.$titles{$option}.'</li>'; 20487: } 20488: } 20489: $resulttext .= '</ul></li>'; 20490: } 20491: } 20492: } 20493: } 20494: } 20495: } else { 20496: $resulttext .= '<li>'.&mt('No bubblesheet data upload formats set -- will default to assuming .dat format').'</li>'; 20497: } 20498: } 20499: $resulttext .= '</ul>'; 20500: } else { 20501: $resulttext = &mt('Changes made to bubblesheet format file.'); 20502: } 20503: &Apache::loncommon::devalidate_domconfig_cache($dom); 20504: if (ref($lastactref) eq 'HASH') { 20505: $lastactref->{'domainconfig'} = 1; 20506: } 20507: } else { 20508: $resulttext = &mt('No changes made to bubblesheet format settings'); 20509: } 20510: } else { 20511: $resulttext = '<span class="LC_error">'. 20512: &mt('An error occurred: [_1]',$putresult).'</span>'; 20513: } 20514: } else { 20515: $resulttext = &mt('No changes made to bubblesheet format file'); 20516: } 20517: if ($errors) { 20518: $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'. 20519: $errors.'</ul></p>'; 20520: } 20521: return $resulttext; 20522: } 20523: 20524: sub modify_coursecategories { 20525: my ($dom,$lastactref,%domconfig) = @_; 20526: my ($resulttext,%deletions,%reorderings,%needreordering,%adds,%changes,$errors, 20527: $cathash); 20528: my @deletecategory = &Apache::loncommon::get_env_multiple('form.deletecategory'); 20529: my @catitems = ('unauth','auth'); 20530: my @cattypes = ('std','domonly','codesrch','none'); 20531: if (ref($domconfig{'coursecategories'}) eq 'HASH') { 20532: $cathash = $domconfig{'coursecategories'}{'cats'}; 20533: if ($domconfig{'coursecategories'}{'togglecats'} ne $env{'form.togglecats'}) { 20534: $changes{'togglecats'} = 1; 20535: $domconfig{'coursecategories'}{'togglecats'} = $env{'form.togglecats'}; 20536: } 20537: if ($domconfig{'coursecategories'}{'categorize'} ne $env{'form.categorize'}) { 20538: $changes{'categorize'} = 1; 20539: $domconfig{'coursecategories'}{'categorize'} = $env{'form.categorize'}; 20540: } 20541: if ($domconfig{'coursecategories'}{'togglecatscomm'} ne $env{'form.togglecatscomm'}) { 20542: $changes{'togglecatscomm'} = 1; 20543: $domconfig{'coursecategories'}{'togglecatscomm'} = $env{'form.togglecatscomm'}; 20544: } 20545: if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) { 20546: $changes{'categorizecomm'} = 1; 20547: $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'}; 20548: 20549: } 20550: if ($domconfig{'coursecategories'}{'togglecatsplace'} ne $env{'form.togglecatsplace'}) { 20551: $changes{'togglecatsplace'} = 1; 20552: $domconfig{'coursecategories'}{'togglecatsplace'} = $env{'form.togglecatsplace'}; 20553: } 20554: if ($domconfig{'coursecategories'}{'categorizeplace'} ne $env{'form.categorizeplace'}) { 20555: $changes{'categorizeplace'} = 1; 20556: $domconfig{'coursecategories'}{'categorizeplace'} = $env{'form.categorizeplace'}; 20557: } 20558: foreach my $item (@catitems) { 20559: if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) { 20560: if ($domconfig{'coursecategories'}{$item} ne $env{'form.coursecat_'.$item}) { 20561: $changes{$item} = 1; 20562: $domconfig{'coursecategories'}{$item} = $env{'form.coursecat_'.$item}; 20563: } 20564: } 20565: } 20566: } else { 20567: $changes{'togglecats'} = 1; 20568: $changes{'categorize'} = 1; 20569: $changes{'togglecatscomm'} = 1; 20570: $changes{'categorizecomm'} = 1; 20571: $changes{'togglecatsplace'} = 1; 20572: $changes{'categorizeplace'} = 1; 20573: $domconfig{'coursecategories'} = { 20574: togglecats => $env{'form.togglecats'}, 20575: categorize => $env{'form.categorize'}, 20576: togglecatscomm => $env{'form.togglecatscomm'}, 20577: categorizecomm => $env{'form.categorizecomm'}, 20578: togglecatsplace => $env{'form.togglecatsplace'}, 20579: categorizeplace => $env{'form.categorizeplace'}, 20580: }; 20581: foreach my $item (@catitems) { 20582: if ($env{'form.coursecat_'.$item} ne 'std') { 20583: $changes{$item} = 1; 20584: } 20585: if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) { 20586: $domconfig{'coursecategories'}{$item} = $env{'form.coursecat_'.$item}; 20587: } 20588: } 20589: } 20590: if (ref($cathash) eq 'HASH') { 20591: if (($domconfig{'coursecategories'}{'cats'}{'instcode::0'} ne '') && ($env{'form.instcode'} == 0)) { 20592: push (@deletecategory,'instcode::0'); 20593: } 20594: if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '') && ($env{'form.communities'} == 0)) { 20595: push(@deletecategory,'communities::0'); 20596: } 20597: if (($domconfig{'coursecategories'}{'cats'}{'placement::0'} ne '') && ($env{'form.placement'} == 0)) { 20598: push(@deletecategory,'placement::0'); 20599: } 20600: } 20601: my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail); 20602: if (ref($cathash) eq 'HASH') { 20603: if (@deletecategory > 0) { 20604: #FIXME Need to remove category from all courses using a deleted category 20605: &Apache::loncommon::extract_categories($cathash,\@predelcats,\@predeltrails,\%predelallitems); 20606: foreach my $item (@deletecategory) { 20607: if ($domconfig{'coursecategories'}{'cats'}{$item} ne '') { 20608: delete($domconfig{'coursecategories'}{'cats'}{$item}); 20609: $deletions{$item} = 1; 20610: &recurse_cat_deletes($item,$cathash,\%deletions); 20611: } 20612: } 20613: } 20614: foreach my $item (keys(%{$cathash})) { 20615: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item); 20616: if ($cathash->{$item} ne $env{'form.'.$item}) { 20617: $reorderings{$item} = 1; 20618: $domconfig{'coursecategories'}{'cats'}{$item} = $env{'form.'.$item}; 20619: } 20620: if ($env{'form.addcategory_name_'.$item} ne '') { 20621: my $newcat = $env{'form.addcategory_name_'.$item}; 20622: my $newdepth = $depth+1; 20623: my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth; 20624: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos_'.$item}; 20625: $adds{$newitem} = 1; 20626: } 20627: if ($env{'form.subcat_'.$item} ne '') { 20628: my $newcat = $env{'form.subcat_'.$item}; 20629: my $newdepth = $depth+1; 20630: my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth; 20631: $domconfig{'coursecategories'}{'cats'}{$newitem} = 0; 20632: $adds{$newitem} = 1; 20633: } 20634: } 20635: } 20636: if ($env{'form.instcode'} eq '1') { 20637: if (ref($cathash) eq 'HASH') { 20638: my $newitem = 'instcode::0'; 20639: if ($cathash->{$newitem} eq '') { 20640: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'}; 20641: $adds{$newitem} = 1; 20642: } 20643: } else { 20644: my $newitem = 'instcode::0'; 20645: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'}; 20646: $adds{$newitem} = 1; 20647: } 20648: } 20649: if ($env{'form.communities'} eq '1') { 20650: if (ref($cathash) eq 'HASH') { 20651: my $newitem = 'communities::0'; 20652: if ($cathash->{$newitem} eq '') { 20653: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.communities_pos'}; 20654: $adds{$newitem} = 1; 20655: } 20656: } else { 20657: my $newitem = 'communities::0'; 20658: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.communities_pos'}; 20659: $adds{$newitem} = 1; 20660: } 20661: } 20662: if ($env{'form.placement'} eq '1') { 20663: if (ref($cathash) eq 'HASH') { 20664: my $newitem = 'placement::0'; 20665: if ($cathash->{$newitem} eq '') { 20666: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'}; 20667: $adds{$newitem} = 1; 20668: } 20669: } else { 20670: my $newitem = 'placement::0'; 20671: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'}; 20672: $adds{$newitem} = 1; 20673: } 20674: } 20675: if ($env{'form.addcategory_name'} ne '') { 20676: if (($env{'form.addcategory_name'} ne 'instcode') && 20677: ($env{'form.addcategory_name'} ne 'communities') && 20678: ($env{'form.addcategory_name'} ne 'placement')) { 20679: my $newitem = &escape($env{'form.addcategory_name'}).'::0'; 20680: $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'}; 20681: $adds{$newitem} = 1; 20682: } 20683: } 20684: my $putresult; 20685: if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { 20686: if (keys(%deletions) > 0) { 20687: foreach my $key (keys(%deletions)) { 20688: if ($predelallitems{$key} ne '') { 20689: $sort_by_deltrail{$predelallitems{$key}} = $predeltrails[$predelallitems{$key}]; 20690: } 20691: } 20692: } 20693: my (@chkcats,@chktrails,%chkallitems); 20694: &Apache::loncommon::extract_categories($domconfig{'coursecategories'}{'cats'},\@chkcats,\@chktrails,\%chkallitems); 20695: if (ref($chkcats[0]) eq 'ARRAY') { 20696: my $depth = 0; 20697: my $chg = 0; 20698: for (my $i=0; $i<@{$chkcats[0]}; $i++) { 20699: my $name = $chkcats[0][$i]; 20700: my $item; 20701: if ($name eq '') { 20702: $chg ++; 20703: } else { 20704: $item = &escape($name).'::0'; 20705: if ($chg) { 20706: $domconfig{'coursecategories'}{'cats'}{$item} -= $chg; 20707: } 20708: $depth ++; 20709: &recurse_check(\@chkcats,$domconfig{'coursecategories'}{'cats'},$depth,$name); 20710: $depth --; 20711: } 20712: } 20713: } 20714: } 20715: if ((keys(%changes) > 0) || (keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { 20716: $putresult = &Apache::lonnet::put_dom('configuration',\%domconfig,$dom); 20717: if ($putresult eq 'ok') { 20718: my %title = ( 20719: togglecats => 'Show/Hide a course in catalog', 20720: categorize => 'Assign a category to a course', 20721: togglecatscomm => 'Show/Hide a community in catalog', 20722: categorizecomm => 'Assign a category to a community', 20723: ); 20724: my %level = ( 20725: dom => 'set in Domain ("Modify Course/Community")', 20726: crs => 'set in Course ("Course Configuration")', 20727: comm => 'set in Community ("Community Configuration")', 20728: none => 'No catalog', 20729: std => 'Standard catalog', 20730: domonly => 'Domain-only catalog', 20731: codesrch => 'Code search form', 20732: ); 20733: $resulttext = &mt('Changes made:').'<ul>'; 20734: if ($changes{'togglecats'}) { 20735: $resulttext .= '<li>'.&mt("$title{'togglecats'} $level{$env{'form.togglecats'}}").'</li>'; 20736: } 20737: if ($changes{'categorize'}) { 20738: $resulttext .= '<li>'.&mt("$title{'categorize'} $level{$env{'form.categorize'}}").'</li>'; 20739: } 20740: if ($changes{'togglecatscomm'}) { 20741: $resulttext .= '<li>'.&mt("$title{'togglecatscomm'} $level{$env{'form.togglecatscomm'}}").'</li>'; 20742: } 20743: if ($changes{'categorizecomm'}) { 20744: $resulttext .= '<li>'.&mt("$title{'categorizecomm'} $level{$env{'form.categorizecomm'}}").'</li>'; 20745: } 20746: if ($changes{'unauth'}) { 20747: $resulttext .= '<li>'.&mt('Catalog type for unauthenticated users set to "'.$level{$env{'form.coursecat_unauth'}}.'"').'</li>'; 20748: } 20749: if ($changes{'auth'}) { 20750: $resulttext .= '<li>'.&mt('Catalog type for authenticated users set to "'.$level{$env{'form.coursecat_auth'}}.'"').'</li>'; 20751: } 20752: if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { 20753: my $cathash; 20754: if (ref($domconfig{'coursecategories'}) eq 'HASH') { 20755: $cathash = $domconfig{'coursecategories'}{'cats'}; 20756: } else { 20757: $cathash = {}; 20758: } 20759: my (@cats,@trails,%allitems); 20760: &Apache::loncommon::extract_categories($cathash,\@cats,\@trails,\%allitems); 20761: if (keys(%deletions) > 0) { 20762: $resulttext .= '<li>'.&mt('Deleted categories:').'<ul>'; 20763: foreach my $predeltrail (sort {$a <=> $b } (keys(%sort_by_deltrail))) { 20764: $resulttext .= '<li>'.$predeltrails[$predeltrail].'</li>'; 20765: } 20766: $resulttext .= '</ul></li>'; 20767: } 20768: if (keys(%reorderings) > 0) { 20769: my %sort_by_trail; 20770: $resulttext .= '<li>'.&mt('Reordered categories:').'<ul>'; 20771: foreach my $key (keys(%reorderings)) { 20772: if ($allitems{$key} ne '') { 20773: $sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}]; 20774: } 20775: } 20776: foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) { 20777: $resulttext .= '<li>'.$trails[$trail].'</li>'; 20778: } 20779: $resulttext .= '</ul></li>'; 20780: } 20781: if (keys(%adds) > 0) { 20782: my %sort_by_trail; 20783: $resulttext .= '<li>'.&mt('Added categories:').'<ul>'; 20784: foreach my $key (keys(%adds)) { 20785: if ($allitems{$key} ne '') { 20786: $sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}]; 20787: } 20788: } 20789: foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) { 20790: $resulttext .= '<li>'.$trails[$trail].'</li>'; 20791: } 20792: $resulttext .= '</ul></li>'; 20793: } 20794: &Apache::lonnet::do_cache_new('cats',$dom,$cathash,3600); 20795: if (ref($lastactref) eq 'HASH') { 20796: $lastactref->{'cats'} = 1; 20797: } 20798: } 20799: $resulttext .= '</ul>'; 20800: if ($changes{'unauth'} || $changes{'auth'}) { 20801: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); 20802: if ($changes{'auth'}) { 20803: $domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'}; 20804: } 20805: if ($changes{'unauth'}) { 20806: $domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'}; 20807: } 20808: my $cachetime = 24*60*60; 20809: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 20810: if (ref($lastactref) eq 'HASH') { 20811: $lastactref->{'domdefaults'} = 1; 20812: } 20813: } 20814: } else { 20815: $resulttext = '<span class="LC_error">'. 20816: &mt('An error occurred: [_1]',$putresult).'</span>'; 20817: } 20818: } else { 20819: $resulttext = &mt('No changes made to course and community categories'); 20820: } 20821: return $resulttext; 20822: } 20823: 20824: sub modify_serverstatuses { 20825: my ($dom,%domconfig) = @_; 20826: my ($resulttext,%changes,%currserverstatus,%newserverstatus); 20827: if (ref($domconfig{'serverstatuses'}) eq 'HASH') { 20828: %currserverstatus = %{$domconfig{'serverstatuses'}}; 20829: } 20830: my @pages = &serverstatus_pages(); 20831: foreach my $type (@pages) { 20832: $newserverstatus{$type}{'namedusers'} = ''; 20833: $newserverstatus{$type}{'machines'} = ''; 20834: if (defined($env{'form.'.$type.'_namedusers'})) { 20835: my @users = split(/,/,$env{'form.'.$type.'_namedusers'}); 20836: my @okusers; 20837: foreach my $user (@users) { 20838: my ($uname,$udom) = split(/:/,$user); 20839: if (($udom =~ /^$match_domain$/) && 20840: (&Apache::lonnet::domain($udom)) && 20841: ($uname =~ /^$match_username$/)) { 20842: if (!grep(/^\Q$user\E/,@okusers)) { 20843: push(@okusers,$user); 20844: } 20845: } 20846: } 20847: if (@okusers > 0) { 20848: @okusers = sort(@okusers); 20849: $newserverstatus{$type}{'namedusers'} = join(',',@okusers); 20850: } 20851: } 20852: if (defined($env{'form.'.$type.'_machines'})) { 20853: my @machines = split(/,/,$env{'form.'.$type.'_machines'}); 20854: my @okmachines; 20855: foreach my $ip (@machines) { 20856: my @parts = split(/\./,$ip); 20857: next if (@parts < 4); 20858: my $badip = 0; 20859: for (my $i=0; $i<4; $i++) { 20860: if (!(($parts[$i] >= 0) && ($parts[$i] <= 255))) { 20861: $badip = 1; 20862: last; 20863: } 20864: } 20865: if (!$badip) { 20866: push(@okmachines,$ip); 20867: } 20868: } 20869: @okmachines = sort(@okmachines); 20870: $newserverstatus{$type}{'machines'} = join(',',@okmachines); 20871: } 20872: } 20873: my %serverstatushash = ( 20874: serverstatuses => \%newserverstatus, 20875: ); 20876: foreach my $type (@pages) { 20877: foreach my $setting ('namedusers','machines') { 20878: my (@current,@new); 20879: if (ref($currserverstatus{$type}) eq 'HASH') { 20880: if ($currserverstatus{$type}{$setting} ne '') { 20881: @current = split(/,/,$currserverstatus{$type}{$setting}); 20882: } 20883: } 20884: if ($newserverstatus{$type}{$setting} ne '') { 20885: @new = split(/,/,$newserverstatus{$type}{$setting}); 20886: } 20887: if (@current > 0) { 20888: if (@new > 0) { 20889: foreach my $item (@current) { 20890: if (!grep(/^\Q$item\E$/,@new)) { 20891: $changes{$type}{$setting} = 1; 20892: last; 20893: } 20894: } 20895: foreach my $item (@new) { 20896: if (!grep(/^\Q$item\E$/,@current)) { 20897: $changes{$type}{$setting} = 1; 20898: last; 20899: } 20900: } 20901: } else { 20902: $changes{$type}{$setting} = 1; 20903: } 20904: } elsif (@new > 0) { 20905: $changes{$type}{$setting} = 1; 20906: } 20907: } 20908: } 20909: if (keys(%changes) > 0) { 20910: my $titles= &LONCAPA::lonauthcgi::serverstatus_titles(); 20911: my $putresult = &Apache::lonnet::put_dom('configuration', 20912: \%serverstatushash,$dom); 20913: if ($putresult eq 'ok') { 20914: $resulttext .= &mt('Changes made:').'<ul>'; 20915: foreach my $type (@pages) { 20916: if (ref($changes{$type}) eq 'HASH') { 20917: $resulttext .= '<li>'.$titles->{$type}.'<ul>'; 20918: if ($changes{$type}{'namedusers'}) { 20919: if ($newserverstatus{$type}{'namedusers'} eq '') { 20920: $resulttext .= '<li>'.&mt("Access terminated for all specific (named) users").'</li>'."\n"; 20921: } else { 20922: $resulttext .= '<li>'.&mt("Access available for the following specified users: ").$newserverstatus{$type}{'namedusers'}.'</li>'."\n"; 20923: } 20924: } 20925: if ($changes{$type}{'machines'}) { 20926: if ($newserverstatus{$type}{'machines'} eq '') { 20927: $resulttext .= '<li>'.&mt("Access terminated for all specific IP addresses").'</li>'."\n"; 20928: } else { 20929: $resulttext .= '<li>'.&mt("Access available for the following specified IP addresses: ").$newserverstatus{$type}{'machines'}.'</li>'."\n"; 20930: } 20931: 20932: } 20933: $resulttext .= '</ul></li>'; 20934: } 20935: } 20936: $resulttext .= '</ul>'; 20937: } else { 20938: $resulttext = '<span class="LC_error">'. 20939: &mt('An error occurred saving access settings for server status pages: [_1].',$putresult).'</span>'; 20940: 20941: } 20942: } else { 20943: $resulttext = &mt('No changes made to access to server status pages'); 20944: } 20945: return $resulttext; 20946: } 20947: 20948: sub modify_helpsettings { 20949: my ($r,$dom,$confname,$lastactref,%domconfig) = @_; 20950: my ($resulttext,$errors,%changes,%helphash); 20951: my %defaultchecked = ('submitbugs' => 'on'); 20952: my @offon = ('off','on'); 20953: my @toggles = ('submitbugs'); 20954: my %current = ('submitbugs' => '', 20955: 'adhoc' => {}, 20956: ); 20957: if (ref($domconfig{'helpsettings'}) eq 'HASH') { 20958: %current = %{$domconfig{'helpsettings'}}; 20959: } 20960: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 20961: foreach my $item (@toggles) { 20962: if ($defaultchecked{$item} eq 'on') { 20963: if ($current{$item} eq '') { 20964: if ($env{'form.'.$item} eq '0') { 20965: $changes{$item} = 1; 20966: } 20967: } elsif ($current{$item} ne $env{'form.'.$item}) { 20968: $changes{$item} = 1; 20969: } 20970: } elsif ($defaultchecked{$item} eq 'off') { 20971: if ($current{$item} eq '') { 20972: if ($env{'form.'.$item} eq '1') { 20973: $changes{$item} = 1; 20974: } 20975: } elsif ($current{$item} ne $env{'form.'.$item}) { 20976: $changes{$item} = 1; 20977: } 20978: } 20979: if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) { 20980: $helphash{'helpsettings'}{$item} = $env{'form.'.$item}; 20981: } 20982: } 20983: my $maxnum = $env{'form.helproles_maxnum'}; 20984: my $confname = $dom.'-domainconfig'; 20985: my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_'); 20986: my (@allpos,%newsettings,%changedprivs,$newrole); 20987: my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); 20988: my @accesstypes = ('all','dh','da','none','status','inc','exc'); 20989: my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']); 20990: my %lt = &Apache::lonlocal::texthash( 20991: s => 'system', 20992: d => 'domain', 20993: order => 'Display order', 20994: access => 'Role usage', 20995: all => 'All with domain helpdesk or helpdesk assistant role', 20996: dh => 'All with domain helpdesk role', 20997: da => 'All with domain helpdesk assistant role', 20998: none => 'None', 20999: status => 'Determined based on institutional status', 21000: inc => 'Include all, but exclude specific personnel', 21001: exc => 'Exclude all, but include specific personnel', 21002: ); 21003: for (my $num=0; $num<=$maxnum; $num++) { 21004: my ($prefix,$identifier,$rolename,%curr); 21005: if ($num == $maxnum) { 21006: next unless ($env{'form.newcusthelp'} == $maxnum); 21007: $identifier = 'custhelp'.$num; 21008: $prefix = 'helproles_'.$num; 21009: $rolename = $env{'form.custhelpname'.$num}; 21010: $rolename=~s/[^A-Za-z0-9]//gs; 21011: next if ($rolename eq ''); 21012: next if (exists($existing{'rolesdef_'.$rolename})); 21013: my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier); 21014: my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'}, 21015: $newprivs{'c'},$confname,$dom); 21016: if ($result ne 'ok') { 21017: $errors .= '<li><span class="LC_error">'. 21018: &mt('An error occurred storing the new custom role: [_1]', 21019: $result).'</span></li>'; 21020: next; 21021: } else { 21022: $changedprivs{$rolename} = \%newprivs; 21023: $newrole = $rolename; 21024: } 21025: } else { 21026: $prefix = 'helproles_'.$num; 21027: $rolename = $env{'form.'.$prefix}; 21028: next if ($rolename eq ''); 21029: next unless (exists($existing{'rolesdef_'.$rolename})); 21030: $identifier = 'custhelp'.$num; 21031: my %newprivs = &Apache::lonuserutils::custom_role_update($rolename,$identifier); 21032: my %currprivs; 21033: ($currprivs{'s'},$currprivs{'d'},$currprivs{'c'}) = 21034: split(/\_/,$existing{'rolesdef_'.$rolename}); 21035: foreach my $level ('c','d','s') { 21036: if ($newprivs{$level} ne $currprivs{$level}) { 21037: my $result = &Apache::lonnet::definerole($rolename,$newprivs{'s'},$newprivs{'d'}, 21038: $newprivs{'c'},$confname,$dom); 21039: if ($result ne 'ok') { 21040: $errors .= '<li><span class="LC_error">'. 21041: &mt('An error occurred storing privileges for existing role [_1]: [_2]', 21042: $rolename,$result).'</span></li>'; 21043: } else { 21044: $changedprivs{$rolename} = \%newprivs; 21045: } 21046: last; 21047: } 21048: } 21049: if (ref($current{'adhoc'}) eq 'HASH') { 21050: if (ref($current{'adhoc'}{$rolename}) eq 'HASH') { 21051: %curr = %{$current{'adhoc'}{$rolename}}; 21052: } 21053: } 21054: } 21055: my $newpos = $env{'form.'.$prefix.'_pos'}; 21056: $newpos =~ s/\D+//g; 21057: $allpos[$newpos] = $rolename; 21058: my $newdesc = $env{'form.'.$prefix.'_desc'}; 21059: $helphash{'helpsettings'}{'adhoc'}{$rolename}{'desc'} = $newdesc; 21060: if ($curr{'desc'}) { 21061: if ($curr{'desc'} ne $newdesc) { 21062: $changes{'customrole'}{$rolename}{'desc'} = 1; 21063: $newsettings{$rolename}{'desc'} = $newdesc; 21064: } 21065: } elsif ($newdesc ne '') { 21066: $changes{'customrole'}{$rolename}{'desc'} = 1; 21067: $newsettings{$rolename}{'desc'} = $newdesc; 21068: } 21069: my $access = $env{'form.'.$prefix.'_access'}; 21070: if (grep(/^\Q$access\E$/,@accesstypes)) { 21071: $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = $access; 21072: if ($access eq 'status') { 21073: my @statuses = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_status'); 21074: if (scalar(@statuses) == 0) { 21075: $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'none'; 21076: } else { 21077: my (@shownstatus,$numtypes); 21078: $helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = []; 21079: if (ref($types) eq 'ARRAY') { 21080: $numtypes = scalar(@{$types}); 21081: foreach my $type (sort(@statuses)) { 21082: if ($type eq 'default') { 21083: push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type); 21084: } elsif (grep(/^\Q$type\E$/,@{$types})) { 21085: push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$type); 21086: push(@shownstatus,$usertypes->{$type}); 21087: } 21088: } 21089: } 21090: if (grep(/^default$/,@statuses)) { 21091: push(@shownstatus,$othertitle); 21092: } 21093: if (scalar(@shownstatus) == 1+$numtypes) { 21094: $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'} = 'all'; 21095: delete($helphash{'helpsettings'}{'adhoc'}{$rolename}{'status'}); 21096: } else { 21097: $newsettings{$rolename}{'status'} = join(' '.&mt('or').' ',@shownstatus); 21098: if (ref($curr{'status'}) eq 'ARRAY') { 21099: my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access}); 21100: if (@diffs) { 21101: $changes{'customrole'}{$rolename}{$access} = 1; 21102: } 21103: } elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) { 21104: $changes{'customrole'}{$rolename}{$access} = 1; 21105: } 21106: } 21107: } 21108: } elsif (($access eq 'inc') || ($access eq 'exc')) { 21109: my @personnel = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_staff_'.$access); 21110: my @newspecstaff; 21111: $helphash{'helpsettings'}{'adhoc'}{$rolename}{$access} = []; 21112: foreach my $person (sort(@personnel)) { 21113: if ($domhelpdesk{$person}) { 21114: push(@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}},$person); 21115: } 21116: } 21117: if (ref($curr{$access}) eq 'ARRAY') { 21118: my @diffs = &Apache::loncommon::compare_arrays($helphash{'helpsettings'}{'adhoc'}{$rolename}{$access},$curr{$access}); 21119: if (@diffs) { 21120: $changes{'customrole'}{$rolename}{$access} = 1; 21121: } 21122: } elsif (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) { 21123: $changes{'customrole'}{$rolename}{$access} = 1; 21124: } 21125: foreach my $person (@{$helphash{'helpsettings'}{'adhoc'}{$rolename}{$access}}) { 21126: my ($uname,$udom) = split(/:/,$person); 21127: push(@newspecstaff,&Apache::loncommon::aboutmewrapper(&Apache::loncommon::plainname($uname,$udom,'lastname'),$uname,$udom)); 21128: } 21129: $newsettings{$rolename}{$access} = join(', ',sort(@newspecstaff)); 21130: } 21131: } else { 21132: $helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}= 'all'; 21133: } 21134: unless ($curr{'access'} eq $access) { 21135: $changes{'customrole'}{$rolename}{'access'} = 1; 21136: $newsettings{$rolename}{'access'} = $lt{$helphash{'helpsettings'}{'adhoc'}{$rolename}{'access'}}; 21137: } 21138: } 21139: if (@allpos > 0) { 21140: my $idx = 0; 21141: foreach my $rolename (@allpos) { 21142: if ($rolename ne '') { 21143: $helphash{'helpsettings'}{'adhoc'}{$rolename}{'order'} = $idx; 21144: if (ref($current{'adhoc'}) eq 'HASH') { 21145: if (ref($current{'adhoc'}{$rolename}) eq 'HASH') { 21146: if ($current{'adhoc'}{$rolename}{'order'} ne $idx) { 21147: $changes{'customrole'}{$rolename}{'order'} = 1; 21148: $newsettings{$rolename}{'order'} = $idx+1; 21149: } 21150: } 21151: } 21152: $idx ++; 21153: } 21154: } 21155: } 21156: my $putresult; 21157: if (keys(%changes) > 0) { 21158: $putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom); 21159: if ($putresult eq 'ok') { 21160: if (ref($helphash{'helpsettings'}) eq 'HASH') { 21161: $domdefaults{'submitbugs'} = $helphash{'helpsettings'}{'submitbugs'}; 21162: if (ref($helphash{'helpsettings'}{'adhoc'}) eq 'HASH') { 21163: $domdefaults{'adhocroles'} = $helphash{'helpsettings'}{'adhoc'}; 21164: } 21165: } 21166: my $cachetime = 24*60*60; 21167: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 21168: if (ref($lastactref) eq 'HASH') { 21169: $lastactref->{'domdefaults'} = 1; 21170: } 21171: } else { 21172: $errors .= '<li><span class="LC_error">'. 21173: &mt('An error occurred storing the settings: [_1]', 21174: $putresult).'</span></li>'; 21175: } 21176: } 21177: if ((keys(%changes) && ($putresult eq 'ok')) || (keys(%changedprivs))) { 21178: $resulttext = &mt('Changes made:').'<ul>'; 21179: my (%shownprivs,@levelorder); 21180: @levelorder = ('c','d','s'); 21181: if ((keys(%changes)) && ($putresult eq 'ok')) { 21182: foreach my $item (sort(keys(%changes))) { 21183: if ($item eq 'submitbugs') { 21184: $resulttext .= '<li>'.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".', 21185: &Apache::loncommon::modal_link('http://bugs.loncapa.org', 21186: &mt('LON-CAPA bug tracker'),600,500)).'</li>'; 21187: } elsif ($item eq 'customrole') { 21188: if (ref($changes{'customrole'}) eq 'HASH') { 21189: my @keyorder = ('order','desc','access','status','exc','inc'); 21190: my %keytext = &Apache::lonlocal::texthash( 21191: order => 'Order', 21192: desc => 'Role description', 21193: access => 'Role usage', 21194: status => 'Allowed institutional types', 21195: exc => 'Allowed personnel', 21196: inc => 'Disallowed personnel', 21197: ); 21198: foreach my $role (sort(keys(%{$changes{'customrole'}}))) { 21199: if (ref($changes{'customrole'}{$role}) eq 'HASH') { 21200: if ($role eq $newrole) { 21201: $resulttext .= '<li>'.&mt('New custom role added: [_1]', 21202: $role).'<ul>'; 21203: } else { 21204: $resulttext .= '<li>'.&mt('Existing custom role modified: [_1]', 21205: $role).'<ul>'; 21206: } 21207: foreach my $key (@keyorder) { 21208: if ($changes{'customrole'}{$role}{$key}) { 21209: $resulttext .= '<li>'.&mt("[_1] set to: [_2]", 21210: $keytext{$key},$newsettings{$role}{$key}). 21211: '</li>'; 21212: } 21213: } 21214: if (ref($changedprivs{$role}) eq 'HASH') { 21215: $shownprivs{$role} = 1; 21216: $resulttext .= '<li>'.&mt('Privileges set to :').'<ul>'; 21217: foreach my $level (@levelorder) { 21218: foreach my $item (split(/\:/,$changedprivs{$role}{$level})) { 21219: next if ($item eq ''); 21220: my ($priv) = split(/\&/,$item,2); 21221: if (&Apache::lonnet::plaintext($priv)) { 21222: $resulttext .= '<li>'.&Apache::lonnet::plaintext($priv); 21223: unless ($level eq 'c') { 21224: $resulttext .= ' ('.$lt{$level}.')'; 21225: } 21226: $resulttext .= '</li>'; 21227: } 21228: } 21229: } 21230: $resulttext .= '</ul>'; 21231: } 21232: $resulttext .= '</ul></li>'; 21233: } 21234: } 21235: } 21236: } 21237: } 21238: } 21239: if (keys(%changedprivs)) { 21240: foreach my $role (sort(keys(%changedprivs))) { 21241: unless ($shownprivs{$role}) { 21242: $resulttext .= '<li>'.&mt('Existing custom role modified: [_1]', 21243: $role).'<ul>'. 21244: '<li>'.&mt('Privileges set to :').'<ul>'; 21245: foreach my $level (@levelorder) { 21246: foreach my $item (split(/\:/,$changedprivs{$role}{$level})) { 21247: next if ($item eq ''); 21248: my ($priv) = split(/\&/,$item,2); 21249: if (&Apache::lonnet::plaintext($priv)) { 21250: $resulttext .= '<li>'.&Apache::lonnet::plaintext($priv); 21251: unless ($level eq 'c') { 21252: $resulttext .= ' ('.$lt{$level}.')'; 21253: } 21254: $resulttext .= '</li>'; 21255: } 21256: } 21257: } 21258: $resulttext .= '</ul></li></ul></li>'; 21259: } 21260: } 21261: } 21262: $resulttext .= '</ul>'; 21263: } else { 21264: $resulttext = &mt('No changes made to help settings'); 21265: } 21266: if ($errors) { 21267: $resulttext .= '<br />'.&mt('The following errors occurred: ').'<ul>'. 21268: $errors.'</ul>'; 21269: } 21270: return $resulttext; 21271: } 21272: 21273: sub modify_coursedefaults { 21274: my ($dom,$lastactref,%domconfig) = @_; 21275: my ($resulttext,$errors,%changes,%defaultshash); 21276: my %defaultchecked = ( 21277: 'canuse_pdfforms' => 'off', 21278: 'uselcmath' => 'on', 21279: 'usejsme' => 'on', 21280: 'inline_chem' => 'on', 21281: 'ltiauth' => 'off', 21282: ); 21283: my @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem','ltiauth'); 21284: my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial', 21285: 'uploadquota_community','uploadquota_textbook','uploadquota_placement', 21286: 'mysqltables_official','mysqltables_unofficial','mysqltables_community', 21287: 'mysqltables_textbook','mysqltables_placement'); 21288: my @types = ('official','unofficial','community','textbook','placement'); 21289: my %staticdefaults = ( 21290: anonsurvey_threshold => 10, 21291: uploadquota => 500, 21292: postsubmit => 60, 21293: mysqltables => 172800, 21294: ); 21295: my %texoptions = ( 21296: MathJax => 'MathJax', 21297: mimetex => &mt('Convert to Images'), 21298: tth => &mt('TeX to HTML'), 21299: ); 21300: $defaultshash{'coursedefaults'} = {}; 21301: 21302: if (ref($domconfig{'coursedefaults'}) ne 'HASH') { 21303: if ($domconfig{'coursedefaults'} eq '') { 21304: $domconfig{'coursedefaults'} = {}; 21305: } 21306: } 21307: 21308: if (ref($domconfig{'coursedefaults'}) eq 'HASH') { 21309: foreach my $item (@toggles) { 21310: if ($defaultchecked{$item} eq 'on') { 21311: if (($domconfig{'coursedefaults'}{$item} eq '') && 21312: ($env{'form.'.$item} eq '0')) { 21313: $changes{$item} = 1; 21314: } elsif ($domconfig{'coursedefaults'}{$item} ne $env{'form.'.$item}) { 21315: $changes{$item} = 1; 21316: } 21317: } elsif ($defaultchecked{$item} eq 'off') { 21318: if (($domconfig{'coursedefaults'}{$item} eq '') && 21319: ($env{'form.'.$item} eq '1')) { 21320: $changes{$item} = 1; 21321: } elsif ($domconfig{'coursedefaults'}{$item} ne $env{'form.'.$item}) { 21322: $changes{$item} = 1; 21323: } 21324: } 21325: $defaultshash{'coursedefaults'}{$item} = $env{'form.'.$item}; 21326: } 21327: foreach my $item (@numbers) { 21328: my ($currdef,$newdef); 21329: $newdef = $env{'form.'.$item}; 21330: if ($item eq 'anonsurvey_threshold') { 21331: $currdef = $domconfig{'coursedefaults'}{$item}; 21332: $newdef =~ s/\D//g; 21333: if ($newdef eq '' || $newdef < 1) { 21334: $newdef = 1; 21335: } 21336: $defaultshash{'coursedefaults'}{$item} = $newdef; 21337: } else { 21338: my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/); 21339: if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') { 21340: $currdef = $domconfig{'coursedefaults'}{$setting}{$type}; 21341: } 21342: $newdef =~ s/[^\w.\-]//g; 21343: $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef; 21344: } 21345: if ($currdef ne $newdef) { 21346: if ($item eq 'anonsurvey_threshold') { 21347: unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) { 21348: $changes{$item} = 1; 21349: } 21350: } elsif ($item =~ /^(uploadquota|mysqltables)_/) { 21351: my $setting = $1; 21352: unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) { 21353: $changes{$setting} = 1; 21354: } 21355: } 21356: } 21357: } 21358: my $texengine; 21359: if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) { 21360: $texengine = $env{'form.texengine'}; 21361: my $currdef = $domconfig{'coursedefaults'}{'texengine'}; 21362: if ($currdef eq '') { 21363: unless ($texengine eq $Apache::lonnet::deftex) { 21364: $changes{'texengine'} = 1; 21365: } 21366: } elsif ($currdef ne $texengine) { 21367: $changes{'texengine'} = 1; 21368: } 21369: } 21370: if ($texengine ne '') { 21371: $defaultshash{'coursedefaults'}{'texengine'} = $texengine; 21372: } 21373: my $currclone = $domconfig{'coursedefaults'}{'canclone'}; 21374: my @currclonecode; 21375: if (ref($currclone) eq 'HASH') { 21376: if (ref($currclone->{'instcode'}) eq 'ARRAY') { 21377: @currclonecode = @{$currclone->{'instcode'}}; 21378: } 21379: } 21380: my $newclone; 21381: if ($env{'form.canclone'} =~ /^(none|domain|instcode)$/) { 21382: $newclone = $env{'form.canclone'}; 21383: } 21384: if ($newclone eq 'instcode') { 21385: my @newcodes = &Apache::loncommon::get_env_multiple('form.clonecode'); 21386: my (%codedefaults,@code_order,@clonecode); 21387: &Apache::lonnet::auto_instcode_defaults($dom,\%codedefaults, 21388: \@code_order); 21389: foreach my $item (@code_order) { 21390: if (grep(/^\Q$item\E$/,@newcodes)) { 21391: push(@clonecode,$item); 21392: } 21393: } 21394: if (@clonecode) { 21395: $defaultshash{'coursedefaults'}{'canclone'} = { $newclone => \@clonecode }; 21396: my @diffs = &Apache::loncommon::compare_arrays(\@currclonecode,\@clonecode); 21397: if (@diffs) { 21398: $changes{'canclone'} = 1; 21399: } 21400: } else { 21401: $newclone eq ''; 21402: } 21403: } elsif ($newclone ne '') { 21404: $defaultshash{'coursedefaults'}{'canclone'} = $newclone; 21405: } 21406: if ($newclone ne $currclone) { 21407: $changes{'canclone'} = 1; 21408: } 21409: my %credits; 21410: foreach my $type (@types) { 21411: unless ($type eq 'community') { 21412: $credits{$type} = $env{'form.'.$type.'_credits'}; 21413: $credits{$type} =~ s/[^\d.]+//g; 21414: } 21415: } 21416: if ((ref($domconfig{'coursedefaults'}{'coursecredits'}) ne 'HASH') && 21417: ($env{'form.coursecredits'} eq '1')) { 21418: $changes{'coursecredits'} = 1; 21419: foreach my $type (keys(%credits)) { 21420: $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type}; 21421: } 21422: } else { 21423: if ($env{'form.coursecredits'} eq '1') { 21424: foreach my $type (@types) { 21425: unless ($type eq 'community') { 21426: if ($domconfig{'coursedefaults'}{'coursecredits'}{$type} ne $credits{$type}) { 21427: $changes{'coursecredits'} = 1; 21428: } 21429: $defaultshash{'coursedefaults'}{'coursecredits'}{$type} = $credits{$type}; 21430: } 21431: } 21432: } elsif (ref($domconfig{'coursedefaults'}{'coursecredits'}) eq 'HASH') { 21433: foreach my $type (@types) { 21434: unless ($type eq 'community') { 21435: if ($domconfig{'coursedefaults'}{'coursecredits'}{$type}) { 21436: $changes{'coursecredits'} = 1; 21437: last; 21438: } 21439: } 21440: } 21441: } 21442: } 21443: if ($env{'form.postsubmit'} eq '1') { 21444: $defaultshash{'coursedefaults'}{'postsubmit'}{'client'} = 'on'; 21445: my %currtimeout; 21446: if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') { 21447: if ($domconfig{'coursedefaults'}{'postsubmit'}{'client'} eq 'off') { 21448: $changes{'postsubmit'} = 1; 21449: } 21450: if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { 21451: %currtimeout = %{$domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}}; 21452: } 21453: } else { 21454: $changes{'postsubmit'} = 1; 21455: } 21456: foreach my $type (@types) { 21457: my $timeout = $env{'form.'.$type.'_timeout'}; 21458: $timeout =~ s/\D//g; 21459: if ($timeout == $staticdefaults{'postsubmit'}) { 21460: $timeout = ''; 21461: } elsif (($timeout eq '') || ($timeout =~ /^0+$/)) { 21462: $timeout = '0'; 21463: } 21464: unless ($timeout eq '') { 21465: $defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}{$type} = $timeout; 21466: } 21467: if (exists($currtimeout{$type})) { 21468: if ($timeout ne $currtimeout{$type}) { 21469: $changes{'postsubmit'} = 1; 21470: } 21471: } elsif ($timeout ne '') { 21472: $changes{'postsubmit'} = 1; 21473: } 21474: } 21475: } else { 21476: $defaultshash{'coursedefaults'}{'postsubmit'}{'client'} = 'off'; 21477: if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') { 21478: if ($domconfig{'coursedefaults'}{'postsubmit'}{'client'} eq 'on') { 21479: $changes{'postsubmit'} = 1; 21480: } 21481: } else { 21482: $changes{'postsubmit'} = 1; 21483: } 21484: } 21485: } 21486: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, 21487: $dom); 21488: if ($putresult eq 'ok') { 21489: if (keys(%changes) > 0) { 21490: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 21491: if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) || 21492: ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) || 21493: ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) || 21494: ($changes{'inline_chem'}) || ($changes{'ltiauth'})) { 21495: foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine','ltiauth') { 21496: if ($changes{$item}) { 21497: $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item}; 21498: } 21499: } 21500: if ($changes{'coursecredits'}) { 21501: if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') { 21502: foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'coursecredits'}})) { 21503: $domdefaults{$type.'credits'} = 21504: $defaultshash{'coursedefaults'}{'coursecredits'}{$type}; 21505: } 21506: } 21507: } 21508: if ($changes{'postsubmit'}) { 21509: if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') { 21510: $domdefaults{'postsubmit'} = $defaultshash{'coursedefaults'}{'postsubmit'}{'client'}; 21511: if (ref($defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { 21512: foreach my $type (keys(%{$defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}})) { 21513: $domdefaults{$type.'postsubtimeout'} = 21514: $defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; 21515: } 21516: } 21517: } 21518: } 21519: if ($changes{'uploadquota'}) { 21520: if (ref($defaultshash{'coursedefaults'}{'uploadquota'}) eq 'HASH') { 21521: foreach my $type (@types) { 21522: $domdefaults{$type.'quota'}=$defaultshash{'coursedefaults'}{'uploadquota'}{$type}; 21523: } 21524: } 21525: } 21526: if ($changes{'canclone'}) { 21527: if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') { 21528: if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') { 21529: my @clonecodes = @{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}}; 21530: if (@clonecodes) { 21531: $domdefaults{'canclone'} = join('+',@clonecodes); 21532: } 21533: } 21534: } else { 21535: $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'}; 21536: } 21537: } 21538: my $cachetime = 24*60*60; 21539: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 21540: if (ref($lastactref) eq 'HASH') { 21541: $lastactref->{'domdefaults'} = 1; 21542: } 21543: } 21544: $resulttext = &mt('Changes made:').'<ul>'; 21545: foreach my $item (sort(keys(%changes))) { 21546: if ($item eq 'canuse_pdfforms') { 21547: if ($env{'form.'.$item} eq '1') { 21548: $resulttext .= '<li>'.&mt("Course/Community users can create/upload PDF forms set to 'on'").'</li>'; 21549: } else { 21550: $resulttext .= '<li>'.&mt('Course/Community users can create/upload PDF forms set to "off"').'</li>'; 21551: } 21552: } elsif ($item eq 'uselcmath') { 21553: if ($env{'form.'.$item} eq '1') { 21554: $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>'; 21555: } else { 21556: $resulttext .= '<li>'.&mt('Math preview uses DragMath (Java), if supported by client OS.').'</li>'; 21557: } 21558: } elsif ($item eq 'usejsme') { 21559: if ($env{'form.'.$item} eq '1') { 21560: $resulttext .= '<li>'.&mt('Molecule editor uses JSME (HTML5), if supported by browser.').'</li>'; 21561: } else { 21562: $resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>'; 21563: } 21564: } elsif ($item eq 'inline_chem') { 21565: if ($env{'form.'.$item} eq '1') { 21566: $resulttext .= '<li>'.&mt('Chemical Reaction Response uses inline previewer').'</li>'; 21567: } else { 21568: $resulttext .= '<li>'.&mt('Chemical Reaction Response uses pop-up previewer').'</li>'; 21569: } 21570: } elsif ($item eq 'texengine') { 21571: if ($defaultshash{'coursedefaults'}{'texengine'} ne '') { 21572: $resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"', 21573: $texoptions{$defaultshash{'coursedefaults'}{'texengine'}}).'</li>'; 21574: } 21575: } elsif ($item eq 'anonsurvey_threshold') { 21576: $resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>'; 21577: } elsif ($item eq 'uploadquota') { 21578: if (ref($defaultshash{'coursedefaults'}{'uploadquota'}) eq 'HASH') { 21579: $resulttext .= '<li>'.&mt('Default quota for content uploaded to a course/community via Course Editor set as follows:').'<ul>'. 21580: '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'. 21581: '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'. 21582: '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'. 21583: '<li>'.&mt('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'placement'}.'</b>').'</li>'. 21584: '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'. 21585: '</ul>'. 21586: '</li>'; 21587: } else { 21588: $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>'; 21589: } 21590: } elsif ($item eq 'mysqltables') { 21591: if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') { 21592: $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'. 21593: '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'. 21594: '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'. 21595: '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'. 21596: '<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'. 21597: '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'. 21598: '</ul>'. 21599: '</li>'; 21600: } else { 21601: $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver remains default: [_1] s',$staticdefaults{'uploadquota'}).'</li>'; 21602: } 21603: } elsif ($item eq 'postsubmit') { 21604: if ($domdefaults{'postsubmit'} eq 'off') { 21605: $resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.'); 21606: } else { 21607: $resulttext .= '<li>'.&mt('Submit button(s) disabled on page after student makes submission').'; '; 21608: if (ref($defaultshash{'coursedefaults'}{'postsubmit'}) eq 'HASH') { 21609: $resulttext .= &mt('durations:').'<ul>'; 21610: foreach my $type (@types) { 21611: $resulttext .= '<li>'; 21612: my $timeout; 21613: if (ref($defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { 21614: $timeout = $defaultshash{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; 21615: } 21616: my $display; 21617: if ($timeout eq '0') { 21618: $display = &mt('unlimited'); 21619: } elsif ($timeout eq '') { 21620: $display = &mt('[quant,_1,second] (default)',$staticdefaults{'postsubmit'}); 21621: } else { 21622: $display = &mt('[quant,_1,second]',$timeout); 21623: } 21624: if ($type eq 'community') { 21625: $resulttext .= &mt('Communities'); 21626: } elsif ($type eq 'official') { 21627: $resulttext .= &mt('Official courses'); 21628: } elsif ($type eq 'unofficial') { 21629: $resulttext .= &mt('Unofficial courses'); 21630: } elsif ($type eq 'textbook') { 21631: $resulttext .= &mt('Textbook courses'); 21632: } elsif ($type eq 'placement') { 21633: $resulttext .= &mt('Placement tests'); 21634: } 21635: $resulttext .= ' -- '.$display.'</li>'; 21636: } 21637: $resulttext .= '</ul>'; 21638: } 21639: $resulttext .= '</li>'; 21640: } 21641: } elsif ($item eq 'coursecredits') { 21642: if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') { 21643: if (($domdefaults{'officialcredits'} eq '') && 21644: ($domdefaults{'unofficialcredits'} eq '') && 21645: ($domdefaults{'textbookcredits'} eq '')) { 21646: $resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>'; 21647: } else { 21648: $resulttext .= '<li>'.&mt('Student credits can be set per course by a Domain Coordinator, with the following defaults applying:').'<ul>'. 21649: '<li>'.&mt('Official courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'official'}).'</li>'. 21650: '<li>'.&mt('Unofficial courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'unofficial'}).'</li>'. 21651: '<li>'.&mt('Textbook courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'textbook'}).'</li>'. 21652: '</ul>'. 21653: '</li>'; 21654: } 21655: } else { 21656: $resulttext .= '<li>'.&mt('Student credits not in use for courses in this domain').'</li>'; 21657: } 21658: } elsif ($item eq 'canclone') { 21659: if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') { 21660: if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') { 21661: my $clonecodes = join(' '.&mt('and').' ',@{$defaultshash{'coursedefaults'}{'canclone'}{'instcode'}}); 21662: $resulttext .= '<li>'.&mt('By default, official courses can be cloned from existing courses with the same: [_1]','<b>'.$clonecodes.'</b>').'</li>'; 21663: } 21664: } elsif ($defaultshash{'coursedefaults'}{'canclone'} eq 'domain') { 21665: $resulttext .= '<li>'.&mt('By default, a course requester can clone any course from his/her domain.').'</li>'; 21666: } else { 21667: $resulttext .= '<li>'.&mt('By default, only course owner and coordinators may clone a course.').'</li>'; 21668: } 21669: } elsif ($item eq 'ltiauth') { 21670: if ($env{'form.'.$item} eq '1') { 21671: $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL need not require re-authentication').'</li>'; 21672: } else { 21673: $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>'; 21674: } 21675: } 21676: } 21677: $resulttext .= '</ul>'; 21678: } else { 21679: $resulttext = &mt('No changes made to course defaults'); 21680: } 21681: } else { 21682: $resulttext = '<span class="LC_error">'. 21683: &mt('An error occurred: [_1]',$putresult).'</span>'; 21684: } 21685: return $resulttext; 21686: } 21687: 21688: sub modify_selfenrollment { 21689: my ($dom,$lastactref,%domconfig) = @_; 21690: my ($resulttext,$errors,%changes,%selfenrollhash,%ordered); 21691: my @types = ('official','unofficial','community','textbook','placement'); 21692: my %titles = &tool_titles(); 21693: my %descs = &Apache::lonuserutils::selfenroll_default_descs(); 21694: ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles(); 21695: $ordered{'default'} = ['types','registered','approval','limit']; 21696: 21697: my (%roles,%shown,%toplevel); 21698: $roles{'0'} = &Apache::lonnet::plaintext('dc'); 21699: 21700: if (ref($domconfig{'selfenrollment'}) ne 'HASH') { 21701: if ($domconfig{'selfenrollment'} eq '') { 21702: $domconfig{'selfenrollment'} = {}; 21703: } 21704: } 21705: %toplevel = ( 21706: admin => 'Configuration Rights', 21707: default => 'Default settings', 21708: validation => 'Validation of self-enrollment requests', 21709: ); 21710: my ($itemsref,$namesref,$fieldsref) = &Apache::lonuserutils::selfenroll_validation_types(); 21711: 21712: if (ref($ordered{'admin'}) eq 'ARRAY') { 21713: foreach my $item (@{$ordered{'admin'}}) { 21714: foreach my $type (@types) { 21715: if ($env{'form.selfenrolladmin_'.$item.'_'.$type}) { 21716: $selfenrollhash{'admin'}{$type}{$item} = 1; 21717: } else { 21718: $selfenrollhash{'admin'}{$type}{$item} = 0; 21719: } 21720: if (ref($domconfig{'selfenrollment'}{'admin'}) eq 'HASH') { 21721: if (ref($domconfig{'selfenrollment'}{'admin'}{$type}) eq 'HASH') { 21722: if ($selfenrollhash{'admin'}{$type}{$item} ne 21723: $domconfig{'selfenrollment'}{'admin'}{$type}{$item}) { 21724: push(@{$changes{'admin'}{$type}},$item); 21725: } 21726: } else { 21727: if (!$selfenrollhash{'admin'}{$type}{$item}) { 21728: push(@{$changes{'admin'}{$type}},$item); 21729: } 21730: } 21731: } elsif (!$selfenrollhash{'admin'}{$type}{$item}) { 21732: push(@{$changes{'admin'}{$type}},$item); 21733: } 21734: } 21735: } 21736: } 21737: 21738: foreach my $item (@{$ordered{'default'}}) { 21739: foreach my $type (@types) { 21740: my $value = $env{'form.selfenrolldefault_'.$item.'_'.$type}; 21741: if ($item eq 'types') { 21742: unless (($value eq 'all') || ($value eq 'dom')) { 21743: $value = ''; 21744: } 21745: } elsif ($item eq 'registered') { 21746: unless ($value eq '1') { 21747: $value = 0; 21748: } 21749: } elsif ($item eq 'approval') { 21750: unless ($value =~ /^[012]$/) { 21751: $value = 0; 21752: } 21753: } else { 21754: unless (($value eq 'allstudents') || ($value eq 'selfenrolled')) { 21755: $value = 'none'; 21756: } 21757: } 21758: $selfenrollhash{'default'}{$type}{$item} = $value; 21759: if (ref($domconfig{'selfenrollment'}{'default'}) eq 'HASH') { 21760: if (ref($domconfig{'selfenrollment'}{'default'}{$type}) eq 'HASH') { 21761: if ($selfenrollhash{'default'}{$type}{$item} ne 21762: $domconfig{'selfenrollment'}{'default'}{$type}{$item}) { 21763: push(@{$changes{'default'}{$type}},$item); 21764: } 21765: } else { 21766: push(@{$changes{'default'}{$type}},$item); 21767: } 21768: } else { 21769: push(@{$changes{'default'}{$type}},$item); 21770: } 21771: if ($item eq 'limit') { 21772: if (($value eq 'allstudents') || ($value eq 'selfenrolled')) { 21773: $env{'form.selfenrolldefault_cap_'.$type} =~ s/\D//g; 21774: if ($env{'form.selfenrolldefault_cap_'.$type} ne '') { 21775: $selfenrollhash{'default'}{$type}{'cap'} = $env{'form.selfenrolldefault_cap_'.$type}; 21776: } 21777: } else { 21778: $selfenrollhash{'default'}{$type}{'cap'} = ''; 21779: } 21780: if (ref($domconfig{'selfenrollment'}{'default'}{$type}) eq 'HASH') { 21781: if ($selfenrollhash{'default'}{$type}{'cap'} ne 21782: $domconfig{'selfenrollment'}{'admin'}{$type}{'cap'}) { 21783: push(@{$changes{'default'}{$type}},'cap'); 21784: } 21785: } elsif ($selfenrollhash{'default'}{$type}{'cap'} ne '') { 21786: push(@{$changes{'default'}{$type}},'cap'); 21787: } 21788: } 21789: } 21790: } 21791: 21792: foreach my $item (@{$itemsref}) { 21793: if ($item eq 'fields') { 21794: my @changed; 21795: @{$selfenrollhash{'validation'}{$item}} = &Apache::loncommon::get_env_multiple('form.selfenroll_validation_'.$item); 21796: if (@{$selfenrollhash{'validation'}{$item}} > 0) { 21797: @{$selfenrollhash{'validation'}{$item}} = sort(@{$selfenrollhash{'validation'}{$item}}); 21798: } 21799: if (ref($domconfig{'selfenrollment'}{'validation'}) eq 'HASH') { 21800: if (ref($domconfig{'selfenrollment'}{'validation'}{$item}) eq 'ARRAY') { 21801: @changed = &Apache::loncommon::compare_arrays($selfenrollhash{'validation'}{$item}, 21802: $domconfig{'selfenrollment'}{'validation'}{$item}); 21803: } else { 21804: @changed = @{$selfenrollhash{'validation'}{$item}}; 21805: } 21806: } else { 21807: @changed = @{$selfenrollhash{'validation'}{$item}}; 21808: } 21809: if (@changed) { 21810: if ($selfenrollhash{'validation'}{$item}) { 21811: $changes{'validation'}{$item} = join(', ',@{$selfenrollhash{'validation'}{$item}}); 21812: } else { 21813: $changes{'validation'}{$item} = &mt('None'); 21814: } 21815: } 21816: } else { 21817: $selfenrollhash{'validation'}{$item} = $env{'form.selfenroll_validation_'.$item}; 21818: if ($item eq 'markup') { 21819: if ($env{'form.selfenroll_validation_'.$item}) { 21820: $env{'form.selfenroll_validation_'.$item} =~ s/[\n\r\f]+/\s/gs; 21821: } 21822: } 21823: if (ref($domconfig{'selfenrollment'}{'validation'}) eq 'HASH') { 21824: if ($domconfig{'selfenrollment'}{'validation'}{$item} ne $selfenrollhash{'validation'}{$item}) { 21825: $changes{'validation'}{$item} = $selfenrollhash{'validation'}{$item}; 21826: } 21827: } 21828: } 21829: } 21830: 21831: my $putresult = &Apache::lonnet::put_dom('configuration',{'selfenrollment' => \%selfenrollhash}, 21832: $dom); 21833: if ($putresult eq 'ok') { 21834: if (keys(%changes) > 0) { 21835: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 21836: $resulttext = &mt('Changes made:').'<ul>'; 21837: foreach my $key ('admin','default','validation') { 21838: if (ref($changes{$key}) eq 'HASH') { 21839: $resulttext .= '<li>'.$toplevel{$key}.'<ul>'; 21840: if ($key eq 'validation') { 21841: foreach my $item (@{$itemsref}) { 21842: if (exists($changes{$key}{$item})) { 21843: if ($item eq 'markup') { 21844: $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$namesref->{$item}, 21845: '<br /><pre>'.$changes{$key}{$item}.'</pre>').'</li>'; 21846: } else { 21847: $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$namesref->{$item}, 21848: '<b>'.$changes{$key}{$item}.'</b>').'</li>'; 21849: } 21850: } 21851: } 21852: } else { 21853: foreach my $type (@types) { 21854: if ($type eq 'community') { 21855: $roles{'1'} = &mt('Community personnel'); 21856: } else { 21857: $roles{'1'} = &mt('Course personnel'); 21858: } 21859: if (ref($changes{$key}{$type}) eq 'ARRAY') { 21860: if (ref($selfenrollhash{$key}{$type}) eq 'HASH') { 21861: if ($key eq 'admin') { 21862: my @mgrdc = (); 21863: if (ref($ordered{$key}) eq 'ARRAY') { 21864: foreach my $item (@{$ordered{'admin'}}) { 21865: if (ref($selfenrollhash{$key}{$type}) eq 'HASH') { 21866: if ($selfenrollhash{$key}{$type}{$item} eq '0') { 21867: push(@mgrdc,$item); 21868: } 21869: } 21870: } 21871: if (@mgrdc) { 21872: $domdefaults{$type.'selfenrolladmdc'} = join(',',@mgrdc); 21873: } else { 21874: delete($domdefaults{$type.'selfenrolladmdc'}); 21875: } 21876: } 21877: } else { 21878: if (ref($ordered{$key}) eq 'ARRAY') { 21879: foreach my $item (@{$ordered{$key}}) { 21880: if (grep(/^\Q$item\E$/,@{$changes{$key}{$type}})) { 21881: $domdefaults{$type.'selfenroll'.$item} = 21882: $selfenrollhash{$key}{$type}{$item}; 21883: } 21884: } 21885: } 21886: } 21887: } 21888: $resulttext .= '<li>'.$titles{$type}.'<ul>'; 21889: foreach my $item (@{$ordered{$key}}) { 21890: if (grep(/^\Q$item\E$/,@{$changes{$key}{$type}})) { 21891: $resulttext .= '<li>'; 21892: if ($key eq 'admin') { 21893: $resulttext .= &mt('[_1] -- management by: [_2]',$titlesref->{$item}, 21894: '<b>'.$roles{$selfenrollhash{'admin'}{$type}{$item}}.'</b>'); 21895: } else { 21896: $resulttext .= &mt('[_1] set to: [_2]',$titlesref->{$item}, 21897: '<b>'.$descs{$item}{$selfenrollhash{'default'}{$type}{$item}}.'</b>'); 21898: } 21899: $resulttext .= '</li>'; 21900: } 21901: } 21902: $resulttext .= '</ul></li>'; 21903: } 21904: } 21905: $resulttext .= '</ul></li>'; 21906: } 21907: } 21908: } 21909: if ((exists($changes{'admin'})) || (exists($changes{'default'}))) { 21910: my $cachetime = 24*60*60; 21911: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 21912: if (ref($lastactref) eq 'HASH') { 21913: $lastactref->{'domdefaults'} = 1; 21914: } 21915: } 21916: $resulttext .= '</ul>'; 21917: } else { 21918: $resulttext = &mt('No changes made to self-enrollment settings'); 21919: } 21920: } else { 21921: $resulttext = '<span class="LC_error">'. 21922: &mt('An error occurred: [_1]',$putresult).'</span>'; 21923: } 21924: return $resulttext; 21925: } 21926: 21927: sub modify_wafproxy { 21928: my ($dom,$action,$lastactref,%domconfig) = @_; 21929: my %servers = &Apache::lonnet::internet_dom_servers($dom); 21930: my (%othercontrol,%canset,%values,%curralias,%currsaml,%currvalue,@warnings, 21931: %wafproxy,%changes,%expirecache,%expiresaml); 21932: foreach my $server (sort(keys(%servers))) { 21933: my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server}); 21934: if ($serverhome eq $server) { 21935: my $serverdom = &Apache::lonnet::host_domain($server); 21936: if ($serverdom eq $dom) { 21937: $canset{$server} = 1; 21938: } 21939: } 21940: } 21941: if (ref($domconfig{'wafproxy'}) eq 'HASH') { 21942: %{$values{$dom}} = (); 21943: if (ref($domconfig{'wafproxy'}{'alias'}) eq 'HASH') { 21944: %curralias = %{$domconfig{'wafproxy'}{'alias'}}; 21945: } 21946: if (ref($domconfig{'wafproxy'}{'saml'}) eq 'HASH') { 21947: %currsaml = %{$domconfig{'wafproxy'}{'saml'}}; 21948: } 21949: foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') { 21950: $currvalue{$item} = $domconfig{'wafproxy'}{$item}; 21951: } 21952: } 21953: my $output; 21954: if (keys(%canset)) { 21955: %{$wafproxy{'alias'}} = (); 21956: %{$wafproxy{'saml'}} = (); 21957: foreach my $key (sort(keys(%canset))) { 21958: if ($env{'form.wafproxy_'.$dom}) { 21959: $wafproxy{'alias'}{$key} = $env{'form.wafproxy_alias_'.$key}; 21960: $wafproxy{'alias'}{$key} =~ s/^\s+|\s+$//g; 21961: if ($wafproxy{'alias'}{$key} ne $curralias{$key}) { 21962: $changes{'alias'} = 1; 21963: } 21964: if ($env{'form.wafproxy_alias_saml_'.$key}) { 21965: $wafproxy{'saml'}{$key} = 1; 21966: } 21967: if ($wafproxy{'saml'}{$key} ne $currsaml{$key}) { 21968: $changes{'saml'} = 1; 21969: } 21970: } else { 21971: $wafproxy{'alias'}{$key} = ''; 21972: $wafproxy{'saml'}{$key} = ''; 21973: if ($curralias{$key}) { 21974: $changes{'alias'} = 1; 21975: } 21976: if ($currsaml{$key}) { 21977: $changes{'saml'} = 1; 21978: } 21979: } 21980: if ($wafproxy{'alias'}{$key} eq '') { 21981: if ($curralias{$key}) { 21982: $expirecache{$key} = 1; 21983: } 21984: delete($wafproxy{'alias'}{$key}); 21985: } 21986: if ($wafproxy{'saml'}{$key} eq '') { 21987: if ($currsaml{$key}) { 21988: $expiresaml{$key} = 1; 21989: } 21990: delete($wafproxy{'saml'}{$key}); 21991: } 21992: } 21993: unless (keys(%{$wafproxy{'alias'}})) { 21994: delete($wafproxy{'alias'}); 21995: } 21996: unless (keys(%{$wafproxy{'saml'}})) { 21997: delete($wafproxy{'saml'}); 21998: } 21999: # Localization for values in %warn occurs in &mt() calls separately. 22000: my %warn = ( 22001: trusted => 'trusted IP range(s)', 22002: vpnint => 'internal IP range(s) for VPN sessions(s)', 22003: vpnext => 'IP range(s) for backend WAF connections', 22004: ); 22005: foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext','sslopt') { 22006: my $possible = $env{'form.wafproxy_'.$item}; 22007: $possible =~ s/^\s+|\s+$//g; 22008: if ($possible ne '') { 22009: if ($item eq 'remoteip') { 22010: if ($possible =~ /^[mhn]$/) { 22011: $wafproxy{$item} = $possible; 22012: } 22013: } elsif ($item eq 'ipheader') { 22014: if ($wafproxy{'remoteip'} eq 'h') { 22015: $wafproxy{$item} = $possible; 22016: } 22017: } elsif ($item eq 'sslopt') { 22018: if ($possible =~ /^0|1$/) { 22019: $wafproxy{$item} = $possible; 22020: } 22021: } else { 22022: my (@ok,$count); 22023: if (($item eq 'vpnint') || ($item eq 'vpnext')) { 22024: unless ($env{'form.wafproxy_vpnaccess'}) { 22025: $possible = ''; 22026: } 22027: } elsif ($item eq 'trusted') { 22028: unless ($wafproxy{'remoteip'} eq 'h') { 22029: $possible = ''; 22030: } 22031: } 22032: unless ($possible eq '') { 22033: $possible =~ s/[\r\n]+/\s/g; 22034: $possible =~ s/\s*-\s*/-/g; 22035: $possible =~ s/\s+/,/g; 22036: $possible =~ s/,+/,/g; 22037: } 22038: $count = 0; 22039: if ($possible ne '') { 22040: foreach my $poss (split(/\,/,$possible)) { 22041: $count ++; 22042: $poss = &validate_ip_pattern($poss); 22043: if ($poss ne '') { 22044: push(@ok,$poss); 22045: } 22046: } 22047: my $diff = $count - scalar(@ok); 22048: if ($diff) { 22049: push(@warnings,'<li>'. 22050: &mt('[quant,_1,IP] invalid and excluded from saved value for [_2]', 22051: $diff,$warn{$item}). 22052: '</li>'); 22053: } 22054: if (@ok) { 22055: my @cidr_list; 22056: foreach my $item (@ok) { 22057: @cidr_list = &Net::CIDR::cidradd($item,@cidr_list); 22058: } 22059: $wafproxy{$item} = join(',',@cidr_list); 22060: } 22061: } 22062: } 22063: if ($wafproxy{$item} ne $currvalue{$item}) { 22064: $changes{$item} = 1; 22065: } 22066: } elsif ($currvalue{$item}) { 22067: $changes{$item} = 1; 22068: } 22069: } 22070: } else { 22071: if (keys(%curralias)) { 22072: $changes{'alias'} = 1; 22073: } 22074: if (keys(%currsaml)) { 22075: $changes{'saml'} = 1; 22076: } 22077: if (keys(%currvalue)) { 22078: foreach my $key (keys(%currvalue)) { 22079: $changes{$key} = 1; 22080: } 22081: } 22082: } 22083: if (keys(%changes)) { 22084: my %defaultshash = ( 22085: wafproxy => \%wafproxy, 22086: ); 22087: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, 22088: $dom); 22089: if ($putresult eq 'ok') { 22090: my $cachetime = 24*60*60; 22091: my (%domdefaults,$updatedomdefs); 22092: foreach my $item ('ipheader','trusted','vpnint','vpnext','sslopt') { 22093: if ($changes{$item}) { 22094: unless ($updatedomdefs) { 22095: %domdefaults = &Apache::lonnet::get_domain_defaults($dom); 22096: $updatedomdefs = 1; 22097: } 22098: if ($wafproxy{$item}) { 22099: $domdefaults{'waf_'.$item} = $wafproxy{$item}; 22100: } elsif (exists($domdefaults{'waf_'.$item})) { 22101: delete($domdefaults{'waf_'.$item}); 22102: } 22103: } 22104: } 22105: if ($updatedomdefs) { 22106: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 22107: if (ref($lastactref) eq 'HASH') { 22108: $lastactref->{'domdefaults'} = 1; 22109: } 22110: } 22111: if ((exists($wafproxy{'alias'})) || (keys(%expirecache))) { 22112: my %updates = %expirecache; 22113: foreach my $key (keys(%expirecache)) { 22114: &Apache::lonnet::devalidate_cache_new('proxyalias',$key); 22115: } 22116: if (ref($wafproxy{'alias'}) eq 'HASH') { 22117: my $cachetime = 24*60*60; 22118: foreach my $key (keys(%{$wafproxy{'alias'}})) { 22119: $updates{$key} = 1; 22120: &Apache::lonnet::do_cache_new('proxyalias',$key,$wafproxy{'alias'}{$key}, 22121: $cachetime); 22122: } 22123: } 22124: if (ref($lastactref) eq 'HASH') { 22125: $lastactref->{'proxyalias'} = \%updates; 22126: } 22127: } 22128: if ((exists($wafproxy{'saml'})) || (keys(%expiresaml))) { 22129: my %samlupdates = %expiresaml; 22130: foreach my $key (keys(%expiresaml)) { 22131: &Apache::lonnet::devalidate_cache_new('proxysaml',$key); 22132: } 22133: if (ref($wafproxy{'saml'}) eq 'HASH') { 22134: my $cachetime = 24*60*60; 22135: foreach my $key (keys(%{$wafproxy{'saml'}})) { 22136: $samlupdates{$key} = 1; 22137: &Apache::lonnet::do_cache_new('proxysaml',$key,$wafproxy{'saml'}{$key}, 22138: $cachetime); 22139: } 22140: } 22141: if (ref($lastactref) eq 'HASH') { 22142: $lastactref->{'proxysaml'} = \%samlupdates; 22143: } 22144: } 22145: $output = &mt('Changes were made to Web Application Firewall/Reverse Proxy').'<ul>'; 22146: foreach my $item ('alias','saml','remoteip','ipheader','trusted','vpnint','vpnext','sslopt') { 22147: if ($changes{$item}) { 22148: if ($item eq 'alias') { 22149: my $numaliased = 0; 22150: if (ref($wafproxy{'alias'}) eq 'HASH') { 22151: my $shown; 22152: if (keys(%{$wafproxy{'alias'}})) { 22153: foreach my $server (sort(keys(%{$wafproxy{'alias'}}))) { 22154: $shown .= '<li>'.&mt('[_1] aliased by [_2]', 22155: &Apache::lonnet::hostname($server), 22156: $wafproxy{'alias'}{$server}).'</li>'; 22157: $numaliased ++; 22158: } 22159: if ($numaliased) { 22160: $output .= '<li>'.&mt('Aliases for hostnames set to: [_1]', 22161: '<ul>'.$shown.'</ul>').'</li>'; 22162: } 22163: } 22164: } 22165: unless ($numaliased) { 22166: $output .= '<li>'.&mt('Aliases deleted for hostnames').'</li>'; 22167: } 22168: } elsif ($item eq 'saml') { 22169: my $shown; 22170: if (ref($wafproxy{'saml'}) eq 'HASH') { 22171: if (keys(%{$wafproxy{'saml'}})) { 22172: $shown = join(', ',sort(keys(%{$wafproxy{'saml'}}))); 22173: } 22174: } 22175: if ($shown) { 22176: $output .= '<li>'.&mt('Alias used by SSO Auth for: [_1]', 22177: $shown).'</li>'; 22178: } else { 22179: $output .= '<li>'.&mt('No alias used for SSO Auth').'</li>'; 22180: } 22181: } else { 22182: if ($item eq 'remoteip') { 22183: my %ip_methods = &remoteip_methods(); 22184: if ($wafproxy{$item} =~ /^[mh]$/) { 22185: $output .= '<li>'.&mt("Method for determining user's IP set to: [_1]", 22186: $ip_methods{$wafproxy{$item}}).'</li>'; 22187: } else { 22188: if (($env{'form.wafproxy_'.$dom}) && (ref($wafproxy{'alias'}) eq 'HASH')) { 22189: $output .= '<li>'.&mt("No method in use to get user's real IP (will report IP used by WAF)."). 22190: '</li>'; 22191: } else { 22192: $output .= '<li>'.&mt('WAF/Reverse Proxy not in use').'</li>'; 22193: } 22194: } 22195: } elsif ($item eq 'ipheader') { 22196: if ($wafproxy{$item}) { 22197: $output .= '<li>'.&mt('Request header with remote IP set to: [_1]', 22198: $wafproxy{$item}).'</li>'; 22199: } else { 22200: $output .= '<li>'.&mt('Request header with remote IP deleted').'</li>'; 22201: } 22202: } elsif ($item eq 'trusted') { 22203: if ($wafproxy{$item}) { 22204: $output .= '<li>'.&mt('Trusted IP range(s) set to: [_1]', 22205: $wafproxy{$item}).'</li>'; 22206: } else { 22207: $output .= '<li>'.&mt('Trusted IP range(s) deleted').'</li>'; 22208: } 22209: } elsif ($item eq 'vpnint') { 22210: if ($wafproxy{$item}) { 22211: $output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions set to: [_1]', 22212: $wafproxy{$item}).'</li>'; 22213: } else { 22214: $output .= '<li>'.&mt('Internal IP Range(s) for VPN sessions deleted').'</li>'; 22215: } 22216: } elsif ($item eq 'vpnext') { 22217: if ($wafproxy{$item}) { 22218: $output .= '<li>'.&mt('IP Range(s) for backend WAF connections set to: [_1]', 22219: $wafproxy{$item}).'</li>'; 22220: } else { 22221: $output .= '<li>'.&mt('IP Range(s) for backend WAF connections deleted').'</li>'; 22222: } 22223: } elsif ($item eq 'sslopt') { 22224: if ($wafproxy{$item}) { 22225: $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>'; 22226: } else { 22227: $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>'; 22228: } 22229: } 22230: } 22231: } 22232: } 22233: } else { 22234: $output = '<span class="LC_error">'. 22235: &mt('An error occurred: [_1]',$putresult).'</span>'; 22236: } 22237: } elsif (keys(%canset)) { 22238: $output = &mt('No changes made to Web Application Firewall/Reverse Proxy settings'); 22239: } 22240: if (@warnings) { 22241: $output .= '<br />'.&mt('Warnings:').'<ul>'. 22242: join("\n",@warnings).'</ul>'; 22243: } 22244: return $output; 22245: } 22246: 22247: sub validate_ip_pattern { 22248: my ($pattern) = @_; 22249: if ($pattern =~ /^([^-]+)\-([^-]+)$/) { 22250: my ($start,$end) = ($1,$2); 22251: if ((&Net::CIDR::cidrvalidate($start)) && (&Net::CIDR::cidrvalidate($end))) { 22252: if (($start !~ m{/}) && ($end !~ m{/})) { 22253: return $start.'-'.$end; 22254: } 22255: } 22256: } elsif ($pattern ne '') { 22257: $pattern = &Net::CIDR::cidrvalidate($pattern); 22258: if ($pattern ne '') { 22259: return $pattern; 22260: } 22261: } 22262: return; 22263: } 22264: 22265: sub modify_usersessions { 22266: my ($dom,$lastactref,%domconfig) = @_; 22267: my @hostingtypes = ('version','excludedomain','includedomain'); 22268: my @offloadtypes = ('primary','default'); 22269: my %types = ( 22270: remote => \@hostingtypes, 22271: hosted => \@hostingtypes, 22272: spares => \@offloadtypes, 22273: ); 22274: my @prefixes = ('remote','hosted','spares'); 22275: my @lcversions = &Apache::lonnet::all_loncaparevs(); 22276: my (%by_ip,%by_location,@intdoms,@instdoms); 22277: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 22278: my @locations = sort(keys(%by_location)); 22279: my (%defaultshash,%changes); 22280: foreach my $prefix (@prefixes) { 22281: $defaultshash{'usersessions'}{$prefix} = {}; 22282: } 22283: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 22284: my $resulttext; 22285: my %iphost = &Apache::lonnet::get_iphost(); 22286: foreach my $prefix (@prefixes) { 22287: next if ($prefix eq 'spares'); 22288: foreach my $type (@{$types{$prefix}}) { 22289: my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'}; 22290: if ($type eq 'version') { 22291: my $value = $env{'form.'.$prefix.'_'.$type}; 22292: my $okvalue; 22293: if ($value ne '') { 22294: if (grep(/^\Q$value\E$/,@lcversions)) { 22295: $okvalue = $value; 22296: } 22297: } 22298: if (ref($domconfig{'usersessions'}) eq 'HASH') { 22299: if (ref($domconfig{'usersessions'}{$prefix}) eq 'HASH') { 22300: if ($domconfig{'usersessions'}{$prefix}{$type} ne '') { 22301: if ($inuse == 0) { 22302: $changes{$prefix}{$type} = 1; 22303: } else { 22304: if ($okvalue ne $domconfig{'usersessions'}{$prefix}{$type}) { 22305: $changes{$prefix}{$type} = 1; 22306: } 22307: if ($okvalue ne '') { 22308: $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; 22309: } 22310: } 22311: } else { 22312: if (($inuse == 1) && ($okvalue ne '')) { 22313: $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; 22314: $changes{$prefix}{$type} = 1; 22315: } 22316: } 22317: } else { 22318: if (($inuse == 1) && ($okvalue ne '')) { 22319: $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; 22320: $changes{$prefix}{$type} = 1; 22321: } 22322: } 22323: } else { 22324: if (($inuse == 1) && ($okvalue ne '')) { 22325: $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; 22326: $changes{$prefix}{$type} = 1; 22327: } 22328: } 22329: } else { 22330: my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type); 22331: my @okvals; 22332: foreach my $val (@vals) { 22333: if ($val =~ /:/) { 22334: my @items = split(/:/,$val); 22335: foreach my $item (@items) { 22336: if (ref($by_location{$item}) eq 'ARRAY') { 22337: push(@okvals,$item); 22338: } 22339: } 22340: } else { 22341: if (ref($by_location{$val}) eq 'ARRAY') { 22342: push(@okvals,$val); 22343: } 22344: } 22345: } 22346: @okvals = sort(@okvals); 22347: if (ref($domconfig{'usersessions'}) eq 'HASH') { 22348: if (ref($domconfig{'usersessions'}{$prefix}) eq 'HASH') { 22349: if (ref($domconfig{'usersessions'}{$prefix}{$type}) eq 'ARRAY') { 22350: if ($inuse == 0) { 22351: $changes{$prefix}{$type} = 1; 22352: } else { 22353: $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; 22354: my @changed = &Apache::loncommon::compare_arrays($domconfig{'usersessions'}{$prefix}{$type},$defaultshash{'usersessions'}{$prefix}{$type}); 22355: if (@changed > 0) { 22356: $changes{$prefix}{$type} = 1; 22357: } 22358: } 22359: } else { 22360: if ($inuse == 1) { 22361: $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; 22362: $changes{$prefix}{$type} = 1; 22363: } 22364: } 22365: } else { 22366: if ($inuse == 1) { 22367: $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; 22368: $changes{$prefix}{$type} = 1; 22369: } 22370: } 22371: } else { 22372: if ($inuse == 1) { 22373: $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; 22374: $changes{$prefix}{$type} = 1; 22375: } 22376: } 22377: } 22378: } 22379: } 22380: 22381: my @alldoms = &Apache::lonnet::all_domains(); 22382: my %servers = &Apache::lonnet::internet_dom_servers($dom); 22383: my %spareid = ¤t_offloads_to($dom,$domconfig{'usersessions'},\%servers); 22384: my $savespares; 22385: 22386: foreach my $lonhost (sort(keys(%servers))) { 22387: my $serverhomeID = 22388: &Apache::lonnet::get_server_homeID($servers{$lonhost}); 22389: my $serverhostname = &Apache::lonnet::hostname($lonhost); 22390: $defaultshash{'usersessions'}{'spares'}{$lonhost} = {}; 22391: my %spareschg; 22392: foreach my $type (@{$types{'spares'}}) { 22393: my @okspares; 22394: my @checked = &Apache::loncommon::get_env_multiple('form.spare_'.$type.'_'.$lonhost); 22395: foreach my $server (@checked) { 22396: if (&Apache::lonnet::hostname($server) ne '') { 22397: unless (&Apache::lonnet::hostname($server) eq $serverhostname) { 22398: unless (grep(/^\Q$server\E$/,@okspares)) { 22399: push(@okspares,$server); 22400: } 22401: } 22402: } 22403: } 22404: my $new = $env{'form.newspare_'.$type.'_'.$lonhost}; 22405: my $newspare; 22406: if (($new ne '') && (&Apache::lonnet::hostname($new))) { 22407: unless (&Apache::lonnet::hostname($new) eq $serverhostname) { 22408: $newspare = $new; 22409: } 22410: } 22411: my @spares; 22412: if (($newspare ne '') && (!grep(/^\Q$newspare\E$/,@okspares))) { 22413: @spares = sort(@okspares,$newspare); 22414: } else { 22415: @spares = sort(@okspares); 22416: } 22417: $defaultshash{'usersessions'}{'spares'}{$lonhost}{$type} = \@spares; 22418: if (ref($spareid{$lonhost}) eq 'HASH') { 22419: if (ref($spareid{$lonhost}{$type}) eq 'ARRAY') { 22420: my @diffs = &Apache::loncommon::compare_arrays($spareid{$lonhost}{$type},\@spares); 22421: if (@diffs > 0) { 22422: $spareschg{$type} = 1; 22423: } 22424: } 22425: } 22426: } 22427: if (keys(%spareschg) > 0) { 22428: $changes{'spares'}{$lonhost} = \%spareschg; 22429: } 22430: } 22431: $defaultshash{'usersessions'}{'offloadnow'} = {}; 22432: $defaultshash{'usersessions'}{'offloadoth'} = {}; 22433: my @offloadnow = &Apache::loncommon::get_env_multiple('form.offloadnow'); 22434: my @okoffload; 22435: if (@offloadnow) { 22436: foreach my $server (@offloadnow) { 22437: if (&Apache::lonnet::hostname($server) ne '') { 22438: unless (grep(/^\Q$server\E$/,@okoffload)) { 22439: push(@okoffload,$server); 22440: } 22441: } 22442: } 22443: if (@okoffload) { 22444: foreach my $lonhost (@okoffload) { 22445: $defaultshash{'usersessions'}{'offloadnow'}{$lonhost} = 1; 22446: } 22447: } 22448: } 22449: my @offloadoth = &Apache::loncommon::get_env_multiple('form.offloadoth'); 22450: my @okoffloadoth; 22451: if (@offloadoth) { 22452: foreach my $server (@offloadoth) { 22453: if (&Apache::lonnet::hostname($server) ne '') { 22454: unless (grep(/^\Q$server\E$/,@okoffloadoth)) { 22455: push(@okoffloadoth,$server); 22456: } 22457: } 22458: } 22459: if (@okoffloadoth) { 22460: foreach my $lonhost (@okoffloadoth) { 22461: $defaultshash{'usersessions'}{'offloadoth'}{$lonhost} = 1; 22462: } 22463: } 22464: } 22465: if (ref($domconfig{'usersessions'}) eq 'HASH') { 22466: if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') { 22467: if (ref($changes{'spares'}) eq 'HASH') { 22468: if (keys(%{$changes{'spares'}}) > 0) { 22469: $savespares = 1; 22470: } 22471: } 22472: } else { 22473: $savespares = 1; 22474: } 22475: foreach my $offload ('offloadnow','offloadoth') { 22476: if (ref($domconfig{'usersessions'}{$offload}) eq 'HASH') { 22477: foreach my $lonhost (keys(%{$domconfig{'usersessions'}{$offload}})) { 22478: unless ($defaultshash{'usersessions'}{$offload}{$lonhost}) { 22479: $changes{$offload} = 1; 22480: last; 22481: } 22482: } 22483: unless ($changes{$offload}) { 22484: foreach my $lonhost (keys(%{$defaultshash{'usersessions'}{$offload}})) { 22485: unless ($domconfig{'usersessions'}{$offload}{$lonhost}) { 22486: $changes{$offload} = 1; 22487: last; 22488: } 22489: } 22490: } 22491: } else { 22492: if (($offload eq 'offloadnow') && (@okoffload)) { 22493: $changes{'offloadnow'} = 1; 22494: } 22495: if (($offload eq 'offloadoth') && (@okoffloadoth)) { 22496: $changes{'offloadoth'} = 1; 22497: } 22498: } 22499: } 22500: } else { 22501: if (@okoffload) { 22502: $changes{'offloadnow'} = 1; 22503: } 22504: if (@okoffloadoth) { 22505: $changes{'offloadoth'} = 1; 22506: } 22507: } 22508: my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.'); 22509: if ((keys(%changes) > 0) || ($savespares)) { 22510: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, 22511: $dom); 22512: if ($putresult eq 'ok') { 22513: if (ref($defaultshash{'usersessions'}) eq 'HASH') { 22514: if (ref($defaultshash{'usersessions'}{'remote'}) eq 'HASH') { 22515: $domdefaults{'remotesessions'} = $defaultshash{'usersessions'}{'remote'}; 22516: } 22517: if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') { 22518: $domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'}; 22519: } 22520: if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') { 22521: $domdefaults{'offloadnow'} = $defaultshash{'usersessions'}{'offloadnow'}; 22522: } 22523: if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') { 22524: $domdefaults{'offloadoth'} = $defaultshash{'usersessions'}{'offloadoth'}; 22525: } 22526: } 22527: my $cachetime = 24*60*60; 22528: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 22529: &Apache::lonnet::do_cache_new('usersessions',$dom,$defaultshash{'usersessions'},3600); 22530: if (ref($lastactref) eq 'HASH') { 22531: $lastactref->{'domdefaults'} = 1; 22532: $lastactref->{'usersessions'} = 1; 22533: } 22534: if (keys(%changes) > 0) { 22535: my %lt = &usersession_titles(); 22536: $resulttext = &mt('Changes made:').'<ul>'; 22537: foreach my $prefix (@prefixes) { 22538: if (ref($changes{$prefix}) eq 'HASH') { 22539: $resulttext .= '<li>'.$lt{$prefix}.'<ul>'; 22540: if ($prefix eq 'spares') { 22541: if (ref($changes{$prefix}) eq 'HASH') { 22542: foreach my $lonhost (sort(keys(%{$changes{$prefix}}))) { 22543: $resulttext .= '<li><b>'.$lonhost.'</b> '; 22544: my $lonhostdom = &Apache::lonnet::host_domain($lonhost); 22545: my $cachekey = &escape('spares').':'.&escape($lonhostdom); 22546: &Apache::lonnet::remote_devalidate_cache($lonhost,[$cachekey]); 22547: if (ref($changes{$prefix}{$lonhost}) eq 'HASH') { 22548: foreach my $type (@{$types{$prefix}}) { 22549: if ($changes{$prefix}{$lonhost}{$type}) { 22550: my $offloadto = &mt('None'); 22551: if (ref($defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}) eq 'ARRAY') { 22552: if (@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}} > 0) { 22553: $offloadto = join(', ',@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}}); 22554: } 22555: } 22556: $resulttext .= &mt('[_1] set to: [_2].','<i>'.$lt{$type}.'</i>',$offloadto).(' 'x3); 22557: } 22558: } 22559: } 22560: $resulttext .= '</li>'; 22561: } 22562: } 22563: } else { 22564: foreach my $type (@{$types{$prefix}}) { 22565: if (defined($changes{$prefix}{$type})) { 22566: my ($newvalue,$notinuse); 22567: if (ref($defaultshash{'usersessions'}) eq 'HASH') { 22568: if (ref($defaultshash{'usersessions'}{$prefix})) { 22569: if ($type eq 'version') { 22570: $newvalue = $defaultshash{'usersessions'}{$prefix}{$type}; 22571: } else { 22572: if (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') { 22573: if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) { 22574: $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}}); 22575: } 22576: } else { 22577: $notinuse = 1; 22578: } 22579: } 22580: } 22581: } 22582: if ($newvalue eq '') { 22583: if ($type eq 'version') { 22584: $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>'; 22585: } elsif ($notinuse) { 22586: $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>'; 22587: } else { 22588: $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>'; 22589: } 22590: } else { 22591: if ($type eq 'version') { 22592: $newvalue .= ' '.&mt('(or later)'); 22593: } 22594: $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>'; 22595: } 22596: } 22597: } 22598: } 22599: $resulttext .= '</ul>'; 22600: } 22601: } 22602: if ($changes{'offloadnow'}) { 22603: if (ref($defaultshash{'usersessions'}{'offloadnow'}) eq 'HASH') { 22604: if (keys(%{$defaultshash{'usersessions'}{'offloadnow'}}) > 0) { 22605: $resulttext .= '<li>'.&mt('Switch any active user on next access, for server(s):').'<ul>'; 22606: foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadnow'}}))) { 22607: $resulttext .= '<li>'.$lonhost.'</li>'; 22608: } 22609: $resulttext .= '</ul>'; 22610: } else { 22611: $resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.'); 22612: } 22613: } else { 22614: $resulttext .= '<li>'.&mt('No servers now set to switch any active user on next access.').'</li>'; 22615: } 22616: } 22617: if ($changes{'offloadoth'}) { 22618: if (ref($defaultshash{'usersessions'}{'offloadoth'}) eq 'HASH') { 22619: if (keys(%{$defaultshash{'usersessions'}{'offloadoth'}}) > 0) { 22620: $resulttext .= '<li>'.&mt('Switch other institutions on next access, for server(s):').'<ul>'; 22621: foreach my $lonhost (sort(keys(%{$defaultshash{'usersessions'}{'offloadoth'}}))) { 22622: $resulttext .= '<li>'.$lonhost.'</li>'; 22623: } 22624: $resulttext .= '</ul>'; 22625: } else { 22626: $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.'); 22627: } 22628: } else { 22629: $resulttext .= '<li>'.&mt('No servers now set to switch other institutions on next access.').'</li>'; 22630: } 22631: } 22632: $resulttext .= '</ul>'; 22633: } else { 22634: $resulttext = $nochgmsg; 22635: } 22636: } else { 22637: $resulttext = '<span class="LC_error">'. 22638: &mt('An error occurred: [_1]',$putresult).'</span>'; 22639: } 22640: } else { 22641: $resulttext = $nochgmsg; 22642: } 22643: return $resulttext; 22644: } 22645: 22646: sub modify_ssl { 22647: my ($dom,$lastactref,%domconfig) = @_; 22648: my (%by_ip,%by_location,@intdoms,@instdoms); 22649: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 22650: my @locations = sort(keys(%by_location)); 22651: my %servers = &Apache::lonnet::internet_dom_servers($dom); 22652: my (%defaultshash,%changes); 22653: my $action = 'ssl'; 22654: my @prefixes = ('connto','connfrom','replication'); 22655: foreach my $prefix (@prefixes) { 22656: $defaultshash{$action}{$prefix} = {}; 22657: } 22658: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 22659: my $resulttext; 22660: my %iphost = &Apache::lonnet::get_iphost(); 22661: my @reptypes = ('certreq','nocertreq'); 22662: my @connecttypes = ('dom','intdom','other'); 22663: my %types = ( 22664: connto => \@connecttypes, 22665: connfrom => \@connecttypes, 22666: replication => \@reptypes, 22667: ); 22668: foreach my $prefix (sort(keys(%types))) { 22669: foreach my $type (@{$types{$prefix}}) { 22670: if (($prefix eq 'connto') || ($prefix eq 'connfrom')) { 22671: my $value = 'yes'; 22672: if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) { 22673: $value = $env{'form.'.$prefix.'_'.$type}; 22674: } 22675: if (ref($domconfig{$action}) eq 'HASH') { 22676: if (ref($domconfig{$action}{$prefix}) eq 'HASH') { 22677: if ($domconfig{$action}{$prefix}{$type} ne '') { 22678: if ($value ne $domconfig{$action}{$prefix}{$type}) { 22679: $changes{$prefix}{$type} = 1; 22680: } 22681: $defaultshash{$action}{$prefix}{$type} = $value; 22682: } else { 22683: $defaultshash{$action}{$prefix}{$type} = $value; 22684: $changes{$prefix}{$type} = 1; 22685: } 22686: } else { 22687: $defaultshash{$action}{$prefix}{$type} = $value; 22688: $changes{$prefix}{$type} = 1; 22689: } 22690: } else { 22691: $defaultshash{$action}{$prefix}{$type} = $value; 22692: $changes{$prefix}{$type} = 1; 22693: } 22694: if (($type eq 'dom') && (keys(%servers) == 1)) { 22695: delete($changes{$prefix}{$type}); 22696: } elsif (($type eq 'intdom') && (@instdoms == 1)) { 22697: delete($changes{$prefix}{$type}); 22698: } elsif (($type eq 'other') && (keys(%by_location) == 0)) { 22699: delete($changes{$prefix}{$type}); 22700: } 22701: } elsif ($prefix eq 'replication') { 22702: if (@locations > 0) { 22703: my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'}; 22704: my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type); 22705: my @okvals; 22706: foreach my $val (@vals) { 22707: if ($val =~ /:/) { 22708: my @items = split(/:/,$val); 22709: foreach my $item (@items) { 22710: if (ref($by_location{$item}) eq 'ARRAY') { 22711: push(@okvals,$item); 22712: } 22713: } 22714: } else { 22715: if (ref($by_location{$val}) eq 'ARRAY') { 22716: push(@okvals,$val); 22717: } 22718: } 22719: } 22720: @okvals = sort(@okvals); 22721: if (ref($domconfig{$action}) eq 'HASH') { 22722: if (ref($domconfig{$action}{$prefix}) eq 'HASH') { 22723: if (ref($domconfig{$action}{$prefix}{$type}) eq 'ARRAY') { 22724: if ($inuse == 0) { 22725: $changes{$prefix}{$type} = 1; 22726: } else { 22727: $defaultshash{$action}{$prefix}{$type} = \@okvals; 22728: my @changed = &Apache::loncommon::compare_arrays($domconfig{$action}{$prefix}{$type},$defaultshash{$action}{$prefix}{$type}); 22729: if (@changed > 0) { 22730: $changes{$prefix}{$type} = 1; 22731: } 22732: } 22733: } else { 22734: if ($inuse == 1) { 22735: $defaultshash{$action}{$prefix}{$type} = \@okvals; 22736: $changes{$prefix}{$type} = 1; 22737: } 22738: } 22739: } else { 22740: if ($inuse == 1) { 22741: $defaultshash{$action}{$prefix}{$type} = \@okvals; 22742: $changes{$prefix}{$type} = 1; 22743: } 22744: } 22745: } else { 22746: if ($inuse == 1) { 22747: $defaultshash{$action}{$prefix}{$type} = \@okvals; 22748: $changes{$prefix}{$type} = 1; 22749: } 22750: } 22751: } 22752: } 22753: } 22754: } 22755: if (keys(%changes)) { 22756: foreach my $prefix (keys(%changes)) { 22757: if (ref($changes{$prefix}) eq 'HASH') { 22758: if (scalar(keys(%{$changes{$prefix}})) == 0) { 22759: delete($changes{$prefix}); 22760: } 22761: } else { 22762: delete($changes{$prefix}); 22763: } 22764: } 22765: } 22766: my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings'); 22767: if (keys(%changes) > 0) { 22768: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, 22769: $dom); 22770: if ($putresult eq 'ok') { 22771: if (ref($defaultshash{$action}) eq 'HASH') { 22772: if (ref($defaultshash{$action}{'replication'}) eq 'HASH') { 22773: $domdefaults{'replication'} = $defaultshash{$action}{'replication'}; 22774: } 22775: if (ref($defaultshash{$action}{'connto'}) eq 'HASH') { 22776: $domdefaults{'connto'} = $defaultshash{$action}{'connto'}; 22777: } 22778: if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') { 22779: $domdefaults{'connfrom'} = $defaultshash{$action}{'connfrom'}; 22780: } 22781: } 22782: my $cachetime = 24*60*60; 22783: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 22784: if (ref($lastactref) eq 'HASH') { 22785: $lastactref->{'domdefaults'} = 1; 22786: } 22787: if (keys(%changes) > 0) { 22788: my %titles = &ssl_titles(); 22789: $resulttext = &mt('Changes made:').'<ul>'; 22790: foreach my $prefix (@prefixes) { 22791: if (ref($changes{$prefix}) eq 'HASH') { 22792: $resulttext .= '<li>'.$titles{$prefix}.'<ul>'; 22793: foreach my $type (@{$types{$prefix}}) { 22794: if (defined($changes{$prefix}{$type})) { 22795: my ($newvalue,$notinuse); 22796: if (ref($defaultshash{$action}) eq 'HASH') { 22797: if (ref($defaultshash{$action}{$prefix})) { 22798: if (($prefix eq 'connto') || ($prefix eq 'connfrom')) { 22799: $newvalue = $titles{$defaultshash{$action}{$prefix}{$type}}; 22800: } else { 22801: if (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') { 22802: if (@{$defaultshash{$action}{$prefix}{$type}} > 0) { 22803: $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}}); 22804: } 22805: } else { 22806: $notinuse = 1; 22807: } 22808: } 22809: } 22810: if ($notinuse) { 22811: $resulttext .= '<li>'.&mt('[_1] set to: not in use',$titles{$type}).'</li>'; 22812: } elsif ($newvalue eq '') { 22813: $resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>'; 22814: } else { 22815: $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>'; 22816: } 22817: } 22818: } 22819: } 22820: $resulttext .= '</ul>'; 22821: } 22822: } 22823: } else { 22824: $resulttext = $nochgmsg; 22825: } 22826: } else { 22827: $resulttext = '<span class="LC_error">'. 22828: &mt('An error occurred: [_1]',$putresult).'</span>'; 22829: } 22830: } else { 22831: $resulttext = $nochgmsg; 22832: } 22833: return $resulttext; 22834: } 22835: 22836: sub modify_trust { 22837: my ($dom,$lastactref,%domconfig) = @_; 22838: my (%by_ip,%by_location,@intdoms,@instdoms); 22839: &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms); 22840: my @locations = sort(keys(%by_location)); 22841: my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg); 22842: my @types = ('exc','inc'); 22843: my (%defaultshash,%changes); 22844: foreach my $prefix (@prefixes) { 22845: $defaultshash{'trust'}{$prefix} = {}; 22846: } 22847: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); 22848: my $resulttext; 22849: foreach my $prefix (@prefixes) { 22850: foreach my $type (@types) { 22851: my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'}; 22852: my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type); 22853: my @okvals; 22854: foreach my $val (@vals) { 22855: if ($val =~ /:/) { 22856: my @items = split(/:/,$val); 22857: foreach my $item (@items) { 22858: if (ref($by_location{$item}) eq 'ARRAY') { 22859: push(@okvals,$item); 22860: } 22861: } 22862: } else { 22863: if (ref($by_location{$val}) eq 'ARRAY') { 22864: push(@okvals,$val); 22865: } 22866: } 22867: } 22868: @okvals = sort(@okvals); 22869: if (ref($domconfig{'trust'}) eq 'HASH') { 22870: if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') { 22871: if (ref($domconfig{'trust'}{$prefix}{$type}) eq 'ARRAY') { 22872: if ($inuse == 0) { 22873: $changes{$prefix}{$type} = 1; 22874: } else { 22875: $defaultshash{'trust'}{$prefix}{$type} = \@okvals; 22876: my @changed = &Apache::loncommon::compare_arrays($domconfig{'trust'}{$prefix}{$type},$defaultshash{'trust'}{$prefix}{$type}); 22877: if (@changed > 0) { 22878: $changes{$prefix}{$type} = 1; 22879: } 22880: } 22881: } else { 22882: if ($inuse == 1) { 22883: $defaultshash{'trust'}{$prefix}{$type} = \@okvals; 22884: $changes{$prefix}{$type} = 1; 22885: } 22886: } 22887: } else { 22888: if ($inuse == 1) { 22889: $defaultshash{'trust'}{$prefix}{$type} = \@okvals; 22890: $changes{$prefix}{$type} = 1; 22891: } 22892: } 22893: } else { 22894: if ($inuse == 1) { 22895: $defaultshash{'trust'}{$prefix}{$type} = \@okvals; 22896: $changes{$prefix}{$type} = 1; 22897: } 22898: } 22899: } 22900: } 22901: my $nochgmsg = &mt('No changes made to trust settings.'); 22902: if (keys(%changes) > 0) { 22903: my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, 22904: $dom); 22905: if ($putresult eq 'ok') { 22906: if (ref($defaultshash{'trust'}) eq 'HASH') { 22907: foreach my $prefix (@prefixes) { 22908: if (ref($defaultshash{'trust'}{$prefix}) eq 'HASH') { 22909: $domdefaults{'trust'.$prefix} = $defaultshash{'trust'}{$prefix}; 22910: } 22911: } 22912: } 22913: my $cachetime = 24*60*60; 22914: &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); 22915: &Apache::lonnet::do_cache_new('trust',$dom,$defaultshash{'trust'},3600); 22916: if (ref($lastactref) eq 'HASH') { 22917: $lastactref->{'domdefaults'} = 1; 22918: $lastactref->{'trust'} = 1; 22919: } 22920: if (keys(%changes) > 0) { 22921: my %lt = &trust_titles(); 22922: $resulttext = &mt('Changes made:').'<ul>'; 22923: foreach my $prefix (@prefixes) { 22924: if (ref($changes{$prefix}) eq 'HASH') { 22925: $resulttext .= '<li>'.$lt{$prefix}.'<ul>'; 22926: foreach my $type (@types) { 22927: if (defined($changes{$prefix}{$type})) { 22928: my ($newvalue,$notinuse); 22929: if (ref($defaultshash{'trust'}) eq 'HASH') { 22930: if (ref($defaultshash{'trust'}{$prefix})) { 22931: if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') { 22932: if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) { 22933: $newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}}); 22934: } 22935: } else { 22936: $notinuse = 1; 22937: } 22938: } 22939: } 22940: if ($notinuse) { 22941: $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>'; 22942: } elsif ($newvalue eq '') { 22943: $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>'; 22944: } else { 22945: $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>'; 22946: } 22947: } 22948: } 22949: $resulttext .= '</ul>'; 22950: } 22951: } 22952: $resulttext .= '</ul>'; 22953: } else { 22954: $resulttext = $nochgmsg; 22955: } 22956: } else { 22957: $resulttext = '<span class="LC_error">'. 22958: &mt('An error occurred: [_1]',$putresult).'</span>'; 22959: } 22960: } else { 22961: $resulttext = $nochgmsg; 22962: } 22963: return $resulttext; 22964: } 22965: 22966: sub modify_loadbalancing { 22967: my ($dom,%domconfig) = @_; 22968: my $primary_id = &Apache::lonnet::domain($dom,'primary'); 22969: my $intdom = &Apache::lonnet::internet_dom($primary_id); 22970: my ($othertitle,$usertypes,$types) = 22971: &Apache::loncommon::sorted_inst_types($dom); 22972: my %servers = &Apache::lonnet::internet_dom_servers($dom); 22973: my %libraryservers = &Apache::lonnet::get_servers($dom,'library'); 22974: my @sparestypes = ('primary','default'); 22975: my %typetitles = &sparestype_titles(); 22976: my $resulttext; 22977: my (%currbalancer,%currtargets,%currrules,%existing,%currcookies); 22978: if (ref($domconfig{'loadbalancing'}) eq 'HASH') { 22979: %existing = %{$domconfig{'loadbalancing'}}; 22980: } 22981: &get_loadbalancers_config(\%servers,\%existing,\%currbalancer, 22982: \%currtargets,\%currrules,\%currcookies); 22983: my ($saveloadbalancing,%defaultshash,%changes); 22984: my ($alltypes,$othertypes,$titles) = 22985: &loadbalancing_titles($dom,$intdom,$usertypes,$types); 22986: my %ruletitles = &offloadtype_text(); 22987: my @deletions = &Apache::loncommon::get_env_multiple('form.loadbalancing_delete'); 22988: for (my $i=0; $i<$env{'form.loadbalancing_total'}; $i++) { 22989: my $balancer = $env{'form.loadbalancing_lonhost_'.$i}; 22990: if ($balancer eq '') { 22991: next; 22992: } 22993: if (!exists($servers{$balancer})) { 22994: if (exists($currbalancer{$balancer})) { 22995: push(@{$changes{'delete'}},$balancer); 22996: } 22997: next; 22998: } 22999: if ((@deletions > 0) && (grep(/^\Q$i\E$/,@deletions))) { 23000: push(@{$changes{'delete'}},$balancer); 23001: next; 23002: } 23003: if (!exists($currbalancer{$balancer})) { 23004: push(@{$changes{'add'}},$balancer); 23005: } 23006: $defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'} = []; 23007: $defaultshash{'loadbalancing'}{$balancer}{'targets'}{'default'} = []; 23008: $defaultshash{'loadbalancing'}{$balancer}{'rules'} = {}; 23009: unless (ref($domconfig{'loadbalancing'}) eq 'HASH') { 23010: $saveloadbalancing = 1; 23011: } 23012: foreach my $sparetype (@sparestypes) { 23013: my @targets = &Apache::loncommon::get_env_multiple('form.loadbalancing_target_'.$i.'_'.$sparetype); 23014: my @offloadto; 23015: foreach my $target (@targets) { 23016: if (($servers{$target}) && ($target ne $balancer)) { 23017: if ($sparetype eq 'default') { 23018: if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'}) eq 'ARRAY') { 23019: next if (grep(/^\Q$target\E$/,@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'}})); 23020: } 23021: } 23022: unless(grep(/^\Q$target\E$/,@offloadto)) { 23023: push(@offloadto,$target); 23024: } 23025: } 23026: } 23027: if ($env{'form.loadbalancing_target_'.$i.'_hosthere'} eq $sparetype) { 23028: unless(grep(/^\Q$balancer\E$/,@offloadto)) { 23029: push(@offloadto,$balancer); 23030: } 23031: } 23032: $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto; 23033: } 23034: if ($env{'form.loadbalancing_cookie_'.$i}) { 23035: $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1; 23036: if (exists($currbalancer{$balancer})) { 23037: unless ($currcookies{$balancer}) { 23038: $changes{'curr'}{$balancer}{'cookie'} = 1; 23039: } 23040: } 23041: } elsif (exists($currbalancer{$balancer})) { 23042: if ($currcookies{$balancer}) { 23043: $changes{'curr'}{$balancer}{'cookie'} = 1; 23044: } 23045: } 23046: if (ref($currtargets{$balancer}) eq 'HASH') { 23047: foreach my $sparetype (@sparestypes) { 23048: if (ref($currtargets{$balancer}{$sparetype}) eq 'ARRAY') { 23049: my @targetdiffs = &Apache::loncommon::compare_arrays($currtargets{$balancer}{$sparetype},$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}); 23050: if (@targetdiffs > 0) { 23051: $changes{'curr'}{$balancer}{'targets'} = 1; 23052: } 23053: } elsif (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { 23054: if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) { 23055: $changes{'curr'}{$balancer}{'targets'} = 1; 23056: } 23057: } 23058: } 23059: } else { 23060: if (ref($defaultshash{'loadbalancing'}{$balancer}) eq 'HASH') { 23061: foreach my $sparetype (@sparestypes) { 23062: if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { 23063: if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) { 23064: $changes{'curr'}{$balancer}{'targets'} = 1; 23065: } 23066: } 23067: } 23068: } 23069: } 23070: my $ishomedom; 23071: if (&Apache::lonnet::host_domain($balancer) eq $dom) { 23072: $ishomedom = 1; 23073: } 23074: if (ref($alltypes) eq 'ARRAY') { 23075: foreach my $type (@{$alltypes}) { 23076: my $rule; 23077: unless ((($type eq '_LC_external') || ($type eq '_LC_internetdom')) && 23078: (!$ishomedom)) { 23079: $rule = $env{'form.loadbalancing_rules_'.$i.'_'.$type}; 23080: } 23081: if ($rule eq 'specific') { 23082: my $specifiedhost = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type}; 23083: if (exists($servers{$specifiedhost})) { 23084: $rule = $specifiedhost; 23085: } 23086: } 23087: $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type} = $rule; 23088: if (ref($currrules{$balancer}) eq 'HASH') { 23089: if ($rule ne $currrules{$balancer}{$type}) { 23090: $changes{'curr'}{$balancer}{'rules'}{$type} = 1; 23091: } 23092: } elsif ($rule ne '') { 23093: $changes{'curr'}{$balancer}{'rules'}{$type} = 1; 23094: } 23095: } 23096: } 23097: } 23098: my $nochgmsg = &mt('No changes made to Load Balancer settings.'); 23099: if ((keys(%changes) > 0) || ($saveloadbalancing)) { 23100: unless (ref($defaultshash{'loadbalancing'}) eq 'HASH') { 23101: $defaultshash{'loadbalancing'} = {}; 23102: } 23103: my $putresult = &Apache::lonnet::put_dom('configuration', 23104: \%defaultshash,$dom); 23105: if ($putresult eq 'ok') { 23106: if (keys(%changes) > 0) { 23107: my %toupdate; 23108: if (ref($changes{'delete'}) eq 'ARRAY') { 23109: foreach my $balancer (sort(@{$changes{'delete'}})) { 23110: $resulttext .= '<li>'.&mt('Load Balancing discontinued for: [_1]',$balancer).'</li>'; 23111: $toupdate{$balancer} = 1; 23112: } 23113: } 23114: if (ref($changes{'add'}) eq 'ARRAY') { 23115: foreach my $balancer (sort(@{$changes{'add'}})) { 23116: $resulttext .= '<li>'.&mt('Load Balancing enabled for: [_1]',$balancer); 23117: $toupdate{$balancer} = 1; 23118: } 23119: } 23120: if (ref($changes{'curr'}) eq 'HASH') { 23121: foreach my $balancer (sort(keys(%{$changes{'curr'}}))) { 23122: $toupdate{$balancer} = 1; 23123: if (ref($changes{'curr'}{$balancer}) eq 'HASH') { 23124: if ($changes{'curr'}{$balancer}{'targets'}) { 23125: my %offloadstr; 23126: foreach my $sparetype (@sparestypes) { 23127: if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { 23128: if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) { 23129: $offloadstr{$sparetype} = join(', ',@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}}); 23130: } 23131: } 23132: } 23133: if (keys(%offloadstr) == 0) { 23134: $resulttext .= '<li>'.&mt("Servers to which Load Balance server offloads set to 'None', by default").'</li>'; 23135: } else { 23136: my $showoffload; 23137: foreach my $sparetype (@sparestypes) { 23138: $showoffload .= '<i>'.$typetitles{$sparetype}.'</i>: '; 23139: if (defined($offloadstr{$sparetype})) { 23140: $showoffload .= $offloadstr{$sparetype}; 23141: } else { 23142: $showoffload .= &mt('None'); 23143: } 23144: $showoffload .= (' 'x3); 23145: } 23146: $resulttext .= '<li>'.&mt('By default, Load Balancer: [_1] set to offload to - [_2]',$balancer,$showoffload).'</li>'; 23147: } 23148: } 23149: } 23150: if (ref($changes{'curr'}{$balancer}{'rules'}) eq 'HASH') { 23151: if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) { 23152: foreach my $type (@{$alltypes}) { 23153: if ($changes{'curr'}{$balancer}{'rules'}{$type}) { 23154: my $rule = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type}; 23155: my $balancetext; 23156: if ($rule eq '') { 23157: $balancetext = $ruletitles{'default'}; 23158: } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') || 23159: ($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) { 23160: if (($type eq '_LC_ipchange') || ($type eq '_LC_ipchangesso')) { 23161: foreach my $sparetype (@sparestypes) { 23162: if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { 23163: map { $toupdate{$_} = 1; } (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}}); 23164: } 23165: } 23166: foreach my $item (@{$alltypes}) { 23167: next if ($item =~ /^_LC_ipchange/); 23168: my $hasrule = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$item}; 23169: if ($hasrule eq 'homeserver') { 23170: map { $toupdate{$_} = 1; } (keys(%libraryservers)); 23171: } else { 23172: unless (($hasrule eq 'default') || ($hasrule eq 'none') || ($hasrule eq 'externalbalancer')) { 23173: if ($servers{$hasrule}) { 23174: $toupdate{$hasrule} = 1; 23175: } 23176: } 23177: } 23178: } 23179: if (($rule eq 'balancer') || ($rule eq 'offloadedto')) { 23180: $balancetext = $ruletitles{$rule}; 23181: } else { 23182: my $receiver = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type}; 23183: $balancetext = $ruletitles{'particular'}.' '.$receiver; 23184: if ($receiver) { 23185: $toupdate{$receiver}; 23186: } 23187: } 23188: } else { 23189: $balancetext = $ruletitles{$rule}; 23190: } 23191: } else { 23192: $balancetext = &mt('offload to [_1]',$defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type}); 23193: } 23194: $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- balancing for [_2] set to - "[_3]"',$balancer,$titles->{$type},$balancetext).'</li>'; 23195: } 23196: } 23197: } 23198: } 23199: if ($changes{'curr'}{$balancer}{'cookie'}) { 23200: if ($currcookies{$balancer}) { 23201: $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use disabled', 23202: $balancer).'</li>'; 23203: } else { 23204: $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled', 23205: $balancer).'</li>'; 23206: } 23207: } 23208: } 23209: } 23210: if (keys(%toupdate)) { 23211: my %thismachine; 23212: my $updatedhere; 23213: my $cachetime = 60*60*24; 23214: map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); 23215: foreach my $lonhost (keys(%toupdate)) { 23216: if ($thismachine{$lonhost}) { 23217: unless ($updatedhere) { 23218: &Apache::lonnet::do_cache_new('loadbalancing',$dom, 23219: $defaultshash{'loadbalancing'}, 23220: $cachetime); 23221: $updatedhere = 1; 23222: } 23223: } else { 23224: my $cachekey = &escape('loadbalancing').':'.&escape($dom); 23225: &Apache::lonnet::remote_devalidate_cache($lonhost,[$cachekey]); 23226: } 23227: } 23228: } 23229: if ($resulttext ne '') { 23230: $resulttext = &mt('Changes made:').'<ul>'.$resulttext.'</ul>'; 23231: } else { 23232: $resulttext = $nochgmsg; 23233: } 23234: } else { 23235: $resulttext = $nochgmsg; 23236: } 23237: } else { 23238: $resulttext = '<span class="LC_error">'. 23239: &mt('An error occurred: [_1]',$putresult).'</span>'; 23240: } 23241: } else { 23242: $resulttext = $nochgmsg; 23243: } 23244: return $resulttext; 23245: } 23246: 23247: sub recurse_check { 23248: my ($chkcats,$categories,$depth,$name) = @_; 23249: if (ref($chkcats->[$depth]{$name}) eq 'ARRAY') { 23250: my $chg = 0; 23251: for (my $j=0; $j<@{$chkcats->[$depth]{$name}}; $j++) { 23252: my $category = $chkcats->[$depth]{$name}[$j]; 23253: my $item; 23254: if ($category eq '') { 23255: $chg ++; 23256: } else { 23257: my $deeper = $depth + 1; 23258: $item = &escape($category).':'.&escape($name).':'.$depth; 23259: if ($chg) { 23260: $categories->{$item} -= $chg; 23261: } 23262: &recurse_check($chkcats,$categories,$deeper,$category); 23263: $deeper --; 23264: } 23265: } 23266: } 23267: return; 23268: } 23269: 23270: sub recurse_cat_deletes { 23271: my ($item,$coursecategories,$deletions) = @_; 23272: my ($deleted,$container,$depth) = map { &unescape($_); } split(/:/,$item); 23273: my $subdepth = $depth + 1; 23274: if (ref($coursecategories) eq 'HASH') { 23275: foreach my $subitem (keys(%{$coursecategories})) { 23276: my ($child,$parent,$itemdepth) = map { &unescape($_); } split(/:/,$subitem); 23277: if (($parent eq $deleted) && ($itemdepth == $subdepth)) { 23278: delete($coursecategories->{$subitem}); 23279: $deletions->{$subitem} = 1; 23280: &recurse_cat_deletes($subitem,$coursecategories,$deletions); 23281: } 23282: } 23283: } 23284: return; 23285: } 23286: 23287: sub active_dc_picker { 23288: my ($dom,$numinrow,$inputtype,$name,%currhash) = @_; 23289: my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']); 23290: my @domcoord = keys(%domcoords); 23291: if (keys(%currhash)) { 23292: foreach my $dc (keys(%currhash)) { 23293: unless (exists($domcoords{$dc})) { 23294: push(@domcoord,$dc); 23295: } 23296: } 23297: } 23298: @domcoord = sort(@domcoord); 23299: my $numdcs = scalar(@domcoord); 23300: my $rows = 0; 23301: my $table; 23302: if ($numdcs > 1) { 23303: $table = '<table>'; 23304: for (my $i=0; $i<@domcoord; $i++) { 23305: my $rem = $i%($numinrow); 23306: if ($rem == 0) { 23307: if ($i > 0) { 23308: $table .= '</tr>'; 23309: } 23310: $table .= '<tr>'; 23311: $rows ++; 23312: } 23313: my $check = ''; 23314: if ($inputtype eq 'radio') { 23315: if (keys(%currhash) == 0) { 23316: if (!$i) { 23317: $check = ' checked="checked"'; 23318: } 23319: } elsif (exists($currhash{$domcoord[$i]})) { 23320: $check = ' checked="checked"'; 23321: } 23322: } else { 23323: if (exists($currhash{$domcoord[$i]})) { 23324: $check = ' checked="checked"'; 23325: } 23326: } 23327: if ($i == @domcoord - 1) { 23328: my $colsleft = $numinrow - $rem; 23329: if ($colsleft > 1) { 23330: $table .= '<td class="LC_left_item" colspan="'.$colsleft.'">'; 23331: } else { 23332: $table .= '<td class="LC_left_item">'; 23333: } 23334: } else { 23335: $table .= '<td class="LC_left_item">'; 23336: } 23337: my ($dcname,$dcdom) = split(':',$domcoord[$i]); 23338: my $user = &Apache::loncommon::plainname($dcname,$dcdom); 23339: $table .= '<span class="LC_nobreak"><label>'. 23340: '<input type="'.$inputtype.'" name="'.$name.'"'. 23341: ' value="'.$domcoord[$i].'"'.$check.' />'.$user; 23342: if ($user ne $dcname.':'.$dcdom) { 23343: $table .= ' ('.$dcname.':'.$dcdom.')'; 23344: } 23345: $table .= '</label></span></td>'; 23346: } 23347: $table .= '</tr></table>'; 23348: } elsif ($numdcs == 1) { 23349: my ($dcname,$dcdom) = split(':',$domcoord[0]); 23350: my $user = &Apache::loncommon::plainname($dcname,$dcdom); 23351: if ($inputtype eq 'radio') { 23352: $table = '<input type="hidden" name="'.$name.'" value="'.$domcoord[0].'" />'.$user; 23353: if ($user ne $dcname.':'.$dcdom) { 23354: $table .= ' ('.$dcname.':'.$dcdom.')'; 23355: } 23356: } else { 23357: my $check; 23358: if (exists($currhash{$domcoord[0]})) { 23359: $check = ' checked="checked"'; 23360: } 23361: $table = '<span class="LC_nobreak"><label>'. 23362: '<input type="checkbox" name="'.$name.'" '. 23363: 'value="'.$domcoord[0].'"'.$check.' />'.$user; 23364: if ($user ne $dcname.':'.$dcdom) { 23365: $table .= ' ('.$dcname.':'.$dcdom.')'; 23366: } 23367: $table .= '</label></span>'; 23368: $rows ++; 23369: } 23370: } 23371: return ($numdcs,$table,$rows); 23372: } 23373: 23374: sub usersession_titles { 23375: return &Apache::lonlocal::texthash( 23376: hosted => 'Hosting of sessions for users from other domains on servers in this domain', 23377: remote => 'Hosting of sessions for users in this domain on servers in other domains', 23378: spares => 'Servers offloaded to, when busy', 23379: version => 'LON-CAPA version requirement', 23380: excludedomain => 'Allow all, but exclude specific domains', 23381: includedomain => 'Deny all, but include specific domains', 23382: primary => 'Primary (checked first)', 23383: default => 'Default', 23384: ); 23385: } 23386: 23387: sub id_for_thisdom { 23388: my (%servers) = @_; 23389: my %altids; 23390: foreach my $server (keys(%servers)) { 23391: my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server}); 23392: if ($serverhome ne $server) { 23393: $altids{$serverhome} = $server; 23394: } 23395: } 23396: return %altids; 23397: } 23398: 23399: sub count_servers { 23400: my ($currbalancer,%servers) = @_; 23401: my (@spares,$numspares); 23402: foreach my $lonhost (sort(keys(%servers))) { 23403: next if ($currbalancer eq $lonhost); 23404: push(@spares,$lonhost); 23405: } 23406: if ($currbalancer) { 23407: $numspares = scalar(@spares); 23408: } else { 23409: $numspares = scalar(@spares) - 1; 23410: } 23411: return ($numspares,@spares); 23412: } 23413: 23414: sub lonbalance_targets_js { 23415: my ($dom,$types,$servers,$settings) = @_; 23416: my $select = &mt('Select'); 23417: my ($alltargets,$allishome,$allinsttypes,@alltypes); 23418: if (ref($servers) eq 'HASH') { 23419: $alltargets = join("','",sort(keys(%{$servers}))); 23420: my @homedoms; 23421: foreach my $server (sort(keys(%{$servers}))) { 23422: if (&Apache::lonnet::host_domain($server) eq $dom) { 23423: push(@homedoms,'1'); 23424: } else { 23425: push(@homedoms,'0'); 23426: } 23427: } 23428: $allishome = join("','",@homedoms); 23429: } 23430: if (ref($types) eq 'ARRAY') { 23431: if (@{$types} > 0) { 23432: @alltypes = @{$types}; 23433: } 23434: } 23435: push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external'); 23436: $allinsttypes = join("','",@alltypes); 23437: my (%currbalancer,%currtargets,%currrules,%existing,%currcookies); 23438: if (ref($settings) eq 'HASH') { 23439: %existing = %{$settings}; 23440: } 23441: &get_loadbalancers_config($servers,\%existing,\%currbalancer, 23442: \%currtargets,\%currrules,\%currcookies); 23443: my $balancers = join("','",sort(keys(%currbalancer))); 23444: return <<"END"; 23445: 23446: <script type="text/javascript"> 23447: // <![CDATA[ 23448: 23449: currBalancers = new Array('$balancers'); 23450: 23451: function toggleTargets(balnum) { 23452: var lonhostitem = document.getElementById('loadbalancing_lonhost_'+balnum); 23453: var prevhostitem = document.getElementById('loadbalancing_prevlonhost_'+balnum); 23454: var balancer = lonhostitem.options[lonhostitem.selectedIndex].value; 23455: var prevbalancer = prevhostitem.value; 23456: var baltotal = document.getElementById('loadbalancing_total').value; 23457: prevhostitem.value = balancer; 23458: if (prevbalancer != '') { 23459: var prevIdx = currBalancers.indexOf(prevbalancer); 23460: if (prevIdx != -1) { 23461: currBalancers.splice(prevIdx,1); 23462: } 23463: } 23464: if (balancer == '') { 23465: hideSpares(balnum); 23466: } else { 23467: var currIdx = currBalancers.indexOf(balancer); 23468: if (currIdx == -1) { 23469: currBalancers.push(balancer); 23470: } 23471: var homedoms = new Array('$allishome'); 23472: var ishomedom = homedoms[lonhostitem.selectedIndex]; 23473: showSpares(balancer,ishomedom,balnum); 23474: } 23475: balancerChange(balnum,baltotal,'change',prevbalancer,balancer); 23476: return; 23477: } 23478: 23479: function showSpares(balancer,ishomedom,balnum) { 23480: var alltargets = new Array('$alltargets'); 23481: var insttypes = new Array('$allinsttypes'); 23482: var offloadtypes = new Array('primary','default'); 23483: 23484: document.getElementById('loadbalancing_targets_'+balnum).style.display='block'; 23485: document.getElementById('loadbalancing_disabled_'+balnum).style.display='none'; 23486: 23487: for (var i=0; i<offloadtypes.length; i++) { 23488: var count = 0; 23489: for (var j=0; j<alltargets.length; j++) { 23490: if (alltargets[j] != balancer) { 23491: var item = document.getElementById('loadbalancing_target_'+balnum+'_'+offloadtypes[i]+'_'+count); 23492: item.value = alltargets[j]; 23493: item.style.textAlign='left'; 23494: item.style.textFace='normal'; 23495: document.getElementById('loadbalancing_targettxt_'+balnum+'_'+offloadtypes[i]+'_'+count).innerHTML = alltargets[j]; 23496: if (currBalancers.indexOf(alltargets[j]) == -1) { 23497: item.disabled = ''; 23498: } else { 23499: item.disabled = 'disabled'; 23500: item.checked = false; 23501: } 23502: count ++; 23503: } 23504: } 23505: } 23506: for (var k=0; k<insttypes.length; k++) { 23507: if ((insttypes[k] == '_LC_external') || (insttypes[k] == '_LC_internetdom')) { 23508: if (ishomedom == 1) { 23509: document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='block'; 23510: document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='block'; 23511: } else { 23512: document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='none'; 23513: document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='none'; 23514: } 23515: } else { 23516: document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='block'; 23517: document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='block'; 23518: } 23519: if ((insttypes[k] != '_LC_external') && 23520: ((insttypes[k] != '_LC_internetdom') || 23521: ((insttypes[k] == '_LC_internetdom') && (ishomedom == 1)))) { 23522: var item = document.getElementById('loadbalancing_singleserver_'+balnum+'_'+insttypes[k]); 23523: item.options.length = 0; 23524: item.options[0] = new Option("","",true,true); 23525: var idx = 0; 23526: for (var m=0; m<alltargets.length; m++) { 23527: if ((currBalancers.indexOf(alltargets[m]) == -1) && (alltargets[m] != balancer)) { 23528: idx ++; 23529: item.options[idx] = new Option(alltargets[m],alltargets[m],false,false); 23530: } 23531: } 23532: } 23533: } 23534: return; 23535: } 23536: 23537: function hideSpares(balnum) { 23538: var alltargets = new Array('$alltargets'); 23539: var insttypes = new Array('$allinsttypes'); 23540: var offloadtypes = new Array('primary','default'); 23541: 23542: document.getElementById('loadbalancing_targets_'+balnum).style.display='none'; 23543: document.getElementById('loadbalancing_disabled_'+balnum).style.display='block'; 23544: 23545: var total = alltargets.length - 1; 23546: for (var i=0; i<offloadtypes; i++) { 23547: for (var j=0; j<total; j++) { 23548: document.getElementById('loadbalancing_target_'+balnum+'_'+offloadtypes[i]+'_'+j).checked = false; 23549: document.getElementById('loadbalancing_target_'+balnum+'_'+offloadtypes[i]+'_'+j).value = ''; 23550: document.getElementById('loadbalancing_targettxt_'+balnum+'_'+offloadtypes[i]+'_'+j).innerHTML = ''; 23551: } 23552: } 23553: for (var k=0; k<insttypes.length; k++) { 23554: document.getElementById('balanceruletitle_'+balnum+'_'+insttypes[k]).style.display='none'; 23555: document.getElementById('balancerule_'+balnum+'_'+insttypes[k]).style.display='none'; 23556: if (insttypes[k] != '_LC_external') { 23557: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+insttypes[k]).length = 0; 23558: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+insttypes[k]).options[0] = new Option("","",true,true); 23559: } 23560: } 23561: return; 23562: } 23563: 23564: function checkOffloads(item,balnum,type) { 23565: var alltargets = new Array('$alltargets'); 23566: var offloadtypes = new Array('primary','default'); 23567: if (item.checked) { 23568: var total = alltargets.length - 1; 23569: var other; 23570: if (type == offloadtypes[0]) { 23571: other = offloadtypes[1]; 23572: } else { 23573: other = offloadtypes[0]; 23574: } 23575: for (var i=0; i<total; i++) { 23576: var server = document.getElementById('loadbalancing_target_'+balnum+'_'+other+'_'+i).value; 23577: if (server == item.value) { 23578: if (document.getElementById('loadbalancing_target_'+balnum+'_'+other+'_'+i).checked) { 23579: document.getElementById('loadbalancing_target_'+balnum+'_'+other+'_'+i).checked = false; 23580: } 23581: } 23582: } 23583: } 23584: return; 23585: } 23586: 23587: function singleServerToggle(balnum,type) { 23588: var offloadtoSelIdx = document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).selectedIndex; 23589: if (offloadtoSelIdx == 0) { 23590: document.getElementById('loadbalancing_rules_'+balnum+'_'+type+'_0').checked = true; 23591: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = ''; 23592: 23593: } else { 23594: document.getElementById('loadbalancing_rules_'+balnum+'_'+type+'_2').checked = true; 23595: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = '$select'; 23596: } 23597: return; 23598: } 23599: 23600: function balanceruleChange(formname,balnum,type) { 23601: if (type == '_LC_external') { 23602: return; 23603: } 23604: var typesRules = getIndicesByName(formname,'loadbalancing_rules_'+balnum+'_'+type); 23605: for (var i=0; i<typesRules.length; i++) { 23606: if (formname.elements[typesRules[i]].checked) { 23607: if (formname.elements[typesRules[i]].value != 'specific') { 23608: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).selectedIndex = 0; 23609: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = ''; 23610: } else { 23611: document.getElementById('loadbalancing_singleserver_'+balnum+'_'+type).options[0].text = '$select'; 23612: } 23613: } 23614: } 23615: return; 23616: } 23617: 23618: function balancerDeleteChange(balnum) { 23619: var hostitem = document.getElementById('loadbalancing_lonhost_'+balnum); 23620: var baltotal = document.getElementById('loadbalancing_total').value; 23621: var addtarget; 23622: var removetarget; 23623: var action = 'delete'; 23624: if (document.getElementById('loadbalancing_delete_'+balnum)) { 23625: var lonhost = hostitem.value; 23626: var currIdx = currBalancers.indexOf(lonhost); 23627: if (document.getElementById('loadbalancing_delete_'+balnum).checked) { 23628: if (currIdx != -1) { 23629: currBalancers.splice(currIdx,1); 23630: } 23631: addtarget = lonhost; 23632: } else { 23633: if (currIdx == -1) { 23634: currBalancers.push(lonhost); 23635: } 23636: removetarget = lonhost; 23637: action = 'undelete'; 23638: } 23639: balancerChange(balnum,baltotal,action,addtarget,removetarget); 23640: } 23641: return; 23642: } 23643: 23644: function balancerChange(balnum,baltotal,action,addtarget,removetarget) { 23645: if (baltotal > 1) { 23646: var offloadtypes = new Array('primary','default'); 23647: var alltargets = new Array('$alltargets'); 23648: var insttypes = new Array('$allinsttypes'); 23649: for (var i=0; i<baltotal; i++) { 23650: if (i != balnum) { 23651: for (var j=0; j<offloadtypes.length; j++) { 23652: var total = alltargets.length - 1; 23653: for (var k=0; k<total; k++) { 23654: var serveritem = document.getElementById('loadbalancing_target_'+i+'_'+offloadtypes[j]+'_'+k); 23655: var server = serveritem.value; 23656: if ((action == 'delete') || (action == 'change' && addtarget != '')) { 23657: if (server == addtarget) { 23658: serveritem.disabled = ''; 23659: } 23660: } 23661: if ((action == 'undelete') || (action == 'change' && removetarget != '')) { 23662: if (server == removetarget) { 23663: serveritem.disabled = 'disabled'; 23664: serveritem.checked = false; 23665: } 23666: } 23667: } 23668: } 23669: for (var j=0; j<insttypes.length; j++) { 23670: if (insttypes[j] != '_LC_external') { 23671: if (document.getElementById('loadbalancing_singleserver_'+i+'_'+insttypes[j])) { 23672: var singleserver = document.getElementById('loadbalancing_singleserver_'+i+'_'+insttypes[j]); 23673: var currSel = singleserver.selectedIndex; 23674: var currVal = singleserver.options[currSel].value; 23675: if ((action == 'delete') || (action == 'change' && addtarget != '')) { 23676: var numoptions = singleserver.options.length; 23677: var needsnew = 1; 23678: for (var k=0; k<numoptions; k++) { 23679: if (singleserver.options[k] == addtarget) { 23680: needsnew = 0; 23681: break; 23682: } 23683: } 23684: if (needsnew == 1) { 23685: singleserver.options[numoptions] = new Option(addtarget,addtarget,false,false); 23686: } 23687: } 23688: if ((action == 'undelete') || (action == 'change' && removetarget != '')) { 23689: singleserver.options.length = 0; 23690: if ((currVal) && (currVal != removetarget)) { 23691: singleserver.options[0] = new Option("","",false,false); 23692: } else { 23693: singleserver.options[0] = new Option("","",true,true); 23694: } 23695: var idx = 0; 23696: for (var m=0; m<alltargets.length; m++) { 23697: if (currBalancers.indexOf(alltargets[m]) == -1) { 23698: idx ++; 23699: if (currVal == alltargets[m]) { 23700: singleserver.options[idx] = new Option(alltargets[m],alltargets[m],true,true); 23701: } else { 23702: singleserver.options[idx] = new Option(alltargets[m],alltargets[m],false,false); 23703: } 23704: } 23705: } 23706: } 23707: } 23708: } 23709: } 23710: } 23711: } 23712: } 23713: return; 23714: } 23715: 23716: // ]]> 23717: </script> 23718: 23719: END 23720: } 23721: 23722: 23723: sub new_spares_js { 23724: my @sparestypes = ('primary','default'); 23725: my $types = join("','",@sparestypes); 23726: my $select = &mt('Select'); 23727: return <<"END"; 23728: 23729: <script type="text/javascript"> 23730: // <![CDATA[ 23731: 23732: function updateNewSpares(formname,lonhost) { 23733: var types = new Array('$types'); 23734: var include = new Array(); 23735: var exclude = new Array(); 23736: for (var i=0; i<types.length; i++) { 23737: var spareboxes = getIndicesByName(formname,'spare_'+types[i]+'_'+lonhost); 23738: for (var j=0; j<spareboxes.length; j++) { 23739: if (formname.elements[spareboxes[j]].checked) { 23740: exclude.push(formname.elements[spareboxes[j]].value); 23741: } else { 23742: include.push(formname.elements[spareboxes[j]].value); 23743: } 23744: } 23745: } 23746: for (var i=0; i<types.length; i++) { 23747: var newSpare = document.getElementById('newspare_'+types[i]+'_'+lonhost); 23748: var selIdx = newSpare.selectedIndex; 23749: var currnew = newSpare.options[selIdx].value; 23750: var okSpares = new Array(); 23751: for (var j=0; j<newSpare.options.length; j++) { 23752: var possible = newSpare.options[j].value; 23753: if (possible != '') { 23754: if (exclude.indexOf(possible) == -1) { 23755: okSpares.push(possible); 23756: } else { 23757: if (currnew == possible) { 23758: selIdx = 0; 23759: } 23760: } 23761: } 23762: } 23763: for (var k=0; k<include.length; k++) { 23764: if (okSpares.indexOf(include[k]) == -1) { 23765: okSpares.push(include[k]); 23766: } 23767: } 23768: okSpares.sort(); 23769: newSpare.options.length = 0; 23770: if (selIdx == 0) { 23771: newSpare.options[0] = new Option("$select","",true,true); 23772: } else { 23773: newSpare.options[0] = new Option("$select","",false,false); 23774: } 23775: for (var m=0; m<okSpares.length; m++) { 23776: var idx = m+1; 23777: var selThis = 0; 23778: if (selIdx != 0) { 23779: if (okSpares[m] == currnew) { 23780: selThis = 1; 23781: } 23782: } 23783: if (selThis == 1) { 23784: newSpare.options[idx] = new Option(okSpares[m],okSpares[m],true,true); 23785: } else { 23786: newSpare.options[idx] = new Option(okSpares[m],okSpares[m],false,false); 23787: } 23788: } 23789: } 23790: return; 23791: } 23792: 23793: function checkNewSpares(lonhost,type) { 23794: var newSpare = document.getElementById('newspare_'+type+'_'+lonhost); 23795: var chosen = newSpare.options[newSpare.selectedIndex].value; 23796: if (chosen != '') { 23797: var othertype; 23798: var othernewSpare; 23799: if (type == 'primary') { 23800: othernewSpare = document.getElementById('newspare_default_'+lonhost); 23801: } 23802: if (type == 'default') { 23803: othernewSpare = document.getElementById('newspare_primary_'+lonhost); 23804: } 23805: if (othernewSpare.options[othernewSpare.selectedIndex].value == chosen) { 23806: othernewSpare.selectedIndex = 0; 23807: } 23808: } 23809: return; 23810: } 23811: 23812: // ]]> 23813: </script> 23814: 23815: END 23816: 23817: } 23818: 23819: sub common_domprefs_js { 23820: return <<"END"; 23821: 23822: <script type="text/javascript"> 23823: // <![CDATA[ 23824: 23825: function getIndicesByName(formname,item) { 23826: var group = new Array(); 23827: for (var i=0;i<formname.elements.length;i++) { 23828: if (formname.elements[i].name == item) { 23829: group.push(formname.elements[i].id); 23830: } 23831: } 23832: return group; 23833: } 23834: 23835: // ]]> 23836: </script> 23837: 23838: END 23839: 23840: } 23841: 23842: sub recaptcha_js { 23843: my %lt = &captcha_phrases(); 23844: return <<"END"; 23845: 23846: <script type="text/javascript"> 23847: // <![CDATA[ 23848: 23849: function updateCaptcha(caller,context) { 23850: var privitem; 23851: var pubitem; 23852: var privtext; 23853: var pubtext; 23854: var versionitem; 23855: var versiontext; 23856: if (document.getElementById(context+'_recaptchapub')) { 23857: pubitem = document.getElementById(context+'_recaptchapub'); 23858: } else { 23859: return; 23860: } 23861: if (document.getElementById(context+'_recaptchapriv')) { 23862: privitem = document.getElementById(context+'_recaptchapriv'); 23863: } else { 23864: return; 23865: } 23866: if (document.getElementById(context+'_recaptchapubtxt')) { 23867: pubtext = document.getElementById(context+'_recaptchapubtxt'); 23868: } else { 23869: return; 23870: } 23871: if (document.getElementById(context+'_recaptchaprivtxt')) { 23872: privtext = document.getElementById(context+'_recaptchaprivtxt'); 23873: } else { 23874: return; 23875: } 23876: if (document.getElementById(context+'_recaptchaversion')) { 23877: versionitem = document.getElementById(context+'_recaptchaversion'); 23878: } else { 23879: return; 23880: } 23881: if (document.getElementById(context+'_recaptchavertxt')) { 23882: versiontext = document.getElementById(context+'_recaptchavertxt'); 23883: } else { 23884: return; 23885: } 23886: if (caller.checked) { 23887: if (caller.value == 'recaptcha') { 23888: pubitem.type = 'text'; 23889: privitem.type = 'text'; 23890: pubitem.size = '40'; 23891: privitem.size = '40'; 23892: pubtext.innerHTML = "$lt{'pub'}"; 23893: privtext.innerHTML = "$lt{'priv'}"; 23894: versionitem.type = 'text'; 23895: versionitem.size = '3'; 23896: versiontext.innerHTML = "$lt{'ver'}"; 23897: } else { 23898: pubitem.type = 'hidden'; 23899: privitem.type = 'hidden'; 23900: versionitem.type = 'hidden'; 23901: pubtext.innerHTML = ''; 23902: privtext.innerHTML = ''; 23903: versiontext.innerHTML = ''; 23904: } 23905: } 23906: return; 23907: } 23908: 23909: // ]]> 23910: </script> 23911: 23912: END 23913: 23914: } 23915: 23916: sub toggle_display_js { 23917: return <<"END"; 23918: 23919: <script type="text/javascript"> 23920: // <![CDATA[ 23921: 23922: function toggleDisplay(domForm,caller) { 23923: if (document.getElementById(caller)) { 23924: var divitem = document.getElementById(caller); 23925: var optionsElement = domForm.coursecredits; 23926: var checkval = 1; 23927: var dispval = 'block'; 23928: var selfcreateRegExp = /^cancreate_emailverified/; 23929: if (caller == 'emailoptions') { 23930: optionsElement = domForm.cancreate_email; 23931: } 23932: if (caller == 'studentsubmission') { 23933: optionsElement = domForm.postsubmit; 23934: } 23935: if (caller == 'cloneinstcode') { 23936: optionsElement = domForm.canclone; 23937: checkval = 'instcode'; 23938: } 23939: if (selfcreateRegExp.test(caller)) { 23940: optionsElement = domForm.elements[caller]; 23941: checkval = 'other'; 23942: dispval = 'inline' 23943: } 23944: if (optionsElement.length) { 23945: var currval; 23946: for (var i=0; i<optionsElement.length; i++) { 23947: if (optionsElement[i].checked) { 23948: currval = optionsElement[i].value; 23949: } 23950: } 23951: if (currval == checkval) { 23952: divitem.style.display = dispval; 23953: } else { 23954: divitem.style.display = 'none'; 23955: } 23956: } 23957: } 23958: return; 23959: } 23960: 23961: // ]]> 23962: </script> 23963: 23964: END 23965: 23966: } 23967: 23968: sub captcha_phrases { 23969: return &Apache::lonlocal::texthash ( 23970: priv => 'Private key', 23971: pub => 'Public key', 23972: original => 'original (CAPTCHA)', 23973: recaptcha => 'successor (ReCAPTCHA)', 23974: notused => 'unused', 23975: ver => 'ReCAPTCHA version (1 or 2)', 23976: ); 23977: } 23978: 23979: sub devalidate_remote_domconfs { 23980: my ($dom,$cachekeys) = @_; 23981: return unless (ref($cachekeys) eq 'HASH'); 23982: my %servers = &Apache::lonnet::internet_dom_servers($dom); 23983: my %thismachine; 23984: map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); 23985: my @posscached = ('domainconfig','domdefaults','ltitools','usersessions', 23986: 'directorysrch','passwdconf','cats','proxyalias','proxysaml', 23987: 'ipaccess','trust'); 23988: my %cache_by_lonhost; 23989: if (exists($cachekeys->{'samllanding'})) { 23990: if (ref($cachekeys->{'samllanding'}) eq 'HASH') { 23991: my %landing = %{$cachekeys->{'samllanding'}}; 23992: my %domservers = &Apache::lonnet::get_servers($dom); 23993: if (keys(%domservers)) { 23994: foreach my $server (keys(%domservers)) { 23995: my @cached; 23996: next if ($thismachine{$server}); 23997: if ($landing{$server}) { 23998: push(@cached,&escape('samllanding').':'.&escape($server)); 23999: } 24000: if (@cached) { 24001: $cache_by_lonhost{$server} = \@cached; 24002: } 24003: } 24004: } 24005: } 24006: } 24007: if (keys(%servers)) { 24008: foreach my $server (keys(%servers)) { 24009: next if ($thismachine{$server}); 24010: my @cached; 24011: foreach my $name (@posscached) { 24012: if ($cachekeys->{$name}) { 24013: if (($name eq 'proxyalias') || ($name eq 'proxysaml')) { 24014: if (ref($cachekeys->{$name}) eq 'HASH') { 24015: foreach my $key (keys(%{$cachekeys->{$name}})) { 24016: push(@cached,&escape($name).':'.&escape($key)); 24017: } 24018: } 24019: } else { 24020: push(@cached,&escape($name).':'.&escape($dom)); 24021: } 24022: } 24023: } 24024: if ((exists($cache_by_lonhost{$server})) && 24025: (ref($cache_by_lonhost{$server}) eq 'ARRAY')) { 24026: push(@cached,@{$cache_by_lonhost{$server}}); 24027: } 24028: if (@cached) { 24029: &Apache::lonnet::remote_devalidate_cache($server,\@cached); 24030: } 24031: } 24032: } 24033: return; 24034: } 24035: 24036: 1;