--- loncom/lonnet/perl/lonnet.pm 2023/06/02 01:20:29 1.1511 +++ loncom/lonnet/perl/lonnet.pm 2023/06/20 14:03:57 1.1512 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1511 2023/06/02 01:20:29 raeburn Exp $ +# $Id: lonnet.pm,v 1.1512 2023/06/20 14:03:57 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -2757,7 +2757,7 @@ sub get_domain_defaults { 'coursecategories','ssl','autoenroll', 'trust','helpsettings','wafproxy', 'ltisec','toolsec','domexttool', - 'exttool'],$domain); + 'exttool','privacy'],$domain); my @coursetypes = ('official','unofficial','community','textbook','placement'); if (ref($domconfig{'defaults'}) eq 'HASH') { $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; @@ -2968,6 +2968,21 @@ sub get_domain_defaults { } } } + 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'}); + } + } + } &do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime); return %domdefaults; } @@ -5424,7 +5439,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; @@ -5437,6 +5453,16 @@ 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; @@ -5453,7 +5479,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); @@ -5464,6 +5491,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); } @@ -5472,7 +5509,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; @@ -5483,6 +5521,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); } @@ -8249,7 +8297,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) { @@ -8257,11 +8306,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; @@ -8292,6 +8351,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); } @@ -10339,11 +10402,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); } @@ -10471,43 +10536,66 @@ sub plaintext { sub assignrole { my ($udom,$uname,$url,$role,$end,$start,$deleteflag,$selfenroll, - $context)=@_; + $context,$othdomby,$requester,$reqsec,$reqrole)=@_; my $mrole; if ($role =~ /^cr\//) { my $cwosec=$url; $cwosec=~s/^\/($match_domain)\/($match_courseid)\/.*/$1\/$2/; 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 = ''; - } - } - } - } - } - if ($refused) { - &logthis('Refused custom assignrole: '. - $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start. - ' by '.$env{'user.name'}.' at '.$env{'user.domain'}); - return 'refused'; - } + 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 { @@ -10524,7 +10612,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')); @@ -10550,6 +10639,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 '')) { @@ -10662,15 +10794,15 @@ 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')) { &coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag, - $context); + $context,$othdomby,$requester); } if ($role eq 'cc') { &autoupdate_coowners($url,$end,$start,$uname,$udom); @@ -11022,7 +11154,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'}) { @@ -11083,7 +11215,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); @@ -11359,9 +11491,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