--- loncom/interface/lonuserutils.pm	2019/08/26 01:28:51	1.184.4.5
+++ loncom/interface/lonuserutils.pm	2024/07/04 16:29:50	1.184.4.12
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.184.4.5 2019/08/26 01:28:51 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.184.4.12 2024/07/04 16:29:50 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -103,7 +103,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;
@@ -134,6 +134,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);
             }
         }
@@ -510,7 +529,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') ) {
@@ -543,13 +562,15 @@ END
             case 'krb':
                 alertmsg = '$alert{'krb'}';
                 break;
-            case 'loc':
             case 'int':
                 alertmsg = '$alert{'ipass'}';
                 break;
             case 'fsys':
                 alertmsg = '$alert{'ipass'}';
                 break;
+            case 'loc':
+                alertmsg = '';
+                break;
             default:
                 alertmsg = '';
         }
@@ -3661,6 +3682,8 @@ END
         setSections(formname,'$crstype');
         if (seccheck == 'ok') {
             opener.document.$callingform.newsecs.value = formname.sections.value;
+        } else {
+            return;
         }
 END
     } else {
@@ -4286,9 +4309,25 @@ sub upfile_drop_add {
         $fieldstype{$field.'_choice'} = 'scalar';
     }
     &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);
-    my ($cid,$crstype,$setting);
+    my ($cid,$crstype,$setting,%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'};
@@ -4933,6 +4972,16 @@ sub upfile_drop_add {
                     my (%userres,%authres,%roleres,%idres);
                     my $singlesec = '';
                     if ($role eq 'st') {
+                        if (($context eq 'domain') && ($changeauth eq 'Yes') && (!$newuser)) {
+                            if ((&Apache::lonnet::allowed('mau',$userdomain)) &&
+                                (&Apache::lonnet::homeserver($username,$userdomain) ne 'no_host')) {
+                                if ((($amode =~ /^krb4|krb5|internal$/) && $password ne '') ||
+                                     ($amode eq 'localauth')) {
+                                    $authresult =
+                                        &Apache::lonnet::modifyuserauth($userdomain,$username,$amode,$password);
+                                }
+                            }
+                        }
                         my $sec;
                         if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                             if (@secs > 0) {
@@ -4974,16 +5023,16 @@ sub upfile_drop_add {
                                     }
                                 }
                             }
-                            if (!$multiple) {
-                                ($userresult,$authresult,$roleresult,$idresult) = 
-                                    &modifyuserrole($context,$setting,
-                                                    $changeauth,$cid,$userdomain,$username, 
-                                                    $id,$amode,$password,$fname,
-                                                    $mname,$lname,$gen,$singlesec,
-                                                    $env{'form.forceid'},$desiredhost,
-                                                    $email,$role,$enddate,$startdate,
-                                                    $checkid,$inststatus);
-                            }
+                        }
+                        if (!$multiple) {
+                            ($userresult,$authresult,$roleresult,$idresult) = 
+                                &modifyuserrole($context,$setting,
+                                                $changeauth,$cid,$userdomain,$username, 
+                                                $id,$amode,$password,$fname,
+                                                $mname,$lname,$gen,$singlesec,
+                                                $env{'form.forceid'},$desiredhost,
+                                                $email,$role,$enddate,$startdate,
+                                                $checkid,$inststatus,\%emptyok);
                         }
                     }
                     if ($multiple) {
@@ -5103,7 +5152,11 @@ sub passwdrule_alerts {
             my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
             $warning = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>';
             if ($showrules{'min'}) {
-                $warning .= '<li>'.&mt('minimum [quant,_1,character]',$passwdconf{'min'}).'</li>';
+                my $min = $passwdconf{'min'};
+                if ($min eq '') {
+                    $min = $Apache::lonnet::passwdmin;
+                }
+                $warning .= '<li>'.&mt('minimum [quant,_1,character]',$min).'</li>';
             }
             if ($showrules{'max'}) {
                 $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>';
@@ -5995,6 +6048,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;
@@ -6115,12 +6232,21 @@ sub get_permission {
                     $permission{'selfenrolladmin'} = 1;
                 }
             }
+            unless ($permission{'selfenrolladmin'}) {
+                $permission{'selfenrollview'} = 1;
+            }
         }
         if ($env{'request.course.id'}) {
-            my $user = $env{'user.name'}.':'.$env{'user.domain'};
+            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;
@@ -6571,7 +6697,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);