--- loncom/interface/domainprefs.pm 2017/06/23 14:59:27 1.160.6.84.2.2 +++ loncom/interface/domainprefs.pm 2019/02/03 20:43:00 1.160.6.84.2.10 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.160.6.84.2.2 2017/06/23 14:59:27 raeburn Exp $ +# $Id: domainprefs.pm,v 1.160.6.84.2.10 2019/02/03 20:43:00 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -377,11 +377,12 @@ sub handler { modify => \&modify_usermodification, }, 'scantron' => - { text => 'Bubblesheet format file', + { text => 'Bubblesheet format', help => 'Domain_Configuration_Scantron_Format', - header => [ {col1 => 'Item', - col2 => '', - }], + header => [ {col1 => 'Bubblesheet format file', + col2 => ''}, + {col1 => 'Bubblesheet data upload formats', + col2 => 'Settings'}], print => \&print_scantron, modify => \&modify_scantron, }, @@ -553,6 +554,9 @@ END if (grep(/^contacts$/,@actions)) { $js .= &contacts_javascript(); } + if (grep(/^scantron$/,@actions)) { + $js .= &scantron_javascript(); + } &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js); } else { # check if domconfig user exists for the domain. @@ -743,6 +747,8 @@ sub print_config_box { $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal); } elsif ($action eq 'coursecategories') { $output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal); + } elsif ($action eq 'scantron') { + $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal); } elsif ($action eq 'login') { if ($numheaders == 4) { $colspan = ' colspan="2"'; @@ -798,6 +804,8 @@ sub print_config_box { ($action eq 'defaults') || ($action eq 'directorysrch') || ($action eq 'helpsettings')) { $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); + } elsif ($action eq 'scantron') { + $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal); } elsif ($action eq 'login') { if ($numheaders == 4) { $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).' @@ -957,8 +965,6 @@ sub print_config_box { ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || ($action eq 'ltitools')) { $output .= $item->{'print'}->($dom,$settings,\$rowtotal); - } elsif ($action eq 'scantron') { - $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal); } } $output .= ' @@ -1546,7 +1552,8 @@ sub display_color_options { if ($fullwidth ne '' && $fullheight ne '') { if ($fullwidth > $width && $fullheight > $height) { my $size = $width.'x'.$height; - system("convert -sample $size $input $output"); + my @args = ('convert','-sample',$size,$input,$output); + system({$args[0]} @args); $showfile = "/$imgdir/tn-".$filename; } } @@ -2658,7 +2665,7 @@ sub print_autoupdate { my $locknamesettings; $datatable .= &insttypes_row($settings,$types,$usertypes, $dom,$numinrow,$othertitle, - 'lockablenames'); + 'lockablenames',$rowtotal); $$rowtotal ++; } else { my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); @@ -2801,7 +2808,8 @@ sub print_directorysrch { if (ref($usertypes) eq 'HASH') { if (keys(%{$usertypes}) > 0) { $datatable .= &insttypes_row($settings,$types,$usertypes,$dom, - $numinrow,$othertitle,'cansearch'); + $numinrow,$othertitle,'cansearch', + $rowtotal); $cansrchrow = 1; } } @@ -3002,7 +3010,54 @@ sub print_contacts { $to{$item}.'" />'; $rownum ++; } - } else { + } elsif ($position eq 'bottom') { + $css_class = $rownum%2?' class="LC_odd_row"':''; + $datatable .= ''. + ''.&mt('Extra helpdesk form fields:').'
'. + &mt('(e-mail, subject, and description always shown)'). + ''; + if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') && + (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) { + $datatable .= ''; + foreach my $field (@{$fields}) { + $datatable .= ''. + ''; + } + $datatable .= '
'.&mt('Field').''.&mt('Status').'
'.$fieldtitles->{$field}; + if (($field eq 'screenshot') || ($field eq 'cc')) { + $datatable .= ' '.&mt('(logged-in users)'); + } + $datatable .=''; + my $clickaction; + if ($field eq 'screenshot') { + $clickaction = ' onclick="screenshotSize(this);"'; + } + if (ref($possoptions->{$field}) eq 'ARRAY') { + foreach my $option (@{$possoptions->{$field}}) { + my $checked; + if ($currfield{$field} eq $option) { + $checked = ' checked="checked"'; + } + $datatable .= ''.(' 'x2); + } + } + if ($field eq 'screenshot') { + my $display; + if ($currfield{$field} eq 'no') { + $display = ' style="display:none"'; + } + $datatable .= '
'.&mt('Maximum size for upload (MB)').''. + ''; + } + $datatable .= '
'; + } + $datatable .= ''."\n"; + $rownum ++; + } + unless ($position eq 'top') { foreach my $type (@mailings) { $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= ''. @@ -3062,56 +3117,138 @@ sub print_contacts { \%choices,$rownum); $datatable .= $reports; } elsif ($position eq 'bottom') { - $css_class = $rownum%2?' class="LC_odd_row"':''; - $datatable .= ''. - ''.&mt('Extra helpdesk form fields:').'
'. - &mt('(e-mail, subject, and description always shown)'). - ''; - if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') && - (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) { - $datatable .= ''; - foreach my $field (@{$fields}) { - $datatable .= ''. - ''; } - $datatable .= '
'.&mt('Field').''.&mt('Status').'
'.$fieldtitles->{$field}; - if (($field eq 'screenshot') || ($field eq 'cc')) { - $datatable .= ' '.&mt('(logged-in users)'); - } - $datatable .=''; - my $clickaction; - if ($field eq 'screenshot') { - $clickaction = ' onclick="screenshotSize(this);"'; - } - if (ref($possoptions->{$field}) eq 'ARRAY') { - foreach my $option (@{$possoptions->{$field}}) { - my $checked; - if ($currfield{$field} eq $option) { - $checked = ' checked="checked"'; + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + my (@posstypes,%usertypeshash); + if (ref($types) eq 'ARRAY') { + @posstypes = @{$types}; + } + if (@posstypes) { + if (ref($usertypes) eq 'HASH') { + %usertypeshash = %{$usertypes}; + } + my @overridden; + my $numinrow = 4; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'overrides'}) eq 'HASH') { + foreach my $key (sort(keys(%{$settings->{'overrides'}}))) { + if (ref($settings->{'overrides'}{$key}) eq 'HASH') { + push(@overridden,$key); + foreach my $item (@contacts) { + if ($settings->{'overrides'}{$key}{$item}) { + $checked{'override_'.$key}{$item} = ' checked="checked" '; + } + } + $otheremails{'override_'.$key} = $settings->{'overrides'}{$key}{'others'}; + $bccemails{'override_'.$key} = $settings->{'overrides'}{$key}{'bcc'}; + $includeloc{'override_'.$key} = ''; + $includestr{'override_'.$key} = ''; + if ($settings->{'overrides'}{$key}{'include'} ne '') { + ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = + split(/:/,$settings->{'overrides'}{$key}{'include'},2); + $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key}); + } } - $datatable .= ''.(' 'x2); } } - if ($field eq 'screenshot') { - my $display; - if ($currfield{$field} eq 'no') { - $display = ' style="display:none"'; - } - $datatable .= '
'.&mt('Maximum size for upload (MB)').''. - ''; + } + my $customclass = 'LC_helpdesk_override'; + my $optionsprefix = 'LC_options_helpdesk_'; + + my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');"; + + $datatable .= &insttypes_row($settings,$types,$usertypes,$dom, + $numinrow,$othertitle,'overrides', + \$rownum,$onclicktypes,$customclass); + $rownum ++; + $usertypeshash{'default'} = $othertitle; + foreach my $status (@posstypes) { + my $css_class; + if ($rownum%2) { + $css_class = 'LC_odd_row '; + } + $css_class .= $customclass; + my $rowid = $optionsprefix.$status; + my $hidden = 1; + my $currstyle = 'display:none'; + if (grep(/^\Q$status\E$/,@overridden)) { + $currstyle = 'display:table-row'; + $hidden = 0; + } + my $key = 'override_'.$status; + $datatable .= &overridden_helpdesk($checked{$key},$otheremails{$key},$bccemails{$key}, + $includeloc{$key},$includestr{$key},$status,$rowid, + $usertypeshash{$status},$css_class,$currstyle, + \@contacts,$short_titles); + unless ($hidden) { + $rownum ++; } - $datatable .= '
'; } - $datatable .= ''."\n"; - $rownum ++; } $$rowtotal += $rownum; return $datatable; } +sub overridden_helpdesk { + my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid, + $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_; + my $class = 'LC_left_item'; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowid) { + $rowid = ' id="'.$rowid.'"'; + } + if ($rowstyle) { + $rowstyle = ' style="'.$rowstyle.'"'; + } + my ($output,$description); + $description = &mt('Helpdesk requests from: [_1] in this domain (overrides default)',"$typetitle"); + $output = ''. + "$description\n". + ''. + '
'.&mt('E-mail recipient(s)').''. + ''; + if (ref($contacts) eq 'ARRAY') { + foreach my $item (@{$contacts}) { + my $check; + if (ref($checked) eq 'HASH') { + $check = $checked->{$item}; + } + my $title; + if (ref($short_titles) eq 'HASH') { + $title = $short_titles->{$item}; + } + $output .= ' '; + } + } + $output .= '
'.&mt('Others').':  '. + ''; + my %locchecked; + foreach my $loc ('s','b') { + if ($includeloc eq $loc) { + $locchecked{$loc} = ' checked="checked"'; + last; + } + } + $output .= '
'.&mt('Bcc:').(' 'x6). + '
'. + '
'.&mt('Optional added text').''. + &mt('Text automatically added to e-mail:').' '. + '
'. + ''.&mt('Location:').' '. + ''. + (' 'x2). + ''. + '
'. + ''."\n"; + return $output; +} + sub contacts_javascript { return <<"ENDSCRIPT"; @@ -3129,6 +3266,37 @@ function screenshotSize(field) { return; } +function toggleHelpdeskRow(form,checkbox,target,prefix,docount) { + if (form.elements[checkbox].length != undefined) { + var count = 0; + if (docount) { + for (var i=0; i @@ -3194,7 +3362,7 @@ sub print_helpsettings { @jsarray = ('bystatus'); } } - my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh'.'da']); + my %domhelpdesk = &Apache::lonnet::get_active_domroles($dom,['dh','da']); if (keys(%domhelpdesk)) { push(@accesstypes,('inc','exc')); push(@jsarray,('notinc','notexc')); @@ -5090,9 +5258,14 @@ sub loadbalancing_titles { '_LC_ipchange' => &mt('Non-SSO users with IP mismatch'), ); my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange'); + my @available; if (ref($types) eq 'ARRAY') { - unshift(@alltypes,@{$types},'default'); + @available = @{$types}; + } + unless (grep(/^default$/,@available)) { + push(@available,'default'); } + unshift(@alltypes,@available); my %titles; foreach my $type (@alltypes) { if ($type =~ /^_LC_/) { @@ -5219,8 +5392,8 @@ sub contact_titles { 'adminemail' => 'Default Server Admin E-mail address', 'errormail' => 'Error reports to be e-mailed to', 'packagesmail' => 'Package update alerts to be e-mailed to', - 'helpdeskmail' => "Helpdesk requests for this domain's users", - 'otherdomsmail' => 'Helpdesk requests for other (unconfigured) domains', + 'helpdeskmail' => "Helpdesk requests from all users in this domain", + 'otherdomsmail' => 'Helpdesk requests from users in other (unconfigured) domains', 'lonstatusmail' => 'E-mail from nightly status check (warnings/errors)', 'requestsmail' => 'E-mail from course requests requiring approval', 'updatesmail' => 'E-mail from nightly check of LON-CAPA module integrity/updates', @@ -5468,6 +5641,7 @@ sub print_selfcreation { my %radiohash; my $numinrow = 4; map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate; + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); if ($position eq 'top') { my %choices = &Apache::lonlocal::texthash ( cancreate_login => 'Institutional Login', @@ -5483,13 +5657,11 @@ sub print_selfcreation { \%choices,$itemcount,$onclick); $$rowtotal += $itemcount; - my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); - if (ref($usertypes) eq 'HASH') { if (keys(%{$usertypes}) > 0) { $datatable .= &insttypes_row($createsettings,$types,$usertypes, $dom,$numinrow,$othertitle, - 'statustocreate',$$rowtotal); + 'statustocreate',$rowtotal); $$rowtotal ++; } } @@ -5534,16 +5706,22 @@ sub print_selfcreation { $$rowtotal ++; } elsif ($position eq 'middle') { my %domconf = &Apache::lonnet::get_dom('configuration',['usermodification'],$dom); - my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); - $usertypes->{'default'} = $othertitle; + my @posstypes; if (ref($types) eq 'ARRAY') { - push(@{$types},'default'); - $usertypes->{'default'} = $othertitle; - foreach my $status (@{$types}) { - $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'}, - $numinrow,$$rowtotal,$usertypes); - $$rowtotal ++; - } + @posstypes = @{$types}; + } + unless (grep(/^default$/,@posstypes)) { + push(@posstypes,'default'); + } + my %usertypeshash; + if (ref($usertypes) eq 'HASH') { + %usertypeshash = %{$usertypes}; + } + $usertypeshash{'default'} = $othertitle; + foreach my $status (@posstypes) { + $datatable .= &modifiable_userdata_row('selfcreate',$status,$domconf{'usermodification'}, + $numinrow,$$rowtotal,\%usertypeshash); + $$rowtotal ++; } } else { my %choices = &Apache::lonlocal::texthash ( @@ -5561,29 +5739,30 @@ sub print_selfcreation { my $onclick = "toggleDisplay(this.form,'emailoptions');"; my $additional = '
'; my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); - my $usertypes = {}; - my $order = []; - if ((ref($domdefaults{'inststatustypes'}) eq 'HASH') && (ref($domdefaults{'inststatusguest'}) eq 'ARRAY')) { - $usertypes = $domdefaults{'inststatustypes'}; - $order = $domdefaults{'inststatusguest'}; - } - if (ref($order) eq 'ARRAY') { - push(@{$order},'default'); - if (@{$order} > 1) { - $usertypes->{'default'} = &mt('Other users'); - $additional .= ''; - foreach my $status (@{$order}) { - $additional .= ''; - } - $additional .= ''; - foreach my $status (@{$order}) { - $additional .= ''; - } - $additional .= '
'.$usertypes->{$status}.'
'.&email_as_username($rowtotal,$processing,$status).'
'; - } else { - $usertypes->{'default'} = &mt('All users'); - $additional .= &email_as_username($rowtotal,$processing); + my (@ordered,%usertypeshash); + if (ref($domdefaults{'inststatusguest'}) eq 'ARRAY') { + @ordered = @{$domdefaults{'inststatusguest'}}; + } + if (@ordered) { + unless (grep(/^default$/,@ordered)) { + push(@ordered,'default'); + } + if (ref($usertypes) eq 'HASH') { + %usertypeshash = %{$usertypes}; + } + $usertypeshash{'default'} = $othertitle; + $additional .= ''; + foreach my $status (@ordered) { + $additional .= ''; } + $additional .= ''; + foreach my $status (@ordered) { + $additional .= ''; + } + $additional .= '
'.$usertypeshash{$status}.'
'.&email_as_username($rowtotal,$processing,$status).'
'; + } else { + $usertypeshash{'default'} = $othertitle; + $additional .= &email_as_username($rowtotal,$processing); } $additional .= '
'."\n"; @@ -5594,12 +5773,10 @@ sub print_selfcreation { $$rowtotal ++; my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info(); $numinrow = 1; - if (ref($order) eq 'ARRAY') { - foreach my $status (@{$order}) { - $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings, - $numinrow,$$rowtotal,$usertypes,$infofields,$infotitles); - $$rowtotal ++; - } + foreach my $status (@ordered) { + $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings, + $numinrow,$$rowtotal,\%usertypeshash,$infofields,$infotitles); + $$rowtotal ++; } my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email'); @@ -6121,6 +6298,58 @@ sub defaults_titles { return (\%titles); } +sub print_scantron { + my ($r,$position,$dom,$confname,$settings,$rowtotal) = @_; + if ($position eq 'top') { + return &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal); + } else { + return &print_scantronconfig($dom,$settings,\$rowtotal); + } +} + +sub scantron_javascript { + return <<"ENDSCRIPT"; + + + +ENDSCRIPT + +} + sub print_scantronformat { my ($r,$dom,$confname,$settings,$rowtotal) = @_; my $itemcount = 1; @@ -6147,8 +6376,8 @@ sub print_scantronformat { if ($configuserok eq 'ok') { if ($author_ok eq 'ok') { my %legacyfile = ( - default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab', - custom => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab', + default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab', + custom => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab', ); my %md5chk; foreach my $type (keys(%legacyfile)) { @@ -6157,7 +6386,7 @@ sub print_scantronformat { } if ($md5chk{'default'} ne $md5chk{'custom'}) { foreach my $type (keys(%legacyfile)) { - ($scantronurls{$type},my $error) = + ($scantronurls{$type},my $error) = &legacy_scantronformat($r,$dom,$confname, $type,$legacyfile{$type}, $scantronurls{$type}, @@ -6168,13 +6397,13 @@ sub print_scantronformat { } if (keys(%error) == 0) { $is_custom = 1; - $confhash{'scantron'}{'scantronformat'} = + $confhash{'scantron'}{'scantronformat'} = $scantronurls{'custom'}; - my $putresult = + my $putresult = &Apache::lonnet::put_dom('configuration', \%confhash,$dom); if ($putresult ne 'ok') { - $error{'custom'} = + $error{'custom'} = ''. &mt('An error occurred updating the domain configuration: [_1]',$putresult).''; } @@ -6294,6 +6523,129 @@ sub legacy_scantronformat { return ($url,$error); } +sub print_scantronconfig { + my ($dom,$settings,$rowtotal) = @_; + my $itemcount = 2; + my $is_checked = ' checked="checked"'; + my %optionson = ( + hdr => ' checked="checked"', + pad => ' checked="checked"', + rem => ' checked="checked"', + ); + my %optionsoff = ( + hdr => '', + pad => '', + rem => '', + ); + my $currcsvsty = 'none'; + my ($datatable,%csvfields,%checked,%onclick,%csvoptions); + my @fields = &scantroncsv_fields(); + my %titles = &scantronconfig_titles(); + if (ref($settings) eq 'HASH') { + if (ref($settings->{config}) eq 'HASH') { + if ($settings->{config}->{dat}) { + $checked{'dat'} = $is_checked; + } + if (ref($settings->{config}->{csv}) eq 'HASH') { + if (ref($settings->{config}->{csv}->{fields}) eq 'HASH') { + %csvfields = %{$settings->{config}->{csv}->{fields}}; + if (keys(%csvfields) > 0) { + $checked{'csv'} = $is_checked; + $currcsvsty = 'block'; + } + } + if (ref($settings->{config}->{csv}->{options}) eq 'HASH') { + %csvoptions = %{$settings->{config}->{csv}->{options}}; + foreach my $option (keys(%optionson)) { + unless ($csvoptions{$option}) { + $optionsoff{$option} = $optionson{$option}; + $optionson{$option} = ''; + } + } + } + } + } else { + $checked{'dat'} = $is_checked; + } + } else { + $checked{'dat'} = $is_checked; + } + $onclick{'csv'} = ' onclick="toggleScantron(this.form);"'; + my $css_class = $itemcount%2? ' class="LC_odd_row"':''; + $datatable = ''.&mt('Supported formats').''. + ''; + foreach my $item ('dat','csv') { + my $id; + if ($item eq 'csv') { + $id = 'id="scantronconfcsv" '; + } + $datatable .= ''.(' 'x3); + if ($item eq 'csv') { + $datatable .= '
'. + ''.&mt('CSV Column Mapping').''. + ''."\n"; + foreach my $col (@fields) { + my $selnone; + if ($csvfields{$col} eq '') { + $selnone = ' selected="selected"'; + } + $datatable .= ''. + ''; + } + $datatable .= '
'.&mt('Field').''.&mt('Location').'
'.$titles{$col}.'
'. + '
'. + ''.&mt('CSV Options').''; + foreach my $option ('hdr','pad','rem') { + $datatable .= ''.$titles{$option}.':'. + ''.(' 'x2)."\n". + '
'; + } + $datatable .= '
'; + $itemcount ++; + } + } + $datatable .= ''; + $$rowtotal ++; + return $datatable; +} + +sub scantronconfig_titles { + return &Apache::lonlocal::texthash( + dat => 'Standard format (.dat)', + csv => 'Comma separated values (.csv)', + hdr => 'Remove first line in file (contains column titles)', + pad => 'Prepend 0s to PaperID', + rem => 'Remove leading spaces (except Question Response columns)', + CODE => 'CODE', + ID => 'Student ID', + PaperID => 'Paper ID', + FirstName => 'First Name', + LastName => 'Last Name', + FirstQuestion => 'First Question Response', + Section => 'Section', + ); +} + +sub scantroncsv_fields { + return ('PaperID','LastName','FirstName','ID','Section','CODE','FirstQuestion'); +} + sub print_coursecategories { my ($position,$dom,$hdritem,$settings,$rowtotal) = @_; my $datatable; @@ -7067,11 +7419,13 @@ sub modifiable_userdata_row { } sub insttypes_row { - my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rownum) = @_; + my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick, + $customcss,$rowstyle) = @_; my %lt = &Apache::lonlocal::texthash ( cansearch => 'Users allowed to search', statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)', lockablenames => 'User preference to lock name', + overrides => "Override domain's helpdesk settings based on requester's affiliation", ); my $showdom; if ($context eq 'cansearch') { @@ -7081,9 +7435,22 @@ sub insttypes_row { if ($context eq 'statustocreate') { $class = 'LC_right_item'; } - my $css_class = ' class="LC_odd_row"'; - if ($rownum ne '') { - $css_class = ($rownum%2? ' class="LC_odd_row"':''); + my $css_class; + if ($$rowtotal%2) { + $css_class = 'LC_odd_row'; + } + if ($customcss) { + $css_class .= ' '.$customcss; + } + $css_class =~ s/^\s+//; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowstyle) { + $css_class .= ' style="'.$rowstyle.'"'; + } + if ($onclick) { + $onclick = 'onclick="'.$onclick.'" '; } my $output = ''. ''.$lt{$context}.$showdom. @@ -7105,6 +7472,10 @@ sub insttypes_row { if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) { $check = ' checked="checked" '; } + } elsif (ref($settings->{$context}) eq 'HASH') { + if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') { + $check = ' checked="checked" '; + } } elsif ($context eq 'statustocreate') { $check = ' checked="checked" '; } @@ -7119,29 +7490,38 @@ sub insttypes_row { $rem = @{$types}%($numinrow); } my $colsleft = $numinrow - $rem; - if (($rem == 0) && (@{$types} > 0)) { - $output .= ''; - } - if ($colsleft > 1) { - $output .= ''; + if ($context eq 'overrides') { + if ($colsleft > 1) { + $output .= ''; + } else { + $output .= ''; + } + $output .= ' '; } else { - $output .= ''; - } - my $defcheck = ' '; - if (ref($settings) eq 'HASH') { - if (ref($settings->{$context}) eq 'ARRAY') { - if (grep(/^default$/,@{$settings->{$context}})) { + if (($rem == 0) && (@{$types} > 0)) { + $output .= ''; + } + if ($colsleft > 1) { + $output .= ''; + } else { + $output .= ''; + } + my $defcheck = ' '; + if (ref($settings) eq 'HASH') { + if (ref($settings->{$context}) eq 'ARRAY') { + if (grep(/^default$/,@{$settings->{$context}})) { + $defcheck = ' checked="checked" '; + } + } elsif ($context eq 'statustocreate') { $defcheck = ' checked="checked" '; } - } elsif ($context eq 'statustocreate') { - $defcheck = ' checked="checked" '; } + $output .= ''; } - $output .= ''. - ''; + $output .= ''; return $output; } @@ -8175,14 +8555,14 @@ sub publishlogo { } else { my $source = $filepath.'/'.$file; my $logfile; - if (!open($logfile,">>$source".'.log')) { + if (!open($logfile,">>",$source.'.log')) { return (&mt('No write permission to Authoring Space')); } print $logfile "\n================= Publish ".localtime()." ================\n". $env{'user.name'}.':'.$env{'user.domain'}."\n"; # Save the file - if (!open(FH,'>'.$source)) { + if (!open(FH,">",$source)) { &Apache::lonnet::logthis('Failed to create '.$source); return (&mt('Failed to create file')); } @@ -8243,7 +8623,8 @@ $env{'user.name'}.':'.$env{'user.domain' if ($fullwidth ne '' && $fullheight ne '') { if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) { my $thumbsize = $thumbwidth.'x'.$thumbheight; - system("convert -sample $thumbsize $inputfile $outfile"); + my @args = ('convert','-sample',$thumbsize,$inputfile,$outfile); + system({$args[0]} @args); chmod(0660, $filepath.'/tn-'.$file); if (-e $outfile) { my $copyfile=$targetdir.'/tn-'.$file; @@ -8322,7 +8703,7 @@ sub write_metadata { { print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file; my $mfh; - if (open($mfh,'>'.$targetdir.'/'.$file.'.meta')) { + if (open($mfh,">",$targetdir.'/'.$file.'.meta')) { foreach (sort(keys(%metadatafields))) { unless ($_=~/\./) { my $unikey=$_; @@ -8356,7 +8737,7 @@ sub notifysubscribed { next unless (ref($targetsource) eq 'ARRAY'); my ($target,$source)=@{$targetsource}; if ($source ne '') { - if (open(my $logfh,'>>'.$source.'.log')) { + if (open(my $logfh,">>",$source.'.log')) { print $logfh "\nCleanup phase: Notifications\n"; my @subscribed=&subscribed_hosts($target); foreach my $subhost (@subscribed) { @@ -8382,7 +8763,7 @@ sub notifysubscribed { sub subscribed_hosts { my ($target) = @_; my @subscribed; - if (open(my $fh,"<$target.subscription")) { + if (open(my $fh,"<","$target.subscription")) { while (my $subline=<$fh>) { if ($subline =~ /^($match_lonid):/) { my $host = $1; @@ -8581,16 +8962,20 @@ sub modify_quotas { #FIXME need to obsolete item in RES space } elsif ($env{'form.'.$type.'_image_'.$i.'.filename'}) { my ($cdom,$cnum) = split(/_/,$key); - my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i, - $cdom,$cnum,$type,$configuserok, - $switchserver,$author_ok); - if ($imgurl) { - $confhash{$type}{$key}{'image'} = $imgurl; - $changes{$type}{$key} = 1; - } - if ($error) { - &Apache::lonnet::logthis($error); - $errors .= '
  • '.$error.'
  • '; + if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') { + $errors .= '
  • '.&mt('Image not saved: could not find textbook course').'
  • '; + } else { + my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i, + $cdom,$cnum,$type,$configuserok, + $switchserver,$author_ok); + if ($imgurl) { + $confhash{$type}{$key}{'image'} = $imgurl; + $changes{$type}{$key} = 1; + } + if ($error) { + &Apache::lonnet::logthis($error); + $errors .= '
  • '.$error.'
  • '; + } } } elsif ($domconfig{$action}{$type}{$key}{'image'}) { $confhash{$type}{$key}{'image'} = @@ -8624,15 +9009,17 @@ sub modify_quotas { if ($type eq 'textbooks') { if ($env{'form.'.$type.'_addbook_image.filename'} ne '') { my ($cdom,$cnum) = split(/_/,$newbook{$type}); - my ($imageurl,$error) = - &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type, - $configuserok,$switchserver,$author_ok); - if ($imageurl) { - $confhash{$type}{$newbook{$type}}{'image'} = $imageurl; - } - if ($error) { - &Apache::lonnet::logthis($error); - $errors .= '
  • '.$error.'
  • '; + if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') { + my ($imageurl,$error) = + &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type, + $configuserok,$switchserver,$author_ok); + if ($imageurl) { + $confhash{$type}{$newbook{$type}}{'image'} = $imageurl; + } + if ($error) { + &Apache::lonnet::logthis($error); + $errors .= '
  • '.$error.'
  • '; + } } } } @@ -9124,7 +9511,7 @@ sub process_textbook_image { } elsif ($author_ok eq 'ok') { my ($result,$imageurl) = &publishlogo($r,'upload',$caller,$dom,$confname, - "$type/$dom/$cnum/cover",$width,$height); + "$type/$cdom/$cnum/cover",$width,$height); if ($result eq 'ok') { $url = $imageurl; } else { @@ -9207,7 +9594,7 @@ sub modify_ltitools { } if ($env{'form.ltitools_add_image.filename'} ne '') { my ($imageurl,$error) = - &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$dom, + &process_ltitools_image($r,$dom,$confname,'ltitools_add_image',$newid, $configuserok,$switchserver,$author_ok); if ($imageurl) { $confhash{$newid}{'image'} = $imageurl; @@ -9270,6 +9657,7 @@ sub modify_ltitools { my $maxnum = $env{'form.ltitools_maxnum'}; for (my $i=0; $i<=$maxnum; $i++) { my $itemid = $env{'form.ltitools_id_'.$i}; + $itemid =~ s/\D+//g; if (ref($domconfig{$action}{$itemid}) eq 'HASH') { if ($deletions{$itemid}) { if ($domconfig{$action}{$itemid}{'image'}) { @@ -10347,17 +10735,57 @@ sub modify_contacts { my $value = $env{'form.helpform_'.$field}; $value =~ s/^\s+|\s+$//g; if (grep(/^\Q$value\E$/,@{$possoptions->{$field}})) { - $contacts_hash{contacts}{'helpform'}{$field} = $value; + $contacts_hash{'contacts'}{'helpform'}{$field} = $value; if ($field eq 'screenshot') { $env{'form.helpform_maxsize'} =~ s/^\s+|\s+$//g; if ($env{'form.helpform_maxsize'} =~ /^\d+\.?\d*$/) { - $contacts_hash{contacts}{'helpform'}{'maxsize'} = $env{'form.helpform_maxsize'}; + $contacts_hash{'contacts'}{'helpform'}{'maxsize'} = $env{'form.helpform_maxsize'}; } } } } } } + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + my (@statuses,%usertypeshash,@overrides); + if ((ref($types) eq 'ARRAY') && (@{$types} > 0)) { + @statuses = @{$types}; + if (ref($usertypes) eq 'HASH') { + %usertypeshash = %{$usertypes}; + } + } + if (@statuses) { + my @possoverrides = &Apache::loncommon::get_env_multiple('form.overrides'); + foreach my $type (@possoverrides) { + if (($type ne '') && (grep(/^\Q$type\E$/,@statuses))) { + push(@overrides,$type); + } + } + if (@overrides) { + foreach my $type (@overrides) { + my @standard = &Apache::loncommon::get_env_multiple('form.override_'.$type); + foreach my $item (@contacts) { + if (grep(/^\Q$item\E$/,@standard)) { + $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 1; + $newsetting{'override_'.$type}{$item} = 1; + } else { + $contacts_hash{'contacts'}{'overrides'}{$type}{$item} = 0; + $newsetting{'override_'.$type}{$item} = 0; + } + } + $contacts_hash{'contacts'}{'overrides'}{$type}{'others'} = $env{'form.override_'.$type.'_others'}; + $contacts_hash{'contacts'}{'overrides'}{$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'}; + $newsetting{'override_'.$type}{'others'} = $env{'form.override_'.$type.'_others'}; + $newsetting{'override_'.$type}{'bcc'} = $env{'form.override_'.$type.'_bcc'}; + if (($env{'form.override_'.$type.'_includestr'} ne '') && ($env{'form.override_'.$type.'_includeloc'} =~ /^s|b$/)) { + $includestr{$type} = $env{'form.override_'.$type.'_includestr'}; + $includeloc{$type} = $env{'form.override_'.$type.'_includeloc'}; + $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type}); + $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'}; + } + } + } + } if (keys(%currsetting) > 0) { foreach my $item (@contacts) { if ($to{$item} ne $currsetting{$item}) { @@ -10412,6 +10840,33 @@ sub modify_contacts { } } } + if (@statuses) { + if (ref($currsetting{'overrides'}) eq 'HASH') { + foreach my $key (keys(%{$currsetting{'overrides'}})) { + if (ref($currsetting{'overrides'}{$key}) eq 'HASH') { + if (ref($newsetting{'override_'.$key}) eq 'HASH') { + foreach my $item (@contacts,'bcc','others','include') { + if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { + push(@{$changes{'overrides'}},$key); + last; + } + } + } else { + push(@{$changes{'overrides'}},$key); + } + } + } + foreach my $key (@overrides) { + unless (exists($currsetting{'overrides'}{$key})) { + push(@{$changes{'overrides'}},$key); + } + } + } else { + foreach my $key (@overrides) { + push(@{$changes{'overrides'}},$key); + } + } + } } else { my %default; $default{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'}; @@ -10526,6 +10981,60 @@ sub modify_contacts { $resulttext .= ''; } } + if (ref($changes{'overrides'}) eq 'ARRAY') { + my @deletions; + foreach my $type (@{$changes{'overrides'}}) { + if ($usertypeshash{$type}) { + if (grep(/^\Q$type\E/,@overrides)) { + $resulttext .= '
  • '.&mt("Overrides based on requester's affiliation set for [_1]", + $usertypeshash{$type}).'
    • '; + if (ref($newsetting{'override_'.$type}) eq 'HASH') { + my @text; + foreach my $item (@contacts) { + if ($newsetting{'override_'.$type}{$item}) { + push(@text,$short_titles->{$item}); + } + } + if ($newsetting{'override_'.$type}{'others'} ne '') { + push(@text,$newsetting{'override_'.$type}{'others'}); + } + + if (@text) { + $resulttext .= &mt('Helpdesk e-mail sent to: [_1]', + ''.join(', ',@text).''); + } + if ($newsetting{'override_'.$type}{'bcc'} ne '') { + my $bcctext; + if (@text) { + $bcctext = ' '.&mt('with Bcc to'); + } else { + $bcctext = '(Bcc)'; + } + $resulttext .= $bcctext.': '.$newsetting{'override_'.$type}{'bcc'}.''; + } elsif (!@text) { + $resulttext .= &mt('Helpdesk e-mail sent to no one'); + } + $resulttext .= '
    • '; + if ($newsetting{'override_'.$type}{'include'} ne '') { + my ($loc,$str) = split(/:/,$newsetting{'override_'.$type}{'include'}); + if ($loc eq 'b') { + $resulttext .= '
    • '.&mt('Text automatically added to e-mail body:').' '.&unescape($str).'
    • '; + } elsif ($loc eq 's') { + $resulttext .= '
    • '.&mt('Text automatically added to e-mail subject:').' '.&unescape($str).'
    • '; + } + } + } + $resulttext .= '
  • '; + } else { + push(@deletions,$usertypeshash{$type}); + } + } + } + if (@deletions) { + $resulttext .= '
  • '.&mt("Overrides based on requester's affiliation discontinued for: [_1]", + join(', ',@deletions)).'
  • '; + } + } my @offon = ('off','on'); if ($changes{'reporterrors'}) { $resulttext .= '
  • '. @@ -10581,7 +11090,6 @@ sub modify_contacts { &mt('Max size for file uploaded to help form by logged-in user set to [_1] MB.', $contacts_hash{'contacts'}{'helpform'}{'maxsize'}). '
  • '; - } } $resulttext .= ''; @@ -11175,7 +11683,7 @@ sub modify_selfcreation { $save_usercreate{'cancreate'}{'shibenv'} = $cancreate{'shibenv'}; } $save_usercreate{'cancreate'}{'emailusername'} = $cancreate{'emailusername'}; - $save_usercreate{'emailrule'} = \@email_rule; + $save_usercreate{'email_rule'} = \@email_rule; my %userconfig_hash = ( usercreation => \%save_usercreate, @@ -11896,7 +12404,7 @@ sub modify_scantron { my $custom = 'custom.tab'; my $default = 'default.tab'; my $servadm = $r->dir_config('lonAdmEMail'); - my ($configuserok,$author_ok,$switchserver) = + my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); if ($env{'form.scantronformat.filename'} ne '') { my $error; @@ -11931,6 +12439,67 @@ sub modify_scantron { if ($env{'form.scantronformat_del'}) { $confhash{'scantron'}{'scantronformat'} = ''; $changes{'scantronformat'} = 1; + } else { + $confhash{'scantron'}{'scantronformat'} = $domconfig{'scantron'}{'scantronformat'}; + } + } + } + my @options = ('hdr','pad','rem'); + my @fields = &scantroncsv_fields(); + my %titles = &scantronconfig_titles(); + my @formats = &Apache::loncommon::get_env_multiple('form.scantronconfig'); + my ($newdat,$currdat,%newcol,%currcol); + if (grep(/^dat$/,@formats)) { + $confhash{'scantron'}{config}{dat} = 1; + $newdat = 1; + } else { + $newdat = 0; + } + if (grep(/^csv$/,@formats)) { + my %bynum; + foreach my $field (@fields) { + if ($env{'form.scantronconfig_csv_'.$field} =~ /^(\d+)$/) { + my $posscol = $1; + if (($posscol < 20) && (!$bynum{$posscol})) { + $confhash{'scantron'}{config}{csv}{fields}{$field} = $posscol; + $bynum{$posscol} = $field; + $newcol{$field} = $posscol; + } + } + } + if (keys(%newcol)) { + foreach my $option (@options) { + if ($env{'form.scantroncsv_'.$option}) { + $confhash{'scantron'}{config}{csv}{options}{$option} = 1; + } + } + } + } + $currdat = 1; + if (ref($domconfig{'scantron'}) eq 'HASH') { + if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') { + unless (exists($domconfig{'scantron'}{'config'}{'dat'})) { + $currdat = 0; + } + if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') { + if (ref($domconfig{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') { + %currcol = %{$domconfig{'scantron'}{'config'}{'csv'}{'fields'}}; + } + } + } + } + if ($currdat != $newdat) { + $changes{'config'} = 1; + } else { + foreach my $field (@fields) { + if ($currcol{$field} ne '') { + if ($currcol{$field} ne $newcol{$field}) { + $changes{'config'} = 1; + last; + } + } elsif ($newcol{$field} ne '') { + $changes{'config'} = 1; + last; } } } @@ -11941,29 +12510,64 @@ sub modify_scantron { if (keys(%changes) > 0) { if (ref($confhash{'scantron'}) eq 'HASH') { $resulttext = &mt('Changes made:').'
      '; - if ($confhash{'scantron'}{'scantronformat'} eq '') { - $resulttext .= '
    • '.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'
    • '; - } else { - $resulttext .= '
    • '.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'
    • '; + if ($changes{'scantronformat'}) { + if ($confhash{'scantron'}{'scantronformat'} eq '') { + $resulttext .= '
    • '.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'
    • '; + } else { + $resulttext .= '
    • '.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'
    • '; + } + } + if ($changes{'config'}) { + if (ref($confhash{'scantron'}{'config'}) eq 'HASH') { + if ($confhash{'scantron'}{'config'}{'dat'}) { + $resulttext .= '
    • '.&mt('Bubblesheet data upload formats includes .dat format').'
    • '; + } + if (ref($confhash{'scantron'}{'config'}{'csv'}) eq 'HASH') { + if (ref($confhash{'scantron'}{'config'}{'csv'}{'fields'}) eq 'HASH') { + if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'fields'}})) { + $resulttext .= '
    • '.&mt('Bubblesheet data upload formats includes .csv format, with following fields/column numbers supported:').'
        '; + foreach my $field (@fields) { + if ($confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} ne '') { + my $showcol = $confhash{'scantron'}{'config'}{'csv'}{'fields'}{$field} + 1; + $resulttext .= '
      • '.$titles{$field}.': '.$showcol.'
      • '; + } + } + $resulttext .= '
    • '; + if (ref($confhash{'scantron'}{'config'}{'csv'}{'options'}) eq 'HASH') { + if (keys(%{$confhash{'scantron'}{'config'}{'csv'}{'options'}})) { + $resulttext .= '
    • '.&mt('Bubblesheet data upload formats includes .csv format, with following options:').'
        '; + foreach my $option (@options) { + if ($confhash{'scantron'}{'config'}{'csv'}{'options'}{$option} ne '') { + $resulttext .= '
      • '.$titles{$option}.'
      • '; + } + } + $resulttext .= '
    • '; + } + } + } + } + } + } else { + $resulttext .= '
    • '.&mt('No bubblesheet data upload formats set -- will default to assuming .dat format').'
    • '; + } } $resulttext .= '
    '; } else { $resulttext = &mt('Changes made to bubblesheet format file.'); } - $resulttext .= ''; &Apache::loncommon::devalidate_domconfig_cache($dom); if (ref($lastactref) eq 'HASH') { $lastactref->{'domainconfig'} = 1; } } else { - $resulttext = &mt('No changes made to bubblesheet format file'); + $resulttext = &mt('No changes made to bubblesheet format settings'); } } else { $resulttext = ''. &mt('An error occurred: [_1]',$putresult).''; } } else { - $resulttext = &mt('No changes made to bubblesheet format file'); + $resulttext = &mt('No changes made to bubblesheet format settings'); } if ($errors) { $resulttext .= &mt('The following errors occurred: ').'
      '.