--- loncom/interface/lonuserutils.pm 2022/11/23 02:55:37 1.212 +++ loncom/interface/lonuserutils.pm 2022/12/01 01:28:26 1.213 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Utility functions for managing LON-CAPA user accounts # -# $Id: lonuserutils.pm,v 1.212 2022/11/23 02:55:37 raeburn Exp $ +# $Id: lonuserutils.pm,v 1.213 2022/12/01 01:28:26 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -215,12 +215,13 @@ sub get_instdoms { sub restricted_dom { my ($context,$key,$udom,$uname,$role,$start,$end,$cdom,$cnum,$csec,$credits, $process_by,$instdoms,$got_role_approvals,$got_instdoms,$reject,$pending, - $notifydc) = @_; + $notifydc,$status,$unauthorized,$currqueued) = @_; return if ($udom eq $cdom); return unless ((ref($process_by) eq 'HASH') && (ref($instdoms) eq 'HASH') && (ref($got_role_approvals) eq 'HASH') && (ref($got_instdoms) eq 'HASH') && (ref($reject) eq 'HASH') && (ref($pending) eq 'HASH') && - (ref($notifydc) eq 'HASH')); + (ref($notifydc) eq 'HASH') && (ref($status) eq 'HASH') && + (ref($unauthorized) eq 'HASH') && (ref($currqueued) eq 'HASH')); my (%approval,@notify,$gotdata,$skip); if (ref($got_role_approvals->{$context}) eq 'HASH') { if ($got_role_approvals->{$context}{$udom}) { @@ -255,62 +256,126 @@ sub restricted_dom { if (grep(/^\Q$cdom\E$/,@inst)) { if (exists($approval{'instdom'})) { my $rule = $approval{'instdom'}; - if ($rule eq 'none') { - $reject->{$key} = { - cdom => $cdom, - cnum => $cnum, - csec => $csec, - udom => $udom, - uname => $uname, - role => $role, - }; - $skip = 1; - } elsif (($rule eq 'user') || ($rule eq 'domain')) { - $pending->{$key} = { - cdom => $cdom, - cnum => $cnum, - csec => $csec, - udom => $udom, - uname => $uname, - role => $role, - start => $start, - end => $end, - adj => $rule, - }; - if (($role eq 'st') && ($credits ne '')) { - $pending->{$key}->{'credits'} = $credits; + if (($rule eq 'none') || ($rule eq 'user') || ($rule eq 'domain')) { + my ($id,$currstatus,$curradj) = &get_othdomreq_status($key,$uname,$udom,$role,$cdom,$cnum,$csec); + if (($currstatus ne '') && ($curradj eq $rule)) { + $status->{$key}->{$uname.':'.$udom} = $currstatus; + } + if ($rule eq 'none') { + $reject->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + }; + $skip = 1; + } elsif (($rule eq 'user') || ($rule eq 'domain')) { + if ($curradj eq $rule) { + unless ($currstatus eq 'approved') { + if ($currstatus eq 'rejected') { + $unauthorized->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + }; + } elsif ($currstatus eq 'pending') { + $currqueued->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + adj => $rule, + }; + } + $skip = 1; + } + } else { + $pending->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + start => $start, + end => $end, + adj => $rule, + }; + if (($role eq 'st') && ($credits ne '')) { + $pending->{$key}->{$uname.':'.$udom}->{'credits'} = $credits; + } + $skip = 1; + } } - $skip = 1; } } } elsif (exists($approval{'extdom'})) { my $rule = $approval{'extdom'}; - if ($rule eq 'none') { - $reject->{$key} = { - cdom => $cdom, - cnum => $cnum, - csec => $csec, - udom => $udom, - uname => $uname, - role => $role, - }; - $skip = 1; - } elsif (($rule eq 'user') || ($rule eq 'domain')) { - $pending->{$key} = { - cdom => $cdom, - cnum => $cnum, - csec => $csec, - udom => $udom, - uname => $uname, - role => $role, - start => $start, - end => $end, - adj => $rule, - }; - if (($role eq 'st') && ($credits ne '')) { - $pending->{$key}->{'credits'} = $credits; + if (($rule eq 'none') || ($rule eq 'user') || ($rule eq 'domain')) { + my ($id,$currstatus,$curradj) = &get_othdomreq_status($key,$uname,$udom,$role,$cdom,$cnum,$csec); + if (($currstatus ne '') && ($curradj eq $rule)) { + $status->{$key}->{$uname.':'.$udom} = $currstatus; + } + if ($rule eq 'none') { + $reject->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + }; + $skip = 1; + } elsif (($rule eq 'user') || ($rule eq 'domain')) { + if ($curradj eq $rule) { + unless ($currstatus eq 'approved') { + if ($currstatus eq 'rejected') { + $unauthorized->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + }; + } elsif ($currstatus eq 'pending') { + $currqueued->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + adj => $rule, + }; + } + $skip = 1; + } + } else { + $pending->{$key}->{$uname.':'.$udom} = { + cdom => $cdom, + cnum => $cnum, + csec => $csec, + udom => $udom, + uname => $uname, + role => $role, + start => $start, + end => $end, + adj => $rule, + }; + if (($role eq 'st') && ($credits ne '')) { + $pending->{$key}->{$uname.':'.$udom}->{'credits'} = $credits; + } + $skip = 1; + } } - $skip = 1; } } } @@ -318,53 +383,130 @@ sub restricted_dom { return $skip; } +sub get_othdomreq_status { + my ($key,$uname,$udom,$role,$cdom,$cnum,$csec) = @_; + my $id = $uname.':'.$udom.':'.$role; + my ($dbnum,$currstatus,$curradj); + if (($role eq 'ca') || ($role eq 'aa')) { + $dbnum = $cnum; + } elsif ($key eq $cdom.'_'.$role) { + $dbnum = &Apache::lonnet::get_domainconfiguser($cdom); + } else { + $id .= ':'.$csec; + $dbnum = $cnum; + } + my $statusid = 'status&'.$id; + my %curr = &Apache::lonnet::get('nohist_othdomqueued',[$id,$statusid],$cdom,$dbnum); + if (ref($curr{$id}) eq 'HASH') { + $curradj = $curr{$id}{'adj'}; + } + $currstatus = $curr{$statusid}; + return ($id,$currstatus,$curradj); +} + sub print_roles_rejected { - my ($context,$reject) = @_; - return unless (ref($reject) eq 'HASH'); + my ($context,$reject,$unauthorized) = @_; + return unless ((ref($reject) eq 'HASH') || (ref($unauthorized) eq 'HASH')); my $output; if (keys(%{$reject}) > 0) { $output = '

'. &mt("The following roles could not be assigned because the user is from another domain, and that domain's policies disallow it").'

'; } + if (keys(%{$unauthorized}) > 0) { + $output = '

'. + &mt("The following roles could not be assigned because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain, and approval has been withheld.").'

'; + } return $output; } sub print_roles_queued { - my ($context,$pending,$notifydc) = @_; - return unless ((ref($pending) eq 'HASH') && (ref($notifydc) eq 'HASH')); + my ($context,$pending,$notifydc,$currqueued) = @_; + return unless ((ref($pending) eq 'HASH') && (ref($notifydc) eq 'HASH') && + (ref($currqueued) eq 'HASH')); my $output; if (keys(%{$pending}) > 0) { my $now = time; @@ -374,83 +516,100 @@ sub print_roles_queued { my $requester = $env{'user.name'}.':'.$env{'user.domain'}; foreach my $key (sort(keys(%{$pending}))) { if (ref($pending->{$key}) eq 'HASH') { - my $role = $pending->{$key}{'role'}; - my $uname = $pending->{$key}{'uname'}; - my $udom = $pending->{$key}{'udom'}; - my $csec = $pending->{$key}{'csec'}; - my $cdom = $pending->{$key}{'cdom'}; - my $cnum = $pending->{$key}{'cnum'}; - my $adj = $pending->{$key}{'adj'}; - my $start = $pending->{$key}{'start'}; - my $end = $pending->{$key}{'end'}; - my $credits = $pending->{$key}{'credits'}; - my $now = time; - my ($crstype,$title); - if ($context eq 'course') { - $crstype = &Apache::loncommon::course_type(); - } elsif ($context eq 'domain') { - if (&Apache::lonnet::is_course($cdom,$cnum)) { - my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum); - $crstype = $coursedata{'type'}; - $title = $coursedata{'description'}; - } elsif (($role eq 'ca') || ($role eq 'aa')) { - $title = &Apache::loncommon::plainname($cnum,$cdom); - } - } - my $plainrole = &Apache::lonnet::plaintext($role,$crstype); - my $extent = "/$cdom/$cnum"; - $output .= '
  • '.&mt('User: [_1]',$uname).' | '. - &mt('Domain: [_1]',$udom).' | '. - &mt('Role: [_1]',$plainrole).' | '; - if ($crstype) { - if ($csec ne '') { - $output .= &mt('Section: [_1]',$csec).' | '; - $extent .= "/$csec"; - } - } - if ($adj eq 'user') { - $output .= '
    '.&mt('Message sent to user for approval'); - $touser{$uname.':'.$udom}{$extent.':'.$role} = { - timestamp => $now, - requester => $requester, - start => $start, - end => $end, - credits => $credits, - context => $context, - }; - } elsif ($adj eq 'domain') { - $output .= '
    '.&mt("Message sent to user's domain coordinator for approval"); - $todom{$udom}{$uname.':'.$extent.':'.$role} = { - timestamp => $now, - requester => $requester, - start => $start, - end => $end, - credits => $credits, - context => $context, - }; - } - $output .= '
  • '; - my $id = $uname.':'.$udom.':'.$role; - if (($context eq 'course') || ($crstype)) { - $id .= ':'.$csec; - $crsqueue{$cdom.'_'.$cnum}{$id} = { - timestamp => $now, - requester => $requester, - adj => $adj, - }; - } elsif (($context eq 'author') || - (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa')))) { - $caqueue{$cnum.':'.$cdom}{$id} = { - timestamp => $now, - requester => $requester, - adj => $adj, - }; - } elsif ($context eq 'domain') { - $domqueue{$id} = { - timestamp => $now, - requester => $requester, - adj => $adj, - }; + foreach my $user (sort(keys(%{$pending->{$key}}))) { + if (ref($pending->{$key}->{$user}) eq 'HASH') { + my $role = $pending->{$key}->{$user}{'role'}; + my $uname = $pending->{$key}->{$user}{'uname'}; + my $udom = $pending->{$key}->{$user}{'udom'}; + my $csec = $pending->{$key}->{$user}{'csec'}; + my $cdom = $pending->{$key}->{$user}{'cdom'}; + my $cnum = $pending->{$key}->{$user}{'cnum'}; + my $adj = $pending->{$key}->{$user}{'adj'}; + my $start = $pending->{$key}->{$user}{'start'}; + my $end = $pending->{$key}->{$user}{'end'}; + my $credits = $pending->{$key}->{$user}{'credits'}; + my $now = time; + my ($crstype,$title,$plainrole,$extent,$id,$status); + if ($context eq 'course') { + $crstype = &Apache::loncommon::course_type(); + $title = $env{'course.'.$env{'request.course.id'}.'.description'}; + } elsif ($context eq 'domain') { + if (&Apache::lonnet::is_course($cdom,$cnum)) { + my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum); + $crstype = $coursedata{'type'}; + $title = $coursedata{'description'}; + } elsif (($role eq 'ca') || ($role eq 'aa')) { + $title = &Apache::loncommon::plainname($cnum,$cdom); + } + } + $plainrole = &Apache::lonnet::plaintext($role,$crstype); + $extent = "/$cdom/$cnum"; + $id = $uname.':'.$udom.':'.$role; + if (($context eq 'course') || ($crstype)) { + $id .= ':'.$csec; + } + $output .= '
  • '.&mt('User: [_1]',$uname).' | '. + &mt('Domain: [_1]',$udom).' | '. + &mt('Role: [_1]',$plainrole); + if ($crstype) { + if ($csec ne'') { + $output .= ' | '.&mt('Section: [_1]',$csec); + } + } elsif (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa'))) { + $output .= ' | '.&mt('Authoring Space belonging to: [_1]',$title); + } + if (($context eq 'domain') && ($crstype)) { + $output .= ' | '.&mt("$crstype: [_1]",$title); + } + if (($crstype) && ($csec ne '')) { + $extent .= "/$csec"; + } + if ($adj eq 'user') { + $output .= '
    '.&mt('Message sent to user for approval'); + $touser{$uname.':'.$udom}{'pending:'.$extent.':'.$role} = { + timestamp => $now, + requester => $requester, + start => $start, + end => $end, + credits => $credits, + context => $context, + }; + } elsif ($adj eq 'domain') { + $output .= '
    '.&mt("Message sent to user's domain coordinator for approval"); + $todom{$udom}{'pending:'.$uname.':'.$extent.':'.$role} = { + timestamp => $now, + requester => $requester, + start => $start, + end => $end, + credits => $credits, + context => $context, + }; + } + $output .= '
  • '; + if (($context eq 'course') || ($crstype)) { + $crsqueue{$cdom.'_'.$cnum}{$id} = { + timestamp => $now, + requester => $requester, + adj => $adj, + }; + $crsqueue{$cdom.'_'.$cnum}{'status&'.$id} = 'pending'; + } elsif (($context eq 'author') || + (($context eq 'domain') && (($role eq 'ca') || ($role eq 'aa')))) { + $caqueue{$cnum.':'.$cdom}{$id} = { + timestamp => $now, + requester => $requester, + adj => $adj, + }; + $caqueue{$cnum.':'.$cdom}{'status&'.$id} = 'pending'; + } elsif ($context eq 'domain') { + $domqueue{$id} = { + timestamp => $now, + requester => $requester, + adj => $adj, + }; + $domqueue{'status&'.$id} = 'pending'; + } + } } } } @@ -458,7 +617,7 @@ sub print_roles_queued { if (keys(%touser)) { foreach my $key (keys(%touser)) { my ($uname,$udom) = split(/:/,$touser{$key}); - if (&Apache::lonnet::put('queuedrolereqs',$touser{$key},$udom,$uname) eq 'ok') { + if (&Apache::lonnet::put('nohist_queuedrolereqs',$touser{$key},$udom,$uname) eq 'ok') { my $owndomdesc = &Apache::lonnet::domain($udom); &Apache::loncoursequeueadmin::send_selfserve_notification($uname.':'.$udom, '','',$owndomdesc,$now,'othdomroleuser',$requester); @@ -469,7 +628,7 @@ sub print_roles_queued { foreach my $dom (keys(%todom)) { if (ref($todom{$dom}) eq 'HASH') { my $confname = &Apache::lonnet::get_domainconfiguser($dom); - if (&Apache::lonnet::put('queuedrolereqs',$todom{$dom},$dom,$confname) eq 'ok') { + if (&Apache::lonnet::put('nohist_queuedrolereqs',$todom{$dom},$dom,$confname) eq 'ok') { if (ref($notifydc->{$dom}) eq 'ARRAY') { if (@{$notifydc->{$dom}} > 0) { my $notifylist = join(',',@{$notifydc->{$dom}}); @@ -485,7 +644,7 @@ sub print_roles_queued { foreach my $key (keys(%crsqueue)) { my ($cdom,$cnum) = split(/_/,$key); if (ref($crsqueue{$key}) eq 'HASH') { - &Apache::lonnet::put('othdomqueued',$crsqueue{$key},$cdom,$cnum); + &Apache::lonnet::put('nohist_othdomqueued',$crsqueue{$key},$cdom,$cnum); } } } @@ -493,15 +652,59 @@ sub print_roles_queued { foreach my $key (keys(%caqueue)) { my ($auname,$audom) = split(/:/,$key); if (ref($caqueue{$key}) eq 'HASH') { - &Apache::lonnet::put('othdomqueued',$caqueue{$key},$audom,$auname); + &Apache::lonnet::put('nohist_othdomqueued',$caqueue{$key},$audom,$auname); } } } if (keys(%domqueue)) { my $confname = &Apache::lonnet::get_domainconfiguser($env{'request.role.domain'}); - &Apache::lonnet::put('othdomqueued',\%domqueue,$env{'request.role.domain'},$confname); + &Apache::lonnet::put('nohist_othdomqueued',\%domqueue,$env{'request.role.domain'},$confname); } } + if (keys(%{$currqueued}) > 0) { + $output = '

    '. + &mt("The following role assignments were already queued because the user is from another domain, and that domain's policies require approval by the user themselves or by a domain coordinator in that domain").'

    '; + } return $output; } @@ -4720,7 +4923,7 @@ sub upfile_drop_add { } $r->rflush; my (%got_role_approvals,%got_instdoms,%process_by,%instdoms, - %pending,%reject,%notifydc); + %pending,%reject,%notifydc,%status,%unauthorized,%currqueued); my %counts = ( user => 0, @@ -5262,7 +5465,7 @@ sub upfile_drop_add { next if (&restricted_dom($context,$item,$userdomain,$username,$role,$startdate, $enddate,$crsdom,$crsnum,$sec,$credits,\%process_by, \%instdoms,\%got_role_approvals,\%got_instdoms,\%reject, - \%pending,\%notifydc)); + \%pending,\%notifydc,\%status,\%unauthorized,\%currqueued)); } &modifystudent($userdomain,$username,$cid,$sec, $desiredhost,$context); @@ -5300,7 +5503,8 @@ sub upfile_drop_add { next if (&restricted_dom($context,$item,$userdomain,$username,$possrole, $startdate,$enddate,$crsdom,$crsnum,$sec, $credits,\%process_by,\%instdoms,\%got_role_approvals, - \%got_instdoms,\%reject,\%pending,\%notifydc)); + \%got_instdoms,\%reject,\%pending,\%notifydc, + \%status,\%unauthorized,\%currqueued)); } ($userres{$sec},$authres{$sec},$roleres{$sec},$idres{$sec}) = &modifyuserrole($context,$setting, @@ -5328,7 +5532,8 @@ sub upfile_drop_add { $item .= '_'.$possrole; next if (&restricted_dom($context,$item,$userdomain,$username,$possrole,$startdate,$enddate, $crsdom,$crsnum,$singlesec,$credits,\%process_by,\%instdoms, - \%got_role_approvals,\%got_instdoms,\%reject,\%pending,\%notifydc)); + \%got_role_approvals,\%got_instdoms,\%reject,\%pending,\%notifydc, + \%status,\%unauthorized,\%currqueued)); } ($userresult,$authresult,$roleresult,$idresult) = &modifyuserrole($context,$setting, @@ -5379,11 +5584,11 @@ sub upfile_drop_add { } $r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules)); $r->print(&passwdrule_alerts($domain,\%showpasswdrules)); - if (keys(%reject)) { - $r->print(&print_roles_rejected($context,\%reject)); + if ((keys(%reject)) || (keys(%unauthorized))) { + $r->print(&print_roles_rejected($context,\%reject,\%unauthorized)); } - if (keys(%pending)) { - $r->print(&print_roles_queued($context,\%pending,\%notifydc)); + if ((keys(%pending)) || (keys(%currqueued))) { + $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued)); } ##################################### # Display list of students to drop # @@ -5579,7 +5784,7 @@ sub update_user_list { $crstype = &Apache::loncommon::course_type(); } my (@changelist,%got_role_approvals,%got_instdoms,%process_by,%instdoms, - %pending,%reject,%notifydc); + %pending,%reject,%notifydc,%status,%unauthorized,%currqueued); if ($choice eq 'drop') { @changelist = &Apache::loncommon::get_env_multiple('form.droplist'); } else { @@ -5697,7 +5902,8 @@ sub update_user_list { if ($choice eq 'reenable') { next if (&restricted_dom($context,$id,$udom,$uname,$role,$now,$end,$cdom,$cnum, $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals, - \%got_instdoms,\%reject,\%pending,\%notifydc)); + \%got_instdoms,\%reject,\%pending,\%notifydc, + \%status,\%unauthorized,\%currqueued)); if ($role eq 'st') { $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { @@ -5708,7 +5914,8 @@ sub update_user_list { } elsif ($choice eq 'activate') { next if (&restricted_dom($context,$id,$udom,$uname,$role,$now,$end,$cdom,$cnum, $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals, - \%got_instdoms,\%reject,\%pending,\%notifydc)); + \%got_instdoms,\%reject,\%pending,\%notifydc, + \%status,\%unauthorized,\%currqueued)); if ($role eq 'st') { $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { @@ -5718,7 +5925,8 @@ sub update_user_list { } elsif ($choice eq 'chgdates') { next if (&restricted_dom($context,$id,$udom,$uname,$role,$start,$end,$cdom,$cnum, $sec,$credits,\%process_by,\%instdoms,\%got_role_approvals, - \%got_instdoms,\%reject,\%pending,\%notifydc)); + \%got_instdoms,\%reject,\%pending,\%notifydc, + \%status,\%unauthorized,\%currqueued)); if ($role eq 'st') { $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec); } else { @@ -5928,11 +6136,11 @@ sub update_user_list { $r->print(&make_dates_default($startdate,$enddate,$context,$crstype)); } } - if (keys(%reject)) { - $r->print(&print_roles_rejected($context,\%reject)); + if ((keys(%reject)) || (keys(%unauthorized))) { + $r->print(&print_roles_rejected($context,\%reject,\%unauthorized)); } - if (keys(%pending)) { - $r->print(&print_roles_queued($context,\%pending,\%notifydc)); + if ((keys(%pending)) || (keys(%currqueued))) { + $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued)); } my $linktext = &mt('Display User Lists'); if ($choice eq 'drop') {