--- loncom/interface/loncommon.pm 2014/12/20 15:35:40 1.1203 +++ loncom/interface/loncommon.pm 2016/02/17 19:15:48 1.1233 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1203 2014/12/20 15:35:40 raeburn Exp $ +# $Id: loncommon.pm,v 1.1233 2016/02/17 19:15:48 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -73,11 +73,14 @@ use Apache::courseclassifier(); use LONCAPA qw(:DEFAULT :match); use DateTime::TimeZone; use DateTime::Locale::Catalog; +use Encode(); use Text::Aspell; use Authen::Captcha; use Captcha::reCAPTCHA; use Crypt::DES; use DynaLoader; # for Crypt::DES version +use MIME::Lite; +use MIME::Types; # ---------------------------------------------- Designs use vars qw(%defaultdesign); @@ -535,7 +538,7 @@ ENDAUTHORBRW sub coursebrowser_javascript { my ($domainfilter,$sec_element,$formname,$role_element,$crstype, - $credits_element) = @_; + $credits_element,$instcode) = @_; my $wintitle = 'Course_Browser'; if ($crstype eq 'Community') { $wintitle = 'Community_Browser'; @@ -585,7 +588,10 @@ sub coursebrowser_javascript { if (formname == 'ccrs') { var ownername = document.forms[formid].ccuname.value; var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value; - url += '&cloner='+ownername+':'+ownerdom; + url += '&cloner='+ownername+':'+ownerdom+'&crscode='+document.forms[formid].crscode.value; + } + if (formname == 'requestcrs') { + url += '&crsdom=$domainfilter&crscode=$instcode'; } if (multflag !=null && multflag != '') { url += '&multiple='+multflag; @@ -983,6 +989,7 @@ sub select_datelocale { $locale_names{$id} = '('.$en_terr.')'; } } + $locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id}); push (@possibles,$id); } } @@ -994,7 +1001,7 @@ sub select_datelocale { } $output.=">$item"; if ($locale_names{$item} ne '') { - $output.=" $locale_names{$item}\n"; + $output.=' '.$locale_names{$item}; } $output.="\n"; } @@ -1757,6 +1764,241 @@ RESIZE } +sub colorfuleditor_js { + return <<"COLORFULEDIT" + +COLORFULEDIT +} + +sub xmleditor_js { + return < + +XMLEDIT +} + +sub insert_folding_button { + my $curDepth = $Apache::lonxml::curdepth; + my $lastresource = $env{'request.ambiguous'}; + + return ""; +} + =pod =head1 Excel and CSV file utility routines @@ -2029,12 +2271,16 @@ See lonrights.pm for an example invocati #------------------------------------------- sub select_form { - my ($def,$name,$hashref,$onchange) = @_; + my ($def,$name,$hashref,$onchange,$readonly) = @_; return unless (ref($hashref) eq 'HASH'); if ($onchange) { $onchange = ' onchange="'.$onchange.'"'; } - my $selectform = "\n"; my @keys; if (exists($hashref->{'select_form_order'})) { @keys=@{$hashref->{'select_form_order'}}; @@ -3805,8 +4051,13 @@ sub get_previous_attempt { my %lasthash=(); my $version; for ($version=1;$version<=$returnhash{'version'};$version++) { - foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) { - $lasthash{$key}=$returnhash{$version.':'.$key}; + foreach my $key (reverse(sort(split(/\:/,$returnhash{$version.':keys'})))) { + if ($key =~ /\.rawrndseed$/) { + my ($id) = ($key =~ /^(.+)\.rawrndseed$/); + $lasthash{$id.'.rndseed'} = $returnhash{$version.':'.$key}; + } else { + $lasthash{$key}=$returnhash{$version.':'.$key}; + } } } $prevattempts=&start_data_table().&start_data_table_header_row(); @@ -3926,9 +4177,15 @@ sub get_previous_attempt { } } else { if ($key =~ /\./) { - my $value = &format_previous_attempt_value($key, - $returnhash{$version.':'.$key}); - $prevattempts.=''.$value.' '; + my $value = $returnhash{$version.':'.$key}; + if ($key =~ /\.rndseed$/) { + my ($id) = ($key =~ /^(.+)\.[^.]+$/); + if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) { + $value = $returnhash{$version.':'.$id.'.rawrndseed'}; + } + } + $prevattempts.=''.&format_previous_attempt_value($key,$value). + ' '; } else { $prevattempts.=' '; } @@ -3937,9 +4194,15 @@ sub get_previous_attempt { } else { foreach my $key (sort(keys(%lasthash))) { next if ($key =~ /\.foilorder$/); - my $value = &format_previous_attempt_value($key, - $returnhash{$version.':'.$key}); - $prevattempts.=''.$value.' '; + my $value = $returnhash{$version.':'.$key}; + if ($key =~ /\.rndseed$/) { + my ($id) = ($key =~ /^(.+)\.[^.]+$/); + if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) { + $value = $returnhash{$version.':'.$id.'.rawrndseed'}; + } + } + $prevattempts.=''.&format_previous_attempt_value($key,$value). + ' '; } } $prevattempts.=&end_data_table_row(); @@ -4696,9 +4959,9 @@ sub blocking_status { # build a link to a popup window containing the details my $querystring = "?activity=$activity"; # $uname and $udom decide whose portfolio the user is trying to look at - if ($activity eq 'port') { - $querystring .= "&udom=$udom" if $udom; - $querystring .= "&uname=$uname" if $uname; + if (($activity eq 'port') || ($activity eq 'passwd')) { + $querystring .= "&udom=$udom" if ($udom =~ /^$match_domain$/); + $querystring .= "&uname=$uname" if ($uname =~ /^$match_username$/); } elsif ($activity eq 'docs') { $querystring .= '&url='.&HTML::Entities::encode($url,'&"'); } @@ -4717,13 +4980,17 @@ END_MYBLOCK my $popupUrl = "/adm/blockingstatus/$querystring"; my $text = &mt('Communication Blocked'); + my $class = 'LC_comblock'; if ($activity eq 'docs') { $text = &mt('Content Access Blocked'); + $class = ''; } elsif ($activity eq 'printout') { $text = &mt('Printing Blocked'); + } elsif ($activity eq 'passwd') { + $text = &mt('Password Changing Blocked'); } $output .= <<"END_BLOCK"; -
+
$text @@ -4744,17 +5011,39 @@ sub check_ip_acc { if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) { return 1; } - my $allowed=0; + my $allowed; my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip; my $name; - foreach my $pattern (split(',',$acc)) { - $pattern =~ s/^\s*//; - $pattern =~ s/\s*$//; + my %access = ( + allowfrom => 1, + denyfrom => 0, + ); + my @allows; + my @denies; + foreach my $item (split(',',$acc)) { + $item =~ s/^\s*//; + $item =~ s/\s*$//; + my $pattern; + if ($item =~ /^\!(.+)$/) { + push(@denies,$1); + } else { + push(@allows,$item); + } + } + my $numdenies = scalar(@denies); + my $numallows = scalar(@allows); + my $count = 0; + foreach my $pattern (@denies,@allows) { + $count ++; + my $acctype = 'allowfrom'; + if ($count <= $numdenies) { + $acctype = 'denyfrom'; + } if ($pattern =~ /\*$/) { #35.8.* $pattern=~s/\*//; - if ($ip =~ /^\Q$pattern\E/) { $allowed=1; } + if ($ip =~ /^\Q$pattern\E/) { $allowed=$access{$acctype}; } } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) { #35.8.3.[34-56] my $low=$2; @@ -4762,7 +5051,7 @@ sub check_ip_acc { $pattern=$1; if ($ip =~ /^\Q$pattern\E/) { my $last=(split(/\./,$ip))[3]; - if ($last <=$high && $last >=$low) { $allowed=1; } + if ($last <=$high && $last >=$low) { $allowed=$access{$acctype}; } } } elsif ($pattern =~ /^\*/) { #*.msu.edu @@ -4772,10 +5061,10 @@ sub check_ip_acc { my $netaddr=inet_aton($ip); ($name)=gethostbyaddr($netaddr,AF_INET); } - if ($name =~ /\Q$pattern\E$/i) { $allowed=1; } + if ($name =~ /\Q$pattern\E$/i) { $allowed=$access{$acctype}; } } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) { #127.0.0.1 - if ($ip =~ /^\Q$pattern\E/) { $allowed=1; } + if ($ip =~ /^\Q$pattern\E/) { $allowed=$access{$acctype}; } } else { #some.name.com if (!defined($name)) { @@ -4783,9 +5072,16 @@ sub check_ip_acc { my $netaddr=inet_aton($ip); ($name)=gethostbyaddr($netaddr,AF_INET); } - if ($name =~ /\Q$pattern\E$/i) { $allowed=1; } + if ($name =~ /\Q$pattern\E$/i) { $allowed=$access{$acctype}; } + } + if ($allowed =~ /^(0|1)$/) { last; } + } + if ($allowed eq '') { + if ($numdenies && !$numallows) { + $allowed = 1; + } else { + $allowed = 0; } - if ($allowed) { last; } } return $allowed; } @@ -4841,23 +5137,29 @@ sub get_domainconf { if (keys(%{$domconfig{'login'}})) { foreach my $key (keys(%{$domconfig{'login'}})) { if (ref($domconfig{'login'}{$key}) eq 'HASH') { - if ($key eq 'loginvia') { - if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') { - foreach my $hostname (keys(%{$domconfig{'login'}{'loginvia'}})) { - if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') { - if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) { - my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'}; - $designhash{$udom.'.login.loginvia'} = $server; - if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') { - - $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'}; - } else { - $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'}; + if (($key eq 'loginvia') || ($key eq 'headtag')) { + if (ref($domconfig{'login'}{$key}) eq 'HASH') { + foreach my $hostname (keys(%{$domconfig{'login'}{$key}})) { + if (ref($domconfig{'login'}{$key}{$hostname}) eq 'HASH') { + if ($key eq 'loginvia') { + if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) { + my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'}; + $designhash{$udom.'.login.loginvia'} = $server; + if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') { + + $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'}; + } else { + $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'}; + } } - if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) { - $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}; + } elsif ($key eq 'headtag') { + if ($domconfig{'login'}{'headtag'}{$hostname}{'url'}) { + $designhash{$udom.'.login.headtag_'.$hostname} = $domconfig{'login'}{'headtag'}{$hostname}{'url'}; } } + if ($domconfig{'login'}{$key}{$hostname}{'exempt'}) { + $designhash{$udom.'.login.'.$key.'_exempt_'.$hostname} = $domconfig{'login'}{$key}{$hostname}{'exempt'}; + } } } } @@ -6554,7 +6856,7 @@ div.LC_edit_problem_footer, div.LC_edit_problem_footer div, div.LC_edit_problem_editxml_header, div.LC_edit_problem_editxml_header div { - margin-top: 5px; + z-index: 100; } div.LC_edit_problem_header_title { @@ -6570,14 +6872,17 @@ table.LC_edit_problem_header_title { background: $tabbg; } -div.LC_edit_problem_discards { - float: left; - padding-bottom: 5px; +div.LC_edit_actionbar { + background-color: $sidebg; + margin: 0; + padding: 0; + line-height: 200%; } -div.LC_edit_problem_saves { - float: right; - padding-bottom: 5px; +div.LC_edit_actionbar div{ + padding: 0; + margin: 0; + display: inline-block; } .LC_edit_opt { @@ -6593,6 +6898,10 @@ div.LC_edit_problem_saves { margin-left: 40px; } +#LC_edit_problem_codemirror div{ + margin-left: 0px; +} + img.stift { border-width: 0; vertical-align: middle; @@ -6680,6 +6989,10 @@ fieldset { /* overflow: hidden; */ } +article.geogebraweb div { + margin: 0; +} + fieldset > legend { font-weight: bold; padding: 0 5px 0 5px; @@ -6707,7 +7020,6 @@ fieldset > legend { ol.LC_primary_menu { margin: 0; padding: 0; - background-color: $pgbg_or_bgcolor; } ol#LC_PathBreadcrumbs { @@ -6719,23 +7031,48 @@ ol.LC_primary_menu li { vertical-align: middle; text-align: left; list-style: none; + position: relative; float: left; + z-index: 100; /* will be displayed above codemirror and underneath the help-layer */ + line-height: 1.5em; } -ol.LC_primary_menu li a { +ol.LC_primary_menu li a, +ol.LC_primary_menu li p { display: block; margin: 0; padding: 0 5px 0 10px; text-decoration: none; } -ol.LC_primary_menu li ul { +ol.LC_primary_menu li p span.LC_primary_menu_innertitle { + display: inline-block; + width: 95%; + text-align: left; +} + +ol.LC_primary_menu li p span.LC_primary_menu_innerarrow { + display: inline-block; + width: 5%; + float: right; + text-align: right; + font-size: 70%; +} + +ol.LC_primary_menu ul { display: none; - width: 10em; + width: 15em; background-color: $data_table_light; + position: absolute; + top: 100%; } -ol.LC_primary_menu li:hover ul, ol.LC_primary_menu li.hover ul { +ol.LC_primary_menu ul ul { + left: 100%; + top: 0; +} + +ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul { display: block; position: absolute; margin: 0; @@ -6744,15 +7081,21 @@ ol.LC_primary_menu li:hover ul, ol.LC_pr } ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li { +/* First Submenu -> size should be smaller than the menu title of the whole menu */ font-size: 90%; vertical-align: top; float: none; border-left: 1px solid black; border-right: 1px solid black; +/* A dark bottom border to visualize different menu options; +overwritten in the create_submenu routine for the last border-bottom of the menu */ + border-bottom: 1px solid $data_table_dark; } -ol.LC_primary_menu li:hover li a, ol.LC_primary_menu li.hover li a { - background-color:$data_table_light; +ol.LC_primary_menu li li p:hover { + color:$button_hover; + text-decoration:none; + background-color:$data_table_dark; } ol.LC_primary_menu li li a:hover { @@ -6760,6 +7103,11 @@ ol.LC_primary_menu li li a:hover { background-color:$data_table_dark; } +/* Font-size equal to the size of the predecessors*/ +ol.LC_primary_menu li:hover li li { + font-size: 100%; +} + ol.LC_primary_menu li img { vertical-align: bottom; height: 1.1em; @@ -7302,6 +7650,16 @@ ul.LC_funclist li { } /* + styles used for response display +*/ +div.LC_radiofoil, div.LC_rankfoil { + margin: .5em 0em .5em 0em; +} +table.LC_itemgroup { + margin-top: 1em; +} + +/* styles used by TTH when "Default set of options to pass to tth/m when converting TeX" in course settings has been set @@ -7322,6 +7680,87 @@ span.roman {font-family: serif; font-sty span.overacc2 {position: relative; left: .8em; top: -1.2ex;} span.overacc1 {position: relative; left: .6em; top: -1.2ex;} +/* + sections with roles, for content only +*/ +section[class^="role-"] { + padding-left: 10px; + padding-right: 5px; + margin-top: 8px; + margin-bottom: 8px; + border: 1px solid #2A4; + border-radius: 5px; + box-shadow: 0px 1px 1px #BBB; +} +section[class^="role-"]>h1 { + position: relative; + margin: 0px; + padding-top: 10px; + padding-left: 40px; +} +section[class^="role-"]>h1:before { + position: absolute; + left: -5px; + top: 5px; +} +section.role-activity>h1:before { + content:url('/adm/daxe/images/section_icons/activity.png'); +} +section.role-advice>h1:before { + content:url('/adm/daxe/images/section_icons/advice.png'); +} +section.role-bibliography>h1:before { + content:url('/adm/daxe/images/section_icons/bibliography.png'); +} +section.role-citation>h1:before { + content:url('/adm/daxe/images/section_icons/citation.png'); +} +section.role-conclusion>h1:before { + content:url('/adm/daxe/images/section_icons/conclusion.png'); +} +section.role-definition>h1:before { + content:url('/adm/daxe/images/section_icons/definition.png'); +} +section.role-demonstration>h1:before { + content:url('/adm/daxe/images/section_icons/demonstration.png'); +} +section.role-example>h1:before { + content:url('/adm/daxe/images/section_icons/example.png'); +} +section.role-explanation>h1:before { + content:url('/adm/daxe/images/section_icons/explanation.png'); +} +section.role-introduction>h1:before { + content:url('/adm/daxe/images/section_icons/introduction.png'); +} +section.role-method>h1:before { + content:url('/adm/daxe/images/section_icons/method.png'); +} +section.role-more_information>h1:before { + content:url('/adm/daxe/images/section_icons/more_information.png'); +} +section.role-objectives>h1:before { + content:url('/adm/daxe/images/section_icons/objectives.png'); +} +section.role-prerequisites>h1:before { + content:url('/adm/daxe/images/section_icons/prerequisites.png'); +} +section.role-remark>h1:before { + content:url('/adm/daxe/images/section_icons/remark.png'); +} +section.role-reminder>h1:before { + content:url('/adm/daxe/images/section_icons/reminder.png'); +} +section.role-summary>h1:before { + content:url('/adm/daxe/images/section_icons/summary.png'); +} +section.role-syntax>h1:before { + content:url('/adm/daxe/images/section_icons/syntax.png'); +} +section.role-warning>h1:before { + content:url('/adm/daxe/images/section_icons/warning.png'); +} + END } @@ -7414,6 +7853,82 @@ sub headtag { ADDMETA + } else { + unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) { + my $requrl = $env{'request.uri'}; + if ($requrl eq '') { + $requrl = $ENV{'REQUEST_URI'}; + $requrl =~ s/\?.+$//; + } + unless (($requrl =~ m{^/adm/(?:switchserver|login|authenticate|logout|groupsort|cleanup|helper|slotrequest|grades)(\?|$)}) || + (($requrl =~ m{^/res/}) && (($env{'form.submitted'} eq 'scantron') || + ($env{'form.grade_symb'}) || ($Apache::lonhomework::scantronmode)))) { + my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'}; + unless (&Apache::lonnet::allowed('mau',$dom_in_use)) { + my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use); + if (ref($domdefs{'offloadnow'}) eq 'HASH') { + my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; + if ($domdefs{'offloadnow'}{$lonhost}) { + my $newserver = &Apache::lonnet::spareserver(30000,undef,1,$dom_in_use); + if (($newserver) && ($newserver ne $lonhost)) { + my $numsec = 5; + my $timeout = $numsec * 1000; + my ($newurl,$locknum,%locks,$msg); + if ($env{'request.role.adv'}) { + ($locknum,%locks) = &Apache::lonnet::get_locks(); + } + my $disable_submit = 0; + if ($requrl =~ /$LONCAPA::assess_re/) { + $disable_submit = 1; + } + if ($locknum) { + my @lockinfo = sort(values(%locks)); + $msg = &mt('Once the following tasks are complete: ')."\\n". + join(", ",sort(values(%locks)))."\\n". + &mt('your session will be transferred to a different server, after you click "Roles".'); + } else { + if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) { + $msg = &mt('Your LON-CAPA submission has been recorded')."\\n"; + } + $msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec); + $newurl = '/adm/switchserver?otherserver='.$newserver; + if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) { + $newurl .= '&role='.$env{'request.role'}; + } + if ($env{'request.symb'}) { + $newurl .= '&symb='.$env{'request.symb'}; + } else { + $newurl .= '&origurl='.$requrl; + } + } + &js_escape(\$msg); + $result.=< + +OFFLOAD + } + } + } + } + } + } } if (!defined($title)) { $title = 'The LearningOnline Network with CAPA'; @@ -7787,7 +8302,7 @@ var modalWindow = { modalWindow.height = height; modalWindow.content = ""; modalWindow.open(); - }; + }; // END LON-CAPA Internal --> // ]]> @@ -9121,7 +9636,7 @@ sub user_picker { } $srchterm = $srch->{'srchterm'}; } - my %lt=&Apache::lonlocal::texthash( + my %html_lt=&Apache::lonlocal::texthash( 'usr' => 'Search criteria', 'doma' => 'Domain/institution to search', 'uname' => 'username', @@ -9134,6 +9649,8 @@ sub user_picker { 'exact' => 'is', 'contains' => 'contains', 'begins' => 'begins with', + ); + my %js_lt=&Apache::lonlocal::texthash( 'youm' => "You must include some text to search for.", 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.", 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.", @@ -9143,6 +9660,8 @@ sub user_picker { 'whse' => "When searching by last,first you must include at least one character in the first name.", 'thfo' => "The following need to be corrected before the search can be run:", ); + &html_escape(\%html_lt); + &js_escape(\%js_lt); my $domform = &select_dom_form($currdom,'srchdomain',1,1); my $srchinsel = ' \n"; @@ -9169,10 +9688,10 @@ sub user_picker { foreach my $option ('lastname','lastfirst','uname') { if ($curr_selected{'srchby'} eq $option) { $srchbysel .= ' - '; + '; } else { $srchbysel .= ' - '; + '; } } $srchbysel .= "\n \n"; @@ -9181,10 +9700,10 @@ sub user_picker { foreach my $option ('begins','contains','exact') { if ($curr_selected{'srchtype'} eq $option) { $srchtypesel .= ' - '; + '; } else { $srchtypesel .= ' - '; + '; } } $srchtypesel .= "\n \n"; @@ -9269,46 +9788,46 @@ function validateEntry(callingForm) { if (srchterm == "") { checkok = 0; - msg += "$lt{'youm'}\\n"; + msg += "$js_lt{'youm'}\\n"; } if (srchtype== 'begins') { if (srchterm.length < 2) { checkok = 0; - msg += "$lt{'thte'}\\n"; + msg += "$js_lt{'thte'}\\n"; } } if (srchtype== 'contains') { if (srchterm.length < 3) { checkok = 0; - msg += "$lt{'thet'}\\n"; + msg += "$js_lt{'thet'}\\n"; } } if (srchin == 'instd') { if (srchdomain == '') { checkok = 0; - msg += "$lt{'yomc'}\\n"; + msg += "$js_lt{'yomc'}\\n"; } } if (srchin == 'dom') { if (srchdomain == '') { checkok = 0; - msg += "$lt{'ymcd'}\\n"; + msg += "$js_lt{'ymcd'}\\n"; } } if (srchby == 'lastfirst') { if (srchterm.indexOf(",") == -1) { checkok = 0; - msg += "$lt{'whus'}\\n"; + msg += "$js_lt{'whus'}\\n"; } if (srchterm.indexOf(",") == srchterm.length -1) { checkok = 0; - msg += "$lt{'whse'}\\n"; + msg += "$js_lt{'whse'}\\n"; } } if (checkok == 0) { - alert("$lt{'thfo'}\\n"+msg); + alert("$js_lt{'thfo'}\\n"+msg); return; } if (checkok == 1) { @@ -9326,10 +9845,10 @@ $new_user_create END_BLOCK $output .= &Apache::lonhtmlcommon::start_pick_box(). - &Apache::lonhtmlcommon::row_title($lt{'doma'}). + &Apache::lonhtmlcommon::row_title($html_lt{'doma'}). $domform. &Apache::lonhtmlcommon::row_closure(). - &Apache::lonhtmlcommon::row_title($lt{'usr'}). + &Apache::lonhtmlcommon::row_title($html_lt{'usr'}). $srchbysel. $srchtypesel. ''. @@ -9342,56 +9861,160 @@ END_BLOCK sub user_rule_check { my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_; - my $response; + my ($response,%inst_response); if (ref($usershash) eq 'HASH') { - foreach my $user (keys(%{$usershash})) { - my ($uname,$udom) = split(/:/,$user); - next if ($udom eq '' || $uname eq ''); - my ($id,$newuser); - if (ref($usershash->{$user}) eq 'HASH') { - $newuser = $usershash->{$user}->{'newuser'}; - $id = $usershash->{$user}->{'id'}; - } - my $inst_response; + if (keys(%{$usershash}) > 1) { + my (%by_username,%by_id,%userdoms); + my $checkid; if (ref($checks) eq 'HASH') { - if (defined($checks->{'username'})) { - ($inst_response,%{$inst_results->{$user}}) = - &Apache::lonnet::get_instuser($udom,$uname); - } elsif (defined($checks->{'id'})) { - ($inst_response,%{$inst_results->{$user}}) = - &Apache::lonnet::get_instuser($udom,undef,$id); + if ((!defined($checks->{'username'})) && (defined($checks->{'id'}))) { + $checkid = 1; + } + } + foreach my $user (keys(%{$usershash})) { + my ($uname,$udom) = split(/:/,$user); + if ($checkid) { + if (ref($usershash->{$user}) eq 'HASH') { + if ($usershash->{$user}->{'id'} ne '') { + $by_id{$udom}{$usershash->{$user}->{'id'}} = $uname; + $userdoms{$udom} = 1; + if (ref($inst_results) eq 'HASH') { + $inst_results->{$uname.':'.$udom} = {}; + } + } + } + } else { + $by_username{$udom}{$uname} = 1; + $userdoms{$udom} = 1; + if (ref($inst_results) eq 'HASH') { + $inst_results->{$uname.':'.$udom} = {}; + } + } + } + foreach my $udom (keys(%userdoms)) { + if (!$got_rules->{$udom}) { + my %domconfig = &Apache::lonnet::get_dom('configuration', + ['usercreation'],$udom); + if (ref($domconfig{'usercreation'}) eq 'HASH') { + foreach my $item ('username','id') { + if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { + $$curr_rules{$udom}{$item} = + $domconfig{'usercreation'}{$item.'_rule'}; + } + } + } + $got_rules->{$udom} = 1; + } + } + if ($checkid) { + foreach my $udom (keys(%by_id)) { + my ($outcome,$results) = &Apache::lonnet::get_multiple_instusers($udom,$by_id{$udom},'id'); + if ($outcome eq 'ok') { + foreach my $id (keys(%{$by_id{$udom}})) { + my $uname = $by_id{$udom}{$id}; + $inst_response{$uname.':'.$udom} = $outcome; + } + if (ref($results) eq 'HASH') { + foreach my $uname (keys(%{$results})) { + if (exists($inst_response{$uname.':'.$udom})) { + $inst_response{$uname.':'.$udom} = $outcome; + $inst_results->{$uname.':'.$udom} = $results->{$uname}; + } + } + } + } } } else { - ($inst_response,%{$inst_results->{$user}}) = - &Apache::lonnet::get_instuser($udom,$uname); - return; + foreach my $udom (keys(%by_username)) { + my ($outcome,$results) = &Apache::lonnet::get_multiple_instusers($udom,$by_username{$udom}); + if ($outcome eq 'ok') { + foreach my $uname (keys(%{$by_username{$udom}})) { + $inst_response{$uname.':'.$udom} = $outcome; + } + if (ref($results) eq 'HASH') { + foreach my $uname (keys(%{$results})) { + $inst_results->{$uname.':'.$udom} = $results->{$uname}; + } + } + } + } } - if (!$got_rules->{$udom}) { - my %domconfig = &Apache::lonnet::get_dom('configuration', - ['usercreation'],$udom); - if (ref($domconfig{'usercreation'}) eq 'HASH') { - foreach my $item ('username','id') { - if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { - $$curr_rules{$udom}{$item} = - $domconfig{'usercreation'}{$item.'_rule'}; + } elsif (keys(%{$usershash}) == 1) { + my $user = (keys(%{$usershash}))[0]; + my ($uname,$udom) = split(/:/,$user); + if (($udom ne '') && ($uname ne '')) { + if (ref($usershash->{$user}) eq 'HASH') { + if (ref($checks) eq 'HASH') { + if (defined($checks->{'username'})) { + ($inst_response{$user},%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,$uname); + } elsif (defined($checks->{'id'})) { + if ($usershash->{$user}->{'id'} ne '') { + ($inst_response{$user},%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,undef, + $usershash->{$user}->{'id'}); + } else { + ($inst_response{$user},%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,$uname); + } + } + } else { + ($inst_response{$user},%{$inst_results->{$user}}) = + &Apache::lonnet::get_instuser($udom,$uname); + return; + } + if (!$got_rules->{$udom}) { + my %domconfig = &Apache::lonnet::get_dom('configuration', + ['usercreation'],$udom); + if (ref($domconfig{'usercreation'}) eq 'HASH') { + foreach my $item ('username','id') { + if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { + $$curr_rules{$udom}{$item} = + $domconfig{'usercreation'}{$item.'_rule'}; + } + } } + $got_rules->{$udom} = 1; } } - $got_rules->{$udom} = 1; + } else { + return; + } + } else { + return; + } + foreach my $user (keys(%{$usershash})) { + my ($uname,$udom) = split(/:/,$user); + next if (($udom eq '') || ($uname eq '')); + my $id; + if (ref($inst_results) eq 'HASH') { + if (ref($inst_results->{$user}) eq 'HASH') { + $id = $inst_results->{$user}->{'id'}; + } + } + if ($id eq '') { + if (ref($usershash->{$user})) { + $id = $usershash->{$user}->{'id'}; + } } foreach my $item (keys(%{$checks})) { if (ref($$curr_rules{$udom}) eq 'HASH') { if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') { if (@{$$curr_rules{$udom}{$item}} > 0) { - my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item}); + my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item, + $$curr_rules{$udom}{$item}); foreach my $rule (@{$$curr_rules{$udom}{$item}}) { if ($rule_check{$rule}) { $$rulematch{$user}{$item} = $rule; - if ($inst_response eq 'ok') { + if ($inst_response{$user} eq 'ok') { if (ref($inst_results) eq 'HASH') { if (ref($inst_results->{$user}) eq 'HASH') { if (keys(%{$inst_results->{$user}}) == 0) { $$alerts{$item}{$udom}{$uname} = 1; + } elsif ($item eq 'id') { + if ($inst_results->{$user}->{'id'} eq '') { + $$alerts{$item}{$udom}{$uname} = 1; + } } } } @@ -9677,13 +10300,35 @@ future_reservable - ref to hash of stude sub get_future_slots { my ($cnum,$cdom,$now,$symb) = @_; + my $map; + if ($symb) { + ($map) = &Apache::lonnet::decode_symb($symb); + } my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future); my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom); foreach my $slot (keys(%slots)) { next unless($slots{$slot}->{'type'} eq 'schedulable_student'); if ($symb) { - next if (($slots{$slot}->{'symb'} ne '') && - ($slots{$slot}->{'symb'} ne $symb)); + if ($slots{$slot}->{'symb'} ne '') { + my $canuse; + my %oksymbs; + my @slotsymbs = split(/\s*,\s*/,$slots{$slot}->{'symb'}); + map { $oksymbs{$_} = 1; } @slotsymbs; + if ($oksymbs{$symb}) { + $canuse = 1; + } else { + foreach my $item (@slotsymbs) { + if ($item =~ /\.(page|sequence)$/) { + (undef,undef,my $sloturl) = &Apache::lonnet::decode_symb($item); + if (($map ne '') && ($map eq $sloturl)) { + $canuse = 1; + last; + } + } + } + } + next unless ($canuse); + } } if (($slots{$slot}->{'starttime'} > $now) && ($slots{$slot}->{'endtime'} > $now)) { @@ -11201,7 +11846,6 @@ function camtasiaToggle() { for (var i=0; inew( + From => $from, + To => $to, + Subject => $subject, + Type =>'TEXT', + Data => $body, + ); + if ($cc_string ne '') { + $msg->add("Cc" => $cc_string); + } + if ($bcc ne '') { + $msg->add("Bcc" => $bcc); + } + $msg->attr("content-type" => "text/plain"); + $msg->attr("content-type.charset" => "UTF-8"); + # Attach file if given + if ($attachment_path) { + unless ($file_name) { + if ($attachment_path =~ m-/([^/]+)$-) { $file_name = $1; } + } + my ($type, $encoding) = MIME::Types::by_suffix($attachment_path); + $msg->attach(Type => $type, + Path => $attachment_path, + Filename => $file_name + ); + # Otherwise attach text if given + } elsif ($attachment_text) { + $msg->attach(Type => 'TEXT', + Data => $attachment_text); + } + # Send it + $msg->send('sendmail'); +} + +############################################################ +############################################################ + +=pod + =head1 Course Catalog Routines =over 4 @@ -14000,34 +14725,92 @@ sub check_clone { (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) { $can_clone = 1; } else { - my %clonehash = &Apache::lonnet::get('environment',['cloners'], + my %clonehash = &Apache::lonnet::get('environment',['cloners','internal.coursecode'], $args->{'clonedomain'},$args->{'clonecourse'}); - my @cloners = split(/,/,$clonehash{'cloners'}); - if (grep(/^\*$/,@cloners)) { - $can_clone = 1; - } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { - $can_clone = 1; + if ($clonehash{'cloners'} eq '') { + my %domdefs = &Apache::lonnet::get_domain_defaults($args->{'course_domain'}); + if ($domdefs{'canclone'}) { + unless ($domdefs{'canclone'} eq 'none') { + if ($domdefs{'canclone'} eq 'domain') { + if ($args->{'ccdomain'} eq $args->{'clonedomain'}) { + $can_clone = 1; + } + } elsif (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && + ($args->{'clonedomain'} eq $args->{'course_domain'})) { + if (&Apache::lonnet::default_instcode_cloning($args->{'clonedomain'},$domdefs{'canclone'}, + $clonehash{'internal.coursecode'},$args->{'crscode'})) { + $can_clone = 1; + } + } + } + } } else { + my @cloners = split(/,/,$clonehash{'cloners'}); + if (grep(/^\*$/,@cloners)) { + $can_clone = 1; + } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { + $can_clone = 1; + } elsif (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners)) { + $can_clone = 1; + } + unless ($can_clone) { + if (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && + ($args->{'clonedomain'} eq $args->{'course_domain'})) { + my (%gotdomdefaults,%gotcodedefaults); + foreach my $cloner (@cloners) { + if (($cloner ne '*') && ($cloner !~ /^\*\:$match_domain$/) && + ($cloner !~ /^$match_username\:$match_domain$/) && ($cloner ne '')) { + my (%codedefaults,@code_order); + if (ref($gotcodedefaults{$args->{'clonedomain'}}) eq 'HASH') { + if (ref($gotcodedefaults{$args->{'clonedomain'}}{'defaults'}) eq 'HASH') { + %codedefaults = %{$gotcodedefaults{$args->{'clonedomain'}}{'defaults'}}; + } + if (ref($gotcodedefaults{$args->{'clonedomain'}}{'order'}) eq 'ARRAY') { + @code_order = @{$gotcodedefaults{$args->{'clonedomain'}}{'order'}}; + } + } else { + &Apache::lonnet::auto_instcode_defaults($args->{'clonedomain'}, + \%codedefaults, + \@code_order); + $gotcodedefaults{$args->{'clonedomain'}}{'defaults'} = \%codedefaults; + $gotcodedefaults{$args->{'clonedomain'}}{'order'} = \@code_order; + } + if (@code_order > 0) { + if (&Apache::lonnet::check_instcode_cloning(\%codedefaults,\@code_order, + $cloner,$clonehash{'internal.coursecode'}, + $args->{'crscode'})) { + $can_clone = 1; + last; + } + } + } + } + } + } + } + unless ($can_clone) { my $ccrole = 'cc'; if ($args->{'crstype'} eq 'Community') { $ccrole = 'co'; } my %roleshash = &Apache::lonnet::get_my_roles($args->{'ccuname'}, - $args->{'ccdomain'}, - 'userroles',['active'],[$ccrole], - [$args->{'clonedomain'}]); - if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { + $args->{'ccdomain'}, + 'userroles',['active'],[$ccrole], + [$args->{'clonedomain'}]); + if ($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) { $can_clone = 1; - } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},$args->{'ccuname'},$args->{'ccdomain'})) { + } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'}, + $args->{'ccuname'},$args->{'ccdomain'})) { $can_clone = 1; + } + } + unless ($can_clone) { + if ($args->{'crstype'} eq 'Community') { + $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); } else { - if ($args->{'crstype'} eq 'Community') { - $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); - } else { - $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); - } - } + $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); + } } } } @@ -14613,6 +15396,17 @@ sub init_user_environment { } } closedir(DIR); +# If there is a undeleted lockfile for the user's paste buffer remove it. + my $namespace = 'nohist_courseeditor'; + my $lockingkey = 'paste'."\0".'locked_num'; + my %lockhash = &Apache::lonnet::get($namespace,[$lockingkey], + $domain,$username); + if (exists($lockhash{$lockingkey})) { + my $delresult = &Apache::lonnet::del($namespace,[$lockingkey],$domain,$username); + unless ($delresult eq 'ok') { + &Apache::lonnet::logthis("Failed to delete paste buffer locking key in $namespace for ".$username.":".$domain." Result was: $delresult"); + } + } } # Give them a new cookie my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'} @@ -15229,11 +16023,18 @@ cloneruname - optional username of new c clonerudom - optional domain of new course owner -domcloner - Optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, +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). +cc_clone - escaped comma separated list of courses for which course cloner has active CC role + (and so can clone automatically) + +reqcrsdom - domain of new course, where search_courses is used to identify potential courses to clone + +reqinstcode - institutional code of new course, where search_courses is used to identify potential + courses to clone Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type. @@ -15244,7 +16045,8 @@ Side Effects: None sub search_courses { - my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles) = @_; + my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles, + $cc_clone,$reqcrsdom,$reqinstcode) = @_; my (%courses,%showcourses,$cloner); if (($filter->{'ownerfilter'} ne '') || ($filter->{'ownerdomfilter'} ne '')) { @@ -15292,10 +16094,10 @@ sub search_courses { $filter->{'combownerfilter'}, $filter->{'coursefilter'}, undef,undef,$type,$regexpok,undef,undef, - undef,undef,$cloner,$env{'form.cc_clone'}, + undef,undef,$cloner,$cc_clone, $filter->{'cloneableonly'}, $createdbefore,$createdafter,undef, - $domcloner); + $domcloner,undef,$reqcrsdom,$reqinstcode); if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) { my $ccrole; if ($type eq 'Community') { @@ -15333,8 +16135,206 @@ sub search_courses { =back +=head1 Routines for version requirements for current course. + +=over 4 + +=item * &check_release_required() + +Compares required LON-CAPA version with version on server, and +if required version is newer looks for a server with the required version. + +Looks first at servers in user's owen domain; if none suitable, looks at +servers in course's domain are permitted to host sessions for user's domain. + +Inputs: + +$loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp) + +$courseid - Course ID of current course + +$rolecode - User's current role in course (for switchserver query string). + +$required - LON-CAPA version needed by course (format: Major.Minor). + + +Returns: + +$switchserver - query string tp append to /adm/switchserver call (if + current server's LON-CAPA version is too old. + +$warning - Message is displayed if no suitable server could be found. + +=cut + +sub check_release_required { + my ($loncaparev,$courseid,$rolecode,$required) = @_; + my ($switchserver,$warning); + if ($required ne '') { + my ($reqdmajor,$reqdminor) = ($required =~ /^(\d+)\.(\d+)$/); + my ($major,$minor) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); + if ($reqdmajor ne '' && $reqdminor ne '') { + my $otherserver; + if (($major eq '' && $minor eq '') || + (($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)))) { + my ($userdomserver) = &Apache::lonnet::choose_server($env{'user.domain'},undef,$required,1); + my $switchlcrev = + &Apache::lonnet::get_server_loncaparev($env{'user.domain'}, + $userdomserver); + my ($swmajor,$swminor) = ($switchlcrev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); + if (($swmajor eq '' && $swminor eq '') || ($reqdmajor > $swmajor) || + (($reqdmajor == $swmajor) && ($reqdminor > $swminor))) { + my $cdom = $env{'course.'.$courseid.'.domain'}; + if ($cdom ne $env{'user.domain'}) { + my ($coursedomserver,$coursehostname) = &Apache::lonnet::choose_server($cdom,undef,$required,1); + my $serverhomeID = &Apache::lonnet::get_server_homeID($coursehostname); + my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID); + my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom); + my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'}); + my $remoterev = &Apache::lonnet::get_server_loncaparev($serverhomedom,$coursedomserver); + my $canhost = + &Apache::lonnet::can_host_session($env{'user.domain'}, + $coursedomserver, + $remoterev, + $udomdefaults{'remotesessions'}, + $defdomdefaults{'hostedsessions'}); + + if ($canhost) { + $otherserver = $coursedomserver; + } else { + $warning = &mt('Requires LON-CAPA version [_1].',$env{'course.'.$courseid.'.internal.releaserequired'}).'
'. &mt("No suitable server could be found amongst servers in either your own domain or in the course's domain."); + } + } else { + $warning = &mt('Requires LON-CAPA version [_1].',$env{'course.'.$courseid.'.internal.releaserequired'}).'
'.&mt("No suitable server could be found amongst servers in your own domain (which is also the course's domain)."); + } + } else { + $otherserver = $userdomserver; + } + } + if ($otherserver ne '') { + $switchserver = 'otherserver='.$otherserver.'&role='.$rolecode; + } + } + } + return ($switchserver,$warning); +} + +=pod + +=item * &check_release_result() + +Inputs: + +$switchwarning - Warning message if no suitable server found to host session. + +$switchserver - query string to append to /adm/switchserver containing lonHostID + and current role. + +Returns: HTML to display with information about requirement to switch server. + Either displaying warning with link to Roles/Courses screen or + display link to switchserver. + +=cut + +sub check_release_result { + my ($switchwarning,$switchserver) = @_; + my $output = &start_page('Selected course unavailable on this server'). + '

'; + if ($switchwarning) { + $output .= $switchwarning.'
'; + if (&show_course()) { + $output .= &mt('Display courses'); + } else { + $output .= &mt('Display roles'); + } + $output .= ''; + } elsif ($switchserver) { + $output .= &mt('This course requires a newer version of LON-CAPA than is installed on this server.'). + '
'. + ''. + &mt('Switch Server'). + ''; + } + $output .= '

'.&end_page(); + return $output; +} + +=pod + +=item * &needs_coursereinit() + +Determine if course contents stored for user's session needs to be +refreshed, because content has changed since "Big Hash" last tied. + +Check for change is made if time last checked is more than 10 minutes ago +(by default). + +Inputs: + +$loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp) + +$interval (optional) - Time which may elapse (in s) between last check for content + change in current course. (default: 600 s). + +Returns: an array; first element is: + +=over 4 + +'switch' - if content updates mean user's session + needs to be switched to a server running a newer LON-CAPA version + +'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded) + on current server hosting user's session + +'' - if no action required. + +=back + +If first item element is 'switch': + +second item is $switchwarning - Warning message if no suitable server found to host session. + +third item is $switchserver - query string to append to /adm/switchserver containing lonHostID + and current role. + +otherwise: no other elements returned. + +=back + =cut +sub needs_coursereinit { + my ($loncaparev,$interval) = @_; + return() unless ($env{'request.course.id'} && $env{'request.course.tied'}); + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $now = time; + if ($interval eq '') { + $interval = 600; + } + if (($now-$env{'request.course.timechecked'})>$interval) { + my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum); + &Apache::lonnet::appenv({'request.course.timechecked'=>$now}); + if ($lastchange > $env{'request.course.tied'}) { + my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired'); + if ($curr_reqd_hash{'internal.releaserequired'} ne '') { + my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'}; + if ($curr_reqd_hash{'internal.releaserequired'} ne $required) { + &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' => + $curr_reqd_hash{'internal.releaserequired'}}); + my ($switchserver,$switchwarning) = + &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'}, + $curr_reqd_hash{'internal.releaserequired'}); + if ($switchwarning ne '' || $switchserver ne '') { + return ('switch',$switchwarning,$switchserver); + } + } + } + return ('update'); + } + } + return (); +} sub update_content_constraints { my ($cdom,$cnum,$chome,$cid) = @_; @@ -15342,7 +16342,7 @@ sub update_content_constraints { my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'}); my %checkresponsetypes; foreach my $key (keys(%Apache::lonnet::needsrelease)) { - my ($item,$name,$value) = split(/:/,$key); + my ($item,$name,$value,$valmatch) = split(/:/,$key); if ($item eq 'resourcetag') { if ($name eq 'responsetype') { $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key} @@ -15655,7 +16655,7 @@ sub create_recaptcha { my $captcha = Captcha::reCAPTCHA->new; return $captcha->get_options_setter({theme => 'white'})."\n". $captcha->get_html($pubkey,undef,$use_ssl). - &mt('If either word is hard to read, [_1] will replace them.', + &mt('If the text is hard to read, [_1] will replace them.', 'reCAPTCHA refresh'). '

'; } @@ -15766,11 +16766,19 @@ sub des_decrypt { } 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)) ); + my $plaintext=''; + my $cypherlength = length($cyphertext); + my $numchunks = int($cypherlength/32); + for (my $j=0; $j<$numchunks; $j++) { + my $start = $j*32; + my $cypherblock = substr($cyphertext,$start,32); + my $chunk = + $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,0,16)))); + $chunk .= + $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,16,16)))); + $chunk=substr($chunk,1,ord(substr($chunk,0,1)) ); + $plaintext .= $chunk; + } return $plaintext; } 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.