--- loncom/interface/lonuserutils.pm 2014/02/16 15:38:53 1.163
+++ loncom/interface/lonuserutils.pm 2024/08/31 20:02:12 1.222
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Utility functions for managing LON-CAPA user accounts
#
-# $Id: lonuserutils.pm,v 1.163 2014/02/16 15:38:53 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.222 2024/08/31 20:02:12 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,12 +30,30 @@
package Apache::lonuserutils;
+=pod
+
+=head1 NAME
+
+Apache::lonuserutils.pm
+
+=head1 SYNOPSIS
+
+ Utilities for management of users and custom roles
+
+ Provides subroutines called by loncreateuser.pm
+
+=head1 OVERVIEW
+
+=cut
+
use strict;
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon;
+use Apache::loncoursequeueadmin;
use Apache::lonlocal;
use Apache::longroup;
+use HTML::Entities;
use LONCAPA qw(:DEFAULT :match);
###############################################################
@@ -86,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;
@@ -97,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);
@@ -117,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);
}
}
@@ -136,6 +177,560 @@ sub modifyuserrole {
return ($userresult,$authresult,$roleresult,$idresult);
}
+sub role_approval {
+ my ($dom,$context,$process_by,$notifydc) = @_;
+ if (ref($process_by) eq 'HASH') {
+ my %domconfig = &Apache::lonnet::get_dom('configuration',['privacy'],$dom);
+ if (ref($domconfig{'privacy'}) eq 'HASH') {
+ if (ref($notifydc) eq 'ARRAY') {
+ if ($domconfig{'privacy'}{'notify'} ne '') {
+ @{$notifydc} = split(/,/,$domconfig{'privacy'}{'notify'});
+ }
+ }
+ if (ref($domconfig{'privacy'}{'approval'}) eq 'HASH') {
+ my %approvalconf = %{$domconfig{'privacy'}{'approval'}};
+ foreach my $key ('instdom','extdom') {
+ if (ref($approvalconf{$key}) eq 'HASH') {
+ if (keys(%{$approvalconf{$key}})) {
+ $process_by->{$key} = $approvalconf{$key}{$context};
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+sub get_instdoms {
+ my ($udom,$instdoms) = @_;
+ return unless (ref($instdoms) eq 'ARRAY');
+ my @intdoms;
+ my %iphost = &Apache::lonnet::get_iphost();
+ my $primary_id = &Apache::lonnet::domain($udom,'primary');
+ my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
+ if (ref($iphost{$primary_ip}) eq 'ARRAY') {
+ foreach my $id (@{$iphost{$primary_ip}}) {
+ my $intdom = &Apache::lonnet::internet_dom($id);
+ unless(grep(/^\Q$intdom\E$/,@intdoms)) {
+ push(@intdoms,$intdom);
+ }
+ }
+ }
+ foreach my $ip (keys(%iphost)) {
+ if (ref($iphost{$ip}) eq 'ARRAY') {
+ foreach my $id (@{$iphost{$ip}}) {
+ my $location = &Apache::lonnet::internet_dom($id);
+ if ($location) {
+ if (grep(/^\Q$location\E$/,@intdoms)) {
+ my $dom = &Apache::lonnet::host_domain($id);
+ unless (grep(/^\Q$dom\E/,@{$instdoms})) {
+ push(@{$instdoms},$dom);
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+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,$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($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}) {
+ $gotdata = 1;
+ if (ref($process_by->{$context}{$udom}) eq 'HASH') {
+ %approval = %{$process_by->{$context}{$udom}};
+ }
+ }
+ }
+ unless ($gotdata) {
+ &role_approval($udom,$context,\%approval,\@notify);
+ $process_by->{$context} = {
+ $udom => \%approval,
+ };
+ $got_role_approvals->{$context} = {
+ $udom => 1,
+ };
+ $notifydc->{$udom} = \@notify;
+ }
+ if (ref($process_by->{$context}) eq 'HASH') {
+ if (ref($process_by->{$context}{$udom}) eq 'HASH') {
+ my @inst;
+ if ($got_instdoms->{$udom}) {
+ if (ref($instdoms->{$udom}) eq 'ARRAY') {
+ @inst = @{$instdoms->{$udom}};
+ }
+ } else {
+ &get_instdoms(\@inst);
+ $instdoms->{$udom} = \@inst;
+ $got_instdoms->{$udom} = 1;
+ }
+ if (grep(/^\Q$cdom\E$/,@inst)) {
+ if (exists($approval{'instdom'})) {
+ my $rule = $approval{'instdom'};
+ 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;
+ }
+ }
+ }
+ }
+ } elsif (exists($approval{'extdom'})) {
+ my $rule = $approval{'extdom'};
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ 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,$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").'
';
+ foreach my $key (sort(keys(%{$reject}))) {
+ if (ref($reject->{$key}) eq 'HASH') {
+ foreach my $user (sort(keys(%{$reject->{$key}}))) {
+ if (ref($reject->{$key}->{$user}) eq 'HASH') {
+ my ($crstype,$role,$cdom,$cnum,$csec,$title,$plainrole);
+ $role = $reject->{$key}->{$user}{'role'};
+ $cdom = $reject->{$key}->{$user}{'cdom'};
+ $cnum = $reject->{$key}->{$user}{'cnum'};
+ $csec = $reject->{$key}->{$user}{'csec'};
+ if (($context eq 'domain') && ($cnum ne '')) {
+ if (($role eq 'ca') || ($role eq 'aa')) {
+ $title = &Apache::loncommon::plainname($cnum,$cdom);
+ } else {
+ if (&Apache::lonnet::is_course($cdom,$cnum)) {
+ my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
+ $crstype = $coursedata{'type'};
+ $title = $coursedata{'description'};
+ }
+ }
+ } elsif ($context eq 'course') {
+ $crstype = &Apache::loncommon::course_type();
+ }
+ my $plainrole = &Apache::lonnet::plaintext($role,$crstype);
+ $output .= ''.&mt('User: [_1]',$reject->{$key}->{$user}{'uname'}).' | '.
+ &mt('Domain: [_1]',$reject->{$key}->{$user}{'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);
+ }
+ $output .= ' ';
+ }
+ }
+ }
+ }
+ $output .= ' ';
+ }
+ 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.").'
';
+ foreach my $key (sort(keys(%{$unauthorized}))) {
+ if (ref($unauthorized->{$key}) eq 'HASH') {
+ foreach my $user (sort(keys(%{$unauthorized->{$key}}))) {
+ if (ref($unauthorized->{$key}->{$user}) eq 'HASH') {
+ my ($crstype,$role,$cdom,$cnum,$csec,$title,$plainrole);
+ $role = $unauthorized->{$key}->{$user}{'role'};
+ $cdom = $unauthorized->{$key}->{$user}{'cdom'};
+ $cnum = $unauthorized->{$key}->{$user}{'cnum'};
+ $csec = $unauthorized->{$key}->{$user}{'csec'};
+ if (($context eq 'domain') && ($cnum ne '')) {
+ if (($role eq 'ca') || ($role eq 'aa')) {
+ $title = &mt('Authoring Space belonging to: [_1]',
+ &Apache::loncommon::plainname($cnum,$cdom));
+ } else {
+ if (&Apache::lonnet::is_course($cdom,$cnum)) {
+ my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
+ $crstype = $coursedata{'type'};
+ $title = &mt("$crstype: [_1]",$coursedata{'description'});
+ }
+ }
+ } elsif ($context eq 'course') {
+ $crstype = &Apache::loncommon::course_type();
+ }
+ $plainrole = &Apache::lonnet::plaintext($role,$crstype);
+ $output .= ''.&mt('User: [_1]',$unauthorized->{$key}->{$user}{'uname'}).' | '.
+ &mt('Domain: [_1]',$unauthorized->{$key}->{$user}{'udom'}).' | '.
+ &mt('Role: [_1]',$plainrole);
+ if ($crstype) {
+ if ($csec ne'') {
+ $output .= ' | '.&mt('Section: [_1]',$csec);
+ }
+ }
+ if ($title ne '') {
+ $output .= ' | '.$title;
+ }
+ $output .= ' ';
+ }
+ }
+ }
+ }
+ $output .= ' ';
+ }
+ return $output;
+}
+
+sub print_roles_queued {
+ 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;
+ $output = ''.
+ &mt("The following role assignments have been 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").'
';
+ my (%todom,%touser,%crsqueue,%caqueue,%domqueue);
+ my $requester = $env{'user.name'}.':'.$env{'user.domain'};
+ foreach my $key (sort(keys(%{$pending}))) {
+ if (ref($pending->{$key}) eq 'HASH') {
+ 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(/:/,$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);
+ }
+ }
+ }
+ if (keys(%todom)) {
+ foreach my $dom (keys(%todom)) {
+ if (ref($todom{$dom}) eq 'HASH') {
+ my $confname = &Apache::lonnet::get_domainconfiguser($dom);
+ 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}});
+ &Apache::loncoursequeueadmin::send_selfserve_notification($notifylist,
+ '','','',$now,'othdomroledc',$requester);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (keys(%crsqueue)) {
+ foreach my $key (keys(%crsqueue)) {
+ my ($cdom,$cnum) = split(/_/,$key);
+ if (ref($crsqueue{$key}) eq 'HASH') {
+ &Apache::lonnet::put('nohist_othdomqueued',$crsqueue{$key},$cdom,$cnum);
+ }
+ }
+ }
+ if (keys(%caqueue)) {
+ foreach my $key (keys(%caqueue)) {
+ my ($auname,$audom) = split(/:/,$key);
+ if (ref($caqueue{$key}) eq 'HASH') {
+ &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('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").'
';
+ my $requester = $env{'user.name'}.':'.$env{'user.domain'};
+ foreach my $key (sort(keys(%{$currqueued}))) {
+ if (ref($currqueued->{$key}) eq 'HASH') {
+ foreach my $user (sort(keys(%{$currqueued->{$key}}))) {
+ if (ref($currqueued->{$key}->{$user}) eq 'HASH') {
+ my $role = $currqueued->{$key}->{$user}{'role'};
+ my $csec = $currqueued->{$key}->{$user}{'csec'};
+ my $cdom = $currqueued->{$key}->{$user}{'cdom'};
+ my $cnum = $currqueued->{$key}->{$user}{'cnum'};
+ my ($crstype,$title,$plainrole);
+ if ($context eq 'course') {
+ $crstype = &Apache::loncommon::course_type();
+ } elsif (($context eq 'domain') && ($cnum ne '')) {
+ if (($role eq 'ca') || ($role eq 'aa')) {
+ $title = &mt('Authoring Space belonging to: [_1]',
+ &Apache::loncommon::plainname($cnum,$cdom));
+ } elsif (&Apache::lonnet::is_course($cdom,$cnum)) {
+ my %coursedata = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
+ $crstype = $coursedata{'type'};
+ $title = &mt("$crstype: [_1]",$coursedata{'description'});
+ }
+ }
+ $plainrole = &Apache::lonnet::plaintext($role,$crstype);
+ $output .= ''.&mt('User: [_1]',$currqueued->{$key}->{$user}{'uname'}).' | '.
+ &mt('Domain: [_1]',$currqueued->{$key}->{$user}{'udom'}).' | '.
+ &mt('Role: [_1]',$plainrole);
+ if ($title ne '') {
+ $output .= ' | '.$title;
+ }
+ if ($crstype) {
+ if ($csec ne '') {
+ $output .= ' | '.&mt('Section: [_1]',$csec);
+ }
+ }
+ $output .= ' ';
+ }
+ }
+ }
+ }
+ $output .= ' ';
+ }
+ return $output;
+}
+
sub propagate_id_change {
my ($uname,$udom,$user) = @_;
my (@types,@roles);
@@ -421,7 +1016,7 @@ sub javascript_validations {
} elsif ($context eq 'domain') {
$setsection_call = 'setCourse()';
$setsections_js = &dc_setcourse_js($param{'formname'},$mode,
- $context,$showcredits);
+ $context,$showcredits,$domain);
}
$finish = " var checkSec = $setsection_call\n".
" if (checkSec == 'ok') {\n".
@@ -450,6 +1045,7 @@ sub javascript_validations {
if (($mode eq 'upload') && ($context eq 'domain')) {
$alert{'inststatus'} = &mt('The optional affiliation field was not specified');
}
+ &js_escape(\%alert);
my $function_name = <<"END";
$setsections_js
@@ -492,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') ) {
@@ -513,21 +1109,28 @@ END
/* regexp here to check for non \d \. in credits */
END
} else {
+ my ($numrules,$intargjs) =
+ &Apache::loncommon::passwd_validation_js('vf.elements[current.argfield].value',$domain);
$auth_checks .= (< 0) {
+$intargjs
+ }
}
END
}
@@ -623,6 +1230,7 @@ END
$section_checks.$authheader;
return $result;
}
+
###############################################################
###############################################################
sub upload_manager_javascript_forward_associate {
@@ -642,8 +1250,9 @@ sub upload_manager_javascript_forward_as
$numbuttons ++;
}
if (!$can_assign->{'int'}) {
- my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.').'\n'.
+ my $warning = &mt('You may not specify an initial password for each user, as this is only available when new users use LON-CAPA internal authentication.')."\n".
&mt('Your current role does not have rights to create users with that authentication type.');
+ &js_escape(\$warning);
$auth_update = <<"END";
// Currently the initial password field is only supported for internal auth
// (see bug 6368).
@@ -781,6 +1390,7 @@ sub upload_manager_javascript_reverse_as
if (!$can_assign->{'int'}) {
my $warning = &mt('You may not specify an initial password, as this is only available when new users use LON-CAPA internal authentication.\n').
&mt('Your current role does not have rights to create users with that authentication type.');
+ &js_escape(\$warning);
$auth_update = <<"END";
// Currently the initial password field is only supported for internal auth
// (see bug 6368).
@@ -878,6 +1488,7 @@ sub print_upload_manager_footer {
my $krbform = &Apache::loncommon::authform_kerberos(%param);
my $intform = &Apache::loncommon::authform_internal(%param);
my $locform = &Apache::loncommon::authform_local(%param);
+ my $ltiform = &Apache::loncommon::authform_lti(%param);
my $date_table = &date_setting_table(undef,undef,$context,undef,
$formname,$permission,$crstype);
@@ -906,7 +1517,7 @@ sub print_upload_manager_footer {
&Apache::loncommon::help_open_topic('Auth_Options').
"\n";
}
- $Str .= &set_login($defdom,$krbform,$intform,$locform);
+ $Str .= &set_login($defdom,$krbform,$intform,$locform,$ltiform);
my ($home_server_pick,$numlib) =
&Apache::loncommon::home_server_form_item($defdom,'lcserver',
@@ -923,8 +1534,14 @@ sub print_upload_manager_footer {
&Apache::lonhtmlcommon::row_closure();
}
+ my ($trusted,$untrusted);
+ if ($context eq 'course') {
+ ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('enroll',$defdom);
+ } elsif ($context eq 'author') {
+ ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('othcoau',$defdom);
+ }
$Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain'))
- .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1)
+ .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1,undef,$trusted,$untrusted)
.&Apache::lonhtmlcommon::row_closure();
$Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates'))
@@ -1081,7 +1698,7 @@ sub forceid_change {
my ($context) = @_;
my $output =
' '
- .&mt('Force change of exising ID')
+ .&mt('Force change of existing ID')
.' '.&Apache::loncommon::help_open_topic('ForceIDChange')."\n";
if ($context eq 'domain') {
$output .=
@@ -1101,8 +1718,15 @@ sub print_upload_manager_form {
if (!$env{'form.datatoken'}) {
$datatoken=&Apache::loncommon::upfile_store($r);
} else {
- $datatoken=$env{'form.datatoken'};
- &Apache::loncommon::load_tmp_file($r);
+ $datatoken=&Apache::loncommon::valid_datatoken($env{'form.datatoken'});
+ if ($datatoken ne '') {
+ &Apache::loncommon::load_tmp_file($r,$datatoken);
+ }
+ }
+ if ($datatoken eq '') {
+ $r->print(''.&mt('Error').': '.
+ &mt('Invalid datatoken').'
');
+ return 'missingdata';
}
my @records=&Apache::loncommon::upfile_record_sep();
if($env{'form.noFirstLine'}){
@@ -1186,6 +1810,7 @@ sub print_upload_manager_form {
}
&print_upload_manager_footer($r,$i,$keyfields,$defdom,$today,$halfyear,
$context,$permission,$crstype,$showcredits);
+ return 'ok';
}
sub setup_date_selectors {
@@ -1446,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;
@@ -1527,16 +2160,17 @@ sub curr_role_permissions {
# ======================================================= Existing Custom Roles
sub my_custom_roles {
- my ($crstype) = @_;
+ my ($crstype,$udom,$uname) = @_;
my %returnhash=();
my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});
- my %rolehash=&Apache::lonnet::dump('roles');
+ my %rolehash=&Apache::lonnet::dump('roles',$udom,$uname);
foreach my $key (keys(%rolehash)) {
if ($key=~/^rolesdef\_(\w+)$/) {
+ my $role = $1;
if ($crstype eq 'Community') {
next if ($rolehash{$key} =~ /bre\&S/);
}
- $returnhash{$1}=$1;
+ $returnhash{$role}=$role;
}
}
return %returnhash;
@@ -1549,6 +2183,24 @@ sub print_userlist {
if (! exists($env{'form.sortby'})) {
$env{'form.sortby'} = 'username';
}
+ my ($showstart,$showend);
+ if (($env{'form.Status'} eq '') && ($env{'form.phase'} eq '') &&
+ ($env{'form.showrole'} eq '') && ($context eq 'course') &&
+ ($env{'request.course.id'} ne '') &&
+ ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'} ne '')) {
+ my $now = time;
+ my $startaccess = $env{'course.'.$env{'request.course.id'}.'.default_enrollment_start_date'};
+ my $endaccess = $env{'course.'.$env{'request.course.id'}.'.default_enrollment_end_date'};
+ if (($startaccess) && ($startaccess > $now)) {
+ $env{'form.Status'} = 'Future';
+ $showstart = 1;
+ }
+ if (($endaccess ne '') && ($endaccess != 0) && ($endaccess < $now)) {
+ $env{'form.Status'} = 'Expired';
+ undef($showstart);
+ $showend = 1;
+ }
+ }
if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) {
$env{'form.Status'} = 'Active';
}
@@ -1616,7 +2268,7 @@ sub print_userlist {
$r->print(§ion_group_filter($cnum,$cdom));
}
$r->print(''.
- &column_checkboxes($context,$mode,$formname,$showcredits).
+ &column_checkboxes($context,$mode,$formname,$showcredits,$showstart,$showend).
'
');
if ($env{'form.phase'} eq '') {
$r->print(' '.
@@ -1702,12 +2354,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)) {
@@ -1998,14 +2669,17 @@ 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;
}
sub column_checkboxes {
- my ($context,$mode,$formname,$showcredits) = @_;
+ my ($context,$mode,$formname,$showcredits,$showstart,$showend) = @_;
my @cols = &get_cols_array($context,$mode,$showcredits);
my @showncols = &Apache::loncommon::get_env_multiple('form.showcol');
my (%disabledchk,%unchecked);
@@ -2018,11 +2692,21 @@ sub column_checkboxes {
if ($showcredits) {
$unchecked{'credits'} = 1;
}
- } elsif ($context eq 'domain') {
+ my %curr_groups = &Apache::longroup::coursegroups();
+ unless (keys(%curr_groups)) {
+ $unchecked{'groups'} = 1;
+ }
+ } elsif ($context eq 'domain') {
$unchecked{'extent'} = 1;
}
- $unchecked{'start'} = 1;
- $unchecked{'end'} = 1;
+ if ($showstart) {
+ $unchecked{'lastlogin'} = 1;
+ } else {
+ $unchecked{'start'} = 1;
+ }
+ unless ($showend) {
+ $unchecked{'end'} = 1;
+ }
} else {
if ($env{'form.Status'} ne 'Any') {
$disabledchk{'status'} = 1;
@@ -2039,6 +2723,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);
@@ -2130,6 +2819,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');
@@ -2154,6 +2844,7 @@ sub gather_userinfo {
($userdata{'username'},$userdata{'domain'},$userdata{'role'}) =
split(/:/,$item);
($userdata{'start'},$userdata{'end'})=split(/:/,$rolehash->{$item});
+ next if (($userdata{'username'} eq '') && ($userdata{'domain'} eq ''));
&build_user_record($context,\%userdata,$userinfo,$indexhash,
$item,$userlist);
} elsif ($context eq 'course') {
@@ -2259,7 +2950,6 @@ sub build_user_record {
sub courses_selector {
my ($cdom,$formname) = @_;
- my %coursecodes = ();
my %codes = ();
my @codetitles = ();
my %cat_titles = ();
@@ -2272,14 +2962,15 @@ sub courses_selector {
my $jscript = '';
my $totcodes = 0;
- $totcodes =
- &Apache::courseclassifier::retrieve_instcodes(\%coursecodes,
- $cdom,$totcodes);
- if ($totcodes > 0) {
- $format_reply =
- &Apache::lonnet::auto_instcode_format($caller,$cdom,\%coursecodes,
- \%codes,\@codetitles,\%cat_titles,\%cat_order);
- if ($format_reply eq 'ok') {
+ my $instcats = &Apache::lonnet::get_dom_instcats($cdom);
+ if (ref($instcats) eq 'HASH') {
+ if ((ref($instcats->{'codetitles'}) eq 'ARRAY') && (ref($instcats->{'codes'}) eq 'HASH') &&
+ (ref($instcats->{'cat_titles'}) eq 'HASH') && (ref($instcats->{'cat_order'}) eq 'HASH')) {
+ %codes = %{$instcats->{'codes'}};
+ @codetitles = @{$instcats->{'codetitles'}};
+ %cat_titles = %{$instcats->{'cat_titles'}};
+ %cat_order = %{$instcats->{'cat_order'}};
+ $totcodes = scalar(keys(%codes));
my $numtypes = @codetitles;
&Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);
my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles);
@@ -2287,7 +2978,7 @@ sub courses_selector {
my $allidlist = $idlist{$codetitles[0]};
$jscript .= &Apache::courseclassifier::courseset_js_start($formname,$longtitles_str,$allidlist);
$jscript .= $scripttext;
- $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,@codetitles);
+ $jscript .= &Apache::courseclassifier::javascript_code_selections($formname,\@codetitles);
}
}
my $cb_jscript = &Apache::loncommon::coursebrowser_javascript($cdom);
@@ -2316,7 +3007,8 @@ function setCourseCat(formname) {
}
courseSet('$codetitles[1]');
for (var j=0; j{'photo'} = &Apache::loncoursedata::CL_PHOTO();
$index->{'thumbnail'} = &Apache::loncoursedata::CL_THUMBNAIL();
$index->{'credits'} = &Apache::loncoursedata::CL_CREDITS();
+ $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;
}
@@ -2486,6 +3180,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');
@@ -2542,14 +3239,22 @@ $verify_action_js
function username_display_launch(username,domain) {
var target;
- for (var i=0; i "Open in a new window",
'modify' => "Modify a user's information",
'track' => "View a user's recent activity",
+ 'activity' => "View a user's access log",
);
my %lt = (%coltxt,%acttxt);
my $rolefilter = $env{'form.showrole'};
@@ -2694,12 +3400,17 @@ END
if ($permission->{'cusr'}) {
unshift (@linkdests,'modify');
}
- if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) ||
- &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'.
- $env{'request.course.sec'})) {
- push(@linkdests,'track');
+ if ($context eq 'course') {
+ if (&Apache::lonnet::allowed('vsa', $env{'request.course.id'}) ||
+ &Apache::lonnet::allowed('vsa', $env{'request.course.id'}.'/'.
+ $env{'request.course.sec'})) {
+ push(@linkdests,'track');
+ }
+ } elsif ($context eq 'domain') {
+ if (&Apache::lonnet::allowed('vac',$env{'request.role.domain'})) {
+ push(@linkdests,'activity');
+ }
}
-
$output .= '';
my $usernamelink = $env{'form.usernamelink'};
if ($usernamelink eq '') {
@@ -2722,7 +3433,7 @@ END
.' '.$lt{'owin'}
.' ';
}
- $output .= "\n".' '."\n".
+ $output .= "\n".'
'."\n".
&Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row();
if ($mode eq 'autoenroll') {
@@ -2789,6 +3500,7 @@ END
foreach my $idx (@$keylist) {
$index{$idx} = $i++;
}
+ my $now = time;
my $usercount = 0;
my ($secfilter,$grpfilter);
if ($context eq 'course') {
@@ -2806,10 +3518,21 @@ 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') {
+ my $authormanagers;
+ if ($env{'request.role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)$}) {
+ my %envhash = &Apache::lonnet::userenvironment($1,$2,'authormanagers');
+ $authormanagers = $envhash{'authormanagers'};
+ } else {
+ $authormanagers = $env{'environment.authormanagers'};
+ }
+ if ($authormanagers ne '') {
+ map { $camanagers{$_.':ca'} = 1; } split(/,/,$authormanagers);
+ }
}
# Get groups, role, permanent e-mail so we can sort on them if
# necessary.
@@ -2909,6 +3632,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'};
@@ -2968,6 +3701,12 @@ END
} (keys(%$userlist));
}
my $rowcount = 0;
+ my $disabled;
+ if ($mode eq 'autoenroll') {
+ unless ($permission->{'cusr'}) {
+ $disabled = ' disabled="disabled"';
+ }
+ }
foreach my $user (@sorted_users) {
my %in;
my $sdata = $userlist->{$user};
@@ -3004,16 +3743,16 @@ END
if ($mode eq 'autoenroll') {
my $cellentry;
if ($in{'type'} eq 'auto') {
- $cellentry = ''.&mt('auto').' '.&mt('Change').' ';
+ $cellentry = ''.&mt('auto').' '.&mt('Change').' ';
$autocount ++;
} else {
- $cellentry = ''.&mt('manual').' '.&mt('Change').'';
+ $cellentry = '';
@@ -3053,13 +3792,21 @@ END
if ($role eq 'st') {
$checkval .= ':'.$in{'type'}.':'.
$in{'lockedtype'}.':'.
- $in{'credits'};
+ $in{'credits'}.':'.
+ &escape($in{'instsec'});
}
}
}
if ($showcheckbox) {
$r->print(' ');
+ 'actionlist" value="'.
+ &HTML::Entities::encode($checkval,'&<>"').'" />');
+ foreach my $item ('start','end') {
+ $r->print(' ');
+ }
+ $r->print('');
} else {
$r->print(' ');
}
@@ -3073,8 +3820,6 @@ END
foreach my $item (@cols) {
if ($item eq 'username') {
$r->print(''.&print_username_link($mode,\%in).' ');
- } elsif (($item eq 'start' || $item eq 'end') && ($actionselect)) {
- $r->print(''.$in{$item}.' '."\n");
} elsif ($item eq 'status') {
my $showitem = $in{$item};
if (defined($ltstatus{$in{$item}})) {
@@ -3173,6 +3918,10 @@ sub bulkaction_javascript {
my $noaction = &mt("You need to select an action to take for the user(s) you have selected");
my $singconfirm = &mt(' for a single user?');
my $multconfirm = &mt(' for multiple users?');
+ &js_escape(\$alert);
+ &js_escape(\$noaction);
+ &js_escape(\$singconfirm);
+ &js_escape(\$multconfirm);
my $output = <<"ENDJS";
function verify_action (field) {
var numchecked = 0;
@@ -3461,6 +4210,8 @@ END
setSections(formname,'$crstype');
if (seccheck == 'ok') {
opener.document.$callingform.newsecs.value = formname.sections.value;
+ } else {
+ return;
}
END
} else {
@@ -3709,10 +4460,16 @@ sub results_header_row {
$description .= ' ('.$constraint.')';
}
} elsif ($context eq 'author') {
+ my ($auname,$audom);
+ if ($env{'request.role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)$}) {
+ ($audom,$auname) = ($1,$2);
+ } else {
+ ($audom,$auname) = ($env{'user.domain'},$env{'user.name'});
+ }
$description =
&mt('Author space for [_1]'
,''
- .&Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'})
+ .&Apache::loncommon::plainname($auname,$audom)
.' ')
.': ';
if ($statusmode eq 'Expired') {
@@ -4045,7 +4802,7 @@ sub print_first_users_upload_form {
.&Apache::lonhtmlcommon::end_pick_box();
$str .= ''
- .' '
.'
';
@@ -4056,7 +4813,10 @@ sub print_first_users_upload_form {
# ================================================= Drop/Add from uploaded file
sub upfile_drop_add {
my ($r,$context,$permission,$showcredits) = @_;
- &Apache::loncommon::load_tmp_file($r);
+ my $datatoken = &Apache::loncommon::valid_datatoken($env{'form.datatoken'});
+ if ($datatoken ne '') {
+ &Apache::loncommon::load_tmp_file($r,$datatoken);
+ }
my @userdata=&Apache::loncommon::upfile_record_sep();
if($env{'form.noFirstLine'}){shift(@userdata);}
my @keyfields = split(/\,/,$env{'form.keyfields'});
@@ -4070,10 +4830,6 @@ sub upfile_drop_add {
$fields{$env{'form.f'.$i}}=$keyfields[$i];
}
}
- if ($env{'form.fullup'} ne 'yes') {
- $r->print(''."\n");
+ $r->print(''.
+ &mt('There are no students with current/future access to the course.').
+ '
'."\n");
} elsif (ref($classlist) eq 'HASH') {
# Remove the students we just added from the list of students.
foreach my $line (@userdata) {
@@ -4701,9 +5764,7 @@ sub upfile_drop_add {
}
}
} # end of unless
- if ($env{'form.fullup'} ne 'yes') {
- $r->print('');
- }
+ return 'ok';
}
sub print_namespacing_alerts {
@@ -4746,15 +5807,52 @@ sub print_namespacing_alerts {
}
}
+sub passwdrule_alerts {
+ my ($domain,$passwdrules) = @_;
+ my $warning;
+ if (ref($passwdrules) eq 'HASH') {
+ my %showrules = %{$passwdrules};
+ if (keys(%showrules)) {
+ my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
+ $warning = ''.&mt('Password requirement(s) unmet for one or more users:').' ';
+ if ($showrules{'min'}) {
+ my $min = $passwdconf{'min'};
+ if ($min eq '') {
+ $min = $Apache::lonnet::passwdmin;
+ }
+ $warning .= ''.&mt('minimum [quant,_1,character]',$min).' ';
+ }
+ if ($showrules{'max'}) {
+ $warning .= ''.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).' ';
+ }
+ if ($showrules{'uc'}) {
+ $warning .= ''.&mt('contain at least one upper case letter').' ';
+ }
+ if ($showrules{'lc'}) {
+ $warning .= ''.&mt('contain at least one lower case letter').' ';
+ }
+ if ($showrules{'num'}) {
+ $warning .= ''.&mt('contain at least one number').' ';
+ }
+ if ($showrules{'spec'}) {
+ $warning .= ''.&mt('contain at least one non-alphanumeric').' ';
+ }
+ $warning .= ' ';
+ }
+ }
+ return $warning;
+}
+
sub user_change_result {
my ($r,$userresult,$authresult,$roleresult,$idresult,$counts,$flushc,
$username,$userdomain,$userchg) = @_;
my $okresult = 0;
+ my @status;
if ($userresult ne 'ok') {
if ($userresult =~ /^error:(.+)$/) {
my $error = $1;
- $r->print(' '.
- &mt('[_1]: Unable to add/modify: [_2]',''.$username.':'.$userdomain.' ',$error));
+ push(@status,
+ &mt('[_1]: Unable to add/modify: [_2]',''.$username.':'.$userdomain.' ',$error));
}
} else {
$counts->{'user'} ++;
@@ -4763,8 +5861,8 @@ sub user_change_result {
if ($authresult ne 'ok') {
if ($authresult =~ /^error:(.+)$/) {
my $error = $1;
- $r->print(' '.
- &mt('[_1]: Unable to modify authentication: [_2]',''.$username.':'.$userdomain.' ',$error));
+ push(@status,
+ &mt('[_1]: Unable to modify authentication: [_2]',''.$username.':'.$userdomain.' ',$error));
}
} else {
$counts->{'auth'} ++;
@@ -4773,8 +5871,8 @@ sub user_change_result {
if ($roleresult ne 'ok') {
if ($roleresult =~ /^error:(.+)$/) {
my $error = $1;
- $r->print(' '.
- &mt('[_1]: Unable to add role: [_2]',''.$username.':'.$userdomain.' ',$error));
+ push(@status,
+ &mt('[_1]: Unable to add role: [_2]',''.$username.':'.$userdomain.' ',$error));
}
} else {
$counts->{'role'} ++;
@@ -4783,14 +5881,16 @@ sub user_change_result {
if ($okresult) {
$flushc++;
$userchg->{$username.':'.$userdomain}=1;
- $r->print('. ');
if ($flushc>15) {
$r->rflush;
$flushc=0;
}
}
if ($idresult) {
- $r->print($idresult);
+ push(@status,$idresult);
+ }
+ if (@status) {
+ $r->print(''.join(' ',@status).' ');
}
return $flushc;
}
@@ -4831,7 +5931,8 @@ sub update_user_list {
if ($context eq 'course') {
$crstype = &Apache::loncommon::course_type();
}
- my @changelist;
+ my (@changelist,%got_role_approvals,%got_instdoms,%process_by,%instdoms,
+ %pending,%reject,%notifydc,%status,%unauthorized,%currqueued);
if ($choice eq 'drop') {
@changelist = &Apache::loncommon::get_env_multiple('form.droplist');
} else {
@@ -4861,7 +5962,7 @@ sub update_user_list {
foreach my $item (@changelist) {
my ($role,$uname,$udom,$cid,$sec,$scope,$result,$type,$locktype,
@sections,$scopestem,$singlesec,$showsecs,$warn_singlesec,
- $nothingtodo,$keepnosection,$credits);
+ $nothingtodo,$keepnosection,$credits,$instsec,$cdom,$cnum);
if ($choice eq 'drop') {
($uname,$udom,$sec) = split(/:/,$item,-1);
$role = 'st';
@@ -4874,9 +5975,12 @@ sub update_user_list {
$scope = $scopestem.'/'.$sec;
}
} elsif ($context eq 'course') {
- ($uname,$udom,$role,$sec,$type,$locktype,$credits) =
- split(/\:/,$item);
+ ($uname,$udom,$role,$sec,$type,$locktype,$credits,$instsec) =
+ split(/\:/,$item,8);
+ $instsec = &unescape($instsec);
$cid = $env{'request.course.id'};
+ $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
$scopestem = '/'.$cid;
$scopestem =~s/\_/\//g;
if ($sec eq '') {
@@ -4887,15 +5991,21 @@ sub update_user_list {
} elsif ($context eq 'author') {
($uname,$udom,$role) = split(/\:/,$item,-1);
$scope = '/'.$env{'user.domain'}.'/'.$env{'user.name'};
+ $cdom = $env{'user.domain'};
+ $cnum = $env{'user.name'};
} elsif ($context eq 'domain') {
if ($setting eq 'domain') {
($role,$uname,$udom) = split(/\:/,$item,-1);
$scope = '/'.$env{'request.role.domain'}.'/';
+ $cdom = $env{'request.role.domain'};
} elsif ($setting eq 'author') {
($uname,$udom,$role,$scope) = split(/\:/,$item);
+ (undef,$cdom,$cnum) = split(/\//,$scope);
} elsif ($setting eq 'course') {
- ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits) =
- split(/\:/,$item);
+ ($uname,$udom,$role,$cid,$sec,$type,$locktype,$credits,$instsec) =
+ split(/\:/,$item,9);
+ ($cdom,$cnum) = split('_',$cid);
+ $instsec = &unescape($instsec);
$scope = '/'.$cid;
$scope =~s/\_/\//g;
if ($sec ne '') {
@@ -4917,7 +6027,7 @@ sub update_user_list {
$end = $now;
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);
+ &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
} else {
$result =
&Apache::lonnet::revokerole($udom,$uname,$scope,$role,
@@ -4925,7 +6035,7 @@ sub update_user_list {
}
} elsif ($choice eq 'delete') {
if ($role eq 'st') {
- &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits);
+ &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$now,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
}
$result =
&Apache::lonnet::assignrole($udom,$uname,$scope,$role,$now,
@@ -4936,24 +6046,37 @@ sub update_user_list {
$start = $startdate;
$end = $enddate;
}
+ my $id = $scope.'_'.$role;
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,
+ \%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);
+ $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
} else {
$result =
&Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
$now,'','',$context);
}
} 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,
+ \%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);
+ $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
} else {
$result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
$now,'','',$context);
}
} 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,
+ \%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);
+ $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
} else {
$result = &Apache::lonnet::assignrole($udom,$uname,$scope,$role,$end,
$start,'','',$context);
@@ -5023,7 +6146,7 @@ sub update_user_list {
} else {
if ($role eq 'st') {
$result =
- &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits);
+ &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,undef,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
} else {
my $newscope = $scopestem;
$result = &Apache::lonnet::assignrole($udom,$uname,$newscope,$role,$end,$start,'','',$context);
@@ -5037,7 +6160,7 @@ sub update_user_list {
foreach my $newsec (@newsecs) {
if (!grep(/^\Q$newsec\E$/,@retained)) {
if ($role eq 'st') {
- $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits);
+ $result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$newsec,$end,$start,$type,$locktype,$cid,'',$context,$credits,$instsec);
if (@newsecs > 1) {
my $showsingle;
if ($newsec eq '') {
@@ -5161,6 +6284,12 @@ sub update_user_list {
$r->print(&make_dates_default($startdate,$enddate,$context,$crstype));
}
}
+ if ((keys(%reject)) || (keys(%unauthorized))) {
+ $r->print(&print_roles_rejected($context,\%reject,\%unauthorized));
+ }
+ if ((keys(%pending)) || (keys(%currqueued))) {
+ $r->print(&print_roles_queued($context,\%pending,\%notifydc,\%currqueued));
+ }
my $linktext = &mt('Display User Lists');
if ($choice eq 'drop') {
$linktext = &mt('Display current class roster');
@@ -5215,18 +6344,25 @@ sub active_student_roles {
sub section_check_js {
my $groupslist= &get_groupslist();
+ my %js_lt = &Apache::lonlocal::texthash(
+ mayn => 'may not be used as the name for a section, as it is a reserved word.',
+ plch => 'Please choose a different section name.',
+ mnot => 'may not be used as a section name, as it is the name of a course group.',
+ secn => 'Section names and group names must be distinct. Please choose a different section name.',
+ );
+ &js_escape(\%js_lt);
return <<"END";
function validate(caller) {
var groups = new Array($groupslist);
var secname = caller.value;
if ((secname == 'all') || (secname == 'none')) {
- alert("'"+secname+"' may not be used as the name for a section, as it is a reserved word.\\nPlease choose a different section name.");
+ alert("'"+secname+"' $js_lt{'mayn'}\\n$js_lt{'plch'}");
return 'error';
}
if (secname != '') {
for (var k=0; k'.$authformloc.''.
&Apache::loncommon::end_data_table_row()."\n";
}
+ if ($can_assign{'lti'}) {
+ $response .= &Apache::loncommon::start_data_table_row().
+ ''.$authformlti.' '.
+ &Apache::loncommon::end_data_table_row()."\n";
+ }
$response .= &Apache::loncommon::end_data_table();
}
return $response;
}
sub course_sections {
- my ($sections_count,$role,$current_sec) = @_;
+ my ($sections_count,$role,$current_sec,$disabled) = @_;
my $output = '';
- my @sections = (sort {$a <=> $b} keys %{$sections_count});
+ my @sections = (sort {$a <=> $b} keys(%{$sections_count}));
my $numsec = scalar(@sections);
my $is_selected = ' selected="selected"';
if ($numsec <= 1) {
- $output = ''."\n".
+ $output = ''."\n".
' '.&mt('Select').' '."\n";
if ($current_sec eq 'none') {
$output .=
@@ -5294,7 +6435,7 @@ sub course_sections {
my $multiple = 4;
if (scalar(@sections) < 4) { $multiple = scalar(@sections); }
if ($role eq 'st') {
- $output .= '>'."\n".
+ $output .= $disabled.'>'."\n".
' '.&mt('Select').' '."\n";
if ($current_sec eq 'none') {
$output .=
@@ -5304,7 +6445,7 @@ sub course_sections {
' '.&mt('No section')." \n";
}
} else {
- $output .= 'multiple="multiple" size="'.$multiple.'">'."\n";
+ $output .= 'multiple="multiple" size="'.$multiple.'"'.$disabled.'>'."\n";
}
foreach my $sec (@sections) {
if ($current_sec eq $sec) {
@@ -5351,7 +6492,7 @@ sub setsections_javascript {
}
$rolecode = "var match = str.split('_');
var role = match[3];\n";
- } elsif ($formname eq 'enrollstudent') {
+ } elsif (($formname eq 'enrollstudent') || ($formname eq 'selfenroll')) {
$checkincluded = 'formname.name == "'.$formname.'"';
if ($checkauth) {
$finish = "var authcheck = auth_check();\n".
@@ -5385,7 +6526,8 @@ sub setsections_javascript {
mnot => 'may not be used as a section name, as it is the name of a course group.',
secn => 'Section names and group names must be distinct. Please choose a different section name.',
nonw => 'Section names may only contain letters or numbers.',
- );
+ );
+ &js_escape(\%alerts);
$setsection_js .= <<"ENDSECCODE";
function setSections(formname,crstype) {
@@ -5396,6 +6538,9 @@ function setSections(formname,crstype) {
var groups = new Array($groupslist);
for (var i=0;i{'mip'}) &&
+ ($udom eq $env{'request.role.domain'})) {
+ unless ($env{'course.'.$env{'request.course.id'}.'.internal.nopasswdchg'}) {
+ my ($cnum,$cdom) = &get_course_identity();
+ if ((&Apache::lonnet::is_course_owner($cdom,$cnum)) && ($udom eq $env{'user.domain'})) {
+ my @userstatuses = ('default');
+ my %userenv = &Apache::lonnet::userenvironment($udom,$uname,'inststatus');
+ if ($userenv{'inststatus'} ne '') {
+ @userstatuses = split(/:/,$userenv{'inststatus'});
+ }
+ my $noupdate = 1;
+ my %passwdconf = &Apache::lonnet::get_passwdconf($cdom);
+ if (ref($passwdconf{'crsownerchg'}) eq 'HASH') {
+ if (ref($passwdconf{'crsownerchg'}{'for'}) eq 'ARRAY') {
+ foreach my $status (@userstatuses) {
+ if (grep(/^\Q$status\E$/,@{$passwdconf{'crsownerchg'}{'for'}})) {
+ undef($noupdate);
+ last;
+ }
+ }
+ }
+ }
+ if ($noupdate) {
+ return;
+ }
+ my %owned = &Apache::lonnet::courseiddump($cdom,'.',1,'.',
+ $env{'user.name'}.':'.$env{'user.domain'},
+ undef,undef,undef,'.');
+ my %roleshash = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
+ ['active','future']);
+ foreach my $key (keys(%roleshash)) {
+ my ($name,$domain,$role) = split(/:/,$key);
+ if ($role eq 'st') {
+ next if (($name eq $cnum) && ($domain eq $cdom));
+ if ($owned{$domain.'_'.$name}) {
+ if (ref($owned{$domain.'_'.$name}) eq 'HASH') {
+ if ($owned{$domain.'_'.$name}{'nopasswdchg'}) {
+ $noupdate = 1;
+ last;
+ }
+ }
+ } else {
+ $noupdate = 1;
+ last;
+ }
+ } else {
+ $noupdate = 1;
+ last;
+ }
+ }
+ unless ($noupdate) {
+ $canchange = 1;
+ }
+ }
+ }
+ }
+ return $canchange;
+}
+
sub check_usertype {
my ($dom,$uname,$rules,$curr_rules,$got_rules) = @_;
my $usertype;
@@ -5659,7 +6875,7 @@ sub roles_by_context {
} elsif ($context eq 'author') {
@allroles = ('ca','aa');
} elsif ($context eq 'domain') {
- @allroles = ('li','ad','dg','sc','au','dc');
+ @allroles = ('li','ad','dg','dh','da','sc','au','dc');
}
return @allroles;
}
@@ -5701,9 +6917,60 @@ sub get_permission {
if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) {
$permission{'grp_manage'} = 1;
}
+ if ($permission{'cusr'}) {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my %coursehash = (
+ 'internal.selfenrollmgrdc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrdc'},
+ 'internal.selfenrollmgrcc' => $env{'course.'.$env{'request.course.id'}.'.internal.selfenrollmgrcc'},
+ 'internal.coursecode' => $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'},
+ 'internal.textbook' =>$env{'course.'.$env{'request.course.id'}.'.internal.textbook'},
+ );
+ my ($managed_by_cc,$managed_by_dc) = &selfenrollment_administration($cdom,$cnum,$crstype,\%coursehash);
+ if (ref($managed_by_cc) eq 'ARRAY') {
+ if (@{$managed_by_cc}) {
+ $permission{'selfenrolladmin'} = 1;
+ }
+ }
+ unless ($permission{'selfenrolladmin'}) {
+ $permission{'selfenrollview'} = 1;
+ }
+ }
+ if ($env{'request.course.id'}) {
+ my $user;
+ if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) {
+ $user = $env{'user.name'}.':'.$env{'user.domain'};
+ }
+ if (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.courseowner'} eq
+ $user)) {
+ $permission{'owner'} = 1;
+ if (&Apache::lonnet::allowed('mip',$env{'request.course.id'})) {
+ $permission{'mip'} = 1;
+ }
+ } elsif (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.co-owners'} ne '')) {
+ if (grep(/^\Q$user\E$/,split(/,/,$env{'course.'.$env{'request.course.id'}.'.internal.co-owners'}))) {
+ $permission{'co-owner'} = 1;
+ }
+ }
+ }
} 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) {
@@ -5720,11 +6987,20 @@ sub get_permission {
if (&Apache::lonnet::allowed('ccr',$env{'request.role.domain'})) {
$permission{'custom'} = 1;
}
- $permission{'view'} = $permission{'cusr'};
+ if (&Apache::lonnet::allowed('vac',$env{'request.role.domain'})) {
+ $permission{'activity'} = 1;
+ }
+ if (&Apache::lonnet::allowed('vur',$env{'request.role.domain'})) {
+ $permission{'view'} = 1;
+ }
+ if (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'})) {
+ $permission{'owner'} = 1;
+ }
}
my $allowed = 0;
- foreach my $perm (values(%permission)) {
- if ($perm) { $allowed=1; last; }
+ foreach my $key (keys(%permission)) {
+ next if (($key eq 'owner') || ($key eq 'co-owner') || ($key eq 'author'));
+ if ($permission{$key}) { $allowed=1; last; }
}
return (\%permission,$allowed);
}
@@ -5737,6 +7013,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);
@@ -5773,7 +7061,7 @@ sub get_course_identity {
}
sub dc_setcourse_js {
- my ($formname,$mode,$context,$showcredits) = @_;
+ my ($formname,$mode,$context,$showcredits,$domain) = @_;
my ($dc_setcourse_code,$authen_check);
my $cctext = &Apache::lonnet::plaintext('cc');
my $cotext = &Apache::lonnet::plaintext('co');
@@ -5782,7 +7070,7 @@ sub dc_setcourse_js {
if ($mode eq 'upload') {
$role = 'courserole';
} else {
- $authen_check = &verify_authen($formname,$context);
+ $authen_check = &verify_authen($formname,$context,$domain);
}
$dc_setcourse_code = (<<"SCRIPTTOP");
$authen_check
@@ -5926,12 +7214,14 @@ ENDSCRIPT
}
sub verify_authen {
- my ($formname,$context) = @_;
+ my ($formname,$context,$domain) = @_;
my %alerts = &authcheck_alerts();
my $finish = "return 'ok';";
if ($context eq 'author') {
$finish = "document.$formname.submit();";
}
+ my ($numrules,$intargjs) =
+ &Apache::loncommon::passwd_validation_js('argpicked',$domain);
my $outcome = <<"ENDSCRIPT";
function auth_check() {
@@ -5965,6 +7255,7 @@ function auth_check() {
break;
case 'int':
alertmsg = '$alerts{'ipass'}';
+ break;
case 'fsys':
alertmsg = '$alerts{'ipass'}';
break;
@@ -5978,6 +7269,11 @@ function auth_check() {
alert(alertmsg);
return;
}
+ } else if (logintype == 'int') {
+ var numrules = $numrules;
+ if (numrules > 0) {
+$intargjs
+ }
}
$finish
}
@@ -6003,6 +7299,7 @@ sub sectioncheck_alerts {
thwa => 'There was a problem with your course selection',
thwc => 'There was a problem with your community selection',
);
+ &js_escape(\%alerts);
return %alerts;
}
@@ -6013,6 +7310,7 @@ sub authcheck_alerts {
krb => 'You need to specify the Kerberos domain.',
ipass => 'You need to specify the initial password.',
);
+ &js_escape(\%alerts);
return %alerts;
}
@@ -6031,5 +7329,570 @@ sub is_courseowner {
return;
}
+sub get_selfenroll_titles {
+ my @row = ('types','registered','enroll_dates','access_dates','section',
+ 'approval','limit');
+ my %lt = &Apache::lonlocal::texthash (
+ types => 'Users allowed to self-enroll',
+ registered => 'Registration status (official courses)' ,
+ enroll_dates => 'Dates self-enrollment available',
+ access_dates => 'Access dates for self-enrolling users',
+ section => "Self-enrolling users' section",
+ approval => 'Processing of requests',
+ limit => 'Enrollment limit',
+ );
+ return (\@row,\%lt);
+}
+
+sub selfenroll_default_descs {
+ my %desc = (
+ types => {
+ dom => &mt('Course domain'),
+ all => &mt('Any domain'),
+ '' => &mt('None'),
+ },
+ limit => {
+ none => &mt('No limit'),
+ allstudents => &mt('Limit by total students'),
+ selfenrolled => &mt('Limit by total self-enrolled'),
+ },
+ approval => {
+ '0' => &mt('Processed automatically'),
+ '1' => &mt('Queued for approval'),
+ '2' => &mt('Queued, pending validation'),
+ },
+ registered => {
+ 0 => 'No registration required',
+ 1 => 'Registered students only',
+ },
+ );
+ return %desc;
+}
+
+sub selfenroll_validation_types {
+ my @items = ('url','fields','button','markup');
+ my %names = &Apache::lonlocal::texthash (
+ url => 'Web address of validation server/script',
+ fields => 'Form fields to send to validator',
+ button => 'Text for validation button',
+ markup => 'Validation description (HTML)',
+ );
+ my @fields = ('username','domain','uniquecode','course','coursetype','description');
+ return (\@items,\%names,\@fields);
+}
+
+sub get_extended_type {
+ my ($cdom,$cnum,$crstype,$current) = @_;
+ my $type = 'unofficial';
+ my %settings;
+ if (ref($current) eq 'HASH') {
+ %settings = %{$current};
+ } else {
+ %settings = &Apache::lonnet::get('environment',['internal.coursecode','internal.textbook'],$cdom,$cnum);
+ }
+ if ($crstype eq 'Community') {
+ $type = 'community';
+ } elsif ($crstype eq 'Placement') {
+ $type = 'placement';
+ } elsif ($settings{'internal.coursecode'}) {
+ $type = 'official';
+ } elsif ($settings{'internal.textbook'}) {
+ $type = 'textbook';
+ }
+ return $type;
+}
+
+sub selfenrollment_administration {
+ my ($cdom,$cnum,$crstype,$coursehash) = @_;
+ my %settings;
+ if (ref($coursehash) eq 'HASH') {
+ %settings = %{$coursehash};
+ } else {
+ %settings = &Apache::lonnet::get('environment',
+ ['internal.selfenrollmgrdc','internal.selfenrollmgrcc',
+ 'internal.coursecode','internal.textbook'],$cdom,$cnum);
+ }
+ my ($possconfigs) = &get_selfenroll_titles();
+ my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
+ my $selfenrolltype = &get_extended_type($cdom,$cnum,$crstype,\%settings);
+
+ my (@in_course,@in_domain);
+ if ($settings{'internal.selfenrollmgrcc'} ne '') {
+ @in_course = split(/,/,$settings{'internal.selfenrollmgrcc'});
+ my @diffs = &Apache::loncommon::compare_arrays($possconfigs,\@in_course);
+ unless (@diffs) {
+ return (\@in_course,\@in_domain);
+ }
+ }
+ if ($settings{'internal.selfenrollmgrdc'} ne '') {
+ @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
+ my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs);
+ unless (@diffs) {
+ return (\@in_course,\@in_domain);
+ }
+ }
+ my @combined = @in_course;
+ push(@combined,@in_domain);
+ my @diffs = &Apache::loncommon::compare_arrays(\@combined,$possconfigs);
+ unless (@diffs) {
+ return (\@in_course,\@in_domain);
+ }
+ if ($domdefaults{$selfenrolltype.'selfenrolladmdc'} eq '') {
+ push(@in_course,@diffs);
+ } else {
+ my @defaultdc = split(/,/,$domdefaults{$selfenrolltype.'selfenrolladmdc'});
+ foreach my $item (@diffs) {
+ if (grep(/^\Q$item\E$/,@defaultdc)) {
+ push(@in_domain,$item);
+ } else {
+ push(@in_course,$item);
+ }
+ }
+ }
+ return (\@in_course,\@in_domain);
+}
+
+sub custom_role_header {
+ my ($context,$crstype,$templaterolerefs,$prefix) = @_;
+ my %lt = &Apache::lonlocal::texthash(
+ sele => 'Select a Template',
+ );
+ my ($context_code,$button_code);
+ if ($context eq 'domain') {
+ $context_code = &custom_coursetype_switch($crstype,$prefix);
+ }
+ if (ref($templaterolerefs) eq 'ARRAY') {
+ foreach my $role (@{$templaterolerefs}) {
+ my $display = 'inline';
+ if (($context eq 'domain') && ($role eq 'co')) {
+ $display = 'none';
+ }
+ $button_code .= &make_button_code($role,$crstype,$display,$prefix).' ';
+ }
+ }
+ return <<"END";
+
+
+$lt{'sele'}
+$button_code
+
+$context_code
+
+END
+}
+
+sub custom_coursetype_switch {
+ my ($crstype,$prefix) = @_;
+ my ($checkedcourse,$checkedcommunity);
+ if ($crstype eq 'Community') {
+ $checkedcommunity = ' checked="checked"';
+ } else {
+ $checkedcourse = ' checked="checked"';
+ }
+ my %lt = &Apache::lonlocal::texthash(
+ cont => 'Context',
+ cour => 'Course',
+ comm => 'Community',
+ );
+ return <<"END";
+
+
+$lt{'cont'}
+
+
+$lt{'cour'}
+
+
+
+$lt{'comm'}
+
+
+
+END
+}
+
+sub custom_role_table {
+ my ($crstype,$full,$levels,$levelscurrent,$prefix,$add_class,$id) = @_;
+ return unless ((ref($full) eq 'HASH') && (ref($levels) eq 'HASH') &&
+ (ref($levelscurrent) eq 'HASH'));
+ my %lt=&Apache::lonlocal::texthash (
+ 'prv' => "Privilege",
+ 'crl' => "Course Level",
+ 'dml' => "Domain Level",
+ 'ssl' => "System Level");
+ my %cr = (
+ course => '_c',
+ domain => '_d',
+ system => '_s',
+ );
+
+ my $output=&Apache::loncommon::start_data_table($add_class,$id).
+ &Apache::loncommon::start_data_table_header_row().
+ ''.$lt{'prv'}.' '.$lt{'crl'}.' '.$lt{'dml'}.
+ ' '.$lt{'ssl'}.' '.
+ &Apache::loncommon::end_data_table_header_row();
+ foreach my $priv (sort(keys(%{$full}))) {
+ my $privtext = &Apache::lonnet::plaintext($priv,$crstype);
+ $output .= &Apache::loncommon::start_data_table_row().
+ ''.$privtext.' ';
+ foreach my $type ('course','domain','system') {
+ if (($type eq 'system') && ($priv eq 'bre') && ($crstype eq 'Community')) {
+ $output .= ' ';
+ } else {
+ $output .= ''.
+ ($levels->{$type}{$priv}?' {$type}{$priv}?' checked="checked"':'').' />':' ').
+ ' ';
+ }
+ }
+ $output .= &Apache::loncommon::end_data_table_row();
+ }
+ $output .= &Apache::loncommon::end_data_table();
+ return $output;
+}
+
+sub custom_role_privs {
+ my ($privs,$full,$levels,$levelscurrent)= @_;
+ return unless ((ref($privs) eq 'HASH') && (ref($full) eq 'HASH') &&
+ (ref($levels) eq 'HASH') && (ref($levelscurrent) eq 'HASH'));
+ my %cr = (
+ course => 'cr:c',
+ domain => 'cr:d',
+ system => 'cr:s',
+ );
+ foreach my $type ('course','domain','system') {
+ foreach my $item (split(/\:/,$Apache::lonnet::pr{$cr{$type}})) {
+ my ($priv,$restrict)=split(/\&/,$item);
+ if (!$restrict) { $restrict='F'; }
+ $levels->{$type}->{$priv}=$restrict;
+ if ($privs->{$type}=~/\:$priv/) {
+ $levelscurrent->{$type}->{$priv}=1;
+ }
+ $full->{$priv}=1;
+ }
+ }
+ return;
+}
+
+sub custom_template_roles {
+ my ($context,$crstype) = @_;
+ my @template_roles = ("in","ta","ep");
+ if (($context eq 'domain') || ($context eq 'domprefs')) {
+ push(@template_roles,"ad");
+ }
+ push(@template_roles,"st");
+ if ($context eq 'domain') {
+ unshift(@template_roles,('co','cc'));
+ } else {
+ if ($crstype eq 'Community') {
+ unshift(@template_roles,'co');
+ } else {
+ unshift(@template_roles,'cc');
+ }
+ }
+ return @template_roles;
+}
+
+sub custom_roledefs_js {
+ my ($context,$crstype,$formname,$full,$templaterolesref,$jsback) = @_;
+ my $button_code = "\n";
+ my $head_script = "\n";
+ my (%roletitlestr,$rolenamestr);
+ my %role_titles = (
+ Course => [],
+ Community => [],
+ );
+ $head_script .= ''."\n";
+ return $head_script;
+}
+
+# --------------------------------------------------------
+sub make_script_template {
+ my ($role,$crstype,$formname) = @_;
+ my $return_script = 'function set_'.$role.'(prefix) {'."\n";
+ my (%full_by_level,%role_priv);
+ foreach my $level ('c','d','s') {
+ foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) {
+ next if (($level eq 's') && ($crstype eq 'Community') && ($item eq 'bre&S'));
+ my ($priv,$restrict)=split(/\&/,$item);
+ $full_by_level{$level}{$priv}=1;
+ }
+ $role_priv{$level} = {};
+ my @temp = split(/:/,$Apache::lonnet::pr{$role.':'.$level});
+ foreach my $priv (@temp) {
+ my ($priv_item, $dummy) = split(/\&/,$priv);
+ $role_priv{$level}{$priv_item} = 1;
+ }
+ }
+ my %to_check = (
+ c => ['c','d','s'],
+ d => ['d','s'],
+ s => ['s'],
+ );
+ foreach my $level ('c','d','s') {
+ if (ref($full_by_level{$level}) eq 'HASH') {
+ foreach my $priv (keys(%{$full_by_level{$level}})) {
+ my $value = 'false';
+ if (ref($to_check{$level}) eq 'ARRAY') {
+ foreach my $lett (@{$to_check{$level}}) {
+ if (exists($role_priv{$lett}{$priv})) {
+ $value = 'true';
+ last;
+ }
+ }
+ $return_script .= "document.$formname.elements[prefix+'".$priv."_".$level."'].checked = $value;\n";
+ }
+ }
+ }
+ }
+ $return_script .= '}'."\n";
+ return ($return_script);
+}
+# ----------------------------------------------------------
+sub make_button_code {
+ my ($role,$crstype,$display,$prefix) = @_;
+ my $label = &Apache::lonnet::plaintext($role,$crstype);
+ my $button_code = ' ';
+ return ($button_code);
+}
+
+sub custom_role_update {
+ my ($rolename,$prefix) = @_;
+# ------------------------------------------------------- What can be assigned?
+ my %privs = (
+ c => '',
+ d => '',
+ s => '',
+ );
+ foreach my $level (keys(%privs)) {
+ foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:'.$level})) {
+ my ($priv,$restrict)=split(/\&/,$item);
+ if (!$restrict) { $restrict=''; }
+ if ($env{'form.'.$prefix.$priv.'_'.$level}) {
+ $privs{$level} .=':'.$item;
+ }
+ }
+ }
+ return %privs;
+}
+
+sub adhoc_status_types {
+ my ($cdom,$context,$role,$selectedref,$othertitle,$usertypes,$types,$disabled) = @_;
+ my $output = &Apache::loncommon::start_data_table();
+ my $numinrow = 3;
+ my $rem;
+ if (ref($types) eq 'ARRAY') {
+ for (my $i=0; $i<@{$types}; $i++) {
+ if (defined($usertypes->{$types->[$i]})) {
+ my $rem = $i%($numinrow);
+ if ($rem == 0) {
+ if ($i > 0) {
+ $output .= &Apache::loncommon::end_data_table_row();
+ }
+ $output .= &Apache::loncommon::start_data_table_row();
+ }
+ my $check;
+ if (ref($selectedref) eq 'ARRAY') {
+ if (grep(/^\Q$types->[$i]\E$/,@{$selectedref})) {
+ $check = ' checked="checked"';
+ }
+ }
+ $output .= ''.
+ ''.
+ ' [$i].'"'.$check.$disabled.' />'.
+ $usertypes->{$types->[$i]}.' ';
+ }
+ }
+ $rem = @{$types}%($numinrow);
+ }
+ my $colsleft = $numinrow - $rem;
+ if (($rem == 0) && (@{$types} > 0)) {
+ $output .= &Apache::loncommon::start_data_table_row();
+ }
+ if ($colsleft > 1) {
+ $output .= '';
+ } else {
+ $output .= ' ';
+ }
+ my $defcheck;
+ if (ref($selectedref) eq 'ARRAY') {
+ if (grep(/^default$/,@{$selectedref})) {
+ $defcheck = ' checked="checked"';
+ }
+ }
+ $output .= ''.
+ ' '.
+ $othertitle.' '.
+ &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table();
+ return $output;
+}
+
+sub adhoc_staff {
+ my ($access,$context,$role,$selectedref,$adhocref,$disabled) = @_;
+ my $output;
+ if (ref($adhocref) eq 'HASH') {
+ my %by_fullname;
+ my $numinrow = 4;
+ my $rem;
+ my @personnel = keys(%{$adhocref});
+ if (@personnel) {
+ foreach my $person (@personnel) {
+ my ($uname,$udom) = split(/:/,$person);
+ my $fullname = &Apache::loncommon::plainname($uname,$udom,'lastname');
+ $by_fullname{$fullname} = $person;
+ }
+ my @sorted = sort(keys(%by_fullname));
+ my $count = scalar(@sorted);
+ $output = &Apache::loncommon::start_data_table();
+ for (my $i=0; $i<$count; $i++) {
+ my $rem = $i%($numinrow);
+ if ($rem == 0) {
+ if ($i > 0) {
+ $output .= &Apache::loncommon::end_data_table_row();
+ }
+ $output .= &Apache::loncommon::start_data_table_row();
+ }
+ my $check;
+ my $user = $by_fullname{$sorted[$i]};
+ if (ref($selectedref) eq 'ARRAY') {
+ if (grep(/^\Q$user\E$/,@{$selectedref})) {
+ $check = ' checked="checked"';
+ }
+ }
+ if ($i == $count-1) {
+ my $colsleft = $numinrow - $rem;
+ if ($colsleft > 1) {
+ $output .= '';
+ } else {
+ $output .= ' ';
+ }
+ } else {
+ $output .= ' ';
+ }
+ $output .= ''.
+ ' '.$sorted[$i].
+ ' ';
+ if ($i == $count-1) {
+ $output .= &Apache::loncommon::end_data_table_row();
+ }
+ }
+ $output .= &Apache::loncommon::end_data_table();
+ }
+ }
+ return $output;
+}
+
+
1;