--- loncom/interface/loncommon.pm 2007/11/02 18:47:08 1.607 +++ loncom/interface/loncommon.pm 2007/12/05 18:40:47 1.621 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.607 2007/11/02 18:47:08 albertel Exp $ +# $Id: loncommon.pm,v 1.621 2007/12/05 18:40:47 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -257,6 +257,7 @@ sub browser_and_searcher_javascript { } url += 'catalogmode=interactive&'; url += 'mode=$mode&'; + url += 'inhibitmenu=yes&'; url += 'form=' + formname + '&'; if (only != null) { url += 'only=' + only + '&'; @@ -544,7 +545,7 @@ linked_select_forms returns a string con and html for two \n"; - foreach my $value (sort(keys(%$hashref))) { + my @order = sort(keys(%{$hashref})); + if (ref($menuorder) eq 'ARRAY') { + @order = @{$menuorder}; + } + foreach my $value (@order) { $result.=" \n"; @@ -673,7 +687,12 @@ END $result .= $middletext; $result .= "".&mt('Visible input').''; return $result; } @@ -4117,8 +4137,9 @@ sub standard_css { my $table_header = '#DDDDDD'; my $feedback_link_bg = '#BBBBBB'; - my $border = ($env{'browser.type'} eq 'explorer') ? '0px 2px 0px 2px' - : '0px 3px 0px 4px'; + my $border = ($env{'browser.type'} eq 'explorer' || + $env{'browser.type'} eq 'safari' ) ? '0px 2px 0px 2px' + : '0px 3px 0px 4px'; return < td, table.LC_aboutme_port tr td { background-color: $data_table_light; padding: 2px; } -table.LC_data_table tr.LC_even_row td, +table.LC_data_table tr.LC_even_row > td, table.LC_aboutme_port tr.LC_even_row td { background-color: $data_table_dark; } @@ -4813,6 +4835,7 @@ table.LC_descriptive_input td.LC_descrip font-weight: bold; } div.LC_feedback_link { + clear: both; background: white; width: 100%; } @@ -5016,7 +5039,6 @@ div.LC_clear_float_footer { div.LC_grade_select_mode { - float: left; font-family: $sans; } div.LC_grade_select_mode div div { @@ -5076,13 +5098,22 @@ span.LC_grade_check_note { right: 1em; } +table.LC_scantron_action { + width: 100%; +} +table.LC_scantron_action tr th { + font: normal bold $sans; +} -div.LC_edit_problem_header { +div.LC_edit_problem_header, +div.LC_edit_problem_footer { font: normal medium $sans; margin: 2px; } div.LC_edit_problem_header, div.LC_edit_problem_header div, +div.LC_edit_problem_footer, +div.LC_edit_problem_footer div, div.LC_edit_problem_editxml_header, div.LC_edit_problem_editxml_header div { margin-top: 5px; @@ -5491,30 +5522,30 @@ sub simple_error_page { } { - my $row_count; + my @row_count; sub start_data_table { my ($add_class) = @_; my $css_class = (join(' ','LC_data_table',$add_class)); - undef($row_count); + unshift(@row_count,0); return ''."\n"; } sub end_data_table { - undef($row_count); + shift(@row_count); return '
'."\n";; } sub start_data_table_row { my ($add_class) = @_; - $row_count++; - my $css_class = ($row_count % 2)?'':'LC_even_row'; + $row_count[0]++; + my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row'; $css_class = (join(' ',$css_class,$add_class)); return ''."\n";; } sub continue_data_table_row { my ($add_class) = @_; - my $css_class = ($row_count % 2)?'':'LC_even_row'; + my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row'; $css_class = (join(' ',$css_class,$add_class)); return ''."\n";; } @@ -5524,7 +5555,7 @@ sub simple_error_page { } sub start_data_table_empty_row { - $row_count++; + $row_count[0]++; return ''."\n";; } @@ -5796,12 +5827,15 @@ previous, future, or all. 5. reference to array of section restrictions (optional) 6. reference to results object (hash of hashes). 7. reference to optional userdata hash -Keys of top level hash are roles. +8. reference to optional statushash +Keys of top level results hash are roles. Keys of inner hashes are username:domain, with values set to access type. Optional userdata hash returns an array with arguments in the same order as loncoursedata::get_classlist() for student data. +Optional statushash returns + Entries for end, start, section and status are blank because of the possibility of multiple values for non-student roles. @@ -5810,7 +5844,7 @@ of the possibility of multiple values fo ############################################### sub get_course_users { - my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_; + my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash) = @_; my %idx = (); my %seclists; @@ -5830,6 +5864,7 @@ sub get_course_users { my $match = 0; my $secmatch = 0; my $section = $$classlist{$student}[$idx{section}]; + my $status = $$classlist{$student}[$idx{status}]; if ($section eq '') { $section = 'none'; } @@ -5849,7 +5884,6 @@ sub get_course_users { next; } } - push(@{$seclists{$student}},$section); if (defined($$types{'active'})) { if ($$classlist{$student}[$idx{status}] eq 'Active') { push(@{$$users{st}{$student}},'active'); @@ -5857,25 +5891,35 @@ sub get_course_users { } } if (defined($$types{'previous'})) { - if ($$classlist{$student}[$idx{end}] <= $now) { + if ($$classlist{$student}[$idx{status}] eq 'Expired') { push(@{$$users{st}{$student}},'previous'); $match = 1; } } if (defined($$types{'future'})) { - if (($$classlist{$student}[$idx{start}] > $now) && ($$classlist{$student}[$idx{end}] > $now) || ($$classlist{$student}[$idx{end}] == 0) || ($$classlist{$student}[$idx{end}] eq '')) { + if ($$classlist{$student}[$idx{status}] eq 'Future') { push(@{$$users{st}{$student}},'future'); $match = 1; } } - if ($match && ref($userdata) eq 'HASH') { - $$userdata{$student} = $$classlist{$student}; + if ($match) { + push(@{$seclists{$student}},$section); + if (ref($userdata) eq 'HASH') { + $$userdata{$student} = $$classlist{$student}; + } + if (ref($statushash) eq 'HASH') { + $statushash->{$student}{'st'}{$section} = $status; + } } } } if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) { my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); my $now = time; + my %displaystatus = ( previous => 'Expired', + active => 'Active', + future => 'Future', + ); foreach my $person (sort(keys(%coursepersonnel))) { my $match = 0; my $secmatch = 0; @@ -5931,6 +5975,9 @@ sub get_course_users { if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) { push(@{$seclists{$uname.':'.$udom}},$usec); } + if (ref($statushash) eq 'HASH') { + $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status}; + } } } } @@ -5940,15 +5987,25 @@ sub get_course_users { my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum); if ( defined($csettings{'internal.courseowner'}) ) { my $owner = $csettings{'internal.courseowner'}; - if ($owner !~ /^[^:]+:[^:]+$/) { - $owner = $owner.':'.$cdom; + next if ($owner eq ''); + my ($ownername,$ownerdom); + if ($owner =~ /^([^:]+):([^:]+)$/) { + $ownername = $1; + $ownerdom = $2; + } else { + $ownername = $owner; + $ownerdom = $cdom; + $owner = $ownername.':'.$ownerdom; } @{$$users{'ow'}{$owner}} = 'any'; if (defined($userdata) && - !exists($$userdata{$owner.':'.$cdom})) { - &get_user_info($cdom,$owner,\%idx,$userdata); - if (!grep(/^none$/,@{$seclists{$owner.':'.$cdom}})) { - push(@{$seclists{$owner.':'.$cdom}},'none'); + !exists($$userdata{$owner})) { + &get_user_info($ownerdom,$ownername,\%idx,$userdata); + if (!grep(/^none$/,@{$seclists{$owner}})) { + push(@{$seclists{$owner}},'none'); + } + if (ref($statushash) eq 'HASH') { + $statushash->{$owner}{'ow'}{'none'} = 'Any'; } } } @@ -5968,6 +6025,8 @@ sub get_user_info { &plainname($uname,$udom,'lastname'); $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname; $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom; + my %idhash = &Apache::lonnet::idrget($udom,($uname)); + $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname}; return; } @@ -6380,57 +6439,143 @@ 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 [_1], but the user does not exist in the institutional directory.',$domdesc).'
'.&mt("You must choose a username with a different format -- one that will not conflict with 'official' institutional usernames."); - } +sub user_rule_check { + my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_; + my $response; + if (ref($usershash) eq 'HASH') { + foreach my $user (keys(%{$usershash})) { + my ($uname,$udom) = split(/:/,$user); + next if ($udom eq '' || $uname eq ''); + my ($id,$newuser); + if (ref($usershash->{$user}) eq 'HASH') { + $newuser = $usershash->{$user}->{'newuser'}; + $id = $usershash->{$user}->{'id'}; + } + my $inst_response; + if (ref($checks) eq 'HASH') { + if (defined($checks->{'username'})) { + ($inst_response,%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,$uname); + } elsif (defined($checks->{'id'})) { + ($inst_response,%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,undef,$id); + } + } else { + ($inst_response,%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,$uname); + return; + } + if (!$got_rules->{$udom}) { + my %domconfig = &Apache::lonnet::get_dom('configuration', + ['usercreation'],$udom); + if (ref($domconfig{'usercreation'}) eq 'HASH') { + foreach my $item ('username','id') { + if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { + $$curr_rules{$udom}{$item} = + $domconfig{'usercreation'}{$item.'_rule'}; } } - last; } + $got_rules->{$udom} = 1; } - if ($response) { - if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) { - if (@{$ruleorder} > 0) { - $response .= '
'.&mt('Usernames with the following format(s) may only be used for verified users at [_1]:',$domdesc).' '; } } } } - return ($response,$rulematch,$rules,%inst_results); + return; +} + +sub user_rule_formats { + my ($domain,$domdesc,$curr_rules,$check) = @_; + my %text = ( + 'username' => 'Usernames', + 'id' => 'IDs', + ); + my $output; + my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check); + if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) { + if (@{$ruleorder} > 0) { + $output = '
'.&mt("$text{$check} with the following format(s) may only be used for verified users at [_1]:",$domdesc).' '; + } + } + return $output; +} + +sub instrule_disallow_msg { + my ($checkitem,$domdesc,$count,$mode) = @_; + my $response; + my %text = ( + item => 'username', + items => 'usernames', + match => 'matches', + do => 'does', + action => 'a username', + one => 'one', + ); + if ($count > 1) { + $text{'item'} = 'usernames'; + $text{'match'} ='match'; + $text{'do'} = 'do'; + $text{'action'} = 'usernames', + $text{'one'} = 'ones'; + } + if ($checkitem eq 'id') { + $text{'items'} = 'IDs'; + $text{'item'} = 'ID'; + $text{'action'} = 'an ID'; + if ($count > 1) { + $text{'item'} = 'IDs'; + $text{'action'} = 'IDs'; + } + } + $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for [_1], but the $text{'item'} $text{'do'} not exist in the institutional directory.",$domdesc).'
'; + if ($mode eq 'upload') { + if ($checkitem eq 'username') { + $response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}."); + } elsif ($checkitem eq 'id') { + $response .= &mt("Either upload a file which includes $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the ID/Student Number field."); + } + } else { + if ($checkitem eq 'username') { + $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}."); + } elsif ($checkitem eq 'id') { + $response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank."); + } + } + return $response; } =pod @@ -7491,6 +7636,76 @@ sub restore_settings { } } +####################################################### +####################################################### + +=pod + +=head1 Domain E-mail Routines + +=over 4 + +=item &build_recipient_list + +Build recipient lists for three types of e-mail: +(a) Error Reports, (b) Package Updates, (c) Help requests, generated by +lonerrorhandler.pm, CHECKRPMS and lonsupportreq.pm respectively. + +Inputs: +defmail (scalar - email address of default recipient), +mailing type (scalar - errormail, packagesmail, or helpdeskmail), +defdom (domain for which to retrieve configuration settings), +origmail (scalar - email address of recipient from loncapa.conf, +i.e., predates configuration by DC via domainprefs.pm + +Returns: comma separated list of addresses to which to send e-mail. + +=cut + +############################################################ +############################################################ +sub build_recipient_list { + my ($defmail,$mailing,$defdom,$origmail) = @_; + my @recipients; + my $otheremails; + my %domconfig = + &Apache::lonnet::get_dom('configuration',['contacts'],$defdom); + if (ref($domconfig{'contacts'}) eq 'HASH') { + if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') { + my @contacts = ('adminemail','supportemail'); + foreach my $item (@contacts) { + if ($domconfig{'contacts'}{$mailing}{$item}) { + my $addr = $domconfig{'contacts'}{$item}; + if (!grep(/^\Q$addr\E$/,@recipients)) { + push(@recipients,$addr); + } + } + $otheremails = $domconfig{'contacts'}{$mailing}{'others'}; + } + } + } elsif ($origmail ne '') { + push(@recipients,$origmail); + } + if ($defmail ne '') { + push(@recipients,$defmail); + } + if ($otheremails) { + my @others; + if ($otheremails =~ /,/) { + @others = split(/,/,$otheremails); + } else { + push(@others,$otheremails); + } + foreach my $addr (@others) { + if (!grep(/^\Q$addr\E$/,@recipients)) { + push(@recipients,$addr); + } + } + } + my $recipientlist = join(',',@recipients); + return $recipientlist; +} + ############################################################ ############################################################