--- loncom/interface/loncommon.pm 2012/08/01 04:34:00 1.1075.2.11 +++ loncom/interface/loncommon.pm 2012/12/12 23:03:07 1.1075.2.17 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1075.2.11 2012/08/01 04:34:00 raeburn Exp $ +# $Id: loncommon.pm,v 1.1075.2.17 2012/12/12 23:03:07 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -70,6 +70,8 @@ use Apache::lonclonecourse(); use LONCAPA qw(:DEFAULT :match); use DateTime::TimeZone; use DateTime::Locale::Catalog; +use Authen::Captcha; +use Captcha::reCAPTCHA; # ---------------------------------------------- Designs use vars qw(%defaultdesign); @@ -885,10 +887,14 @@ sub check_uncheck_jscript { function checkAll(field) { if (field.length > 0) { for (i = 0; i < field.length; i++) { - field[i].checked = true ; + if (!field[i].disabled) { + field[i].checked = true; + } } } else { - field.checked = true + if (!field.disabled) { + field.checked = true; + } } } @@ -3226,7 +3232,7 @@ sub aboutmewrapper { if (!defined($username) && !defined($domain)) { return; } - return ''.$link.''; } @@ -4954,12 +4960,19 @@ Inputs: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value +=item * $no_inline_link, if true and in remote mode, don't show the + 'Switch To Inline Menu' link + =item * $args, optional argument valid values are no_auto_mt_title -> prevents &mt()ing the title arg inherit_jsmath -> when creating popup window in a page, should it have jsmath forced on by the current page +=item * $advtoolsref, optional argument, ref to an array containing + inlineremote items to be added in "Functions" menu below + breadcrumbs. + =back Returns: A uniform header for LON-CAPA web pages. @@ -4971,7 +4984,7 @@ other decorations will be returned. sub bodytag { my ($title,$function,$addentries,$bodyonly,$domain,$forcereg, - $no_nav_bar,$bgcolor,$args)=@_; + $no_nav_bar,$bgcolor,$no_inline_link,$args,$advtoolsref)=@_; my $public; if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')) @@ -5013,6 +5026,8 @@ sub bodytag { } if (!$realm) { $realm=' '; } +# Set messages + my $messages=&domainlogo($domain); my $extra_body_attr = &make_attr_string($forcereg,\%design); @@ -5047,11 +5062,13 @@ sub bodytag { $role = '('.$role.')' if $role; &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']); - if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') { - return $bodytag; - } + if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') { + return $bodytag; + } + + if ($env{'request.state'} eq 'construct') { $forcereg=1; } - if ($env{'request.state'} eq 'construct') { $forcereg=1; } + unless ($env{'environment.remote'} eq 'on') { # if ($env{'request.state'} eq 'construct') { # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls @@ -5094,6 +5111,12 @@ sub bodytag { $args->{'bread_crumbs'}); } elsif ($forcereg) { $bodytag .= &Apache::lonmenu::innerregister($forcereg); + } else { + $bodytag .= + &Apache::lonmenu::prepare_functions($env{'request.noversionuri'}, + $forcereg,$args->{'group'}, + $args->{'bread_crumbs'}, + $advtoolsref); } }else{ # this is to seperate menu from content when there's no secondary @@ -5103,6 +5126,55 @@ sub bodytag { } return $bodytag; + } + +# +# Top frame rendering, Remote is up +# + + my $imgsrc = $img; + if ($img =~ /^\/adm/) { + $imgsrc = &lonhttpdurl($img); + } + my $upperleft=''.$function.''; + + # Explicit link to get inline menu + my $menu= ($no_inline_link?'' + :''.&mt('Switch to Inline Menu Mode').''); + + if ($dc_info) { + $dc_info = qq|($dc_info)|; + } + + unless ($env{'form.inhibitmenu'}) { + $bodytag .= qq|
$name $role
+
    +
  1. $menu
  2. +
$realm $dc_info
|; + } + my $funclist; + if ($env{'request.state'} eq 'construct') { + if (!$public){ + if ($env{'request.state'} eq 'construct') { + $funclist = &Apache::lonhtmlcommon::scripttag( + &Apache::lonmenu::utilityfunctions(), 'start'). + &Apache::lonhtmlcommon::scripttag('','end'). + &Apache::lonmenu::innerregister($forcereg, + $args->{'bread_crumbs'}); + } + } + } + return(< +$upperleft + $messages  + +$titleinfo $dc_info $menu + + +$funclist +ENDBODY } sub dc_courseid_toggle { @@ -5134,8 +5206,15 @@ sub make_attr_string { delete($attr_ref->{$key}); } } - $attr_ref->{'onload'} = $on_load; - $attr_ref->{'onunload'}= $on_unload; + if ($env{'environment.remote'} eq 'on') { + $attr_ref->{'onload'} = + &Apache::lonmenu::loadevents(). $on_load; + $attr_ref->{'onunload'}= + &Apache::lonmenu::unloadevents().$on_unload; + } else { + $attr_ref->{'onload'} = $on_load; + $attr_ref->{'onunload'}= $on_unload; + } } my $attr_string; @@ -5308,10 +5387,12 @@ form, .inline { .LC_error { color: red; - font-size: larger; } -.LC_warning, +.LC_warning { + color: darkorange; +} + .LC_diff_removed { color: red; } @@ -5474,11 +5555,11 @@ td.LC_table_cell_checkbox { text-align: left; } -.LC_head_subbox { +.LC_head_subbox, .LC_actionbox { clear:both; background: #F8F8F8; /* $sidebg; */ border: 1px solid $sidebg; - margin: 0 0 10px 0; + margin: 0 0 10px 0; padding: 3px; text-align: left; } @@ -6173,7 +6254,6 @@ div.LC_docs_entry_move { table.LC_data_table tr > td.LC_docs_entry_commands, table.LC_data_table tr > td.LC_docs_entry_parameter { - background: #DDDDDD; font-size: x-small; } @@ -7047,6 +7127,27 @@ ul.LC_funclist li { cursor:pointer; } +/* + styles used by TTH when "Default set of options to pass to tth/m + when converting TeX" in course settings has been set + + option passed: -t + +*/ + +td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;} +td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;} +td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;} +td div.norm {line-height:normal;} + +/* + option passed -y3 +*/ + +span.roman {font-family: serif; font-style: normal; font-weight: normal;} +span.overacc2 {position: relative; left: .8em; top: -1.2ex;} +span.overacc1 {position: relative; left: .6em; top: -1.2ex;} + END } @@ -7100,8 +7201,8 @@ sub headtag { if (!$args->{'frameset'}) { $result .= &Apache::lonhtmlcommon::htmlareaheaders(); } - if ($args->{'force_register'} && $env{'request.noversionuri'} !~ m{^/res/adm/pages/}) { - $result .= Apache::lonxml::display_title(); + if ($args->{'force_register'}) { + $result .= &Apache::lonmenu::registerurl(1); } if (!$args->{'no_nav_bar'} && !$args->{'only_body'} @@ -7310,12 +7411,16 @@ $args - additional optional args support skip_phases -> hash ref of head -> skip the generation body -> skip all generation + no_inline_link -> if true and in remote mode, don't show the + 'Switch To Inline Menu' link no_auto_mt_title -> prevent &mt()ing the title arg inherit_jsmath -> when creating popup window in a page, should it have jsmath forced on by the current page bread_crumbs -> Array containing breadcrumbs bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs + group -> includes the current group, if page is for a + specific group =back @@ -7328,7 +7433,7 @@ sub start_page { #&Apache::lonnet::logthis("start_page ".join(':',caller(0))); $env{'internal.start_page'}++; - my $result; + my ($result,@advtools); if (! exists($args->{'skip_phases'}{'head'}) ) { $result .= &xml_begin() . &headtag($title, $head_extra, $args); @@ -7345,7 +7450,8 @@ sub start_page { $args->{'function'}, $args->{'add_entries'}, $args->{'only_body'}, $args->{'domain'}, $args->{'force_register'}, $args->{'no_nav_bar'}, - $args->{'bgcolor'}, $args); + $args->{'bgcolor'}, $args->{'no_inline_link'}, + $args, \@advtools); } } @@ -7769,7 +7875,7 @@ sub simple_error_page { my ($r,$title,$msg) = @_; my $page = &Apache::loncommon::start_page($title). - &mt($msg). + '

'.&mt($msg).'

'. &Apache::loncommon::end_page(); if (ref($r)) { $r->print($page); @@ -11219,11 +11325,11 @@ sub process_extracted_files { if ($env{'form.folderpath'}) { my @items = split('&',$env{'form.folderpath'}); $folders{'0'} = $items[-2]; - $containers{'0'}='sequence'; - } elsif ($env{'form.pagepath'}) { - my @items = split('&',$env{'form.pagepath'}); - $folders{'0'} = $items[-2]; - $containers{'0'}='page'; + if ($env{'form.folderpath'} =~ /\:1$/) { + $containers{'0'}='page'; + } else { + $containers{'0'}='sequence'; + } } my @archdirs = &get_env_multiple('form.archive_directory'); if ($numitems) { @@ -13818,6 +13924,20 @@ sub init_user_environment { \%userenv,\%domdef,\%is_adv); } + $userenv{'canrequest.author'} = + &Apache::lonnet::usertools_access($username,$domain,'requestauthor', + 'reload','requestauthor', + \%userenv,\%domdef,\%is_adv); + my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'], + $domain,$username); + my $reqstatus = $reqauthor{'author_status'}; + if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { + if (ref($reqauthor{'author'}) eq 'HASH') { + $userenv{'requestauthorqueued'} = $reqstatus.':'. + $reqauthor{'author'}{'timestamp'}; + } + } + $env{'user.environment'} = "$lonids/$cookie.id"; if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id", @@ -13992,6 +14112,164 @@ sub parse_supplemental_title { return $title; } +sub captcha_display { + my ($context,$lonhost) = @_; + my ($output,$error); + my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost); + if ($captcha eq 'original') { + $output = &create_captcha(); + unless ($output) { + $error = 'captcha'; + } + } elsif ($captcha eq 'recaptcha') { + $output = &create_recaptcha($pubkey); + unless ($output) { + $error = 'recaptcha'; + } + } + return ($output,$error); +} + +sub captcha_response { + my ($context,$lonhost) = @_; + my ($captcha_chk,$captcha_error); + my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost); + if ($captcha eq 'original') { + ($captcha_chk,$captcha_error) = &check_captcha(); + } elsif ($captcha eq 'recaptcha') { + $captcha_chk = &check_recaptcha($privkey); + } else { + $captcha_chk = 1; + } + return ($captcha_chk,$captcha_error); +} + +sub get_captcha_config { + my ($context,$lonhost) = @_; + my ($captcha,$pubkey,$privkey,$hashtocheck); + my $hostname = &Apache::lonnet::hostname($lonhost); + my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname); + my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID); + if ($context eq 'usercreation') { + my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom); + if (ref($domconfig{$context}) eq 'HASH') { + $hashtocheck = $domconfig{$context}{'cancreate'}; + if (ref($hashtocheck) eq 'HASH') { + if ($hashtocheck->{'captcha'} eq 'recaptcha') { + if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') { + $pubkey = $hashtocheck->{'recaptchakeys'}{'public'}; + $privkey = $hashtocheck->{'recaptchakeys'}{'private'}; + } + if ($privkey && $pubkey) { + $captcha = 'recaptcha'; + } else { + $captcha = 'original'; + } + } elsif ($hashtocheck->{'captcha'} ne 'notused') { + $captcha = 'original'; + } + } + } else { + $captcha = 'captcha'; + } + } elsif ($context eq 'login') { + my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom); + if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') { + $pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'}; + $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'}; + if ($privkey && $pubkey) { + $captcha = 'recaptcha'; + } else { + $captcha = 'original'; + } + } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') { + $captcha = 'original'; + } + } + return ($captcha,$pubkey,$privkey); +} + +sub create_captcha { + my %captcha_params = &captcha_settings(); + my ($output,$maxtries,$tries) = ('',10,0); + while ($tries < $maxtries) { + $tries ++; + my $captcha = Authen::Captcha->new ( + output_folder => $captcha_params{'output_dir'}, + data_folder => $captcha_params{'db_dir'}, + ); + my $md5sum = $captcha->generate_code($captcha_params{'numchars'}); + + if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') { + $output = ''."\n". + &mt('Type in the letters/numbers shown below').' '. + '
'. + ''; + last; + } + } + return $output; +} + +sub captcha_settings { + my %captcha_params = ( + output_dir => $Apache::lonnet::perlvar{'lonCaptchaDir'}, + www_output_dir => "/captchaspool", + db_dir => $Apache::lonnet::perlvar{'lonCaptchaDb'}, + numchars => '5', + ); + return %captcha_params; +} + +sub check_captcha { + my ($captcha_chk,$captcha_error); + my $code = $env{'form.code'}; + my $md5sum = $env{'form.crypt'}; + my %captcha_params = &captcha_settings(); + my $captcha = Authen::Captcha->new( + output_folder => $captcha_params{'output_dir'}, + data_folder => $captcha_params{'db_dir'}, + ); + my $captcha_chk = $captcha->check_code($code,$md5sum); + my %captcha_hash = ( + 0 => 'Code not checked (file error)', + -1 => 'Failed: code expired', + -2 => 'Failed: invalid code (not in database)', + -3 => 'Failed: invalid code (code does not match crypt)', + ); + if ($captcha_chk != 1) { + $captcha_error = $captcha_hash{$captcha_chk} + } + return ($captcha_chk,$captcha_error); +} + +sub create_recaptcha { + my ($pubkey) = @_; + my $captcha = Captcha::reCAPTCHA->new; + return $captcha->get_options_setter({theme => 'white'})."\n". + $captcha->get_html($pubkey). + &mt('If either word is hard to read, [_1] will replace them.', + 'reCAPTCHA refresh'). + '

'; +} + +sub check_recaptcha { + my ($privkey) = @_; + my $captcha_chk; + my $captcha = Captcha::reCAPTCHA->new; + my $captcha_result = + $captcha->check_answer( + $privkey, + $ENV{'REMOTE_ADDR'}, + $env{'form.recaptcha_challenge_field'}, + $env{'form.recaptcha_response_field'}, + ); + if ($captcha_result->{is_valid}) { + $captcha_chk = 1; + } + return $captcha_chk; +} + =pod =back