--- loncom/interface/lonuserutils.pm 2016/11/13 21:09:56 1.179
+++ loncom/interface/lonuserutils.pm 2023/09/04 16:17:12 1.184.4.10.2.4
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Utility functions for managing LON-CAPA user accounts
#
-# $Id: lonuserutils.pm,v 1.179 2016/11/13 21:09:56 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.184.4.10.2.4 2023/09/04 16:17:12 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -438,7 +438,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".
@@ -510,7 +510,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') ) {
@@ -531,19 +531,25 @@ 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
}
@@ -641,6 +651,7 @@ END
$section_checks.$authheader;
return $result;
}
+
###############################################################
###############################################################
sub upload_manager_javascript_forward_associate {
@@ -1121,8 +1132,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'}){
@@ -1206,6 +1224,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 {
@@ -2279,7 +2298,6 @@ sub build_user_record {
sub courses_selector {
my ($cdom,$formname) = @_;
- my %coursecodes = ();
my %codes = ();
my @codetitles = ();
my %cat_titles = ();
@@ -2292,14 +2310,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);
@@ -2307,7 +2326,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);
@@ -2336,7 +2355,8 @@ function setCourseCat(formname) {
}
courseSet('$codetitles[1]');
for (var j=0; j '.$lt{'owin'}
.'';
}
- $output .= "\n".' '."\n".
+ $output .= "\n".'
'."\n".
&Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row();
if ($mode eq 'autoenroll') {
@@ -3101,7 +3121,14 @@ END
}
if ($showcheckbox) {
$r->print(' ');
+ 'actionlist" value="'.
+ &HTML::Entities::encode($checkval,'&<>"').'" />');
+ foreach my $item ('start','end') {
+ $r->print(' ');
+ }
+ $r->print('');
} else {
$r->print(' ');
}
@@ -3115,8 +3142,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}})) {
@@ -3507,6 +3532,8 @@ END
setSections(formname,'$crstype');
if (seccheck == 'ok') {
opener.document.$callingform.newsecs.value = formname.sections.value;
+ } else {
+ return;
}
END
} else {
@@ -4091,7 +4118,7 @@ sub print_first_users_upload_form {
.&Apache::lonhtmlcommon::end_pick_box();
$str .= ''
- .' '
.'
';
@@ -4102,7 +4129,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'});
@@ -4116,10 +4146,6 @@ sub upfile_drop_add {
$fields{$env{'form.f'.$i}}=$keyfields[$i];
}
}
- if ($env{'form.fullup'} ne 'yes') {
- $r->print('
\n");
if ($counts{'role'} > 0) {
$r->print("\n".
- &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.&mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.')."
\n");
+ &mt('Roles added for [quant,_1,user].',$counts{'role'}).' '.
+ &mt('If a user is currently logged-in to LON-CAPA, any new roles which are active will be available when the user next logs in.').
+ "\n");
} else {
$r->print(''.&mt('No roles added').'
');
}
@@ -4829,6 +4907,7 @@ sub upfile_drop_add {
$counts{'auth'})."\n");
}
$r->print(&print_namespacing_alerts($domain,\%alerts,\%curr_rules));
+ $r->print(&passwdrule_alerts($domain,\%showpasswdrules));
#####################################
# Display list of students to drop #
#####################################
@@ -4837,10 +4916,9 @@ sub upfile_drop_add {
# Get current classlist
my $classlist = &Apache::loncoursedata::get_classlist();
if (! defined($classlist)) {
- $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) {
@@ -4856,9 +4934,7 @@ sub upfile_drop_add {
}
}
} # end of unless
- if ($env{'form.fullup'} ne 'yes') {
- $r->print('');
- }
+ return 'ok';
}
sub print_namespacing_alerts {
@@ -4901,6 +4977,42 @@ 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) = @_;
@@ -5770,6 +5882,70 @@ sub can_modify_userinfo {
return %canmodify;
}
+sub can_change_internalpass {
+ my ($uname,$udom,$crstype,$permission) = @_;
+ my $canchange;
+ if (&Apache::lonnet::allowed('mau',$udom)) {
+ $canchange = 1;
+ } elsif ((ref($permission) eq 'HASH') && ($permission->{'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;
@@ -5833,7 +6009,7 @@ sub roles_by_context {
} elsif ($context eq 'author') {
@allroles = ('ca','aa');
} elsif ($context eq 'domain') {
- @allroles = ('li','ad','dg','dh','sc','au','dc');
+ @allroles = ('li','ad','dg','dh','da','sc','au','dc');
}
return @allroles;
}
@@ -5890,6 +6066,26 @@ sub get_permission {
$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'});
@@ -5916,10 +6112,14 @@ sub get_permission {
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'));
+ if ($permission{$key}) { $allowed=1; last; }
}
return (\%permission,$allowed);
}
@@ -5968,7 +6168,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');
@@ -5977,7 +6177,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
@@ -6121,12 +6321,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() {
@@ -6160,6 +6362,7 @@ function auth_check() {
break;
case 'int':
alertmsg = '$alerts{'ipass'}';
+ break;
case 'fsys':
alertmsg = '$alerts{'ipass'}';
break;
@@ -6173,6 +6376,11 @@ function auth_check() {
alert(alertmsg);
return;
}
+ } else if (logintype == 'int') {
+ var numrules = $numrules;
+ if (numrules > 0) {
+$intargjs
+ }
}
$finish
}
@@ -6324,7 +6532,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);
@@ -6411,7 +6619,7 @@ END
}
sub custom_role_table {
- my ($crstype,$full,$levels,$levelscurrent,$prefix) = @_;
+ 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 (
@@ -6425,7 +6633,7 @@ sub custom_role_table {
system => '_s',
);
- my $output=&Apache::loncommon::start_data_table().
+ 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'}.' '.
@@ -6682,5 +6890,116 @@ sub custom_role_update {
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;