--- loncom/interface/loncommon.pm 2020/10/01 12:34:08 1.1075.2.141.2.9
+++ loncom/interface/loncommon.pm 2023/10/06 13:40:53 1.1075.2.161.2.20
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1075.2.141.2.9 2020/10/01 12:34:08 raeburn Exp $
+# $Id: loncommon.pm,v 1.1075.2.161.2.20 2023/10/06 13:40:53 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -61,7 +61,7 @@ use POSIX qw(strftime mktime);
use Apache::lonmenu();
use Apache::lonenc();
use Apache::lonlocal;
-use Apache::lonnet();
+use Apache::lonnavmaps();
use HTML::Entities;
use Apache::lonhtmlcommon();
use Apache::loncoursedata();
@@ -71,6 +71,7 @@ use Apache::lonuserutils();
use Apache::lonuserstate();
use Apache::courseclassifier();
use LONCAPA qw(:DEFAULT :match);
+use LONCAPA::map();
use HTTP::Request;
use DateTime::TimeZone;
use DateTime::Locale;
@@ -430,7 +431,7 @@ sub studentbrowser_javascript {
+ENDJS
+ }
$endbodytag=
- "
".
+ "$endbodyjs
".
&mt('Continue').''.
$endbodytag;
}
}
+ if ((ref($args) eq 'HASH') && ($args->{'dashjs'})) {
+ $endbodytag = &Apache::lonhtmlcommon::dash_to_minus_js().$endbodytag;
+ }
return $endbodytag;
}
@@ -7150,6 +7705,11 @@ fieldset {
/* overflow: hidden; */
}
+fieldset#LC_selectuser {
+ margin: 0;
+ padding: 0;
+}
+
article.geogebraweb div {
margin: 0;
}
@@ -7693,6 +8253,10 @@ a#LC_content_toolbar_edittoplevel {
background-image:url(/res/adm/pages/edittoplevel.gif);
}
+a#LC_content_toolbar_printout {
+ background-image:url(/res/adm/pages/printout.gif);
+}
+
ul#LC_toolbar li a:hover {
background-position: bottom center;
}
@@ -7810,6 +8374,18 @@ ul.LC_funclist li {
cursor:pointer;
}
+.LCisDisabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+a[aria-disabled="true"] {
+ color: currentColor;
+ display: inline-block; /* For IE11/ MS Edge bug */
+ pointer-events: none;
+ text-decoration: none;
+}
+
pre.LC_wordwrap {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
@@ -7892,7 +8468,13 @@ Inputs: $title - optional title for the
3- whether the side effect should occur
(side effect of setting
$env{'internal.head.redirect'} to the url
- redirected too)
+ redirected to)
+ 4- whether the redirect target should be
+ the opener of the current (pop-up)
+ window (side effect of setting
+ $env{'internal.head.to_opener'} to
+ 1, if true.
+ 5- whether encrypt check should be skipped
domain -> force to color decorate a page for a specific
domain
function -> force usage of a specific rolish color scheme
@@ -7955,15 +8537,45 @@ sub headtag {
}
}
if (ref($args->{'redirect'})) {
- my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
- $url = &Apache::lonenc::check_encrypt($url);
+ my ($time,$url,$inhibit_continue,$to_opener,$skip_enc_check) = @{$args->{'redirect'}};
+ if (!$skip_enc_check) {
+ $url = &Apache::lonenc::check_encrypt($url);
+ }
if (!$inhibit_continue) {
$env{'internal.head.redirect'} = $url;
}
- $result.=<
+ADDMETA
+ if ($to_opener) {
+ $env{'internal.head.to_opener'} = 1;
+ my $dest = &js_escape($url);
+ my $timeout = int($time * 1000);
+ $result .=<<"ENDJS";
+
+ENDJS
+ } else {
+ $result.=<<"ADDMETA";
ADDMETA
+ }
} else {
unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
my $requrl = $env{'request.uri'};
@@ -7978,10 +8590,17 @@ ADDMETA
unless (&Apache::lonnet::allowed('mau',$dom_in_use)) {
my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use);
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
- my $offload;
+ my ($offload,$offloadoth);
if (ref($domdefs{'offloadnow'}) eq 'HASH') {
if ($domdefs{'offloadnow'}{$lonhost}) {
$offload = 1;
+ if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) &&
+ (!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) {
+ unless (&Apache::lonnet::shared_institution($env{'user.domain'})) {
+ $offloadoth = 1;
+ $dom_in_use = $env{'user.domain'};
+ }
+ }
}
}
unless ($offload) {
@@ -7991,6 +8610,7 @@ ADDMETA
(!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) {
unless (&Apache::lonnet::shared_institution($env{'user.domain'})) {
$offload = 1;
+ $offloadoth = 1;
$dom_in_use = $env{'user.domain'};
}
}
@@ -7998,7 +8618,13 @@ ADDMETA
}
}
if ($offload) {
- my $newserver = &Apache::lonnet::spareserver(30000,undef,1,$dom_in_use);
+ my $newserver = &Apache::lonnet::spareserver(undef,30000,undef,1,$dom_in_use);
+ if (($newserver eq '') && ($offloadoth)) {
+ my @domains = &Apache::lonnet::current_machine_domains();
+ if (($dom_in_use ne '') && (!grep(/^\Q$dom_in_use\E$/,@domains))) {
+ ($newserver) = &Apache::lonnet::choose_server($dom_in_use);
+ }
+ }
if (($newserver) && ($newserver ne $lonhost)) {
my $numsec = 5;
my $timeout = $numsec * 1000;
@@ -8012,7 +8638,7 @@ ADDMETA
}
if ($locknum) {
my @lockinfo = sort(values(%locks));
- $msg = &mt('Once the following tasks are complete: ')."\n".
+ $msg = &mt('Once the following tasks are complete:')." \n".
join(", ",sort(values(%locks)))."\n";
if (&show_course()) {
$msg .= &mt('your session will be transferred to a different server, after you click "Courses".');
@@ -8174,7 +8800,8 @@ 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,undef,1);
+ my $clientip = &Apache::lonnet::get_requestor_ip();
+ my $blocked = &blocking_status('printout',$clientip,$cnum,$cdom,undef,1);
if ($blocked) {
my $checkrole = "cm./$cdom/$cnum";
if ($env{'request.course.sec'} ne '') {
@@ -8295,6 +8922,10 @@ $args - additional optional args support
will contain https:// if server uses
https (as per hosts.tab), but request is for http
hostname -> hostname, originally from $r->hostname(), (optional).
+ links_disabled -> Links in primary and secondary menus are disabled
+ (Can enable them once page has loaded - see lonroles.pm
+ for an example).
+ links_target -> Target for links, e.g., _parent (optional).
=back
@@ -8307,12 +8938,83 @@ sub start_page {
#&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
$env{'internal.start_page'}++;
- my ($result,@advtools);
+ my ($result,@advtools,$ltiscope,$ltiuri,%ltimenu,$menucoll,%menu);
if (! exists($args->{'skip_phases'}{'head'}) ) {
$result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
}
-
+
+ if (($env{'request.course.id'}) && ($env{'request.lti.login'})) {
+ if ($env{'course.'.$env{'request.course.id'}.'.lti.override'}) {
+ unless ($env{'course.'.$env{'request.course.id'}.'.lti.topmenu'}) {
+ $args->{'no_primary_menu'} = 1;
+ }
+ unless ($env{'course.'.$env{'request.course.id'}.'.lti.inlinemenu'}) {
+ $args->{'no_inline_menu'} = 1;
+ }
+ if ($env{'course.'.$env{'request.course.id'}.'.lti.lcmenu'}) {
+ map { $ltimenu{$_} = 1; } split(/,/,$env{'course.'.$env{'request.course.id'}.'.lti.lcmenu'});
+ }
+ } else {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider');
+ if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') {
+ unless ($lti{$env{'request.lti.login'}}{'topmenu'}) {
+ $args->{'no_primary_menu'} = 1;
+ }
+ unless ($lti{$env{'request.lti.login'}}{'inlinemenu'}) {
+ $args->{'no_inline_menu'} = 1;
+ }
+ if (ref($lti{$env{'request.lti.login'}}{'lcmenu'}) eq 'ARRAY') {
+ map { $ltimenu{$_} = 1; } @{$lti{$env{'request.lti.login'}}{'lcmenu'}};
+ }
+ }
+ }
+ ($ltiscope,$ltiuri) = &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'},
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'});
+ } elsif ($env{'request.course.id'}) {
+ my $expiretime=600;
+ if ((time-$env{'course.'.$env{'request.course.id'}.'.last_cache'}) > $expiretime) {
+ &Apache::lonnet::coursedescription($env{'request.course.id'},{'freshen_cache' => 1});
+ }
+ my ($deeplinkmenu,$menuref);
+ ($menucoll,$deeplinkmenu,$menuref) = &menucoll_in_effect();
+ if ($menucoll) {
+ if (ref($menuref) eq 'HASH') {
+ %menu = %{$menuref};
+ }
+ if ($menu{'top'} eq 'n') {
+ $args->{'no_primary_menu'} = 1;
+ }
+ if ($menu{'inline'} eq 'n') {
+ unless (&Apache::lonnet::allowed('opa')) {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $crstype = &course_type();
+ my $now = time;
+ my $ccrole;
+ if ($crstype eq 'Community') {
+ $ccrole = 'co';
+ } else {
+ $ccrole = 'cc';
+ }
+ if ($env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum}) {
+ my ($start,$end) = split(/\./,$env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum});
+ if ((($start) && ($start<0)) ||
+ (($end) && ($end<$now)) ||
+ (($start) && ($now<$start))) {
+ $args->{'no_inline_menu'} = 1;
+ }
+ } else {
+ $args->{'no_inline_menu'} = 1;
+ }
+ }
+ }
+ }
+ }
+
+ my $showncrumbs;
if (! exists($args->{'skip_phases'}{'body'}) ) {
if ($args->{'frameset'}) {
my $attr_string = &make_attr_string($args->{'force_register'},
@@ -8325,7 +9027,8 @@ sub start_page {
$args->{'only_body'}, $args->{'domain'},
$args->{'force_register'}, $args->{'no_nav_bar'},
$args->{'bgcolor'}, $args->{'no_inline_link'},
- $args, \@advtools);
+ $args, \@advtools,
+ $ltiscope,$ltiuri,\%ltimenu,$menucoll,\%menu,\$showncrumbs);
}
}
@@ -8347,6 +9050,7 @@ sub start_page {
#Breadcrumbs
if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
+ unless ($showncrumbs) {
&Apache::lonhtmlcommon::clear_breadcrumbs();
#if any br links exists, add them to the breadcrumbs
if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
@@ -8360,17 +9064,26 @@ sub start_page {
}
my $menulink;
# if arg: bread_crumbs_nomenu is true pass 0 as $menulink item.
- if (exists($args->{'bread_crumbs_nomenu'})) {
+ if ((exists($args->{'bread_crumbs_nomenu'})) ||
+ ($ltiscope eq 'map') || ($ltiscope eq 'resource')) {
$menulink = 0;
} else {
undef($menulink);
}
+ my $linkprotout;
+ if ($env{'request.deeplink.login'}) {
+ my $linkprotout = &Apache::lonmenu::linkprot_exit();
+ if ($linkprotout) {
+ &Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout);
+ }
+ }
#if bread_crumbs_component exists show it as headline else show only the breadcrumbs
if(exists($args->{'bread_crumbs_component'})){
$result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'},'',$menulink);
- }else{
+ } else {
$result .= &Apache::lonhtmlcommon::breadcrumbs('','',$menulink);
}
+ }
} elsif (($env{'environment.remote'} eq 'on') &&
($env{'form.inhibitmenu'} ne 'yes') &&
($env{'request.noversionuri'} =~ m{^/res/}) &&
@@ -8412,6 +9125,147 @@ sub end_page {
return $result;
}
+sub menucoll_in_effect {
+ my ($menucoll,$deeplinkmenu,%menu);
+ if ($env{'request.course.id'}) {
+ $menucoll = $env{'course.'.$env{'request.course.id'}.'.menudefault'};
+ if ($env{'request.deeplink.login'}) {
+ my ($deeplink_symb,$deeplink,$check_login_symb);
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ if ($env{'request.noversionuri'} =~ m{^/(res|uploaded)/}) {
+ if ($env{'request.noversionuri'} =~ /\.(page|sequence)$/) {
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (ref($navmap)) {
+ $deeplink = $navmap->get_mapparam(undef,
+ &Apache::lonnet::declutter($env{'request.noversionuri'}),
+ '0.deeplink');
+ } else {
+ $check_login_symb = 1;
+ }
+ } else {
+ my $symb=&Apache::lonnet::symbread();
+ if ($symb) {
+ $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$symb);
+ } else {
+ $check_login_symb = 1;
+ }
+ }
+ } else {
+ $check_login_symb = 1;
+ }
+ if ($check_login_symb) {
+ $deeplink_symb = &deeplink_login_symb($cnum,$cdom);
+ if ($deeplink_symb =~ /\.(page|sequence)$/) {
+ my $mapname = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[2]);
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (ref($navmap)) {
+ $deeplink = $navmap->get_mapparam(undef,$mapname,'0.deeplink');
+ }
+ } else {
+ $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$deeplink_symb);
+ }
+ }
+ if ($deeplink ne '') {
+ my ($state,$others,$listed,$scope,$protect,$display,$target) = split(/,/,$deeplink);
+ if ($display =~ /^\d+$/) {
+ $deeplinkmenu = 1;
+ $menucoll = $display;
+ }
+ }
+ }
+ if ($menucoll) {
+ %menu = &page_menu($env{'course.'.$env{'request.course.id'}.'.menucollections'},$menucoll);
+ }
+ }
+ return ($menucoll,$deeplinkmenu,\%menu);
+}
+
+sub deeplink_login_symb {
+ my ($cnum,$cdom) = @_;
+ my $login_symb;
+ if ($env{'request.deeplink.login'}) {
+ $login_symb = &symb_from_tinyurl($env{'request.deeplink.login'},$cnum,$cdom);
+ }
+ return $login_symb;
+}
+
+sub symb_from_tinyurl {
+ my ($url,$cnum,$cdom) = @_;
+ if ($url =~ m{^\Q/tiny/$cdom/\E(\w+)$}) {
+ my $key = $1;
+ my ($tinyurl,$login);
+ my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key);
+ if (defined($cached)) {
+ $tinyurl = $result;
+ } else {
+ my $configuname = &Apache::lonnet::get_domainconfiguser($cdom);
+ my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname);
+ if ($currtiny{$key} ne '') {
+ $tinyurl = $currtiny{$key};
+ &Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600);
+ }
+ }
+ if ($tinyurl ne '') {
+ my ($cnumreq,$symb) = split(/\&/,$tinyurl);
+ if (wantarray) {
+ return ($cnumreq,$symb);
+ } elsif ($cnumreq eq $cnum) {
+ return $symb;
+ }
+ }
+ }
+ if (wantarray) {
+ return ();
+ } else {
+ return;
+ }
+}
+
+sub usable_exttools {
+ my %tooltypes;
+ if ($env{'request.course.id'}) {
+ if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'}) {
+ if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'both') {
+ %tooltypes = (
+ crs => 1,
+ dom => 1,
+ );
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'crs') {
+ $tooltypes{'crs'} = 1;
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'dom') {
+ $tooltypes{'dom'} = 1;
+ }
+ } else {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $crstype = lc($env{'course.'.$env{'request.course.id'}.'.type'});
+ if ($crstype eq '') {
+ $crstype = 'course';
+ }
+ if ($crstype eq 'course') {
+ if ($env{'course.'.$env{'request.course.id'}.'internal.coursecode'}) {
+ $crstype = 'official';
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.textbook'}) {
+ $crstype = 'textbook';
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.lti'}) {
+ $crstype = 'lti';
+ } else {
+ $crstype = 'unofficial';
+ }
+ }
+ my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
+ if ($domdefaults{$crstype.'domexttool'}) {
+ $tooltypes{'dom'} = 1;
+ }
+ if ($domdefaults{$crstype.'exttool'}) {
+ $tooltypes{'crs'} = 1;
+ }
+ }
+ }
+ return %tooltypes;
+}
+
sub wishlist_window {
return(<<'ENDWISHLIST');
@@ -8519,7 +9382,7 @@ ENDADHOC
}
sub modal_adhoc_inner {
- my ($funcname,$width,$height,$content)=@_;
+ my ($funcname,$width,$height,$content,$possmathjax)=@_;
my $innerwidth=$width-20;
$content=&js_ready(
&start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
@@ -8528,12 +9391,12 @@ sub modal_adhoc_inner {
&end_scrollbox().
&end_page()
);
- return &modal_adhoc_script($funcname,$width,$height,$content);
+ return &modal_adhoc_script($funcname,$width,$height,$content,$possmathjax);
}
sub modal_adhoc_window {
- my ($funcname,$width,$height,$content,$linktext)=@_;
- return &modal_adhoc_inner($funcname,$width,$height,$content).
+ my ($funcname,$width,$height,$content,$linktext,$possmathjax)=@_;
+ return &modal_adhoc_inner($funcname,$width,$height,$content,$possmathjax).
"".$linktext."";
}
@@ -8894,14 +9757,21 @@ function expand_div(caller) {
sub simple_error_page {
my ($r,$title,$msg,$args) = @_;
+ my %displayargs;
if (ref($args) eq 'HASH') {
if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }
+ if ($args->{'only_body'}) {
+ $displayargs{'only_body'} = 1;
+ }
+ if ($args->{'no_nav_bar'}) {
+ $displayargs{'no_nav_bar'} = 1;
+ }
} else {
$msg = &mt($msg);
}
my $page =
- &Apache::loncommon::start_page($title).
+ &Apache::loncommon::start_page($title,'',\%displayargs).
''.$msg.'
'.
&Apache::loncommon::end_page();
if (ref($r)) {
@@ -10389,11 +11259,15 @@ sub sorted_inst_types {
}
sub get_institutional_codes {
- my ($settings,$allcourses,$LC_code) = @_;
+ my ($cdom,$crs,$settings,$allcourses,$LC_code) = @_;
# Get complete list of course sections to update
my @currsections = ();
my @currxlists = ();
+ my (%unclutteredsec,%unclutteredlcsec);
my $coursecode = $$settings{'internal.coursecode'};
+ my $crskey = $crs.':'.$coursecode;
+ @{$unclutteredsec{$crskey}} = ();
+ @{$unclutteredlcsec{$crskey}} = ();
if ($$settings{'internal.sectionnums'} ne '') {
@currsections = split(/,/,$$settings{'internal.sectionnums'});
@@ -10404,8 +11278,8 @@ sub get_institutional_codes {
}
if (@currxlists > 0) {
- foreach (@currxlists) {
- if (m/^([^:]+):(\w*)$/) {
+ foreach my $xl (@currxlists) {
+ if ($xl =~ /^([^:]+):(\w*)$/) {
unless (grep/^$1$/,@{$allcourses}) {
push(@{$allcourses},$1);
$$LC_code{$1} = $2;
@@ -10413,15 +11287,28 @@ sub get_institutional_codes {
}
}
}
-
+
if (@currsections > 0) {
- foreach (@currsections) {
- if (m/^(\w+):(\w*)$/) {
- my $sec = $coursecode.$1;
+ foreach my $sec (@currsections) {
+ if ($sec =~ m/^(\w+):(\w*)$/ ) {
+ my $instsec = $1;
my $lc_sec = $2;
- unless (grep/^$sec$/,@{$allcourses}) {
+ unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) {
+ push(@{$unclutteredsec{$crskey}},$instsec);
+ push(@{$unclutteredlcsec{$crskey}},$lc_sec);
+ }
+ }
+ }
+ }
+
+ if (@{$unclutteredsec{$crskey}} > 0) {
+ my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',\%unclutteredsec);
+ if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) {
+ for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) {
+ my $sec = $coursecode.$formattedsec{$crskey}[$i];
+ unless (grep/^\Q$sec\E$/,@{$allcourses}) {
push(@{$allcourses},$sec);
- $$LC_code{$sec} = $lc_sec;
+ $$LC_code{$sec} = $unclutteredlcsec{$crskey}[$i];
}
}
}
@@ -12952,7 +13839,9 @@ sub process_extracted_files {
my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
$docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
$title;
- if (($outer !~ /\D/) && ($mapinner{$outer} !~ /\D/) && ($newidx !~ /\D/)) {
+ if (($outer !~ /\D/) &&
+ (($mapinner{$outer} eq 'default') || ($mapinner{$outer} !~ /\D/)) &&
+ ($newidx !~ /\D/)) {
if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
}
@@ -14713,7 +15602,7 @@ sub recurse_categories {
for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
my $name = $cats->[$depth]{$category}[$k];
my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
- my $trailstr = join(' -> ',(@{$parents},$category));
+ my $trailstr = join(' » ',(@{$parents},$category));
if ($allitems->{$item} eq '') {
push(@{$trails},$trailstr);
$allitems->{$item} = scalar(@{$trails})-1;
@@ -14991,7 +15880,7 @@ sub commit_studentrole {
}
$oldsecurl = $uurl;
$expire_role_result =
- &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
+ &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','','',$context);
if ($env{'request.course.sec'} ne '') {
if ($expire_role_result eq 'refused') {
my @roles = ('st');
@@ -15249,7 +16138,7 @@ sub check_clone {
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 => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}],
}));
- }
+ }
}
}
}
@@ -15325,7 +16214,7 @@ sub construct_course {
#
# Do the cloning
-#
+#
my @clonemsg;
if ($can_clone && $cloneid) {
push(@clonemsg,
@@ -15336,7 +16225,7 @@ sub construct_course {
my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
# Copy all files
my @info =
- &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},
+ &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},
$args->{'dateshift'},$args->{'crscode'},
$args->{'ccuname'}.':'.$args->{'ccdomain'},
$args->{'tinyurls'});
@@ -15367,8 +16256,7 @@ sub construct_course {
'plc.users.denied',
'hidefromcat',
'checkforpriv',
- 'categories',
- 'internal.uniquecode'],
+ 'categories'],
$$crsudom,$$crsunum);
if ($args->{'textbook'}) {
$cenv{'internal.textbook'} = $args->{'textbook'};
@@ -15383,6 +16271,9 @@ sub construct_course {
if ($args->{'crstype'}) {
$cenv{'type'}=$args->{'crstype'};
}
+ if ($args->{'lti'}) {
+ $cenv{'internal.lti'}=$args->{'lti'};
+ }
if ($args->{'crsid'}) {
$cenv{'courseid'}=$args->{'crsid'};
}
@@ -15404,6 +16295,7 @@ sub construct_course {
$cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};
}
my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
+ my @oklcsecs = (); # Used to accumulate LON-CAPA sections for validated institutional sections.
if ($args->{'crssections'}) {
$cenv{'internal.sectionnums'} = '';
if ($args->{'crssections'} =~ m/,/) {
@@ -15417,7 +16309,11 @@ sub construct_course {
my $class = $args->{'crscode'}.$sec;
my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
$cenv{'internal.sectionnums'} .= $item.',';
- unless ($addcheck eq 'ok') {
+ if ($addcheck eq 'ok') {
+ unless (grep(/^\Q$gp\E$/,@oklcsecs)) {
+ push(@oklcsecs,$gp);
+ }
+ } else {
push(@badclasses,$class);
}
}
@@ -15445,7 +16341,11 @@ sub construct_course {
my ($xl,$gp) = split/:/,$item;
my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
$cenv{'internal.crosslistings'} .= $item.',';
- unless ($addcheck eq 'ok') {
+ if ($addcheck eq 'ok') {
+ unless (grep(/^\Q$gp\E$/,@oklcsecs)) {
+ push(@oklcsecs,$gp);
+ }
+ } else {
push(@badclasses,$xl);
}
}
@@ -15508,6 +16408,36 @@ sub construct_course {
if ($args->{'no_end_date'}) {
$args->{'endaccess'} = 0;
}
+# If an official course with institutional sections is created by cloning
+# an existing course, section-specific hiding of course totals in student's
+# view of grades as copied from cloned course, will be checked for valid
+# sections.
+ if (($can_clone && $cloneid) &&
+ ($cenv{'internal.coursecode'} ne '') &&
+ ($cenv{'grading'} eq 'standard') &&
+ ($cenv{'hidetotals'} ne '') &&
+ ($cenv{'hidetotals'} ne 'all')) {
+ my @hidesecs;
+ my $deletehidetotals;
+ if (@oklcsecs) {
+ foreach my $sec (split(/,/,$cenv{'hidetotals'})) {
+ if (grep(/^\Q$sec$/,@oklcsecs)) {
+ push(@hidesecs,$sec);
+ }
+ }
+ if (@hidesecs) {
+ $cenv{'hidetotals'} = join(',',@hidesecs);
+ } else {
+ $deletehidetotals = 1;
+ }
+ } else {
+ $deletehidetotals = 1;
+ }
+ if ($deletehidetotals) {
+ delete($cenv{'hidetotals'});
+ &Apache::lonnet::del('environment',['hidetotals'],$$crsudom,$$crsunum);
+ }
+ }
$cenv{'internal.autostart'}=$args->{'enrollstart'};
$cenv{'internal.autoend'}=$args->{'enrollend'};
$cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
@@ -15626,7 +16556,6 @@ sub construct_course {
#
unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
|| ($cloneid)) {
- use LONCAPA::map;
$outcome .= &mt('Setting first resource').': ';
my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
@@ -15733,12 +16662,13 @@ sub group_term {
}
sub course_types {
- my @types = ('official','unofficial','community','textbook');
+ my @types = ('official','unofficial','community','textbook','lti');
my %typename = (
official => 'Official course',
unofficial => 'Unofficial course',
community => 'Community',
textbook => 'Textbook course',
+ lti => 'LTI provider',
);
return (\@types,\%typename);
}
@@ -15818,6 +16748,24 @@ sub compare_arrays {
return @difference;
}
+sub lon_status_items {
+ my %defaults = (
+ E => 100,
+ W => 4,
+ N => 1,
+ U => 5,
+ threshold => 200,
+ sysmail => 2500,
+ );
+ my %names = (
+ E => 'Errors',
+ W => 'Warnings',
+ N => 'Notices',
+ U => 'Unsent',
+ );
+ return (\%defaults,\%names);
+}
+
# -------------------------------------------------------- Initialize user login
sub init_user_environment {
my ($r, $username, $domain, $authhost, $form, $args) = @_;
@@ -15920,6 +16868,7 @@ sub init_user_environment {
# --------------------------------------------------------- Write first profile
{
+ my $ip = &Apache::lonnet::get_requestor_ip();
my %initial_env =
("user.name" => $username,
"user.domain" => $domain,
@@ -15938,7 +16887,7 @@ sub init_user_environment {
"request.course.sec" => '',
"request.role" => 'cm',
"request.role.adv" => $env{'user.adv'},
- "request.host" => $ENV{'REMOTE_ADDR'},);
+ "request.host" => $ip,);
if ($form->{'localpath'}) {
$initial_env{"browser.localpath"} = $form->{'localpath'};
@@ -15970,13 +16919,13 @@ sub init_user_environment {
my %is_adv = ( is_adv => $env{'user.adv'} );
my %domdef = &Apache::lonnet::get_domain_defaults($domain);
- foreach my $tool ('aboutme','blog','webdav','portfolio') {
+ foreach my $tool ('aboutme','blog','webdav','portfolio','timezone') {
$userenv{'availabletools.'.$tool} =
&Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
undef,\%userenv,\%domdef,\%is_adv);
}
- foreach my $crstype ('official','unofficial','community','textbook') {
+ foreach my $crstype ('official','unofficial','community','textbook','lti') {
$userenv{'canrequest.'.$crstype} =
&Apache::lonnet::usertools_access($username,$domain,$crstype,
'reload','requestcourses',
@@ -16799,27 +17748,51 @@ sub needs_coursereinit {
}
if (($now-$env{'request.course.timechecked'})>$interval) {
&Apache::lonnet::appenv({'request.course.timechecked'=>$now});
- my $blocked = &blocking_status('reinit',$cnum,$cdom,undef,1);
+ my $blocked = &blocking_status('reinit',undef,$cnum,$cdom,undef,1);
if ($blocked) {
return ();
}
- my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum);
- 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);
- }
+ my $update;
+ my $lastmainchange = &Apache::lonnet::get_coursechange($cdom,$cnum);
+ my $lastsuppchange = &Apache::lonnet::get_suppchange($cdom,$cnum);
+ if ($lastmainchange > $env{'request.course.tied'}) {
+ my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum);
+ if ($needswitch) {
+ return ('switch',$switchwarning,$switchserver);
+ }
+ $update = 'main';
+ }
+ if ($lastsuppchange > $env{'request.course.suppupdated'}) {
+ if ($update) {
+ $update = 'both';
+ } else {
+ my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum);
+ if ($needswitch) {
+ return ('switch',$switchwarning,$switchserver);
+ } else {
+ $update = 'supp';
}
}
- return ('update');
+ return ($update);
+ }
+ }
+ return ();
+}
+
+sub switch_for_update {
+ my ($loncaparev,$cdom,$cnum) = @_;
+ 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 ();
@@ -16902,8 +17875,10 @@ sub parse_supplemental_title {
my $name = &plainname($uname,$udom);
$name = &HTML::Entities::encode($name,'"<>&\'');
$renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
- $title=''.&Apache::lonlocal::locallocaltime($time).' '.
- $name.':
'.$foldertitle;
+ $title=''.&Apache::lonlocal::locallocaltime($time).' '.$name;
+ if ($foldertitle ne '') {
+ $title .= ':
'.$foldertitle;
+ }
}
if (wantarray) {
return ($title,$foldertitle,$renametitle);
@@ -16911,28 +17886,147 @@ sub parse_supplemental_title {
return $title;
}
+sub get_supplemental {
+ my ($cnum,$cdom,$ignorecache,$possdel)=@_;
+ my $hashid=$cnum.':'.$cdom;
+ my ($supplemental,$cached,$set_httprefs);
+ unless ($ignorecache) {
+ ($supplemental,$cached) = &Apache::lonnet::is_cached_new('supplemental',$hashid);
+ }
+ unless (defined($cached)) {
+ my $chome=&Apache::lonnet::homeserver($cnum,$cdom);
+ unless ($chome eq 'no_host') {
+ my @order = @LONCAPA::map::order;
+ my @resources = @LONCAPA::map::resources;
+ my @resparms = @LONCAPA::map::resparms;
+ my @zombies = @LONCAPA::map::zombies;
+ my ($errors,%ids,%hidden);
+ $errors =
+ &recurse_supplemental($cnum,$cdom,'supplemental.sequence',
+ $errors,$possdel,\%ids,\%hidden);
+ @LONCAPA::map::order = @order;
+ @LONCAPA::map::resources = @resources;
+ @LONCAPA::map::resparms = @resparms;
+ @LONCAPA::map::zombies = @zombies;
+ $set_httprefs = 1;
+ if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {
+ &Apache::lonnet::appenv({'request.course.suppupdated' => time});
+ }
+ $supplemental = {
+ ids => \%ids,
+ hidden => \%hidden,
+ };
+ &Apache::lonnet::do_cache_new('supplemental',$hashid,$supplemental,600);
+ }
+ }
+ return ($supplemental,$set_httprefs);
+}
+
sub recurse_supplemental {
- my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_;
- if ($suppmap) {
+ my ($cnum,$cdom,$suppmap,$errors,$possdel,$suppids,$hiddensupp,$hidden) = @_;
+ if (($suppmap) && (ref($suppids) eq 'HASH') && (ref($hiddensupp) eq 'HASH')) {
+ my $mapnum;
+ if ($suppmap eq 'supplemental.sequence') {
+ $mapnum = 0;
+ } else {
+ ($mapnum) = ($suppmap =~ /^supplemental_(\d+)\.sequence$/);
+ }
my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
if ($fatal) {
$errors ++;
} else {
- if ($#LONCAPA::map::resources > 0) {
- foreach my $res (@LONCAPA::map::resources) {
- my ($title,$src,$ext,$type,$status)=split(/\:/,$res);
+ my @order = @LONCAPA::map::order;
+ if (@order > 0) {
+ my @resources = @LONCAPA::map::resources;
+ my @resparms = @LONCAPA::map::resparms;
+ foreach my $idx (@order) {
+ my ($title,$src,$ext,$type,$status)=split(/\:/,$resources[$idx]);
if (($src ne '') && ($status eq 'res')) {
+ my $id = $mapnum.':'.$idx;
+ push(@{$suppids->{$src}},$id);
+ if (($hidden) || (&get_supp_parameter($resparms[$idx],'parameter_hiddenresource') =~ /^yes/i)) {
+ $hiddensupp->{$id} = 1;
+ }
if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
- ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors);
+ $errors = &recurse_supplemental($cnum,$cdom,$1,$errors,$possdel,$suppids,
+ $hiddensupp,$hiddensupp->{$id});
} else {
- $numfiles ++;
+ my $allowed;
+ if (($env{'request.role.adv'}) || (!$hiddensupp->{$id})) {
+ $allowed = 1;
+ } elsif ($possdel) {
+ foreach my $item (@{$suppids->{$src}}) {
+ next if ($item eq $id);
+ unless ($hiddensupp->{$item}) {
+ $allowed = 1;
+ last;
+ }
+ }
+ if ((!$allowed) && (exists($env{'httpref.'.$src}))) {
+ &Apache::lonnet::delenv('httpref.'.$src);
+ }
+ }
+ if ($allowed && (!exists($env{'httpref.'.$src}))) {
+ &Apache::lonnet::allowuploaded('/adm/coursedoc',$src);
+ }
}
}
}
}
}
}
- return ($numfiles,$errors);
+ return $errors;
+}
+
+sub set_supp_httprefs {
+ my ($cnum,$cdom,$supplemental,$possdel) = @_;
+ if (ref($supplemental) eq 'HASH') {
+ if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) {
+ foreach my $src (keys(%{$supplemental->{'ids'}})) {
+ next if ($src =~ /\.sequence$/);
+ if (ref($supplemental->{'ids'}->{$src}) eq 'ARRAY') {
+ my $allowed;
+ if ($env{'request.role.adv'}) {
+ $allowed = 1;
+ } else {
+ foreach my $id (@{$supplemental->{'ids'}->{$src}}) {
+ unless ($supplemental->{'hidden'}->{$id}) {
+ $allowed = 1;
+ last;
+ }
+ }
+ }
+ if (exists($env{'httpref.'.$src})) {
+ if ($possdel) {
+ unless ($allowed) {
+ &Apache::lonnet::delenv('httpref.'.$src);
+ }
+ }
+ } elsif ($allowed) {
+ &Apache::lonnet::allowuploaded('/adm/coursedoc',$src);
+ }
+ }
+ }
+ if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {
+ &Apache::lonnet::appenv({'request.course.suppupdated' => time});
+ }
+ }
+ }
+}
+
+sub get_supp_parameter {
+ my ($resparm,$name)=@_;
+ return if ($resparm eq '');
+ my $value=undef;
+ my $ptype=undef;
+ foreach (split('&&&',$resparm)) {
+ my ($thistype,$thisname,$thisvalue)=split('___',$_);
+ if ($thisname eq $name) {
+ $value=$thisvalue;
+ $ptype=$thistype;
+ }
+ }
+ return $value;
}
sub symb_to_docspath {
@@ -17005,6 +18099,67 @@ sub symb_to_docspath {
return $path;
}
+sub validate_folderpath {
+ my ($supplementalflag,$allowed,$coursenum,$coursedom) = @_;
+ if ($env{'form.folderpath'} ne '') {
+ my @items = split(/\&/,$env{'form.folderpath'});
+ my ($badpath,$changed,$got_supp,$supppath,%supphidden,%suppids);
+ for (my $i=0; $i<@items; $i++) {
+ my $odd = $i%2;
+ if (($odd) && (!$supplementalflag) && ($items[$i] !~ /^[^:]*:(|\d+):(|1):(|1):(|1):(|1)$/)) {
+ $badpath = 1;
+ } elsif ($odd && $supplementalflag) {
+ my $idx = $i-1;
+ if ($items[$i] =~ /^([^:]*)::(|1):::$/) {
+ my $esc_name = $1;
+ if ((!$allowed) || ($items[$idx] eq 'supplemental')) {
+ $supppath .= '&'.$esc_name;
+ $changed = 1;
+ } else {
+ $supppath .= '&'.$items[$i];
+ }
+ } elsif (($allowed) && ($items[$idx] ne 'supplemental')) {
+ $changed = 1;
+ my $is_hidden;
+ unless ($got_supp) {
+ my ($supplemental) = &get_supplemental($coursenum,$coursedom);
+ if (ref($supplemental) eq 'HASH') {
+ if (ref($supplemental->{'hidden'}) eq 'HASH') {
+ %supphidden = %{$supplemental->{'hidden'}};
+ }
+ if (ref($supplemental->{'ids'}) eq 'HASH') {
+ %suppids = %{$supplemental->{'ids'}};
+ }
+ }
+ $got_supp = 1;
+ }
+ if (ref($suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}) eq 'ARRAY') {
+ my $mapid = $suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}->[0];
+ if ($supphidden{$mapid}) {
+ $is_hidden = 1;
+ }
+ }
+ $supppath .= '&'.$items[$i].'::'.$is_hidden.':::';
+ } else {
+ $supppath .= '&'.$items[$i];
+ }
+ } elsif ((!$odd) && ($items[$i] !~ /^(default|supplemental)(|_\d+)$/)) {
+ $badpath = 1;
+ } elsif ($supplementalflag) {
+ $supppath .= '&'.$items[$i];
+ }
+ last if ($badpath);
+ }
+ if ($badpath) {
+ delete($env{'form.folderpath'});
+ } elsif ($changed && $supplementalflag) {
+ $supppath =~ s/^\&//;
+ $env{'form.folderpath'} = $supppath;
+ }
+ }
+ return;
+}
+
sub captcha_display {
my ($context,$lonhost,$defdom) = @_;
my ($output,$error);
@@ -17125,13 +18280,17 @@ sub create_captcha {
if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
$output = ''."\n".
+ ''.
&mt('Type in the letters/numbers shown below').' '.
- ''.
- '
'.
+ ''.
+ '
'.
'';
last;
}
}
+ if ($output eq '') {
+ &Apache::lonnet::logthis("Failed to create Captcha code after $tries attempts.");
+ }
return $output;
}
@@ -17170,7 +18329,8 @@ sub check_captcha {
sub create_recaptcha {
my ($pubkey,$version) = @_;
if ($version >= 2) {
- return '';
+ return ''.
+ '';
} else {
my $use_ssl;
if ($ENV{'SERVER_PORT'} == 443) {
@@ -17188,13 +18348,14 @@ sub create_recaptcha {
sub check_recaptcha {
my ($privkey,$version) = @_;
my $captcha_chk;
+ my $ip = &Apache::lonnet::get_requestor_ip();
if ($version >= 2) {
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
my %info = (
secret => $privkey,
response => $env{'form.g-recaptcha-response'},
- remoteip => $ENV{'REMOTE_ADDR'},
+ remoteip => $ip,
);
my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info);
if ($response->is_success) {
@@ -17210,7 +18371,7 @@ sub check_recaptcha {
my $captcha_result =
$captcha->check_answer(
$privkey,
- $ENV{'REMOTE_ADDR'},
+ $ip,
$env{'form.recaptcha_challenge_field'},
$env{'form.recaptcha_response_field'},
);
@@ -17262,11 +18423,14 @@ sub cleanup_html {
# $context is the calling context -- roles, grades, contents, menu or flip.
sub critical_redirect {
my ($interval,$context) = @_;
+ unless (($env{'user.domain'} ne '') && ($env{'user.name'} ne '')) {
+ return ();
+ }
if ((time-$env{'user.criticalcheck.time'})>$interval) {
if (($env{'request.course.id'}) && (($context eq 'flip') || ($context eq 'contents'))) {
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
- my $blocked = &blocking_status('alert',$cnum,$cdom,undef,1);
+ my $blocked = &blocking_status('alert',undef,$cnum,$cdom,undef,1);
if ($blocked) {
my $checkrole = "cm./$cdom/$cnum";
if ($env{'request.course.sec'} ne '') {
@@ -17283,7 +18447,7 @@ sub critical_redirect {
&Apache::lonnet::appenv({'user.criticalcheck.time'=>time});
my $redirecturl;
if ($what[0]) {
- if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
+ if (($what[0] ne 'con_lost') && ($what[0] ne 'no_such_host') && ($what[0]!~/^error\:/)) {
$redirecturl='/adm/email?critical=display';
my $url=&Apache::lonnet::absolute_url().$redirecturl;
return (1, $url);
@@ -17414,6 +18578,18 @@ sub make_short_symbs {
push(@errors,&mt('error: could not store unique six character URLs'));
}
}
+ my $dellockres = &Apache::lonnet::del_dom('tiny',["lock\0$now"],$cdom);
+ unless ($dellockres eq 'ok') {
+ push(@errors,&mt('error: could not release lockfile'));
+ }
+ } else {
+ push(@errors,&mt('error: could not obtain lockfile'));
+ }
+ if (keys(%courseonly)) {
+ my $result = &Apache::lonnet::newput('tiny',\%courseonly,$cdom,$cnum);
+ if ($result ne 'ok') {
+ push(@errors,&mt('error: could not update course look-up of short URLs'));
+ }
}
}
}
@@ -17636,6 +18812,37 @@ sub is_nonframeable {
return $uselink;
}
+sub page_menu {
+ my ($menucolls,$menunum) = @_;
+ my %menu;
+ foreach my $item (split(/;/,$menucolls)) {
+ my ($num,$value) = split(/\%/,$item);
+ if ($num eq $menunum) {
+ my @entries = split(/\&/,$value);
+ foreach my $entry (@entries) {
+ my ($name,$fields) = split(/=/,$entry);
+ if (($name eq 'top') || ($name eq 'inline') || ($name eq 'foot') || ($name eq 'main')) {
+ $menu{$name} = $fields;
+ } else {
+ my @shown;
+ if ($fields =~ /,/) {
+ @shown = split(/,/,$fields);
+ } else {
+ @shown = ($fields);
+ }
+ if (@shown) {
+ foreach my $field (@shown) {
+ next if ($field eq '');
+ $menu{$field} = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return %menu;
+}
+
1;
__END__;