--- loncom/interface/loncommon.pm 2008/07/06 05:01:52 1.664 +++ loncom/interface/loncommon.pm 2008/10/02 14:05:45 1.689 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.664 2008/07/06 05:01:52 raeburn Exp $ +# $Id: loncommon.pm,v 1.689 2008/10/02 14:05:45 bisitz Exp $ # # Copyright Michigan State University Board of Trustees # @@ -61,6 +61,7 @@ use POSIX qw(strftime mktime); use Apache::lonmenu(); use Apache::lonenc(); use Apache::lonlocal; +use Apache::lonnet(); use HTML::Entities; use Apache::lonhtmlcommon(); use Apache::loncoursedata(); @@ -68,6 +69,7 @@ use Apache::lontexconvert(); use Apache::lonclonecourse(); use LONCAPA qw(:DEFAULT :match); use DateTime::TimeZone; +use DateTime::Locale::Catalog; # ---------------------------------------------- Designs use vars qw(%defaultdesign); @@ -657,6 +659,57 @@ sub select_timezone { return $output; } +sub select_datelocale { + my ($name,$selected,$onchange,$includeempty)=@_; + my $output='<select name="'.$name.'" '.$onchange.'>'."\n"; + if ($includeempty) { + $output .= '<option value=""'; + if ($selected eq '') { + $output .= ' selected="selected" '; + } + $output .= '> </option>'; + } + my (@possibles,%locale_names); + my @locales = DateTime::Locale::Catalog::Locales; + foreach my $locale (@locales) { + if (ref($locale) eq 'HASH') { + my $id = $locale->{'id'}; + if ($id ne '') { + my $en_terr = $locale->{'en_territory'}; + my $native_terr = $locale->{'native_territory'}; + my @languages = &preferred_languages(); + if (grep(/^en$/,@languages) || !@languages) { + if ($en_terr ne '') { + $locale_names{$id} = '('.$en_terr.')'; + } elsif ($native_terr ne '') { + $locale_names{$id} = $native_terr; + } + } else { + if ($native_terr ne '') { + $locale_names{$id} = $native_terr.' '; + } elsif ($en_terr ne '') { + $locale_names{$id} = '('.$en_terr.')'; + } + } + push (@possibles,$id); + } + } + } + foreach my $item (sort(@possibles)) { + $output.= '<option value="'.$item.'"'; + if ($item eq $selected) { + $output.=' selected="selected"'; + } + $output.=">$item"; + if ($locale_names{$item} ne '') { + $output.=" $locale_names{$item}</option>\n"; + } + $output.="</option>\n"; + } + $output.="</select>"; + return $output; +} + =pod =item * &linked_select_forms(...) @@ -878,7 +931,7 @@ sub help_open_topic { # Add the graphic my $title = &mt('Online Help'); - my $helpicon=&lonhttpdurl("/res/adm/pages/help.png"); + my $helpicon=&lonhttpdurl("/adm/help/help.png"); $template .= <<"ENDTEMPLATE"; <a target="_top" href="$link" title="$title"><img src="$helpicon" border="0" alt="(Help: $topic)" /></a> ENDTEMPLATE @@ -904,6 +957,9 @@ sub helpLatexCheatsheet { .'</td><td>'. &Apache::loncommon::help_open_topic("Other_Symbols",&mt('Other Symbols'), undef,undef,600) + .'</td><td>'. + &Apache::loncommon::help_open_topic("Authoring_Output_Tags",&mt('Output Tags'), + undef,undef,600) .'</td></tr></table>'; } @@ -913,6 +969,8 @@ sub general_help { $helptopic='Authoring_Intro'; } elsif ($env{'request.role'}=~/^cc/) { $helptopic='Course_Coordination_Intro'; + } elsif ($env{'request.role'}=~/^dc/) { + $helptopic='Domain_Coordination_Intro'; } return $helptopic; } @@ -1502,9 +1560,9 @@ sub create_text_file { $fh = Apache::File->new('>/home/httpd'.$filename); if (! defined($fh)) { $r->log_error("Couldn't open $filename for output $!"); - $r->print("Problems occured in creating the output file. ". - "This error has been logged. ". - "Please alert your LON-CAPA administrator."); + $r->print(&mt('Problems occurred in creating the output file. ' + .'This error has been logged. ' + .'Please alert your LON-CAPA administrator.')); } return ($fh,$filename) } @@ -2982,14 +3040,19 @@ sub preferred_languages { } } } + return &get_genlanguages(@languages); +} + +sub get_genlanguages { + my (@languages) = @_; # turn "en-ca" into "en-ca,en" my @genlanguages; foreach my $lang (@languages) { - unless ($lang=~/\w/) { next; } - push(@genlanguages,$lang); - if ($lang=~/(\-|\_)/) { - push(@genlanguages,(split(/(\-|\_)/,$lang))[0]); - } + unless ($lang=~/\w/) { next; } + push(@genlanguages,$lang); + if ($lang=~/(\-|\_)/) { + push(@genlanguages,(split(/(\-|\_)/,$lang))[0]); + } } #uniqueify the languages list my %count; @@ -3343,16 +3406,21 @@ sub pprmlink { sub timehash { - my @ltime=localtime(shift); - return ( 'seconds' => $ltime[0], - 'minutes' => $ltime[1], - 'hours' => $ltime[2], - 'day' => $ltime[3], - 'month' => $ltime[4]+1, - 'year' => $ltime[5]+1900, - 'weekday' => $ltime[6], - 'dayyear' => $ltime[7]+1, - 'dlsav' => $ltime[8] ); + my ($thistime) = @_; + my $timezone = &Apache::lonlocal::gettimezone(); + my $dt = DateTime->from_epoch(epoch => $thistime) + ->set_time_zone($timezone); + my $wday = $dt->day_of_week(); + if ($wday == 7) { $wday = 0; } + return ( 'second' => $dt->second(), + 'minute' => $dt->minute(), + 'hour' => $dt->hour(), + 'day' => $dt->day_of_month(), + 'month' => $dt->month(), + 'year' => $dt->year(), + 'weekday' => $wday, + 'dayyear' => $dt->day_of_year(), + 'dlsav' => $dt->is_dst() ); } sub utc_string { @@ -3362,6 +3430,24 @@ sub utc_string { sub maketime { my %th=@_; + my ($epoch_time,$timezone,$dt); + $timezone = &Apache::lonlocal::gettimezone(); + eval { + $dt = DateTime->new( year => $th{'year'}, + month => $th{'month'}, + day => $th{'day'}, + hour => $th{'hour'}, + minute => $th{'minute'}, + second => $th{'second'}, + time_zone => $timezone, + ); + }; + if (!$@) { + $epoch_time = $dt->epoch; + if ($epoch_time) { + return $epoch_time; + } + } return POSIX::mktime( ($th{'seconds'},$th{'minutes'},$th{'hours'}, $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1)); @@ -3742,6 +3828,60 @@ sub blocking_status { ############################################### +sub check_ip_acc { + my ($acc)=@_; + &Apache::lonxml::debug("acc is $acc"); + if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) { + return 1; + } + my $allowed=0; + my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'}; + + my $name; + foreach my $pattern (split(',',$acc)) { + $pattern =~ s/^\s*//; + $pattern =~ s/\s*$//; + if ($pattern =~ /\*$/) { + #35.8.* + $pattern=~s/\*//; + if ($ip =~ /^\Q$pattern\E/) { $allowed=1; } + } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) { + #35.8.3.[34-56] + my $low=$2; + my $high=$3; + $pattern=$1; + if ($ip =~ /^\Q$pattern\E/) { + my $last=(split(/\./,$ip))[3]; + if ($last <=$high && $last >=$low) { $allowed=1; } + } + } elsif ($pattern =~ /^\*/) { + #*.msu.edu + $pattern=~s/\*//; + if (!defined($name)) { + use Socket; + my $netaddr=inet_aton($ip); + ($name)=gethostbyaddr($netaddr,AF_INET); + } + if ($name =~ /\Q$pattern\E$/i) { $allowed=1; } + } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) { + #127.0.0.1 + if ($ip =~ /^\Q$pattern\E/) { $allowed=1; } + } else { + #some.name.com + if (!defined($name)) { + use Socket; + my $netaddr=inet_aton($ip); + ($name)=gethostbyaddr($netaddr,AF_INET); + } + if ($name =~ /\Q$pattern\E$/i) { $allowed=1; } + } + if ($allowed) { last; } + } + return $allowed; +} + +############################################### + =pod =head1 Domain Template Functions @@ -4488,7 +4628,6 @@ table.LC_docs_path td.LC_docs_path_compo td.LC_table_cell_checkbox { text-align: center; } - table#LC_mainmenu td.LC_mainmenu_column { vertical-align: top; } @@ -4502,7 +4641,7 @@ table#LC_mainmenu td.LC_mainmenu_column .LC_menubuttons_link { text-decoration: none; } - +#2008--9-5: new menu style sheet.Changed category .LC_menubuttons_category { color: $font; background: $pgbg; @@ -4569,6 +4708,10 @@ td.LC_menubuttons_img { text-align: right; } +.LC_roleslog_note { + font-size: smaller; +} + table.LC_aboutme_port { border: 0px; border-collapse: collapse; @@ -5351,6 +5494,32 @@ hr.LC_edit_problem_divide { height: 3px; border: 0px; } +img.stift{ + border-width:0; + vertical-align:middle; +} + +table#LC_mainmenu{ + margin-top:10px; + width:80%; + +} + +table#LC_mainmenu td.LC_mainmenu_col_fieldset{ + vertical-align: top; + width: 45%; +} +.LC_mainmenu_fieldset_category { + color: $font; + background: $pgbg; + font-family: $sans; + font-size: small; + font-weight: bold; +} +fieldset#LC_mainmenu_fieldset { + margin:0px 10px 10px 0px; + +} END } @@ -6799,12 +6968,16 @@ sub instrule_disallow_msg { $text{'action'} = 'IDs'; } } - $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for <span class=\"LC_cusr_emph\">[_1]</span>, but the $text{'item'} $text{'do'} not exist in the institutional directory.",$domdesc).'<br />'; + $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.",'<span class="LC_cusr_emph">'.$domdesc.'</span>').'<br />'; 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."); + $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 Student/Employee ID field."); + } + } elsif ($mode eq 'selfcreate') { + if ($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."); } } else { if ($checkitem eq 'username') { @@ -6834,7 +7007,7 @@ sub sorted_inst_types { my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom); my $othertitle = &mt('All users'); if ($env{'request.course.id'}) { - $othertitle = 'any'; + $othertitle = &mt('Any users'); } my @types; if (ref($order) eq 'ARRAY') { @@ -6847,9 +7020,6 @@ sub sorted_inst_types { } if (keys(%{$usertypes}) > 0) { $othertitle = &mt('Other users'); - if ($env{'request.course.id'}) { - $othertitle = 'other'; - } } return ($othertitle,$usertypes,\@types); } @@ -7238,7 +7408,6 @@ sub check_for_upload { } } } - my $getpropath = 1; if (($current_disk_usage + $filesize) > $disk_quota){ my $msg = '<span class="LC_error">'. &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'. @@ -7538,7 +7707,7 @@ sub csv_print_select_table { &end_data_table_header_row()."\n"); foreach my $array_ref (@$d) { my ($value,$display,$defaultcol)=@{ $array_ref }; - $r->print(&start_data_table_row().'<tr><td>'.$display.'</td>'); + $r->print(&start_data_table_row().'<td>'.$display.'</td>'); $r->print('<td><select name=f'.$i. ' onchange="javascript:flip(this.form,'.$i.');">'); @@ -8235,8 +8404,10 @@ sub build_recipient_list { } elsif ($origmail ne '') { push(@recipients,$origmail); } - if ($defmail ne '') { - push(@recipients,$defmail); + if (defined($defmail)) { + if ($defmail ne '') { + push(@recipients,$defmail); + } } if ($otheremails) { my @others; @@ -8340,6 +8511,9 @@ idx (reference to hash of counters used jsarray (reference to array of categories used to create Javascript arrays for Domain Coordinator interface for editing Course Categories). +subcats (reference to hash of arrays containing all subcategories within each + category, -recursive) + Returns: nothing Side effects: populates trails and allitems hash references. @@ -8347,7 +8521,7 @@ Side effects: populates trails and allit =cut sub extract_categories { - my ($categories,$cats,$trails,$allitems,$idx,$jsarray) = @_; + my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_; if (ref($categories) eq 'HASH') { &gather_categories($categories,$cats,$idx,$jsarray); if (ref($cats->[0]) eq 'ARRAY') { @@ -8368,7 +8542,14 @@ sub extract_categories { if (ref($cats->[1]{$name}) eq 'ARRAY') { for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) { my $category = $cats->[1]{$name}[$j]; - &recurse_categories($cats,2,$category,$trails,$allitems,\@parents); + if (ref($subcats) eq 'HASH') { + push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1'); + } + &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats); + } + } else { + if (ref($subcats) eq 'HASH') { + $subcats->{$item} = []; } } } @@ -8407,7 +8588,7 @@ Side effects: populates trails and allit =cut sub recurse_categories { - my ($cats,$depth,$category,$trails,$allitems,$parents) = @_; + my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_; my $shallower = $depth - 1; if (ref($cats->[$depth]{$category}) eq 'ARRAY') { for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) { @@ -8420,7 +8601,21 @@ sub recurse_categories { } my $deeper = $depth+1; push(@{$parents},$category); - &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents); + if (ref($subcats) eq 'HASH') { + my $subcat = &escape($name).':'.$category.':'.$depth; + for (my $j=@{$parents}; $j>=0; $j--) { + my $higher; + if ($j > 0) { + $higher = &escape($parents->[$j]).':'. + &escape($parents->[$j-1]).':'.$j; + } else { + $higher = &escape($parents->[$j]).'::'.$j; + } + push(@{$subcats->{$higher}},$subcat); + } + } + &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents, + $subcats); pop(@{$parents}); } } else { @@ -8478,9 +8673,10 @@ sub assign_categories_table { $checked = ' checked="checked" '; } } - $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">' - .'<input type="checkbox" name="usecategory" value="'. - $item.'"'.$checked.' />'.&escape($parent).'</span></td>'; + $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'. + '<input type="checkbox" name="usecategory" value="'. + $item.'"'.$checked.' />'.$parent.'</span>'. + '<input type="hidden" name="catname" value="'.$parent.'" /></td>'; my $depth = 1; push(@path,$parent); $output .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories); @@ -8546,7 +8742,9 @@ sub assign_category_rows { } $text .= '<tr><td><span class="LC_nobreak"><label>'. '<input type="checkbox" name="usecategory" value="'. - $item.'"'.$checked.' />'.$name.'</label></span></td><td>'; + $item.'"'.$checked.' />'.$name.'</label></span>'. + '<input type="hidden" name="catname" value="'.$name.'" />'. + '</td><td>'; if (ref($path) eq 'ARRAY') { push(@{$path},$name); $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories); @@ -9229,7 +9427,7 @@ sub init_user_environment { } # Give them a new cookie my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'} - : $now); + : $now.$$.int(rand(10000))); $cookie="$username\_$id\_$domain\_$authhost"; # Initialize roles @@ -9344,12 +9542,52 @@ sub init_user_environment { sub _add_to_env { my ($idf,$env_data,$prefix) = @_; - while (my ($key,$value) = each(%$env_data)) { - $idf->{$prefix.$key} = $value; - $env{$prefix.$key} = $value; + if (ref($env_data) eq 'HASH') { + while (my ($key,$value) = each(%$env_data)) { + $idf->{$prefix.$key} = $value; + $env{$prefix.$key} = $value; + } + } +} + +# --- Get the symbolic name of a problem and the url +sub get_symb { + my ($request,$silent) = @_; + (my $url=$env{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--; + my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url))); + if ($symb eq '') { + if (!$silent) { + $request->print("Unable to handle ambiguous references:$url:."); + return (); + } } + &Apache::lonenc::check_decrypt(\$symb); + return ($symb); } +# --------------------------------------------------------------Get annotation + +sub get_annotation { + my ($symb,$enc) = @_; + + my $key = $symb; + if (!$enc) { + $key = + &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]); + } + my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]); + return $annotation{$key}; +} + +sub clean_symb { + my ($symb) = @_; + + &Apache::lonenc::check_decrypt(\$symb); + my $enc = $env{'request.enc'}; + delete($env{'request.enc'}); + + return ($symb,$enc); +} =pod