--- loncom/interface/lonuserutils.pm 2022/11/23 02:55:37 1.212 +++ loncom/interface/lonuserutils.pm 2023/12/07 04:47:00 1.220 @@ -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.220 2023/12/07 04:47:00 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -104,7 +104,7 @@ sub modifystudent { sub modifyuserrole { my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass, $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role, - $end,$start,$checkid,$inststatus) = @_; + $end,$start,$checkid,$inststatus,$emptyok) = @_; my ($scope,$userresult,$authresult,$roleresult,$idresult); if ($setting eq 'course' || $context eq 'course') { $scope = '/'.$cid; @@ -115,7 +115,11 @@ sub modifyuserrole { } elsif ($context eq 'domain') { $scope = '/'.$env{'request.role.domain'}.'/'; } elsif ($context eq 'author') { - $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'}; + if ($env{'request.role'} =~ m{^ca\.(/$match_domain/$match_username)$}) { + $scope = $1; + } else { + $scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'}; + } } if ($context eq 'domain') { my $uhome = &Apache::lonnet::homeserver($uname,$udom); @@ -135,6 +139,25 @@ sub modifyuserrole { generation => $gene, id => $uid, ); + + # When "Update ID in user's course(s)" and "Force change of existing ID" + # checkboxes both checked, prevent replacement of name information + # in classlist.db file(s) for the user's course(s) with blank(s), + # in the case where the uploaded csv file was without column(s) for + # the particular field. Fields are: First Name, Middle Names/Initials, + # Last Name (or the composite: Last Name, First Names), and Generation. + + my %emptyallowed; + if ((ref($emptyok) eq 'HASH') && (keys(%{$emptyok}) > 0)) { + %emptyallowed = %{$emptyok}; + } + foreach my $field (keys(%userupdate)) { + if ($userupdate{$field} eq '') { + unless ($emptyallowed{$field}) { + delete($userupdate{$field}); + } + } + } $idresult = &propagate_id_change($uname,$udom,\%userupdate); } } @@ -215,12 +238,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 +279,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 +406,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,91 +539,108 @@ 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'; + } + } } } } $output .= '

    '; 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') { + my ($uname,$udom) = split(/:/,$key); + 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 +651,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 +667,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,14 +675,58 @@ 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; } @@ -862,7 +1088,7 @@ END "; } elsif ($mode eq 'modifycourse') { $auth_checks .= " - if (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') { + if ((current.argfield !== null) && (current.argfield !== undefined) && (current.argfield !== '') && (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '')) { "; } if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) { @@ -1845,6 +2071,14 @@ sub construction_space_roles { foreach my $role (@allroles) { if (&Apache::lonnet::allowed('c'.$role,$env{'user.domain'}.'/'.$env{'user.name'})) { push(@roles,$role); + } elsif ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) { + my ($audom,$auname) = ($1,$2); + if (($role eq 'ca') || ($role eq 'aa')) { + if ((&Apache::lonnet::allowed('v'.$role,,$audom.'/'.$auname)) && + ($env{"environment.internal.manager./$audom/$auname"})) { + push(@roles,$role); + } + } } } return @roles; @@ -2102,12 +2336,31 @@ sub print_userlist { } else { my (%cstr_roles,%dom_roles); if ($context eq 'author') { - # List co-authors and assistant co-authors my @possroles = &roles_by_context($context); - %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef, - \@statuses,\@possroles); - &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo, - \%cstr_roles,$permission); + my @allowedroles; + # List co-authors and assistant co-authors + my ($auname,$audom); + if ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) { + ($audom,$auname) = ($1,$2); + foreach my $role (@possroles) { + if ((&Apache::lonnet::allowed('v'.$role,"$audom/$auname")) || + (&Apache::lonnet::allowed('c'.$role,"$audom/$auname"))) { + push(@allowedroles,$role); + } + } + } elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) { + if ($1 eq $env{'user.domain'}) { + $auname = $env{'user.name'}; + $audom = $env{'user.domain'}; + } + @allowedroles = @possroles; + } + if (($auname ne '') && ($audom ne '')) { + %cstr_roles = &Apache::lonnet::get_my_roles($auname,$audom,undef, + \@statuses,\@allowedroles); + &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo, + \%cstr_roles,$permission); + } } elsif ($context eq 'domain') { if ($env{'form.roletype'} eq 'domain') { if (grep(/^authorusage$/,@cols)) { @@ -2398,7 +2651,10 @@ sub get_cols_array { push(@cols,'photo'); } if ($context eq 'domain') { - push (@cols,('authorusage','authorquota','extent')); + push(@cols,('authorusage','authorquota','extent')); + } + if ($context eq 'author') { + push(@cols,'manager'); } } return @cols; @@ -2439,6 +2695,11 @@ sub column_checkboxes { } elsif ($env{'form.roletype'} eq 'domain') { $disabledchk{'extent'} = 1; } + } elsif ($context eq 'author') { + if (($env{'form.Status'} eq 'Expired') || + ($env{'form.showrole'} eq 'aa')) { + $disabledchk{'manager'} = 1; + } } } my $numposs = scalar(@cols); @@ -2530,6 +2791,7 @@ sub get_column_names { 'ca' => "check all", 'ua' => "uncheck all", 'clicker' => "clicker-ID", + 'manager' => "co-author manager", ); if ($context eq 'domain' && $env{'form.roletype'} eq 'course') { $lt{'extent'} = &mt('course(s): description, section(s), status'); @@ -2814,6 +3076,7 @@ sub make_keylist_array { $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC(); $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA(); $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE(); + $index->{'manager'} = &Apache::loncoursedata::CL_CAMANAGER(); foreach my $key (keys(%{$index})) { $keylist->[$index->{$key}] = $key; } @@ -2888,6 +3151,9 @@ sub show_users_list { (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) { push(@sortable,('authorusage','authorquota')); } + if ($context eq 'author') { + push(@sortable,'manager'); + } } if ($mode eq 'pickauthor') { @sortable = ('username','fullname','email','status'); @@ -3205,6 +3471,7 @@ END foreach my $idx (@$keylist) { $index{$idx} = $i++; } + my $now = time; my $usercount = 0; my ($secfilter,$grpfilter); if ($context eq 'course') { @@ -3222,10 +3489,12 @@ END Future => 'Future', Expired => 'Expired', ); - # If this is for a single course get last course "log-in". - my %crslogins; + my (%crslogins,%camanagers); if ($context eq 'course') { + # If this is for a single course get last course "log-in". %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum); + } elsif ($context eq 'author') { + map { $camanagers{$_.':ca'} = 1; } split(/,/,$env{'environment.authormanagers'}); } # Get groups, role, permanent e-mail so we can sort on them if # necessary. @@ -3325,6 +3594,16 @@ END } } } + if ($context eq 'author') { + if (($camanagers{$user}) && + ((!defined($userlist->{$user}->[$index{'end'}])) || + ($userlist->{$user}->[$index{'end'}] == 0) || + ($userlist->{$user}->[$index{'end'}] > $now))) { + $userlist->{$user}->[$index{'manager'}] = &mt('Yes'); + } else { + $userlist->{$user}->[$index{'manager'}] = &mt('No'); + } + } my %emails = &Apache::loncommon::getemails($uname,$udom); if ($emails{'permanentemail'} =~ /\S/) { $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'}; @@ -4520,9 +4799,25 @@ sub upfile_drop_add { $fieldstype{$field.'_choice'} = 'scalar'; } &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype); - my ($cid,$crstype,$setting,$crsdom,$crsnum); + my ($cid,$crstype,$setting,$crsdom,$crsnum,$oldcrsuserdoms,%emptyok); if ($context eq 'domain') { $setting = $env{'form.roleaction'}; + if (exists($fields{'names'})) { + map { $emptyok{$_} = 1; } ('lastname','firstname','middlename'); + } else { + if (exists($fields{'lname'})) { + $emptyok{'lastname'} = 1; + } + if (exists($fields{'fname'})) { + $emptyok{'firstname'} = 1; + } + if (exists($fields{'mname'})) { + $emptyok{'middlename'} = 1; + } + } + if (exists($fields{'gen'})) { + $emptyok{'generation'} = 1; + } } if ($env{'request.course.id'} ne '') { $cid = $env{'request.course.id'}; @@ -4535,6 +4830,11 @@ sub upfile_drop_add { $crstype = &Apache::loncommon::course_type($cid); $crsdom = $env{'form.dcdomain'}; $crsnum = $env{'form.dccourse'}; + if (exists($env{'course.'.$cid.'.internal.userdomains'})) { + $oldcrsuserdoms = 1; + } + my %coursedesc = &Apache::lonnet::coursedescription($cid,{ one_time => 1 }); + $env{'course.'.$cid.'.internal.userdomains'} = $coursedesc{'internal.userdomains'}; } } my ($startdate,$enddate) = &get_dates_from_form(); @@ -4720,7 +5020,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 +5562,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 +5600,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 +5629,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, @@ -5337,7 +5639,7 @@ sub upfile_drop_add { $mname,$lname,$gen,$singlesec, $env{'form.forceid'},$desiredhost, $email,$role,$enddate,$startdate, - $checkid,$inststatus); + $checkid,$inststatus,\%emptyok); } } if ($multiple) { @@ -5359,6 +5661,13 @@ sub upfile_drop_add { } # end of loop $r->print(''); &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); + if (($context eq 'domain') && ($setting eq 'course')) { + unless ($oldcrsuserdoms) { + if (exists($env{'course.'.$cid.'.internal.userdomains'})) { + delete($env{'course.'.$cid.'.internal.userdomains'}); + } + } + } } # Flush the course logs so reverse user roles immediately updated $r->register_cleanup(\&Apache::lonnet::flushcourselogs); @@ -5379,11 +5688,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 +5888,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 +6006,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 +6018,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 +6029,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 +6240,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') { @@ -6572,6 +6884,9 @@ sub get_permission { $permission{'selfenrolladmin'} = 1; } } + unless ($permission{'selfenrolladmin'}) { + $permission{'selfenrollview'} = 1; + } } if ($env{'request.course.id'}) { my $user; @@ -6591,8 +6906,23 @@ sub get_permission { } } } elsif ($context eq 'author') { - $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'}); - $permission{'view'} = $permission{'cusr'}; + my $audom = $env{'request.role.domain'}; + my $auname = $env{'user.name'}; + if ((&Apache::lonnet::allowed('cca',"$audom/$auname")) || + (&Apache::lonnet::allowed('caa',"$audom/$auname"))) { + $permission{'author'} = 1; + $permission{'cusr'} = 1; + $permission{'view'} = 1; + } + } elsif ($context eq 'coauthor') { + my ($audom,$auname) = ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}); + if ((&Apache::lonnet::allowed('vca',"$audom/$auname")) || + (&Apache::lonnet::allowed('vaa',"$audom/$auname"))) { + if ($env{"environment.internal.manager./$audom/$auname"}) { + $permission{'cusr'} = 1; + $permission{'view'} = 1; + } + } } else { my @allroles = &roles_by_context($context); foreach my $role (@allroles) { @@ -6621,7 +6951,7 @@ sub get_permission { } my $allowed = 0; foreach my $key (keys(%permission)) { - next if (($key eq 'owner') || ($key eq 'co-owner')); + next if (($key eq 'owner') || ($key eq 'co-owner') || ($key eq 'author')); if ($permission{$key}) { $allowed=1; last; } } return (\%permission,$allowed); @@ -6635,6 +6965,18 @@ sub authorpriv { || (&Apache::lonnet::allowed('caa',$audom.'/'.$auname))) { return ''; } return 1; } +sub coauthorpriv { + my ($auname,$audom)=@_; + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + if (((&Apache::lonnet::allowed('vca',"$udom/$uname")) || + (&Apache::lonnet::allowed('vaa',"$udom/$uname"))) && + ($env{"environment.internal.manager./$audom/$auname"})) { + return 1; + } + return ''; +} + sub roles_on_upload { my ($context,$setting,$crstype,%customroles) = @_; my (@possible_roles,@permitted_roles); @@ -7035,7 +7377,7 @@ sub selfenrollment_administration { } } if ($settings{'internal.selfenrollmgrdc'} ne '') { - my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'}); + @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'}); my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs); unless (@diffs) { return (\@in_course,\@in_domain);