--- loncom/interface/loncommon.pm 2024/03/29 00:45:24 1.1075.2.161.2.24 +++ loncom/interface/loncommon.pm 2014/05/16 18:32:51 1.1189 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1075.2.161.2.24 2024/03/29 00:45:24 raeburn Exp $ +# $Id: loncommon.pm,v 1.1189 2014/05/16 18:32:51 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::lonnavmaps(); +use Apache::lonnet(); use HTML::Entities; use Apache::lonhtmlcommon(); use Apache::loncoursedata(); @@ -71,21 +71,13 @@ 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; -use Encode(); +use DateTime::Locale::Catalog; +use Text::Aspell; use Authen::Captcha; use Captcha::reCAPTCHA; -use JSON::DWIW; -use LWP::UserAgent; use Crypt::DES; use DynaLoader; # for Crypt::DES version -use File::Copy(); -use File::Path(); -use String::CRC32(); -use Short::URL(); # ---------------------------------------------- Designs use vars qw(%defaultdesign); @@ -170,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; @@ -200,18 +193,19 @@ BEGIN { { my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}. '/language.tab'; - if ( open(my $fh,'<',$langtabfile) ) { + if ( open(my $fh,"<$langtabfile") ) { 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); @@ -221,7 +215,7 @@ BEGIN { { my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. '/copyright.tab'; - if ( open (my $fh,'<',$copyrightfile) ) { + if ( open (my $fh,"<$copyrightfile") ) { while (my $line = <$fh>) { next if ($line=~/^\#/); chomp($line); @@ -235,7 +229,7 @@ BEGIN { { my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. '/source_copyright.tab'; - if ( open (my $fh,'<',$sourcecopyrightfile) ) { + if ( open (my $fh,"<$sourcecopyrightfile") ) { while (my $line = <$fh>) { next if ($line =~ /^\#/); chomp($line); @@ -249,7 +243,7 @@ BEGIN { # -------------------------------------------------------------- default domain designs my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; my $designfile = $designdir.'/default.tab'; - if ( open (my $fh,'<',$designfile) ) { + if ( open (my $fh,"<$designfile") ) { while (my $line = <$fh>) { next if ($line =~ /^\#/); chomp($line); @@ -263,12 +257,12 @@ BEGIN { { my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}. '/filecategories.tab'; - if ( open (my $fh,'<',$categoryfile) ) { + if ( open (my $fh,"<$categoryfile") ) { while (my $line = <$fh>) { next if ($line =~ /^\#/); chomp($line); my ($extension,$category)=(split(/\s+/,$line,2)); - push(@{$category_extensions{lc($category)}},$extension); + push @{$category_extensions{lc($category)}},$extension; } close($fh); } @@ -278,7 +272,7 @@ BEGIN { { my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}. '/filetypes.tab'; - if ( open (my $fh,'<',$typesfile) ) { + if ( open (my $fh,"<$typesfile") ) { while (my $line = <$fh>) { next if ($line =~ /^\#/); chomp($line); @@ -431,7 +425,7 @@ sub studentbrowser_javascript { -COLORFULEDIT -} - -sub xmleditor_js { - return < - -XMLEDIT -} - -sub insert_folding_button { - my $curDepth = $Apache::lonxml::curdepth; - my $lastresource = $env{'request.ambiguous'}; - - return ""; -} - -=pod - -=item * &iframe_wrapper_headjs() - -emits javascript containing two global vars to facilitate handling of resizing -by code in iframe_wrapper_resizejs() used when an iframe is present in a page -with standard LON-CAPA menus. - -=cut - -# -# Where iframe is in use, if window.onload() executes before the custom resize function -# has been defined (jQuery), two global javascript vars (LCnotready and LCresizedef) -# are used to ensure document.ready() triggers a call to resize, so the iframe contents -# do not obscure the Functions menu. -# - -sub iframe_wrapper_headjs { - return <<"ENDJS"; - - -ENDJS - -} - -=pod - -=item * &iframe_wrapper_resizejs() - -emits javascript used to handle resizing for a page containing -an iframe, to ensure that the iframe does not obscure any -standard LON-CAPA menu items. - -=back - -=cut - -# -# jQuery to use when iframe is in use and a page resize occurs. -# This script will ensure that the iframe does not obscure any -# standard LON-CAPA inline menus (primary, secondary, and/or -# breadcrumbs and Functions menus. Expects javascript from -# &iframe_wrapper_headjs() to be in head portion of the web page, -# e.g., by inclusion in second arg passed to &start_page(). -# - -sub iframe_wrapper_resizejs { - my $offset = 5; - &get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']); - if (($env{'form.inhibitmenu'} eq 'yes') || ($env{'form.only_body'})) { - $offset = 0; - } - return &Apache::lonhtmlcommon::scripttag(< form to allow a user to select options from a ref to a hash containing: option_name => displayed text. An optional $onchange can include -a javascript onchange item, e.g., onchange="this.form.submit();". -An optional arg -- $readonly -- if true will cause the select form -to be disabled, e.g., for the case where an instructor has a section- -specific role, and is viewing/modifying parameters. +a javascript onchange item, e.g., onchange="this.form.submit();" See lonrights.pm for an example invocation and use. @@ -2391,16 +2029,12 @@ See lonrights.pm for an example invocati #------------------------------------------- sub select_form { - my ($def,$name,$hashref,$onchange,$readonly) = @_; + my ($def,$name,$hashref,$onchange) = @_; return unless (ref($hashref) eq 'HASH'); if ($onchange) { $onchange = ' onchange="'.$onchange.'"'; } - my $disabled; - if ($readonly) { - $disabled = ' disabled="disabled"'; - } - my $selectform = "\n"; my @keys; if (exists($hashref->{'select_form_order'})) { @keys=@{$hashref->{'select_form_order'}}; @@ -2569,7 +2203,7 @@ sub select_level_form { =pod -=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) +=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms) Returns a string containing a \n"; + my $selectdomain = "'; + $authtype = ''; } } } @@ -3050,7 +2665,7 @@ sub authform_kerberos { if ($authtype eq '') { $authtype = ''; + $krbcheck.' />'; } if (($can_assign{'krb4'} && $can_assign{'krb5'}) || ($can_assign{'krb4'} && !$can_assign{'krb5'} && @@ -3063,9 +2678,9 @@ sub authform_kerberos { '', - ''. ''. ''; if (ref($path) eq 'ARRAY') { push(@{$path},$name); - $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories,$disabled); + $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories); pop(@{$path}); } $text .= ''; @@ -16214,7 +13761,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'); @@ -16263,7 +13810,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; @@ -16326,8 +13873,7 @@ sub check_clone { my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); - my $clonetitle; - my @clonemsg; + my $clonemsg; my $can_clone = 0; my $lctype = lc($args->{'crstype'}); if ($lctype ne 'community') { @@ -16335,154 +13881,59 @@ sub check_clone { } if ($clonehome eq 'no_host') { if ($args->{'crstype'} eq 'Community') { - push(@clonemsg,({ - mt => 'No new community created.', - args => [], - }, - { - mt => 'A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.', - args => [$args->{'clonedomain'}.':'.$args->{'clonedomain'}], - })); + $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); } else { - push(@clonemsg,({ - mt => 'No new course created.', - args => [], - }, - { - mt => 'A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.', - args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}], - })); - } + $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); + } } else { my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); - $clonetitle = $clonedesc{'description'}; if ($args->{'crstype'} eq 'Community') { if ($clonedesc{'type'} ne 'Community') { - push(@clonemsg,({ - mt => 'No new community created.', - args => [], - }, - { - mt => 'A new community could not be cloned from the specified original - [_1] - because it is a course not a community.', - args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}], - })); - return ($can_clone,\@clonemsg,$cloneid,$clonehome); + $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); + return ($can_clone, $clonemsg, $cloneid, $clonehome); } } - if (($env{'request.role.domain'} eq $args->{'clonedomain'}) && + if (($env{'request.role.domain'} eq $args->{'clonedomain'}) && (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) { $can_clone = 1; } else { - my %clonehash = &Apache::lonnet::get('environment',['cloners','internal.coursecode'], + my %clonehash = &Apache::lonnet::get('environment',['cloners'], $args->{'clonedomain'},$args->{'clonecourse'}); - 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; - } - } - } - } + my @cloners = split(/,/,$clonehash{'cloners'}); + if (grep(/^\*$/,@cloners)) { + $can_clone = 1; + } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { + $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}) { + 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))) { $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') { - push(@clonemsg,({ - mt => 'No new community created.', - args => [], - }, - { - 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 => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}], - })); } else { - push(@clonemsg,({ - mt => 'No new course created.', - args => [], - }, - { - 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'}], - })); + 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'}); + } } } } } - return ($can_clone,\@clonemsg,$cloneid,$clonehome,$clonetitle); + return ($can_clone, $clonemsg, $cloneid, $clonehome); } sub construct_course { - my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context, - $cnum,$category,$coderef,$callercontext,$user_lh) = @_; - my ($outcome,$msgref,$clonemsgref); + my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category,$coderef) = @_; + my $outcome; my $linefeed = '
'."\n"; if ($context eq 'auto') { $linefeed = "\n"; @@ -16491,11 +13942,18 @@ sub construct_course { # # Are we cloning? # - my ($can_clone,$cloneid,$clonehome,$clonetitle); + my ($can_clone, $clonemsg, $cloneid, $clonehome); if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { - ($can_clone,$clonemsgref,$cloneid,$clonehome,$clonetitle) = &check_clone($args,$linefeed); + ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed); + if ($context ne 'auto') { + if ($clonemsg ne '') { + $clonemsg = ''.$clonemsg.''; + } + } + $outcome .= $clonemsg.$linefeed; + if (!$can_clone) { - return (0,$outcome,$clonemsgref); + return (0,$outcome); } } @@ -16513,20 +13971,15 @@ sub construct_course { $args->{'ccuname'}.':'. $args->{'ccdomain'}, $args->{'crstype'}, - $cnum,$context,$category, - $callercontext); + $cnum,$context,$category); # Note: The testing routines depend on this being output; see # Utils::Course. This needs to at least be output as a comment # if anyone ever decides to not show this, and Utils::Course::new # will need to be suitably modified. - if (($callercontext eq 'auto') && ($user_lh ne '')) { - $outcome .= &mt_user($user_lh,'New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; - } else { - $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; - } + $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; if ($$courseid =~ /^error:/) { - return (0,$outcome,$clonemsgref); + return (0,$outcome); } # @@ -16535,37 +13988,23 @@ sub construct_course { ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid); my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom); if ($crsuhome eq 'no_host') { - if (($callercontext eq 'auto') && ($user_lh ne '')) { - $outcome .= &mt_user($user_lh, - 'Course creation failed, unrecognized course home server.'); - } else { - $outcome .= &mt('Course creation failed, unrecognized course home server.'); - } - $outcome .= $linefeed; - return (0,$outcome,$clonemsgref); + $outcome .= &mt('Course creation failed, unrecognized course home server.').$linefeed; + return (0,$outcome); } $outcome .= &mt('Created on').': '.$crsuhome.$linefeed; # # Do the cloning -# - my @clonemsg; +# if ($can_clone && $cloneid) { - push(@clonemsg, - { - mt => 'Created [_1] by cloning from [_2]', - args => [$crstype,$clonetitle], - }); + $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome); + if ($context ne 'auto') { + $clonemsg = ''.$clonemsg.''; + } + $outcome .= $clonemsg.$linefeed; my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); # Copy all files - my @info = - &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'}, - $args->{'dateshift'},$args->{'crscode'}, - $args->{'ccuname'}.':'.$args->{'ccdomain'}, - $args->{'tinyurls'}); - if (@info) { - push(@clonemsg,@info); - } + &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'}); # Restore URL $cenv{'url'}=$oldcenv{'url'}; # Restore title @@ -16590,7 +14029,8 @@ sub construct_course { 'plc.users.denied', 'hidefromcat', 'checkforpriv', - 'categories'], + 'categories', + 'internal.uniquecode'], $$crsudom,$$crsunum); if ($args->{'textbook'}) { $cenv{'internal.textbook'} = $args->{'textbook'}; @@ -16605,9 +14045,6 @@ 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'}; } @@ -16629,7 +14066,6 @@ 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/,/) { @@ -16643,12 +14079,8 @@ 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.','; - if ($addcheck eq 'ok') { - unless (grep(/^\Q$gp\E$/,@oklcsecs)) { - push(@oklcsecs,$gp); - } - } else { - push(@badclasses,$class); + unless ($addcheck eq 'ok') { + push @badclasses, $class; } } $cenv{'internal.sectionnums'} =~ s/,$//; @@ -16675,12 +14107,8 @@ 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.','; - if ($addcheck eq 'ok') { - unless (grep(/^\Q$gp\E$/,@oklcsecs)) { - push(@oklcsecs,$gp); - } - } else { - push(@badclasses,$xl); + unless ($addcheck eq 'ok') { + push @badclasses, $xl; } } $cenv{'internal.crosslistings'} =~ s/,$//; @@ -16715,63 +14143,32 @@ sub construct_course { } if (@badclasses > 0) { my %lt=&Apache::lonlocal::texthash( - 'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course.', - 'howi' => 'However, if automated course roster updates are enabled for this class, these particular sections/crosslistings are not guaranteed to contribute towards enrollment.', - 'itis' => 'It is possible that rights to access enrollment for these classes will be available through assignment of co-owners.', + 'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course. However, if automated course roster updates are enabled for this class, these particular sections/crosslistings will not contribute towards enrollment, because the user identified as the course owner for this LON-CAPA course', + 'dnhr' => 'does not have rights to access enrollment in these classes', + 'adby' => 'as determined by the policies of your institution on access to official classlists' ); - my $badclass_msg = $lt{'tclb'}.$linefeed.$lt{'howi'}.$linefeed. - &mt('That is because the user identified as the course owner ([_1]) does not have rights to access enrollment in these classes, as determined by the policies of your institution on access to official classlists',$cenv{'internal.courseowner'}).$linefeed.$lt{'itis'}; + my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}. + ' ('.$lt{'adby'}.')'; if ($context eq 'auto') { $outcome .= $badclass_msg.$linefeed; - } else { $outcome .= '
'.$badclass_msg.$linefeed.'
    '."\n"; - } - foreach my $item (@badclasses) { + foreach my $item (@badclasses) { + if ($context eq 'auto') { + $outcome .= " - $item\n"; + } else { + $outcome .= "
  • $item
  • \n"; + } + } if ($context eq 'auto') { - $outcome .= " - $item\n"; + $outcome .= $linefeed; } else { - $outcome .= "
  • $item
  • \n"; + $outcome .= "


\n"; } - } - if ($context eq 'auto') { - $outcome .= $linefeed; - } else { - $outcome .= "

\n"; - } + } } 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'}; @@ -16799,9 +14196,6 @@ sub construct_course { if ($args->{'setcontent'}) { $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; } - if ($args->{'setcomment'}) { - $cenv{'comment.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; - } } if ($args->{'reshome'}) { $cenv{'reshome'}=$args->{'reshome'}.'/'; @@ -16836,7 +14230,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; } @@ -16873,23 +14267,19 @@ sub construct_course { # Open all assignments # if ($args->{'openall'}) { - my $opendate = time; - if ($args->{'openallfrom'} =~ /^\d+$/) { - $opendate = $args->{'openallfrom'}; - } my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate'; - my %storecontent = ($storeunder => $opendate, + my %storecontent = ($storeunder => time, $storeunder.'.type' => 'date_start'); - $outcome .= &mt('All assignments open starting [_1]', - &Apache::lonlocal::locallocaltime($opendate)).': '. - &Apache::lonnet::cput - ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed; + + $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput + ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed; } # # Set first page # unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank') || ($cloneid)) { + use LONCAPA::map; $outcome .= &mt('Setting first resource').': '; my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence'; @@ -16912,7 +14302,7 @@ sub construct_course { $outcome .= ($fatal?$errtext:'write ok').$linefeed; } - return (1,$outcome,\@clonemsg); + return (1,$outcome); } sub make_unique_code { @@ -16925,7 +14315,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; @@ -16996,13 +14386,12 @@ sub group_term { } sub course_types { - my @types = ('official','unofficial','community','textbook','lti'); + my @types = ('official','unofficial','community','textbook'); my %typename = ( official => 'Official course', unofficial => 'Unofficial course', community => 'Community', textbook => 'Textbook course', - lti => 'LTI provider', ); return (\@types,\%typename); } @@ -17063,7 +14452,7 @@ sub escape_url { my ($url) = @_; my @urlslices = split(/\//, $url,-1); my $lastitem = &escape(pop(@urlslices)); - return &HTML::Entities::encode(join('/',@urlslices),"'").'/'.$lastitem; + return join('/',@urlslices).'/'.$lastitem; } sub compare_arrays { @@ -17082,24 +14471,6 @@ 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) = @_; @@ -17109,8 +14480,7 @@ sub init_user_environment { # See if old ID present, if so, remove - my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv, - $coauthorenv); + my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv); my $now=time; if ($public) { @@ -17136,37 +14506,10 @@ sub init_user_environment { opendir(DIR,$lonids); while ($filename=readdir(DIR)) { if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) { - if (tie(my %oldenv,'GDBM_File',"$lonids/$filename", - &GDBM_READER(),0640)) { - my $linkedfile; - if (exists($oldenv{'user.linkedenv'})) { - $linkedfile = $oldenv{'user.linkedenv'}; - } - untie(%oldenv); - if (unlink("$lonids/$filename")) { - if ($linkedfile =~ /^[a-f0-9]+_linked$/) { - if (-l "$lonids/$linkedfile.id") { - unlink("$lonids/$linkedfile.id"); - } - } - } - } else { - unlink($lonids.'/'.$filename); - } + unlink($lonids.'/'.$filename); } } 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'} @@ -17175,13 +14518,13 @@ sub init_user_environment { # Initialize roles - ($userroles,$firstaccenv,$timerintenv,$coauthorenv) = + ($userroles,$firstaccenv,$timerintenv) = &Apache::lonnet::rolesinit($domain,$username,$authhost); } # ------------------------------------ Check browser type and MathML capability - my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,$clientunicode, - $clientos,$clientmobile,$clientinfo,$clientosversion) = &decode_user_agent($r); + my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, + $clientunicode,$clientos,$clientmobile,$clientinfo) = &decode_user_agent($r); # ------------------------------------------------------------- Get environment @@ -17203,7 +14546,6 @@ sub init_user_environment { # --------------------------------------------------------- Write first profile { - my $ip = &Apache::lonnet::get_requestor_ip(); my %initial_env = ("user.name" => $username, "user.domain" => $domain, @@ -17215,14 +14557,13 @@ 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" => '', "request.course.sec" => '', "request.role" => 'cm', "request.role.adv" => $env{'user.adv'}, - "request.host" => $ip,); + "request.host" => $ENV{'REMOTE_ADDR'},); if ($form->{'localpath'}) { $initial_env{"browser.localpath"} = $form->{'localpath'}; @@ -17241,55 +14582,36 @@ sub init_user_environment { $env{'user.noloadbalance'} = $lonhost; } - if ($form->{'noloadbalance'}) { - my @hosts = &Apache::lonnet::current_machine_ids(); - my $hosthere = $form->{'noloadbalance'}; - if (grep(/^\Q$hosthere\E$/,@hosts)) { - $initial_env{"user.noloadbalance"} = $hosthere; - $env{'user.noloadbalance'} = $hosthere; - } - } - + my %is_adv = ( is_adv => $env{'user.adv'} ); + my %domdef; unless ($domain eq 'public') { - my %is_adv = ( is_adv => $env{'user.adv'} ); - my %domdef = &Apache::lonnet::get_domain_defaults($domain); + %domdef = &Apache::lonnet::get_domain_defaults($domain); + } - 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','lti') { - $userenv{'canrequest.'.$crstype} = - &Apache::lonnet::usertools_access($username,$domain,$crstype, - 'reload','requestcourses', - \%userenv,\%domdef,\%is_adv); - } - - if ((ref($userroles) eq 'HASH') && ($userroles->{'user.author'}) && - (exists($userroles->{"user.role.au./$domain/"}))) { - if ($userenv{'authoreditors'}) { - $userenv{'editors'} = $userenv{'authoreditors'}; - } elsif ($domdef{'editors'} ne '') { - $userenv{'editors'} = $domdef{'editors'}; - } else { - $userenv{'editors'} = 'edit,xml'; - } - } + foreach my $tool ('aboutme','blog','webdav','portfolio') { + $userenv{'availabletools.'.$tool} = + &Apache::lonnet::usertools_access($username,$domain,$tool,'reload', + undef,\%userenv,\%domdef,\%is_adv); + } - $userenv{'canrequest.author'} = - &Apache::lonnet::usertools_access($username,$domain,'requestauthor', - 'reload','requestauthor', + foreach my $crstype ('official','unofficial','community','textbook') { + $userenv{'canrequest.'.$crstype} = + &Apache::lonnet::usertools_access($username,$domain,$crstype, + 'reload','requestcourses', \%userenv,\%domdef,\%is_adv); - my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'], - $domain,$username); - my $reqstatus = $reqauthor{'author_status'}; - if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { - if (ref($reqauthor{'author'}) eq 'HASH') { - $userenv{'requestauthorqueued'} = $reqstatus.':'. - $reqauthor{'author'}{'timestamp'}; - } + } + + $userenv{'canrequest.author'} = + &Apache::lonnet::usertools_access($username,$domain,'requestauthor', + 'reload','requestauthor', + \%userenv,\%domdef,\%is_adv); + my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'], + $domain,$username); + my $reqstatus = $reqauthor{'author_status'}; + if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { + if (ref($reqauthor{'author'}) eq 'HASH') { + $userenv{'requestauthorqueued'} = $reqstatus.':'. + $reqauthor{'author'}{'timestamp'}; } } @@ -17306,11 +14628,6 @@ sub init_user_environment { if (ref($timerintenv) eq 'HASH') { &_add_to_env(\%disk_env,$timerintenv); } - if (ref($coauthorenv) eq 'HASH') { - if (keys(%{$coauthorenv})) { - &_add_to_env(\%disk_env,$coauthorenv); - } - } if (ref($args->{'extra_env'})) { &_add_to_env(\%disk_env,$args->{'extra_env'}); } @@ -17401,12 +14718,12 @@ and quotacheck.pl Inputs: -filterlist - anonymous array of fields to include as potential filters +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"). + 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 @@ -17422,19 +14739,19 @@ cloneruname - username of owner of new c 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) +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". +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 +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 +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 @@ -17576,7 +14893,7 @@ sub build_filters { if (exists($filter->{'instcodefilter'})) { # if (($fixeddom) || ($formname eq 'requestcrs') || # ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) { - if ($codedom) { + if ($codedom) { $officialjs = 1; ($instcodeform,$jscript,$$numtitlesref) = &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker', @@ -17610,12 +14927,7 @@ sub build_filters { $output .= ''."\n". ''."\n"; - } elsif ($formname eq 'quotacheck') { - $output .= qq| - - -|; - } else { + } elsif ($formname ne 'quotacheck') { my $name_input; if ($cnameelement ne '') { $name_input = '{'ownerfilter'} ne '') || ($filter->{'ownerdomfilter'} ne '')) { @@ -17879,10 +15183,10 @@ sub search_courses { $filter->{'combownerfilter'}, $filter->{'coursefilter'}, undef,undef,$type,$regexpok,undef,undef, - undef,undef,$cloner,$cc_clone, + undef,undef,$cloner,$env{'form.cc_clone'}, $filter->{'cloneableonly'}, $createdbefore,$createdafter,undef, - $domcloner,undef,$reqcrsdom,$reqinstcode); + $domcloner); if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) { my $ccrole; if ($type eq 'Community') { @@ -17902,7 +15206,7 @@ sub search_courses { 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); + push (@{$courses{$cid}{roles}},$courserole); } } else { $courses{$cid}{roles} = [$courserole]; @@ -17916,237 +15220,42 @@ sub search_courses { return %courses; } + =pod =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; +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); } - } - 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) { - &Apache::lonnet::appenv({'request.course.timechecked'=>$now}); - my $blocked = &blocking_status('reinit',undef,$cnum,$cdom,undef,1); - if ($blocked) { - return (); - } - 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'; - } + push(@{$checkparms->{$name}},$value); } - 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); + } elsif ($item eq 'resourcetag') { + if ($name eq 'responsetype') { + $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key} + } + } elsif ($item eq 'course') { + if ($name eq 'crstype') { + $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key}; } } } - return (); + ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'}); + ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'}); + return; } sub update_content_constraints { @@ -18226,10 +15335,8 @@ 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; - if ($foldertitle ne '') { - $title .= ':
'.$foldertitle; - } + $title=''.&Apache::lonlocal::locallocaltime($time).' '. + $name.':
'.$foldertitle; } if (wantarray) { return ($title,$foldertitle,$renametitle); @@ -18237,152 +15344,33 @@ 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,$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 ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_; + if ($suppmap) { my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap); if ($fatal) { $errors ++; } else { - 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 ($#LONCAPA::map::resources > 0) { + foreach my $res (@LONCAPA::map::resources) { + my ($title,$src,$ext,$type,$status)=split(/\:/,$res); 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)$}) { - $errors = &recurse_supplemental($cnum,$cdom,$1,$errors,$possdel,$suppids, - $hiddensupp,$hiddensupp->{$id}); + ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors); } else { - 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); - } + $numfiles ++; } } } } } } - 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; + return ($numfiles,$errors); } sub symb_to_docspath { - my ($symb,$navmapref) = @_; - return unless ($symb && ref($navmapref)); + my ($symb) = @_; + return unless ($symb); my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb); if ($resurl=~/\.(sequence|page)$/) { $mapurl=$resurl; @@ -18390,11 +15378,9 @@ sub symb_to_docspath { $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'}; } my $mapresobj; - unless (ref($$navmapref)) { - $$navmapref = Apache::lonnavmaps::navmap->new(); - } - if (ref($$navmapref)) { - $mapresobj = $$navmapref->getResourceByUrl($mapurl); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + $mapresobj = $navmap->getResourceByUrl($mapurl); } $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1}; my $type=$2; @@ -18404,7 +15390,7 @@ sub symb_to_docspath { if ($pcslist ne '') { foreach my $pc (split(/,/,$pcslist)) { next if ($pc <= 1); - my $res = $$navmapref->getByMapPc($pc); + my $res = $navmap->getByMapPc($pc); if (ref($res)) { my $thisurl = $res->src(); $thisurl=~s{^.*/([^/]+)\.\w+$}{$1}; @@ -18450,94 +15436,32 @@ 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 ($context,$lonhost) = @_; my ($output,$error); - my ($captcha,$pubkey,$privkey,$version) = - &get_captcha_config($context,$lonhost,$defdom); + my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost); if ($captcha eq 'original') { $output = &create_captcha(); unless ($output) { $error = 'captcha'; } } elsif ($captcha eq 'recaptcha') { - $output = &create_recaptcha($pubkey,$version); + $output = &create_recaptcha($pubkey); unless ($output) { $error = 'recaptcha'; } } - return ($output,$error,$captcha,$version); + return ($output,$error,$captcha); } sub captcha_response { - my ($context,$lonhost,$defdom) = @_; + my ($context,$lonhost) = @_; my ($captcha_chk,$captcha_error); - my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost,$defdom); + my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost); if ($captcha eq 'original') { ($captcha_chk,$captcha_error) = &check_captcha(); } elsif ($captcha eq 'recaptcha') { - $captcha_chk = &check_recaptcha($privkey,$version); + $captcha_chk = &check_recaptcha($privkey); } else { $captcha_chk = 1; } @@ -18545,8 +15469,8 @@ sub captcha_response { } sub get_captcha_config { - my ($context,$lonhost,$dom_in_effect) = @_; - my ($captcha,$pubkey,$privkey,$version,$hashtocheck); + my ($context,$lonhost) = @_; + my ($captcha,$pubkey,$privkey,$hashtocheck); my $hostname = &Apache::lonnet::hostname($lonhost); my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname); my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID); @@ -18562,10 +15486,6 @@ sub get_captcha_config { } if ($privkey && $pubkey) { $captcha = 'recaptcha'; - $version = $hashtocheck->{'recaptchaversion'}; - if ($version ne '2') { - $version = 1; - } } else { $captcha = 'original'; } @@ -18583,39 +15503,14 @@ sub get_captcha_config { $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'}; if ($privkey && $pubkey) { $captcha = 'recaptcha'; - $version = $domconfhash{$serverhomedom.'.login.recaptchaversion'}; - if ($version ne '2') { - $version = 1; - } } else { $captcha = 'original'; } } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') { $captcha = 'original'; } - } elsif ($context eq 'passwords') { - if ($dom_in_effect) { - my %passwdconf = &Apache::lonnet::get_passwdconf($dom_in_effect); - if ($passwdconf{'captcha'} eq 'recaptcha') { - if (ref($passwdconf{'recaptchakeys'}) eq 'HASH') { - $pubkey = $passwdconf{'recaptchakeys'}{'public'}; - $privkey = $passwdconf{'recaptchakeys'}{'private'}; - } - if ($privkey && $pubkey) { - $captcha = 'recaptcha'; - $version = $passwdconf{'recaptchaversion'}; - if ($version ne '2') { - $version = 1; - } - } else { - $captcha = 'original'; - } - } elsif ($passwdconf{'captcha'} ne 'notused') { - $captcha = 'original'; - } - } } - return ($captcha,$pubkey,$privkey,$version); + return ($captcha,$pubkey,$privkey); } sub create_captcha { @@ -18631,17 +15526,13 @@ sub create_captcha { if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') { $output = ''."\n". - ''. &mt('Type in the letters/numbers shown below').' '. - ''. - '
'. + ''. + '
'. 'captcha'; last; } } - if ($output eq '') { - &Apache::lonnet::logthis("Failed to create Captcha code after $tries attempts."); - } return $output; } @@ -18678,63 +15569,38 @@ sub check_captcha { } sub create_recaptcha { - my ($pubkey,$version) = @_; - if ($version >= 2) { - return '
'. - '
'; - } else { - my $use_ssl; - if ($ENV{'SERVER_PORT'} == 443) { - $use_ssl = 1; - } - my $captcha = Captcha::reCAPTCHA->new; - return $captcha->get_options_setter({theme => 'white'})."\n". - $captcha->get_html($pubkey,undef,$use_ssl). - &mt('If the text is hard to read, [_1] will replace them.', - 'reCAPTCHA refresh'). - '

'; - } + my ($pubkey) = @_; + my $use_ssl; + if ($ENV{'SERVER_PORT'} == 443) { + $use_ssl = 1; + } + my $captcha = Captcha::reCAPTCHA->new; + return $captcha->get_options_setter({theme => 'white'})."\n". + $captcha->get_html($pubkey,undef,$use_ssl). + &mt('If either word is hard to read, [_1] will replace them.', + 'reCAPTCHA refresh'). + '

'; } sub check_recaptcha { - my ($privkey,$version) = @_; + my ($privkey) = @_; 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 => $ip, - ); - my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info); - if ($response->is_success) { - my $data = JSON::DWIW->from_json($response->decoded_content); - if (ref($data) eq 'HASH') { - if ($data->{'success'}) { - $captcha_chk = 1; - } - } - } - } else { - my $captcha = Captcha::reCAPTCHA->new; - my $captcha_result = - $captcha->check_answer( - $privkey, - $ip, - $env{'form.recaptcha_challenge_field'}, - $env{'form.recaptcha_response_field'}, - ); - if ($captcha_result->{is_valid}) { - $captcha_chk = 1; - } + my $captcha = Captcha::reCAPTCHA->new; + my $captcha_result = + $captcha->check_answer( + $privkey, + $ENV{'REMOTE_ADDR'}, + $env{'form.recaptcha_challenge_field'}, + $env{'form.recaptcha_response_field'}, + ); + if ($captcha_result->{is_valid}) { + $captcha_chk = 1; } return $captcha_chk; } sub emailusername_info { - my @fields = ('firstname','lastname','institution','web','location','officialemail','id'); + my @fields = ('firstname','lastname','institution','web','location','officialemail'); my %titles = &Apache::lonlocal::texthash ( lastname => 'Last Name', firstname => 'First Name', @@ -18742,7 +15608,6 @@ sub emailusername_info { location => "School's city, state/province, country", web => "School's web address", officialemail => 'E-mail address at institution (if different)', - id => 'Student/Employee ID', ); return (\@fields,\%titles); } @@ -18769,45 +15634,6 @@ sub cleanup_html { return $outgoing; } -# Checks for critical messages and returns a redirect url if one exists. -# $interval indicates how often to check for messages. -# $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',undef,$cnum,$cdom,undef,1); - if ($blocked) { - my $checkrole = "cm./$cdom/$cnum"; - if ($env{'request.course.sec'} ne '') { - $checkrole .= "/$env{'request.course.sec'}"; - } - unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && - ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) { - return; - } - } - } - 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] ne 'no_such_host') && ($what[0]!~/^error\:/)) { - $redirecturl='/adm/email?critical=display'; - my $url=&Apache::lonnet::absolute_url().$redirecturl; - return (1, $url); - } - } - } - return (); -} - # Use: # my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver); # @@ -18842,358 +15668,14 @@ sub des_decrypt { } else { $cypher=new DES $keybin; } - 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; - } + 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; } -sub get_requested_shorturls { - my ($cdom,$cnum,$navmap) = @_; - return unless (ref($navmap)); - my ($numnew,$errors); - my @toshorten = &Apache::loncommon::get_env_multiple('form.addtiny'); - if (@toshorten) { - my (%maps,%resources,%titles); - &Apache::loncourserespicker::enumerate_course_contents($navmap,\%maps,\%resources,\%titles, - 'shorturls',$cdom,$cnum); - if (keys(%resources)) { - my %tocreate; - foreach my $item (sort {$a <=> $b} (@toshorten)) { - my $symb = $resources{$item}; - if ($symb) { - $tocreate{$cnum.'&'.$symb} = 1; - } - } - if (keys(%tocreate)) { - ($numnew,$errors) = &make_short_symbs($cdom,$cnum, - \%tocreate); - } - } - } - return ($numnew,$errors); -} - -sub make_short_symbs { - my ($cdom,$cnum,$tocreateref,$lockuser) = @_; - my ($numnew,@errors); - if (ref($tocreateref) eq 'HASH') { - my %tocreate = %{$tocreateref}; - if (keys(%tocreate)) { - my %coursetiny = &Apache::lonnet::dump('tiny',$cdom,$cnum); - my $su = Short::URL->new(no_vowels => 1); - my $init = ''; - my (%newunique,%addcourse,%courseonly,%failed); - # get lock on tiny db - my $now = time; - if ($lockuser eq '') { - $lockuser = $env{'user.name'}.':'.$env{'user.domain'}; - } - my $lockhash = { - "lock\0$now" => $lockuser, - }; - my $tries = 0; - my $gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom); - my ($code,$error); - while (($gotlock ne 'ok') && ($tries<3)) { - $tries ++; - sleep 1; - $gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom); - } - if ($gotlock eq 'ok') { - $init = &shorten_symbs($cdom,$init,$su,\%coursetiny,\%tocreate,\%newunique, - \%addcourse,\%courseonly,\%failed); - if (keys(%failed)) { - my $numfailed = scalar(keys(%failed)); - push(@errors,&mt('error: could not obtain unique six character URL for [quant,_1,resource]',$numfailed)); - } - if (keys(%newunique)) { - my $putres = &Apache::lonnet::newput_dom('tiny',\%newunique,$cdom); - if ($putres eq 'ok') { - $numnew = scalar(keys(%newunique)); - my $newputres = &Apache::lonnet::newput('tiny',\%addcourse,$cdom,$cnum); - unless ($newputres eq 'ok') { - push(@errors,&mt('error: could not store course look-up of short URLs')); - } - } else { - 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')); - } - } - } - } - return ($numnew,\@errors); -} - -sub shorten_symbs { - my ($cdom,$init,$su,$coursetiny,$tocreate,$newunique,$addcourse,$courseonly,$failed) = @_; - return unless ((ref($su)) && (ref($coursetiny) eq 'HASH') && (ref($tocreate) eq 'HASH') && - (ref($newunique) eq 'HASH') && (ref($addcourse) eq 'HASH') && - (ref($courseonly) eq 'HASH') && (ref($failed) eq 'HASH')); - my (%possibles,%collisions); - foreach my $key (keys(%{$tocreate})) { - my $num = String::CRC32::crc32($key); - my $tiny = $su->encode($num,$init); - if ($tiny) { - $possibles{$tiny} = $key; - } - } - if (!$init) { - $init = 1; - } else { - $init ++; - } - if (keys(%possibles)) { - my @posstiny = keys(%possibles); - my $configuname = &Apache::lonnet::get_domainconfiguser($cdom); - my %currtiny = &Apache::lonnet::get('tiny',\@posstiny,$cdom,$configuname); - if (keys(%currtiny)) { - foreach my $key (keys(%currtiny)) { - next if ($currtiny{$key} eq ''); - if ($currtiny{$key} eq $possibles{$key}) { - my ($tcnum,$tsymb) = split(/\&/,$currtiny{$key}); - unless (($coursetiny->{$tsymb} eq $key) || ($addcourse->{$tsymb} eq $key) || ($courseonly->{$tsymb} eq $key)) { - $courseonly->{$tsymb} = $key; - } - } else { - $collisions{$possibles{$key}} = 1; - } - delete($possibles{$key}); - } - } - foreach my $key (keys(%possibles)) { - $newunique->{$key} = $possibles{$key}; - my ($tcnum,$tsymb) = split(/\&/,$possibles{$key}); - unless (($coursetiny->{$tsymb} eq $key) || ($addcourse->{$tsymb} eq $key) || ($courseonly->{$tsymb} eq $key)) { - $addcourse->{$tsymb} = $key; - } - } - } - if (keys(%collisions)) { - if ($init <5) { - if (!$init) { - $init = 1; - } else { - $init ++; - } - $init = &shorten_symbs($cdom,$init,$su,$coursetiny,\%collisions, - $newunique,$addcourse,$courseonly,$failed); - } else { - foreach my $key (keys(%collisions)) { - $failed->{$key} = 1; - $failed->{$key} = 1; - } - } - } - return $init; -} - -sub is_nonframeable { - my ($url,$absolute,$hostname,$ip,$nocache) = @_; - my ($remprotocol,$remhost) = ($url =~ m{^(https?)\://(([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,})}i); - return if (($remprotocol eq '') || ($remhost eq '')); - - $remprotocol = lc($remprotocol); - $remhost = lc($remhost); - my $remport = 80; - if ($remprotocol eq 'https') { - $remport = 443; - } - my ($result,$cached) = &Apache::lonnet::is_cached_new('noiframe',$remhost.':'.$remport); - if ($cached) { - unless ($nocache) { - if ($result) { - return 1; - } else { - return 0; - } - } - } - my $uselink; - my $request = new HTTP::Request('HEAD',$url); - my $ua = LWP::UserAgent->new; - $ua->timeout(5); - my $response=$ua->request($request); - if ($response->is_success()) { - my $secpolicy = lc($response->header('content-security-policy')); - my $xframeop = lc($response->header('x-frame-options')); - $secpolicy =~ s/^\s+|\s+$//g; - $xframeop =~ s/^\s+|\s+$//g; - if (($secpolicy ne '') || ($xframeop ne '')) { - my $remotehost = $remprotocol.'://'.$remhost; - my ($origin,$protocol,$port); - if ($ENV{'SERVER_PORT'} =~/^\d+$/) { - $port = $ENV{'SERVER_PORT'}; - } else { - $port = 80; - } - if ($absolute eq '') { - $protocol = 'http:'; - if ($port == 443) { - $protocol = 'https:'; - } - $origin = $protocol.'//'.lc($hostname); - } else { - $origin = lc($absolute); - ($protocol,$hostname) = ($absolute =~ m{^(https?:)//([^/]+)$}); - } - if (($secpolicy) && ($secpolicy =~ /\Qframe-ancestors\E([^;]*)(;|$)/)) { - my $framepolicy = $1; - $framepolicy =~ s/^\s+|\s+$//g; - my @policies = split(/\s+/,$framepolicy); - if (@policies) { - if (grep(/^\Q'none'\E$/,@policies)) { - $uselink = 1; - } else { - $uselink = 1; - if ((grep(/^\Q*\E$/,@policies)) || (grep(/^\Q$protocol\E$/,@policies)) || - (($origin ne '') && (grep(/^\Q$origin\E$/,@policies))) || - (($ip ne '') && (grep(/^\Q$ip\E$/,@policies)))) { - undef($uselink); - } - if ($uselink) { - if (grep(/^\Q'self'\E$/,@policies)) { - if (($origin ne '') && ($remotehost eq $origin)) { - undef($uselink); - } - } - } - if ($uselink) { - my @possok; - if ($ip ne '') { - push(@possok,$ip); - } - my $hoststr = ''; - foreach my $part (reverse(split(/\./,$hostname))) { - if ($hoststr eq '') { - $hoststr = $part; - } else { - $hoststr = "$part.$hoststr"; - } - if ($hoststr eq $hostname) { - push(@possok,$hostname); - } else { - push(@possok,"*.$hoststr"); - } - } - if (@possok) { - foreach my $poss (@possok) { - last if (!$uselink); - foreach my $policy (@policies) { - if ($policy =~ m{^(\Q$protocol\E//|)\Q$poss\E(\Q:$port\E|)$}) { - undef($uselink); - last; - } - } - } - } - } - } - } - } elsif ($xframeop ne '') { - $uselink = 1; - my @policies = split(/\s*,\s*/,$xframeop); - if (@policies) { - unless (grep(/^deny$/,@policies)) { - if ($origin ne '') { - if (grep(/^sameorigin$/,@policies)) { - if ($remotehost eq $origin) { - undef($uselink); - } - } - if ($uselink) { - foreach my $policy (@policies) { - if ($policy =~ /^allow-from\s*(.+)$/) { - my $allowfrom = $1; - if (($allowfrom ne '') && ($allowfrom eq $origin)) { - undef($uselink); - last; - } - } - } - } - } - } - } - } - } - } - if ($nocache) { - if ($cached) { - my $devalidate; - if ($uselink && !$result) { - $devalidate = 1; - } elsif (!$uselink && $result) { - $devalidate = 1; - } - if ($devalidate) { - &Apache::lonnet::devalidate_cache_new('noiframe',$remhost.':'.$remport); - } - } - } else { - if ($uselink) { - $result = 1; - } else { - $result = 0; - } - &Apache::lonnet::do_cache_new('noiframe',$remhost.':'.$remport,$result,3600); - } - 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__;