--- loncom/interface/loncommon.pm 2013/12/30 01:31:55 1.1075.2.60 +++ loncom/interface/loncommon.pm 2014/11/08 18:26:06 1.1199 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1075.2.60 2013/12/30 01:31:55 raeburn Exp $ +# $Id: loncommon.pm,v 1.1199 2014/11/08 18:26:06 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -69,11 +69,15 @@ use Apache::lontexconvert(); use Apache::lonclonecourse(); use Apache::lonuserutils(); use Apache::lonuserstate(); +use Apache::courseclassifier(); use LONCAPA qw(:DEFAULT :match); use DateTime::TimeZone; use DateTime::Locale::Catalog; +use Text::Aspell; use Authen::Captcha; use Captcha::reCAPTCHA; +use Crypt::DES; +use DynaLoader; # for Crypt::DES version # ---------------------------------------------- Designs use vars qw(%defaultdesign); @@ -158,6 +162,7 @@ sub ssi_with_retries { # ----------------------------------------------- Filetypes/Languages/Copyright my %language; my %supported_language; +my %supported_codes; my %latex_language; # For choosing hyphenation in my %latex_language_bykey; # for choosing hyphenation from metadata my %cprtag; @@ -192,14 +197,15 @@ BEGIN { while (my $line = <$fh>) { next if ($line=~/^\#/); chomp($line); - my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line)); + my ($key,$code,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line)); $language{$key}=$val.' - '.$enc; if ($sup) { $supported_language{$key}=$sup; + $supported_codes{$key} = $code; } if ($latex) { $latex_language_bykey{$key} = $latex; - $latex_language{$two} = $latex; + $latex_language{$code} = $latex; } } close($fh); @@ -663,7 +669,7 @@ if (!Array.prototype.indexOf) { var n = 0; if (arguments.length > 0) { n = Number(arguments[1]); - if (n !== n) { // shortcut for verifying if it's NaN + if (n !== n) { // shortcut for verifying if it is NaN n = 0; } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); @@ -899,12 +905,12 @@ sub check_uncheck_jscript { function checkAll(field) { if (field.length > 0) { for (i = 0; i < field.length; i++) { - if (!field[i].disabled) { + if (!field[i].disabled) { field[i].checked = true; } } } else { - if (!field.disabled) { + if (!field.disabled) { field.checked = true; } } @@ -1014,6 +1020,33 @@ sub select_language { =pod + +=item * &list_languages() + +Returns an array reference that is suitable for use in language prompters. +Each array element is itself a two element array. The first element +is the language code. The second element a descsriptiuon of the +language itself. This is suitable for use in e.g. +&Apache::edit::select_arg (once dereferenced that is). + +=cut + +sub list_languages { + my @lang_choices; + + foreach my $id (&languageids()) { + my $code = &supportedlanguagecode($id); + if ($code) { + my $selector = $supported_codes{$id}; + my $description = &plainlanguagedescription($id); + push (@lang_choices, [$selector, $description]); + } + } + return \@lang_choices; +} + +=pod + =item * &linked_select_forms(...) linked_select_forms returns a string containing a block @@ -1234,11 +1267,7 @@ sub help_open_topic { $topic=~s/\W/\_/g; if (!$stayOnPage) { - if ($env{'browser.mobile'}) { - $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');"; - } else { - $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))"; - } + $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');"; } elsif ($stayOnPage eq 'popup') { $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))"; } else { @@ -1287,8 +1316,10 @@ sub helpLatexCheatsheet { .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600) .''; unless ($not_author) { - $out .= ' ' - .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600) + $out .= '' + .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600) + .' ' + .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600) .''; } $out .= ''; # End cheatsheet @@ -1352,20 +1383,23 @@ sub help_open_menu { sub top_nav_help { my ($text) = @_; $text = &mt($text); - my $stay_on_page; - unless ($env{'environment.remote'} eq 'on') { - $stay_on_page = 1; - } - my $link = ($stay_on_page) ? "javascript:helpMenu('display')" - : "javascript:helpMenu('open')"; - my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page); + my $stay_on_page = 1; + my ($link,$banner_link); + unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) { + $link = ($stay_on_page) ? "javascript:helpMenu('display')" + : "javascript:helpMenu('open')"; + $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page); + } my $title = &mt('Get help'); - - return <<"END"; + if ($link) { + return <<"END"; $banner_link $text END + } else { + return ' '.$text.' '; + } } sub help_menu_js { @@ -1380,9 +1414,9 @@ sub help_menu_js { &Apache::loncommon::start_page('Help Menu', undef, {'frameset' => 1, 'js_ready' => 1, - 'use_absolute' => $httphost, + 'use_absolute' => $httphost, 'add_entries' => { - 'border' => '0', + 'border' => '0', 'rows' => "110,*",},}); my $end_page = &Apache::loncommon::end_page({'frameset' => 1, @@ -1412,9 +1446,10 @@ function helpMenu(target) { return; } function writeHelp(caller) { - caller.document.writeln('$start_page\\n\\n\\n$end_page') - caller.document.close() - caller.focus() + caller.document.writeln('$start_page\\n\\n'); + caller.document.writeln('\\n$end_page'); + caller.document.close(); + caller.focus(); } // END LON-CAPA Internal --> // ]]> @@ -2183,7 +2218,7 @@ The optional $onchange argument specifie The optional $incdoms is a reference to an array of domains which will be the only available options. -The optional $excdoms is a reference to an array of domains which will be excluded from the available options. +The optional $excdoms is a reference to an array of domains which will be excluded from the available options. =cut @@ -2201,7 +2236,7 @@ sub select_dom_form { } if ($includeempty) { @domains=('',@domains); } if (ref($excdoms) eq 'ARRAY') { - map { $exclude{$_} = 1; } @{$excdoms}; + map { $exclude{$_} = 1; } @{$excdoms}; } my $selectdomain = "'. + &mt('Hide').''; + } + $prevattempts .= ''; if (@hidden) { foreach my $key (sort(keys(%lasthash))) { next if ($key =~ /\.foilorder$/); @@ -3800,7 +3961,7 @@ sub get_previous_attempt { if ($key =~/$regexp$/ && (defined &$gradesub)) { $value = &$gradesub($value); } - $prevattempts.=''.$value.' '; + $prevattempts.=''. $value.' '; } else { $prevattempts.=' '; } @@ -3816,7 +3977,7 @@ sub get_previous_attempt { if ($key =~/$regexp$/ && (defined &$gradesub)) { $value = &$gradesub($value); } - $prevattempts.=''.$value.' '; + $prevattempts.=''.$value.' '; } } $prevattempts.= &end_data_table_row().&end_data_table(); @@ -3837,11 +3998,13 @@ sub get_previous_attempt { sub format_previous_attempt_value { my ($key,$value) = @_; if (($key =~ /timestamp/) || ($key=~/duedate/)) { - $value = &Apache::lonlocal::locallocaltime($value); + $value = &Apache::lonlocal::locallocaltime($value); } elsif (ref($value) eq 'ARRAY') { - $value = '('.join(', ', @{ $value }).')'; + $value = &HTML::Entities::encode('('.join(', ', @{ $value }).')','"<>&'); } elsif ($key =~ /answerstring$/) { my %answers = &Apache::lonnet::str2hash($value); + my @answer = %answers; + %answers = map {&HTML::Entities::encode($_, '"<>&')} @answer; my @anskeys = sort(keys(%answers)); if (@anskeys == 1) { my $answer = $answers{$anskeys[0]}; @@ -3864,7 +4027,7 @@ sub format_previous_attempt_value { } } } else { - $value = &unescape($value); + $value = &HTML::Entities::encode(&unescape($value), '"<>&'); } return $value; } @@ -4225,23 +4388,20 @@ sub findallcourses { ############################################### sub blockcheck { - my ($setters,$activity,$uname,$udom,$url) = @_; + my ($setters,$activity,$uname,$udom,$url,$is_course) = @_; - if (!defined($udom)) { + if (defined($udom) && defined($uname)) { + # If uname and udom are for a course, check for blocks in the course. + if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) { + my ($startblock,$endblock,$triggerblock) = + &get_blocks($setters,$activity,$udom,$uname,$url); + return ($startblock,$endblock,$triggerblock); + } + } else { $udom = $env{'user.domain'}; - } - if (!defined($uname)) { $uname = $env{'user.name'}; } - # If uname and udom are for a course, check for blocks in the course. - - if (&Apache::lonnet::is_course($udom,$uname)) { - my ($startblock,$endblock,$triggerblock) = - &get_blocks($setters,$activity,$udom,$uname,$url); - return ($startblock,$endblock,$triggerblock); - } - my $startblock = 0; my $endblock = 0; my $triggerblock = ''; @@ -4251,7 +4411,8 @@ sub blockcheck { # boards, chat or groups, check for blocking in current course only. if (($activity eq 'boards' || $activity eq 'chat' || - $activity eq 'groups') && ($env{'request.course.id'})) { + $activity eq 'groups' || $activity eq 'printout') && + ($env{'request.course.id'})) { foreach my $key (keys(%live_courses)) { if ($key ne $env{'request.course.id'}) { delete($live_courses{$key}); @@ -4515,12 +4676,12 @@ sub parse_block_record { } sub blocking_status { - my ($activity,$uname,$udom,$url) = @_; + my ($activity,$uname,$udom,$url,$is_course) = @_; my %setters; # check for active blocking my ($startblock,$endblock,$triggerblock) = - &blockcheck(\%setters,$activity,$uname,$udom,$url); + &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course); my $blocked = 0; if ($startblock && $endblock) { $blocked = 1; @@ -5012,9 +5173,6 @@ 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, @@ -5036,7 +5194,7 @@ other decorations will be returned. sub bodytag { my ($title,$function,$addentries,$bodyonly,$domain,$forcereg, - $no_nav_bar,$bgcolor,$no_inline_link,$args,$advtoolsref)=@_; + $no_nav_bar,$bgcolor,$args,$advtoolsref)=@_; my $public; if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')) @@ -5060,7 +5218,10 @@ sub bodytag { @design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; # role and realm - my ($role,$realm) = split(/\./,$env{'request.role'},2); + my ($role,$realm) = split(m{\./},$env{'request.role'},2); + if ($realm) { + $realm = '/'.$realm; + } if ($role eq 'ca') { my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$}); $realm = &plainname($rname,$rdom); @@ -5110,23 +5271,7 @@ sub bodytag { $role = '('.$role.')' if $role; - if ($env{'request.state'} eq 'construct') { $forcereg=1; } - - - - my $funclist; - if (($env{'environment.remote'} eq 'on') && ($env{'request.state'} ne 'construct')) { - $bodytag .= Apache::lonhtmlcommon::scripttag(Apache::lonmenu::utilityfunctions($httphost), 'start')."\n". - Apache::lonmenu::serverform(); - my $forbodytag; - &Apache::lonmenu::prepare_functions($env{'request.noversionuri'}, - $forcereg,$args->{'group'}, - $args->{'bread_crumbs'}, - $advtoolsref,'',\$forbodytag); - unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') { - $funclist = $forbodytag; - } - } else { + if ($env{'request.state'} eq 'construct') { $forcereg=1; } # if ($env{'request.state'} eq 'construct') { # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls @@ -5138,11 +5283,11 @@ sub bodytag { my ($left,$right) = Apache::lonmenu::primary_menu(); if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) { - if ($dc_info) { + if ($dc_info) { $dc_info = qq|$dc_info|; - } - $bodytag .= qq|
$left $role
- $realm $dc_info
|; + } + $bodytag .= qq|
$left $role
+ $realm $dc_info
|; return $bodytag; } @@ -5157,6 +5302,10 @@ sub bodytag { } $bodytag .= qq|
$realm $dc_info
|; + #if directed to not display the secondary menu, don't. + if ($args->{'no_secondary_menu'}) { + return $bodytag; + } #don't show menus for public users if (!$public){ $bodytag .= Apache::lonmenu::secondary_menu($httphost); @@ -5165,18 +5314,15 @@ sub bodytag { if ($env{'request.state'} eq 'construct') { $bodytag .= &Apache::lonmenu::innerregister($forcereg, $args->{'bread_crumbs'}); - } elsif ($forcereg) { + } elsif ($forcereg) { $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef, $args->{'group'}); } else { - my $forbodytag; - &Apache::lonmenu::prepare_functions($env{'request.noversionuri'}, - $forcereg,$args->{'group'}, - $args->{'bread_crumbs'}, - $advtoolsref,'',\$forbodytag); - unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') { - $bodytag .= $forbodytag; - } + $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 @@ -5186,54 +5332,6 @@ sub bodytag { } return $bodytag; - } - -# -# Top frame rendering, Remote is up -# - - my $imgsrc = $img; - if ($img =~ /^\/adm/) { - $imgsrc = &lonhttpdurl($img); - } - my $upperleft=''.$function.''; - - my $help=($no_inline_link?'' - :&Apache::loncommon::top_nav_help('Help')); - - # 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)|; - } - - my $name = &plainname($env{'user.name'},$env{'user.domain'}); - unless ($public) { - $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'}, - undef,'LC_menubuttons_link'); - } - - unless ($env{'form.inhibitmenu'}) { - $bodytag .= qq|
$name $role
-
    -
  1. $help
  2. -
  3. $menu
  4. -
$realm $dc_info
|; - } - if ($env{'request.state'} eq 'construct') { - if (!$public){ - if ($env{'request.state'} eq 'construct') { - $funclist = &Apache::lonhtmlcommon::scripttag( - &Apache::lonmenu::utilityfunctions($httphost), 'start'). - &Apache::lonhtmlcommon::scripttag('','end'). - &Apache::lonmenu::innerregister($forcereg, - $args->{'bread_crumbs'}); - } - } - } - return $bodytag."\n".$funclist; } sub dc_courseid_toggle { @@ -5265,15 +5363,8 @@ sub make_attr_string { delete($attr_ref->{$key}); } } - 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; - } + $attr_ref->{'onload'} = $on_load; + $attr_ref->{'onunload'}= $on_unload; } my $attr_string; @@ -6722,7 +6813,6 @@ ul#LC_secondary_menu li { font-weight: bold; line-height: 1.8em; border-right: 1px solid black; - vertical-align: middle; float: left; } @@ -7278,13 +7368,16 @@ sub headtag { ''. &font_settings($args); - my $inhibitprint = &print_suppression(); + my $inhibitprint; + if ($args->{'print_suppress'}) { + $inhibitprint = &print_suppression(); + } if (!$args->{'frameset'}) { $result .= &Apache::lonhtmlcommon::htmlareaheaders(); } - if ($args->{'force_register'}) { - $result .= &Apache::lonmenu::registerurl(1); + if ($args->{'force_register'} && $env{'request.noversionuri'} !~ m{^/res/adm/pages/}) { + $result .= Apache::lonxml::display_title(); } if (!$args->{'no_nav_bar'} && !$args->{'only_body'} @@ -7324,7 +7417,11 @@ ADDMETA } if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } $result .= ' LON-CAPA '.$title.'' - .'' + .'{'frameset'}) { + $result .= ' /'; + } + $result .= '>' .$inhibitprint .$head_extra; if ($env{'browser.mobile'}) { @@ -7350,8 +7447,12 @@ sub font_settings { my $headerstring=''; if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) || ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) { - $headerstring.= - ''."\n"; + $headerstring.= + '{'frameset'}) { + $headerstring.= ' /'; + } + $headerstring .= '>'."\n"; } return $headerstring; } @@ -7396,7 +7497,7 @@ sub print_suppression { } my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - my $blocked = &blocking_status('printout',$cnum,$cdom); + my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1); if ($blocked) { my $checkrole = "cm./$cdom/$cnum"; if ($env{'request.course.sec'} ne '') { @@ -7443,6 +7544,7 @@ Inputs: none =cut sub xml_begin { + my ($is_frameset) = @_; my $output=''; if ($env{'browser.mathml'}) { @@ -7454,9 +7556,12 @@ sub xml_begin { .'' .''; + } elsif ($is_frameset) { + $output=''."\n". + ''."\n"; } else { - $output=''."\n" - .''."\n"; + $output=''."\n". + ''."\n"; } return $output; } @@ -7500,16 +7605,14 @@ $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 + group -> includes the current group, if page is for a + specific group =back @@ -7525,7 +7628,7 @@ sub start_page { my ($result,@advtools); if (! exists($args->{'skip_phases'}{'head'}) ) { - $result .= &xml_begin() . &headtag($title, $head_extra, $args); + $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args); } if (! exists($args->{'skip_phases'}{'body'}) ) { @@ -7539,8 +7642,8 @@ sub start_page { $args->{'function'}, $args->{'add_entries'}, $args->{'only_body'}, $args->{'domain'}, $args->{'force_register'}, $args->{'no_nav_bar'}, - $args->{'bgcolor'}, $args->{'no_inline_link'}, - $args, \@advtools); + $args->{'bgcolor'}, $args, + \@advtools); } } @@ -7580,11 +7683,6 @@ sub start_page { }else{ $result .= &Apache::lonhtmlcommon::breadcrumbs(); } - } elsif (($env{'environment.remote'} eq 'on') && - ($env{'form.inhibitmenu'} ne 'yes') && - ($env{'request.noversionuri'} =~ m{^/res/}) && - ($env{'request.noversionuri'} !~ m{^/res/adm/pages/})) { - $result .= '

'; } return $result; } @@ -7631,9 +7729,11 @@ function set_wishlistlink(title, path) { title = document.title; title = title.replace(/^LON-CAPA /,''); } + title = encodeURIComponent(title); if (!path) { path = location.pathname; } + path = encodeURIComponent(path); Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path, 'wishlistNewLink','width=560,height=350,scrollbars=0'); } @@ -7679,7 +7779,7 @@ var modalWindow = { modalWindow.windowId = "myModal"; modalWindow.width = width; modalWindow.height = height; - modalWindow.content = ""; modalWindow.open(); }; // END LON-CAPA Internal --> @@ -7727,7 +7827,7 @@ sub modal_adhoc_inner { my ($funcname,$width,$height,$content)=@_; my $innerwidth=$width-20; $content=&js_ready( - &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}). + &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}). &start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1). $content. &end_scrollbox(). @@ -8372,7 +8472,7 @@ sub get_sections { } } - if ($check_students) { + if ($check_students) { my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum); my $sec_index = &Apache::loncoursedata::CL_SECTION(); my $status_index = &Apache::loncoursedata::CL_STATUS(); @@ -8768,8 +8868,8 @@ sub get_user_quota { if ($quota eq '' || wantarray) { if ($quotaname eq 'course') { my %domdefs = &Apache::lonnet::get_domain_defaults($udom); - if (($crstype eq 'official') || ($crstype eq 'unofficial') || - ($crstype eq 'community') || ($crstype eq 'textbook')) { + if (($crstype eq 'official') || ($crstype eq 'unofficial') || + ($crstype eq 'community') || ($crstype eq 'textbook')) { $defquota = $domdefs{$crstype.'quota'}; } if ($defquota eq '') { @@ -8910,7 +9010,7 @@ 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. -Inputs: 6 +Inputs: 7 1. username or coursenum 2. domain 3. context ('author' or 'course') @@ -8940,10 +9040,10 @@ sub excess_filesize_warning { } $disk_quota = int($disk_quota * 1000); if (($current_disk_usage + $filesize) > $disk_quota) { - return '

'. + return '

'. &mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.", - ''.$filename.'',$filesize).''. - '
'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', + ''.$filename.'',$filesize).'

'. + '

'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', $disk_quota,$current_disk_usage). '

'; } @@ -8953,6 +9053,8 @@ sub excess_filesize_warning { ############################################### + + sub get_secgrprole_info { my ($cdom,$cnum,$needroles,$type) = @_; my %sections_count = &get_sections($cdom,$cnum); @@ -9394,7 +9496,14 @@ sub personal_data_fieldtitles { sub sorted_inst_types { my ($dom) = @_; - my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom); + my ($usertypes,$order); + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); + if (ref($domdefaults{'inststatus'}) eq 'HASH') { + $usertypes = $domdefaults{'inststatus'}{'inststatustypes'}; + $order = $domdefaults{'inststatus'}{'inststatusorder'}; + } else { + ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom); + } my $othertitle = &mt('All users'); if ($env{'request.course.id'}) { $othertitle = &mt('Any users'); @@ -9803,7 +9912,7 @@ sub ask_for_embedded_content { $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; } - if (($actionurl eq '/adm/portfolio') || + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { my $current_path='/'; if ($env{'form.currentpath'}) { @@ -9835,18 +9944,18 @@ sub ask_for_embedded_content { $toplevel = $url; if ($args->{'context'} eq 'paste') { ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/}); - ($path) = + ($path) = ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/}); $fileloc = &Apache::lonnet::filelocation('',$toplevel); $fileloc =~ s{^/}{}; } } - } elsif ($actionurl eq '/adm/dependencies') { + } elsif ($actionurl eq '/adm/dependencies') { if ($env{'request.course.id'} ne '') { if (ref($args) eq 'HASH') { $url = $args->{'docs_url'}; $title = $args->{'docs_title'}; - $toplevel = $url; + $toplevel = $url; unless ($toplevel =~ m{^/}) { $toplevel = "/$url"; } @@ -9857,7 +9966,15 @@ sub ask_for_embedded_content { ($path) = ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/}); } - $fileloc = &Apache::lonnet::filelocation('',$toplevel); + if ($toplevel=~/^\/*(uploaded|editupload)/) { + $fileloc = $toplevel; + $fileloc=~ s/^\s*(\S+)\s*$/$1/; + my ($udom,$uname,$fname) = + ($fileloc=~ m{^/+(?:uploaded|editupload)/+($match_domain)/+($match_name)/+(.*)$}); + $fileloc = propath($udom,$uname).'/userfiles/'.$fname; + } else { + $fileloc = &Apache::lonnet::filelocation('',$toplevel); + } $fileloc =~ s{^/}{}; ($filename) = ($fileloc =~ m{.+/([^/]+)$}); $heading = &mt('Status of dependencies in [_1]',"$title ($filename)"); @@ -9917,8 +10034,8 @@ sub ask_for_embedded_content { my $dirptr = 16384; foreach my $path (keys(%subdependencies)) { $currsubfile{$path} = {}; - if (($actionurl eq '/adm/portfolio') || - ($actionurl eq '/adm/coursegrp_portfolio')) { + if (($actionurl eq '/adm/portfolio') || + ($actionurl eq '/adm/coursegrp_portfolio')) { my ($sublistref,$listerror) = &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath); if (ref($sublistref) eq 'ARRAY') { @@ -10060,7 +10177,7 @@ sub ask_for_embedded_content { $counter = scalar(keys(%existing)); $numpathchg = scalar(keys(%pathchanges)); return ($output,$counter,$numpathchg,\%existing); - } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && + } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) { $counter = scalar(keys(%existing)); $numpathchg = scalar(keys(%pathchanges)); @@ -10289,7 +10406,7 @@ sub ask_for_embedded_content { 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 +to a course or portfolio, where "Upload embedded images/multimedia files if HTML file" checkbox was checked. @@ -10308,7 +10425,7 @@ sub clean_path { @contents = ($embed_file); } my $lastidx = scalar(@contents)-1; - for (my $i=0; $i<=$lastidx; $i++) { + for (my $i=0; $i<=$lastidx; $i++) { $contents[$i]=~s{\\}{/}g; $contents[$i]=~s/\s+/\_/g; $contents[$i]=~s{[^/\w\.\-]}{}g; @@ -10647,7 +10764,7 @@ sub modify_html_refs { } my (%allfiles,%codebase,$output,$content); my @changes = &get_env_multiple('form.namechange'); - unless ((@changes > 0) || ($context eq 'syllabus')) { + unless ((@changes > 0) || ($context eq 'syllabus')) { if (wantarray) { return ('',0,0); } else { @@ -10782,7 +10899,7 @@ sub modify_html_refs { } } if ($rewrites) { - my $saveresult; + my $saveresult; my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult); if ($url eq $container) { my ($fname) = ($container =~ m{/([^/]+)$}); @@ -10888,11 +11005,11 @@ sub check_for_upload { if ($currsize < $filesize) { my $extra = $filesize - $currsize; if (($current_disk_usage + $extra) > $disk_quota) { - my $msg = ''. + my $msg = '

'. &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.', - ''.$fname.'',$filesize,$currsize).''. - '
'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', - $disk_quota,$current_disk_usage); + ''.$fname.'',$filesize,$currsize).'

'. + '

'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', + $disk_quota,$current_disk_usage).'

'; return ('will_exceed_quota',$msg); } } @@ -10901,21 +11018,21 @@ sub check_for_upload { } } if (($current_disk_usage + $filesize) > $disk_quota){ - my $msg = ''. - &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.',''.$fname.'',$filesize).''. - '
'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage); + my $msg = '

'. + &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.',''.$fname.'',$filesize).'

'. + '

'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage).'

'; return ('will_exceed_quota',$msg); } elsif ($found_file) { if ($locked_file) { - my $msg = ''; + my $msg = '

'; $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].',''.$fname.'',''.$port_path.$env{'form.currentpath'}.''); - $msg .= '
'; + $msg .= '

'; $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.',''.$fname.''); return ('file_locked',$msg); } else { - my $msg = ''; + my $msg = '

'; $msg .= &mt(' A file by that name: [_1] was found in [_2].',''.$fname.'',$port_path.$env{'form.currentpath'}); - $msg .= ''; + $msg .= '

'; return ('existingfile',$msg); } } @@ -11013,7 +11130,7 @@ sub decompress_form { "$topdir/media/player.swf", "$topdir/media/swfobject.js", "$topdir/media/expressInstall.swf"); - my @camtasia8 = ("$topdir/","$topdir/$topdir.html", + my @camtasia8_1 = ("$topdir/","$topdir/$topdir.html", "$topdir/$topdir.mp4", "$topdir/$topdir\_config.xml", "$topdir/$topdir\_controller.swf", @@ -11035,13 +11152,36 @@ sub decompress_form { "$topdir/skins/express_show/", "$topdir/skins/express_show/player-min.css", "$topdir/skins/express_show/spritesheet.png"); + my @camtasia8_4 = ("$topdir/","$topdir/$topdir.html", + "$topdir/$topdir.mp4", + "$topdir/$topdir\_config.xml", + "$topdir/$topdir\_controller.swf", + "$topdir/$topdir\_embed.css", + "$topdir/$topdir\_First_Frame.png", + "$topdir/$topdir\_player.html", + "$topdir/$topdir\_Thumbnails.png", + "$topdir/playerProductInstall.swf", + "$topdir/scripts/", + "$topdir/scripts/config_xml.js", + "$topdir/scripts/techsmith-smart-player.min.js", + "$topdir/skins/", + "$topdir/skins/configuration_express.xml", + "$topdir/skins/express_show/", + "$topdir/skins/express_show/spritesheet.min.css", + "$topdir/skins/express_show/spritesheet.png", + "$topdir/skins/express_show/techsmith-smart-player.min.css"); my @diffs = &compare_arrays(\@paths,\@camtasia6); if (@diffs == 0) { $is_camtasia = 6; } else { - @diffs = &compare_arrays(\@paths,\@camtasia8); + @diffs = &compare_arrays(\@paths,\@camtasia8_1); if (@diffs == 0) { $is_camtasia = 8; + } else { + @diffs = &compare_arrays(\@paths,\@camtasia8_4); + if (@diffs == 0) { + $is_camtasia = 8; + } } } } @@ -11055,6 +11195,7 @@ function camtasiaToggle() { for (var i=0; i'.&mt('Filename should end with one of: [_1].', '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz'); @@ -11369,7 +11510,7 @@ sub process_decompression { $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'}; $displayed{'folder'} = $i; } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) || - (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) { + (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) { $env{'form.archive_'.$i} = 'display'; $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'}; $displayed{'web'} = $i; @@ -11821,7 +11962,7 @@ sub process_extracted_files { $folders{'0'} = $items[-2]; if ($env{'form.folderpath'} =~ /\:1$/) { $containers{'0'}='page'; - } else { + } else { $containers{'0'}='sequence'; } } @@ -11941,7 +12082,7 @@ sub process_extracted_files { } } } else { - $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'
'; + $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'
'; } } for (my $i=1; $i<=$numitems; $i++) { @@ -11963,7 +12104,7 @@ sub process_extracted_files { } if ($itemidx eq '') { $itemidx = 0; - } + } if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) { if ($mapinner{$referrer{$i}}) { $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}"; @@ -12010,12 +12151,12 @@ sub process_extracted_files { $showpath = "$relpath/$title"; } else { $showpath = "/$title"; - } + } $result .= '
  • '.&mt('[_1] included as a dependency',$showpath).'
  • '."\n"; - } + } unless ($ishome) { my $fetch = "$fullpath/$title"; - $fetch =~ s/^\Q$prefix$dir\E//; + $fetch =~ s/^\Q$prefix$dir\E//; $prompttofetch{$fetch} = 1; } } @@ -12025,7 +12166,7 @@ sub process_extracted_files { $path,$env{'form.archive_content_'.$referrer{$i}}).'
    '; } } else { - $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'
    '; + $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'
    '; } } if (keys(%todelete)) { @@ -13215,14 +13356,14 @@ generated by lonerrorhandler.pm, CHECKRP lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively. Inputs: -defmail (scalar - email address of default recipient), +defmail (scalar - email address of default recipient), 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 +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. @@ -13630,6 +13771,12 @@ sub assign_category_rows { return $text; } +=pod + +=back + +=cut + ############################################################ ############################################################ @@ -13760,7 +13907,7 @@ sub commit_studentrole { } } } else { - if ($secchange) { + if ($secchange) { $$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed; } else { $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed; @@ -13982,6 +14129,9 @@ sub construct_course { 'categories', 'internal.uniquecode'], $$crsudom,$$crsunum); + if ($args->{'textbook'}) { + $cenv{'internal.textbook'} = $args->{'textbook'}; + } } # @@ -14177,7 +14327,7 @@ sub construct_course { if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') { $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code; my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime'); - } + } if (ref($coderef)) { $$coderef = $code; } @@ -14262,7 +14412,7 @@ sub make_unique_code { my $tries = 0; my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom); my ($code,$error); - + while (($gotlock ne 'ok') && ($tries<3)) { $tries ++; sleep 1; @@ -14470,8 +14620,8 @@ sub init_user_environment { } # ------------------------------------ Check browser type and MathML capability - my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, - $clientunicode,$clientos,$clientmobile,$clientinfo) = &decode_user_agent($r); + my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,$clientunicode, + $clientos,$clientmobile,$clientinfo,$clientosversion) = &decode_user_agent($r); # ------------------------------------------------------------- Get environment @@ -14504,6 +14654,7 @@ sub init_user_environment { "browser.os" => $clientos, "browser.mobile" => $clientmobile, "browser.info" => $clientinfo, + "browser.osversion" => $clientosversion, "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'}, "request.course.fn" => '', "request.course.uri" => '', @@ -14555,7 +14706,7 @@ sub init_user_environment { my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'], $domain,$username); my $reqstatus = $reqauthor{'author_status'}; - if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { + if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { if (ref($reqauthor{'author'}) eq 'HASH') { $userenv{'requestauthorqueued'} = $reqstatus.':'. $reqauthor{'author'}{'timestamp'}; @@ -14646,36 +14797,540 @@ sub clean_symb { return ($symb,$enc); } -sub build_release_hashes { - my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_; - return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') && - (ref($checkcrstypes) eq 'HASH') && (ref($anonsurvey) eq 'HASH') && - (ref($randomizetry) eq 'HASH')); - foreach my $key (keys(%Apache::lonnet::needsrelease)) { - my ($item,$name,$value) = split(/:/,$key); - if ($item eq 'parameter') { - if (ref($checkparms->{$name}) eq 'ARRAY') { - unless(grep(/^\Q$name\E$/,@{$checkparms->{$name}})) { - push(@{$checkparms->{$name}},$value); - } +############################################################ +############################################################ + +=pod + +=head1 Routines for building display used to search for courses + + +=over 4 + +=item * &build_filters() + +Create markup for a table used to set filters to use when selecting +courses in a domain. Used by lonpickcourse.pm, lonmodifycourse.pm +and quotacheck.pl + + +Inputs: + +filterlist - anonymous array of fields to include as potential filters + +crstype - course type + +roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used + to pop-open a course selector (will contain "extra element"). + +multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1 + +filter - anonymous hash of criteria and their values + +action - form action + +numfiltersref - ref to scalar (count of number of elements in institutional codes -- e.g., 4 for year, semester, department, and number) + +caller - caller context (e.g., set to 'modifycourse' when routine is called from lonmodifycourse.pm) + +cloneruname - username of owner of new course who wants to clone + +clonerudom - domain of owner of new course who wants to clone + +typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community) + +codetitlesref - reference to array of titles of components in institutional codes (official courses) + +codedom - domain + +formname - value of form element named "form". + +fixeddom - domain, if fixed. + +prevphase - value to assign to form element named "phase" when going back to the previous screen + +cnameelement - name of form element in form on opener page which will receive title of selected course + +cnumelement - name of form element in form on opener page which will receive courseID of selected course + +cdomelement - name of form element in form on opener page which will receive domain of selected course + +setroles - includes access constraint identifier when setting a roles-based condition for acces to a portfolio file + +clonetext - hidden form elements containing list of courses cloneable by intended course owner when DC creates a course + +clonewarning - warning message about missing information for intended course owner when DC creates a course + + +Returns: $output - HTML for display of search criteria, and hidden form elements. + + +Side Effects: None + +=cut + +# ---------------------------------------------- search for courses based on last activity etc. + +sub build_filters { + my ($filterlist,$crstype,$roleelement,$multelement,$filter,$action, + $numtitlesref,$caller,$cloneruname,$clonerudom,$typeelement, + $codetitlesref,$codedom,$formname,$fixeddom,$prevphase, + $cnameelement,$cnumelement,$cdomelement,$setroles, + $clonetext,$clonewarning) = @_; + my ($list,$jscript); + my $onchange = 'javascript:updateFilters(this)'; + my ($domainselectform,$sincefilterform,$createdfilterform, + $ownerdomselectform,$persondomselectform,$instcodeform, + $typeselectform,$instcodetitle); + if ($formname eq '') { + $formname = $caller; + } + foreach my $item (@{$filterlist}) { + unless (($item eq 'descriptfilter') || ($item eq 'instcodefilter') || + ($item eq 'sincefilter') || ($item eq 'createdfilter')) { + if ($item eq 'domainfilter') { + $filter->{$item} = &LONCAPA::clean_domain($filter->{$item}); + } elsif ($item eq 'coursefilter') { + $filter->{$item} = &LONCAPA::clean_courseid($filter->{$item}); + } elsif ($item eq 'ownerfilter') { + $filter->{$item} = &LONCAPA::clean_username($filter->{$item}); + } elsif ($item eq 'ownerdomfilter') { + $filter->{'ownerdomfilter'} = + &LONCAPA::clean_domain($filter->{$item}); + $ownerdomselectform = &select_dom_form($filter->{'ownerdomfilter'}, + 'ownerdomfilter',1); + } elsif ($item eq 'personfilter') { + $filter->{$item} = &LONCAPA::clean_username($filter->{$item}); + } elsif ($item eq 'persondomfilter') { + $persondomselectform = &select_dom_form($filter->{'persondomfilter'}, + 'persondomfilter',1); } else { - push(@{$checkparms->{$name}},$value); + $filter->{$item} =~ s/\W//g; } - } elsif ($item eq 'resourcetag') { - if ($name eq 'responsetype') { - $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key} + if (!$filter->{$item}) { + $filter->{$item} = ''; + } + } + if ($item eq 'domainfilter') { + my $allow_blank = 1; + if ($formname eq 'portform') { + $allow_blank=0; + } elsif ($formname eq 'studentform') { + $allow_blank=0; } - } elsif ($item eq 'course') { - if ($name eq 'crstype') { - $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key}; + if ($fixeddom) { + $domainselectform = ''. + &Apache::lonnet::domain($codedom,'description'); + } else { + $domainselectform = &select_dom_form($filter->{$item}, + 'domainfilter', + $allow_blank,'',$onchange); } + } else { + $list->{$item} = &HTML::Entities::encode($filter->{$item},'<>&"'); + } + } + + # last course activity filter and selection + $sincefilterform = &timebased_select_form('sincefilter',$filter); + + # course created filter and selection + if (exists($filter->{'createdfilter'})) { + $createdfilterform = &timebased_select_form('createdfilter',$filter); + } + + my %lt = &Apache::lonlocal::texthash( + 'cac' => "$crstype Activity", + 'ccr' => "$crstype Created", + 'cde' => "$crstype Title", + 'cdo' => "$crstype Domain", + 'ins' => 'Institutional Code', + 'inc' => 'Institutional Categorization', + 'cow' => "$crstype Owner/Co-owner", + 'cop' => "$crstype Personnel Includes", + 'cog' => 'Type', + ); + + if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) { + my $typeval = 'Course'; + if ($crstype eq 'Community') { + $typeval = 'Community'; + } + $typeselectform = ''; + } else { + $typeselectform = '"; + } + + my ($cloneableonlyform,$cloneabletitle); + if (exists($filter->{'cloneableonly'})) { + my $cloneableon = ''; + my $cloneableoff = ' checked="checked"'; + if ($filter->{'cloneableonly'}) { + $cloneableon = $cloneableoff; + $cloneableoff = ''; + } + $cloneableonlyform = ''.(' 'x3).''; + if ($formname eq 'ccrs') { + $cloneabletitle = &mt('Cloneable for [_1]',$cloneruname.':'.$clonerudom); + } else { + $cloneabletitle = &mt('Cloneable by you'); + } + } + my $officialjs; + if ($crstype eq 'Course') { + if (exists($filter->{'instcodefilter'})) { +# if (($fixeddom) || ($formname eq 'requestcrs') || +# ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) { + if ($codedom) { + $officialjs = 1; + ($instcodeform,$jscript,$$numtitlesref) = + &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker', + $officialjs,$codetitlesref); + if ($jscript) { + $jscript = ''."\n"; + } + } + if ($instcodeform eq '') { + $instcodeform = + ''; + $instcodetitle = $lt{'ins'}; + } else { + $instcodetitle = $lt{'inc'}; + } + if ($fixeddom) { + $instcodetitle .= '
    ('.$codedom.')'; + } + } + } + my $output = qq| +
    + +|; + if ($formname eq 'modifycourse') { + $output .= ''."\n". + ''."\n"; + } elsif ($formname eq 'quotacheck') { + $output .= qq| + + +|; + } else { + my $name_input; + if ($cnameelement ne '') { + $name_input = ''; + } + $output .= qq| + + +$name_input +$roleelement +$multelement +$typeelement +|; + if ($formname eq 'portform') { + $output .= ''."\n"; } } - ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'}); - ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'}); + if ($fixeddom) { + $output .= ''."\n"; + } + $output .= "
    \n".&Apache::lonhtmlcommon::start_pick_box(); + if ($sincefilterform) { + $output .= &Apache::lonhtmlcommon::row_title($lt{'cac'}) + .$sincefilterform + .&Apache::lonhtmlcommon::row_closure(); + } + if ($createdfilterform) { + $output .= &Apache::lonhtmlcommon::row_title($lt{'ccr'}) + .$createdfilterform + .&Apache::lonhtmlcommon::row_closure(); + } + if ($domainselectform) { + $output .= &Apache::lonhtmlcommon::row_title($lt{'cdo'}) + .$domainselectform + .&Apache::lonhtmlcommon::row_closure(); + } + if ($typeselectform) { + if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) { + $output .= $typeselectform; + } else { + $output .= &Apache::lonhtmlcommon::row_title($lt{'cog'}) + .$typeselectform + .&Apache::lonhtmlcommon::row_closure(); + } + } + if ($instcodeform) { + $output .= &Apache::lonhtmlcommon::row_title($instcodetitle) + .$instcodeform + .&Apache::lonhtmlcommon::row_closure(); + } + if (exists($filter->{'ownerfilter'})) { + $output .= &Apache::lonhtmlcommon::row_title($lt{'cow'}). + '
    '.&mt('Username').'
    '. + '
    '.&mt('Domain').'
    '. + $ownerdomselectform.'
    '. + &Apache::lonhtmlcommon::row_closure(); + } + if (exists($filter->{'personfilter'})) { + $output .= &Apache::lonhtmlcommon::row_title($lt{'cop'}). + '
    '.&mt('Username').'
    '. + '
    '.&mt('Domain').'
    '. + $persondomselectform.'
    '. + &Apache::lonhtmlcommon::row_closure(); + } + if (exists($filter->{'coursefilter'})) { + $output .= &Apache::lonhtmlcommon::row_title(&mt('LON-CAPA course ID')) + .'' + .&Apache::lonhtmlcommon::row_closure(); + } + if ($cloneableonlyform) { + $output .= &Apache::lonhtmlcommon::row_title($cloneabletitle). + $cloneableonlyform.&Apache::lonhtmlcommon::row_closure(); + } + if (exists($filter->{'descriptfilter'})) { + $output .= &Apache::lonhtmlcommon::row_title($lt{'cde'}) + .'' + .&Apache::lonhtmlcommon::row_closure(1); + } + $output .= &Apache::lonhtmlcommon::end_pick_box().'

    '.$clonetext."\n". + ''."\n". + '

    '."\n".'
    '."\n".'
    '."\n"; + return $jscript.$clonewarning.$output; +} + +=pod + +=item * &timebased_select_form() + +Create markup for a dropdown list used to select a time-based +filter e.g., Course Activity, Course Created, when searching for courses +or communities + +Inputs: + +item - name of form element (sincefilter or createdfilter) + +filter - anonymous hash of criteria and their values + +Returns: HTML for a select box contained a blank, then six time selections, + with value set in incoming form variables currently selected. + +Side Effects: None + +=cut + +sub timebased_select_form { + my ($item,$filter) = @_; + if (ref($filter) eq 'HASH') { + $filter->{$item} =~ s/[^\d-]//g; + if (!$filter->{$item}) { $filter->{$item}=-1; } + return &select_form( + $filter->{$item}, + $item, + { '-1' => '', + '86400' => &mt('today'), + '604800' => &mt('last week'), + '2592000' => &mt('last month'), + '7776000' => &mt('last three months'), + '15552000' => &mt('last six months'), + '31104000' => &mt('last year'), + 'select_form_order' => + ['-1','86400','604800','2592000','7776000', + '15552000','31104000']}); + } +} + +=pod + +=item * &js_changer() + +Create script tag containing Javascript used to submit course search form +when course type or domain is changed, and also to hide 'Searching ...' on +page load completion for page showing search result. + +Inputs: None + +Returns: markup containing updateFilters() and hideSearching() javascript functions. + +Side Effects: None + +=cut + +sub js_changer { + return < +// + + +ENDJS +} + +=pod + +=item * &search_courses() + +Process selected filters form course search form and pass to lonnet::courseiddump +to retrieve a hash for which keys are courseIDs which match the selected filters. + +Inputs: + +dom - domain being searched + +type - course type ('Course' or 'Community' or '.' if any). + +filter - anonymous hash of criteria and their values + +numtitles - for institutional codes - number of categories + +cloneruname - optional username of new course owner + +clonerudom - optional domain of new course owner + +domcloner - Optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, + (used when DC is using course creation form) + +codetitles - reference to array of titles of components in institutional codes (official courses). + + +Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type. + + +Side Effects: None + +=cut + + +sub search_courses { + my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles) = @_; + my (%courses,%showcourses,$cloner); + if (($filter->{'ownerfilter'} ne '') || + ($filter->{'ownerdomfilter'} ne '')) { + $filter->{'combownerfilter'} = $filter->{'ownerfilter'}.':'. + $filter->{'ownerdomfilter'}; + } + foreach my $item ('descriptfilter','coursefilter','combownerfilter') { + if (!$filter->{$item}) { + $filter->{$item}='.'; + } + } + my $now = time; + my $timefilter = + ($filter->{'sincefilter'}==-1?1:$now-$filter->{'sincefilter'}); + my ($createdbefore,$createdafter); + if (($filter->{'createdfilter'} ne '') && ($filter->{'createdfilter'} !=-1)) { + $createdbefore = $now; + $createdafter = $now-$filter->{'createdfilter'}; + } + my ($instcodefilter,$regexpok); + if ($numtitles) { + if ($env{'form.official'} eq 'on') { + $instcodefilter = + &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles); + $regexpok = 1; + } elsif ($env{'form.official'} eq 'off') { + $instcodefilter = &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles); + unless ($instcodefilter eq '') { + $regexpok = -1; + } + } + } else { + $instcodefilter = $filter->{'instcodefilter'}; + } + if ($instcodefilter eq '') { $instcodefilter = '.'; } + if ($type eq '') { $type = '.'; } + + if (($clonerudom ne '') && ($cloneruname ne '')) { + $cloner = $cloneruname.':'.$clonerudom; + } + %courses = &Apache::lonnet::courseiddump($dom, + $filter->{'descriptfilter'}, + $timefilter, + $instcodefilter, + $filter->{'combownerfilter'}, + $filter->{'coursefilter'}, + undef,undef,$type,$regexpok,undef,undef, + undef,undef,$cloner,$env{'form.cc_clone'}, + $filter->{'cloneableonly'}, + $createdbefore,$createdafter,undef, + $domcloner); + if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) { + my $ccrole; + if ($type eq 'Community') { + $ccrole = 'co'; + } else { + $ccrole = 'cc'; + } + my %rolehash = &Apache::lonnet::get_my_roles($filter->{'personfilter'}, + $filter->{'persondomfilter'}, + 'userroles',undef, + [$ccrole,'in','ad','ep','ta','cr'], + $dom); + foreach my $role (keys(%rolehash)) { + my ($cnum,$cdom,$courserole) = split(':',$role); + my $cid = $cdom.'_'.$cnum; + if (exists($courses{$cid})) { + if (ref($courses{$cid}) eq 'HASH') { + if (ref($courses{$cid}{roles}) eq 'ARRAY') { + if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) { + push (@{$courses{$cid}{roles}},$courserole); + } + } else { + $courses{$cid}{roles} = [$courserole]; + } + $showcourses{$cid} = $courses{$cid}; + } + } + } + %courses = %showcourses; + } + return %courses; +} + + +=pod + +=back + +=cut + + sub update_content_constraints { my ($cdom,$cnum,$chome,$cid) = @_; my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired'); @@ -14869,7 +15524,7 @@ sub captcha_display { $error = 'recaptcha'; } } - return ($output,$error); + return ($output,$error,$captcha); } sub captcha_response { @@ -14945,8 +15600,9 @@ sub create_captcha { if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') { $output = ''."\n". &mt('Type in the letters/numbers shown below').' '. - '
    '. - ''; + ''. + '
    '. + 'captcha'; last; } } @@ -15016,6 +15672,19 @@ sub check_recaptcha { return $captcha_chk; } +sub emailusername_info { + my @fields = ('firstname','lastname','institution','web','location','officialemail'); + my %titles = &Apache::lonlocal::texthash ( + lastname => 'Last Name', + firstname => 'First Name', + institution => 'School/college/university', + location => "School's city, state/province, country", + web => "School's web address", + officialemail => 'E-mail address at institution (if different)', + ); + return (\@fields,\%titles); +} + sub cleanup_html { my ($incoming) = @_; my $outgoing; @@ -15038,11 +15707,67 @@ sub cleanup_html { return $outgoing; } -=pod - -=back +# Checks for critical messages and returns a redirect url if one exists. +# $interval indicates how often to check for messages. +sub critical_redirect { + my ($interval) = @_; + if ((time-$env{'user.criticalcheck.time'})>$interval) { + my @what=&Apache::lonnet::dump('critical', $env{'user.domain'}, + $env{'user.name'}); + &Apache::lonnet::appenv({'user.criticalcheck.time'=>time}); + my $redirecturl; + if ($what[0]) { + if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) { + $redirecturl='/adm/email?critical=display'; + my $url=&Apache::lonnet::absolute_url().$redirecturl; + return (1, $url); + } + } + } + return (); +} -=cut +# Use: +# my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver); +# +################################################## +# password associated functions # +################################################## +sub des_keys { + # Make a new key for DES encryption. + # Each key has two parts which are returned separately. + # Please note: Each key must be passed through the &hex function + # before it is output to the web browser. The hex versions cannot + # be used to decrypt. + my @hexstr=('0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f'); + my $lkey=''; + for (0..7) { + $lkey.=$hexstr[rand(15)]; + } + my $ukey=''; + for (0..7) { + $ukey.=$hexstr[rand(15)]; + } + return ($lkey,$ukey); +} + +sub des_decrypt { + my ($key,$cyphertext) = @_; + my $keybin=pack("H16",$key); + my $cypher; + if ($Crypt::DES::VERSION>=2.03) { + $cypher=new Crypt::DES $keybin; + } else { + $cypher=new DES $keybin; + } + my $plaintext= + $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16)))); + $plaintext.= + $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16)))); + $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) ); + return $plaintext; +} 1; __END__;