--- loncom/interface/loncommon.pm 2007/08/18 00:01:37 1.565 +++ loncom/interface/loncommon.pm 2007/09/24 23:29:53 1.587 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.565 2007/08/18 00:01:37 albertel Exp $ +# $Id: loncommon.pm,v 1.587 2007/09/24 23:29:53 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -721,24 +721,20 @@ sub help_open_topic { my $template = ""; my $link; - + $topic=~s/\W/\_/g; - if (!$stayOnPage) - { + if (!$stayOnPage) { $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))"; - } - else - { + } else { $link = "/adm/help/${filename}.hlp"; } # Add the text - if ($text ne "") - { + if ($text ne "") { $template .= - "<table bgcolor='#3333AA' cellspacing='1' cellpadding='1' border='0'><tr>". - "<td bgcolor='#5555FF'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; + "<table bgcolor='#3333AA' cellspacing='1' cellpadding='1' border='0'><tr>". + "<td bgcolor='#5555FF'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; } # Add the graphic @@ -805,14 +801,10 @@ sub help_open_menu { my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text) = @_; $stayOnPage = 0 if (not defined $stayOnPage); - # formerly only used pop-up help (stayOnPage = 0) + # only use pop-up help (stayOnPage == 0) # if environment.remote is on (using remote control UI) - # if ($env{'browser.interface'} eq 'textual' || - # $env{'environment.remote'} eq 'off' ) { - # $stayOnPage=1; - #} - # Now making pop-up help the default even with remote control - if ($env{'browser.interface'} eq 'textual') { + if ($env{'browser.interface'} eq 'textual' || + $env{'environment.remote'} eq 'off' ) { $stayOnPage=1; } my $output; @@ -834,15 +826,13 @@ sub help_open_menu { sub top_nav_help { my ($text) = @_; - $text = &mt($text); - - my $stayOnPage = + my $stay_on_page = ($env{'browser.interface'} eq 'textual' || $env{'environment.remote'} eq 'off' ); - my $link= ($stayOnPage) ? "javascript:helpMenu('display')" + my $link = ($stay_on_page) ? "javascript:helpMenu('display')" : "javascript:helpMenu('open')"; - my $banner_link = &update_help_link(undef,undef,undef,undef,$stayOnPage); + my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page); my $title = &mt('Get help'); @@ -870,7 +860,7 @@ sub help_menu_js { 'js_ready' => 1, 'add_entries' => { 'border' => '0', - 'rows' => "105,*",},}); + 'rows' => "110,*",},}); my $end_page = &Apache::loncommon::end_page({'frameset' => 1, 'js_ready' => 1,}); @@ -1521,24 +1511,68 @@ sub select_dom_form { =pod -=item * home_server_option_list($domain) +=item * home_server_form_item($domain,$name,$defaultflag) + +input: 4 arguments (two required, two optional) - + $domain - domain of new user + $name - name of form element + $default - Value of 'default' causes a default item to be first + option, and selected by default. + $hide - Value of 'hide' causes hiding of the name of the server, + if 1 server found, or default, if 0 found. +output: returns 1 items: +(a) form element which contains either: + (i) <select name="$name"> + <option value="$hostid1">$hostid $servers{$hostid}</option> + <option value="$hostid2">$hostid $servers{$hostid}</option> + </select> + form item if there are multiple library servers in $domain, or + (ii) an <input type="hidden" name="$name" value="$hostid" /> form item + if there is only one library server in $domain. -returns a string which contains an <option> list to be used in a -<select> form input. See loncreateuser.pm for an example. +(b) number of library servers found. + +See loncreateuser.pm for example of use. =cut #------------------------------------------- -sub home_server_option_list { - my $domain = shift; +sub home_server_form_item { + my ($domain,$name,$default,$hide) = @_; my %servers = &Apache::lonnet::get_servers($domain,'library'); - my $result = ''; - foreach my $hostid (sort(keys(%servers))) { - $result.= - '<option value="'.$hostid.'">'. - $hostid.' '.$servers{$hostid}."</option>\n"; + my $result; + my $numlib = keys(%servers); + if ($numlib > 1) { + $result .= '<select name="'.$name.'" />'."\n"; + if ($default) { + $result .= '<option value="default" selected>'.&mt('default'). + '</option>'."\n"; + } + foreach my $hostid (sort(keys(%servers))) { + $result.= '<option value="'.$hostid.'">'. + $hostid.' '.$servers{$hostid}."</option>\n"; + } + $result .= '</select>'."\n"; + } elsif ($numlib == 1) { + my $hostid; + foreach my $item (keys(%servers)) { + $hostid = $item; + } + $result .= '<input type="hidden" name="'.$name.'" value="'. + $hostid.'" />'; + if (!$hide) { + $result .= $hostid.' '.$servers{$hostid}; + } + $result .= "\n"; + } elsif ($default) { + $result .= '<input type="hidden" name="'.$name. + '" value="default" />'; + if (!$hide) { + $result .= &mt('default'); + } + $result .= "\n"; } - return $result; + return ($result,$numlib); } =pod @@ -1786,11 +1820,17 @@ sub authform_nochange{ kerb_def_dom => 'MSU.EDU', @_, ); - my $result = '<label>'.&mt('[_1] Do not change login data', - '<input type="radio" name="login" value="nochange" '. - 'checked="checked" onclick="'. + my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); + my $result; + if (keys(%can_assign) == 0) { + $result = &mt('Under you current role you are not permitted to change login settings for this user'); + } else { + $result = '<label>'.&mt('[_1] Do not change login data', + '<input type="radio" name="login" value="nochange" '. + 'checked="checked" onclick="'. "javascript:changed_radio('nochange',$in{'formname'});".'" />'). '</label>'; + } return $result; } @@ -1801,64 +1841,148 @@ sub authform_kerberos{ kerb_def_auth => 'krb4', @_, ); - my ($check4,$check5,$krbarg); + my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype, + $autharg,$jscall); + my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); if ($in{'kerb_def_auth'} eq 'krb5') { - $check5 = " checked=\"on\""; + $check5 = ' checked="on"'; } else { - $check4 = " checked=\"on\""; + $check4 = ' checked="on"'; } $krbarg = $in{'kerb_def_dom'}; - - my $krbcheck = ""; - if ( grep/^curr_authtype$/,(keys %in) ) { - if ($in{'curr_authtype'} =~ m/^krb/) { - $krbcheck = " checked=\"on\""; - if ( grep/^curr_autharg$/,(keys %in) ) { + if (grep(/^curr_authtype$/,(keys(%in)))) { + if ($in{'curr_authtype'} =~ m/^krb(\d+)$/) { + $krbver = $1; + $krbcheck = ' checked="on"'; + if ($krbver eq '5') { + $check5 = ' checked="on"'; + $check4 = ''; + } else { + $check4 = ' checked="on"'; + $check5 = ''; + } + if (grep(/^curr_autharg$/,(keys(%in)))) { $krbarg = $in{'curr_autharg'}; } + if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) { + if (grep(/^curr_autharg$/,(keys(%in)))) { + $result = + &mt('Currently Kerberos authenticated with domain [_1] Version [_2].', + $in{'curr_autharg'},$krbver); + } else { + $result = + &mt('Currently Kerberos authenticated, Version [_1].',$krbver); + } + return $result; + } + } + } else { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="krb">'; } } - - my $jscall = "javascript:changed_radio('krb',$in{'formname'});"; - my $result .= &mt + if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) { + return; + } elsif ($authtype eq '') { + if (grep(/^mode$/,(keys(%in)))) { + if ($in{'mode'} eq 'modifycourse') { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="krb">'; + } + } + } + } + $jscall = "javascript:changed_radio('krb',$in{'formname'});"; + if ($authtype eq '') { + $authtype = '<input type="radio" name="login" value="krb" '. + 'onclick="'.$jscall.'" onchange="'.$jscall.'"'. + $krbcheck.' />'; + } + if (($can_assign{'krb4'} && $can_assign{'krb5'}) || + ($can_assign{'krb4'} && !$can_assign{'krb5'} && + $in{'curr_authtype'} eq 'krb5') || + (!$can_assign{'krb4'} && $can_assign{'krb5'} && + $in{'curr_authtype'} eq 'krb4')) { + $result .= &mt ('[_1] Kerberos authenticated with domain [_2] '. '[_3] Version 4 [_4] Version 5 [_5]', - '<label><input type="radio" name="login" value="krb" '. - 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.$krbcheck.' />', + '<label>'.$authtype, '</label><input type="text" size="10" name="krbarg" '. 'value="'.$krbarg.'" '. 'onchange="'.$jscall.'" />', '<label><input type="radio" name="krbver" value="4" '.$check4.' />', '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />', '</label>'); + } elsif ($can_assign{'krb4'}) { + $result .= &mt + ('[_1] Kerberos authenticated with domain [_2] '. + '[_3] Version 4 [_4]', + '<label>'.$authtype, + '</label><input type="text" size="10" name="krbarg" '. + 'value="'.$krbarg.'" '. + 'onchange="'.$jscall.'" />', + '<label><input type="hidden" name="krbver" value="4" />', + '</label>'); + } elsif ($can_assign{'krb5'}) { + $result .= &mt + ('[_1] Kerberos authenticated with domain [_2] '. + '[_3] Version 5 [_4]', + '<label>'.$authtype, + '</label><input type="text" size="10" name="krbarg" '. + 'value="'.$krbarg.'" '. + 'onchange="'.$jscall.'" />', + '<label><input type="hidden" name="krbver" value="5" />', + '</label>'); + } return $result; } sub authform_internal{ - my %args = ( + my %in = ( formname => 'document.cu', kerb_def_dom => 'MSU.EDU', @_, ); - - my $intcheck = ""; - my $intarg = 'value=""'; - if ( grep/^curr_authtype$/,(keys %args) ) { - if ($args{'curr_authtype'} eq 'int') { - $intcheck = " checked=\"on\""; - if ( grep/^curr_autharg$/,(keys %args) ) { - $intarg = "value=\"$args{'curr_autharg'}\""; + my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall); + my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); + if (grep(/^curr_authtype$/,(keys(%in)))) { + if ($in{'curr_authtype'} eq 'internal:') { + if ($can_assign{'int'}) { + $intcheck = 'checked="on" '; + if (grep(/^curr_autharg$/,(keys(%in)))) { + $intarg = $in{'curr_autharg'}; + } + } else { + $result = &mt('Currently internally authenticated.'); + return $result; } } + } else { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="int">'; + } } - - my $jscall = "javascript:changed_radio('int',$args{'formname'});"; - my $result.=&mt + if (!$can_assign{'int'}) { + return; + } elsif ($authtype eq '') { + if (grep(/^mode$/,(keys(%in)))) { + if ($in{'mode'} eq 'modifycourse') { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="int">'; + } + } + } + } + $jscall = "javascript:changed_radio('int',$in{'formname'});"; + if ($authtype eq '') { + $authtype = '<input type="radio" name="login" value="int" '.$intcheck. + ' onchange="'.$jscall.'" onclick="'.$jscall.'" />'; + } + $autharg = '<input type="text" size="10" name="intarg" value="'. + $intarg.'" onchange="'.$jscall.'" />'; + $result = &mt ('[_1] Internally authenticated (with initial password [_2])', - '<label><input type="radio" name="login" value="int" '.$intcheck. - ' onchange="'.$jscall.'" onclick="'.$jscall.'" />', - '</label><input type="text" size="10" name="intarg" '.$intarg. - ' onchange="'.$jscall.'" />'); + '<label>'.$authtype,'</label>'.$autharg); return $result; } @@ -1868,24 +1992,46 @@ sub authform_local{ kerb_def_dom => 'MSU.EDU', @_, ); - - my $loccheck = ""; - my $locarg = 'value=""'; - if ( grep/^curr_authtype$/,(keys %in) ) { - if ($in{'curr_authtype'} eq 'loc') { - $loccheck = " checked=\"on\""; - if ( grep/^curr_autharg$/,(keys %in) ) { - $locarg = "value=\"$in{'curr_autharg'}\""; + my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall); + my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); + if (grep(/^curr_authtype$/,(keys(%in)))) { + if ($in{'curr_authtype'} eq 'localauth:') { + if ($can_assign{'loc'}) { + $loccheck = 'checked="on" '; + if (grep(/^curr_autharg$/,(keys(%in)))) { + $locarg = $in{'curr_autharg'}; + } + } else { + $result = &mt('Currently using local (institutional) authentication.'); + return $result; } } + } else { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="loc">'; + } } - - my $jscall = "javascript:changed_radio('loc',$in{'formname'});"; - my $result.=&mt('[_1] Local Authentication with argument [_2]', - '<label><input type="radio" name="login" value="loc" '.$loccheck. - ' onchange="'.$jscall.'" onclick="'.$jscall.'" />', - '</label><input type="text" size="10" name="locarg" '.$locarg. - ' onchange="'.$jscall.'" />'); + if (!$can_assign{'loc'}) { + return; + } elsif ($authtype eq '') { + if (grep(/^mode$/,(keys(%in)))) { + if ($in{'mode'} eq 'modifycourse') { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="loc">'; + } + } + } + } + $jscall = "javascript:changed_radio('loc',$in{'formname'});"; + if ($authtype eq '') { + $authtype = '<input type="radio" name="login" value="loc" '. + $loccheck.' onchange="'.$jscall.'" onclick="'. + $jscall.'" />'; + } + $autharg = '<input type="text" size="10" name="locarg" value="'. + $locarg.'" onchange="'.$jscall.'" />'; + $result = &mt('[_1] Local Authentication with argument [_2]', + '<label>'.$authtype,'</label>'.$autharg); return $result; } @@ -1895,16 +2041,92 @@ sub authform_filesystem{ kerb_def_dom => 'MSU.EDU', @_, ); - my $jscall = "javascript:changed_radio('fsys',$in{'formname'});"; - my $result.= &mt + my ($fsyscheck,$result,$authtype,$autharg,$jscall); + my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); + if (grep(/^curr_authtype$/,(keys(%in)))) { + if ($in{'curr_authtype'} eq 'unix:') { + if ($can_assign{'fsys'}) { + $fsyscheck = 'checked="on" '; + } else { + $result = &mt('Currently Filesystem Authenticated.'); + return $result; + } + } + } else { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="fsys">'; + } + } + if (!$can_assign{'fsys'}) { + return; + } elsif ($authtype eq '') { + if (grep(/^mode$/,(keys(%in)))) { + if ($in{'mode'} eq 'modifycourse') { + if ($authnum == 1) { + $authtype = '<input type="hidden" name="login" value="fsys">'; + } + } + } + } + $jscall = "javascript:changed_radio('fsys',$in{'formname'});"; + if ($authtype eq '') { + $authtype = '<input type="radio" name="login" value="fsys" '. + $fsyscheck.' onchange="'.$jscall.'" onclick="'. + $jscall.'" />'; + } + $autharg = '<input type="text" size="10" name="fsysarg" value=""'. + ' onchange="'.$jscall.'" />'; + $result = &mt ('[_1] Filesystem Authenticated (with initial password [_2])', '<label><input type="radio" name="login" value="fsys" '. - 'onchange="'.$jscall.'" onclick="'.$jscall.'" />', + $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />', '</label><input type="text" size="10" name="fsysarg" value="" '. 'onchange="'.$jscall.'" />'); return $result; } +sub get_assignable_auth { + my ($dom) = @_; + if ($dom eq '') { + $dom = $env{'request.role.domain'}; + } + my %can_assign = ( + krb4 => 1, + krb5 => 1, + int => 1, + loc => 1, + ); + my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom); + if (ref($domconfig{'usercreation'}) eq 'HASH') { + if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') { + my $authhash = $domconfig{'usercreation'}{'authtypes'}; + my $context; + if ($env{'request.role'} =~ /^au/) { + $context = 'author'; + } elsif ($env{'request.role'} =~ /^dc/) { + $context = 'domain'; + } elsif ($env{'request.course.id'}) { + $context = 'course'; + } + if ($context) { + if (ref($authhash->{$context}) eq 'HASH') { + %can_assign = %{$authhash->{$context}}; + } + } + } + } + my $authnum = 0; + foreach my $key (keys(%can_assign)) { + if ($can_assign{$key}) { + $authnum ++; + } + } + if ($can_assign{'krb4'} && $can_assign{'krb5'}) { + $authnum --; + } + return ($authnum,%can_assign); +} + ############################################################### ## Get Authentication Defaults for Domain ## ############################################################### @@ -2030,7 +2252,7 @@ sub initialize_keywords { # Remove special values from %Keywords. foreach my $value ('total.count','average.count') { delete($Keywords{$value}) if (exists($Keywords{$value})); - } + } return 1; } @@ -2541,9 +2763,11 @@ sub preferred_languages { @languages=(@languages, split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'})); } - my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0]; + my $browser=$ENV{'HTTP_ACCEPT_LANGUAGE'}; if ($browser) { - @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser)); + my @browser = + map { (split(/\s*;\s*/,$_))[0] } (split(/\s*,\s*/,$browser)); + push(@languages,@browser); } if (&Apache::lonnet::domain($env{'user.domain'},'lang_def')) { @languages=(@languages, @@ -2565,14 +2789,40 @@ sub preferred_languages { my @genlanguages; foreach my $lang (@languages) { unless ($lang=~/\w/) { next; } - push (@genlanguages,$lang); + push(@genlanguages,$lang); if ($lang=~/(\-|\_)/) { push(@genlanguages,(split(/(\-|\_)/,$lang))[0]); } } + #uniqueify the languages list + my %count; + @genlanguages = map { $count{$_}++ == 0 ? $_ : () } @genlanguages; return @genlanguages; } +sub languages { + my ($possible_langs) = @_; + my @preferred_langs = &preferred_languages(); + if (!ref($possible_langs)) { + if( wantarray ) { + return @preferred_langs; + } else { + return $preferred_langs[0]; + } + } + my %possibilities = map { $_ => 1 } (@$possible_langs); + my @preferred_possibilities; + foreach my $preferred_lang (@preferred_langs) { + if (exists($possibilities{$preferred_lang})) { + push(@preferred_possibilities, $preferred_lang); + } + } + if( wantarray ) { + return @preferred_possibilities; + } + return $preferred_possibilities[0]; +} + ############################################################### ## Student Answer Attempts ## ############################################################### @@ -2647,25 +2897,15 @@ sub get_previous_attempt { for ($version=1;$version<=$returnhash{'version'};$version++) { $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>'; foreach my $key (sort(keys(%lasthash))) { - my $value; - if ($key =~ /timestamp/) { - $value=scalar(localtime($returnhash{$version.':'.$key})); - } else { - $value=$returnhash{$version.':'.$key}; - } - $prevattempts.='<td>'.&unescape($value).' </td>'; + my $value = &format_previous_attempt_value($key, + $returnhash{$version.':'.$key}); + $prevattempts.='<td>'.$value.' </td>'; } } } $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>'; foreach my $key (sort(keys(%lasthash))) { - my $value; - if ($key =~ /timestamp/) { - $value=scalar(localtime($lasthash{$key})); - } else { - $value=$lasthash{$key}; - } - $value=&unescape($value); + my $value = &format_previous_attempt_value($key,$lasthash{$key}); if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} $prevattempts.='<td>'.$value.' </td>'; } @@ -2678,6 +2918,19 @@ sub get_previous_attempt { } } +sub format_previous_attempt_value { + my ($key,$value) = @_; + if ($key =~ /timestamp/) { + $value = &Apache::lonlocal::locallocaltime($value); + } elsif (ref($value) eq 'ARRAY') { + $value = '('.join(', ', @{ $value }).')'; + } else { + $value = &unescape($value); + } + return $value; +} + + sub relative_to_absolute { my ($url,$output)=@_; my $parser=HTML::TokeParser->new(\$output); @@ -3515,9 +3768,6 @@ sub bodytag { if (!$realm) { $realm=' '; } # Set messages my $messages=&domainlogo($domain); -# Port for miniserver - my $lonhttpdPort=$Apache::lonnet::perlvar{'lonhttpdPort'}; - if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; } my $extra_body_attr = &make_attr_string($forcereg,\%design); @@ -3635,7 +3885,7 @@ ENDROLE my $imgsrc = $img; if ($img =~ /^\/adm/) { - $imgsrc = 'http://'.$ENV{'HTTP_HOST'}.':'.$lonhttpdPort.$img; + $imgsrc = &lonhttpdurl($img); } my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />'; @@ -4343,9 +4593,7 @@ table#LC_helpmenu_links a:hover { border: 1px solid #8888FF; background: #CCCCFF; } - table.LC_pick_box { - width: 100%; border-collapse: separate; background: white; border: 1px solid black; @@ -4358,6 +4606,14 @@ table.LC_pick_box td.LC_pick_box_title { width: 184px; padding: 8px; } +table.LC_pick_box td.LC_pick_box_value { + text-align: left; + padding: 8px; +} +table.LC_pick_box td.LC_pick_box_select { + text-align: left; + padding: 8px; +} table.LC_pick_box td.LC_pick_box_separator { padding: 0px; height: 1px; @@ -4366,7 +4622,48 @@ table.LC_pick_box td.LC_pick_box_separat table.LC_pick_box td.LC_pick_box_submit { text-align: right; } - +table.LC_pick_box td.LC_evenrow_value { + text-align: left; + padding: 8px; + background-color: $data_table_light; +} +table.LC_pick_box td.LC_oddrow_value { + text-align: left; + padding: 8px; + background-color: $data_table_light; +} +table.LC_helpform_receipt { + width: 620px; + border-collapse: separate; + background: white; + border: 1px solid black; + border-spacing: 1px; +} +table.LC_helpform_receipt td.LC_pick_box_title { + background: $tabbg; + font-weight: bold; + text-align: right; + width: 184px; + padding: 8px; +} +table.LC_helpform_receipt td.LC_evenrow_value { + text-align: left; + padding: 8px; + background-color: $data_table_light; +} +table.LC_helpform_receipt td.LC_oddrow_value { + text-align: left; + padding: 8px; + background-color: $data_table_light; +} +table.LC_helpform_receipt td.LC_pick_box_separator { + padding: 0px; + height: 1px; + background: black; +} +span.LC_helpform_receipt_cat { + font-weight: bold; +} table.LC_group_priv_box { background: white; border: 1px solid black; @@ -4511,6 +4808,10 @@ span.LC_nobreak { white-space: nowrap; } +span.LC_cusr_emph { + font-style: italic; +} + table.LC_docs_documents { background: #BBBBBB; border-width: 0px; @@ -4578,6 +4879,13 @@ table.LC_docs_adddocs th { background: #DDDDDD; } +table.LC_sty_begin { + background: #BBFFBB; +} +table.LC_sty_end { + background: #FFBBBB; +} + END } @@ -5609,11 +5917,11 @@ sub get_secgrprole_info { } sub user_picker { - my ($dom,$srch,$forcenewuser) = @_; + my ($dom,$srch,$forcenewuser,$caller) = @_; my $currdom = $dom; my %curr_selected = ( srchin => 'dom', - srchby => 'uname', + srchby => 'lastname', ); my $srchterm; if (ref($srch) eq 'HASH') { @@ -5632,16 +5940,26 @@ sub user_picker { $srchterm = $srch->{'srchterm'}; } my %lt=&Apache::lonlocal::texthash( + 'usr' => 'Search criteria', 'doma' => 'Domain/institution to search', 'uname' => 'username', 'lastname' => 'last name', 'lastfirst' => 'last name, first name', 'crs' => 'in this course', - 'dom' => 'in this domain', + 'dom' => 'in selected LON-CAPA domain', 'alc' => 'all LON-CAPA', - 'instd' => 'in institutional directory', + 'instd' => 'in institutional directory for selected domain', 'exact' => 'is', 'contains' => 'contains', + 'begins' => 'begins with', + 'youm' => "You must include some text to search for.", + 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.", + 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.", + 'yomc' => "You must choose a domain when using an institutional directory search.", + 'ymcd' => "You must choose a domain when using a domain search.", + 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.", + 'whse' => "When searching by last,first you must include at least one character in the first name.", + 'thfo' => "The following need to be corrected before the search can be run:", ); my $domform = &select_dom_form($currdom,'srchdomain',1,1); my $srchinsel = ' <select name="srchin">'; @@ -5665,7 +5983,7 @@ sub user_picker { $srchinsel .= "\n </select>\n"; my $srchbysel = ' <select name="srchby">'; - foreach my $option ('uname','lastname','lastfirst') { + foreach my $option ('lastname','lastfirst','uname') { if ($curr_selected{'srchby'} eq $option) { $srchbysel .= ' <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>'; @@ -5677,7 +5995,7 @@ sub user_picker { $srchbysel .= "\n </select>\n"; my $srchtypesel = ' <select name="srchtype">'; - foreach my $option ('exact','contains') { + foreach my $option ('begins','contains','exact') { if ($curr_selected{'srchtype'} eq $option) { $srchtypesel .= ' <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>'; @@ -5691,29 +6009,34 @@ sub user_picker { my ($newuserscript,$new_user_create); if ($forcenewuser) { - $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\');" /> </p>'; + if (ref($srch) eq 'HASH') { + if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) { + $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>'; + } + } + $newuserscript = <<"ENDSCRIPT"; -function setSearch(createnew) { +function setSearch(createnew,callingForm) { if (createnew == 1) { - for (var i=0; i<document.crtuser.srchby.length; i++) { - if (document.crtuser.srchby.options[i].value == 'uname') { - document.crtuser.srchby.selectedIndex = i; + for (var i=0; i<callingForm.srchby.length; i++) { + if (callingForm.srchby.options[i].value == 'uname') { + callingForm.srchby.selectedIndex = i; } } - for (var i=0; i<document.crtuser.srchin.length; i++) { - if ( document.crtuser.srchin.options[i].value == 'dom') { - document.crtuser.srchin.selectedIndex = i; + for (var i=0; i<callingForm.srchin.length; i++) { + if ( callingForm.srchin.options[i].value == 'dom') { + callingForm.srchin.selectedIndex = i; } } - for (var i=0; i<document.crtuser.srchtype.length; i++) { - if (document.crtuser.srchtype.options[i].value == 'exact') { - document.crtuser.srchtype.selectedIndex = i; + for (var i=0; i<callingForm.srchtype.length; i++) { + if (callingForm.srchtype.options[i].value == 'exact') { + callingForm.srchtype.selectedIndex = i; } } - for (var i=0; i<document.crtuser.srchdomain.length; i++) { - if (document.crtuser.srchdomain.options[i].value == '$env{'request.role.domain'}') { - document.crtuser.srchdomain.selectedIndex = i; + for (var i=0; i<callingForm.srchdomain.length; i++) { + if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') { + callingForm.srchdomain.selectedIndex = i; } } } @@ -5724,62 +6047,69 @@ ENDSCRIPT my $output = <<"END_BLOCK"; <script type="text/javascript"> -function validateEntry() { +function validateEntry(callingForm) { var checkok = 1; var srchin; - for (var i=0; i<document.crtuser.srchin.length; i++) { - if ( document.crtuser.srchin[i].checked ) { - srchin = document.crtuser.srchin[i].value; + for (var i=0; i<callingForm.srchin.length; i++) { + if ( callingForm.srchin[i].checked ) { + srchin = callingForm.srchin[i].value; } } - var srchtype = document.crtuser.srchtype.options[document.crtuser.srchtype.selectedIndex].value; - var srchby = document.crtuser.srchby.options[document.crtuser.srchby.selectedIndex].value; - var srchdomain = document.crtuser.srchdomain.options[document.crtuser.srchdomain.selectedIndex].value; - var srchterm = document.crtuser.srchterm.value; - var srchin = document.crtuser.srchin.options[document.crtuser.srchin.selectedIndex].value; + var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value; + var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value; + var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value; + var srchterm = callingForm.srchterm.value; + var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value; var msg = ""; if (srchterm == "") { checkok = 0; - msg += "You must include some text to search for.\\n"; + msg += "$lt{'youm'}\\n"; + } + + if (srchtype== 'begins') { + if (srchterm.length < 2) { + checkok = 0; + msg += "$lt{'thte'}\\n"; + } } if (srchtype== 'contains') { if (srchterm.length < 3) { checkok = 0; - msg += "The text you are searching for must contain at least three characters when using a 'contains' type search.\\n"; + msg += "$lt{'thet'}\\n"; } } if (srchin == 'instd') { if (srchdomain == '') { checkok = 0; - msg += "You must choose a domain when using an institutional directory search.\\n"; + msg += "$lt{'yomc'}\\n"; } } if (srchin == 'dom') { if (srchdomain == '') { checkok = 0; - msg += "You must choose a domain when using a domain search.\\n"; + msg += "$lt{'ymcd'}\\n"; } } if (srchby == 'lastfirst') { if (srchterm.indexOf(",") == -1) { checkok = 0; - msg += "When using searching by last,first you must include a comma as separator between last name and first name.\\n"; + msg += "$lt{'whus'}\\n"; } if (srchterm.indexOf(",") == srchterm.length -1) { checkok = 0; - msg += "When searching by last,first you must include at least one character in the first name.\\n"; + msg += "$lt{'whse'}\\n"; } } if (checkok == 0) { - alert("The following need to be corrected before the search can be run:\\n"+msg); + alert("$lt{'thfo'}\\n"+msg); return; } if (checkok == 1) { - document.crtuser.submit(); + callingForm.submit(); } } @@ -5791,16 +6121,18 @@ $new_user_create <table> <tr> + <td>$lt{'doma'}:</td> + <td>$domform</td> + </td> + </tr> + <tr> + <td>$lt{'usr'}:</td> <td>$srchbysel $srchtypesel <input type="text" size="15" name="srchterm" value="$srchterm" /> $srchinsel </td> </tr> - <tr> - <td>$lt{'doma'}: $domform</td> - </td> - </tr> </table> <br /> END_BLOCK @@ -5808,7 +6140,58 @@ END_BLOCK return $output; } - +sub username_rule_check { + my ($srch,$caller) = @_; + my ($response,@curr_rules,%inst_results,$rulematch); + my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($srch->{'srchdomain'}); + if (ref($srch) eq 'HASH') { + (my $inst_response,%inst_results) = + &Apache::lonnet::get_instuser($srch->{'srchdomain'}, + $srch->{'srchterm'}); + my %domconfig = &Apache::lonnet::get_dom('configuration', + ['usercreation'],$srch->{'srchdomain'}); + if (ref($domconfig{'usercreation'}) eq 'HASH') { + if (ref($domconfig{'usercreation'}{'username_rule'}) eq 'ARRAY') { + @curr_rules = @{$domconfig{'usercreation'}{'username_rule'}}; + } + } + if (@curr_rules > 0) { + my $domdesc = &Apache::lonnet::domain($srch->{'srchdomain'},'description'); + my $instuser_reqd; + my %rule_check = &Apache::lonnet::inst_rulecheck($srch->{'srchdomain'},$srch->{'srchterm'},\@curr_rules); + foreach my $rule (@curr_rules) { + if ($rule_check{$rule}) { + $rulematch = $rule; + if ($inst_response eq 'ok') { + if (keys(%inst_results) == 0) { + if ($caller eq 'new') { + $response = &mt('The username you chose matches the format of usernames defined for <span class="LC_cusr_emph">[_1]</span>, but the user does not exist in the institutional directory.',$domdesc).'<br />'.&mt("You must choose a username with a different format -- one that will not conflict with 'official' institutional usernames."); + } + } + } + last; + } + } + if ($response) { + if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) { + if (@{$ruleorder} > 0) { + $response .= '<br />'.&mt('Usernames with the following format(s) may <span class="LC_cusr_emph">only</span> be used for verified users at [_1]:',$domdesc).' <ul>'; + foreach my $rule (@{$ruleorder}) { + if (grep(/^\Q$rule\E$/,@curr_rules)) { + if (ref($rules->{$rule}) eq 'HASH') { + $response .= '<li>'.$rules->{$rule}{'name'}.': '. + $rules->{$rule}{'desc'}.'</li>'; + } + } + } + } + $response .= '</ul>'; + } + } + } + } + return ($response,$rulematch,$rules,%inst_results); +} =pod @@ -6969,6 +7352,45 @@ sub commit_studentrole { ############################################################ ############################################################ +sub check_clone { + my ($args,$linefeed) = @_; + my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; + my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); + my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); + my $clonemsg; + my $can_clone = 0; + + if ($clonehome eq 'no_host') { + $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); + } else { + my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); + if ($env{'request.role.domain'} eq $args->{'clonedomain'}) { + $can_clone = 1; + } else { + my %clonehash = &Apache::lonnet::get('environment',['cloners'], + $args->{'clonedomain'},$args->{'clonecourse'}); + my @cloners = split(/,/,$clonehash{'cloners'}); + if (grep(/^\*$/,@cloners)) { + $can_clone = 1; + } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { + $can_clone = 1; + } else { + my %roleshash = + &Apache::lonnet::get_my_roles($args->{'ccuname'}, + $args->{'ccdomain'}, + 'userroles',['active'],['cc'], + [$args->{'clonedomain'}]); + if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { + $can_clone = 1; + } else { + $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); + } + } + } + } + return ($can_clone, $clonemsg, $cloneid, $clonehome); +} + sub construct_course { my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context) = @_; my $outcome; @@ -6976,6 +7398,25 @@ sub construct_course { if ($context eq 'auto') { $linefeed = "\n"; } + +# +# Are we cloning? +# + my ($can_clone, $clonemsg, $cloneid, $clonehome); + if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { + ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed); + if ($context ne 'auto') { + if ($clonemsg ne '') { + $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>'; + } + } + $outcome .= $clonemsg.$linefeed; + + if (!$can_clone) { + return (0,$outcome); + } + } + # # Open course # @@ -6996,81 +7437,39 @@ sub construct_course { # if anyone ever decides to not show this, and Utils::Course::new # will need to be suitably modified. $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; - # # Check if created correctly # ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid); my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom); $outcome .= &mt('Created on').': '.$crsuhome.$linefeed; + # -# Are we cloning? -# - my $cloneid=''; - if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { - my $can_clone = 0; - $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; - my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); - my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); - my $clonemsg; - if ($clonehome eq 'no_host') { - $clonemsg = &mt('Attempting to clone non-existing [_1]',$crstype); - if ($context eq 'auto') { - $outcome .= $clonemsg; - } else { - $outcome .= '<font color="red">'.$clonemsg.'</font>'; - } - $outcome .= $linefeed; - } else { - my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); - if ($env{'request.role.domain'} eq $args->{'form.clonedomain'}) { - $can_clone = 1; - } else { - my %clonehash = &Apache::lonnet::get('environment',['cloners'], - $args->{'clonedomain'},$args->{'clonecourse'}); - my @cloners = split(/,/,$clonehash{'cloners'}); - my %roleshash = - &Apache::lonnet::get_my_roles($args->{'ccuname'}, - $args->{'ccdomain'},'userroles',['active'],['cc'], - [$args->{'clonedomain'}]); - if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { - $can_clone = 1; - } else { - $clonemsg = &mt('The new course was not cloned from an existing course because the course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); - if ($context eq 'auto') { - $outcome .= $clonemsg; - } else { - $outcome .= '<font color="red">'.$clonemsg.'</font>'; - } - $outcome .= $linefeed; - } - } - } - if ($can_clone) { - $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome); - if ($context eq 'auto') { - $outcome = $clonemsg; - } else { - $outcome .= '<font color="green">'.$clonemsg.'</font>'; - } - $outcome .= $linefeed; - my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); +# Do the cloning +# + if ($can_clone && $cloneid) { + $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome); + if ($context ne 'auto') { + $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>'; + } + $outcome .= $clonemsg.$linefeed; + my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); # Copy all files - &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid); + &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid); # Restore URL - $cenv{'url'}=$oldcenv{'url'}; + $cenv{'url'}=$oldcenv{'url'}; # Restore title - $cenv{'description'}=$oldcenv{'description'}; + $cenv{'description'}=$oldcenv{'description'}; # restore grading mode - if (defined($oldcenv{'grading'})) { - $cenv{'grading'}=$oldcenv{'grading'}; - } -# Mark as cloned - $cenv{'clonedfrom'}=$cloneid; - delete($cenv{'default_enrollment_start_date'}); - delete($cenv{'default_enrollment_end_date'}); + if (defined($oldcenv{'grading'})) { + $cenv{'grading'}=$oldcenv{'grading'}; } +# Mark as cloned + $cenv{'clonedfrom'}=$cloneid; + delete($cenv{'default_enrollment_start_date'}); + delete($cenv{'default_enrollment_end_date'}); } + # # Set environment (will override cloned, if existing) # @@ -7178,7 +7577,7 @@ sub construct_course { ' ('.$lt{'adby'}.')'; if ($context eq 'auto') { $outcome .= $badclass_msg.$linefeed; - $outcome .= '<font color="red">'.$badclass_msg.$linefeed.'<ul>'."\n"; + $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n"; foreach my $item (@badclasses) { if ($context eq 'auto') { $outcome .= " - $item\n"; @@ -7189,7 +7588,7 @@ sub construct_course { if ($context eq 'auto') { $outcome .= $linefeed; } else { - $outcome .= "</ul><br /><br /></font>\n"; + $outcome .= "</ul><br /><br /></div>\n"; } } } @@ -7211,7 +7610,7 @@ sub construct_course { if ($context eq 'auto') { $outcome .= $krb_msg; } else { - $outcome .= '<font color="red" size="+1">'.$krb_msg.'</font>'; + $outcome .= '<span class="LC_error">'.$krb_msg.'</span>'; } $outcome .= $linefeed; } @@ -7309,7 +7708,8 @@ sub construct_course { if ($errtext) { $fatal=2; } $outcome .= ($fatal?$errtext:'write ok').$linefeed; } - return $outcome; + + return (1,$outcome); } ############################################################ @@ -7352,10 +7752,27 @@ sub icon { return &lonhttpdurl($iconname); } -sub lonhttpdurl { - my ($url)=@_; +sub lonhttpd_port { my $lonhttpd_port=$Apache::lonnet::perlvar{'lonhttpdPort'}; if (!defined($lonhttpd_port)) { $lonhttpd_port='8080'; } + # IE doesn't like a secure page getting images from a non-secure + # port (when logging we haven't parsed the browser type so default + # back to secure + if ((!exists($env{'browser.type'}) || $env{'browser.type'} eq 'explorer') + && $ENV{'SERVER_PORT'} == 443) { + return 443; + } + return $lonhttpd_port; + +} + +sub lonhttpdurl { + my ($url)=@_; + + my $lonhttpd_port = &lonhttpd_port(); + if ($lonhttpd_port == 443) { + return 'https://'.$ENV{'SERVER_NAME'}.$url; + } return 'http://'.$ENV{'SERVER_NAME'}.':'.$lonhttpd_port.$url; }