--- loncom/lonnet/perl/lonnet.pm 2022/10/22 17:24:55 1.1497 +++ loncom/lonnet/perl/lonnet.pm 2024/03/29 17:32:03 1.1524 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1497 2022/10/22 17:24:55 raeburn Exp $ +# $Id: lonnet.pm,v 1.1524 2024/03/29 17:32:03 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -415,6 +415,63 @@ sub remote_devalidate_cache { return $response; } +sub sign_lti { + my ($cdom,$cnum,$crsdef,$type,$context,$url,$ltinum,$keynum,$paramsref,$inforef) = @_; + my $chome; + if (&domain($cdom) ne '') { + if ($crsdef) { + $chome = &homeserver($cnum,$cdom); + } else { + $chome = &domain($cdom,'primary'); + } + } + if ($cdom && $chome && ($chome ne 'no_host')) { + if ((ref($paramsref) eq 'HASH') && + (ref($inforef) eq 'HASH')) { + my $rep; + if (grep { $_ eq $chome } ¤t_machine_ids()) { + # domain information is hosted on this machine + $rep = + &LONCAPA::Lond::sign_lti_payload($cdom,$cnum,$crsdef,$type, + $context,$url,$ltinum,$keynum, + $perlvar{'lonVersion'}, + $paramsref,$inforef); + if (ref($rep) eq 'HASH') { + return ('ok',$rep); + } + } else { + my ($escurl,$params,$info); + $escurl = &escape($url); + if (ref($paramsref) eq 'HASH') { + $params = &freeze_escape($paramsref); + } + if (ref($inforef) eq 'HASH') { + $info = &freeze_escape($inforef); + } + $rep=&reply("encrypt:signlti:$cdom:$cnum:$crsdef:$type:$context:$escurl:$ltinum:$keynum:$params:$info",$chome); + } + if (($rep eq '') || ($rep =~ /^con_lost|error|no_such_host|unknown_cmd/i)) { + return (); + } elsif (($inforef->{'respfmt'} eq 'to_post_body') || + ($inforef->{'respfmt'} eq 'to_authorization_header')) { + return ('ok',$rep); + } else { + my %returnhash; + foreach my $item (split(/\&/,$rep)) { + my ($name,$value)=split(/\=/,$item); + $returnhash{&unescape($name)}=&thaw_unescape($value); + } + return('ok',\%returnhash); + } + } else { + return (); + } + } else { + return (); + &logthis("sign_lti failed - no homeserver and/or domain ($cdom) ($chome)"); + } +} + # -------------------------------------------------- Non-critical communication sub subreply { my ($cmd,$server)=@_; @@ -2696,9 +2753,11 @@ sub get_domain_defaults { &get_dom('configuration',['defaults','quotas', 'requestcourses','inststatus', 'coursedefaults','usersessions', - 'requestauthor','selfenrollment', - 'coursecategories','ssl','autoenroll', - 'trust','helpsettings','wafproxy','ltisec'],$domain); + 'requestauthor','authordefaults', + 'selfenrollment','coursecategories', + 'ssl','autoenroll','trust', + 'helpsettings','wafproxy', + 'ltisec','toolsec','privacy'],$domain); my @coursetypes = ('official','unofficial','community','textbook','placement'); if (ref($domconfig{'defaults'}) eq 'HASH') { $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; @@ -2724,7 +2783,7 @@ sub get_domain_defaults { } else { $domdefaults{'defaultquota'} = $domconfig{'quotas'}; } - my @usertools = ('aboutme','blog','webdav','portfolio'); + my @usertools = ('aboutme','blog','webdav','portfolio','portaccess'); foreach my $item (@usertools) { if (ref($domconfig{'quotas'}{$item}) eq 'HASH') { $domdefaults{$item} = $domconfig{'quotas'}{$item}; @@ -2742,6 +2801,17 @@ sub get_domain_defaults { if (ref($domconfig{'requestauthor'}) eq 'HASH') { $domdefaults{'requestauthor'} = $domconfig{'requestauthor'}; } + if (ref($domconfig{'authordefaults'}) eq 'HASH') { + foreach my $item ('nocodemirror','copyright','sourceavail','domcoordacc','editors') { + if ($item eq 'editors') { + if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') { + $domdefaults{$item} = join(',',@{$domconfig{'authordefaults'}{'editors'}}); + } + } else { + $domdefaults{$item} = $domconfig{'authordefaults'}{$item}; + } + } + } if (ref($domconfig{'inststatus'}) eq 'HASH') { foreach my $item ('inststatustypes','inststatusorder','inststatusguest') { $domdefaults{$item} = $domconfig{'inststatus'}{$item}; @@ -2764,12 +2834,30 @@ sub get_domain_defaults { if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') { $domdefaults{$type.'quota'} = $domconfig{'coursedefaults'}{'uploadquota'}{$type}; } + if (ref($domconfig{'coursedefaults'}{'coursequota'}) eq 'HASH') { + $domdefaults{$type.'coursequota'} = $domconfig{'coursedefaults'}{'coursequota'}{$type}; + } if ($domdefaults{'postsubmit'} eq 'on') { if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { $domdefaults{$type.'postsubtimeout'} = $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; } } + if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') { + $domdefaults{$type.'domexttool'} = $domconfig{'coursedefaults'}{'domexttool'}{$type}; + } else { + $domdefaults{$type.'domexttool'} = 1; + } + if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') { + $domdefaults{$type.'exttool'} = $domconfig{'coursedefaults'}{'exttool'}{$type}; + } else { + $domdefaults{$type.'exttool'} = 0; + } + if (ref($domconfig{'coursedefaults'}{'crsauthor'}) eq 'HASH') { + $domdefaults{$type.'crsauthor'} = $domconfig{'coursedefaults'}{'crsauthor'}{$type}; + } else { + $domdefaults{$type.'crsauthor'} = 1; + } } if (ref($domconfig{'coursedefaults'}{'canclone'}) eq 'HASH') { if (ref($domconfig{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') { @@ -2884,7 +2972,44 @@ sub get_domain_defaults { } if (ref($domconfig{'ltisec'}{'private'}) eq 'HASH') { if (ref($domconfig{'ltisec'}{'private'}{'keys'}) eq 'ARRAY') { - $domdefaults{'privhosts'} = $domconfig{'ltisec'}{'private'}{'keys'}; + $domdefaults{'ltiprivhosts'} = $domconfig{'ltisec'}{'private'}{'keys'}; + } + } + if (ref($domconfig{'ltisec'}{'suggested'}) eq 'HASH') { + my %suggestions = %{$domconfig{'ltisec'}{'suggested'}}; + foreach my $item (keys(%{$domconfig{'ltisec'}{'suggested'}})) { + unless (ref($domconfig{'ltisec'}{'suggested'}{$item}) eq 'HASH') { + delete($suggestions{$item}); + } + } + if (keys(%suggestions)) { + $domdefaults{'linkprotsuggested'} = \%suggestions; + } + } + } + if (ref($domconfig{'toolsec'}) eq 'HASH') { + if (ref($domconfig{'toolsec'}{'encrypt'}) eq 'HASH') { + $domdefaults{'toolenc_crs'} = $domconfig{'toolsec'}{'encrypt'}{'crs'}; + $domdefaults{'toolenc_dom'} = $domconfig{'toolsec'}{'encrypt'}{'dom'}; + } + if (ref($domconfig{'toolsec'}{'private'}) eq 'HASH') { + if (ref($domconfig{'toolsec'}{'private'}{'keys'}) eq 'ARRAY') { + $domdefaults{'toolprivhosts'} = $domconfig{'toolsec'}{'private'}{'keys'}; + } + } + } + if (ref($domconfig{'privacy'}) eq 'HASH') { + if (ref($domconfig{'privacy'}{'approval'}) eq 'HASH') { + foreach my $domtype ('instdom','extdom') { + if (ref($domconfig{'privacy'}{'approval'}{$domtype}) eq 'HASH') { + foreach my $roletype ('domain','author','course','community') { + if ($domconfig{'privacy'}{'approval'}{$domtype}{$roletype} eq 'user') { + $domdefaults{'userapprovals'} = 1; + last; + } + } + } + last if ($domdefaults{'userapprovals'}); } } } @@ -2924,6 +3049,7 @@ sub get_dom_instcats { if (&auto_instcode_format($caller,$dom,\%coursecodes,\%codes, \@codetitles,\%cat_titles,\%cat_order) eq 'ok') { $instcats = { + totcodes => $totcodes, codes => \%codes, codetitles => \@codetitles, cat_titles => \%cat_titles, @@ -3822,6 +3948,29 @@ sub can_edit_resource { } } +# +# For /adm/viewcoauthors can only edit if author or co-author who is manager. +# + + if (($resurl eq '/adm/viewcoauthors') && ($cnum ne '') && ($cdom ne '')) { + if (((&allowed('cca',"$cdom/$cnum")) || + (&allowed('caa',"$cdom/$cnum"))) || + ((&allowed('vca',"$cdom/$cnum") || + &allowed('vaa',"$cdom/$cnum")) && + ($env{"environment.internal.manager./$cdom/$cnum"}))) { + $home = $env{'user.home'}; + $cfile = $resurl; + if ($env{'form.forceedit'}) { + $forceview = 1; + } else { + $forceedit = 1; + } + return ($cfile,$home,$switchserver,$forceedit,$forceview); + } else { + return; + } + } + if ($env{'request.course.id'}) { my $crsedit = &allowed('mdc',$env{'request.course.id'}); if ($group ne '') { @@ -3856,10 +4005,15 @@ sub can_edit_resource { return; } } elsif (!$crsedit) { + if ($env{'request.role'} =~ m{^st\./$cdom/$cnum}) { # # No edit allowed where CC has switched to student role. # - return; + return; + } elsif (($resurl !~ m{^/res/$match_domain/$match_username/}) || + ($resurl =~ m{^/res/lib/templates/})) { + return; + } } } } @@ -3885,7 +4039,7 @@ sub can_edit_resource { $forceedit = 1; } $cfile = $resurl; - } elsif (($resurl ne '') && (&is_on_map($resurl))) { + } elsif (($resurl ne '') && (&is_on_map($resurl))) { if ($resurl =~ m{^/adm/$match_domain/$match_username/\d+/smppg|bulletinboard$}) { $incourse = 1; if ($env{'form.forceedit'}) { @@ -4268,7 +4422,7 @@ sub resizeImage { # input: $formname - the contents of the file are in $env{"form.$formname"} # the desired filename is in $env{"form.$formname.filename"} # $context - possible values: coursedoc, existingfile, overwrite, -# canceloverwrite, scantron or ''. +# canceloverwrite, scantron, toollogo or ''. # if 'coursedoc': upload to the current course # if 'existingfile': write file to tmp/overwrites directory # if 'canceloverwrite': delete file written to tmp/overwrites directory @@ -4280,8 +4434,8 @@ sub resizeImage { # Section => 4, CODE => 5, FirstQuestion => 9 }). # $allfiles - reference to hash for embedded objects # $codebase - reference to hash for codebase of java objects -# $desuname - username for permanent storage of uploaded file -# $dsetudom - domain for permanaent storage of uploaded file +# $destuname - username for permanent storage of uploaded file +# $destudom - domain for permanaent storage of uploaded file # $thumbwidth - width (pixels) of thumbnail to make for uploaded image # $thumbheight - height (pixels) of thumbnail to make for uploaded image # $resizewidth - width (pixels) to which to resize uploaded image @@ -4491,11 +4645,24 @@ sub finishuserfileupload { if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) { my $input = $filepath.'/'.$file; my $output = $filepath.'/'.'tn-'.$file; + my $makethumb; my $thumbsize = $thumbwidth.'x'.$thumbheight; - my @args = ('convert','-sample',$thumbsize,$input,$output); - system({$args[0]} @args); - if (-e $filepath.'/'.'tn-'.$file) { - $fetchthumb = 1; + if ($context eq 'toollogo') { + my ($fullwidth,$fullheight) = &check_dimensions($input); + if ($fullwidth ne '' && $fullheight ne '') { + if ($fullwidth > $thumbwidth && $fullheight > $thumbheight) { + $makethumb = 1; + } + } + } else { + $makethumb = 1; + } + if ($makethumb) { + my @args = ('convert','-sample',$thumbsize,$input,$output); + system({$args[0]} @args); + if (-e $filepath.'/'.'tn-'.$file) { + $fetchthumb = 1; + } } } @@ -4727,6 +4894,30 @@ sub embedded_dependency { return; } +sub check_dimensions { + my ($inputfile) = @_; + my ($fullwidth,$fullheight); + if (($inputfile =~ m|^[/\w.\-]+$|) && (-e $inputfile)) { + my $mm = new File::MMagic; + my $mime_type = $mm->checktype_filename($inputfile); + if ($mime_type =~ m{^image/}) { + if (open(PIPE,"identify $inputfile 2>&1 |")) { + my $imageinfo = ; + if (!close(PIPE)) { + &Apache::lonnet::logthis("Failed to close PIPE opened to retrieve image information for $inputfile"); + } + chomp($imageinfo); + my ($fullsize) = + ($imageinfo =~ /^\Q$inputfile\E\s+\w+\s+(\d+x\d+)/); + if ($fullsize) { + ($fullwidth,$fullheight) = split(/x/,$fullsize); + } + } + } + } + return ($fullwidth,$fullheight); +} + sub bubblesheet_converter { my ($cdom,$fullpath,$config,$format) = @_; if ((&domain($cdom) ne '') && @@ -5090,7 +5281,7 @@ sub flushcourselogs { # Typo in rev. 1.458 (2003/12/09)?? # These should likely by $env{'course.'.$cid.'.domain'} and $env{'course.'.$cid.'.num'} # -# While these ramain as $env{'request.'.$cid.'.domain'} and $env{'request.'.$cid.'.num'} +# While these remain as $env{'request.'.$cid.'.domain'} and $env{'request.'.$cid.'.num'} # $dom and $name will always be null, so the &inc() call will default to storing this data # in a nohist_accesscount.db file for the user rather than the course. # @@ -5301,7 +5492,8 @@ sub userrolelog { } sub courserolelog { - my ($trole,$username,$domain,$area,$tstart,$tend,$delflag,$selfenroll,$context)=@_; + my ($trole,$username,$domain,$area,$tstart,$tend,$delflag,$selfenroll, + $context,$othdomby,$requester)=@_; if ($area =~ m-^/($match_domain)/($match_courseid)/?([^/]*)-) { my $cdom = $1; my $cnum = $2; @@ -5314,11 +5506,51 @@ sub courserolelog { selfenroll => $selfenroll, context => $context, ); + if ($othdomby) { + if ($othdomby eq 'othdombydc') { + $storehash{'approval'} = 'domain'; + } elsif ($othdomby eq 'othdombyuser') { + $storehash{'approval'} = 'user'; + } + if ($requester ne '') { + $storehash{'requester'} = $requester; + } + } if ($trole eq 'gr') { $namespace = 'groupslog'; $storehash{'group'} = $sec; } else { $storehash{'section'} = $sec; + my ($curruserdomstr,$newuserdomstr); + if (exists($env{'course.'.$cdom.'_'.$cnum.'.internal.userdomains'})) { + $curruserdomstr = $env{'course.'.$env{'request.course.id'}.'.internal.userdomains'}; + } else { + my %courseinfo = &coursedescription($cdom.'/'.$cnum); + $curruserdomstr = $courseinfo{'internal.userdomains'}; + } + if ($curruserdomstr ne '') { + my @udoms = split(/,/,$curruserdomstr); + unless (grep(/^\Q$domain\E/,@udoms)) { + push(@udoms,$domain); + $newuserdomstr = join(',',sort(@udoms)); + } + } else { + $newuserdomstr = $domain; + } + if ($newuserdomstr ne '') { + my $putresult = &put('environment',{ 'internal.userdomains' => $newuserdomstr }, + $cdom,$cnum); + if ($putresult eq 'ok') { + unless (($selfenroll) || ($context eq 'selfenroll')) { + if (($context eq 'createcourse') || ($context eq 'requestcourses') || + ($context eq 'automated') || ($context eq 'domain')) { + $env{'course.'.$cdom.'_'.$cnum.'.internal.userdomains'} = $newuserdomstr; + } elsif ($env{'request.course.id'} eq $cdom.'_'.$cnum) { + &appenv({'course.'.$cdom.'_'.$cnum.'.internal.userdomains' => $newuserdomstr}); + } + } + } + } } &write_log('course',$namespace,\%storehash,$delflag,$username, $domain,$cnum,$cdom); @@ -5330,7 +5562,8 @@ sub courserolelog { } sub domainrolelog { - my ($trole,$username,$domain,$area,$tstart,$tend,$delflag,$context)=@_; + my ($trole,$username,$domain,$area,$tstart,$tend,$delflag, + $context,$othdomby,$requester)=@_; if ($area =~ m{^/($match_domain)/$}) { my $cdom = $1; my $domconfiguser = &get_domainconfiguser($cdom); @@ -5341,6 +5574,16 @@ sub domainrolelog { end => $tend, context => $context, ); + if ($othdomby) { + if ($othdomby eq 'othdombydc') { + $storehash{'approval'} = 'domain'; + } elsif ($othdomby eq 'othdombyuser') { + $storehash{'approval'} = 'user'; + } + if ($requester ne '') { + $storehash{'requester'} = $requester; + } + } &write_log('domain',$namespace,\%storehash,$delflag,$username, $domain,$domconfiguser,$cdom); } @@ -5349,7 +5592,8 @@ sub domainrolelog { } sub coauthorrolelog { - my ($trole,$username,$domain,$area,$tstart,$tend,$delflag,$context)=@_; + my ($trole,$username,$domain,$area,$tstart,$tend,$delflag, + $context,$othdomby,$requester)=@_; if ($area =~ m{^/($match_domain)/($match_username)$}) { my $audom = $1; my $auname = $2; @@ -5360,6 +5604,16 @@ sub coauthorrolelog { end => $tend, context => $context, ); + if ($othdomby) { + if ($othdomby eq 'othdombydc') { + $storehash{'approval'} = 'domain'; + } elsif ($othdomby eq 'othdombyuser') { + $storehash{'approval'} = 'user'; + } + if ($requester ne '') { + $storehash{'requester'} = $requester; + } + } &write_log('author',$namespace,\%storehash,$delflag,$username, $domain,$auname,$audom); } @@ -6740,7 +6994,7 @@ sub rolesinit { my %firstaccess = &dump('firstaccesstimes', $domain, $username); my %timerinterval = &dump('timerinterval', $domain, $username); my (%coursetimerstarts, %firstaccchk, %firstaccenv, %coursetimerintervals, - %timerintchk, %timerintenv); + %timerintchk, %timerintenv, %coauthorenv); foreach my $key (keys(%firstaccess)) { my ($cid, $rest) = split(/\0/, $key); @@ -6754,6 +7008,8 @@ sub rolesinit { my %allroles=(); my %allgroups=(); + my %gotcoauconfig=(); + my %domdefaults=(); for my $area (grep { ! /^rolesdef_/ } keys(%rolesdump)) { my $role = $rolesdump{$area}; @@ -6805,6 +7061,37 @@ sub rolesinit { } else { # Normal role, defined in roles.tab &standard_roleprivs(\%allroles,$trole,$tdomain,$spec,$trest,$area); + if (($trole eq 'ca') || ($trole eq 'aa')) { + (undef,my ($audom,$auname)) = split(/\//,$area); + unless ($gotcoauconfig{$area}) { + my @ca_settings = ('authoreditors','coauthorlist','coauthoroptin'); + my %info = &userenvironment($audom,$auname,@ca_settings); + $gotcoauconfig{$area} = 1; + foreach my $item (@ca_settings) { + if (exists($info{$item})) { + my $name = $item; + if ($item eq 'authoreditors') { + $name = 'editors'; + unless ($info{'authoreditors'}) { + my %domdefs; + if (ref($domdefaults{$audom}) eq 'HASH') { + %domdefs = %{$domdefaults{$audom}}; + } else { + %domdefs = &get_domain_defaults($audom); + $domdefaults{$audom} = \%domdefs; + } + if ($domdefs{$name} ne '') { + $info{'authoreditors'} = $domdefs{$name}; + } else { + $info{'authoreditors'} = 'edit,xml'; + } + } + } + $coauthorenv{"environment.internal.$name.$area"} = $info{$item}; + } + } + } + } } my $cid = $tdomain.'_'.$trest; @@ -6833,7 +7120,7 @@ sub rolesinit { $env{'user.adv'} = $userroles{'user.adv'}; $env{'user.rar'} = $userroles{'user.rar'}; - return (\%userroles,\%firstaccenv,\%timerintenv); + return (\%userroles,\%firstaccenv,\%timerintenv,\%coauthorenv); } sub set_arearole { @@ -7727,7 +8014,7 @@ sub portfolio_access { } sub get_portfolio_access { - my ($udom,$unum,$file_name,$group,$clientip,$access_hash) = @_; + my ($udom,$unum,$file_name,$group,$clientip,$access_hash,$portaccessref) = @_; if (!ref($access_hash)) { my $current_perms = &get_portfile_permissions($udom,$unum); @@ -7736,11 +8023,19 @@ sub get_portfolio_access { $access_hash = $access_controls{$file_name}; } - my ($public,$guest,@domains,@users,@courses,@groups,@ips); + my $portaccess; + if (ref($portaccess) eq 'SCALAR') { + $portaccess = $$portaccessref; + } else { + $portaccess = &usertools_access($unum,$udom,'portaccess',undef,'tools'); + } + + my ($public,$guest,@domains,@users,@courses,@groups,@ips,@userips); my $now = time; if (ref($access_hash) eq 'HASH') { foreach my $key (keys(%{$access_hash})) { my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/); + next if (($scope ne 'ip') && ($portaccess == 0)); if ($start > $now) { next; } @@ -7762,6 +8057,8 @@ sub get_portfolio_access { push(@groups,$key); } elsif ($scope eq 'ip') { push(@ips,$key); + } elsif ($scope eq 'userip') { + push(@userips,$key); } } if ($public) { @@ -7779,6 +8076,19 @@ sub get_portfolio_access { if ($allowed) { return 'ok'; } + } elsif (@userips > 0) { + my $allowed; + foreach my $useripkey (@userips) { + if (ref($access_hash->{$useripkey}{'ip'}) eq 'ARRAY') { + if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$useripkey}{'ip'}}),$clientip)) { + $allowed = 1; + last; + } + } + } + if ($allowed) { + return 'ok'; + } } if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { if ($guest) { @@ -7954,6 +8264,17 @@ sub is_portfolio_file { return; } +sub is_coursetool_logo { + my ($uri) = @_; + if ($env{'request.course.id'}) { + my $courseurl = &courseid_to_courseurl($env{'request.course.id'}); + if ($uri =~ m{^/*uploaded\Q$courseurl\E/toollogo/\d+/[^/]+$}) { + return 1; + } + } + return; +} + sub usertools_access { my ($uname,$udom,$tool,$action,$context,$userenvref,$domdefref,$is_advref)=@_; my ($access,%tools); @@ -7973,12 +8294,16 @@ sub usertools_access { %tools = ( requestauthor => 1, ); + } elsif ($context eq 'authordefaults') { + %tools = ( + webdav => 1, + ); } else { %tools = ( aboutme => 1, blog => 1, - webdav => 1, portfolio => 1, + portaccess => 1, timezone => 1, ); } @@ -7995,6 +8320,10 @@ sub usertools_access { return $env{'environment.canrequest.'.$tool}; } elsif ($context eq 'requestauthor') { return $env{'environment.canrequest.author'}; + } elsif ($context eq 'authordefaults') { + if ($tool eq 'webdav') { + return $env{'environment.availabletools.'.$tool}; + } } else { return $env{'environment.availabletools.'.$tool}; } @@ -8003,7 +8332,11 @@ sub usertools_access { my ($toolstatus,$inststatus,$envkey); if ($context eq 'requestauthor') { - $envkey = $context; + $envkey = $context; + } elsif ($context eq 'authordefaults') { + if ($tool eq 'webdav') { + $envkey = 'tools.'.$tool; + } } else { $envkey = $context.'.'.$tool; } @@ -8115,7 +8448,8 @@ sub is_course_owner { } sub is_advanced_user { - my ($udom,$uname) = @_; + my ($udom,$uname,$nocache) = @_; + my ($is_adv,$is_author,$use_cache,$hashid); if ($udom ne '' && $uname ne '') { if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) { if (wantarray) { @@ -8123,11 +8457,21 @@ sub is_advanced_user { } else { return $env{'user.adv'}; } + } elsif (!$nocache) { + $use_cache = 1; + $hashid = "$udom:$uname"; + my ($info,$cached)=&is_cached_new('isadvau',$hashid); + if ($cached) { + ($is_adv,$is_author) = split(/:/,$info); + if (wantarray) { + return ($is_adv,$is_author); + } + return $is_adv; + } } } my %roleshash = &get_my_roles($uname,$udom,'userroles',undef,undef,undef,1); my %allroles; - my ($is_adv,$is_author); foreach my $role (keys(%roleshash)) { my ($trest,$tdomain,$trole,$sec) = split(/:/,$role); my $area = '/'.$tdomain.'/'.$trest; @@ -8158,6 +8502,10 @@ sub is_advanced_user { } } } + if ($use_cache) { + my $cachetime = 600; + &do_cache_new('isadvau',$hashid,$is_adv.':'.$is_author,$cachetime); + } if (wantarray) { return ($is_adv,$is_author); } @@ -8562,7 +8910,7 @@ sub allowed { # If this is generating or modifying users, exit with special codes - if (':csu:cdc:ccc:cin:cta:cep:ccr:cst:cad:cli:cau:cdg:cca:caa:'=~/\:\Q$priv\E\:/) { + if (':csu:cdc:ccc:cin:cta:cep:ccr:cst:cad:cli:cau:cdg:cca:caa:vca:vaa:'=~/\:\Q$priv\E\:/) { if (($priv eq 'cca') || ($priv eq 'caa')) { my ($audom,$auname)=split('/',$uri); # no author name given, so this just checks on the general right to make a co-author in this domain @@ -8571,6 +8919,13 @@ sub allowed { if (($auname ne $env{'user.name'} && $env{'request.role'} !~ /^dc\./) || (($audom ne $env{'user.domain'} && $env{'request.role'} !~ /^dc\./) && ($audom ne $env{'request.role.domain'}))) { return ''; } + } elsif (($priv eq 'vca') || ($priv eq 'vaa')) { + my ($audom,$auname)=split('/',$uri); + unless ($auname) { return $thisallowed; } + unless (($env{'request.role'} eq "dc./$audom") || + ($env{'request.role'} eq "ca./$uri")) { + return ''; + } } return $thisallowed; } @@ -8582,6 +8937,12 @@ sub allowed { if ($env{'request.course.id'}) { + if ($priv eq 'bre') { + if (&is_coursetool_logo($uri)) { + return 'F'; + } + } + # If this is modifying password (internal auth) domains must match for user and user's role. if ($priv eq 'mip') { @@ -8902,22 +9263,41 @@ sub constructaccess { if (exists($env{'user.priv.au./'.$ownerdomain.'/./'})) { return ($ownername,$ownerdomain,$ownerhome); } - } else { -# Co-author for this? - if (exists($env{'user.priv.ca./'.$ownerdomain.'/'.$ownername.'./'}) || - exists($env{'user.priv.aa./'.$ownerdomain.'/'.$ownername.'./'}) ) { - $ownerhome = &homeserver($ownername,$ownerdomain); - return ($ownername,$ownerdomain,$ownerhome); - } + } elsif (&is_course($ownerdomain,$ownername)) { +# Course Authoring Space? if ($env{'request.course.id'}) { if (($ownername eq $env{'course.'.$env{'request.course.id'}.'.num'}) && ($ownerdomain eq $env{'course.'.$env{'request.course.id'}.'.domain'})) { if (&allowed('mdc',$env{'request.course.id'})) { + return if ($env{'course.'.$env{'request.course.id'}.'.internal.crsauthor'} eq '0'); + unless ($env{'course.'.$env{'request.course.id'}.'.internal.crsauthor'}) { + my %domdefs = &get_domain_defaults($ownerdomain); + my $type = lc($env{'course.'.$env{'request.course.id'}.'.type'}); + unless (($type eq 'community') || ($type eq 'placement')) { + $type = 'unofficial'; + if ($env{'course.'.$env{'request.course.id'}.'internal.coursecode'} ne '') { + $type = 'official'; + } elsif ($env{'course.'.$env{'request.course.id'}.'internal.textbook'} ne '') { + $type = 'textbook'; + } else { + $type = 'unofficial'; + } + } + return if ($domdefs{$type.'crsauthor'} eq '0'); + } $ownerhome = $env{'course.'.$env{'request.course.id'}.'.home'}; return ($ownername,$ownerdomain,$ownerhome); } } } + return ''; + } else { +# Co-author for this? + if (exists($env{'user.priv.ca./'.$ownerdomain.'/'.$ownername.'./'}) || + exists($env{'user.priv.aa./'.$ownerdomain.'/'.$ownername.'./'}) ) { + $ownerhome = &homeserver($ownername,$ownerdomain); + return ($ownername,$ownerdomain,$ownerhome); + } } # We don't have any access right now. If we are not possibly going to do anything about this, @@ -10196,11 +10576,13 @@ sub toggle_coursegroup_status { } sub modify_group_roles { - my ($cdom,$cnum,$group_id,$user,$end,$start,$userprivs,$selfenroll,$context) = @_; + my ($cdom,$cnum,$group_id,$user,$end,$start,$userprivs,$selfenroll,$context, + $othdomby,$requester) = @_; my $url = '/'.$cdom.'/'.$cnum.'/'.$group_id; my $role = 'gr/'.&escape($userprivs); my ($uname,$udom) = split(/:/,$user); - my $result = &assignrole($udom,$uname,$url,$role,$end,$start,'',$selfenroll,$context); + my $result = &assignrole($udom,$uname,$url,$role,$end,$start,'',$selfenroll,$context, + $othdomby,$requester); if ($result eq 'ok') { &devalidate_getgroups_cache($udom,$uname,$cdom,$cnum); } @@ -10328,43 +10710,66 @@ sub plaintext { sub assignrole { my ($udom,$uname,$url,$role,$end,$start,$deleteflag,$selfenroll, - $context)=@_; - my $mrole; + $context,$othdomby,$requester,$reqsec,$reqrole)=@_; + my ($mrole,$rolelogcontext); if ($role =~ /^cr\//) { my $cwosec=$url; $cwosec=~s/^\/($match_domain)\/($match_courseid)\/.*/$1\/$2/; - unless (&allowed('ccr',$cwosec)) { - my $refused = 1; - if ($context eq 'requestcourses') { - if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) { - if ($role =~ m{^cr/($match_domain)/($match_username)/([^/]+)$}) { - if (($1 eq $env{'user.domain'}) && ($2 eq $env{'user.name'})) { - my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); - my %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); - if ($crsenv{'internal.courseowner'} eq - $env{'user.name'}.':'.$env{'user.domain'}) { - $refused = ''; - } - } - } - } - } - if ($refused) { - &logthis('Refused custom assignrole: '. - $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start. - ' by '.$env{'user.name'}.' at '.$env{'user.domain'}); - return 'refused'; - } + if ((!&allowed('ccr',$cwosec)) && (!&allowed('ccr',$udom))) { + my $refused = 1; + if ($context eq 'requestcourses') { + if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) { + if ($role =~ m{^cr/($match_domain)/($match_username)/([^/]+)$}) { + if (($1 eq $env{'user.domain'}) && ($2 eq $env{'user.name'})) { + my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); + my %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); + if ($crsenv{'internal.courseowner'} eq + $env{'user.name'}.':'.$env{'user.domain'}) { + $refused = ''; + } + } + } + } + } elsif (($context eq 'course') && ($othdomby eq 'othdombyuser')) { + my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); + my ($sec) = ($url =~ m{^/\Q$cwosec\E/(.*)$}); + my $key = "$uname:$udom:$role:$sec"; + my %queuedrolereq = &Apache::lonnet::get('nohist_othdomqueued',[$key],$cdom,$cnum); + if ((exists($queuedrolereq{$key})) && (ref($queuedrolereq{$key}) eq 'HASH')) { + if (($queuedrolereq{$key}{'adj'} eq 'user') && ($queuedrolereq{$key}{'requester'} eq $requester)) { + $refused = ''; + } + } + } + if ($refused) { + &logthis('Refused custom assignrole: '. + $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start. + ' by '.$env{'user.name'}.' at '.$env{'user.domain'}); + return 'refused'; + } } $mrole='cr'; } elsif ($role =~ /^gr\//) { my $cwogrp=$url; $cwogrp=~s{^/($match_domain)/($match_courseid)/.*}{$1/$2}; - unless (&allowed('mdg',$cwogrp)) { - &logthis('Refused group assignrole: '. - $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '. - $env{'user.name'}.' at '.$env{'user.domain'}); - return 'refused'; + if (!&allowed('mdg',$cwogrp)) { + my $refused = 1; + if (($refused) && ($othdomby eq 'othdombyuser') && ($requester ne '') && ($reqrole ne '')) { + my ($cdom,$cnum) = ($cwogrp =~ m{^/?($match_domain)/($match_courseid)$}); + my $key = "$uname:$udom:$reqrole:$reqsec"; + my %queuedrolereq = &Apache::lonnet::get('nohist_othdomqueued',[$key],$cdom,$cnum); + if ((exists($queuedrolereq{$key})) && (ref($queuedrolereq{$key}) eq 'HASH')) { + if (($queuedrolereq{$key}{'adj'} eq 'user') && ($queuedrolereq{$key}{'requester'} eq $requester)) { + $refused = ''; + } + } + } + if ($refused) { + &logthis('Refused group assignrole: '. + $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '. + $env{'user.name'}.' at '.$env{'user.domain'}); + return 'refused'; + } } $mrole='gr'; } else { @@ -10381,7 +10786,8 @@ sub assignrole { } if ($refused) { my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); - if (!$selfenroll && (($context eq 'course') || ($context eq 'ltienroll' && $env{'request.lti.login'}))) { + if (!$selfenroll && ($othdomby ne 'othdombyuser') && + (($context eq 'course') || ($context eq 'ltienroll' && $env{'request.lti.login'}))) { my %crsenv; if ($role eq 'cc' || $role eq 'co') { %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); @@ -10407,6 +10813,49 @@ sub assignrole { } elsif (($context eq 'ltienroll') && ($env{'request.lti.login'})) { $refused = ''; } + } elsif ($othdomby eq 'othdombyuser') { + my ($key,%queuedrolereq); + if ($context eq 'course') { + my ($sec) = ($url =~ m{^/\Q$cwosec\E/(.*)$}); + $key = "$uname:$udom:$role:$sec"; + %queuedrolereq = &Apache::lonnet::get('nohist_othdomqueued',[$key],$cdom,$cnum); + if ((exists($queuedrolereq{$key})) && (ref($queuedrolereq{$key}) eq 'HASH')) { + if (($queuedrolereq{$key}{'adj'} eq 'user') && ($queuedrolereq{$key}{'requester'} eq $requester)) { + if ((($role eq 'cc') && ($cnum !~ /^$match_community$/)) || + (($role eq 'co') && ($cnum =~ /^$match_community$/))) { + my %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); + if ($crsenv{'internal.courseowner'} eq $requester) { + $refused = ''; + } + } elsif ($role =~ /^(?:in|ta|ep|st)$/) { + $refused = ''; + } + } + } + } elsif (($context eq 'author') && ($role =~ /^ca|aa$/)) { + my $key = "$uname:$udom:$role"; + my ($audom,$auname) = ($url =~ m{^/($match_domain)/($match_username)$}); + if (($audom ne '') && ($auname ne '')) { + my %queuedrolereq = &Apache::lonnet::get('nohist_othdomqueued',[$key],$audom,$auname); + if ((exists($queuedrolereq{$key})) && (ref($queuedrolereq{$key}) eq 'HASH')) { + if (($queuedrolereq{$key}{'adj'} eq 'user') && ($queuedrolereq{$key}{'requester'} eq $requester)) { + $refused = ''; + } + } + } + } elsif (($context eq 'domain') && ($role ne 'dc') && ($role ne 'su')) { + my $key = "$uname:$udom:$role"; + my ($roledom) = ($url =~ m{^/($match_domain)/\Q$role\E$}); + if ($roledom ne '') { + my $confname = $roledom.'-domainconfig'; + my %queuedrolereq = &Apache::lonnet::get('nohist_othdomqueued',[$key],$roledom,$confname); + if ((exists($queuedrolereq{$key})) && (ref($queuedrolereq{$key}) eq 'HASH')) { + if (($queuedrolereq{$key}{'adj'} eq 'user') && ($queuedrolereq{$key}{'requester'} eq $requester)) { + $refused = ''; + } + } + } + } } elsif ($context eq 'requestcourses') { my @possroles = ('st','ta','ep','in','cc','co'); if ((grep(/^\Q$role\E$/,@possroles)) && ($env{'user.name'} ne '' && $env{'user.domain'} ne '')) { @@ -10459,6 +10908,15 @@ sub assignrole { } } } + } elsif (($context eq 'author') && (($role eq 'ca' || $role eq 'aa'))) { + if ($url =~ m{^/($match_domain)/($match_username)$}) { + my ($audom,$auname) = ($1,$2); + if ((&Apache::lonnet::allowed('v'.$role,"$audom/$auname")) && + ($env{"environment.internal.manager.$url"})) { + $refused = ''; + $rolelogcontext = 'coauthor'; + } + } } if ($refused) { &logthis('Refused assignrole: '.$udom.' '.$uname.' '.$url. @@ -10519,15 +10977,18 @@ sub assignrole { $origstart,$selfenroll,$context); } &courserolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag, - $selfenroll,$context); + $selfenroll,$context,$othdomby,$requester); } elsif (($role eq 'li') || ($role eq 'dg') || ($role eq 'sc') || ($role eq 'au') || ($role eq 'dc') || ($role eq 'dh') || ($role eq 'da')) { &domainrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag, - $context); + $context,$othdomby,$requester); } elsif (($role eq 'ca') || ($role eq 'aa')) { + if ($rolelogcontext eq '') { + $rolelogcontext = $context; + } &coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag, - $context); + $rolelogcontext,$othdomby,$requester); } if ($role eq 'cc') { &autoupdate_coowners($url,$end,$start,$uname,$udom); @@ -10879,7 +11340,7 @@ sub modifystudent { sub modify_student_enrollment { my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type, - $locktype,$cid,$selfenroll,$context,$credits,$instsec) = @_; + $locktype,$cid,$selfenroll,$context,$credits,$instsec,$othdomby,$requester) = @_; my ($cdom,$cnum,$chome); if (!$cid) { unless ($cid=$env{'request.course.id'}) { @@ -10940,7 +11401,7 @@ sub modify_student_enrollment { $uurl.='/'.$usec; } my $result = &assignrole($udom,$uname,$uurl,'st',$end,$start,undef, - $selfenroll,$context); + $selfenroll,$context,$othdomby,$requester); if ($result ne 'ok') { if ($old_entry{$user} ne '') { $reply = &cput('classlist',\%old_entry,$cdom,$cnum); @@ -11216,9 +11677,11 @@ sub store_userdata { # ---------------------------------------------------------- Assign Custom Role sub assigncustomrole { - my ($udom,$uname,$url,$rdom,$rnam,$rolename,$end,$start,$deleteflag,$selfenroll,$context)=@_; + my ($udom,$uname,$url,$rdom,$rnam,$rolename,$end,$start,$deleteflag, + $selfenroll,$context,$othdomby,$requester)=@_; return &assignrole($udom,$uname,$url,'cr/'.$rdom.'/'.$rnam.'/'.$rolename, - $end,$start,$deleteflag,$selfenroll,$context); + $end,$start,$deleteflag,$selfenroll,$context,$othdomby, + $requester); } # ----------------------------------------------------------------- Revoke Role @@ -12025,14 +12488,20 @@ sub stat_file { # or corresponding Published Resource Space, and populate the hash ref: # $dirhashref with URLs of all directories, and if $filehashref hash # ref arg is provided, the URLs of any files, excluding versioned, .meta, -# or .rights files in resource space, and .meta, .save, .log, and .bak -# files in Authoring Space. +# or .rights files in resource space, and .meta, .save, .log, .bak and +# .rights files in Authoring Space. # # Inputs: # # $is_home - true if current server is home server for user's space -# $context - either: priv, or res respectively for Authoring or Resource Space. -# $docroot - Document root (i.e., /home/httpd/html +# $recurse - if true will also traverse subdirectories recursively +# $include - reference to hash containing allowed file extensions. If provided, +# files which do not have a matching extension will be ignored. +# $exclude - reference to hash containing excluded file extensions. If provided, +# files which have a matching extension will be ignored. +# $nonemptydir - if true, will only populate $fileshashref hash entry for a particular +# directory with first file found (with acceptable extension). +# $addtopdir - if true, set $dirhashref->{'/'} = 1 # $toppath - Top level directory (i.e., /res/$dom/$uname or /priv/$dom/$uname # $relpath - Current path (relative to top level). # $dirhashref - reference to hash to populate with URLs of directories (Required) @@ -12049,39 +12518,61 @@ sub stat_file { # sub recursedirs { - my ($is_home,$context,$docroot,$toppath,$relpath,$dirhashref,$filehashref) = @_; + my ($is_home,$recurse,$include,$exclude,$nonemptydir,$addtopdir,$toppath,$relpath,$dirhashref,$filehashref) = @_; return unless (ref($dirhashref) eq 'HASH'); + my $docroot = $perlvar{'lonDocRoot'}; my $currpath = $docroot.$toppath; - if ($relpath) { + if ($relpath ne '') { $currpath .= "/$relpath"; } - my $savefile; + my ($savefile,$checkinc,$checkexc); if (ref($filehashref)) { $savefile = 1; } + if (ref($include) eq 'HASH') { + $checkinc = 1; + } + if (ref($exclude) eq 'HASH') { + $checkexc = 1; + } if ($is_home) { - if (opendir(my $dirh,$currpath)) { + if ((-e $currpath) && (opendir(my $dirh,$currpath))) { + my $filecount = 0; foreach my $item (sort { lc($a) cmp lc($b) } grep(!/^\.+$/,readdir($dirh))) { next if ($item eq ''); if (-d "$currpath/$item") { my $newpath; - if ($relpath) { + if ($relpath ne '') { $newpath = "$relpath/$item"; } else { $newpath = $item; } $dirhashref->{&Apache::lonlocal::js_escape($newpath)} = 1; - &recursedirs($is_home,$context,$docroot,$toppath,$newpath,$dirhashref,$filehashref); - } elsif ($savefile) { - if ($context eq 'priv') { - unless ($item =~ /\.(meta|save|log|bak|DS_Store)$/) { - $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1; - } - } else { - unless (($item =~ /\.meta$/) || ($item =~ /\.\d+\.\w+$/) || ($item =~ /\.rights$/)) { + if ($recurse) { + &recursedirs($is_home,$recurse,$include,$exclude,$nonemptydir,$addtopdir,$toppath,$newpath,$dirhashref,$filehashref); + } + } elsif (($savefile) || ($relpath eq '')) { + next if ($nonemptydir && $filecount); + if ($checkinc || $checkexc) { + my ($extension) = ($item =~ /\.(\w+)$/); + if ($checkinc) { + next unless ($extension && $include->{$extension}); + } + if ($checkexc) { + next if ($extension && $exclude->{$extension}); + } + } + if (($relpath eq '') && (!exists($dirhashref->{'/'}))) { + $dirhashref->{'/'} = 1; + } + if ($savefile) { + if ($relpath eq '') { + $filehashref->{'/'}{$item} = 1; + } else { $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1; } } + $filecount ++; } } closedir($dirh); @@ -12092,6 +12583,7 @@ sub recursedirs { my @dir_lines; my $dirptr=16384; if (ref($dirlistref) eq 'ARRAY') { + my $filecount = 0; foreach my $dir_line (sort { my ($afile)=split('&',$a,2); @@ -12107,28 +12599,57 @@ sub recursedirs { if ($relpath) { $newpath = "$relpath/$item"; } else { - $relpath = '/'; $newpath = $item; } $dirhashref->{&Apache::lonlocal::js_escape($newpath)} = 1; - &recursedirs($is_home,$context,$docroot,$toppath,$newpath,$dirhashref,$filehashref); - } elsif ($savefile) { - if ($context eq 'priv') { - unless ($item =~ /\.(meta|save|log|bak|DS_Store)$/) { - $filehashref->{$relpath}{$item} = 1; - } - } else { - unless (($item =~ /\.meta$/) || ($item =~ /\.\d+\.\w+$/)) { - $filehashref->{$relpath}{$item} = 1; + if ($recurse) { + &recursedirs($is_home,$recurse,$include,$exclude,$nonemptydir,$addtopdir,$toppath,$newpath,$dirhashref,$filehashref); + } + } elsif (($savefile) || ($relpath eq '')) { + next if ($nonemptydir && $filecount); + if ($checkinc || $checkexc) { + my $extension; + if ($checkinc) { + next unless ($extension && $include->{$extension}); + } + if ($checkexc) { + next if ($extension && $exclude->{$extension}); + } + } + if (($relpath eq '') && (!exists($dirhashref->{'/'}))) { + $dirhashref->{'/'} = 1; + } + if ($savefile) { + if ($relpath eq '') { + $filehashref->{'/'}{$item} = 1; + } else { + $filehashref->{&Apache::lonlocal::js_escape($relpath)}{$item} = 1; } } + $filecount ++; } } } } + if ($addtopdir) { + if (($relpath eq '') && (!exists($dirhashref->{'/'}))) { + $dirhashref->{'/'} = 1; + } + } return; } +sub priv_exclude { + return { + meta => 1, + save => 1, + log => 1, + bak => 1, + rights => 1, + DS_Store => 1, + }; +} + # -------------------------------------------------------- Value of a Condition # gets the value of a specific preevaluated condition @@ -12352,13 +12873,11 @@ sub get_domain_lti { } else { return %lti; } - if ($context eq 'linkprot') { $cachename = $context; } else { $cachename = $name; } - my ($result,$cached)=&is_cached_new($cachename,$cdom); if (defined($cached)) { if (ref($result) eq 'HASH') { @@ -12374,18 +12893,6 @@ sub get_domain_lti { } else { %lti = %{$domconfig{$name}}; } - if (($context eq 'consumer') && (keys(%lti))) { - my %encdomconfig = &get_dom('encconfig',[$name],$cdom,undef,1); - if (ref($encdomconfig{$name}) eq 'HASH') { - foreach my $id (keys(%lti)) { - if (ref($encdomconfig{$name}{$id}) eq 'HASH') { - foreach my $item ('key','secret') { - $lti{$id}{$item} = $encdomconfig{$name}{$id}{$item}; - } - } - } - } - } } my $cachetime = 24*60*60; &do_cache_new($cachename,$cdom,\%lti,$cachetime); @@ -12394,20 +12901,29 @@ sub get_domain_lti { } sub get_course_lti { - my ($cnum,$cdom) = @_; + my ($cnum,$cdom,$context) = @_; + my ($name,$cachename,%lti); + if ($context eq 'consumer') { + $name = 'ltitools'; + $cachename = 'courseltitools'; + } elsif ($context eq 'provider') { + $name = 'lti'; + $cachename = 'courselti'; + } else { + return %lti; + } my $hashid=$cdom.'_'.$cnum; - my %courselti; - my ($result,$cached)=&is_cached_new('courselti',$hashid); + my ($result,$cached)=&is_cached_new($cachename,$hashid); if (defined($cached)) { if (ref($result) eq 'HASH') { - %courselti = %{$result}; + %lti = %{$result}; } } else { - %courselti = &dump('lti',$cdom,$cnum,undef,undef,undef,1); + %lti = &dump($name,$cdom,$cnum,undef,undef,undef,1); my $cachetime = 24*60*60; - &do_cache_new('courselti',$hashid,\%courselti,$cachetime); + &do_cache_new($cachename,$hashid,\%lti,$cachetime); } - return %courselti; + return %lti; } sub courselti_itemid { @@ -12457,6 +12973,73 @@ sub domainlti_itemid { return $itemid; } +sub get_ltitools_id { + my ($context,$cdom,$cnum,$title) = @_; + my ($lockhash,$tries,$gotlock,$id,$error); + + # get lock on ltitools db + $lockhash = { + lock => $env{'user.name'}. + ':'.$env{'user.domain'}, + }; + $tries = 0; + if ($context eq 'domain') { + $gotlock = &newput_dom('ltitools',$lockhash,$cdom); + } else { + $gotlock = &newput('ltitools',$lockhash,$cdom,$cnum); + } + while (($gotlock ne 'ok') && ($tries<10)) { + $tries ++; + sleep (0.1); + if ($context eq 'domain') { + $gotlock = &newput_dom('ltitools',$lockhash,$cdom); + } else { + $gotlock = &newput('ltitools',$lockhash,$cdom,$cnum); + } + } + if ($gotlock eq 'ok') { + my %currids; + if ($context eq 'domain') { + %currids = &dump_dom('ltitools',$cdom); + } else { + %currids = &dump('ltitools',$cdom,$cnum); + } + if ($currids{'lock'}) { + delete($currids{'lock'}); + if (keys(%currids)) { + my @curr = sort { $a <=> $b } keys(%currids); + if ($curr[-1] =~ /^\d+$/) { + $id = 1 + $curr[-1]; + } + } else { + $id = 1; + } + if ($id) { + if ($context eq 'domain') { + unless (&newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') { + $error = 'nostore'; + } + } else { + unless (&newput('ltitools',{ $id => $title },$cdom,$cnum) eq 'ok') { + $error = 'nostore'; + } + } + } else { + $error = 'nonumber'; + } + } + my $dellockoutcome; + if ($context eq 'domain') { + $dellockoutcome = &del_dom('ltitools',['lock'],$cdom); + } else { + $dellockoutcome = &del('ltitools',['lock'],$cdom,$cnum); + } + } else { + $error = 'nolock'; + } + return ($id,$error); +} + sub count_supptools { my ($cnum,$cdom,$ignorecache,$reload)=@_; my $hashid=$cnum.':'.$cdom; @@ -12468,7 +13051,7 @@ sub count_supptools { my $chome=&homeserver($cnum,$cdom); $numexttools = 0; unless ($chome eq 'no_host') { - my ($supplemental) = &get_supplemental($cnum,$cdom,$reload); + my ($supplemental) = &Apache::loncommon::get_supplemental($cnum,$cdom,$reload); if (ref($supplemental) eq 'HASH') { if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) { foreach my $key (keys(%{$supplemental->{'ids'}})) { @@ -12485,7 +13068,7 @@ sub count_supptools { } sub has_unhidden_suppfiles { - my ($cnum,$cdom,$ignorecache,$possdell)=@_; + my ($cnum,$cdom,$ignorecache,$possdel)=@_; my $hashid=$cnum.':'.$cdom; my ($showsupp,$cached); unless ($ignorecache) { @@ -12494,7 +13077,7 @@ sub has_unhidden_suppfiles { unless (defined($cached)) { my $chome=&homeserver($cnum,$cdom); unless ($chome eq 'no_host') { - my ($supplemental) = &get_supplemental($cnum,$cdom,$ignorecache,$possdel); + my ($supplemental) = &Apache::loncommon::get_supplemental($cnum,$cdom,$ignorecache,$possdel); if (ref($supplemental) eq 'HASH') { if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) { foreach my $key (keys(%{$supplemental->{'ids'}})) { @@ -12517,35 +13100,6 @@ sub has_unhidden_suppfiles { return $showsupp; } -sub get_supplemental { - my ($cnum,$cdom,$ignorecache,$possdel)=@_; - my $hashid=$cnum.':'.$cdom; - my ($supplemental,$cached,$set_httprefs); - unless ($ignorecache) { - ($supplemental,$cached) = &is_cached_new('supplemental',$hashid); - } - unless (defined($cached)) { - my $chome=&homeserver($cnum,$cdom); - unless ($chome eq 'no_host') { - my ($errors,%ids,%hidden); - $errors = - &Apache::loncommon::recurse_supplemental($cnum,$cdom, - 'supplemental.sequence', - $errors,$possdel,\%ids,\%hidden); - $set_httprefs = 1; - if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { - &Apache::lonnet::appenv({'request.course.suppupdated' => time}); - } - $supplemental = { - ids => \%ids, - hidden => \%hidden, - }; - &do_cache_new('supplemental',$hashid,$supplemental,600); - } - } - return ($supplemental,$set_httprefs); -} - # # EXT resource caching routines #