--- loncom/interface/loncommon.pm 2013/07/22 20:50:01 1.1142 +++ loncom/interface/loncommon.pm 2013/12/01 21:29:12 1.1162 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1142 2013/07/22 20:50:01 raeburn Exp $ +# $Id: loncommon.pm,v 1.1162 2013/12/01 21:29:12 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1388,22 +1388,23 @@ sub top_nav_help { return <<"END"; $banner_link - $text +$text END } sub help_menu_js { - my ($text) = @_; + my ($httphost) = @_; my $stayOnPage = 1; my $width = 620; my $height = 600; my $helptopic=&general_help(); - my $details_link = '/adm/help/'.$helptopic.'.hlp'; + my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp'; my $nothing=&Apache::lonhtmlcommon::javascript_nothing(); my $start_page = &Apache::loncommon::start_page('Help Menu', undef, {'frameset' => 1, 'js_ready' => 1, + 'use_absolute' => $httphost, 'add_entries' => { 'border' => '0', 'rows' => "110,*",},}); @@ -1749,8 +1750,6 @@ RESIZE =head1 Excel and CSV file utility routines -=over 4 - =cut ############################################################### @@ -1758,6 +1757,8 @@ RESIZE =pod +=over 4 + =item * &csv_translate($text) Translate $text to allow it to be output as a 'comma separated values' @@ -5124,6 +5125,7 @@ sub bodytag { $public = 1; } if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } + my $httphost = $args->{'use_absolute'}; $function = &get_users_function() if (!$function); my $img = &designparm($function.'.img',$domain); @@ -5196,7 +5198,7 @@ sub bodytag { # } $bodytag .= Apache::lonhtmlcommon::scripttag( - Apache::lonmenu::utilityfunctions(), 'start'); + Apache::lonmenu::utilityfunctions($httphost), 'start'); my ($left,$right) = Apache::lonmenu::primary_menu(); @@ -5222,7 +5224,7 @@ sub bodytag { #don't show menus for public users if (!$public){ - $bodytag .= Apache::lonmenu::secondary_menu(); + $bodytag .= Apache::lonmenu::secondary_menu($httphost); $bodytag .= Apache::lonmenu::serverform(); $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end'); if ($env{'request.state'} eq 'construct') { @@ -5282,7 +5284,7 @@ sub make_attr_string { } my $attr_string; - foreach my $attr (keys(%$attr_ref)) { + foreach my $attr (sort(keys(%$attr_ref))) { $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" '; } return $attr_string; @@ -6496,6 +6498,14 @@ div.LC_edit_problem_saves { white-space: nowrap; } +.LC_edit_problem_latexhelper{ + text-align: right; +} + +#LC_edit_problem_colorful div{ + margin-left: 40px; +} + img.stift { border-width: 0; vertical-align: middle; @@ -7261,6 +7271,7 @@ sub headtag { my $function = $args->{'function'} || &get_users_function(); my $domain = $args->{'domain'} || &determinedomain(); my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain); + my $httphost = $args->{'use_absolute'}; my $url = join(':',$env{'user.name'},$env{'user.domain'}, $Apache::lonnet::perlvar{'lonVersion'}, #time(), @@ -7271,7 +7282,7 @@ sub headtag { my $result = ''. - &font_settings(); + &font_settings($args); my $inhibitprint = &print_suppression(); @@ -7284,7 +7295,7 @@ sub headtag { if (!$args->{'no_nav_bar'} && !$args->{'only_body'} && !$args->{'frameset'}) { - $result .= &help_menu_js(); + $result .= &help_menu_js($httphost); $result.=&modal_window(); $result.=&togglebox_script(); $result.=&wishlist_window(); @@ -7336,15 +7347,17 @@ ADDMETA Returns neccessary to set the proper encoding -Inputs: none +Inputs: optional reference to HASH -- $args passed to &headtag() =cut sub font_settings { + my ($args) = @_; my $headerstring=''; - if (!$env{'browser.mathml'} && $env{'browser.unicode'}) { + if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) || + ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) { $headerstring.= - ''; + ''."\n"; } return $headerstring; } @@ -7448,8 +7461,8 @@ sub xml_begin { .''; } else { - $output='' - .''; + $output=''."\n" + .''."\n"; } return $output; } @@ -8044,10 +8057,16 @@ function expand_div(caller) { } sub simple_error_page { - my ($r,$title,$msg) = @_; + my ($r,$title,$msg,$args) = @_; + if (ref($args) eq 'HASH') { + if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); } + } else { + $msg = &mt($msg); + } + my $page = &Apache::loncommon::start_page($title). - '

'.&mt($msg).'

'. + '

'.$msg.'

'. &Apache::loncommon::end_page(); if (ref($r)) { $r->print($page); @@ -8884,7 +8903,7 @@ sub default_quota { Returns warning message if upload of file to authoring space, or copying of existing file within authoring space will cause quota for the authoring -space to be exceeded, +space to be exceeded. Same, if upload of a file directly to a course/community via Course Editor will cause quota for uploaded content for the course to be exceeded. @@ -9772,11 +9791,10 @@ sub ask_for_embedded_content { my $numexisting = 0; my $numunused = 0; my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum, - $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path); + $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap); my $heading = &mt('Upload embedded files'); my $buttontext = &mt('Upload'); - my ($navmap,$cdom,$cnum); if ($env{'request.course.id'}) { if ($actionurl eq '/adm/dependencies') { $navmap = Apache::lonnavmaps::navmap->new(); @@ -9860,17 +9878,18 @@ sub ask_for_embedded_content { } else { $embed_file = $file; } - my $absolutepath; + my ($absolutepath,$cleaned_file); if ($embed_file =~ m{^\w+://}) { - $newfiles{$embed_file} = 1; - $mapping{$embed_file} = $embed_file; + $cleaned_file = $embed_file; + $newfiles{$cleaned_file} = 1; + $mapping{$cleaned_file} = $embed_file; } else { + $cleaned_file = &clean_path($embed_file); if ($embed_file =~ m{^/}) { $absolutepath = $embed_file; - $embed_file =~ s{^(/+)}{}; } - if ($embed_file =~ m{/}) { - my ($path,$fname) = ($embed_file =~ m{^(.+)/([^/]*)$}); + if ($cleaned_file =~ m{/}) { + my ($path,$fname) = ($cleaned_file =~ m{^(.+)/([^/]*)$}); $path = &check_for_traversal($path,$url,$toplevel); my $item = $fname; if ($path ne '') { @@ -9887,9 +9906,9 @@ sub ask_for_embedded_content { } else { $dependencies{$embed_file} = 1; if ($absolutepath) { - $mapping{$embed_file} = $absolutepath; + $mapping{$cleaned_file} = $absolutepath; } else { - $mapping{$embed_file} = $embed_file; + $mapping{$cleaned_file} = $embed_file; } } } @@ -10263,6 +10282,46 @@ sub ask_for_embedded_content { return ($output,$counter,$numpathchg); } +=pod + +=item * clean_path($name) + +Performs clean-up of directories, subdirectories and filename in an +embedded object, referenced in an HTML file which is being uploaded +to a course or portfolio, where +"Upload embedded images/multimedia files if HTML file" checkbox was +checked. + +Clean-up is similar to replacements in lonnet::clean_filename() +except each / between sub-directory and next level is preserved. + +=cut + +sub clean_path { + my ($embed_file) = @_; + $embed_file =~s{^/+}{}; + my @contents; + if ($embed_file =~ m{/}) { + @contents = split(/\//,$embed_file); + } else { + @contents = ($embed_file); + } + my $lastidx = scalar(@contents)-1; + for (my $i=0; $i<=$lastidx; $i++) { + $contents[$i]=~s{\\}{/}g; + $contents[$i]=~s/\s+/\_/g; + $contents[$i]=~s{[^/\w\.\-]}{}g; + if ($i == $lastidx) { + $contents[$i]=~s/\.(\d+)(?=\.)/_$1/g; + } + } + if ($lastidx > 0) { + return join('/',@contents); + } else { + return $contents[0]; + } +} + sub embedded_file_element { my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_; return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') && @@ -10387,7 +10446,8 @@ sub upload_embedded { # Check if extension is valid if (($fname =~ /\.(\w+)$/) && (&Apache::loncommon::fileembstyle($1) eq 'hdn')) { - $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1).'
'; + $output .= &mt('Invalid file extension ([_1]) - reserved for internal use.',$1) + .' '.&mt('Rename the file with a different extension and re-upload.').'
'; next; } elsif (($fname =~ /\.(\w+)$/) && (!defined(&Apache::loncommon::fileembstyle($1)))) { @@ -10651,6 +10711,7 @@ sub modify_html_refs { my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi); $count += $numchg; $allfiles{$newname} = $allfiles{$ref}; + delete($allfiles{$ref}); } if ($env{'form.embedded_codebase_'.$i} ne '') { $codebase = &unescape($env{'form.embedded_codebase_'.$i}); @@ -12011,7 +12072,7 @@ sub cleanup_empty_dirs { =pod -=item &get_folder_hierarchy() +=item * &get_folder_hierarchy() Provides hierarchy of names of folders/sub-folders containing the current item, @@ -12121,6 +12182,9 @@ sub get_turnedin_filepath { my $title = $res->compTitle(); $title =~ s/\W+/_/g; if ($title ne '') { + if (($pc > 1) && (length($title) > 12)) { + $title = substr($title,0,12); + } push(@pathitems,$title); } } @@ -12129,6 +12193,9 @@ sub get_turnedin_filepath { my $maptitle = $mapres->compTitle(); $maptitle =~ s/\W+/_/g; if ($maptitle ne '') { + if (length($maptitle) > 12) { + $maptitle = substr($maptitle,0,12); + } push(@pathitems,$maptitle); } unless ($env{'request.state'} eq 'construct') { @@ -12169,6 +12236,9 @@ sub get_turnedin_filepath { $restitle = time; } } + if (length($restitle) > 12) { + $restitle = substr($restitle,0,12); + } push(@pathitems,$restitle); $path .= join('/',@pathitems); } @@ -13106,16 +13176,20 @@ sub restore_settings { =item * &build_recipient_list() -Build recipient lists for five types of e-mail: +Build recipient lists for following types of e-mail: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors -(d) Help requests, (e) Course requests needing approval, generated by -lonerrorhandler.pm, CHECKRPMS, loncron, lonsupportreq.pm and -loncoursequeueadmin.pm respectively. +(d) Help requests, (e) Course requests needing approval, (f) loncapa +module change checking, student/employee ID conflict checks, as +generated by lonerrorhandler.pm, CHECKRPMS, loncron, +lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively. Inputs: defmail (scalar - email address of default recipient), -mailing type (scalar - errormail, packagesmail, or helpdeskmail), +mailing type (scalar: errormail, packagesmail, helpdeskmail, +requestsmail, updatesmail, or idconflictsmail). + 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 @@ -13311,7 +13385,7 @@ sub extract_categories { =pod -=item *&recurse_categories() +=item * &recurse_categories() Recursively used to generate breadcrumb trails for course categories. @@ -13382,7 +13456,7 @@ sub recurse_categories { =pod -=item *&assign_categories_table() +=item * &assign_categories_table() Create a datatable for display of hierarchical categories in a domain, with checkboxes to allow a course to be categorized. @@ -13459,7 +13533,7 @@ sub assign_categories_table { =pod -=item *&assign_category_rows() +=item * &assign_category_rows() Create a datatable row for display of nested categories in a domain, with checkboxes to allow a course to be categorized,called recursively. @@ -13493,7 +13567,7 @@ sub assign_category_rows { if (ref($cats->[$depth]{$parent}) eq 'ARRAY') { my $numchildren = @{$cats->[$depth]{$parent}}; my $css_class = $itemcount%2?' class="LC_odd_row"':''; - $text .= ''; + $text .= '
'; for (my $j=0; $j<$numchildren; $j++) { $name = $cats->[$depth]{$parent}[$j]; $item = &escape($name).':'.&escape($parent).':'.$depth; @@ -14343,6 +14417,12 @@ sub init_user_environment { $env{'browser.interface'}=$form->{'interface'}; } + if ($form->{'iptoken'}) { + my $lonhost = $r->dir_config('lonHostID'); + $initial_env{"user.noloadbalance"} = $lonhost; + $env{'user.noloadbalance'} = $lonhost; + } + my %is_adv = ( is_adv => $env{'user.adv'} ); my %domdef; unless ($domain eq 'public') { @@ -14576,6 +14656,30 @@ sub parse_supplemental_title { return $title; } +sub recurse_supplemental { + my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_; + if ($suppmap) { + my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap); + if ($fatal) { + $errors ++; + } else { + if ($#LONCAPA::map::resources > 0) { + foreach my $res (@LONCAPA::map::resources) { + my ($title,$src,$ext,$type,$status)=split(/\:/,$res); + if (($src ne '') && ($status eq 'res')) { + if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) { + ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors); + } else { + $numfiles ++; + } + } + } + } + } + } + return ($numfiles,$errors); +} + sub symb_to_docspath { my ($symb) = @_; return unless ($symb); @@ -14605,7 +14709,7 @@ sub symb_to_docspath { my $thistitle = $res->title(); $path .= '&'. &Apache::lonhtmlcommon::entity_encode($thisurl).'&'. - &Apache::lonhtmlcommon::entity_encode($thistitle). + &escape($thistitle). ':'.$res->randompick(). ':'.$res->randomout(). ':'.$res->encrypted(). @@ -14621,7 +14725,7 @@ sub symb_to_docspath { } $path .= (($path ne '')? '&' : ''). &Apache::lonhtmlcommon::entity_encode($mapurl).'&'. - &Apache::lonhtmlcommon::entity_encode($maptitle). + &escape($maptitle). ':'.$mapresobj->randompick(). ':'.$mapresobj->randomout(). ':'.$mapresobj->encrypted(). @@ -14634,11 +14738,11 @@ sub symb_to_docspath { $maptitle = 'Main Content'; } $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'. - &Apache::lonhtmlcommon::entity_encode($maptitle).':::::'.$ispage; + &escape($maptitle).':::::'.$ispage; } unless ($mapurl eq 'default') { $path = 'default&'. - &Apache::lonhtmlcommon::entity_encode('Main Content'). + &escape('Main Content'). ':::::&'.$path; } return $path; @@ -14777,9 +14881,13 @@ sub check_captcha { sub create_recaptcha { my ($pubkey) = @_; + my $use_ssl; + if ($ENV{'SERVER_PORT'} == 443) { + $use_ssl = 1; + } my $captcha = Captcha::reCAPTCHA->new; return $captcha->get_options_setter({theme => 'white'})."\n". - $captcha->get_html($pubkey). + $captcha->get_html($pubkey,undef,$use_ssl). &mt('If either word is hard to read, [_1] will replace them.', 'reCAPTCHA refresh'). '

'; @@ -14802,6 +14910,28 @@ sub check_recaptcha { return $captcha_chk; } +sub cleanup_html { + my ($incoming) = @_; + my $outgoing; + if ($incoming ne '') { + $outgoing = $incoming; + $outgoing =~ s/;/;/g; + $outgoing =~ s/\#/#/g; + $outgoing =~ s/\&/&/g; + $outgoing =~ s//>/g; + $outgoing =~ s/\(/(/g; + $outgoing =~ s/\)/)/g; + $outgoing =~ s/"/"/g; + $outgoing =~ s/'/'/g; + $outgoing =~ s/\$/$/g; + $outgoing =~ s{/}{/}g; + $outgoing =~ s/=/=/g; + $outgoing =~ s/\\/\/g + } + return $outgoing; +} + =pod =back