--- loncom/interface/domainprefs.pm 2017/05/09 03:04:26 1.297 +++ loncom/interface/domainprefs.pm 2018/12/08 15:03:25 1.344 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.297 2017/05/09 03:04:26 raeburn Exp $ +# $Id: domainprefs.pm,v 1.344 2018/12/08 15:03:25 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -104,7 +104,7 @@ $datatable - HTML containing form eleme In the case of course requests, radio buttons are displayed for each institutional affiliate type (and also default, and _LC_adv) for each of the course types -(official, unofficial, community, textbook, and placement). +(official, unofficial, community, textbook, placement, and lti). In each case the radio buttons allow the selection of one of four values: 0, approval, validate, autolimit=N (where N is blank, or a positive integer). @@ -219,13 +219,14 @@ sub handler { 'serverstatuses','requestcourses','helpsettings', 'coursedefaults','usersessions','loadbalancing', 'requestauthor','selfenrollment','inststatus', - 'ltitools','ssl','trust'],$dom); + 'ltitools','ssl','trust','lti'],$dom); + my %encconfig = + &Apache::lonnet::get_dom('encconfig',['ltitools','lti'],$dom); if (ref($domconfig{'ltitools'}) eq 'HASH') { - my %encconfig = - &Apache::lonnet::get_dom('encconfig',['ltitools'],$dom); if (ref($encconfig{'ltitools'}) eq 'HASH') { foreach my $id (keys(%{$domconfig{'ltitools'}})) { - if (ref($domconfig{'ltitools'}{$id}) eq 'HASH') { + if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') && + (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) { foreach my $item ('key','secret') { $domconfig{'ltitools'}{$id}{$item} = $encconfig{'ltitools'}{$id}{$item}; } @@ -233,12 +234,24 @@ sub handler { } } } + if (ref($domconfig{'lti'}) eq 'HASH') { + if (ref($encconfig{'lti'}) eq 'HASH') { + foreach my $id (keys(%{$domconfig{'lti'}})) { + if ((ref($domconfig{'lti'}{$id}) eq 'HASH') && + (ref($encconfig{'lti'}{$id}) eq 'HASH')) { + foreach my $item ('key','secret') { + $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item}; + } + } + } + } + } my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll', 'autoupdate','autocreate','directorysrch','contacts', 'usercreation','selfcreation','usermodification','scantron', 'requestcourses','requestauthor','coursecategories', 'serverstatuses','helpsettings','coursedefaults', - 'ltitools','selfenrollment','usersessions','ssl','trust'); + 'ltitools','selfenrollment','usersessions','ssl','trust','lti'); my %existing; if (ref($domconfig{'loadbalancing'}) eq 'HASH') { %existing = %{$domconfig{'loadbalancing'}}; @@ -281,7 +294,7 @@ sub handler { {col1 => 'Internal Authentication', col2 => 'Value'}, {col1 => 'Institutional user types', - col2 => 'Assignable to e-mail usernames'}], + col2 => 'Name displayed'}], print => \&print_defaults, modify => \&modify_defaults, }, @@ -339,6 +352,8 @@ sub handler { col2 => 'Value',}, {col1 => 'Recipient(s) for notifications', col2 => 'Value',}, + {col1 => 'Nightly status check e-mail', + col2 => 'Settings',}, {col1 => 'Ask helpdesk form settings', col2 => 'Value',},], print => \&print_contacts, @@ -363,7 +378,7 @@ sub handler { col2 => 'Enabled?'}, {col1 => 'Institutional user type (login/SSO self-creation)', col2 => 'Information user can enter'}, - {col1 => 'Self-creation with e-mail as username', + {col1 => 'Self-creation with e-mail verification', col2 => 'Settings'}], print => \&print_selfcreation, modify => \&modify_selfcreation, @@ -545,6 +560,14 @@ sub handler { print => \&print_trust, modify => \&modify_trust, }, + 'lti' => + {text => 'LTI Provider', + help => 'Domain_Configuration_LTI_Provider', + header => [{col1 => 'Setting', + col2 => 'Value',}], + print => \&print_lti, + modify => \&modify_lti, + }, ); if (keys(%servers) > 1) { $prefs{'login'} = { text => 'Log-in page options', @@ -598,6 +621,9 @@ $javascript_validations $coursebrowserjs END } + if (grep(/^selfcreation$/,@actions)) { + $js .= &selfcreate_javascript(); + } if (grep(/^contacts$/,@actions)) { $js .= &contacts_javascript(); } @@ -694,7 +720,7 @@ sub process_changes { } elsif ($action eq 'usercreation') { $output = &modify_usercreation($dom,%domconfig); } elsif ($action eq 'selfcreation') { - $output = &modify_selfcreation($dom,%domconfig); + $output = &modify_selfcreation($dom,$lastactref,%domconfig); } elsif ($action eq 'usermodification') { $output = &modify_usermodification($dom,%domconfig); } elsif ($action eq 'contacts') { @@ -727,6 +753,8 @@ sub process_changes { $output = &modify_ssl($dom,$lastactref,%domconfig); } elsif ($action eq 'trust') { $output = &modify_trust($dom,$lastactref,%domconfig); + } elsif ($action eq 'lti') { + $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig); } return $output; } @@ -755,11 +783,15 @@ sub print_config_box { $output = &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full, \@templateroles); + } elsif ($action eq 'ltitools') { + $output .= <itools_javascript($settings); + } elsif ($action eq 'lti') { + $output .= <i_javascript($settings); } $output .= '<table class="LC_nested_outer"> <tr> - <th align="left" valign="middle"><span class="LC_nobreak">'. + <th class="LC_left_item LC_middle"><span class="LC_nobreak">'. &mt($item->{text}).' '. &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n". '</tr>'; @@ -874,6 +906,23 @@ sub print_config_box { </tr>'."\n"; if ($action eq 'coursecategories') { $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal); + } elsif ($action eq 'contacts') { + $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal).' + </tr> + </table> + </td> + </tr> + <tr> + <td> + <table class="LC_nested"> + <tr class="LC_info_row"> + <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td> + <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'. + $item->{'print'}->('bottom',$dom,$settings,\$rowtotal).' + </table> + </td> + </tr> + <tr>'; } else { $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); } @@ -975,8 +1024,8 @@ sub print_config_box { <td> <table class="LC_nested"> <tr class="LC_info_row"> - <td class="LC_left_item"'.$colspan.' valign="top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td> - <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td> + <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td> + <td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td> </tr>'. &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal); } elsif ($action eq 'requestauthor') { @@ -991,9 +1040,9 @@ sub print_config_box { <td> <table class="LC_nested"> <tr class="LC_info_row"> - <td class="LC_left_item"'.$colspan.' valign="top">'. + <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'. &mt($item->{'header'}->[2]->{'col1'}).'</td> - <td class="LC_right_item" valign="top">'. + <td class="LC_right_item" style="vertical-align: top">'. &mt($item->{'header'}->[2]->{'col2'}).'</td> </tr>'. &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).' @@ -1021,30 +1070,30 @@ sub print_config_box { <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>'; } elsif ($action eq 'serverstatuses') { $output .= ' - <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}). + <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}). '<br />('.&mt('Automatic access for Dom. Coords.').')</td>'; } else { $output .= ' - <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>'; + <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>'; } if (defined($item->{'header'}->[0]->{'col3'})) { - $output .= '<td class="LC_left_item" valign="top">'. + $output .= '<td class="LC_left_item" style="vertical-align: top">'. &mt($item->{'header'}->[0]->{'col2'}); if ($action eq 'serverstatuses') { $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)'; } } else { - $output .= '<td class="LC_right_item" valign="top">'. + $output .= '<td class="LC_right_item" style="vertical-align: top">'. &mt($item->{'header'}->[0]->{'col2'}); } $output .= '</td>'; if ($item->{'header'}->[0]->{'col3'}) { if (defined($item->{'header'}->[0]->{'col4'})) { - $output .= '<td class="LC_left_item" valign="top">'. + $output .= '<td class="LC_left_item" style="vertical-align: top">'. &mt($item->{'header'}->[0]->{'col3'}); } else { - $output .= '<td class="LC_right_item" valign="top">'. + $output .= '<td class="LC_right_item" style="vertical-align: top">'. &mt($item->{'header'}->[0]->{'col3'}); } if ($action eq 'serverstatuses') { @@ -1053,7 +1102,7 @@ sub print_config_box { $output .= '</td>'; } if ($item->{'header'}->[0]->{'col4'}) { - $output .= '<td class="LC_right_item" valign="top">'. + $output .= '<td class="LC_right_item" style="vertical-align: top">'. &mt($item->{'header'}->[0]->{'col4'}); } $output .= '</tr>'; @@ -1062,7 +1111,7 @@ sub print_config_box { $output .= &print_quotas($dom,$settings,\$rowtotal,$action); } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || - ($action eq 'ltitools')) { + ($action eq 'ltitools') || ($action eq 'lti')) { $output .= $item->{'print'}->($dom,$settings,\$rowtotal); } elsif ($action eq 'scantron') { $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal); @@ -1086,7 +1135,7 @@ sub print_login { my $choice = $choices{'disallowlogin'}; $css_class = ' class="LC_odd_row"'; $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'. - '<td align="right"><table><tr><th>'.$choices{'hostid'}.'</th>'. + '<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'. '<th>'.$choices{'server'}.'</th>'. '<th>'.$choices{'serverpath'}.'</th>'. '<th>'.$choices{'custompath'}.'</th>'. @@ -1367,7 +1416,7 @@ sub print_login { my $choice = $choices{'headtag'}; $css_class = ' class="LC_odd_row"'; $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'. - '<td align="left"><table><tr><th>'.$choices{'hostid'}.'</th>'. + '<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'. '<th>'.$choices{'current'}.'</th>'. '<th>'.$choices{'action'}.'</th>'. '<th>'.$choices{'exempt'}.'</th></tr>'."\n"; @@ -1410,7 +1459,7 @@ sub print_login { } else { $datatable .= '<input type="file" name="loginheadtag_'.$lonhost.'" />'; } - $datatable .= '</td><td><input type="textbox" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>'; + $datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>'; } $datatable .= '</table></td></tr>'; } @@ -1570,7 +1619,7 @@ sub display_color_options { my $datatable = '<tr'.$css_class.'>'. '<td>'.$choices->{'font'}.'</td>'; if (!$is_custom->{'font'}) { - $datatable .= '<td>'.&mt('Default in use:').' <span id="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>'; + $datatable .= '<td>'.&mt('Default in use:').' <span class="css_default_'.$role.'_font" style="color: '.$defaults->{'font'}.';">'.$defaults->{'font'}.'</span></td>'; } else { $datatable .= '<td> </td>'; } @@ -1579,12 +1628,12 @@ sub display_color_options { $datatable .= '<td><span class="LC_nobreak">'. '<input type="text" class="colorchooser" size="10" name="'.$role.'_font"'. ' value="'.$current_color.'" /> '. - ' </td></tr>'; + ' </span></td></tr>'; unless ($role eq 'login') { $datatable .= '<tr'.$css_class.'>'. '<td>'.$choices->{'fontmenu'}.'</td>'; if (!$is_custom->{'fontmenu'}) { - $datatable .= '<td>'.&mt('Default in use:').' <span id="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>'; + $datatable .= '<td>'.&mt('Default in use:').' <span class="css_default_'.$role.'_font" style="color: '.$defaults->{'fontmenu'}.';">'.$defaults->{'fontmenu'}.'</span></td>'; } else { $datatable .= '<td> </td>'; } @@ -1594,7 +1643,7 @@ sub display_color_options { '<input class="colorchooser" type="text" size="10" name="' .$role.'_fontmenu"'. ' value="'.$current_color.'" /> '. - ' </td></tr>'; + ' </span></td></tr>'; } my $switchserver = &check_switchserver($dom,$confname); foreach my $img (@{$images}) { @@ -1653,7 +1702,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; } } @@ -1711,7 +1761,7 @@ sub display_color_options { my $bgs_def; foreach my $item (@{$bgs}) { if (!$is_custom->{$item}) { - $bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span> <span id="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';"> </span><br />'.$defaults->{'bgs'}{$item}.'</td>'; + $bgs_def .= '<td><span class="LC_nobreak">'.$choices->{$item}.'</span> <span class="css_default_'.$role.'_'.$item.'" style="background-color: '.$defaults->{'bgs'}{$item}.';"> </span><br />'.$defaults->{'bgs'}{$item}.'</td>'; } } if ($bgs_def) { @@ -1723,7 +1773,7 @@ sub display_color_options { '<table border="0"><tr>'; foreach my $item (@{$bgs}) { - $datatable .= '<td align="center">'.$choices->{$item}; + $datatable .= '<td style="text-align: center">'.$choices->{$item}; my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item}; if ($designs->{'bgs'}{$item}) { $datatable .= ' '; @@ -1739,7 +1789,7 @@ sub display_color_options { my $links_def; foreach my $item (@{$links}) { if (!$is_custom->{$item}) { - $links_def .= '<td>'.$choices->{$item}.'<br /><span id="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>'; + $links_def .= '<td>'.$choices->{$item}.'<br /><span class="css_default_'.$role.'_'.$item.'" style="color: '.$defaults->{'links'}{$item}.';">'.$defaults->{'links'}{$item}.'</span></td>'; } } if ($links_def) { @@ -1751,7 +1801,7 @@ sub display_color_options { '<table border="0"><tr>'; foreach my $item (@{$links}) { my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item}; - $datatable .= '<td align="center">'.$choices->{$item}."\n"; + $datatable .= '<td style="text-align: center">'.$choices->{$item}."\n"; if ($designs->{'links'}{$item}) { $datatable.=' '; } @@ -1812,7 +1862,7 @@ sub login_text_colors { my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_; my $color_menu = '<table border="0"><tr>'; foreach my $item (@{$logintext}) { - $color_menu .= '<td align="center">'.$choices->{$item}; + $color_menu .= '<td style="text-align: center">'.$choices->{$item}; my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item}; $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color. '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>'; @@ -1825,17 +1875,15 @@ sub image_changes { my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_; my $output; if ($img eq 'login') { - # suppress image for Log-in header + $output = '</td><td>'.$logincolors; # suppress image for Log-in header } elsif (!$is_custom) { if ($img ne 'domlogo') { - $output .= &mt('Default image:').'<br />'; + $output = &mt('Default image:').'<br />'; } else { - $output .= &mt('Default in use:').'<br />'; + $output = &mt('Default in use:').'<br />'; } } - if ($img eq 'login') { # suppress image for Log-in header - $output .= '<td>'.$logincolors; - } else { + if ($img ne 'login') { if ($img_import) { $output .= '<input type="hidden" name="'.$role.'_import_'.$img.'" value="'.$imgfile.'" />'; } @@ -1847,7 +1895,7 @@ sub image_changes { $role.'_del_'.$img.'" value="1" />'.&mt('Delete?'). '</label> '.&mt('Replace:').'</span><br />'; } else { - $output .= '<td valign="middle">'.$logincolors.&mt('Upload:').'<br />'; + $output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />'; } } return $output; @@ -1866,7 +1914,7 @@ sub print_quotas { my $typecount = 0; my ($css_class,%titles); if ($context eq 'requestcourses') { - @usertools = ('official','unofficial','community','textbook','placement'); + @usertools = ('official','unofficial','community','textbook','placement','lti'); @options =('norequest','approval','validate','autolimit'); %validations = &Apache::lonnet::auto_courserequest_checks($dom); %titles = &courserequest_titles(); @@ -2279,7 +2327,7 @@ sub print_quotas { } sub print_requestmail { - my ($dom,$action,$settings,$rowtotal) = @_; + my ($dom,$action,$settings,$rowtotal,$customcss,$rowstyle) = @_; my ($now,$datatable,%currapp); $now = time; if (ref($settings) eq 'HASH') { @@ -2291,7 +2339,19 @@ sub print_requestmail { } my $numinrow = 2; my $css_class; - $css_class = ($$rowtotal%2? ' class="LC_odd_row"':''); + if ($$rowtotal%2) { + $css_class = 'LC_odd_row'; + } + if ($customcss) { + $css_class .= " $customcss"; + } + $css_class =~ s/^\s+//; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowstyle) { + $css_class .= ' style="'.$rowstyle.'"'; + } my $text; if ($action eq 'requestcourses') { $text = &mt('Receive notification of course requests requiring approval'); @@ -2318,7 +2378,7 @@ sub print_studentcode { my ($settings,$rowtotal) = @_; my $rownum = 0; my ($output,%current); - my @crstypes = ('official','unofficial','community','textbook','placement'); + my @crstypes = ('official','unofficial','community','textbook','placement','lti'); if (ref($settings) eq 'HASH') { if (ref($settings->{'uniquecode'}) eq 'HASH') { foreach my $type (@crstypes) { @@ -2445,7 +2505,7 @@ sub print_textbookcourses { $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; } $datatable .= '</select> '."\n". - '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</td>'."\n". + '<input type="checkbox" name="'.$type.'_addbook" value="1" />'.&mt('Add').'</span></td>'."\n". '<td colspan="2">'. '<span class="LC_nobreak">'.&mt('Subject:').'<input type="text" size="15" name="'.$type.'_addbook_subject" value="" /></span> '."\n". (' 'x2). @@ -2462,13 +2522,13 @@ sub print_textbookcourses { } else { $datatable .= '<input type="file" name="'.$type.'_addbook_image" value="" />'; } + $datatable .= '</span>'."\n"; } - $datatable .= '</span>'."\n". - '<span class="LC_nobreak">'.&mt('LON-CAPA course:').' '. + $datatable .= '<span class="LC_nobreak">'.&mt('LON-CAPA course:').' '. &Apache::loncommon::select_dom_form($env{'request.role.domain'},$type.'_addbook_cdom'). '<input type="text" size="25" name="'.$type.'_addbook_cnum" value="" />'. &Apache::loncommon::selectcourse_link - ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course'); + ('display',$type.'_addbook_cnum',$type.'_addbook_cdom',undef,undef,undef,'Course'). '</span></td>'."\n". '</tr>'."\n"; $itemcount ++; @@ -2570,7 +2630,10 @@ ENDSCRIPT sub ltitools_javascript { my ($settings) = @_; - return unless(ref($settings) eq 'HASH'); + my $togglejs = <itools_toggle_js(); + unless (ref($settings) eq 'HASH') { + return $togglejs; + } my (%ordered,$total,%jstext); $total = 0; foreach my $item (keys(%{$settings})) { @@ -2588,7 +2651,7 @@ sub ltitools_javascript { return <<"ENDSCRIPT"; <script type="text/javascript"> // <![CDATA[ -function reorderLTI(form,item) { +function reorderLTITools(form,item) { var changedVal; $jstext var newpos = 'ltitools_add_pos'; @@ -2633,6 +2696,288 @@ $jstext // ]]> </script> +$togglejs + +ENDSCRIPT +} + +sub ltitools_toggle_js { + return <<"ENDSCRIPT"; +<script type="text/javascript"> +// <![CDATA[ + +function toggleLTITools(form,setting,item) { + var radioname = ''; + var divid = ''; + if ((setting == 'passback') || (setting == 'roster')) { + radioname = 'ltitools_'+setting+'_'+item; + divid = 'ltitools_'+setting+'time_'+item; + var num = form.elements[radioname].length; + if (num) { + var setvis = ''; + for (var i=0; i<num; i++) { + if (form.elements[radioname][i].checked) { + if (form.elements[radioname][i].value == '1') { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'inline-block'; + } + setvis = 1; + } + break; + } + } + } + if (!setvis) { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'none'; + } + } + } + if (setting == 'user') { + divid = 'ltitools_'+setting+'_div_'+item; + var checkid = 'ltitools_'+setting+'_field_'+item; + if (document.getElementById(divid)) { + if (document.getElementById(checkid)) { + if (document.getElementById(checkid).checked) { + document.getElementById(divid).style.display = 'inline-block'; + } else { + document.getElementById(divid).style.display = 'none'; + } + } + } + } + return; +} +// ]]> +</script> + +ENDSCRIPT +} + +sub lti_javascript { + my ($settings) = @_; + my $togglejs = <i_toggle_js(); + unless (ref($settings) eq 'HASH') { + return $togglejs; + } + my (%ordered,$total,%jstext); + $total = 0; + foreach my $item (keys(%{$settings})) { + if (ref($settings->{$item}) eq 'HASH') { + my $num = $settings->{$item}{'order'}; + $ordered{$num} = $item; + } + } + $total = scalar(keys(%{$settings})); + my @jsarray = (); + foreach my $item (sort {$a <=> $b } (keys(%ordered))) { + push(@jsarray,$ordered{$item}); + } + my $jstext = ' var lti = Array('."'".join("','",@jsarray)."'".');'."\n"; + return <<"ENDSCRIPT"; +<script type="text/javascript"> +// <![CDATA[ +function reorderLTI(form,item) { + var changedVal; +$jstext + var newpos = 'lti_pos_add'; + var maxh = 1 + $total; + var current = new Array; + var newitemVal = form.elements[newpos].options[form.elements[newpos].selectedIndex].value; + if (item == newpos) { + changedVal = newitemVal; + } else { + changedVal = form.elements[item].options[form.elements[item].selectedIndex].value; + current[newitemVal] = newpos; + } + for (var i=0; i<lti.length; i++) { + var elementName = 'lti_pos_'+lti[i]; + if (elementName != item) { + if (form.elements[elementName]) { + var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value; + current[currVal] = elementName; + } + } + } + var oldVal; + for (var j=0; j<maxh; j++) { + if (current[j] == undefined) { + oldVal = j; + } + } + if (oldVal < changedVal) { + for (var k=oldVal+1; k<=changedVal ; k++) { + var elementName = current[k]; + form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1; + } + } else { + for (var k=changedVal; k<oldVal; k++) { + var elementName = current[k]; + form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1; + } + } + return; +} +// ]]> +</script> + +$togglejs + +ENDSCRIPT +} + +sub lti_toggle_js { + my %lcauthparmtext = &Apache::lonlocal::texthash ( + localauth => 'Local auth argument', + krb => 'Kerberos domain', + ); + return <<"ENDSCRIPT"; +<script type="text/javascript"> +// <![CDATA[ + +function toggleLTI(form,setting,item) { + if ((setting == 'user') || (setting == 'crs') || (setting == 'passback')) { + var radioname = ''; + var divid = ''; + if (setting == 'user') { + radioname = 'lti_mapuser_'+item; + divid = 'lti_userfield_'+item; + } else if (setting == 'crs') { + radioname = 'lti_mapcrs_'+item; + divid = 'lti_crsfield_'+item; + } else { + radioname = 'lti_passbackformat_'+item; + divid = 'lti_passback_'+item; + } + var num = form.elements[radioname].length; + if (num) { + var setvis = ''; + for (var i=0; i<num; i++) { + if (form.elements[radioname][i].checked) { + if (setting == 'passback') { + if (form.elements[radioname][i].value == '1') { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'inline-block'; + } + setvis = 1; + break; + } + } else { + if (form.elements[radioname][i].value == 'other') { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'inline-block'; + } + setvis = 1; + break; + } + } + } + } + if (!setvis) { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'none'; + } + } + } + } else if ((setting == 'sec') || (setting == 'secsrc')) { + var numsec = form.elements['lti_crssec_'+item].length; + if (numsec) { + var setvis = ''; + for (var i=0; i<numsec; i++) { + if (form.elements['lti_crssec_'+item][i].checked) { + if (form.elements['lti_crssec_'+item][i].value == '1') { + if (document.getElementById('lti_crssecfield_'+item)) { + document.getElementById('lti_crssecfield_'+item).style.display = 'inline-block'; + setvis = 1; + var numsrcsec = form.elements['lti_crssecsrc_'+item].length; + if (numsrcsec) { + var setsrcvis = ''; + for (var j=0; j<numsrcsec; j++) { + if (form.elements['lti_crssecsrc_'+item][j].checked) { + if (form.elements['lti_crssecsrc_'+item][j].value == 'other') { + if (document.getElementById('lti_secsrcfield_'+item)) { + document.getElementById('lti_secsrcfield_'+item).style.display = 'inline-block'; + setsrcvis = 1; + } + } + } + } + if (!setsrcvis) { + if (document.getElementById('lti_secsrcfield_'+item)) { + document.getElementById('lti_secsrcfield_'+item).style.display = 'none'; + } + } + } + } + } + } + } + if (!setvis) { + if (document.getElementById('lti_crssecfield_'+item)) { + document.getElementById('lti_crssecfield_'+item).style.display = 'none'; + } + if (document.getElementById('lti_secsrcfield_'+item)) { + document.getElementById('lti_secsrcfield_'+item).style.display = 'none'; + } + } + } + } else if (setting == 'lcauth') { + var numauth = form.elements['lti_lcauth_'+item].length; + if (numauth) { + for (var i=0; i<numauth; i++) { + if (form.elements['lti_lcauth_'+item][i].checked) { + if (document.getElementById('lti_'+setting+'_parmrow_'+item)) { + if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) { + document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none'; + } else { + document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row'; + if (document.getElementById('lti_'+setting+'_parmtext_'+item)) { + if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') { + document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}"; + } else { + document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}"; + } + } + } + } + } + } + } + } else if (setting == 'lcmenu') { + var menus = new Array('lti_topmenu_'+item,'lti_inlinemenu_'+item); + var divid = 'lti_menufield_'+item; + var setvis = ''; + for (var i=0; i<menus.length; i++) { + var radioname = menus[i]; + var num = form.elements[radioname].length; + if (num) { + for (var j=0; j<num; j++) { + if (form.elements[radioname][j].checked) { + if (form.elements[radioname][j].value == '1') { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'inline-block'; + } + setvis = 1; + break; + } + } + } + } + if (setvis == 1) { + break; + } + } + if (!setvis) { + if (document.getElementById(divid)) { + document.getElementById(divid).style.display = 'none'; + } + } + } + return; +} +// ]]> +</script> + ENDSCRIPT } @@ -2715,7 +3060,7 @@ sub print_autoenroll { '<td>'.&mt('Failsafe for no drops when institutional data missing').'</td>'. '<td class="LC_right_item"><span class="LC_nobreak">'. '<input type="text" name="autoenroll_failsafe"'. - ' value="'.$failsafe.'" size="4" /></td></tr>'; + ' value="'.$failsafe.'" size="4" /></span></td></tr>'; $$rowtotal += 4; return $datatable; } @@ -2764,7 +3109,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); @@ -2907,7 +3252,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; } } @@ -2996,7 +3342,7 @@ sub print_contacts { my $datatable; my @contacts = ('adminemail','supportemail'); my (%checked,%to,%otheremails,%bccemails,%includestr,%includeloc,%currfield, - $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings); + $maxsize,$fields,$fieldtitles,$fieldoptions,$possoptions,@mailings,%lonstatus); if ($position eq 'top') { if (ref($settings) eq 'HASH') { foreach my $item (@contacts) { @@ -3011,6 +3357,12 @@ sub print_contacts { foreach my $type (@mailings) { $otheremails{$type} = ''; } + } elsif ($position eq 'lower') { + if (ref($settings) eq 'HASH') { + if (ref($settings->{'lonstatus'}) eq 'HASH') { + %lonstatus = %{$settings->{'lonstatus'}}; + } + } } else { @mailings = ('helpdeskmail','otherdomsmail'); foreach my $type (@mailings) { @@ -3023,7 +3375,7 @@ sub print_contacts { ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields(); } if (ref($settings) eq 'HASH') { - unless ($position eq 'top') { + unless (($position eq 'top') || ($position eq 'lower')) { foreach my $type (@mailings) { if (exists($settings->{$type})) { if (ref($settings->{$type}) eq 'HASH') { @@ -3108,7 +3460,54 @@ sub print_contacts { $to{$item}.'" /></td></tr>'; $rownum ++; } - } else { + } elsif ($position eq 'bottom') { + $css_class = $rownum%2?' class="LC_odd_row"':''; + $datatable .= '<tr'.$css_class.'>'. + '<td>'.&mt('Extra helpdesk form fields:').'<br />'. + &mt('(e-mail, subject, and description always shown)'). + '</td><td class="LC_left_item">'; + if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') && + (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) { + $datatable .= '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Status').'</th></tr>'; + foreach my $field (@{$fields}) { + $datatable .= '<tr><td>'.$fieldtitles->{$field}; + if (($field eq 'screenshot') || ($field eq 'cc')) { + $datatable .= ' '.&mt('(logged-in users)'); + } + $datatable .='</td><td>'; + my $clickaction; + if ($field eq 'screenshot') { + $clickaction = ' onclick="screenshotSize(this);"'; + } + if (ref($possoptions->{$field}) eq 'ARRAY') { + foreach my $option (@{$possoptions->{$field}}) { + my $checked; + if ($currfield{$field} eq $option) { + $checked = ' checked="checked"'; + } + $datatable .= '<span class="LC_nobreak"><label>'. + '<input type="radio" name="helpform_'.$field.'" '. + 'value="'.$option.'"'.$checked.$clickaction.' />'.$fieldoptions->{$option}. + '</label></span>'.(' 'x2); + } + } + if ($field eq 'screenshot') { + my $display; + if ($currfield{$field} eq 'no') { + $display = ' style="display:none"'; + } + $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.'>'. + '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'. + '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />'; + } + $datatable .= '</td></tr>'; + } + $datatable .= '</table>'; + } + $datatable .= '</td></tr>'."\n"; + $rownum ++; + } + unless (($position eq 'top') || ($position eq 'lower')) { foreach my $type (@mailings) { $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= '<tr'.$css_class.'>'. @@ -3142,7 +3541,7 @@ sub print_contacts { 'value="'.$bccemails{$type}.'" /></fieldset>'. '<fieldset><legend>'.&mt('Optional added text').'</legend>'. &mt('Text automatically added to e-mail:').' '. - '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br >'. + '<input type="text" name="'.$type.'_includestr" value="'.$includestr{$type}.'" /><br />'. '<span class="LC_nobreak">'.&mt('Location:').' '. '<label><input type="radio" name="'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'. (' 'x2). @@ -3155,69 +3554,248 @@ sub print_contacts { } if ($position eq 'middle') { my %choices; - $choices{'reporterrors'} = &mt('E-mail error reports to [_1]', - &Apache::loncommon::modal_link('http://loncapa.org/core.html', - &mt('LON-CAPA core group - MSU'),600,500)); + my $corelink = &core_link_msu(); + $choices{'reporterrors'} = &mt('E-mail error reports to [_1]',$corelink); $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]', - &Apache::loncommon::modal_link('http://loncapa.org/core.html', - &mt('LON-CAPA core group - MSU'),600,500)); - my @toggles = ('reporterrors','reportupdates'); + $corelink); + $choices{'reportstatus'} = &mt('E-mail status if errors above threshold to [_1]',$corelink); + my @toggles = ('reporterrors','reportupdates','reportstatus'); my %defaultchecked = ('reporterrors' => 'on', - 'reportupdates' => 'on'); + 'reportupdates' => 'on', + 'reportstatus' => 'on'); (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, \%choices,$rownum); $datatable .= $reports; - } elsif ($position eq 'bottom') { + } elsif ($position eq 'lower') { $css_class = $rownum%2?' class="LC_odd_row"':''; - $datatable .= '<tr'.$css_class.'>'. - '<td>'.&mt('Extra helpdesk form fields:').'<br />'. - &mt('(e-mail, subject, and description always shown)'). - '</td><td class="LC_left_item">'; - if ((ref($fields) eq 'ARRAY') && (ref($fieldtitles) eq 'HASH') && - (ref($fieldoptions) eq 'HASH') && (ref($possoptions) eq 'HASH')) { - $datatable .= '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Status').'</th></tr>'; - foreach my $field (@{$fields}) { - $datatable .= '<tr><td>'.$fieldtitles->{$field}; - if (($field eq 'screenshot') || ($field eq 'cc')) { - $datatable .= ' '.&mt('(logged-in users)'); + my ($threshold,$sysmail,%excluded,%weights); + my ($defaults,$names) = &Apache::loncommon::lon_status_items(); + if ($lonstatus{'threshold'} =~ /^\d+$/) { + $threshold = $lonstatus{'threshold'}; + } else { + $threshold = $defaults->{'threshold'}; + } + if ($lonstatus{'sysmail'} =~ /^\d+$/) { + $sysmail = $lonstatus{'sysmail'}; + } else { + $sysmail = $defaults->{'sysmail'}; + } + if (ref($lonstatus{'weights'}) eq 'HASH') { + foreach my $type ('E','W','N','U') { + if ($lonstatus{'weights'}{$type} =~ /^\d+$/) { + $weights{$type} = $lonstatus{'weights'}{$type}; + } else { + $weights{$type} = $defaults->{$type}; } - $datatable .='</td><td>'; - my $clickaction; - if ($field eq 'screenshot') { - $clickaction = ' onclick="screenshotSize(this);"'; + } + } else { + foreach my $type ('E','W','N','U') { + $weights{$type} = $defaults->{$type}; + } + } + if (ref($lonstatus{'excluded'}) eq 'ARRAY') { + if (@{$lonstatus{'excluded'}} > 0) { + map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}}; + } + } + $datatable .= '<tr'.$css_class.'>'. + '<td class="LC_left_item"><span class="LC_nobreak">'. + $titles->{'errorthreshold'}. + '</span></td><td class="LC_left_item">'. + '<input type="text" name="errorthreshold" value="'. + $threshold.'" size="5" /></td></tr>'; + $rownum ++; + $css_class = $rownum%2?' class="LC_odd_row"':''; + $datatable .= '<tr'.$css_class.'>'. + '<td class="LC_left_item">'. + '<span class="LC_nobreak">'.$titles->{'errorweights'}. + '</span></td><td class="LC_left_item"><table><tr>'; + foreach my $type ('E','W','N','U') { + $datatable .= '<td>'.$names->{$type}.'<br />'. + '<input type="text" name="errorweights_'.$type.'" value="'. + $weights{$type}.'" size="5" /></td>'; + } + $datatable .= '</tr></table></tr>'; + $rownum ++; + $css_class = $rownum%2?' class="LC_odd_row"':''; + $datatable .= '<tr'.$css_class.'><td class="LC_left_item">'. + $titles->{'errorexcluded'}.'</td>'. + '<td class="LC_left_item"><table>'; + my $numinrow = 4; + my @ids = sort(values(%Apache::lonnet::serverhomeIDs)); + for (my $i=0; $i<@ids; $i++) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $datatable .= '</tr>'; } - if (ref($possoptions->{$field}) eq 'ARRAY') { - foreach my $option (@{$possoptions->{$field}}) { - my $checked; - if ($currfield{$field} eq $option) { - $checked = ' checked="checked"'; + $datatable .= '<tr>'; + } + my $check; + if ($excluded{$ids[$i]}) { + $check = ' checked="checked" '; + } + $datatable .= '<td class="LC_left_item">'. + '<span class="LC_nobreak"><label>'. + '<input type="checkbox" name="errorexcluded" '. + 'value="'.$ids[$i].'"'.$check.' />'. + $ids[$i].'</label></span></td>'; + } + my $colsleft = $numinrow - @ids%($numinrow); + if ($colsleft > 1 ) { + $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. + ' </td>'; + } elsif ($colsleft == 1) { + $datatable .= '<td class="LC_left_item"> </td>'; + } + $datatable .= '</tr></table></td></tr>'; + $rownum ++; + $css_class = $rownum%2?' class="LC_odd_row"':''; + $datatable .= '<tr'.$css_class.'>'. + '<td class="LC_left_item"><span class="LC_nobreak">'. + $titles->{'errorsysmail'}. + '</span></td><td class="LC_left_item">'. + '<input type="text" name="errorsysmail" value="'. + $sysmail.'" size="5" /></td></tr>'; + $rownum ++; + } elsif ($position eq 'bottom') { + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + my (@posstypes,%usertypeshash); + if (ref($types) eq 'ARRAY') { + @posstypes = @{$types}; + } + if (@posstypes) { + if (ref($usertypes) eq 'HASH') { + %usertypeshash = %{$usertypes}; + } + my @overridden; + my $numinrow = 4; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'overrides'}) eq 'HASH') { + foreach my $key (sort(keys(%{$settings->{'overrides'}}))) { + if (ref($settings->{'overrides'}{$key}) eq 'HASH') { + push(@overridden,$key); + foreach my $item (@contacts) { + if ($settings->{'overrides'}{$key}{$item}) { + $checked{'override_'.$key}{$item} = ' checked="checked" '; + } + } + $otheremails{'override_'.$key} = $settings->{'overrides'}{$key}{'others'}; + $bccemails{'override_'.$key} = $settings->{'overrides'}{$key}{'bcc'}; + $includeloc{'override_'.$key} = ''; + $includestr{'override_'.$key} = ''; + if ($settings->{'overrides'}{$key}{'include'} ne '') { + ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = + split(/:/,$settings->{'overrides'}{$key}{'include'},2); + $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key}); + } } - $datatable .= '<span class="LC_nobreak"><label>'. - '<input type="radio" name="helpform_'.$field.'" '. - 'value="'.$option.'"'.$checked.$clickaction.' />'.$fieldoptions->{$option}. - '</label></span>'.(' 'x2); } } - if ($field eq 'screenshot') { - my $display; - if ($currfield{$field} eq 'no') { - $display = ' style="display:none"'; - } - $datatable .= '</td></tr><tr id="help_screenshotsize"'.$display.' />'. - '<td>'.&mt('Maximum size for upload (MB)').'</td><td>'. - '<input type="text" size="5" name="helpform_maxsize" value="'.$maxsize.'" />'; + } + 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 .= '</td></tr>'; } - $datatable .= '</table>'; } - $datatable .= '</td></tr>'."\n"; - $rownum ++; } $$rowtotal += $rownum; return $datatable; } +sub core_link_msu { + return &Apache::loncommon::modal_link('http://loncapa.org/core.html', + &mt('LON-CAPA core group - MSU'),600,500); +} + +sub overridden_helpdesk { + my ($checked,$otheremails,$bccemails,$includeloc,$includestr,$type,$rowid, + $typetitle,$css_class,$rowstyle,$contacts,$short_titles) = @_; + my $class = 'LC_left_item'; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowid) { + $rowid = ' id="'.$rowid.'"'; + } + if ($rowstyle) { + $rowstyle = ' style="'.$rowstyle.'"'; + } + my ($output,$description); + $description = &mt('Helpdesk requests from: [_1] in this domain (overrides default)',"<b>$typetitle</b>"); + $output = '<tr'.$css_class.$rowid.$rowstyle.'>'. + "<td>$description</td>\n". + '<td class="'.$class.'" colspan="2">'. + '<fieldset><legend>'.&mt('E-mail recipient(s)').'</legend>'. + '<span class="LC_nobreak">'; + if (ref($contacts) eq 'ARRAY') { + foreach my $item (@{$contacts}) { + my $check; + if (ref($checked) eq 'HASH') { + $check = $checked->{$item}; + } + my $title; + if (ref($short_titles) eq 'HASH') { + $title = $short_titles->{$item}; + } + $output .= '<label>'. + '<input type="checkbox" name="override_'.$type.'"'.$check. + ' value="'.$item.'" />'.$title.'</label> '; + } + } + $output .= '</span><br />'.&mt('Others').': '. + '<input type="text" name="override_'.$type.'_others" '. + 'value="'.$otheremails.'" />'; + my %locchecked; + foreach my $loc ('s','b') { + if ($includeloc eq $loc) { + $locchecked{$loc} = ' checked="checked"'; + last; + } + } + $output .= '<br />'.&mt('Bcc:').(' 'x6). + '<input type="text" name="override_'.$type.'_bcc" '. + 'value="'.$bccemails.'" /></fieldset>'. + '<fieldset><legend>'.&mt('Optional added text').'</legend>'. + &mt('Text automatically added to e-mail:').' '. + '<input type="text" name="override_'.$type.'_includestr" value="'.$includestr.'" /><br />'. + '<span class="LC_nobreak">'.&mt('Location:').' '. + '<label><input type="radio" name="override_'.$type.'_includeloc" value="s"'.$locchecked{'s'}.' />'.&mt('in subject').'</label>'. + (' 'x2). + '<label><input type="radio" name="override_'.$type.'_includeloc" value="b"'.$locchecked{'b'}.' />'.&mt('in body').'</label>'. + '</span></fieldset>'. + '</td></tr>'."\n"; + return $output; +} + sub contacts_javascript { return <<"ENDSCRIPT"; @@ -3235,6 +3813,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<form.elements[checkbox].length; i++) { + if (form.elements[checkbox][i].checked) { + count ++; + } + } + } + for (var i=0; i<form.elements[checkbox].length; i++) { + var type = form.elements[checkbox][i].value; + if (document.getElementById(prefix+type)) { + if (form.elements[checkbox][i].checked) { + document.getElementById(prefix+type).style.display = 'table-row'; + if (count % 2 == 1) { + document.getElementById(prefix+type).className = target+' LC_odd_row'; + } else { + document.getElementById(prefix+type).className = target; + } + count ++; + } else { + document.getElementById(prefix+type).style.display = 'none'; + } + } + } + } + return; +} + + // ]]> </script> @@ -3261,8 +3870,10 @@ sub print_helpsettings { my $css_class; my %existing=&Apache::lonnet::dump('roles',$dom,$confname,'rolesdef_'); my (%customroles,%ordered,%current); - if (ref($settings->{'adhoc'}) eq 'HASH') { - %current = %{$settings->{'adhoc'}}; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'adhoc'}) eq 'HASH') { + %current = %{$settings->{'adhoc'}}; + } } my $count = 0; foreach my $key (sort(keys(%existing))) { @@ -3304,7 +3915,6 @@ sub print_helpsettings { push(@jsarray,('notinc','notexc')); } my $hiddenstr = join("','",@jsarray); - $datatable .= &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname); my $context = 'domprefs'; my $crstype = 'Course'; my $prefix = 'helproles_'; @@ -3338,7 +3948,7 @@ sub print_helpsettings { my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype); $css_class = $itemcount%2?' class="LC_odd_row"':''; my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"'; - $datatable .= '<tr '.$css_class.'><td valign="top"><b>'.$role.'</b><br />'. + $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'. '<select name="helproles_'.$num.'_pos"'.$chgstr.'>'; for (my $k=0; $k<=$maxnum; $k++) { my $vpos = $k+1; @@ -3377,7 +3987,7 @@ sub print_helpsettings { &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent); my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype); my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"'; - $datatable .= '<tr '.$css_class.'><td valign="top"><span class="LC_nobreak"><label>'. + $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'. '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n". '<select name="helproles_'.$count.'_pos"'.$chgstr.'>'; for (my $k=0; $k<$maxnum+1; $k++) { @@ -3407,7 +4017,9 @@ sub print_helpsettings { \@templateroles,$newcust). &Apache::lonuserutils::custom_role_table('Course',\%full,\%levels, \%levelscurrent,$newcust). - '</fieldset></td></tr>'; + '</fieldset>'. + &helpsettings_javascript(\@roles_by_num,$maxnum,$hiddenstr,$formname). + '</td></tr>'; $count ++; $$rowtotal += $count; } @@ -3656,7 +4268,7 @@ sub radiobutton_prefs { foreach my $item (@{$toggles}) { $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= - '<tr'.$css_class.'><td valign="top">'. + '<tr'.$css_class.'><td style="vertical-align: top">'. '<span class="LC_nobreak">'.$choices->{$item}. '</span></td>'; if ($align eq 'left') { @@ -3696,28 +4308,34 @@ sub print_ltitools { my $confname = $dom.'-domainconfig'; my $switchserver = &check_switchserver($dom,$confname); my $maxnum = scalar(keys(%ordered)); - my $datatable = <itools_javascript($settings); + my $datatable; my %lt = <itools_names(); my @courseroles = ('cc','in','ta','ep','st'); my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner); - my @fields = ('fullname','firstname','lastname','email','user','roles'); + my @fields = ('fullname','firstname','lastname','email','roles','user'); if (keys(%ordered)) { my @items = sort { $a <=> $b } keys(%ordered); for (my $i=0; $i<@items; $i++) { $css_class = $itemcount%2?' class="LC_odd_row"':''; my $item = $ordered{$items[$i]}; - my ($title,$key,$secret,$url,$imgsrc,$version); + my ($title,$key,$secret,$url,$lifetime,$imgsrc,%sigsel); if (ref($settings->{$item}) eq 'HASH') { $title = $settings->{$item}->{'title'}; $url = $settings->{$item}->{'url'}; $key = $settings->{$item}->{'key'}; $secret = $settings->{$item}->{'secret'}; + $lifetime = $settings->{$item}->{'lifetime'}; my $image = $settings->{$item}->{'image'}; if ($image ne '') { $imgsrc = '<img src="'.$image.'" alt="'.&mt('Tool Provider icon').'" />'; } + if ($settings->{$item}->{'sigmethod'} eq 'HMAC-256') { + $sigsel{'HMAC-256'} = ' selected="selected"'; + } else { + $sigsel{'HMAC-SHA1'} = ' selected="selected"'; + } } - my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'ltitools_".$item."'".');"'; + my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_".$item."'".');"'; $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' .'<select name="ltitools_'.$item.'"'.$chgstr.'>'; for (my $k=0; $k<=$maxnum; $k++) { @@ -3733,20 +4351,27 @@ sub print_ltitools { &mt('Delete?').'</label></span></td>'. '<td colspan="2">'. '<fieldset><legend>'.&mt('Required settings').'</legend>'. - '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="30" name="ltitools_title_'.$i.'" value="'.$title.'" /></span> '. + '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_title_'.$i.'" value="'.$title.'" /></span> '. (' 'x2). '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_version_'.$i.'">'. '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '. (' 'x2). '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_msgtype_'.$i.'">'. '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '. + (' 'x2). + '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_sigmethod_'.$i.'">'. + '<option value="HMAC-SHA1"'.$sigsel{'HMAC-SHA1'}.'>HMAC-SHA1</option>'. + '<option value="HMAC-SHA256"'.$sigsel{'HMAC-SHA256'}.'>HMAC-SHA256</option></select></span>'. '<br /><br />'. - '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="30" name="ltitools_url_'.$i.'"'. + '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_url_'.$i.'"'. ' value="'.$url.'" /></span>'. (' 'x2). - '<span class="LC_nobreak">'.$lt{'key'}. + '<span class="LC_nobreak">'.$lt{'key'}.':'. '<input type="text" size="25" name="ltitools_key_'.$i.'" value="'.$key.'" /></span> '. (' 'x2). + '<span class="LC_nobreak">'.$lt{'lifetime'}.':'. + '<input type="text" size="5" name="ltitools_lifetime_'.$i.'" value="'.$lifetime.'" /></span> '. + (' 'x2). '<span class="LC_nobreak">'.$lt{'secret'}.':'. '<input type="password" size="20" name="ltitools_secret_'.$i.'" value="'.$secret.'" />'. '<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>'. @@ -3758,6 +4383,8 @@ sub print_ltitools { if (ref($settings->{$item}->{'display'}) eq 'HASH') { if ($settings->{$item}->{'display'}->{'target'} eq 'window') { $currdisp{'window'} = ' checked="checked"'; + } elsif ($settings->{$item}->{'display'}->{'target'} eq 'tab') { + $currdisp{'tab'} = ' checked="checked"'; } else { $currdisp{'iframe'} = ' checked="checked"'; } @@ -3772,7 +4399,7 @@ sub print_ltitools { } else { $currdisp{'iframe'} = ' checked="checked"'; } - foreach my $disp ('iframe','window') { + foreach my $disp ('iframe','tab','window') { $datatable .= '<label><input type="radio" name="ltitools_target_'.$i.'" value="'.$disp.'"'.$currdisp{$disp}.' />'. $lt{$disp}.'</label>'.(' 'x2); } @@ -3782,27 +4409,42 @@ sub print_ltitools { '<input type="text" name="ltitools_'.$dimen.'_'.$i.'" size="5" value="'.$currdisp{$dimen}.'" /></label>'. (' 'x2); } - $datatable .= '<br />'. + $datatable .= '</span><br />'. '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'. - '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></label></div>'. + '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></div>'. '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'. '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}. '</textarea></div><div style=""></div><br />'; - $datatable .= '<br />'; + my %units = ( + 'passback' => 'days', + 'roster' => 'seconds', + ); foreach my $extra ('passback','roster') { + my $validsty = 'none'; + my $currvalid; my $checkedon = ''; my $checkedoff = ' checked="checked"'; if ($settings->{$item}->{$extra}) { $checkedon = $checkedoff; $checkedoff = ''; - } - $datatable .= $lt{$extra}.' '. - '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.' />'. - &mt('Yes').'</label>'.(' 'x2). - '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.' />'. - &mt('No').'</label>'.(' 'x4); + $validsty = 'inline-block'; + if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) { + $currvalid = $settings->{$item}->{$extra.'valid'}; + } + } + my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','$i'".');"'; + $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.' '. + '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.$onclick.' />'. + &mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.$onclick.' />'. + &mt('Yes').'</label></span></div>'. + '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_'.$extra.'time_'.$i.'">'. + '<span class="LC_nobreak">'. + &mt("at least [_1] $units{$extra} after launch", + '<input type="text" name="ltitools_'.$extra.'valid_'.$i.'" value="'.$currvalid.'" />'). + '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>'; } - $datatable .= '<br /><br /><span class="LC_nobreak">'.$lt{'icon'}.': '; + $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': '; if ($imgsrc) { $datatable .= $imgsrc. '<label><input type="checkbox" name="ltitools_image_del"'. @@ -3817,11 +4459,12 @@ sub print_ltitools { $datatable .= '<input type="file" name="ltitools_image_'.$i.'" value="" />'; } $datatable .= '</span></fieldset>'; - my (%checkedfields,%rolemaps); + my (%checkedfields,%rolemaps,$userincdom); if (ref($settings->{$item}) eq 'HASH') { if (ref($settings->{$item}->{'fields'}) eq 'HASH') { %checkedfields = %{$settings->{$item}->{'fields'}}; } + $userincdom = $settings->{$item}->{'incdom'}; if (ref($settings->{$item}->{'roles'}) eq 'HASH') { %rolemaps = %{$settings->{$item}->{'roles'}}; $checkedfields{'roles'} = 1; @@ -3829,23 +4472,47 @@ sub print_ltitools { } $datatable .= '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'. '<span class="LC_nobreak">'; + my $userfieldstyle = 'display:none;'; + my $seluserdom = ''; + my $unseluserdom = ' selected="selected"'; foreach my $field (@fields) { - my $checked; + my ($checked,$onclick,$id,$spacer); if ($checkedfields{$field}) { $checked = ' checked="checked"'; } + if ($field eq 'user') { + $id = ' id="ltitools_user_field_'.$i.'"'; + $onclick = ' onclick="toggleLTITools(this.form,'."'$field','$i'".')"'; + if ($checked) { + $userfieldstyle = 'display:inline-block'; + if ($userincdom) { + $seluserdom = $unseluserdom; + $unseluserdom = ''; + } + } + } else { + $spacer = (' ' x2); + } $datatable .= '<label>'. - '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$checked.' />'. - $lt{$field}.'</label>'.(' ' x2); + '<input type="checkbox" name="ltitools_fields_'.$i.'" value="'.$field.'"'.$id.$checked.$onclick.' />'. + $lt{$field}.'</label>'.$spacer; } - $datatable .= '</span></fieldset>'. + $datatable .= '</span>'; + $datatable .= '<div style="'.$userfieldstyle.'" id="ltitools_user_div_'.$i.'">'. + '<span class="LC_nobreak"> : '. + '<select name="ltitools_userincdom_'.$i.'">'. + '<option value="">'.&mt('Select').'</option>'. + '<option value="0"'.$unseluserdom.'>'.&mt('username').'</option>'. + '<option value="1"'.$seluserdom.'>'.&mt('username:domain').'</option>'. + '</select></span></div>'; + $datatable .= '</fieldset>'. '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>'; foreach my $role (@courseroles) { my ($selected,$selectnone); if (!$rolemaps{$role}) { $selectnone = ' selected="selected"'; } - $datatable .= '<td align="center">'. + $datatable .= '<td style="text-align: center">'. &Apache::lonnet::plaintext($role,'Course').'<br />'. '<select name="ltitools_roles_'.$role.'_'.$i.'">'. '<option value=""'.$selectnone.'>'.&mt('Select').'</option>'; @@ -3869,7 +4536,7 @@ sub print_ltitools { } } $datatable .= '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">'; - foreach my $item ('label','title','target','linktext','explanation') { + foreach my $item ('label','title','target','linktext','explanation','append') { my $checked; if ($courseconfig{$item}) { $checked = ' checked="checked"'; @@ -3902,7 +4569,7 @@ sub print_ltitools { } } $css_class = $itemcount%2?' class="LC_odd_row"':''; - my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'ltitools_add_pos'".');"'; + my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_add_pos'".');"'; $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". '<input type="hidden" name="ltitools_maxnum" value="'.$maxnum.'" />'."\n". '<select name="ltitools_add_pos"'.$chgstr.'>'; @@ -3915,21 +4582,26 @@ sub print_ltitools { $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; } $datatable .= '</select> '."\n". - '<input type="checkbox" name="ltitools_add" value="1" />'.&mt('Add').'</td>'."\n". + '<input type="checkbox" name="ltitools_add" value="1" />'.&mt('Add').'</span></td>'."\n". '<td colspan="2">'. '<fieldset><legend>'.&mt('Required settings').'</legend>'. - '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="30" name="ltitools_add_title" value="" /></span> '."\n". + '<span class="LC_nobreak">'.$lt{'title'}.':<input type="text" size="20" name="ltitools_add_title" value="" /></span> '."\n". (' 'x2). '<span class="LC_nobreak">'.$lt{'version'}.':<select name="ltitools_add_version">'. '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n". (' 'x2). '<span class="LC_nobreak">'.$lt{'msgtype'}.':<select name="ltitools_add_msgtype">'. '<option value="basic-lti-launch-request" selected="selected">Launch</option></select></span> '. + '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="ltitools_add_sigmethod">'. + '<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'. + '<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'. '<br />'. - '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="30" name="ltitools_add_url" value="" /></span> '."\n". + '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="ltitools_add_url" value="" /></span> '."\n". (' 'x2). '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="ltitools_add_key" value="" /></span> '."\n". (' 'x2). + '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="ltitools_add_lifetime" value="300" /></span> '."\n". + (' 'x2). '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="ltitools_add_secret" value="" />'. '<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". '</fieldset>'. @@ -3937,7 +4609,7 @@ sub print_ltitools { '<span class="LC_nobreak">'.&mt('Display target:'); my %defaultdisp; $defaultdisp{'iframe'} = ' checked="checked"'; - foreach my $disp ('iframe','window') { + foreach my $disp ('iframe','tab','window') { $datatable .= '<label><input type="radio" name="ltitools_add_target" value="'.$disp.'"'.$defaultdisp{$disp}.' />'. $lt{$disp}.'</label>'.(' 'x2); } @@ -3947,20 +4619,34 @@ sub print_ltitools { '<input type="text" name="ltitools_add_'.$dimen.'" size="5" /></label>'. (' 'x2); } - $datatable .= '<br />'. + $datatable .= '</span><br />'. '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'. - '<input type="text" name="ltitools_add_linktext" size="5" /></label></div>'. + '<input type="text" name="ltitools_add_linktext" size="5" /></div>'. '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'. - '<textarea name=ltitools_add_explanation" rows="5" cols="40"></textarea>'. + '<textarea name="ltitools_add_explanation" rows="5" cols="40"></textarea>'. '</div><div style=""></div><br />'; + my %units = ( + 'passback' => 'days', + 'roster' => 'seconds', + ); + my %defaulttimes = ( + 'passback' => '7', + 'roster' => '300', + ); foreach my $extra ('passback','roster') { - $datatable .= $lt{$extra}.' '. - '<label><input type="radio" name="ltitools_add_'.$extra.'" value="1" />'. - &mt('Yes').'</label>'.(' 'x2). - '<label><input type="radio" name="ltitools_add_'.$extra.'" value="0" checked="checked" />'. - &mt('No').'</label>'.(' 'x4); + my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"'; + $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.' '. + '<label><input type="radio" name="ltitools_'.$extra.'_add" value="0" checked="checked"'.$onclick.' />'. + &mt('No').'</label></span>'.(' 'x2).'<span class="LC_nobreak">'. + '<label><input type="radio" name="ltitools_'.$extra.'_add" value="1"'.$onclick.' />'. + &mt('Yes').'</label></span></div>'. + '<div class="LC_floatleft" style="display:none;" id="ltitools_'.$extra.'time_add">'. + '<span class="LC_nobreak">'. + &mt("at least [_1] $units{$extra} after launch", + '<input type="text" name="ltitools_'.$extra.'valid_add" value="'.$defaulttimes{$extra}.'" />'). + '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>'; } - $datatable .= '<br /><br /><span class="LC_nobreak">'.$lt{'icon'}.': '. + $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': '. '('.&mt('if larger than 21x21 pixels, image will be scaled').') '; if ($switchserver) { $datatable .= &mt('Upload to library server: [_1]',$switchserver); @@ -3971,15 +4657,29 @@ sub print_ltitools { '<fieldset><legend>'.&mt('User data sent on launch').'</legend>'. '<span class="LC_nobreak">'; foreach my $field (@fields) { + my ($id,$onclick,$spacer); + if ($field eq 'user') { + $id = ' id="ltitools_user_field_add"'; + $onclick = ' onclick="toggleLTITools(this.form,'."'$field','add'".')"'; + } else { + $spacer = (' ' x2); + } $datatable .= '<label>'. - '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'" />'. - $lt{$field}.'</label>'.(' ' x2); + '<input type="checkbox" name="ltitools_add_fields" value="'.$field.'"'.$id.$onclick.' />'. + $lt{$field}.'</label>'.$spacer; } - $datatable .= '</span></fieldset>'. - '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>'; + $datatable .= '</span>'. + '<div style="display:none;" id="ltitools_user_div_add">'. + '<span class="LC_nobreak"> : '. + '<select name="ltitools_userincdom_add">'. + '<option value="" selected="selected">'.&mt('Select').'</option>'. + '<option value="0">'.&mt('username').'</option>'. + '<option value="1">'.&mt('username:domain').'</option>'. + '</select></span></div></fieldset>'; + $datatable .= '<fieldset><legend>'.&mt('Role mapping').'</legend><table><tr>'; foreach my $role (@courseroles) { my ($checked,$checkednone); - $datatable .= '<td align="center">'. + $datatable .= '<td style="text-align: center">'. &Apache::lonnet::plaintext($role,'Course').'<br />'. '<select name="ltitools_add_roles_'.$role.'">'. '<option value="" selected="selected">'.&mt('Select').'</option>'; @@ -3990,7 +4690,7 @@ sub print_ltitools { } $datatable .= '</tr></table></fieldset>'. '<fieldset><legend>'.&mt('Configurable in course').'</legend><span class="LC_nobreak">'; - foreach my $item ('label','title','target','linktext','explanation') { + foreach my $item ('label','title','target','linktext','explanation','append') { $datatable .= '<label>'. '<input type="checkbox" name="ltitools_courseconfig" value="'.$item.'" checked="checked" />'. $lt{'crs'.$item}.'</label>'.(' ' x2)."\n"; @@ -4002,7 +4702,7 @@ sub print_ltitools { '<label><input type="checkbox" name="ltitools_add_custom" value="1" />'. &mt('Add').'</label></span></td><td><input type="text" name="ltitools_add_custom_name" />'. '</td><td><input type="text" name="ltitools_add_custom_value" /></td></tr>'. - '</table></fieldset></td></tr>'."\n". + '</table></fieldset>'."\n". '</td>'."\n". '</tr>'."\n"; $itemcount ++; @@ -4014,17 +4714,20 @@ sub ltitools_names { 'title' => 'Title', 'version' => 'Version', 'msgtype' => 'Message Type', + 'sigmethod' => 'Signature Method', 'url' => 'URL', 'key' => 'Key', + 'lifetime' => 'Nonce lifetime (s)', 'secret' => 'Secret', 'icon' => 'Icon', - 'user' => 'Username:domain', + 'user' => 'User', 'fullname' => 'Full Name', 'firstname' => 'First Name', 'lastname' => 'Last Name', 'email' => 'E-mail', 'roles' => 'Role', - 'window' => 'Window/Tab', + 'window' => 'Window', + 'tab' => 'Tab', 'iframe' => 'iFrame', 'height' => 'Height', 'width' => 'Width', @@ -4037,10 +4740,468 @@ sub ltitools_names { 'crstitle' => 'Course title', 'crslinktext' => 'Link Text', 'crsexplanation' => 'Explanation', + 'crsappend' => 'Provider URL', + ); + return %lt; +} + +sub print_lti { + my ($dom,$settings,$rowtotal) = @_; + my $itemcount = 1; + my $maxnum = 0; + my $css_class; + my %ordered; + if (ref($settings) eq 'HASH') { + foreach my $item (keys(%{$settings})) { + if (ref($settings->{$item}) eq 'HASH') { + my $num = $settings->{$item}{'order'}; + $ordered{$num} = $item; + } + } + } + my $maxnum = scalar(keys(%ordered)); + my $datatable; + my %lt = <i_names(); + if (keys(%ordered)) { + my @items = sort { $a <=> $b } keys(%ordered); + for (my $i=0; $i<@items; $i++) { + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $item = $ordered{$items[$i]}; + my ($key,$secret,$lifetime,$consumer,$current); + if (ref($settings->{$item}) eq 'HASH') { + $key = $settings->{$item}->{'key'}; + $secret = $settings->{$item}->{'secret'}; + $lifetime = $settings->{$item}->{'lifetime'}; + $consumer = $settings->{$item}->{'consumer'}; + $current = $settings->{$item}; + } + my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_".$item."'".');"'; + $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' + .'<select name="lti_pos_'.$item.'"'.$chgstr.'>'; + for (my $k=0; $k<=$maxnum; $k++) { + my $vpos = $k+1; + my $selstr; + if ($k == $i) { + $selstr = ' selected="selected" '; + } + $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; + } + $datatable .= '</select>'.(' 'x2). + '<label><input type="checkbox" name="lti_del" value="'.$item.'" />'. + &mt('Delete?').'</label></span></td>'. + '<td colspan="2">'. + '<fieldset><legend>'.&mt('Required settings').'</legend>'. + '<span class="LC_nobreak">'.$lt{'consumer'}. + ':<input type="text" size="20" name="lti_consumer_'.$i.'" value="'.$consumer.'" /></span> '. + (' 'x2). + '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_'.$i.'">'. + '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '. + (' 'x2). + '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="lti_lifetime_'.$i.'"'. + 'value="'.$lifetime.'" size="5" /></span>'. + '<br /><br />'. + '<span class="LC_nobreak">'.$lt{'key'}. + ':<input type="text" size="25" name="lti_key_'.$i.'" value="'.$key.'" /></span> '. + (' 'x2). + '<span class="LC_nobreak">'.$lt{'secret'}.':'. + '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'. + '<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>'. + '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'. + '</fieldset>'.<i_options($i,$current,$itemcount,%lt).'</td></tr>'; + $itemcount ++; + } + } + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $chgstr = ' onchange="javascript:reorderLTI(this.form,'."'lti_pos_add'".');"'; + $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". + '<input type="hidden" name="lti_maxnum" value="'.$maxnum.'" />'."\n". + '<select name="lti_pos_add"'.$chgstr.'>'; + for (my $k=0; $k<$maxnum+1; $k++) { + my $vpos = $k+1; + my $selstr; + if ($k == $maxnum) { + $selstr = ' selected="selected" '; + } + $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; + } + $datatable .= '</select> '."\n". + '<input type="checkbox" name="lti_add" value="1" />'.&mt('Add').'</span></td>'."\n". + '<td colspan="2">'. + '<fieldset><legend>'.&mt('Required settings').'</legend>'. + '<span class="LC_nobreak">'.$lt{'consumer'}. + ':<input type="text" size="20" name="lti_consumer_add" value="" /></span> '."\n". + (' 'x2). + '<span class="LC_nobreak">'.$lt{'version'}.':<select name="lti_version_add">'. + '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n". + (' 'x2). + '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="lti_lifetime_add" value="300" /></span> '."\n". + '<br /><br />'. + '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="lti_key_add" value="" /></span> '."\n". + (' 'x2). + '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'. + '<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". + '</fieldset>'.<i_options('add',undef,$itemcount,%lt). + '</td>'."\n". + '</tr>'."\n"; + $$rowtotal ++; + return $datatable;; +} + +sub lti_names { + my %lt = &Apache::lonlocal::texthash( + 'version' => 'LTI Version', + 'url' => 'URL', + 'key' => 'Key', + 'lifetime' => 'Nonce lifetime (s)', + 'consumer' => 'LTI Consumer', + 'secret' => 'Secret', + 'email' => 'Email address', + 'sourcedid' => 'User ID', + 'other' => 'Other', + 'passback' => 'Can return grades to Consumer:', + 'roster' => 'Can retrieve roster from Consumer:', + 'topmenu' => 'Display LON-CAPA page header', + 'inlinemenu'=> 'Display LON-CAPA inline menu', ); return %lt; } +sub lti_options { + my ($num,$current,$itemcount,%lt) = @_; + my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield); + $checked{'mapuser'}{'sourcedid'} = ' checked="checked"'; + $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"'; + $checked{'makecrs'}{'N'} = ' checked="checked"'; + $checked{'mapcrstype'} = {}; + $checked{'makeuser'} = {}; + $checked{'selfenroll'} = {}; + $checked{'crssec'} = {}; + $checked{'crssecsrc'} = {}; + $checked{'lcauth'} = {}; + $checked{'menuitem'} = {}; + if ($num eq 'add') { + $checked{'lcauth'}{'lti'} = ' checked="checked"'; + } + my $userfieldsty = 'none'; + my $crsfieldsty = 'none'; + my $crssecfieldsty = 'none'; + my $secsrcfieldsty = 'none'; + my $passbacksty = 'none'; + my $lcauthparm; + my $lcauthparmstyle = 'display:none'; + my $lcauthparmtext; + my $menusty; + my $numinrow = 4; + my %menutitles = <imenu_titles(); + + if (ref($current) eq 'HASH') { + if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) { + $checked{'mapuser'}{'sourcedid'} = ''; + if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') { + $checked{'mapuser'}{'email'} = ' checked="checked"'; + } else { + $checked{'mapuser'}{'other'} = ' checked="checked"'; + $userfield = $current->{'mapuser'}; + $userfieldsty = 'inline-block'; + } + } + if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) { + $checked{'mapcrs'}{'course_offering_sourcedid'} = ''; + if ($current->{'mapcrs'} eq 'context_id') { + $checked{'mapcrs'}{'context_id'} = ' checked="checked"'; + } else { + $checked{'mapcrs'}{'other'} = ' checked="checked"'; + $cidfield = $current->{'mapcrs'}; + $crsfieldsty = 'inline-block'; + } + } + if (ref($current->{'mapcrstype'}) eq 'ARRAY') { + foreach my $type (@{$current->{'mapcrstype'}}) { + $checked{'mapcrstype'}{$type} = ' checked="checked"'; + } + } + if ($current->{'makecrs'}) { + $checked{'makecrs'}{'Y'} = ' checked="checked"'; + } + if (ref($current->{'makeuser'}) eq 'ARRAY') { + foreach my $role (@{$current->{'makeuser'}}) { + $checked{'makeuser'}{$role} = ' checked="checked"'; + } + } + if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) { + $checked{'lcauth'}{$1} = ' checked="checked"'; + unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) { + $lcauthparm = $current->{'lcauthparm'}; + $lcauthparmstyle = 'display:table-row'; + if ($current->{'lcauth'} eq 'localauth') { + $lcauthparmtext = &mt('Local auth argument'); + } else { + $lcauthparmtext = &mt('Kerberos domain'); + } + } + } + if (ref($current->{'selfenroll'}) eq 'ARRAY') { + foreach my $role (@{$current->{'selfenroll'}}) { + $checked{'selfenroll'}{$role} = ' checked="checked"'; + } + } + if (ref($current->{'maproles'}) eq 'HASH') { + %rolemaps = %{$current->{'maproles'}}; + } + if ($current->{'section'} ne '') { + $checked{'crssec'}{'Y'} = ' checked="checked"'; + $crssecfieldsty = 'inline-block'; + if ($current->{'section'} eq 'course_section_sourcedid') { + $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"'; + } else { + $checked{'crssecsrc'}{'other'} = ' checked="checked"'; + $crssecsrc = $current->{'section'}; + $secsrcfieldsty = 'inline-block'; + } + } else { + $checked{'crssec'}{'N'} = ' checked="checked"'; + } + if ($current->{'topmenu'}) { + $checked{'topmenu'}{'Y'} = ' checked="checked"'; + } else { + $checked{'topmenu'}{'N'} = ' checked="checked"'; + } + if ($current->{'inlinemenu'}) { + $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; + } else { + $checked{'inlinemenu'}{'N'} = ' checked="checked"'; + } + if (($current->{'topmenu'}) || ($current->{'inlinemenu'})) { + $menusty = 'inline-block'; + if (ref($current->{'lcmenu'}) eq 'ARRAY') { + foreach my $item (@{$current->{'lcmenu'}}) { + if (exists($menutitles{$item})) { + $checked{'menuitem'}{$item} = ' checked="checked"'; + } + } + } + } else { + $menusty = 'none'; + } + } else { + $checked{'makecrs'}{'N'} = ' checked="checked"'; + $checked{'crssec'}{'N'} = ' checked="checked"'; + $checked{'topmenu'}{'N'} = ' checked="checked"'; + $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; + $checked{'menuitem'}{'grades'} = ' checked="checked"'; + $menusty = 'inline-block'; + } + my @coursetypes = ('official','unofficial','community','textbook','placement','lti'); + my %coursetypetitles = &Apache::lonlocal::texthash ( + official => 'Official', + unofficial => 'Unofficial', + community => 'Community', + textbook => 'Textbook', + placement => 'Placement Test', + lti => 'LTI Provider', + ); + my @authtypes = ('internal','krb4','krb5','localauth'); + my %shortauth = ( + internal => 'int', + krb4 => 'krb4', + krb5 => 'krb5', + localauth => 'loc' + ); + my %authnames = &authtype_names(); + my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator); + my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor); + my @courseroles = ('cc','in','ta','ep','st'); + my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"'; + my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"'; + my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"'; + my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"'; + my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"'; + my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"'; + my $output = '<fieldset><legend>'.&mt('Mapping users').'</legend>'. + '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').': '; + foreach my $option ('sourcedid','email','other') { + $output .= '<label><input type="radio" name="lti_mapuser_'.$num.'" value="'.$option.'"'. + $checked{'mapuser'}{$option}.$onclickuser.' />'.$lt{$option}.'</label>'. + ($option eq 'other' ? '' : (' 'x2) ); + } + $output .= '</span></div>'. + '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="lti_userfield_'.$num.'">'. + '<input type="text" name="lti_customuser_'.$num.'" '. + 'value="'.$userfield.'" /></div></fieldset>'. + '<fieldset><legend>'.&mt('Mapping course roles').'</legend><table><tr>'; + foreach my $ltirole (@lticourseroles) { + my ($selected,$selectnone); + if ($rolemaps{$ltirole} eq '') { + $selectnone = ' selected="selected"'; + } + $output .= '<td style="text-align: center">'.$ltirole.'<br />'. + '<select name="lti_maprole_'.$ltirole.'_'.$num.'">'. + '<option value=""'.$selectnone.'>'.&mt('Select').'</option>'; + foreach my $role (@courseroles) { + unless ($selectnone) { + if ($rolemaps{$ltirole} eq $role) { + $selected = ' selected="selected"'; + } else { + $selected = ''; + } + } + $output .= '<option value="'.$role.'"'.$selected.'>'. + &Apache::lonnet::plaintext($role,'Course'). + '</option>'; + } + $output .= '</select></td>'; + } + $output .= '</tr></table></fieldset>'. + '<fieldset><legend>'.&mt('Roles which may create user accounts').'</legend>'; + foreach my $ltirole (@ltiroles) { + $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_makeuser_'.$num.'" value="'.$ltirole.'"'. + $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label> </span> '; + } + $output .= '</fieldset>'. + '<fieldset><legend>'.&mt('New user accounts created for LTI users').'</legend>'. + '<table>'. + &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount). + '</table>'. + '<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'. + '<td class="LC_left_item">'; + foreach my $auth ('lti',@authtypes) { + my $authtext; + if ($auth eq 'lti') { + $authtext = &mt('None'); + } else { + $authtext = $authnames{$shortauth{$auth}}; + } + $output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num. + '" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'. + $authtext.'</label></span> '; + } + $output .= '</td></tr>'. + '<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'. + '<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'. + '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'. + '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'. + '</table></fieldset>'. + '<fieldset><legend>'.&mt('Mapping courses').'</legend>'. + '<div class="LC_floatleft"><span class="LC_nobreak">'. + &mt('Unique course identifier').': '; + foreach my $option ('course_offering_sourcedid','context_id','other') { + $output .= '<label><input type="radio" name="lti_mapcrs_'.$num.'" value="'.$option.'"'. + $checked{'mapcrs'}{$option}.$onclickcrs.' />'.$option.'</label>'. + ($option eq 'other' ? '' : (' 'x2) ); + } + $output .= '</span></div><div class="LC_floatleft" style="display:'.$crsfieldsty.';" id="lti_crsfield_'.$num.'">'. + '<input type="text" name="lti_mapcrsfield_'.$num.'" value="'.$cidfield.'" />'. + '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'. + '<span class="LC_nobreak">'.&mt('LON-CAPA course type(s)').': '; + foreach my $type (@coursetypes) { + $output .= '<label><input type="checkbox" name="lti_mapcrstype_'.$num.'" value="'.$type.'"'. + $checked{'mapcrstype'}{$type}.' />'.$coursetypetitles{$type}.'</label>'. + (' 'x2); + } + $output .= '</span></fieldset>'. + '<fieldset><legend>'.&mt('Creating courses').'</legend>'. + '<span class="LC_nobreak">'.&mt('Course created (if absent) on Instructor access').': '. + '<label><input type="radio" name="lti_makecrs_'.$num.'" value="0"'. + $checked{'makecrs'}{'N'}.' />'.&mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_makecrs_'.$num.'" value="1"'. + $checked{'makecrs'}{'Y'}.' />'.&mt('Yes').'</label></span>'. + '</fieldset>'. + '<fieldset><legend>'.&mt('Roles which may self-enroll').'</legend>'; + foreach my $lticrsrole (@lticourseroles) { + $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="lti_selfenroll_'.$num.'" value="'.$lticrsrole.'"'. + $checked{'selfenroll'}{$lticrsrole}.' />'.$lticrsrole.'</label> </span> '; + } + $output .= '</fieldset>'. + '<fieldset><legend>'.&mt('Course options').'</legend>'. + '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Assign users to sections').': '. + '<label><input type="radio" name="lti_crssec_'.$num.'" value="0"'. + $checked{'crssec'}{'N'}.$onclicksec.' />'.&mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_crssec_'.$num.'" value="1"'. + $checked{'crssec'}{'Y'}.$onclicksec.' />'.&mt('Yes').'</label></span></div>'. + '<div class="LC_floatleft" style="display:'.$crssecfieldsty.';" id="lti_crssecfield_'.$num.'">'. + '<span class="LC_nobreak">'.&mt('From').':<label>'. + '<input type="radio" name="lti_crssecsrc_'.$num.'" value="course_section_sourcedid"'. + $checked{'crssecsrc'}{'sourcedid'}.$onclicksecsrc.' />'. + &mt('Standard field').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_crssecsrc_'.$num.'" value="other"'. + $checked{'crssecsrc'}{'other'}.$onclicksecsrc.' />'.&mt('Other'). + '</label></span></div><div class="LC_floatleft" style="display:'.$secsrcfieldsty.';" id="lti_secsrcfield_'.$num.'">'. + '<input type="text" name="lti_customsection_'.$num.'" value="'.$crssecsrc.'" />'. + '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'; + my ($pb1p1chk,$pb1p0chk,$onclickpb); + foreach my $extra ('roster','passback') { + my $checkedon = ''; + my $checkedoff = ' checked="checked"'; + if ($extra eq 'passback') { + $pb1p1chk = ' checked="checked"'; + $pb1p0chk = ''; + $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"'; + } else { + $onclickpb = ''; + } + if (ref($current) eq 'HASH') { + if (($current->{$extra})) { + $checkedon = $checkedoff; + $checkedoff = ''; + if ($extra eq 'passback') { + $passbacksty = 'inline-block'; + } + if ($current->{'passbackformat'} eq '1.0') { + $pb1p0chk = ' checked="checked"'; + $pb1p1chk = ''; + } + } + } + $output .= $lt{$extra}.' '. + '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="0"'.$checkedoff.$onclickpb.' />'. + &mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_'.$extra.'_'.$num.'" value="1"'.$checkedon.$onclickpb.' />'. + &mt('Yes').'</label><br />'; + } + $output .= '<div class="LC_floatleft" style="display:'.$passbacksty.';" id="lti_passback_'.$num.'">'. + '<span class="LC_nobreak">'.&mt('Grade format'). + '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'. + &mt('Outcomes Service (1.1)').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'. + &mt('Outcomes Extension (1.0)').'</label></span></div></fieldset>'. + '<fieldset><legend>'.&mt('Course defaults (Course Coordinator can override)').'</legend>'. + '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.': '. + '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'. + $checked{'topmenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_topmenu_'.$num.'" value="1"'. + $checked{'topmenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'. + '<div style="padding:0;clear:both;margin:0;border:0"></div>'. + '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'inlinemenu'}.': '. + '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="0"'. + $checked{'inlinemenu'}{'N'}.$onclickmenu.' />'.&mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="lti_inlinemenu_'.$num.'" value="1"'. + $checked{'inlinemenu'}{'Y'}.$onclickmenu.' />'.&mt('Yes').'</label></span></div>'; + $output .='<div style="padding:0;clear:both;margin:0;border:0"></div>'. + '<div class="LC_floatleft" style="display:'.$menusty.';" id="lti_menufield_'.$num.'">'. + '<span class="LC_nobreak">'.&mt('Menu items').': '; + foreach my $type ('fullname','coursetitle','role','logout','grades') { + $output .= '<label><input type="checkbox" name="lti_menuitem_'.$num.'" value="'.$type.'"'. + $checked{'menuitem'}{$type}.' />'.$menutitles{$type}.'</label>'. + (' 'x2); + } + $output .= '</span></div></fieldset>'; +# '<fieldset><legend>'.&mt('Assigning author roles').'</legend>'; +# +# $output .= '</fieldset>'. +# '<fieldset><legend>'.&mt('Assigning domain roles').'</legend>'; + return $output; +} + +sub ltimenu_titles { + return &Apache::lonlocal::texthash( + fullname => 'Full name', + coursetitle => 'Course title', + role => 'Role', + logout => 'Logout', + grades => 'Grades', + ); +} + sub print_coursedefaults { my ($position,$dom,$settings,$rowtotal) = @_; my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles); @@ -4052,11 +5213,13 @@ sub print_coursedefaults { coursecredits => 'Credits can be specified for courses', uselcmath => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)', usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)', + texengine => 'Default method to display mathematics', postsubmit => 'Disable submit button/keypress following student submission', canclone => "People who may clone a course (besides course's owner and coordinators)", mysqltables => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver', ); my %staticdefaults = ( + texengine => 'MathJax', anonsurvey_threshold => 10, uploadquota => 500, postsubmit => 60, @@ -4070,11 +5233,39 @@ sub print_coursedefaults { 'canclone' => 'none', ); @toggles = ('canuse_pdfforms','uselcmath','usejsme'); + my $deftex = $staticdefaults{'texengine'}; + if (ref($settings) eq 'HASH') { + if ($settings->{'texengine'}) { + if ($settings->{'texengine'} =~ /^(MathJax|mimetex|tth)$/) { + $deftex = $settings->{'texengine'}; + } + } + } + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $mathdisp = '<tr'.$css_class.'><td style="vertical-align: top">'. + '<span class="LC_nobreak">'.$choices{'texengine'}. + '</span></td><td class="LC_right_item">'. + '<select name="texengine">'."\n"; + my %texoptions = ( + MathJax => 'MathJax', + mimetex => &mt('Convert to Images'), + tth => &mt('TeX to HTML'), + ); + foreach my $renderer ('MathJax','mimetex','tth') { + my $selected = ''; + if ($renderer eq $deftex) { + $selected = ' selected="selected"'; + } + $mathdisp .= '<option value="'.$renderer.'"'.$selected.'>'.$texoptions{$renderer}.'</option>'."\n"; + } + $mathdisp .= '</select></td></tr>'."\n"; + $itemcount ++; ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, \%choices,$itemcount); + $datatable = $mathdisp.$datatable; $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= - '<tr'.$css_class.'><td valign="top">'. + '<tr'.$css_class.'><td style="vertical-align: top">'. '<span class="LC_nobreak">'.$choices{'canclone'}. '</span></td><td class="LC_left_item">'; my $currcanclone = 'none'; @@ -4118,7 +5309,7 @@ sub print_coursedefaults { if ($checked) { $show = 'block'; } - $additional = '<div id="cloneinstcode" style="display:'.$show.'" />'. + $additional = '<div id="cloneinstcode" style="display:'.$show.';" />'. &mt('Institutional codes for new and cloned course have identical:'). '<br />'; foreach my $item (@code_order) { @@ -4226,10 +5417,10 @@ sub print_coursedefaults { $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'. $choices{'uploadquota'}. '</span></td>'. - '<td align="right" class="LC_right_item">'. + '<td style="text-align: right" class="LC_right_item">'. '<table><tr>'; foreach my $type (@types) { - $datatable .= '<td align="center">'.&mt($type).'<br />'. + $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'. '<input type="text" name="uploadquota_'.$type.'"'. ' value="'.$curruploadquota{$type}.'" size="5" /></td>'; } @@ -4244,7 +5435,7 @@ sub print_coursedefaults { '<i>'.&mt('Default credits').'</i><br /><table><tr>'; foreach my $type (@types) { next if ($type eq 'community'); - $additional .= '<td align="center">'.&mt($type).'<br />'. + $additional .= '<td style="text-align: center">'.&mt($type).'<br />'. '<input type="text" name="'.$type.'_credits"'. ' value="'.$defcredits{$type}.'" size="3" /></td>'; } @@ -4268,7 +5459,7 @@ sub print_coursedefaults { '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'. '<table><tr>'; foreach my $type (@types) { - $additional .= '<td align="center">'.&mt($type).'<br />'. + $additional .= '<td style="text-align: center">'.&mt($type).'<br />'. '<input type="text" name="'.$type.'_timeout" value="'. $deftimeout{$type}.'" size="5" /></td>'; } @@ -4286,10 +5477,10 @@ sub print_coursedefaults { $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'. $choices{'mysqltables'}. '</span></td>'. - '<td align="right" class="LC_right_item">'. + '<td style="text-align: right" class="LC_right_item">'. '<table><tr>'; foreach my $type (@types) { - $datatable .= '<td align="center">'.&mt($type).'<br />'. + $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'. '<input type="text" name="mysqltables_'.$type.'"'. ' value="'.$currmysql{$type}.'" size="8" /></td>'; } @@ -4489,7 +5680,7 @@ sub print_validation_rows { '</label></span> '; } } elsif ($item eq 'markup') { - $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5" wrap="soft">'. + $datatable .= '<textarea name="'.$caller.'_validation_markup" cols="50" rows="5">'. $currvalidation{$item}. '</textarea>'; } @@ -4511,7 +5702,7 @@ sub print_validation_rows { my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio', 'validationdc',%currhash); my $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; - $datatable .= '</td></tr><tr'.$css_class.'><td>'; + $datatable .= '<tr'.$css_class.'><td>'; if ($numdc > 1) { $datatable .= &mt('Course creation processed as: (choose Dom. Coord.)'); } else { @@ -5148,13 +6339,13 @@ sub print_loadbalancing { my $numinrow = 1; my $datatable; my %servers = &Apache::lonnet::internet_dom_servers($dom); - my (%currbalancer,%currtargets,%currrules,%existing); + my (%currbalancer,%currtargets,%currrules,%existing,%currcookies); if (ref($settings) eq 'HASH') { %existing = %{$settings}; } if ((keys(%servers) > 1) || (keys(%existing) > 0)) { &get_loadbalancers_config(\%servers,\%existing,\%currbalancer, - \%currtargets,\%currrules); + \%currtargets,\%currrules,\%currcookies); } else { return; } @@ -5188,7 +6379,7 @@ sub print_loadbalancing { my $disabled_div_style = 'display: block'; my $homedom_div_style = 'display: none'; $datatable .= '<tr class="'.$css_class[$cssidx].'">'. - '<td rowspan="'.$rownum.'" valign="top">'. + '<td rowspan="'.$rownum.'" style="vertical-align: top">'. '<p>'; if ($lonhost eq '') { $datatable .= '<span class="LC_nobreak">'; @@ -5221,7 +6412,7 @@ sub print_loadbalancing { $homedom_div_style = 'display: block'; } } - $datatable .= '</p></td><td rowspan="'.$rownum.'" valign="top">'. + $datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'. '<div id="loadbalancing_disabled_'.$balnum.'" style="'. $disabled_div_style.'">'.$disabledtext.'</div>'."\n". '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />'; @@ -5231,6 +6422,9 @@ sub print_loadbalancing { my %hostherechecked = ( no => ' checked="checked"', ); + my %balcookiechecked = ( + no => ' checked="checked"', + ); foreach my $sparetype (@sparestypes) { my $targettable; for (my $i=0; $i<$numspares; $i++) { @@ -5286,6 +6480,11 @@ sub print_loadbalancing { } } } + if ($currcookies{$lonhost}) { + %balcookiechecked = ( + yes => ' checked="checked"', + ); + } $datatable .= &mt('Hosting on balancer itself').'<br />'. '<label><input type="radio" name="loadbalancing_target_'.$balnum.'_hosthere" value="no"'. $hostherechecked{'no'}.' />'.&mt('No').'</label><br />'; @@ -5294,7 +6493,12 @@ sub print_loadbalancing { 'value="'.$sparetype.'"'.$hostherechecked{$sparetype}.' /><i>'.$typetitles{$sparetype}. '</i></label><br />'; } - $datatable .= '</div></td></tr>'. + $datatable .= &mt('Use balancer cookie').'<br />'. + '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="1"'. + $balcookiechecked{'yes'}.' />'.&mt('Yes').'</label><br />'. + '<label><input type="radio" name="loadbalancing_cookie_'.$balnum.'" value="0"'. + $balcookiechecked{'no'}.' />'.&mt('No').'</label><br />'. + '</div></td></tr>'. &loadbalancing_rules($dom,$intdom,$currrules{$lonhost}, $othertitle,$usertypes,$types,\%servers, \%currbalancer,$lonhost, @@ -5308,10 +6512,11 @@ sub print_loadbalancing { } sub get_loadbalancers_config { - my ($servers,$existing,$currbalancer,$currtargets,$currrules) = @_; + my ($servers,$existing,$currbalancer,$currtargets,$currrules,$currcookies) = @_; return unless ((ref($servers) eq 'HASH') && (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') && - (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH')); + (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH') && + (ref($currcookies) eq 'HASH')); if (keys(%{$existing}) > 0) { my $oldlonhost; foreach my $key (sort(keys(%{$existing}))) { @@ -5330,6 +6535,9 @@ sub get_loadbalancers_config { $currbalancer->{$key} = 1; $currtargets->{$key} = $existing->{$key}{'targets'}; $currrules->{$key} = $existing->{$key}{'rules'}; + if ($existing->{$key}{'cookie'}) { + $currcookies->{$key} = 1; + } } } } else { @@ -5385,9 +6593,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_/) { @@ -5428,10 +6641,10 @@ sub loadbalance_rule_row { } my $space; if ($islast && $num == 1) { - $space = '<div display="inline-block"> </div>'; + $space = '<div style="display:inline-block;"> </div>'; } my $output = - '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space. + '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td style="vertical-align: top">'.$space. '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n". '<td valaign="top">'.$space. '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n"; @@ -5514,12 +6727,16 @@ 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', 'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID', + 'errorthreshold' => 'Error/warning threshold for status e-mail', + 'errorsysmail' => 'Error threshold for e-mail to core group', + 'errorweights' => 'Weights used to compute error count', + 'errorexcluded' => 'Servers with unsent updates excluded from count', ); my %short_titles = &Apache::lonlocal::texthash ( adminemail => 'Admin E-mail address', @@ -5578,8 +6795,9 @@ sub courserequest_titles { community => 'Communities', textbook => 'Textbook', placement => 'Placement tests', + lti => 'LTI Provider', norequest => 'Not allowed', - approval => 'Approval by Dom. Coord.', + approval => 'Approval by DC', validate => 'With validation', autolimit => 'Numerical limit', unlimited => '(blank for unlimited)', @@ -5668,7 +6886,7 @@ sub print_usercreation { } $datatable .= '<tr'.$css_class.'>'. '<td><span class="LC_nobreak">'.$lt{$item}. - '</span></td><td align="right">'; + '</span></td><td style="text-align: right">'; my @options = ('any'); if (ref($rules) eq 'HASH') { if (keys(%{$rules}) > 0) { @@ -5691,7 +6909,7 @@ sub print_usercreation { } } else { my @contexts = ('author','course','domain'); - my @authtypes = ('int','krb4','krb5','loc'); + my @authtypes = ('int','krb4','krb5','loc','lti'); my %checked; if (ref($settings) eq 'HASH') { if (ref($settings->{'authtypes'}) eq 'HASH') { @@ -5742,7 +6960,8 @@ sub print_usercreation { sub print_selfcreation { my ($position,$dom,$settings,$rowtotal) = @_; - my (@selfcreate,$createsettings,$processing,$datatable); + my (@selfcreate,$createsettings,$processing,$emailoptions,$emailverified, + $emaildomain,$datatable); if (ref($settings) eq 'HASH') { if (ref($settings->{'cancreate'}) eq 'HASH') { $createsettings = $settings->{'cancreate'}; @@ -5759,12 +6978,22 @@ sub print_selfcreation { if (ref($createsettings->{'selfcreateprocessing'}) eq 'HASH') { $processing = $createsettings->{'selfcreateprocessing'}; } + if (ref($createsettings->{'emailoptions'}) eq 'HASH') { + $emailoptions = $createsettings->{'emailoptions'}; + } + if (ref($createsettings->{'emailverified'}) eq 'HASH') { + $emailverified = $createsettings->{'emailverified'}; + } + if (ref($createsettings->{'emaildomain'}) eq 'HASH') { + $emaildomain = $createsettings->{'emaildomain'}; + } } } } my %radiohash; my $numinrow = 4; map { $radiohash{'cancreate_'.$_} = 1; } @selfcreate; + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); if ($position eq 'top') { my %choices = &Apache::lonlocal::texthash ( cancreate_login => 'Institutional Login', @@ -5780,13 +7009,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 ++; } } @@ -5799,7 +7026,7 @@ sub print_selfcreation { $datatable .= '<tr'.$css_class.'>'. '<td class="LC_left_item">'.&mt('Mapping of Shibboleth environment variable names to user data fields (SSO auth)').'</td>'. '<td class="LC_left_item">'."\n". - '<table><tr><td>'."\n"; + '<table>'."\n"; for (my $i=0; $i<@fields; $i++) { $rem = $i%($numperrow); if ($rem == 0) { @@ -5831,142 +7058,418 @@ 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 ( - cancreate_email => 'E-mail address as username', + 'cancreate_email' => 'Non-institutional username (via e-mail verification)', ); my @toggles = sort(keys(%choices)); my %defaultchecked = ( 'cancreate_email' => 'off', ); - my $itemcount = 0; + my $customclass = 'LC_selfcreate_email'; + my $classprefix = 'LC_canmodify_emailusername_'; + my $optionsprefix = 'LC_options_emailusername_'; my $display = 'none'; + my $rowstyle = 'display:none'; if (grep(/^\Qemail\E$/,@selfcreate)) { $display = 'block'; + $rowstyle = 'display:table-row'; } - my $onclick = "toggleDisplay(this.form,'emailoptions');"; - my $additional = '<div id="emailoptions" style="display: '.$display.'">'; + my $onclick = "toggleRows(this.form,'cancreate_email','selfassign','$customclass','$classprefix','$optionsprefix');"; + ($datatable,$$rowtotal) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked, + \%choices,$$rowtotal,$onclick); + $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal,$customclass, + $rowstyle); + $$rowtotal ++; + $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal,$customclass, + $rowstyle); + $$rowtotal ++; + my (@ordered,@posstypes,%usertypeshash); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); - my $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 .= '<table><tr>'; - foreach my $status (@{$order}) { - $additional .= '<th>'.$usertypes->{$status}.'</th>'; - } - $additional .= '</tr><tr>'; - foreach my $status (@{$order}) { - $additional .= '<td>'.&email_as_username($rowtotal,$processing,$status).'</td>'; + my ($emailrules,$emailruleorder) = + &Apache::lonnet::inst_userrules($dom,'email'); + my $primary_id = &Apache::lonnet::domain($dom,'primary'); + my $intdom = &Apache::lonnet::internet_dom($primary_id); + if (ref($types) eq 'ARRAY') { + @posstypes = @{$types}; + } + if (@posstypes) { + unless (grep(/^default$/,@posstypes)) { + push(@posstypes,'default'); + } + if (ref($usertypes) eq 'HASH') { + %usertypeshash = %{$usertypes}; + } + my $currassign; + if (ref($domdefaults{'inststatusguest'}) eq 'ARRAY') { + $currassign = { + selfassign => $domdefaults{'inststatusguest'}, + }; + @ordered = @{$domdefaults{'inststatusguest'}}; + } else { + $currassign = { selfassign => [] }; + } + my $onclicktypes = "toggleDataRow(this.form,'selfassign','$customclass','$optionsprefix',);". + "toggleDataRow(this.form,'selfassign','$customclass','$classprefix',1);"; + $datatable .= &insttypes_row($currassign,$types,$usertypes,$dom, + $numinrow,$othertitle,'selfassign', + $rowtotal,$onclicktypes,$customclass, + $rowstyle); + $$rowtotal ++; + $usertypeshash{'default'} = $othertitle; + foreach my $status (@posstypes) { + my $css_class; + if ($$rowtotal%2) { + $css_class = 'LC_odd_row '; + } + $css_class .= $customclass; + my $rowid = $optionsprefix.$status; + my $hidden = 1; + my $currstyle = 'display:none'; + if (grep(/^\Q$status\E$/,@ordered)) { + $currstyle = $rowstyle; + $hidden = 0; + } + $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain, + $emailrules,$emailruleorder,$settings,$status,$rowid, + $usertypeshash{$status},$css_class,$currstyle,$intdom); + unless ($hidden) { + $$rowtotal ++; } - $additional .= '</tr></table>'; - } else { - $usertypes->{'default'} = &mt('All users'); - $additional .= &email_as_username($rowtotal,$processing); } + } else { + my $css_class; + if ($$rowtotal%2) { + $css_class = 'LC_odd_row '; + } + $css_class .= $customclass; + $usertypeshash{'default'} = $othertitle; + $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain, + $emailrules,$emailruleorder,$settings,'default','', + $othertitle,$css_class,$rowstyle,$intdom); + $$rowtotal ++; } - $additional .= '</div>'."\n"; - - ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked, - \%choices,$$rowtotal,$onclick,$additional); - $$rowtotal ++; - $datatable .= &print_requestmail($dom,'selfcreation',$createsettings,$rowtotal); - $$rowtotal ++; my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info(); $numinrow = 1; - if (ref($order) eq 'ARRAY') { - foreach my $status (@{$order}) { + if (@posstypes) { + foreach my $status (@posstypes) { + my $rowid = $classprefix.$status; + my $datarowstyle = 'display:none'; + if (grep(/^\Q$status\E$/,@ordered)) { + $datarowstyle = $rowstyle; + } $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings, - $numinrow,$$rowtotal,$usertypes,$infofields,$infotitles); - $$rowtotal ++; + $numinrow,$$rowtotal,\%usertypeshash,$infofields, + $infotitles,$rowid,$customclass,$datarowstyle); + unless ($datarowstyle eq 'display:none') { + $$rowtotal ++; + } } + } else { + $datatable .= &modifiable_userdata_row('cancreate','emailusername_default',$settings, + $numinrow,$$rowtotal,\%usertypeshash,$infofields, + $infotitles,'',$customclass,$rowstyle); } - my ($emailrules,$emailruleorder) = - &Apache::lonnet::inst_userrules($dom,'email'); - if (ref($emailrules) eq 'HASH') { - if (keys(%{$emailrules}) > 0) { - $datatable .= &user_formats_row('email',$settings,$emailrules, - $emailruleorder,$numinrow,$$rowtotal); - $$rowtotal ++; + } + return $datatable; +} + +sub selfcreate_javascript { + return <<"ENDSCRIPT"; + +<script type="text/javascript"> +// <![CDATA[ + +function toggleRows(form,radio,checkbox,target,prefix,altprefix) { + var x = document.getElementsByClassName(target); + var insttypes = 0; + var insttypeRegExp = new RegExp(prefix); + if ((x.length != undefined) && (x.length > 0)) { + if (form.elements[radio].length != undefined) { + for (var i=0; i<form.elements[radio].length; i++) { + if (form.elements[radio][i].checked) { + if (form.elements[radio][i].value == 1) { + for (var j=0; j<x.length; j++) { + if (x[j].id == 'undefined') { + x[j].style.display = 'table-row'; + } else if (insttypeRegExp.test(x[j].id)) { + insttypes ++; + } else { + x[j].style.display = 'table-row'; + } + } + } else { + for (var j=0; j<x.length; j++) { + x[j].style.display = 'none'; + } + } + break; + } + } + if (insttypes > 0) { + toggleDataRow(form,checkbox,target,altprefix); + toggleDataRow(form,checkbox,target,prefix,1); } } - $datatable .= &captcha_choice('cancreate',$createsettings,$$rowtotal); } - return $datatable; + return; } -sub email_as_username { - my ($rowtotal,$processing,$type) = @_; - my %choices = - &Apache::lonlocal::texthash ( - automatic => 'Automatic approval', - approval => 'Queued for approval', - ); - my $output; - foreach my $option ('automatic','approval') { - my $checked; - if (ref($processing) eq 'HASH') { - if ($type eq '') { - if (!exists($processing->{'default'})) { - if ($option eq 'automatic') { - $checked = ' checked="checked"'; +function toggleDataRow(form,checkbox,target,prefix,docount) { + if (form.elements[checkbox].length != undefined) { + var count = 0; + if (docount) { + for (var i=0; i<form.elements[checkbox].length; i++) { + if (form.elements[checkbox][i].checked) { + count ++; + } + } + } + for (var i=0; i<form.elements[checkbox].length; i++) { + var type = form.elements[checkbox][i].value; + if (document.getElementById(prefix+type)) { + if (form.elements[checkbox][i].checked) { + document.getElementById(prefix+type).style.display = 'table-row'; + if (count % 2 == 1) { + document.getElementById(prefix+type).className = target+' LC_odd_row'; + } else { + document.getElementById(prefix+type).className = target; } + count ++; } else { - if ($processing->{'default'} eq $option) { - $checked = ' checked="checked"'; + document.getElementById(prefix+type).style.display = 'none'; + } + } + } + } + return; +} + +function toggleEmailOptions(form,radio,prefix,altprefix,status) { + var caller = radio+'_'+status; + if (form.elements[caller].length != undefined) { + for (var i=0; i<form.elements[caller].length; i++) { + if (form.elements[caller][i].checked) { + if (document.getElementById(altprefix+'_inst_'+status)) { + var curr = form.elements[caller][i].value; + if (prefix) { + document.getElementById(prefix+'_'+status).style.display = 'none'; + } + document.getElementById(altprefix+'_inst_'+status).style.display = 'none'; + document.getElementById(altprefix+'_noninst_'+status).style.display = 'none'; + if (curr == 'custom') { + if (prefix) { + document.getElementById(prefix+'_'+status).style.display = 'inline'; + } + } else if (curr == 'inst') { + document.getElementById(altprefix+'_inst_'+status).style.display = 'inline'; + } else if (curr == 'noninst') { + document.getElementById(altprefix+'_noninst_'+status).style.display = 'inline'; } + break; } - } else { - if (!exists($processing->{$type})) { - if ($option eq 'automatic') { - $checked = ' checked="checked"'; + } + } + } +} + +// ]]> +</script> + +ENDSCRIPT +} + +sub noninst_users { + my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules, + $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; + my $class = 'LC_left_item'; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowid) { + $rowid = ' id="'.$rowid.'"'; + } + if ($rowstyle) { + $rowstyle = ' style="'.$rowstyle.'"'; + } + my ($output,$description); + if ($type eq 'default') { + $description = &mt('Requests for: [_1]',$typetitle); + } else { + $description = &mt('Requests for: [_1] (status self-reported)',$typetitle); + } + $output = '<tr'.$css_class.$rowid.$rowstyle.'>'. + "<td>$description</td>\n". + '<td class="'.$class.'" colspan="2">'. + '<table><tr>'; + my %headers = &Apache::lonlocal::texthash( + approve => 'Processing', + email => 'E-mail', + username => 'Username', + ); + foreach my $item ('approve','email','username') { + $output .= '<th>'.$headers{$item}.'</th>'; + } + $output .= '</tr><tr>'; + foreach my $item ('approve','email','username') { + $output .= '<td style="vertical-align: top">'; + my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom); + if ($item eq 'approve') { + %choices = &Apache::lonlocal::texthash ( + automatic => 'Automatically approved', + approval => 'Queued for approval', + ); + @options = ('automatic','approval'); + $hashref = $processing; + $defoption = 'automatic'; + $name = 'cancreate_emailprocess_'.$type; + } elsif ($item eq 'email') { + %choices = &Apache::lonlocal::texthash ( + any => 'Any e-mail', + inst => 'Institutional only', + noninst => 'Non-institutional only', + custom => 'Custom restrictions', + ); + @options = ('any','inst','noninst'); + my $showcustom; + if (ref($emailrules) eq 'HASH') { + if (keys(%{$emailrules}) > 0) { + push(@options,'custom'); + $showcustom = 'cancreate_emailrule'; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'email_rule'}) eq 'ARRAY') { + foreach my $rule (@{$settings->{'email_rule'}}) { + if (exists($emailrules->{$rule})) { + $hascustom ++; + } + } + } elsif (ref($settings->{'email_rule'}) eq 'HASH') { + if (ref($settings->{'email_rule'}{$type}) eq 'ARRAY') { + foreach my $rule (@{$settings->{'email_rule'}{$type}}) { + if (exists($emailrules->{$rule})) { + $hascustom ++; + } + } + } + } + } + } + } + $onclick = ' onclick="toggleEmailOptions(this.form,'."'cancreate_emailoptions','$showcustom',". + "'cancreate_emaildomain','$type'".');"'; + $hashref = $emailoptions; + $defoption = 'any'; + $name = 'cancreate_emailoptions_'.$type; + } elsif ($item eq 'username') { + %choices = &Apache::lonlocal::texthash ( + all => 'Same as e-mail', + first => 'Omit @domain', + free => 'Free to choose', + ); + @options = ('all','first','free'); + $hashref = $emailverified; + $defoption = 'all'; + $name = 'cancreate_usernameoptions_'.$type; + } + foreach my $option (@options) { + my $checked; + if (ref($hashref) eq 'HASH') { + if ($type eq '') { + if (!exists($hashref->{'default'})) { + if ($option eq $defoption) { + $checked = ' checked="checked"'; + } + } else { + if ($hashref->{'default'} eq $option) { + $checked = ' checked="checked"'; + } } } else { - if ($processing->{$type} eq $option) { - $checked = ' checked="checked"'; + if (!exists($hashref->{$type})) { + if ($option eq $defoption) { + $checked = ' checked="checked"'; + } + } else { + if ($hashref->{$type} eq $option) { + $checked = ' checked="checked"'; + } } } + } elsif (($item eq 'email') && ($hascustom)) { + if ($option eq 'custom') { + $checked = ' checked="checked"'; + } + } elsif ($option eq $defoption) { + $checked = ' checked="checked"'; + } + $output .= '<span class="LC_nobreak"><label>'. + '<input type="radio" name="'.$name.'"'. + $checked.' value="'.$option.'"'.$onclick.' />'. + $choices{$option}.'</label></span><br />'; + if ($item eq 'email') { + if ($option eq 'custom') { + my $id = 'cancreate_emailrule_'.$type; + my $display = 'none'; + if ($checked) { + $display = 'inline'; + } + my $numinrow = 2; + $output .= '<fieldset id="'.$id.'" style="display:'.$display.';">'. + '<legend>'.&mt('Disallow').'</legend><table>'. + &user_formats_row('email',$settings,$emailrules, + $emailruleorder,$numinrow,'',$type); + '</table></fieldset>'; + } elsif (($option eq 'inst') || ($option eq 'noninst')) { + my %text = &Apache::lonlocal::texthash ( + inst => 'must end:', + noninst => 'cannot end:', + ); + my $value; + if (ref($emaildomain) eq 'HASH') { + if (ref($emaildomain->{$type}) eq 'HASH') { + $value = $emaildomain->{$type}->{$option}; + } + } + if ($value eq '') { + $value = '@'.$intdom; + } + my $condition = 'cancreate_emaildomain_'.$option.'_'.$type; + my $display = 'none'; + if ($checked) { + $display = 'inline'; + } + $output .= '<div id="'.$condition.'" style="display:'.$display.';">'. + '<span class="LC_domprefs_email">'.$text{$option}.'</span> '. + '<input type="text" name="'.$condition.'" value="'.$value.'" size="10" />'. + '</div>'; + } } - } elsif ($option eq 'automatic') { - $checked = ' checked="checked"'; - } - my $name = 'cancreate_emailprocess'; - if (($type ne '') && ($type ne 'default')) { - $name .= '_'.$type; - } - $output .= '<span class="LC_nobreak"><label>'. - '<input type="radio" name="'.$name.'"'. - $checked.' value="'.$option.'" />'. - $choices{$option}.'</label></span>'; - if ($type eq '') { - $output .= ' '; - } else { - $output .= '<br />'; } + $output .= '</td>'."\n"; } - $$rowtotal ++; + $output .= "</tr></table></td></tr>\n"; return $output; } sub captcha_choice { - my ($context,$settings,$itemcount) = @_; + my ($context,$settings,$itemcount,$customcss,$rowstyle) = @_; my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext, $vertext,$currver); my %lt = &captcha_phrases(); @@ -5999,7 +7502,20 @@ sub captcha_choice { } else { $checked{'original'} = ' checked="checked"'; } - my $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $css_class; + if ($itemcount%2) { + $css_class = 'LC_odd_row'; + } + if ($customcss) { + $css_class .= " $customcss"; + } + $css_class =~ s/^\s+//; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowstyle) { + $css_class .= ' style="'.$rowstyle.'"'; + } my $output = '<tr'.$css_class.'>'. '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="2">'."\n". '<table><tr><td>'."\n"; @@ -6018,7 +7534,7 @@ sub captcha_choice { # specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain. # $output .= '</td></tr>'."\n". - '<tr><td>'."\n". + '<tr><td class="LC_zero_height">'."\n". '<span class="LC_nobreak"><span id="'.$context.'_recaptchapubtxt">'.$pubtext.'</span> '."\n". '<input type="'.$keyentry.'" id="'.$context.'_recaptchapub" name="'.$context.'_recaptchapub" value="'. $currpub.'" size="40" /></span><br />'."\n". @@ -6034,23 +7550,19 @@ sub captcha_choice { } sub user_formats_row { - my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount) = @_; + my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount,$status) = @_; my $output; my %text = ( 'username' => 'new usernames', 'id' => 'IDs', - 'email' => 'self-created accounts (e-mail)', ); - my $css_class = $rowcount%2?' class="LC_odd_row"':''; - $output = '<tr '.$css_class.'>'. - '<td><span class="LC_nobreak">'; - if ($type eq 'email') { - $output .= &mt("Formats disallowed for $text{$type}: "); - } else { - $output .= &mt("Format rules to check for $text{$type}: "); + unless ($type eq 'email') { + my $css_class = $rowcount%2?' class="LC_odd_row"':''; + $output = '<tr '.$css_class.'>'. + '<td><span class="LC_nobreak">'. + &mt("Format rules to check for $text{$type}: "). + '</td><td class="LC_left_item" colspan="2"><table>'; } - $output .= '</span></td>'. - '<td class="LC_left_item" colspan="2"><table>'; my $rem; if (ref($ruleorder) eq 'ARRAY') { for (my $i=0; $i<@{$ruleorder}; $i++) { @@ -6068,25 +7580,41 @@ sub user_formats_row { if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}})) { $check = ' checked="checked" '; } + } elsif ((ref($settings->{$type.'_rule'}) eq 'HASH') && ($status ne '')) { + if (ref($settings->{$type.'_rule'}->{$status}) eq 'ARRAY') { + if (grep(/^\Q$ruleorder->[$i]\E$/,@{$settings->{$type.'_rule'}->{$status}})) { + $check = ' checked="checked" '; + } + } } } + my $name = $type.'_rule'; + if ($type eq 'email') { + $name .= '_'.$status; + } $output .= '<td class="LC_left_item">'. '<span class="LC_nobreak"><label>'. - '<input type="checkbox" name="'.$type.'_rule" '. + '<input type="checkbox" name="'.$name.'" '. 'value="'.$ruleorder->[$i].'"'.$check.'/>'. $rules->{$ruleorder->[$i]}{'name'}.'</label></span></td>'; } } $rem = @{$ruleorder}%($numinrow); } - my $colsleft = $numinrow - $rem; + my $colsleft; + if ($rem) { + $colsleft = $numinrow - $rem; + } if ($colsleft > 1 ) { $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. ' </td>'; } elsif ($colsleft == 1) { $output .= '<td class="LC_left_item"> </td>'; } - $output .= '</tr></table></td></tr>'; + $output .= '</tr></table>'; + unless ($type eq 'email') { + $output .= '</td></tr>'; + } return $output; } @@ -6121,6 +7649,7 @@ sub authtype_names { krb4 => 'Kerberos 4', krb5 => 'Kerberos 5', loc => 'Local', + lti => 'LTI', ); return %lt; } @@ -6189,12 +7718,13 @@ sub print_defaults { '<td><span class="LC_nobreak">'.$titles->{$item}. '</span></td><td class="LC_right_item" colspan="3">'; if ($item eq 'auth_def') { - my @authtypes = ('internal','krb4','krb5','localauth'); + my @authtypes = ('internal','krb4','krb5','localauth','lti'); my %shortauth = ( internal => 'int', krb4 => 'krb4', krb5 => 'krb5', - localauth => 'loc' + localauth => 'loc', + lti => 'lti', ); my %authnames = &authtype_names(); foreach my $auth (@authtypes) { @@ -6282,7 +7812,7 @@ sub print_defaults { 1 => 'Yes, allow login then update passwd file using default cost (if higher)', 2 => 'Yes, disallow login if stored cost is less than domain default', ); - $datatable .= '<table wisth="100%">'; + $datatable .= '<table width="100%">'; foreach my $option (@options) { my $checked = ' '; my $onclick; @@ -6308,17 +7838,12 @@ sub print_defaults { } else { my %defaults; if (ref($settings) eq 'HASH') { - if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH') && - (ref($settings->{'inststatusguest'}) eq 'ARRAY')) { + if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) { my $maxnum = @{$settings->{'inststatusorder'}}; for (my $i=0; $i<$maxnum; $i++) { $css_class = $rownum%2?' class="LC_odd_row"':''; my $item = $settings->{'inststatusorder'}->[$i]; my $title = $settings->{'inststatustypes'}->{$item}; - my $guestok; - if (grep(/^\Q$item\E$/,@{$settings->{'inststatusguest'}})) { - $guestok = 1; - } my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"'; $datatable .= '<tr'.$css_class.'>'. '<td><span class="LC_nobreak">'. @@ -6331,23 +7856,12 @@ sub print_defaults { } $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>'; } - my ($checkedon,$checkedoff); - $checkedoff = ' checked="checked"'; - if ($guestok) { - $checkedon = $checkedoff; - $checkedoff = ''; - } $datatable .= '</select> '.&mt('Internal ID:').' <b>'.$item.'</b> '. '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'. &mt('delete').'</span></td>'. - '<td class="LC_left_item"><span class="LC_nobreak">'.&mt('Name displayed:'). + '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed:'). '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'. - '</span></td>'. - '<td class="LC_right_item"><span class="LC_nobreak">'. - '<label><input type="radio" value="1" name="inststatus_guest_'.$item.'"'.$checkedon.' />'. - &mt('Yes').'</label>'.(' 'x2). - '<label><input type="radio" value="0" name="inststatus_guest_'.$item.'"'.$checkedoff.' />'. - &mt('No').'</label></span></td></tr>'; + '</span></td></tr>'; } $css_class = $rownum%2?' class="LC_odd_row"':''; my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"'; @@ -6364,14 +7878,9 @@ sub print_defaults { $datatable .= '</select> '.&mt('Internal ID:'). '<input type="text" size="10" name="addinststatus" value="" />'. ' '.&mt('(new)'). - '</span></td><td class="LC_left_item"><span class="LC_nobreak">'. + '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'. &mt('Name displayed:'). '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'. - '<td class="LC_right_item"><span class="LC_nobreak">'. - '<label><input type="radio" value="1" name="addinststatus_guest" />'. - &mt('Yes').'</label>'.(' 'x2). - '<label><input type="radio" value="0" name="addinststatus_guest" />'. - &mt('No').'</label></span></td></tr>'; '</tr>'."\n"; $rownum ++; } @@ -6534,7 +8043,7 @@ sub print_scantronformat { } $datatable .= '</span></td>'; if (keys(%error) == 0) { - $datatable .= '<td valign="bottom">'; + $datatable .= '<td style="vertical-align: bottom">'; if (!$switchserver) { $datatable .= &mt('Upload:').'<br />'; } @@ -6633,7 +8142,7 @@ sub print_coursecategories { '<input type="radio" name="coursecat_'.$item.'" value="'.$type.'"'.$ischecked. ' />'.$lt{$type}.'</label> '; } - $datatable .= '</td></tr>'; + $datatable .= '</span></td></tr>'; $itemcount ++; } $$rowtotal += $itemcount; @@ -6719,7 +8228,7 @@ sub print_coursecategories { $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label> '. '<label><input type="radio" name="categorizecomm"'. $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'. - '</tr><tr>'. + '</tr><tr class="LC_odd_row">'. '<td>'.$title{'togglecatsplace'}.'</td>'. '<td class="LC_right_item"><span class="LC_nobreak"><label>'. '<input type="radio" name="togglecatsplace"'. @@ -6876,7 +8385,7 @@ sub print_coursecategories { $datatable .= &initialize_categories($itemcount); } } else { - $datatable .= '<td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td>' + $datatable .= '<tr><td class="LC_right_item">'.$hdritem->{'header'}->[1]->{'col2'}.'</td></tr>' .&initialize_categories($itemcount); } $$rowtotal += $itemcount; @@ -6924,7 +8433,7 @@ sub print_serverstatuses { '<span class="LC_nobreak">'. '<input type="text" name="'.$type.'_machines" '. 'value="'.$machineaccess{$type}.'" size="10" />'. - '</td></tr>'."\n"; + '</span></td></tr>'."\n"; } $$rowtotal += $rownum; return $datatable; @@ -7152,20 +8661,23 @@ sub initialize_categories { communities => 'Communities', placement => 'Placement Tests', ); - my $select0 = ' selected="selected"'; - my $select1 = ''; + my %selnum = ( + instcode => '0', + communities => '1', + placement => '2', + ); + my %selected; foreach my $default ('instcode','communities','placement') { $css_class = $itemcount%2?' class="LC_odd_row"':''; - $chgstr = ' onchange="javascript:reorderCats(this.form,'."'',$default"."_pos','0'".');"'; - if (($default eq 'communities') || ($default eq 'placement')) { - $select1 = $select0; - $select0 = ''; - } + $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"'; + map { $selected{$selnum{$_}} = '' } keys(%selnum); + $selected{$selnum{$default}} = ' selected="selected"'; $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">' - .'<select name="'.$default.'_pos">' - .'<option value="0"'.$select0.'>1</option>' - .'<option value="1"'.$select1.'>2</option>' - .'<option value="2">3</option></select> ' + .'<select name="'.$default.'_pos"'.$chgstr.'>' + .'<option value="0"'.$selected{'0'}.'>1</option>' + .'<option value="1"'.$selected{'1'}.'>2</option>' + .'<option value="2"'.$selected{'2'}.'>3</option>' + .'<option value="3">4</option></select> ' .$default_names{$default} .'</span></td><td><span class="LC_nobreak">' .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />' @@ -7180,9 +8692,11 @@ sub initialize_categories { .'<select name="addcategory_pos"'.$chgstr.'>' .'<option value="0">1</option>' .'<option value="1">2</option>' - .'<option value="2" selected="selected">3</option></select> ' - .&mt('Add category').'</td><td>'.&mt('Name:') - .' <input type="text" size="20" name="addcategory_name" value="" /></td></tr>'; + .'<option value="2">3</option>' + .'<option value="3" selected="selected">4</option></select> ' + .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:') + .' <input type="text" size="20" name="addcategory_name" value="" /></span>' + .'</td></tr>'; return $datatable; } @@ -7237,7 +8751,7 @@ sub build_category_rows { pop(@{$path}); } } else { - $text .= &mt('Add subcategory:').' </span><input type="textbox" size="20" name="addcategory_name_'; + $text .= &mt('Add subcategory:').' </span><input type="text" size="20" name="addcategory_name_'; if ($j == $numchildren) { $text .= $name; } else { @@ -7260,7 +8774,7 @@ sub build_category_rows { my $colspan; if ($parent ne 'instcode') { $colspan = $maxdepth - $depth - 1; - $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="textbox" size="20" name="subcat_'.$name.'" value="" /></td>'; + $text .= '<td colspan="'.$colspan.'">'.&mt('Add subcategory:').'<input type="text" size="20" name="subcat_'.$name.'" value="" /></td>'; } } } @@ -7269,13 +8783,14 @@ sub build_category_rows { } sub modifiable_userdata_row { - my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref) = @_; + my ($context,$item,$settings,$numinrow,$rowcount,$usertypes,$fieldsref,$titlesref, + $rowid,$customcss,$rowstyle) = @_; my ($role,$rolename,$statustype); $role = $item; if ($context eq 'cancreate') { - if ($item =~ /^emailusername_(.+)$/) { - $statustype = $1; - $role = 'emailusername'; + if ($item =~ /^(emailusername)_(.+)$/) { + $role = $1; + $statustype = $2; if (ref($usertypes) eq 'HASH') { if ($usertypes->{$statustype}) { $rolename = &mt('Data provided by [_1]',$usertypes->{$statustype}); @@ -7290,6 +8805,8 @@ sub modifiable_userdata_row { } else { $rolename = $role; } + } elsif ($context eq 'lti') { + $rolename = &mt('Institutional data used (if available)'); } else { if ($role eq 'cr') { $rolename = &mt('Custom role'); @@ -7310,44 +8827,63 @@ sub modifiable_userdata_row { %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); } my $output; - my $css_class = $rowcount%2?' class="LC_odd_row"':''; - $output = '<tr '.$css_class.'>'. + my $css_class; + if ($rowcount%2) { + $css_class = 'LC_odd_row'; + } + if ($customcss) { + $css_class .= " $customcss"; + } + $css_class =~ s/^\s+//; + if ($css_class) { + $css_class = ' class="'.$css_class.'"'; + } + if ($rowstyle) { + $css_class .= ' style="'.$rowstyle.'"'; + } + if ($rowid) { + $rowid = ' id="'.$rowid.'"'; + } + $output = '<tr '.$css_class.$rowid.'>'. '<td><span class="LC_nobreak">'.$rolename.'</span></td>'. '<td class="LC_left_item" colspan="2"><table>'; my $rem; my %checks; + my %current; if (ref($settings) eq 'HASH') { - if (ref($settings->{$context}) eq 'HASH') { + my $hashref; + if ($context eq 'lti') { + if (ref($settings) eq 'HASH') { + $hashref = $settings->{'instdata'}; + } + } elsif (ref($settings->{$context}) eq 'HASH') { if (ref($settings->{$context}->{$role}) eq 'HASH') { - my $hashref = $settings->{$context}->{$role}; - if ($role eq 'emailusername') { - if ($statustype) { - if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') { - $hashref = $settings->{$context}->{$role}->{$statustype}; - if (ref($hashref) eq 'HASH') { - foreach my $field (@fields) { - if ($hashref->{$field}) { - $checks{$field} = $hashref->{$field}; - } - } - } - } + $hashref = $settings->{'lti_instdata'}; + } + if ($role eq 'emailusername') { + if ($statustype) { + if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') { + $hashref = $settings->{$context}->{$role}->{$statustype}; } - } else { - if (ref($hashref) eq 'HASH') { - foreach my $field (@fields) { - if ($hashref->{$field}) { - $checks{$field} = ' checked="checked" '; - } - } + } + } + } + if (ref($hashref) eq 'HASH') { + foreach my $field (@fields) { + if ($hashref->{$field}) { + if ($role eq 'emailusername') { + $checks{$field} = $hashref->{$field}; + } else { + $checks{$field} = ' checked="checked" '; } } } } } - - for (my $i=0; $i<@fields; $i++) { - my $rem = $i%($numinrow); + + my $total = scalar(@fields); + for (my $i=0; $i<$total; $i++) { + $rem = $i%($numinrow); if ($rem == 0) { if ($i > 0) { $output .= '</tr>'; @@ -7358,7 +8894,7 @@ sub modifiable_userdata_row { unless ($role eq 'emailusername') { if (exists($checks{$fields[$i]})) { $check = $checks{$fields[$i]} - } else { + } elsif ($context ne 'lti') { if ($role eq 'st') { if (ref($settings) ne 'HASH') { $check = ' checked="checked" '; @@ -7368,6 +8904,7 @@ sub modifiable_userdata_row { } $output .= '<td class="LC_left_item">'. '<span class="LC_nobreak">'; + my $prefix = 'canmodify'; if ($role eq 'emailusername') { unless ($checks{$fields[$i]} =~ /^(required|optional)$/) { $checks{$fields[$i]} = 'omit'; @@ -7378,21 +8915,27 @@ sub modifiable_userdata_row { $checked='checked="checked" '; } $output .= '<label>'. - '<input type="radio" name="canmodify_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'. + '<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'. &mt($option).'</label>'.(' ' x2); } $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>'; } else { + if ($context eq 'lti') { + $prefix = 'lti'; + } $output .= '<label>'. - '<input type="checkbox" name="canmodify_'.$role.'" '. + '<input type="checkbox" name="'.$prefix.'_'.$role.'" '. 'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}. '</label>'; } $output .= '</span></td>'; - $rem = @fields%($numinrow); } - my $colsleft = $numinrow - $rem; - if ($colsleft > 1 ) { + $rem = $total%$numinrow; + my $colsleft; + if ($rem) { + $colsleft = $numinrow - $rem; + } + if ($colsleft > 1) { $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'. ' </td>'; } elsif ($colsleft == 1) { @@ -7403,11 +8946,14 @@ 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', + selfassign => 'Self-reportable affiliations', + overrides => "Override domain's helpdesk settings based on requester's affiliation", ); my $showdom; if ($context eq 'cansearch') { @@ -7417,9 +8963,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 = '<tr'.$css_class.'>'. '<td>'.$lt{$context}.$showdom. @@ -7441,6 +9000,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" '; } @@ -7448,36 +9011,45 @@ sub insttypes_row { $output .= '<td class="LC_left_item">'. '<span class="LC_nobreak"><label>'. '<input type="checkbox" name="'.$context.'" '. - 'value="'.$types->[$i].'"'.$check.'/>'. + 'value="'.$types->[$i].'"'.$check.$onclick.' />'. $usertypes->{$types->[$i]}.'</label></span></td>'; } } $rem = @{$types}%($numinrow); } my $colsleft = $numinrow - $rem; - if (($rem == 0) && (@{$types} > 0)) { - $output .= '<tr>'; - } - if ($colsleft > 1) { - $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; + if ($context eq 'overrides') { + if ($colsleft > 1) { + $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; + } else { + $output .= '<td class="LC_left_item">'; + } + $output .= ' '; } else { - $output .= '<td class="LC_left_item">'; - } - my $defcheck = ' '; - if (ref($settings) eq 'HASH') { - if (ref($settings->{$context}) eq 'ARRAY') { - if (grep(/^default$/,@{$settings->{$context}})) { + if ($rem == 0) { + $output .= '<tr>'; + } + if ($colsleft > 1) { + $output .= '<td colspan="'.$colsleft.'" class="LC_left_item">'; + } else { + $output .= '<td class="LC_left_item">'; + } + 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 .= '<span class="LC_nobreak"><label>'. + '<input type="checkbox" name="'.$context.'" '. + 'value="default"'.$defcheck.$onclick.' />'. + $othertitle.'</label></span>'; } - $output .= '<span class="LC_nobreak"><label>'. - '<input type="checkbox" name="'.$context.'" '. - 'value="default"'.$defcheck.'/>'. - $othertitle.'</label></span></td>'. - '</tr></table></td></tr>'; + $output .= '</td></tr></table></td></tr>'; return $output; } @@ -8384,7 +9956,7 @@ sub display_colorchgs { } else { my $newitem = $confhash->{$role}{$item}; if ($key eq 'images') { - $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" valign="bottom" />'; + $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />'; } $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>'; } @@ -8511,14 +10083,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')); } @@ -8579,7 +10151,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; @@ -8659,7 +10232,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=$_; @@ -8693,7 +10266,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) { @@ -8719,7 +10292,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; @@ -8761,7 +10334,7 @@ sub modify_quotas { $context = $action; } if ($context eq 'requestcourses') { - @usertools = ('official','unofficial','community','textbook','placement'); + @usertools = ('official','unofficial','community','textbook','placement','lti'); @options =('norequest','approval','validate','autolimit'); %validations = &Apache::lonnet::auto_courserequest_checks($dom); %titles = &courserequest_titles(); @@ -8810,7 +10383,7 @@ sub modify_quotas { my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval'); @approvalnotify = sort(@approvalnotify); $confhash{'notify'}{'approval'} = join(',',@approvalnotify); - my @crstypes = ('official','unofficial','community','textbook','placement'); + my @crstypes = ('official','unofficial','community','textbook','placement','lti'); my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode'); foreach my $type (@hasuniquecode) { if (grep(/^\Q$type\E$/,@crstypes)) { @@ -8918,17 +10491,21 @@ 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 .= '<li><span class="LC_error">'.$error.'</span></li>'; - } + if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') { + $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>'; + } else { + my ($imgurl,$error) = &process_textbook_image($r,$dom,$confname,$type.'_image_'.$i, + $cdom,$cnum,$type,$configuserok, + $switchserver,$author_ok); + if ($imgurl) { + $confhash{$type}{$key}{'image'} = $imgurl; + $changes{$type}{$key} = 1; + } + if ($error) { + &Apache::lonnet::logthis($error); + $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; + } + } } elsif ($domconfig{$action}{$type}{$key}{'image'}) { $confhash{$type}{$key}{'image'} = $domconfig{$action}{$type}{$key}{'image'}; @@ -8961,15 +10538,19 @@ 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 .= '<li><span class="LC_error">'.$error.'</span></li>'; + if (&Apache::lonnet::homeserver($cnum,$cdom) eq 'no_host') { + $errors .= '<li><span class="LC_error">'.&mt('Image not saved: could not find textbook course').'</li>'; + } else { + my ($imageurl,$error) = + &process_textbook_image($r,$dom,$confname,$type.'_addbook_image',$cdom,$cnum,$type, + $configuserok,$switchserver,$author_ok); + if ($imageurl) { + $confhash{$type}{$newbook{$type}}{'image'} = $imageurl; + } + if ($error) { + &Apache::lonnet::logthis($error); + $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; + } } } } @@ -9461,7 +11042,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 { @@ -9501,8 +11082,11 @@ sub modify_ltitools { $allpos[$position] = $newid; } $changes{$newid} = 1; - foreach my $item ('title','url','key','secret') { + foreach my $item ('title','url','key','secret','lifetime') { $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g; + if ($item eq 'lifetime') { + $env{'form.ltitools_add_'.$item} =~ s/[^\d.]//g; + } if ($env{'form.ltitools_add_'.$item}) { if (($item eq 'key') || ($item eq 'secret')) { $encconfig{$newid}{$item} = $env{'form.ltitools_add_'.$item}; @@ -9517,6 +11101,11 @@ sub modify_ltitools { if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') { $confhash{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'}; } + if ($env{'form.ltitools_add_sigmethod'} eq 'HMAC-SHA256') { + $confhash{$newid}{'sigmethod'} = $env{'form.ltitools_add_sigmethod'}; + } else { + $confhash{$newid}{'sigmethod'} = 'HMAC-SHA1'; + } foreach my $item ('width','height','linktext','explanation') { $env{'form.ltitools_add_'.$item} =~ s/^\s+//; $env{'form.ltitools_add_'.$item} =~ s/\s+$//; @@ -9532,17 +11121,26 @@ sub modify_ltitools { } if ($env{'form.ltitools_add_target'} eq 'window') { $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'}; + } elsif ($env{'form.ltitools_add_target'} eq 'tab') { + $confhash{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'}; } else { $confhash{$newid}{'display'}{'target'} = 'iframe'; } foreach my $item ('passback','roster') { - if ($env{'form.ltitools_add_'.$item}) { + if ($env{'form.ltitools_'.$item.'_add'}) { $confhash{$newid}{$item} = 1; + if ($env{'form.ltitools_'.$item.'valid_add'} ne '') { + my $lifetime = $env{'form.ltitools_'.$item.'valid_add'}; + $lifetime =~ s/^\s+|\s+$//g; + if ($lifetime =~ /^\d+\.?\d*$/) { + $confhash{$newid}{$item.'valid'} = $lifetime; + } + } } } 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; @@ -9570,6 +11168,13 @@ sub modify_ltitools { } } } + if (ref($confhash{$newid}{'fields'}) eq 'HASH') { + if ($confhash{$newid}{'fields'}{'user'}) { + if ($env{'form.ltitools_userincdom_add'}) { + $confhash{$newid}{'incdom'} = 1; + } + } + } my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig'); foreach my $item (@courseconfig) { $confhash{$newid}{'crsconf'}{$item} = 1; @@ -9605,6 +11210,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'}) { @@ -9615,7 +11221,7 @@ sub modify_ltitools { } else { my $newpos = $env{'form.ltitools_'.$itemid}; $newpos =~ s/\D+//g; - foreach my $item ('title','url') { + foreach my $item ('title','url','lifetime') { $confhash{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i}; if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) { $changes{$itemid} = 1; @@ -9633,6 +11239,18 @@ sub modify_ltitools { if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') { $confhash{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i}; } + if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') { + $confhash{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i}; + } else { + $confhash{$itemid}{'sigmethod'} = 'HMAC-SHA1'; + } + if ($domconfig{$action}{$itemid}{'sigmethod'} eq '') { + if ($confhash{$itemid}{'sigmethod'} ne 'HMAC-SHA1') { + $changes{$itemid} = 1; + } + } elsif ($domconfig{$action}{$itemid}{'sigmethod'} ne $confhash{$itemid}{'sigmethod'}) { + $changes{$itemid} = 1; + } foreach my $size ('width','height') { $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//; $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//; @@ -9671,6 +11289,8 @@ sub modify_ltitools { } if ($env{'form.ltitools_target_'.$i} eq 'window') { $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i}; + } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') { + $confhash{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i}; } else { $confhash{$itemid}{'display'}{'target'} = 'iframe'; } @@ -9684,13 +11304,23 @@ sub modify_ltitools { foreach my $extra ('passback','roster') { if ($env{'form.ltitools_'.$extra.'_'.$i}) { $confhash{$itemid}{$extra} = 1; + if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') { + my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i}; + $lifetime =~ s/^\s+|\s+$//g; + if ($lifetime =~ /^\d+\.?\d*$/) { + $confhash{$itemid}{$extra.'valid'} = $lifetime; + } + } } if ($domconfig{$action}{$itemid}{$extra} ne $confhash{$itemid}{$extra}) { $changes{$itemid} = 1; } + if ($domconfig{$action}{$itemid}{$extra.'valid'} ne $confhash{$itemid}{$extra.'valid'}) { + $changes{$itemid} = 1; + } } my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i); - foreach my $item ('label','title','target','linktext','explanation') { + foreach my $item ('label','title','target','linktext','explanation','append') { if (grep(/^\Q$item\E$/,@courseconfig)) { $confhash{$itemid}{'crsconf'}{$item} = 1; if (ref($domconfig{$action}{$itemid}{'crsconf'}) eq 'HASH') { @@ -9734,6 +11364,16 @@ sub modify_ltitools { } } } + if (ref($confhash{$itemid}{'fields'}) eq 'HASH') { + if ($confhash{$itemid}{'fields'}{'user'}) { + if ($env{'form.ltitools_userincdom_'.$i}) { + $confhash{$itemid}{'incdom'} = 1; + } + if ($domconfig{$action}{$itemid}{'incdom'} ne $confhash{$itemid}{'incdom'}) { + $changes{$itemid} = 1; + } + } + } $allpos[$newpos] = $itemid; } if ($imgdeletions{$itemid}) { @@ -9867,7 +11507,7 @@ sub modify_ltitools { $resulttext .= '</li><ul>'; my $position = $pos + 1; $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>'; - foreach my $item ('version','msgtype','url') { + foreach my $item ('version','msgtype','sigmethod','url','lifetime') { if ($confhash{$itemid}{$item} ne '') { $resulttext .= '<li>'.$lt{$item}.': '.$confhash{$itemid}{$item}.'</li>'; } @@ -9881,7 +11521,7 @@ sub modify_ltitools { $resulttext .= ('*'x$num).'</li>'; } $resulttext .= '<li>'.&mt('Configurable in course:'); - my @possconfig = ('label','title','target','linktext','explanation'); + my @possconfig = ('label','title','target','linktext','explanation','append'); my $numconfig = 0; if (ref($confhash{$itemid}{'crsconf'}) eq 'HASH') { foreach my $item (@possconfig) { @@ -9899,6 +11539,15 @@ sub modify_ltitools { $resulttext .= '<li>'.$lt{$item}.' '; if ($confhash{$itemid}{$item}) { $resulttext .= &mt('Yes'); + if ($confhash{$itemid}{$item.'valid'}) { + if ($item eq 'passback') { + $resulttext .= ' '.&mt('valid for at least [quant,_1,day] after launch', + $confhash{$itemid}{$item.'valid'}); + } else { + $resulttext .= ' '.&mt('valid for at least [quant,_1,second] after launch', + $confhash{$itemid}{$item.'valid'}); + } + } } else { $resulttext .= &mt('No'); } @@ -9935,6 +11584,13 @@ sub modify_ltitools { } if ($fieldlist) { $fieldlist =~ s/,$//; + if ($confhash{$itemid}{'fields'}{'user'}) { + if ($confhash{$itemid}{'incdom'}) { + $fieldlist .= ' ('.&mt('username:domain').')'; + } else { + $fieldlist .= ' ('.&mt('username').')'; + } + } $resulttext .= '<li>'.&mt('Data sent').':'.$fieldlist.'</li>'; } } @@ -9959,7 +11615,7 @@ sub modify_ltitools { } } if ($customlist) { - $resulttext .= '<li>'.&mt('Custom items').':'.$customlist.'</li>'; + $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>'; } } $resulttext .= '</ul></li>'; @@ -10055,6 +11711,514 @@ sub get_ltitools_id { return ($id,$error); } +sub modify_lti { + my ($r,$dom,$action,$lastactref,%domconfig) = @_; + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); + my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext); + my (%posslti,%posslticrs,%posscrstype); + my @courseroles = ('cc','in','ta','ep','st'); + my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator); + my @lticourseroles = qw(Instructor TeachingAssistant Mentor Learner); + my @coursetypes = ('official','unofficial','community','textbook','placement'); + my %coursetypetitles = &Apache::lonlocal::texthash ( + official => 'Official', + unofficial => 'Unofficial', + community => 'Community', + textbook => 'Textbook', + placement => 'Placement Test', + ); + my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); + my %lt = <i_names(); + map { $posslti{$_} = 1; } @ltiroles; + map { $posslticrs{$_} = 1; } @lticourseroles; + map { $posscrstype{$_} = 1; } @coursetypes; + + my %menutitles = <imenu_titles(); + + my (@items,%deletions,%itemids); + if ($env{'form.lti_add'}) { + my $consumer = $env{'form.lti_consumer_add'}; + $consumer =~ s/(`)/'/g; + ($newid,my $error) = &get_lti_id($dom,$consumer); + if ($newid) { + $itemids{'add'} = $newid; + push(@items,'add'); + $changes{$newid} = 1; + } else { + my $error = &mt('Failed to acquire unique ID for new LTI configuration'); + $errors .= '<li><span class="LC_error">'.$error.'</span></li>'; + } + } + if (ref($domconfig{$action}) eq 'HASH') { + my @todelete = &Apache::loncommon::get_env_multiple('form.lti_del'); + if (@todelete) { + map { $deletions{$_} = 1; } @todelete; + } + my $maxnum = $env{'form.lti_maxnum'}; + for (my $i=0; $i<=$maxnum; $i++) { + my $itemid = $env{'form.lti_id_'.$i}; + $itemid =~ s/\D+//g; + if (ref($domconfig{$action}{$itemid}) eq 'HASH') { + if ($deletions{$itemid}) { + $changes{$itemid} = $domconfig{$action}{$itemid}{'consumer'}; + } else { + push(@items,$i); + $itemids{$i} = $itemid; + } + } + } + } + foreach my $idx (@items) { + my $itemid = $itemids{$idx}; + next unless ($itemid); + my $position = $env{'form.lti_pos_'.$idx}; + $position =~ s/\D+//g; + if ($position ne '') { + $allpos[$position] = $itemid; + } + foreach my $item ('consumer','key','secret','lifetime') { + my $formitem = 'form.lti_'.$item.'_'.$idx; + $env{$formitem} =~ s/(`)/'/g; + if ($item eq 'lifetime') { + $env{$formitem} =~ s/[^\d.]//g; + } + if ($env{$formitem} ne '') { + if (($item eq 'key') || ($item eq 'secret')) { + $encconfig{$itemid}{$item} = $env{$formitem}; + } else { + $confhash{$itemid}{$item} = $env{$formitem}; + unless (($idx eq 'add') || ($changes{$itemid})) { + if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) { + $changes{$itemid} = 1; + } + } + } + } + } + if ($env{'form.lti_version_'.$idx} eq 'LTI-1p0') { + $confhash{$itemid}{'version'} = $env{'form.lti_version_'.$idx}; + } + if ($env{'form.lti_mapuser_'.$idx} eq 'sourcedid') { + $confhash{$itemid}{'mapuser'} = 'lis_person_sourcedid'; + } elsif ($env{'form.lti_mapuser_'.$idx} eq 'email') { + $confhash{$itemid}{'mapuser'} = 'lis_person_contact_email_primary'; + } elsif ($env{'form.lti_mapuser_'.$idx} eq 'other') { + my $mapuser = $env{'form.lti_customuser_'.$idx}; + $mapuser =~ s/(`)/'/g; + $mapuser =~ s/^\s+|\s+$//g; + $confhash{$itemid}{'mapuser'} = $mapuser; + } + foreach my $ltirole (@lticourseroles) { + my $possrole = $env{'form.lti_maprole_'.$ltirole.'_'.$idx}; + if (grep(/^\Q$possrole\E$/,@courseroles)) { + $confhash{$itemid}{'maproles'}{$ltirole} = $possrole; + } + } + my @possmakeuser = &Apache::loncommon::get_env_multiple('form.lti_makeuser_'.$idx); + my @makeuser; + foreach my $ltirole (sort(@possmakeuser)) { + if ($posslti{$ltirole}) { + push(@makeuser,$ltirole); + } + } + $confhash{$itemid}{'makeuser'} = \@makeuser; + if (@makeuser) { + my $lcauth = $env{'form.lti_lcauth_'.$idx}; + if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) { + $confhash{$itemid}{'lcauth'} = $lcauth; + if ($lcauth ne 'internal') { + my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx}; + $lcauthparm =~ s/^(\s+|\s+)$//g; + $lcauthparm =~ s/`//g; + if ($lcauthparm ne '') { + $confhash{$itemid}{'lcauthparm'} = $lcauthparm; + } + } + } else { + $confhash{$itemid}{'lcauth'} = 'lti'; + } + } + my @possinstdata = &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx); + if (@possinstdata) { + foreach my $field (@possinstdata) { + if (exists($fieldtitles{$field})) { + push(@{$confhash{$itemid}{'instdata'}}); + } + } + } + if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') || + ($env{'form.lti_mapcrs_'.$idx} eq 'context_id')) { + $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx}; + } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') { + my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx}; + $mapcrs =~ s/(`)/'/g; + $mapcrs =~ s/^\s+|\s+$//g; + $confhash{$itemid}{'mapcrs'} = $mapcrs; + } + my @posstypes = &Apache::loncommon::get_env_multiple('form.lti_mapcrstype_'.$idx); + my @crstypes; + foreach my $type (sort(@posstypes)) { + if ($posscrstype{$type}) { + push(@crstypes,$type); + } + } + $confhash{$itemid}{'mapcrstype'} = \@crstypes; + if ($env{'form.lti_makecrs_'.$idx}) { + $confhash{$itemid}{'makecrs'} = 1; + } + my @possenroll = &Apache::loncommon::get_env_multiple('form.lti_selfenroll_'.$idx); + my @selfenroll; + foreach my $type (sort(@possenroll)) { + if ($posslticrs{$type}) { + push(@selfenroll,$type); + } + } + $confhash{$itemid}{'selfenroll'} = \@selfenroll; + if ($env{'form.lti_crssec_'.$idx}) { + if ($env{'form.lti_crssecsrc_'.$idx} eq 'course_section_sourcedid') { + $confhash{$itemid}{'section'} = $env{'form.lti_crssecsrc_'.$idx}; + } elsif ($env{'form.lti_crssecsrc_'.$idx} eq 'other') { + my $section = $env{'form.lti_customsection_'.$idx}; + $section =~ s/(`)/'/g; + $section =~ s/^\s+|\s+$//g; + if ($section ne '') { + $confhash{$itemid}{'section'} = $section; + } + } + } + foreach my $field ('passback','roster','topmenu','inlinemenu') { + if ($env{'form.lti_'.$field.'_'.$idx}) { + $confhash{$itemid}{$field} = 1; + } + } + if ($env{'form.lti_passback_'.$idx}) { + if ($env{'form.lti_passbackformat_'.$idx} eq '1.0') { + $confhash{$itemid}{'passbackformat'} = '1.0'; + } else { + $confhash{$itemid}{'passbackformat'} = '1.1'; + } + } + if ($env{'form.lti_topmenu_'.$idx} || $env{'form.lti_inlinemenu_'.$idx}) { + $confhash{$itemid}{lcmenu} = []; + my @possmenu = &Apache::loncommon::get_env_multiple('form.lti_menuitem_'.$idx); + foreach my $field (@possmenu) { + if (exists($menutitles{$field})) { + if ($field eq 'grades') { + next unless ($env{'form.lti_inlinemenu_'.$idx}); + } + push(@{$confhash{$itemid}{lcmenu}},$field); + } + } + } + unless (($idx eq 'add') || ($changes{$itemid})) { + foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu') { + if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) { + $changes{$itemid} = 1; + } + } + unless ($changes{$itemid}) { + if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) { + if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) { + $changes{$itemid} = 1; + } + } + } + foreach my $field ('makeuser','mapcrstype','selfenroll','instdata','lcmenu') { + unless ($changes{$itemid}) { + if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') { + if (ref($confhash{$itemid}{$field}) eq 'ARRAY') { + my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field}, + $confhash{$itemid}{$field}); + if (@diffs) { + $changes{$itemid} = 1; + } + } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) { + $changes{$itemid} = 1; + } + } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') { + if (@{$confhash{$itemid}{$field}} > 0) { + $changes{$itemid} = 1; + } + } + } + } + unless ($changes{$itemid}) { + if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') { + if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { + foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) { + if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne + $confhash{$itemid}{'maproles'}{$ltirole}) { + $changes{$itemid} = 1; + last; + } + } + unless ($changes{$itemid}) { + foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) { + if ($confhash{$itemid}{'maproles'}{$ltirole} ne + $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) { + $changes{$itemid} = 1; + last; + } + } + } + } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) { + $changes{$itemid} = 1; + } + } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { + unless ($changes{$itemid}) { + if (keys(%{$confhash{$itemid}{'maproles'}}) > 0) { + $changes{$itemid} = 1; + } + } + } + } + } + } + if (@allpos > 0) { + my $idx = 0; + foreach my $itemid (@allpos) { + if ($itemid ne '') { + $confhash{$itemid}{'order'} = $idx; + if (ref($domconfig{$action}) eq 'HASH') { + if (ref($domconfig{$action}{$itemid}) eq 'HASH') { + if ($domconfig{$action}{$itemid}{'order'} ne $idx) { + $changes{$itemid} = 1; + } + } + } + $idx ++; + } + } + } + my %ltihash = ( + $action => { %confhash } + ); + my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash, + $dom); + if ($putresult eq 'ok') { + my %ltienchash = ( + $action => { %encconfig } + ); + &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom); + if (keys(%changes) > 0) { + my $cachetime = 24*60*60; + my %ltiall = %confhash; + foreach my $id (keys(%ltiall)) { + if (ref($encconfig{$id}) eq 'HASH') { + foreach my $item ('key','secret') { + $ltiall{$id}{$item} = $encconfig{$id}{$item}; + } + } + } + &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime); + if (ref($lastactref) eq 'HASH') { + $lastactref->{'lti'} = 1; + } + $resulttext = &mt('Changes made:').'<ul>'; + my %bynum; + foreach my $itemid (sort(keys(%changes))) { + my $position = $confhash{$itemid}{'order'}; + $bynum{$position} = $itemid; + } + foreach my $pos (sort { $a <=> $b } keys(%bynum)) { + my $itemid = $bynum{$pos}; + if (ref($confhash{$itemid}) ne 'HASH') { + $resulttext .= '<li>'.&mt('Deleted: [_1]',$changes{$itemid}).'</li>'; + } else { + $resulttext .= '<li><b>'.$confhash{$itemid}{'consumer'}.'</b></li><ul>'; + my $position = $pos + 1; + $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>'; + foreach my $item ('version','lifetime') { + if ($confhash{$itemid}{$item} ne '') { + $resulttext .= '<li>'.$lt{$item}.': '.$confhash{$itemid}{$item}.'</li>'; + } + } + if ($encconfig{$itemid}{'key'} ne '') { + $resulttext .= '<li>'.$lt{'key'}.': '.$encconfig{$itemid}{'key'}.'</li>'; + } + if ($encconfig{$itemid}{'secret'} ne '') { + $resulttext .= '<li>'.$lt{'secret'}.': '; + my $num = length($encconfig{$itemid}{'secret'}); + $resulttext .= ('*'x$num).'</li>'; + } + if ($confhash{$itemid}{'mapuser'}) { + my $shownmapuser; + if ($confhash{$itemid}{'mapuser'} eq 'lis_person_sourcedid') { + $shownmapuser = $lt{'sourcedid'}.' (lis_person_sourcedid)'; + } elsif ($confhash{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') { + $shownmapuser = $lt{'email'}.' (lis_person_contact_email_primary)'; + } else { + $shownmapuser = &mt('Other').' ('.$confhash{$itemid}{'mapuser'}.')'; + } + $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>'; + } + if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { + my $rolemaps; + foreach my $role (@ltiroles) { + if ($confhash{$itemid}{'maproles'}{$role}) { + $rolemaps .= (' 'x2).$role.'='. + &Apache::lonnet::plaintext($confhash{$itemid}{'maproles'}{$role}, + 'Course').','; + } + } + if ($rolemaps) { + $rolemaps =~ s/,$//; + $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>'; + } + } + if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') { + if (@{$confhash{$itemid}{'makeuser'}} > 0) { + $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]', + join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />'; + if ($confhash{$itemid}{'lcauth'} eq 'lti') { + $resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>'; + } else { + $resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]', + $confhash{$itemid}{'lcauth'}); + if ($confhash{$itemid}{'lcauth'} eq 'internal') { + $resulttext .= '; '.&mt('a randomly generated password will be created'); + } elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') { + if ($confhash{$itemid}{'lcauthparm'} ne '') { + $resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'}); + } + } else { + $resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'}); + } + } + $resulttext .= '</li>'; + } else { + $resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>'; + } + } + if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') { + if (@{$confhash{$itemid}{'instdata'}} > 0) { + $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]', + join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>'; + } else { + $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>'; + } + } + if ($confhash{$itemid}{'mapcrs'}) { + $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>'; + } + if (ref($confhash{$itemid}{'mapcrstype'}) eq 'ARRAY') { + if (@{$confhash{$itemid}{'mapcrstype'}} > 0) { + $resulttext .= '<li>'.&mt('Mapping for the following LON-CAPA course types: [_1]', + join(', ',map { $coursetypetitles{$_}; } @coursetypes)). + '</li>'; + } else { + $resulttext .= '<li>'.&mt('No mapping to LON-CAPA courses').'</li>'; + } + } + if ($confhash{$itemid}{'makecrs'}) { + $resulttext .= '<li>'.&mt('Instructor may create course (if absent).').'</li>'; + } else { + $resulttext .= '<li>'.&mt('Instructor may not create course (if absent).').'</li>'; + } + if (ref($confhash{$itemid}{'selfenroll'}) eq 'ARRAY') { + if (@{$confhash{$itemid}{'selfenroll'}} > 0) { + $resulttext .= '<li>'.&mt('Self-enrollment for following roles: [_1]', + join(', ',@{$confhash{$itemid}{'selfenroll'}})). + '</li>'; + } else { + $resulttext .= '<li>'.&mt('Self-enrollment not permitted').'</li>'; + } + } + if ($confhash{$itemid}{'section'}) { + if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') { + $resulttext .= '<li>'.&mt('User section from standard field:'). + ' (course_section_sourcedid)'.'</li>'; + } else { + $resulttext .= '<li>'.&mt('User section from:').' '. + $confhash{$itemid}{'section'}.'</li>'; + } + } else { + $resulttext .= '<li>'.&mt('No section assignment').'</li>'; + } + foreach my $item ('passback','roster','topmenu','inlinemenu') { + $resulttext .= '<li>'.$lt{$item}.': '; + if ($confhash{$itemid}{$item}) { + $resulttext .= &mt('Yes'); + if ($item eq 'passback') { + if ($confhash{$itemid}{'passbackformat'} eq '1.0') { + $resulttext .= ' ('.&mt('Outcomes Extension (1.0)').')'; + } elsif ($confhash{$itemid}{'passbackformat'} eq '1.1') { + $resulttext .= ' ('.&mt('Outcomes Service (1.1)').')'; + } + } + } else { + $resulttext .= &mt('No'); + } + $resulttext .= '</li>'; + } + if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') { + if (@{$confhash{$itemid}{'lcmenu'}} > 0) { + $resulttext .= '<li>'.&mt('Menu items:').' '. + join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>'; + } else { + $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>'; + } + } + $resulttext .= '</ul></li>'; + } + } + $resulttext .= '</ul>'; + } else { + $resulttext = &mt('No changes made.'); + } + } else { + $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>'; + } + if ($errors) { + $resulttext .= &mt('The following errors occurred: ').'<ul>'. + $errors.'</ul>'; + } + return $resulttext; +} + +sub get_lti_id { + my ($domain,$consumer) = @_; + # get lock on lti db + my $lockhash = { + lock => $env{'user.name'}. + ':'.$env{'user.domain'}, + }; + my $tries = 0; + my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain); + my ($id,$error); + + while (($gotlock ne 'ok') && ($tries<10)) { + $tries ++; + sleep (0.1); + $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain); + } + if ($gotlock eq 'ok') { + my %currids = &Apache::lonnet::dump_dom('lti',$domain); + if ($currids{'lock'}) { + delete($currids{'lock'}); + if (keys(%currids)) { + my @curr = sort { $a <=> $b } keys(%currids); + if ($curr[-1] =~ /^\d+$/) { + $id = 1 + $curr[-1]; + } + } else { + $id = 1; + } + if ($id) { + unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') { + $error = 'nostore'; + } + } else { + $error = 'nonumber'; + } + } + my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain); + } else { + $error = 'nolock'; + } + return ($id,$error); +} + sub modify_autoenroll { my ($dom,$lastactref,%domconfig) = @_; my ($resulttext,%changes); @@ -10140,9 +12304,9 @@ sub modify_autoenroll { } if ($changes{'autofailsafe'}) { if ($failsafe ne '') { - $resulttext .= '<li>'.&mt("$title{'failsafe'} set to [_1]",$failsafe).'</li>'; + $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section set to: [_1]',$failsafe).'</li>'; } else { - $resulttext .= '<li>'.&mt("$title{'failsafe'} deleted"); + $resulttext .= '<li>'.&mt('Failsafe for no drops if institutional data missing for a section: deleted'); } &Apache::lonnet::get_domain_defaults($dom,1); if (ref($lastactref) eq 'HASH') { @@ -10641,7 +12805,8 @@ sub modify_contacts { my @contacts = ('supportemail','adminemail'); my @mailings = ('errormail','packagesmail','helpdeskmail','otherdomsmail', 'lonstatusmail','requestsmail','updatesmail','idconflictsmail'); - my @toggles = ('reporterrors','reportupdates'); + my @toggles = ('reporterrors','reportupdates','reportstatus'); + my @lonstatus = ('threshold','sysmail','weights','excluded'); my ($fields,$fieldtitles,$fieldoptions,$possoptions) = &helpform_fields(); foreach my $type (@mailings) { @{$newsetting{$type}} = @@ -10674,23 +12839,98 @@ sub modify_contacts { $contacts_hash{'contacts'}{$item} = $env{'form.'.$item}; } } + my ($lonstatus_defs,$lonstatus_names) = &Apache::loncommon::lon_status_items(); + foreach my $item (@lonstatus) { + if ($item eq 'excluded') { + my (%serverhomes,@excluded); + map { $serverhomes{$_} = 1; } values(%Apache::lonnet::serverhomeIDs); + my @possexcluded = &Apache::loncommon::get_env_multiple('form.errorexcluded'); + if (@possexcluded) { + foreach my $id (sort(@possexcluded)) { + if ($serverhomes{$id}) { + push(@excluded,$id); + } + } + } + if (@excluded) { + $contacts_hash{'contacts'}{'lonstatus'}{$item} = \@excluded; + } + } elsif ($item eq 'weights') { + foreach my $type ('E','W','N') { + $env{'form.error'.$item.'_'.$type} =~ s/^\s+|\s+$//g; + if ($env{'form.error'.$item.'_'.$type} =~ /^\d+$/) { + unless ($env{'form.error'.$item.'_'.$type} == $lonstatus_defs->{$type}) { + $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type} = + $env{'form.error'.$item.'_'.$type}; + } + } + } + } elsif (($item eq 'threshold') || ($item eq 'sysmail')) { + $env{'form.error'.$item} =~ s/^\s+|\s+$//g; + if ($env{'form.error'.$item} =~ /^\d+$/) { + unless ($env{'form.error'.$item} == $lonstatus_defs->{$item}) { + $contacts_hash{'contacts'}{'lonstatus'}{$item} = $env{'form.error'.$item}; + } + } + } + } if ((ref($fields) eq 'ARRAY') && (ref($possoptions) eq 'HASH')) { foreach my $field (@{$fields}) { if (ref($possoptions->{$field}) eq 'ARRAY') { my $value = $env{'form.helpform_'.$field}; $value =~ s/^\s+|\s+$//g; if (grep(/^\Q$value\E$/,@{$possoptions->{$field}})) { - $contacts_hash{contacts}{'helpform'}{$field} = $value; + $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}) { @@ -10745,6 +12985,103 @@ 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); + } + } + } + if (ref($currsetting{'lonstatus'}) eq 'HASH') { + foreach my $key ('excluded','weights','threshold','sysmail') { + if ($key eq 'excluded') { + if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') && + (ref($contacts_hash{contacts}{lonstatus}{excluded}) eq 'ARRAY')) { + if ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') && + (@{$currsetting{'lonstatus'}{$key}})) { + my @diffs = + &Apache::loncommon::compare_arrays($contacts_hash{contacts}{lonstatus}{excluded}, + $currsetting{'lonstatus'}{$key}); + if (@diffs) { + push(@{$changes{'lonstatus'}},$key); + } + } elsif (@{$contacts_hash{contacts}{lonstatus}{excluded}}) { + push(@{$changes{'lonstatus'}},$key); + } + } elsif ((ref($currsetting{'lonstatus'}{$key}) eq 'ARRAY') && + (@{$currsetting{'lonstatus'}{$key}})) { + push(@{$changes{'lonstatus'}},$key); + } + } elsif ($key eq 'weights') { + if ((ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') && + (ref($contacts_hash{contacts}{lonstatus}{$key}) eq 'HASH')) { + if (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') { + foreach my $type ('E','W','N','U') { + unless ($contacts_hash{contacts}{lonstatus}{$key}{$type} eq + $currsetting{'lonstatus'}{$key}{$type}) { + push(@{$changes{'lonstatus'}},$key); + last; + } + } + } else { + foreach my $type ('E','W','N','U') { + if ($contacts_hash{contacts}{lonstatus}{$key}{$type} ne '') { + push(@{$changes{'lonstatus'}},$key); + last; + } + } + } + } elsif (ref($currsetting{'lonstatus'}{$key}) eq 'HASH') { + foreach my $type ('E','W','N','U') { + if ($currsetting{'lonstatus'}{$key}{$type} ne '') { + push(@{$changes{'lonstatus'}},$key); + last; + } + } + } + } elsif (($key eq 'threshold') || ($key eq 'sysmail')) { + if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') { + if ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) { + if ($currsetting{'lonstatus'}{$key} != $contacts_hash{contacts}{lonstatus}{$key}) { + push(@{$changes{'lonstatus'}},$key); + } + } elsif ($contacts_hash{contacts}{lonstatus}{$key} =~ /^\d+$/) { + push(@{$changes{'lonstatus'}},$key); + } + } elsif ($currsetting{'lonstatus'}{$key} =~ /^\d+$/) { + push(@{$changes{'lonstatus'}},$key); + } + } + } + } else { + if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') { + foreach my $key ('excluded','weights','threshold','sysmail') { + if (exists($contacts_hash{contacts}{lonstatus}{$key})) { + push(@{$changes{'lonstatus'}},$key); + } + } + } + } } else { my %default; $default{'supportemail'} = $Apache::lonnet::perlvar{'lonSupportEMail'}; @@ -10789,6 +13126,13 @@ sub modify_contacts { } } } + if (ref($contacts_hash{contacts}{lonstatus}) eq 'HASH') { + foreach my $key ('excluded','weights','threshold','sysmail') { + if (exists($contacts_hash{contacts}{lonstatus}{$key})) { + push(@{$changes{'lonstatus'}},$key); + } + } + } } foreach my $item (@toggles) { if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) { @@ -10859,23 +13203,134 @@ sub modify_contacts { $resulttext .= '</li>'; } } + if (ref($changes{'overrides'}) eq 'ARRAY') { + my @deletions; + foreach my $type (@{$changes{'overrides'}}) { + if ($usertypeshash{$type}) { + if (grep(/^\Q$type\E/,@overrides)) { + $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation set for [_1]", + $usertypeshash{$type}).'<ul><li>'; + if (ref($newsetting{'override_'.$type}) eq 'HASH') { + my @text; + foreach my $item (@contacts) { + if ($newsetting{'override_'.$type}{$item}) { + push(@text,$short_titles->{$item}); + } + } + if ($newsetting{'override_'.$type}{'others'} ne '') { + push(@text,$newsetting{'override_'.$type}{'others'}); + } + + if (@text) { + $resulttext .= &mt('Helpdesk e-mail sent to: [_1]', + '<span class="LC_cusr_emph">'.join(', ',@text).'</span>'); + } + if ($newsetting{'override_'.$type}{'bcc'} ne '') { + my $bcctext; + if (@text) { + $bcctext = ' '.&mt('with Bcc to'); + } else { + $bcctext = '(Bcc)'; + } + $resulttext .= $bcctext.': <span class="LC_cusr_emph">'.$newsetting{'override_'.$type}{'bcc'}.'</span>'; + } elsif (!@text) { + $resulttext .= &mt('Helpdesk e-mail sent to no one'); + } + $resulttext .= '</li>'; + if ($newsetting{'override_'.$type}{'include'} ne '') { + my ($loc,$str) = split(/:/,$newsetting{'override_'.$type}{'include'}); + if ($loc eq 'b') { + $resulttext .= '<li>'.&mt('Text automatically added to e-mail body:').' '.&unescape($str).'</li>'; + } elsif ($loc eq 's') { + $resulttext .= '<li>'.&mt('Text automatically added to e-mail subject:').' '.&unescape($str).'</li>'; + } + } + } + $resulttext .= '</li></ul></li>'; + } else { + push(@deletions,$usertypeshash{$type}); + } + } + } + if (@deletions) { + $resulttext .= '<li>'.&mt("Overrides based on requester's affiliation discontinued for: [_1]", + join(', ',@deletions)).'</li>'; + } + } my @offon = ('off','on'); + my $corelink = &core_link_msu(); if ($changes{'reporterrors'}) { $resulttext .= '<li>'. &mt('E-mail error reports to [_1] set to "'. $offon[$env{'form.reporterrors'}].'".', - &Apache::loncommon::modal_link('http://loncapa.org/core.html', - &mt('LON-CAPA core group - MSU'),600,500)). + $corelink). '</li>'; } if ($changes{'reportupdates'}) { $resulttext .= '<li>'. &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'. $offon[$env{'form.reportupdates'}].'".', - &Apache::loncommon::modal_link('http://loncapa.org/core.html', - &mt('LON-CAPA core group - MSU'),600,500)). + $corelink). + '</li>'; + } + if ($changes{'reportstatus'}) { + $resulttext .= '<li>'. + &mt('E-mail status if errors above threshold to [_1] set to "'. + $offon[$env{'form.reportstatus'}].'".', + $corelink). '</li>'; } + if (ref($changes{'lonstatus'}) eq 'ARRAY') { + $resulttext .= '<li>'. + &mt('Nightly status check e-mail settings').':<ul>'; + my (%defval,%use_def,%shown); + $defval{'threshold'} = $lonstatus_defs->{'threshold'}; + $defval{'sysmail'} = $lonstatus_defs->{'sysmail'}; + $defval{'weights'} = + join(', ',map { $lonstatus_names->{$_}.'='.$lonstatus_defs->{$_}; } ('E','W','N','U')); + $defval{'excluded'} = &mt('None'); + if (ref($contacts_hash{'contacts'}{'lonstatus'}) eq 'HASH') { + foreach my $item ('threshold','sysmail','weights','excluded') { + if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item})) { + if (($item eq 'threshold') || ($item eq 'sysmail')) { + $shown{$item} = $contacts_hash{'contacts'}{'lonstatus'}{$item}; + } elsif ($item eq 'weights') { + if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'HASH') { + foreach my $type ('E','W','N','U') { + $shown{$item} .= $lonstatus_names->{$type}.'='; + if (exists($contacts_hash{'contacts'}{'lonstatus'}{$item}{$type})) { + $shown{$item} .= $contacts_hash{'contacts'}{'lonstatus'}{$item}{$type}; + } else { + $shown{$item} .= $lonstatus_defs->{$type}; + } + $shown{$item} .= ', '; + } + $shown{$item} =~ s/, $//; + } else { + $shown{$item} = $defval{$item}; + } + } elsif ($item eq 'excluded') { + if (ref($contacts_hash{'contacts'}{'lonstatus'}{$item}) eq 'ARRAY') { + $shown{$item} = join(', ',@{$contacts_hash{'contacts'}{'lonstatus'}{$item}}); + } else { + $shown{$item} = $defval{$item}; + } + } + } else { + $shown{$item} = $defval{$item}; + } + } + } else { + foreach my $item ('threshold','weights','excluded','sysmail') { + $shown{$item} = $defval{$item}; + } + } + foreach my $item ('threshold','weights','excluded','sysmail') { + $resulttext .= '<li>'.&mt($titles->{'error'.$item}.' -- [_1]', + $shown{$item}).'</li>'; + } + $resulttext .= '</ul></li>'; + } if ((ref($changes{'helpform'}) eq 'ARRAY') && (ref($fields) eq 'ARRAY')) { my (@optional,@required,@unused,$maxsizechg); foreach my $field (@{$changes{'helpform'}}) { @@ -10914,7 +13369,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'}). '</li>'; - } } $resulttext .= '</ul>'; @@ -10937,12 +13391,10 @@ sub modify_usercreation { if ($key eq 'cancreate') { if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') { foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) { - if (($item eq 'selfcreate') || ($item eq 'statustocreate') || - ($item eq 'captcha') || ($item eq 'recaptchakeys') || - ($item eq 'recaptchaversion')) { - $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; - } else { + if (($item eq 'requestcrs') || ($item eq 'course') || ($item eq 'author')) { $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; + } else { + $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; } } } @@ -11014,7 +13466,7 @@ sub modify_usercreation { } my @authen_contexts = ('author','course','domain'); - my @authtypes = ('int','krb4','krb5','loc'); + my @authtypes = ('int','krb4','krb5','loc','lti'); my %authhash; foreach my $item (@authen_contexts) { my @authallowed = &Apache::loncommon::get_env_multiple('form.'.$item.'_auth'); @@ -11145,14 +13597,18 @@ sub modify_usercreation { } sub modify_selfcreation { - my ($dom,%domconfig) = @_; - my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%changes,%cancreate); - my (%save_usercreate,%save_usermodify); - my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); - if (ref($types) eq 'ARRAY') { - $usertypes->{'default'} = $othertitle; - push(@{$types},'default'); + my ($dom,$lastactref,%domconfig) = @_; + my ($resulttext,$warningmsg,%curr_usercreation,%curr_usermodify,%curr_inststatus,%changes,%cancreate); + my (%save_usercreate,%save_usermodify,%save_inststatus,@types,%usertypes); + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); + my ($othertitle,$usertypesref,$typesref) = &Apache::loncommon::sorted_inst_types($dom); + if (ref($typesref) eq 'ARRAY') { + @types = @{$typesref}; } + if (ref($usertypesref) eq 'HASH') { + %usertypes = %{$usertypesref}; + } + $usertypes{'default'} = $othertitle; # # Retrieve current domain configuration for self-creation of usernames from $domconfig{'usercreation'}. # @@ -11162,10 +13618,11 @@ sub modify_selfcreation { if (ref($domconfig{'usercreation'}{$key}) eq 'HASH') { foreach my $item (keys(%{$domconfig{'usercreation'}{$key}})) { if (($item eq 'selfcreate') || ($item eq 'statustocreate') || - ($item eq 'captcha') || ($item eq 'recaptchakeys') || - ($item eq 'recaptchaversion') || - ($item eq 'emailusername') || ($item eq 'notify') || - ($item eq 'selfcreateprocessing') || ($item eq 'shibenv')) { + ($item eq 'captcha') || ($item eq 'recaptchakeys') || + ($item eq 'recaptchaversion') || ($item eq 'notify') || + ($item eq 'emailusername') || ($item eq 'shibenv') || + ($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || + ($item eq 'emailoptions') || ($item eq 'emaildomain')) { $curr_usercreation{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; } else { $save_usercreate{$key}{$item} = $domconfig{'usercreation'}{$key}{$item}; @@ -11191,41 +13648,160 @@ sub modify_selfcreation { } } } +# +# Retrieve current domain configuration for institutional status types from $domconfig{'inststatus'}. +# + if (ref($domconfig{'inststatus'}) eq 'HASH') { + foreach my $key (keys(%{$domconfig{'inststatus'}})) { + if ($key eq 'inststatusguest') { + $curr_inststatus{$key} = $domconfig{'inststatus'}{$key}; + } else { + $save_inststatus{$key} = $domconfig{'inststatus'}{$key}; + } + } + } my @contexts = ('selfcreate'); @{$cancreate{'selfcreate'}} = (); %{$cancreate{'emailusername'}} = (); - @{$cancreate{'statustocreate'}} = (); + if (@types) { + @{$cancreate{'statustocreate'}} = (); + } %{$cancreate{'selfcreateprocessing'}} = (); %{$cancreate{'shibenv'}} = (); + %{$cancreate{'emailverified'}} = (); + %{$cancreate{'emailoptions'}} = (); + %{$cancreate{'emaildomain'}} = (); my %selfcreatetypes = ( sso => 'users authenticated by institutional single sign on', login => 'users authenticated by institutional log-in', - email => 'users who provide a valid e-mail address for use as username', + email => 'users verified by e-mail', ); # # Populate $cancreate{'selfcreate'} array reference with types of user, for which self-creation of user accounts # is permitted. # + my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email'); - my @statuses; - if (ref($domconfig{'inststatus'}) eq 'HASH') { - if (ref($domconfig{'inststatus'}{'inststatusguest'}) eq 'ARRAY') { - @statuses = @{$domconfig{'inststatus'}{'inststatusguest'}}; - } - } - push(@statuses,'default'); - + my (@statuses,%email_rule); foreach my $item ('login','sso','email') { if ($item eq 'email') { if ($env{'form.cancreate_email'}) { - push(@{$cancreate{'selfcreate'}},'email'); - push(@contexts,'selfcreateprocessing'); - foreach my $type (@statuses) { - if ($type eq 'default') { - $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess'}; - } else { - $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type}; + if (@types) { + my @poss_statuses = &Apache::loncommon::get_env_multiple('form.selfassign'); + foreach my $status (@poss_statuses) { + if (grep(/^\Q$status\E$/,(@types,'default'))) { + push(@statuses,$status); + } + } + $save_inststatus{'inststatusguest'} = \@statuses; + } else { + push(@statuses,'default'); + } + if (@statuses) { + my %curr_rule; + if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') { + foreach my $type (@statuses) { + $curr_rule{$type} = $curr_usercreation{'email_rule'}; + } + } elsif (ref($curr_usercreation{'email_rule'}) eq 'HASH') { + foreach my $type (@statuses) { + $curr_rule{$type} = $curr_usercreation{'email_rule'}{$type}; + } + } + push(@{$cancreate{'selfcreate'}},'email'); + push(@contexts,('selfcreateprocessing','emailverified','emailoptions')); + my %curremaildom; + if (ref($curr_usercreation{'cancreate'}{'emaildomain'}) eq 'HASH') { + %curremaildom = %{$curr_usercreation{'cancreate'}{'emaildomain'}}; + } + foreach my $type (@statuses) { + if ($env{'form.cancreate_emailprocess_'.$type} =~ /^(?:approval|automatic)$/) { + $cancreate{'selfcreateprocessing'}{$type} = $env{'form.cancreate_emailprocess_'.$type}; + } + if ($env{'form.cancreate_usernameoptions_'.$type} =~ /^(?:all|first|free)$/) { + $cancreate{'emailverified'}{$type} = $env{'form.cancreate_usernameoptions_'.$type}; + } + if ($env{'form.cancreate_emailoptions_'.$type} =~ /^(any|inst|noninst|custom)$/) { +# +# Retrieve rules (if any) governing types of e-mail address which may be used to verify a username. +# + my $chosen = $1; + if (($chosen eq 'inst') || ($chosen eq 'noninst')) { + my $emaildom; + if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) { + $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; + $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom; + if (ref($curremaildom{$type}) eq 'HASH') { + if (exists($curremaildom{$type}{$chosen})) { + if ($curremaildom{$type}{$chosen} ne $emaildom) { + push(@{$changes{'cancreate'}},'emaildomain'); + } + } elsif ($emaildom ne '') { + push(@{$changes{'cancreate'}},'emaildomain'); + } + } elsif ($emaildom ne '') { + push(@{$changes{'cancreate'}},'emaildomain'); + } + } + $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type}; + } elsif ($chosen eq 'custom') { + my @possemail_rules = &Apache::loncommon::get_env_multiple('form.email_rule_'.$type); + $email_rule{$type} = []; + if (ref($emailrules) eq 'HASH') { + foreach my $rule (@possemail_rules) { + if (exists($emailrules->{$rule})) { + push(@{$email_rule{$type}},$rule); + } + } + } + if (@{$email_rule{$type}}) { + $cancreate{'emailoptions'}{$type} = 'custom'; + if (ref($curr_rule{$type}) eq 'ARRAY') { + if (@{$curr_rule{$type}} > 0) { + foreach my $rule (@{$curr_rule{$type}}) { + if (!grep(/^\Q$rule\E$/,@{$email_rule{$type}})) { + push(@{$changes{'email_rule'}},$type); + } + } + } + foreach my $type (@{$email_rule{$type}}) { + if (!grep(/^\Q$type\E$/,@{$curr_rule{$type}})) { + push(@{$changes{'email_rule'}},$type); + } + } + } else { + push(@{$changes{'email_rule'}},$type); + } + } + } else { + $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type}; + } + } + } + if (@types) { + if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') { + my @changed = &Apache::loncommon::compare_arrays(\@statuses,$curr_inststatus{'inststatusguest'}); + if (@changed) { + push(@{$changes{'inststatus'}},'inststatusguest'); + } + } else { + push(@{$changes{'inststatus'}},'inststatusguest'); + } + } + } else { + delete($env{'form.cancreate_email'}); + if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') { + if (@{$curr_inststatus{'inststatusguest'}} > 0) { + push(@{$changes{'inststatus'}},'inststatusguest'); + } + } + } + } else { + $save_inststatus{'inststatusguest'} = []; + if (ref($curr_inststatus{'inststatusguest'}) eq 'ARRAY') { + if (@{$curr_inststatus{'inststatusguest'}} > 0) { + push(@{$changes{'inststatus'}},'inststatusguest'); } } } @@ -11235,7 +13811,7 @@ sub modify_selfcreation { } } } - my (@email_rule,%userinfo,%savecaptcha); + my (%userinfo,%savecaptcha); my ($infofields,$infotitles) = &Apache::loncommon::emailusername_info(); # # Populate $cancreate{'emailusername'}{$type} hash ref with information fields (if new user will provide data @@ -11244,8 +13820,8 @@ sub modify_selfcreation { if ($env{'form.cancreate_email'}) { push(@contexts,'emailusername'); - if (ref($types) eq 'ARRAY') { - foreach my $type (@{$types}) { + if (@statuses) { + foreach my $type (@statuses) { if (ref($infofields) eq 'ARRAY') { foreach my $field (@{$infofields}) { if ($env{'form.canmodify_emailusername_'.$type.'_'.$field} =~ /^(required|optional)$/) { @@ -11257,7 +13833,7 @@ sub modify_selfcreation { } # # Populate $cancreate{'notify'} hash ref with names of Domain Coordinators who are to be notified of -# queued requests for self-creation of account using e-mail address as username +# queued requests for self-creation of account verified by e-mail. # my @approvalnotify = &Apache::loncommon::get_env_multiple('form.selfcreationnotifyapproval'); @@ -11277,36 +13853,13 @@ sub modify_selfcreation { push(@{$changes{'cancreate'}},'notify'); } -# -# Retrieve rules (if any) governing types of e-mail address which may be used as a username -# - @email_rule = &Apache::loncommon::get_env_multiple('form.email_rule'); &process_captcha('cancreate',\%changes,\%savecaptcha,$curr_usercreation{'cancreate'}); - if (ref($curr_usercreation{'email_rule'}) eq 'ARRAY') { - if (@{$curr_usercreation{'email_rule'}} > 0) { - foreach my $type (@{$curr_usercreation{'email_rule'}}) { - if (!grep(/^\Q$type\E$/,@email_rule)) { - push(@{$changes{'email_rule'}},$type); - } - } - } - if (@email_rule > 0) { - foreach my $type (@email_rule) { - if (!grep(/^\Q$type\E$/,@{$curr_usercreation{'email_rule'}})) { - push(@{$changes{'email_rule'}},$type); - } - } - } - } elsif (@email_rule > 0) { - push(@{$changes{'email_rule'}},@email_rule); - } } # # Check if domain default is set appropriately, if self-creation of accounts is to be available for # institutional log-in. # if (grep(/^login$/,@{$cancreate{'selfcreate'}})) { - my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) || ($domdefaults{'auth_def'} eq 'localauth'))) { $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '. @@ -11325,14 +13878,10 @@ sub modify_selfcreation { # which the user may supply, if institutional data is unavailable. # if (($env{'form.cancreate_login'}) || ($env{'form.cancreate_sso'})) { - if (ref($types) eq 'ARRAY') { - if (@{$types} > 1) { - @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate'); - push(@contexts,'statustocreate'); - } else { - undef($cancreate{'statustocreate'}); - } - foreach my $type (@{$types}) { + if (@types) { + @{$cancreate{'statustocreate'}} = &Apache::loncommon::get_env_multiple('form.statustocreate'); + push(@contexts,'statustocreate'); + foreach my $type (@types) { my @modifiable = &Apache::loncommon::get_env_multiple('form.canmodify_'.$type); foreach my $field (@fields) { if (grep(/^\Q$field\E$/,@modifiable)) { @@ -11343,7 +13892,7 @@ sub modify_selfcreation { } } if (ref($curr_usermodify{'selfcreate'}) eq 'HASH') { - foreach my $type (@{$types}) { + foreach my $type (@types) { if (ref($curr_usermodify{'selfcreate'}{$type}) eq 'HASH') { foreach my $field (@fields) { if ($save_usermodify{'selfcreate'}{$type}{$field} ne @@ -11355,7 +13904,7 @@ sub modify_selfcreation { } } } else { - foreach my $type (@{$types}) { + foreach my $type (@types) { push(@{$changes{'selfcreate'}},$type); } } @@ -11404,34 +13953,28 @@ sub modify_selfcreation { } } elsif (ref($curr_usercreation{'cancreate'}{$item}) eq 'HASH') { if (ref($cancreate{$item}) eq 'HASH') { - foreach my $curr (keys(%{$curr_usercreation{'cancreate'}{$item}})) { - if (ref($curr_usercreation{'cancreate'}{$item}{$curr}) eq 'HASH') { - foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$curr}})) { - unless ($curr_usercreation{'cancreate'}{$item}{$curr}{$field} eq $cancreate{$item}{$curr}{$field}) { + foreach my $type (keys(%{$curr_usercreation{'cancreate'}{$item}})) { + if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') { + foreach my $field (keys(%{$curr_usercreation{'cancreate'}{$item}{$type}})) { + unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) { if (!grep(/^$item$/,@{$changes{'cancreate'}})) { push(@{$changes{'cancreate'}},$item); } } } - } elsif ($item eq 'selfcreateprocessing') { - if ($cancreate{$item}{$curr} ne $curr_usercreation{'cancreate'}{$item}{$curr}) { - if (!grep(/^$item$/,@{$changes{'cancreate'}})) { - push(@{$changes{'cancreate'}},$item); - } - } - } else { - if (!$cancreate{$item}{$curr}) { + } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) { + if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) { if (!grep(/^$item$/,@{$changes{'cancreate'}})) { push(@{$changes{'cancreate'}},$item); } } } } - foreach my $field (keys(%{$cancreate{$item}})) { - if (ref($cancreate{$item}{$field}) eq 'HASH') { - foreach my $inner (keys(%{$cancreate{$item}{$field}})) { - if (ref($curr_usercreation{'cancreate'}{$item}{$field}) eq 'HASH') { - unless ($curr_usercreation{'cancreate'}{$item}{$field}{$inner} eq $cancreate{$item}{$field}{$inner}) { + foreach my $type (keys(%{$cancreate{$item}})) { + if (ref($cancreate{$item}{$type}) eq 'HASH') { + foreach my $field (keys(%{$cancreate{$item}{$type}})) { + if (ref($curr_usercreation{'cancreate'}{$item}{$type}) eq 'HASH') { + unless ($curr_usercreation{'cancreate'}{$item}{$type}{$field} eq $cancreate{$item}{$type}{$field}) { if (!grep(/^$item$/,@{$changes{'cancreate'}})) { push(@{$changes{'cancreate'}},$item); } @@ -11442,14 +13985,8 @@ sub modify_selfcreation { } } } - } elsif ($item eq 'selfcreateprocessing') { - if ($cancreate{$item}{$field} ne $curr_usercreation{'cancreate'}{$item}{$field}) { - if (!grep(/^$item$/,@{$changes{'cancreate'}})) { - push(@{$changes{'cancreate'}},$item); - } - } - } else { - if (!$curr_usercreation{'cancreate'}{$item}{$field}) { + } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) { + if ($cancreate{$item}{$type} ne $curr_usercreation{'cancreate'}{$item}{$type}) { if (!grep(/^$item$/,@{$changes{'cancreate'}})) { push(@{$changes{'cancreate'}},$item); } @@ -11464,11 +14001,11 @@ sub modify_selfcreation { push(@{$changes{'cancreate'}},$item); } } - } elsif (ref($cancreate{$item}) eq 'HASH') { - if (!$cancreate{$item}{$curr_usercreation{'cancreate'}{$item}}) { - if (!grep(/^$item$/,@{$changes{'cancreate'}})) { - push(@{$changes{'cancreate'}},$item); - } + } + } elsif (($item eq 'selfcreateprocessing') || ($item eq 'emailverified') || ($item eq 'emailoptions')) { + if (ref($cancreate{$item}) eq 'HASH') { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); } } } elsif ($item eq 'emailusername') { @@ -11501,6 +14038,15 @@ sub modify_selfcreation { if (ref($cancreate{'selfcreateprocessing'}) eq 'HASH') { $save_usercreate{'cancreate'}{'selfcreateprocessing'} = $cancreate{'selfcreateprocessing'}; } + if (ref($cancreate{'emailverified'}) eq 'HASH') { + $save_usercreate{'cancreate'}{'emailverified'} = $cancreate{'emailverified'}; + } + if (ref($cancreate{'emailoptions'}) eq 'HASH') { + $save_usercreate{'cancreate'}{'emailoptions'} = $cancreate{'emailoptions'}; + } + if (ref($cancreate{'emaildomain'}) eq 'HASH') { + $save_usercreate{'cancreate'}{'emaildomain'} = $cancreate{'emaildomain'}; + } if (ref($cancreate{'statustocreate'}) eq 'ARRAY') { $save_usercreate{'cancreate'}{'statustocreate'} = $cancreate{'statustocreate'}; } @@ -11508,16 +14054,18 @@ 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, usermodification => \%save_usermodify, + inststatus => \%save_inststatus, ); + my $putresult = &Apache::lonnet::put_dom('configuration',\%userconfig_hash, $dom); # -# Accumulate details of changes to domain cofiguration for self-creation of usernames in $resulttext +# Accumulate details of changes to domain configuration for self-creation of usernames in $resulttext # if ($putresult eq 'ok') { if (keys(%changes) > 0) { @@ -11525,7 +14073,7 @@ sub modify_selfcreation { if (ref($changes{'cancreate'}) eq 'ARRAY') { my %lt = &selfcreation_types(); foreach my $type (@{$changes{'cancreate'}}) { - my $chgtext; + my $chgtext = ''; if ($type eq 'selfcreate') { if (@{$cancreate{$type}} == 0) { $chgtext .= &mt('Self creation of a new user account is not permitted.'); @@ -11540,18 +14088,25 @@ sub modify_selfcreation { if (grep(/^(login|sso)$/,@{$cancreate{$type}})) { if (ref($cancreate{'statustocreate'}) eq 'ARRAY') { if (@{$cancreate{'statustocreate'}} == 0) { - $chgtext .= '<br />'. - '<span class="LC_warning">'. - &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts."). - '</span>'; + $chgtext .= '<span class="LC_warning">'. + &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts via log-in or single sign-on."). + '</span><br />'; } } } + if (grep(/^email$/,@{$cancreate{$type}})) { + if (!@statuses) { + $chgtext .= '<span class="LC_warning">'. + &mt("However, e-mail verification is currently set to 'unavailable' for all user types (including 'other'), so self-creation of accounts is not possible for non-institutional log-in."). + '</span><br />'; + + } + } } } } elsif ($type eq 'shibenv') { if (keys(%{$cancreate{$type}}) == 0) { - $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information'); + $chgtext .= &mt('Shibboleth-autheticated user does not use environment variables to set user information').'<br />'; } else { $chgtext .= &mt('Shibboleth-autheticated user information set from environment variables, as follows:'). '<ul>'; @@ -11564,7 +14119,7 @@ sub modify_selfcreation { } } $chgtext .= '</ul>'; - } + } } elsif ($type eq 'statustocreate') { if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') && (ref($cancreate{'statustocreate'}) eq 'ARRAY')) { @@ -11577,7 +14132,7 @@ sub modify_selfcreation { &mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts."). '</span>'; } - } elsif (ref($usertypes) eq 'HASH') { + } elsif (keys(%usertypes) > 0) { if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) { $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):'); } else { @@ -11588,12 +14143,12 @@ sub modify_selfcreation { if ($case eq 'default') { $chgtext .= '<li>'.$othertitle.'</li>'; } else { - $chgtext .= '<li>'.$usertypes->{$case}.'</li>'; + $chgtext .= '<li>'.$usertypes{$case}.'</li>'; } } $chgtext .= '</ul>'; if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) { - $chgtext .= '<br /><span class="LC_warning">'. + $chgtext .= '<span class="LC_warning">'. &mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.'). '</span>'; } @@ -11605,26 +14160,129 @@ sub modify_selfcreation { $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.'); } } + $chgtext .= '<br />'; } } elsif ($type eq 'selfcreateprocessing') { my %choices = &Apache::lonlocal::texthash ( automatic => 'Automatic approval', approval => 'Queued for approval', ); - if (@statuses > 1) { - $chgtext .= &mt('Processing of requests to create account with e-mail address as username set as follows:'). - '<ul>'; - foreach my $type (@statuses) { - if ($type eq 'default') { - $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$type}}.'</li>'; - } else { - $chgtext .= '<li>'.$usertypes->{$type}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$type}}.'</li>'; - } - } - $chgtext .= '</ul>'; + if (@types) { + if (@statuses) { + $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). + '<ul>'; + foreach my $status (@statuses) { + if ($status eq 'default') { + $chgtext .= '<li>'.$othertitle.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>'; + } else { + $chgtext .= '<li>'.$usertypes{$status}.' -- '.$choices{$cancreate{'selfcreateprocessing'}{$status}}.'</li>'; + } + } + $chgtext .= '</ul>'; + } + } else { + $chgtext .= &mt('Processing of requests to create account with e-mail verification set to: "[_1]"', + $choices{$cancreate{'selfcreateprocessing'}{'default'}}); + } + } elsif ($type eq 'emailverified') { + my %options = &Apache::lonlocal::texthash ( + all => 'Same as e-mail', + first => 'Omit @domain', + free => 'Free to choose', + ); + if (@types) { + if (@statuses) { + $chgtext .= &mt('For self-created accounts verified by e-mail address, username is set as follows:'). + '<ul>'; + foreach my $status (@statuses) { + if ($type eq 'default') { + $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>'; + } else { + $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailverified'}{$status}}.'</li>'; + } + } + $chgtext .= '</ul>'; + } + } else { + $chgtext .= &mt("For self-created accounts verified by e-mail address, user's username is: '[_1]'", + $options{$cancreate{'emailverified'}{'default'}}); + } + } elsif ($type eq 'emailoptions') { + my %options = &Apache::lonlocal::texthash ( + any => 'Any e-mail', + inst => 'Institutional only', + noninst => 'Non-institutional only', + custom => 'Custom restrictions', + ); + if (@types) { + if (@statuses) { + $chgtext .= &mt('For self-created accounts verified by e-mail address, requirements for e-mail address are as follows:'). + '<ul>'; + foreach my $status (@statuses) { + if ($type eq 'default') { + $chgtext .= '<li>'.$othertitle.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>'; + } else { + $chgtext .= '<li>'.$usertypes{$status}.' -- '.$options{$cancreate{'emailoptions'}{$status}}.'</li>'; + } + } + $chgtext .= '</ul>'; + } } else { - $chgtext .= &mt('Processing of requests to create account with e-mail address as username set to: "[_1]"', - $choices{$cancreate{'selfcreateprocessing'}{'default'}}); + if ($cancreate{'emailoptions'}{'default'} eq 'any') { + $chgtext .= &mt('For self-created accounts verified by e-mail address, any e-mail may be used'); + } else { + $chgtext .= &mt('For self-created accounts verified by e-mail address, e-mail restricted to: "[_1]"', + $options{$cancreate{'emailoptions'}{'default'}}); + } + } + } elsif ($type eq 'emaildomain') { + my $output; + if (@statuses) { + foreach my $type (@statuses) { + if (ref($cancreate{'emaildomain'}{$type}) eq 'HASH') { + if ($cancreate{'emailoptions'}{$type} eq 'inst') { + if ($type eq 'default') { + if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || + ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) { + $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>'; + } else { + $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address needs to end: [_1]", + $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; + } + } else { + if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || + ($cancreate{'emaildomain'}{$type}{'inst'} eq '')) { + $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>'; + } else { + $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address needs to end: [_1]", + $cancreate{'emaildomain'}{$type}{'inst'}).'</li>'; + } + } + } elsif ($cancreate{'emailoptions'}{$type} eq 'noninst') { + if ($type eq 'default') { + if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || + ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) { + $output = '<li>'.$othertitle.' -- '.&mt('No restriction on e-mail domain').'</li>'; + } else { + $output = '<li>'.$othertitle.' -- '.&mt("User's e-mail address must not end: [_1]", + $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>'; + } + } else { + if ((ref($cancreate{'emaildomain'}{$type}) ne 'HASH') || + ($cancreate{'emaildomain'}{$type}{'noninst'} eq '')) { + $output = '<li>'.$usertypes{$type}.' -- '.&mt('No restriction on e-mail domain').'</li>'; + } else { + $output = '<li>'.$usertypes{$type}.' -- '.&mt("User's e-mail address must not end: [_1]", + $cancreate{'emaildomain'}{$type}{'noninst'}).'</li>'; + } + } + } + } + } + } + if ($output ne '') { + $chgtext .= &mt('For self-created accounts verified by e-mail address:'). + '<ul>'.$output.'</ul>'; } } elsif ($type eq 'captcha') { if ($savecaptcha{$type} eq 'notused') { @@ -11661,11 +14319,11 @@ sub modify_selfcreation { } } elsif ($type eq 'emailusername') { if (ref($cancreate{'emailusername'}) eq 'HASH') { - if (ref($types) eq 'ARRAY') { - foreach my $type (@{$types}) { + if (@statuses) { + foreach my $type (@statuses) { if (ref($cancreate{'emailusername'}{$type}) eq 'HASH') { if (keys(%{$cancreate{'emailusername'}{$type}}) > 0) { - $chgtext .= &mt('When self-creating account with e-mail as username, the following information will be provided by [_1]:',"'$usertypes->{$type}'"). + $chgtext .= &mt('When self-creating account with e-mail verification, the following information will be provided by [_1]:',"'$usertypes{$type}'"). '<ul>'; foreach my $field (@{$infofields}) { if ($cancreate{'emailusername'}{$type}{$field}) { @@ -11674,48 +14332,86 @@ sub modify_selfcreation { } $chgtext .= '</ul>'; } else { - $chgtext .= &mt('When self creating account with e-mail as username, no information besides e-mail address will be provided by [_1].',"'$usertypes->{$type}'").'<br />'; + $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />'; } } else { - $chgtext .= &mt('When self creating account with e-mail as username, no information besides e-mail address will be provided by [_1].',"'$usertypes->{$type}'").'<br />'; + $chgtext .= &mt('When self creating account with e-mail verification, no information besides e-mail address will be provided by [_1].',"'$usertypes{$type}'").'<br />'; } } } } } elsif ($type eq 'notify') { - $chgtext = &mt('No Domain Coordinators will receive notification of username requests requiring approval.'); + my $numapprove = 0; if (ref($changes{'cancreate'}) eq 'ARRAY') { if ((grep(/^notify$/,@{$changes{'cancreate'}})) && (ref($cancreate{'notify'}) eq 'HASH')) { if ($cancreate{'notify'}{'approval'}) { - $chgtext = &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'}; + $chgtext .= &mt('Notification of username requests requiring approval will be sent to: ').$cancreate{'notify'}{'approval'}; + $numapprove ++; } } } + unless ($numapprove) { + $chgtext .= &mt('No Domain Coordinators will receive notification of username requests requiring approval.'); + } } if ($chgtext) { $resulttext .= '<li>'.$chgtext.'</li>'; } } } - if (ref($changes{'email_rule'}) eq 'ARRAY') { + if ((ref($changes{'email_rule'}) eq 'ARRAY') && (@{$changes{'email_rule'}} > 0)) { my ($emailrules,$emailruleorder) = &Apache::lonnet::inst_userrules($dom,'email'); - my $chgtext = '<ul>'; - foreach my $type (@email_rule) { - if (ref($emailrules->{$type}) eq 'HASH') { - $chgtext .= '<li>'.$emailrules->{$type}{'name'}.'</li>'; + foreach my $type (@{$changes{'email_rule'}}) { + if (ref($email_rule{$type}) eq 'ARRAY') { + my $chgtext = '<ul>'; + foreach my $rule (@{$email_rule{$type}}) { + if (ref($emailrules->{$rule}) eq 'HASH') { + $chgtext .= '<li>'.$emailrules->{$rule}{'name'}.'</li>'; + } + } + $chgtext .= '</ul>'; + my $typename; + if (@types) { + if ($type eq 'default') { + $typename = $othertitle; + } else { + $typename = $usertypes{$type}; + } + $chgtext .= &mt('(Affiliation: [_1])',$typename); + } + if (@{$email_rule{$type}} > 0) { + $resulttext .= '<li>'. + &mt('Accounts may not be created by users verified by e-mail, for e-mail addresses of the following types: ', + $usertypes{$type}). + $chgtext. + '</li>'; + } else { + $resulttext .= '<li>'. + &mt('There are now no restrictions on e-mail addresses which may be used for verification when a user requests an account.'). + '</li>'. + &mt('(Affiliation: [_1])',$typename); + } } } - $chgtext .= '</ul>'; - if (@email_rule > 0) { - $resulttext .= '<li>'. - &mt('Accounts may not be created by users self-enrolling with e-mail addresses of the following types: '). - $chgtext. - '</li>'; - } else { - $resulttext .= '<li>'. - &mt('There are now no restrictions on e-mail addresses which may be used as a username when self-enrolling.'). - '</li>'; + } + if (ref($changes{'inststatus'}) eq 'ARRAY') { + if (ref($save_inststatus{'inststatusguest'}) eq 'ARRAY') { + if (@{$save_inststatus{'inststatusguest'}} > 0) { + my $chgtext = '<ul>'; + foreach my $type (@{$save_inststatus{'inststatusguest'}}) { + $chgtext .= '<li>'.$usertypes{$type}.'</li>'; + } + $chgtext .= '</ul>'; + $resulttext .= '<li>'. + &mt('A user will self-report one of the following affiliations when requesting an account verified by e-mail: '). + $chgtext. + '</li>'; + } else { + $resulttext .= '<li>'. + &mt('No affiliations available for self-reporting when requesting an account verified by e-mail.'). + '</li>'; + } } } if (ref($changes{'selfcreate'}) eq 'ARRAY') { @@ -11723,9 +14419,9 @@ sub modify_selfcreation { my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); foreach my $type (@{$changes{'selfcreate'}}) { my $typename = $type; - if (ref($usertypes) eq 'HASH') { - if ($usertypes->{$type} ne '') { - $typename = $usertypes->{$type}; + if (keys(%usertypes) > 0) { + if ($usertypes{$type} ne '') { + $typename = $usertypes{$type}; } } my @modifiable; @@ -11748,6 +14444,12 @@ sub modify_selfcreation { $resulttext .= '</ul></li>'; } $resulttext .= '</ul>'; + my $cachetime = 24*60*60; + $domdefaults{'inststatusguest'} = $save_inststatus{'inststatusguest'}; + &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); + if (ref($lastactref) eq 'HASH') { + $lastactref->{'domdefaults'} = 1; + } } else { $resulttext = &mt('No changes made to self-creation settings'); } @@ -11946,7 +14648,7 @@ sub modify_defaults { my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def', 'portal_def','intauth_cost','intauth_check','intauth_switch'); - my @authtypes = ('internal','krb4','krb5','localauth'); + my @authtypes = ('internal','krb4','krb5','localauth','lti'); foreach my $item (@items) { $newvalues{$item} = $env{'form.'.$item}; if ($item eq 'auth_def') { @@ -12031,9 +14733,16 @@ sub modify_defaults { } my @todelete = &Apache::loncommon::get_env_multiple('form.inststatus_delete'); my @allpos; - my %guests; my %alltypes; - my ($currtitles,$currguests,$currorder); + my @inststatusguest; + if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') { + foreach my $type (@{$currinststatus->{'inststatusguest'}}) { + unless (grep(/^\Q$type\E$/,@todelete)) { + push(@inststatusguest,$type); + } + } + } + my ($currtitles,$currorder); if (ref($currinststatus) eq 'HASH') { if (ref($currinststatus->{'inststatusorder'}) eq 'ARRAY') { foreach my $type (@{$currinststatus->{'inststatusorder'}}) { @@ -12048,14 +14757,8 @@ sub modify_defaults { $allpos[$position] = $type; $alltypes{$type} = $env{'form.inststatus_title_'.$type}; $alltypes{$type} =~ s/`//g; - if ($env{'form.inststatus_guest_'.$type}) { - $guests{$type} = 1; - } } } - if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') { - $currguests = join(',',@{$currinststatus->{'inststatusguest'}}); - } $currorder = join(',',@{$currinststatus->{'inststatusorder'}}); $currtitles =~ s/,$//; } @@ -12064,9 +14767,6 @@ sub modify_defaults { my $newtype = $env{'form.addinststatus'}; $newtype =~ s/\W//g; unless (exists($alltypes{$newtype})) { - if ($env{'form.addinststatus_guest'}) { - $guests{$newtype} = 1; - } $alltypes{$newtype} = $env{'form.addinststatus_title'}; $alltypes{$newtype} =~ s/`//g; my $position = $env{'form.addinststatus_pos'}; @@ -12076,13 +14776,10 @@ sub modify_defaults { } } } - my (@orderedstatus,@orderedguests); + my @orderedstatus; foreach my $type (@allpos) { unless (($type eq '') || (grep(/^\Q$type\E$/,@orderedstatus))) { push(@orderedstatus,$type); - if ($guests{$type}) { - push(@orderedguests,$type); - } } } foreach my $type (keys(%alltypes)) { @@ -12093,7 +14790,7 @@ sub modify_defaults { $defaults_hash{'inststatus'} = { inststatustypes => \%alltypes, inststatusorder => \@orderedstatus, - inststatusguest => \@orderedguests, + inststatusguest => \@inststatusguest, }; if (ref($defaults_hash{'inststatus'}) eq 'HASH') { foreach my $item ('inststatustypes','inststatusorder','inststatusguest') { @@ -12103,9 +14800,6 @@ sub modify_defaults { if ($currorder ne join(',',@orderedstatus)) { $changes{'inststatus'}{'inststatusorder'} = 1; } - if ($currguests ne join(',',@orderedguests)) { - $changes{'inststatus'}{'inststatusguest'} = 1; - } my $newtitles; foreach my $item (@orderedstatus) { $newtitles .= $alltypes{$item}.','; @@ -12124,26 +14818,15 @@ sub modify_defaults { foreach my $item (sort(keys(%changes))) { if ($item eq 'inststatus') { if (ref($changes{'inststatus'}) eq 'HASH') { - if (($changes{'inststatus'}{'inststatustypes'}) || $changes{'inststatus'}{'inststatusorder'}) { + if (@orderedstatus) { $resulttext .= '<li>'.&mt('Institutional user status types set to:').' '; foreach my $type (@orderedstatus) { $resulttext .= $alltypes{$type}.', '; } $resulttext =~ s/, $//; $resulttext .= '</li>'; - } - if ($changes{'inststatus'}{'inststatusguest'}) { - $resulttext .= '<li>'; - if (@orderedguests) { - $resulttext .= &mt('Types assignable to "non-institutional" usernames set to:').' '; - foreach my $type (@orderedguests) { - $resulttext .= $alltypes{$type}.', '; - } - $resulttext =~ s/, $//; - } else { - $resulttext .= &mt('Types assignable to "non-institutional" usernames set to none.'); - } - $resulttext .= '</li>'; + } else { + $resulttext .= '<li>'.&mt('Institutional user status types deleted').'</li>'; } } } else { @@ -12157,6 +14840,7 @@ sub modify_defaults { krb4 => 'krb4', krb5 => 'krb5', localauth => 'loc', + lti => 'lti', ); $value = $authnames{$shortauth{$value}}; } elsif ($item eq 'intauth_switch') { @@ -12971,7 +15655,7 @@ sub modify_helpsettings { order => 'Order', desc => 'Role description', access => 'Role usage', - status => 'Allowed instituional types', + status => 'Allowed institutional types', exc => 'Allowed personnel', inc => 'Disallowed personnel', ); @@ -13070,7 +15754,11 @@ sub modify_coursedefaults { postsubmit => 60, mysqltables => 172800, ); - + my %texoptions = ( + MathJax => 'MathJax', + mimetex => &mt('Convert to Images'), + tth => &mt('TeX to HTML'), + ); $defaultshash{'coursedefaults'} = {}; if (ref($domconfig{'coursedefaults'}) ne 'HASH') { @@ -13130,6 +15818,20 @@ sub modify_coursedefaults { } } } + my $texengine; + if ($env{'form.texengine'} =~ /^(MathJax|mimetex|tth)$/) { + $texengine = $env{'form.texengine'}; + if ($defaultshash{'coursedefaults'}{'texengine'} eq '') { + unless ($texengine eq 'MathJax') { + $changes{'texengine'} = 1; + } + } elsif ($defaultshash{'coursedefaults'}{'texengine'} ne $texengine) { + $changes{'texengine'} = 1; + } + } + if ($texengine ne '') { + $defaultshash{'coursedefaults'}{'texengine'} = $texengine; + } my $currclone = $domconfig{'coursedefaults'}{'canclone'}; my @currclonecode; if (ref($currclone) eq 'HASH') { @@ -13250,8 +15952,8 @@ sub modify_coursedefaults { my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) || ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) || - ($changes{'canclone'}) || ($changes{'mysqltables'})) { - foreach my $item ('canuse_pdfforms','uselcmath','usejsme') { + ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'})) { + foreach my $item ('canuse_pdfforms','uselcmath','usejsme','texengine') { if ($changes{$item}) { $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item}; } @@ -13320,6 +16022,11 @@ sub modify_coursedefaults { } else { $resulttext .= '<li>'.&mt('Molecule editor uses JME (Java), if supported by client OS.').'</li>'; } + } elsif ($item eq 'texengine') { + if ($defaultshash{'coursedefaults'}{'texengine'} ne '') { + $resulttext .= '<li>'.&mt('Default method to display mathematics set to: "[_1]"', + $texoptions{$defaultshash{'coursedefaults'}{'texengine'}}).'</li>'; + } } elsif ($item eq 'anonsurvey_threshold') { $resulttext .= '<li>'.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'</li>'; } elsif ($item eq 'uploadquota') { @@ -13647,12 +16354,12 @@ sub modify_selfenrollment { $resulttext .= '</ul></li>'; } } - if ((exists($changes{'admin'})) || (exists($changes{'default'}))) { - my $cachetime = 24*60*60; - &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); - if (ref($lastactref) eq 'HASH') { - $lastactref->{'domdefaults'} = 1; - } + } + if ((exists($changes{'admin'})) || (exists($changes{'default'}))) { + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); + if (ref($lastactref) eq 'HASH') { + $lastactref->{'domdefaults'} = 1; } } $resulttext .= '</ul>'; @@ -13935,14 +16642,18 @@ sub modify_usersessions { } else { foreach my $type (@{$types{$prefix}}) { if (defined($changes{$prefix}{$type})) { - my $newvalue; + my ($newvalue,$notinuse); if (ref($defaultshash{'usersessions'}) eq 'HASH') { if (ref($defaultshash{'usersessions'}{$prefix})) { if ($type eq 'version') { $newvalue = $defaultshash{'usersessions'}{$prefix}{$type}; - } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') { - if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) { - $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}}); + } else { + if (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') { + if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) { + $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}}); + } + } else { + $notinuse = 1; } } } @@ -13950,12 +16661,14 @@ sub modify_usersessions { if ($newvalue eq '') { if ($type eq 'version') { $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>'; + } elsif ($notinuse) { + $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>'; } else { $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>'; } } else { if ($type eq 'version') { - $newvalue .= ' '.&mt('(or later)'); + $newvalue .= ' '.&mt('(or later)'); } $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>'; } @@ -14023,12 +16736,17 @@ sub modify_ssl { if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) { $value = $env{'form.'.$prefix.'_'.$type}; } - if (ref($domconfig{$action}{$prefix}) eq 'HASH') { - if ($domconfig{$action}{$prefix}{$type} ne '') { - if ($value ne $domconfig{$action}{$prefix}{$type}) { + if (ref($domconfig{$action}) eq 'HASH') { + if (ref($domconfig{$action}{$prefix}) eq 'HASH') { + if ($domconfig{$action}{$prefix}{$type} ne '') { + if ($value ne $domconfig{$action}{$prefix}{$type}) { + $changes{$prefix}{$type} = 1; + } + $defaultshash{$action}{$prefix}{$type} = $value; + } else { + $defaultshash{$action}{$prefix}{$type} = $value; $changes{$prefix}{$type} = 1; } - $defaultshash{$action}{$prefix}{$type} = $value; } else { $defaultshash{$action}{$prefix}{$type} = $value; $changes{$prefix}{$type} = 1; @@ -14098,6 +16816,17 @@ sub modify_ssl { } } } + if (keys(%changes)) { + foreach my $prefix (keys(%changes)) { + if (ref($changes{$prefix}) eq 'HASH') { + if (scalar(keys(%{$changes{$prefix}})) == 0) { + delete($changes{$prefix}); + } + } else { + delete($changes{$prefix}); + } + } + } my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings'); if (keys(%changes) > 0) { my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, @@ -14108,10 +16837,10 @@ sub modify_ssl { $domdefaults{'replication'} = $defaultshash{$action}{'replication'}; } if (ref($defaultshash{$action}{'connto'}) eq 'HASH') { - $domdefaults{'connto'} = $domconfig{$action}{'connto'}; + $domdefaults{'connto'} = $defaultshash{$action}{'connto'}; } if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') { - $domdefaults{'connfrom'} = $domconfig{$action}{'connfrom'}; + $domdefaults{'connfrom'} = $defaultshash{$action}{'connfrom'}; } } my $cachetime = 24*60*60; @@ -14127,18 +16856,24 @@ sub modify_ssl { $resulttext .= '<li>'.$titles{$prefix}.'<ul>'; foreach my $type (@{$types{$prefix}}) { if (defined($changes{$prefix}{$type})) { - my $newvalue; + my ($newvalue,$notinuse); if (ref($defaultshash{$action}) eq 'HASH') { if (ref($defaultshash{$action}{$prefix})) { if (($prefix eq 'connto') || ($prefix eq 'connfrom')) { $newvalue = $titles{$defaultshash{$action}{$prefix}{$type}}; - } elsif (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') { - if (@{$defaultshash{$action}{$prefix}{$type}} > 0) { - $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}}); + } else { + if (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') { + if (@{$defaultshash{$action}{$prefix}{$type}} > 0) { + $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}}); + } + } else { + $notinuse = 1; } } } - if ($newvalue eq '') { + if ($notinuse) { + $resulttext .= '<li>'.&mt('[_1] set to: not in use',$titles{$type}).'</li>'; + } elsif ($newvalue eq '') { $resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>'; } else { $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>'; @@ -14252,17 +16987,21 @@ sub modify_trust { $resulttext .= '<li>'.$lt{$prefix}.'<ul>'; foreach my $type (@types) { if (defined($changes{$prefix}{$type})) { - my $newvalue; + my ($newvalue,$notinuse); if (ref($defaultshash{'trust'}) eq 'HASH') { if (ref($defaultshash{'trust'}{$prefix})) { if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') { if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) { $newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}}); } + } else { + $notinuse = 1; } } } - if ($newvalue eq '') { + if ($notinuse) { + $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>'; + } elsif ($newvalue eq '') { $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>'; } else { $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>'; @@ -14297,12 +17036,12 @@ sub modify_loadbalancing { my @sparestypes = ('primary','default'); my %typetitles = &sparestype_titles(); my $resulttext; - my (%currbalancer,%currtargets,%currrules,%existing); + my (%currbalancer,%currtargets,%currrules,%existing,%currcookies); if (ref($domconfig{'loadbalancing'}) eq 'HASH') { %existing = %{$domconfig{'loadbalancing'}}; } &get_loadbalancers_config(\%servers,\%existing,\%currbalancer, - \%currtargets,\%currrules); + \%currtargets,\%currrules,\%currcookies); my ($saveloadbalancing,%defaultshash,%changes); my ($alltypes,$othertypes,$titles) = &loadbalancing_titles($dom,$intdom,$usertypes,$types); @@ -14354,6 +17093,18 @@ sub modify_loadbalancing { } $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto; } + if ($env{'form.loadbalancing_cookie_'.$i}) { + $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1; + if (exists($currbalancer{$balancer})) { + unless ($currcookies{$balancer}) { + $changes{'curr'}{$balancer}{'cookie'} = 1; + } + } + } elsif (exists($currbalancer{$balancer})) { + if ($currcookies{$balancer}) { + $changes{'curr'}{$balancer}{'cookie'} = 1; + } + } if (ref($currtargets{$balancer}) eq 'HASH') { foreach my $sparetype (@sparestypes) { if (ref($currtargets{$balancer}{$sparetype}) eq 'ARRAY') { @@ -14507,6 +17258,10 @@ sub modify_loadbalancing { } } } + if ($changes{'curr'}{$balancer}{'cookie'}) { + $resulttext .= '<li>'.&mt('Load Balancer: [_1] -- cookie use enabled', + $balancer).'</li>'; + } if (keys(%toupdate)) { my %thismachine; my $updatedhere; @@ -14736,12 +17491,12 @@ sub lonbalance_targets_js { } push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external'); $allinsttypes = join("','",@alltypes); - my (%currbalancer,%currtargets,%currrules,%existing); + my (%currbalancer,%currtargets,%currrules,%existing,%currcookies); if (ref($settings) eq 'HASH') { %existing = %{$settings}; } &get_loadbalancers_config($servers,\%existing,\%currbalancer, - \%currtargets,\%currrules); + \%currtargets,\%currrules,\%currcookies); my $balancers = join("','",sort(keys(%currbalancer))); return <<"END"; @@ -15226,6 +17981,7 @@ function toggleDisplay(domForm,caller) { var optionsElement = domForm.coursecredits; var checkval = 1; var dispval = 'block'; + var selfcreateRegExp = /^cancreate_emailverified/; if (caller == 'emailoptions') { optionsElement = domForm.cancreate_email; } @@ -15236,6 +17992,11 @@ function toggleDisplay(domForm,caller) { optionsElement = domForm.canclone; checkval = 'instcode'; } + if (selfcreateRegExp.test(caller)) { + optionsElement = domForm.elements[caller]; + checkval = 'other'; + dispval = 'inline' + } if (optionsElement.length) { var currval; for (var i=0; i<optionsElement.length; i++) {