--- loncom/interface/lonuserutils.pm	2007/12/22 22:42:58	1.29
+++ loncom/interface/lonuserutils.pm	2007/12/24 05:26:31	1.33
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.29 2007/12/22 22:42:58 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.33 2007/12/24 05:26:31 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -304,7 +304,7 @@ sub print_upload_manager_header {
     my $javascript_validations =
         &javascript_validations('upload',$krbdefdom,$password_choice,undef,
                                 $env{'request.role.domain'},$context,
-                                $permission,$groupslist);
+                                $groupslist);
     my $checked=(($env{'form.noFirstLine'})?' checked="checked" ':'');
     $r->print(&mt('Total number of records found in file: <b>[_1]</b>.',$distotal).
               "<br />\n");
@@ -332,7 +332,7 @@ sub print_upload_manager_header {
 ###############################################################
 sub javascript_validations {
     my ($mode,$krbdefdom,$curr_authtype,$curr_authfield,$domain,
-        $context,$permission,$groupslist)=@_;
+        $context,$groupslist)=@_;
 
     my %param = (
                   kerb_def_dom => $krbdefdom,
@@ -1264,7 +1264,7 @@ sub print_userlist {
     if ($env{'form.showrole'} eq 'Any') {
        $roleselected = ' selected="selected" '; 
     }
-    my $role_select;
+    my ($role_select,$cnum,$cdom);
     if ($context eq 'domain') {
         $role_select = &domain_roles_select();
         $r->print('<label>'.&mt('Role Type: [_1]',$role_select).'</label>');
@@ -1288,6 +1288,10 @@ sub print_userlist {
         }
         $role_select .= '</select>';
         $r->print('<label>'.&mt('Role: [_1]',$role_select).'</label>');
+        if ($context eq 'course') {
+            ($cnum,$cdom) = &get_course_identity();
+            $r->print(&section_group_filter($cnum,$cdom));
+        }
     }
     if (!(($context eq 'domain') && ($env{'form.roletype'} eq 'course'))) {
         $r->print('&nbsp;'.&list_submit_button(&mt('Update Display')).
@@ -1331,8 +1335,6 @@ sub print_userlist {
                 $userlist{$student} = $classlist->{$student};
             }
         }
-        my $cid = $env{'request.course.id'};
-        my ($cnum,$cdom) = &get_course_identity($cid);
         my $showroles;
         if ($env{'form.showrole'} ne 'Any') {
             $showroles = [$env{'form.showrole'}];
@@ -1468,6 +1470,62 @@ sub print_userlist {
               $env{'form.phase'}.'" /></form>');
 }
 
+sub section_group_filter {
+    my ($cnum,$cdom) = @_;
+    my @filters;
+    if ($env{'request.course.sec'} eq '') {
+        @filters = ('sec');
+    }
+    push(@filters,'grp');
+    my %name = (
+                 sec => 'secfilter',
+                 grp => 'grpfilter',
+               );
+    my %title = &Apache::lonlocal::texthash (
+                                              sec  => 'Section(s)',
+                                              grp  => 'Group(s)',
+                                              all  => 'all',
+                                              none => 'none',
+                                            );
+    my ($output,@options);
+    foreach my $item (@filters) {
+        my $markup; 
+        if ($env{'form.'.$name{$item}} eq '') {
+            $env{'form.'.$name{$item}} = 'all';
+        }
+        if ($item eq 'sec') {
+            if ($env{'form.showrole'} eq 'cc') {
+                $env{'form.'.$name{$item}} = 'none';
+            }
+            my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
+            @options = sort(keys(%sections_count));
+        } elsif ($item eq 'grp') {
+            my %curr_groups = &Apache::longroup::coursegroups();
+            @options = sort(keys(%curr_groups));
+        }
+        if (@options > 0) {
+            my $currsel;
+            $markup = '<select name="'.$name{$item}.'" />'."\n";
+            foreach my $option ('all','none',@options) { 
+                $currsel = '';
+                if ($env{'form.'.$name{$item}} eq $option) {
+                    $currsel = ' selected="selected" ';
+                }
+                $markup .= ' <option value="'.$option.'"'.$currsel.'>';
+                if (($option eq 'all') || ($option eq 'none')) {
+                    $markup .= $title{$option};
+                } else {
+                    $markup .= $option;
+                }   
+                $markup .= '</option>'."\n";
+            }
+            $markup .= '</select>'."\n";
+            $output .= ('&nbsp;'x3).'<label>'.$title{$item}.': '.$markup.'</label>';
+        }
+    }
+    return $output;
+}
+
 sub list_submit_button {
     my ($text) = @_;
     return '<input type="button" name="updatedisplay" value="'.$text.'" onclick="javascript:display_update()" />';
@@ -1819,7 +1877,7 @@ sub show_users_list {
         $sortby = 'username';
     }
     my $setting = $env{'form.roletype'};
-    my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers);
+    my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers,$secfilter,$grpfilter);
     if ($context eq 'course') {
         $cid = $env{'request.course.id'};
         ($cnum,$cdom) = &get_course_identity($cid);
@@ -2047,6 +2105,11 @@ END
                                     $env{'request.role.domain'})) {
                                 $canchange{$role} = 1;
                             }
+                        } elsif ($setting eq 'author') {
+                            if (&Apache::lonnet::allowed('c'.$role,
+                                    $env{'request.role.domain'})) {
+                                $canchange{$role} = 1;
+                            }
                         }
                     } elsif ($context eq 'author') {
                         if (&Apache::lonnet::allowed('c'.$role,
@@ -2158,6 +2221,17 @@ END
         $index{$idx} = $i++;
     }
     my $usercount = 0;
+    my ($secfilter,$grpfilter);
+    if ($context eq 'course') {
+        $secfilter = $env{'form.secfilter'};
+        $grpfilter = $env{'form.grpfilter'};
+        if ($secfilter eq '') {
+            $secfilter = 'all';
+        }
+        if ($grpfilter eq '') {
+            $grpfilter = 'all';
+        }
+    }
     # Get groups, role, permanent e-mail so we can sort on them if
     # necessary.
     foreach my $user (keys(%{$userlist})) {
@@ -2195,11 +2269,40 @@ END
             delete($userlist->{$user});
             next;
         }
-        if (ref($classgroups) eq 'HASH') {
-            $groups = $classgroups->{$user};
-        }
-        if (ref($groups->{active}) eq 'HASH') {
-            $userlist->{$user}->[$index{'groups'}] = join(', ',keys(%{$groups->{'active'}}));
+        if ($context eq 'course') {
+            my @ac_groups;
+            if (ref($classgroups) eq 'HASH') {
+                $groups = $classgroups->{$user};
+            }
+            if (ref($groups->{'active'}) eq 'HASH') {
+                @ac_groups = keys(%{$groups->{'active'}});
+                $userlist->{$user}->[$index{'groups'}] = join(', ',@ac_groups);
+            }
+            if ($mode ne 'autoenroll') {
+                my $section = $userlist->{$user}->[$index{'section'}];
+                if ($secfilter eq 'none') {
+                    if ($section ne '') {
+                        delete($userlist->{$user});
+                        next;
+                    }
+                } elsif ($secfilter ne 'all') {
+                    if ($section ne $secfilter) {
+                        delete($userlist->{$user});
+                        next;
+                    }
+                }
+                if ($grpfilter eq 'none') {
+                    if (@ac_groups > 0) {
+                        delete($userlist->{$user});
+                        next;
+                    }
+                } elsif ($grpfilter ne 'all') {
+                    if (!grep(/^\Q$grpfilter\E$/,@ac_groups)) {
+                        delete($userlist->{$user});
+                        next;
+                    }
+                }
+            }
         }
         my %emails   = &Apache::loncommon::getemails($uname,$udom);
         if ($emails{'permanentemail'} =~ /\S/) {
@@ -2736,14 +2839,48 @@ sub results_header_row {
                 $description .= &mt('All users in course with [_1] roles',$rolefilter);
             }
         }
+        my $constraint;
         my $viewablesec = &viewable_section($permission);
         if ($viewablesec ne '') {
             if ($env{'form.showrole'} eq 'st') {
-                $description .= ' '.&mt('(section [_1] only)',$viewablesec);
+                $constraint = &mt('only users in section "[_1]"',$viewablesec);
             } elsif ($env{'form.showrole'} ne 'cc') {
-                $description .= ' '.&mt('(only users affiliated with no section or section [_1])',$viewablesec);
+                $constraint = &mt('only users affiliated with no section or section "[_1]"',$viewablesec);
+            }
+            if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
+                if ($env{'form.grpfilter'} eq 'none') {
+                    $constraint .= &mt(' and not in any group');
+                } else {
+                    $constraint .= &mt(' and members of group: "[_1]"',$env{'form.grpfilter'});
+                }
+            }
+        } else {
+            if (($env{'form.secfilter'} ne 'all') && ($env{'form.secfilter'} ne '')) {
+                if ($env{'form.secfilter'} eq 'none') {
+                    $constraint = &mt('only users affiliated with no section');
+                } else {
+                    $constraint = &mt('only users affiliated with section "[_1]"',$env{'form.secfilter'});
+                }
+            }
+            if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
+                if ($env{'form.grpfilter'} eq 'none') {
+                    if ($constraint eq '') {
+                        $constraint = &mt('only users not in any group');
+                    } else {
+                        $constraint .= &mt(' and also not in any group'); 
+                    }
+                } else {
+                    if ($constraint eq '') {
+                        $constraint = &mt('only members of group: "[_1]"',$env{'form.grpfilter'});
+                    } else {
+                        $constraint .= &mt(' and also members of group: "[_1]"'.$env{'form.grpfilter'});
+                    }
+                }
             }
         }
+        if ($constraint ne '') {
+            $description .= ' ('.$constraint.')';
+        } 
     } elsif ($context eq 'author') {
         $description = 
             &mt('Author space for <span class="LC_cusr_emph">[_1]</span>',
@@ -2841,7 +2978,7 @@ sub viewable_section {
 #################################################
 #################################################
 sub show_drop_list {
-    my ($r,$classlist,$keylist,$nosort,$permission) = @_;
+    my ($r,$classlist,$nosort,$permission) = @_;
     my $cid = $env{'request.course.id'};
     my ($cnum,$cdom) = &get_course_identity($cid);
     if (! exists($env{'form.sortby'})) {
@@ -2852,9 +2989,6 @@ sub show_drop_list {
     if ($sortby !~ /^(username|domain|section|groups|fullname|id|start|end)$/) {
         $sortby = 'username';
     }
-    my ($classgroups) = &Apache::loncoursedata::get_group_memberships(
-                                              $classlist,$keylist,$cdom,$cnum);
-    #
     my $action = "drop";
     my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
     $r->print(<<END);
@@ -2867,15 +3001,40 @@ $check_uncheck_js
 <p>
 <input type="hidden" name="phase" value="four">
 END
-
-my %lt=&Apache::lonlocal::texthash('usrn'   => "username",
-                                   'dom'    => "domain",
-                                   'sn'     => "student name",
-                                   'sec'    => "section",
-                                   'start'  => "start date",
-                                   'end'    => "end date",
-                                   'groups' => "active groups",
-                                   );
+    my ($indexhash,$keylist) = &make_keylist_array();
+    my $studentcount = 0;
+    if (ref($classlist) eq 'HASH') {
+        foreach my $student (keys(%{$classlist})) {
+            my $sdata = $classlist->{$student}; 
+            my $status = $sdata->[$indexhash->{'status'}];
+            my $section = $sdata->[$indexhash->{'section'}];
+            if ($status ne 'Active') {
+                delete($classlist->{$student});
+                next;
+            }
+            if ($env{'request.course.sec'} ne '') {
+                if ($section ne $env{'request.course.sec'}) {
+                    delete($classlist->{$student});
+                    next;
+                }
+            }
+            $studentcount ++;
+        }
+    }
+    if (!$studentcount) {
+        $r->print(&mt('There are no students to drop.'));
+        return;
+    }
+    my ($classgroups) = &Apache::loncoursedata::get_group_memberships(
+                                              $classlist,$keylist,$cdom,$cnum);
+    my %lt=&Apache::lonlocal::texthash('usrn'   => "username",
+                                       'dom'    => "domain",
+                                       'sn'     => "student name",
+                                       'sec'    => "section",
+                                       'start'  => "start date",
+                                       'end'    => "end date",
+                                       'groups' => "active groups",
+                                      );
     if ($nosort) {
         $r->print(&Apache::loncommon::start_data_table().
                   &Apache::loncommon::start_data_table_header_row());
@@ -2918,32 +3077,26 @@ END
     }
     #
     # Sort the students
-    my %index;
-    my $i;
-    foreach (@$keylist) {
-        $index{$_} = $i++;
-    }
-    $index{'groups'} = scalar(@$keylist);
-    my $index  = $index{$sortby};
-    my $second = $index{'username'};
-    my $third  = $index{'domain'};
+    my $index  = $indexhash->{$sortby};
+    my $second = $indexhash->{'username'};
+    my $third  = $indexhash->{'domain'};
     my @Sorted_Students = sort {
         lc($classlist->{$a}->[$index])  cmp lc($classlist->{$b}->[$index])
             ||
         lc($classlist->{$a}->[$second]) cmp lc($classlist->{$b}->[$second])
             ||
         lc($classlist->{$a}->[$third]) cmp lc($classlist->{$b}->[$third])
-        } (keys(%$classlist));
+        } (keys(%{$classlist}));
     foreach my $student (@Sorted_Students) {
         my $error;
         my $sdata = $classlist->{$student};
-        my $username = $sdata->[$index{'username'}];
-        my $domain   = $sdata->[$index{'domain'}];
-        my $section  = $sdata->[$index{'section'}];
-        my $name     = $sdata->[$index{'fullname'}];
-        my $id       = $sdata->[$index{'id'}];
-        my $start    = $sdata->[$index{'start'}];
-        my $end      = $sdata->[$index{'end'}];
+        my $username = $sdata->[$indexhash->{'username'}];
+        my $domain   = $sdata->[$indexhash->{'domain'}];
+        my $section  = $sdata->[$indexhash->{'section'}];
+        my $name     = $sdata->[$indexhash->{'fullname'}];
+        my $id       = $sdata->[$indexhash->{'id'}];
+        my $start    = $sdata->[$indexhash->{'start'}];
+        my $end      = $sdata->[$indexhash->{'end'}];
         my $groups = $classgroups->{$student};
         my $active_groups;
         if (ref($groups->{active}) eq 'HASH') {
@@ -2959,15 +3112,8 @@ END
         } else {
             $end = &Apache::lonlocal::locallocaltime($end);
         }
-        my $status   = $sdata->[$index{'status'}];
-        next if ($status ne 'Active');
-        if ($env{'request.course.sec'} ne '') {
-            if ($section ne $env{'request.course.sec'}) {
-                next;
-            }
-        }
         my $studentkey = $student.':'.$section;
-        my $startitem = '<input type="hidden" name="'.$studentkey.'_start" value="'.$sdata->[$index{'start'}].'" />';
+        my $startitem = '<input type="hidden" name="'.$studentkey.'_start" value="'.$sdata->[$indexhash->{'start'}].'" />';
         #
         $r->print(&Apache::loncommon::start_data_table_row());
         $r->print(<<"END");
@@ -3534,7 +3680,7 @@ sub upfile_drop_add {
         if ($env{'form.fullup'} eq 'yes') {
             $r->print('<h3>'.&mt('Students to Drop')."</h3>\n");
             #  Get current classlist
-            my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist();
+            my $classlist = &Apache::loncoursedata::get_classlist();
             if (! defined($classlist)) {
                 $r->print('<form name="studentform" method="post" action="/adm/createuser" />'.
                           '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'.
@@ -3542,8 +3688,8 @@ sub upfile_drop_add {
                           '</form>'."\n");
             } else {
                 # Remove the students we just added from the list of students.
-                foreach (@userdata) {
-                    my %entries=&Apache::loncommon::record_sep($_);
+                foreach my $line (@userdata) {
+                    my %entries=&Apache::loncommon::record_sep($line);
                     unless (($entries{$fields{'username'}} eq '') ||
                             (!defined($entries{$fields{'username'}}))) {
                         delete($classlist->{$entries{$fields{'username'}}.
@@ -3551,7 +3697,7 @@ sub upfile_drop_add {
                     }
                 }
                 # Print out list of dropped students.
-                &show_drop_list($r,$classlist,$keylist,'nosort',$permission);
+                &show_drop_list($r,$classlist,'nosort',$permission);
             }
         }
     } # end of unless
@@ -3654,14 +3800,12 @@ sub print_drop_menu {
     my ($r,$context,$permission) = @_;
     $r->print('<h3>'.&mt("Drop Students").'</h3>'."\n".
               '<form name="studentform" method="post">'."\n");
-    my $cid=$env{'request.course.id'};
-    my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist();
+    my $classlist = &Apache::loncoursedata::get_classlist();
     if (! defined($classlist)) {
         $r->print(&mt('There are no students currently enrolled.')."\n");
-        return;
+    } else {
+        &show_drop_list($r,$classlist,'nosort',$permission);
     }
-    # Print out the available choices
-    &show_drop_list($r,$classlist,$keylist,$permission);
     $r->print('</form>'. &Apache::loncommon::end_page());
     return;
 }
@@ -3876,6 +4020,19 @@ sub update_user_list {
                     $plrole,$extent,$uname.':'.$udom,$result).'<br />');
         }
     }
+    $r->print('<form name="studentform" method="post" action="/adm/createuser">'."\n");
+    if ($choice eq 'drop') {
+        $r->print('<input type="hidden" name="action" value="listusers" />'."\n".
+                  '<input type="hidden" name="Status" value="Active" />'."\n".
+                  '<input type="hidden" name="showrole" value="st" />'."\n");
+    } else {
+        foreach my $item ('action','sortby','roletype','showrole','Status','secfilter','grpfilter') {
+            if ($env{'form.'.$item} ne '') {
+                $r->print('<input type="hidden" name="'.$item.'" value="'.$env{'form.'.$item}.
+                          '" />'."\n");
+            }
+        }
+    }
     $r->print('<p><b>'.&mt("$result_text{'ok'}{$choice} role(s) for [quant,_1,user,users,no users].",$count).'</b></p>');
     if ($count > 0) {
         if ($choice eq 'revoke' || $choice eq 'drop') {
@@ -3889,6 +4046,11 @@ sub update_user_list {
             $r->print(&make_dates_default($startdate,$enddate,$context));
         }
     }
+    my $linktext = &mt('Display User Lists');
+    if ($choice eq 'drop') {
+        $linktext = &mt('Display current class roster');
+    }
+    $r->print('<a href="javascript:document.studentform.submit()">'.$linktext.'</a></form>'."\n");
 }
 
 sub classlist_drop {