--- loncom/interface/lonuserutils.pm	2010/01/20 18:22:35	1.97.2.5
+++ loncom/interface/lonuserutils.pm	2010/08/10 04:00:16	1.109.2.4
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.97.2.5 2010/01/20 18:22:35 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.109.2.4 2010/08/10 04:00:16 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -36,6 +36,7 @@ use Apache::loncommon();
 use Apache::lonhtmlcommon;
 use Apache::lonlocal;
 use Apache::longroup;
+use Apache::lonnavmaps;
 use LONCAPA qw(:DEFAULT :match);
 
 ###############################################################
@@ -91,7 +92,7 @@ sub modifyuserrole {
     if ($setting eq 'course' || $context eq 'course') {
         $scope = '/'.$cid;
         $scope =~ s/\_/\//g;
-        if ($role ne 'cc' && $sec ne '') {
+        if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) {
             $scope .='/'.$sec;
         }
     } elsif ($context eq 'domain') {
@@ -295,7 +296,7 @@ sub hidden_input {
 }
 
 sub print_upload_manager_header {
-    my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission)=@_;
+    my ($r,$datatoken,$distotal,$krbdefdom,$context,$permission,$crstype)=@_;
     my $javascript;
     #
     if (! exists($env{'form.upfile_associate'})) {
@@ -332,7 +333,7 @@ sub print_upload_manager_header {
     my $javascript_validations =
         &javascript_validations('upload',$krbdefdom,$password_choice,undef,
                                 $env{'request.role.domain'},$context,
-                                $groupslist);
+                                $groupslist,$crstype);
     my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
     $r->print('<p>'
              .&mt('Total number of records found in file: [_1]'
@@ -365,7 +366,7 @@ sub print_upload_manager_header {
 ###############################################################
 sub javascript_validations {
     my ($mode,$krbdefdom,$curr_authtype,$curr_authfield,$domain,
-        $context,$groupslist)=@_;
+        $context,$groupslist,$crstype)=@_;
     my %param = (
                   kerb_def_dom => $krbdefdom,
                   curr_authtype => $curr_authtype,
@@ -386,10 +387,10 @@ sub javascript_validations {
         if (($context eq 'course') || ($context eq 'domain')) {
             if ($context eq 'course') {
                 if ($env{'request.course.sec'} eq '') {
-                    $setsection_call = 'setSections(document.'.$param{'formname'}.');';
+                    $setsection_call = 'setSections(document.'.$param{'formname'}.",'$crstype'".');';
                     $setsections_js =
                         &setsections_javascript($param{'formname'},$groupslist,
-                                                $mode);
+                                                $mode,'',$crstype);
                 } else {
                     $setsection_call = "'ok'";
                 }
@@ -830,7 +831,7 @@ sub print_upload_manager_footer {
                .'&nbsp;'.&mt('Add a domain role').'</label>'
                .'&nbsp;&nbsp;&nbsp;<label>'
                .'<input type="radio" name="roleaction" value="course" />'
-               .'&nbsp;'.&mt('Add a course role').'</label>'
+               .'&nbsp;'.&mt('Add a course/community role').'</label>'
                .'</span>';
     } elsif ($context eq 'author') {
         $Str .= &Apache::lonhtmlcommon::row_title(
@@ -899,7 +900,7 @@ sub print_upload_manager_footer {
            .'<hr />';
     if ($context eq 'course') {
         $Str .= '<p class="LC_info">'
-               .&mt('Note: For large courses, this operation may be time consuming.')
+               .&mt('Note: This operation may be time consuming when adding several users.')
                .'</p>';
     }
     $Str .= '<p><input type="button"'
@@ -979,7 +980,7 @@ sub print_upload_manager_form {
         &Apache::loncommon::get_kerberos_defaults($defdom);
     #
     &print_upload_manager_header($r,$datatoken,$distotal,$krbdefdom,$context,
-                                 $permission);
+                                 $permission,$crstype);
     my $i;
     my $keyfields;
     if ($total>=0) {
@@ -1141,7 +1142,7 @@ sub date_setting_table {
 }
 
 sub make_dates_default {
-    my ($startdate,$enddate,$context,$crstype = @_;
+    my ($startdate,$enddate,$context,$crstype) = @_;
     my $result = '';
     if ($context eq 'course') {
         my ($cnum,$cdom) = &get_course_identity();
@@ -1176,7 +1177,7 @@ sub default_role_selector {
     my %customroles;
     my ($options,$coursepick,$cb_jscript);
     if ($context ne 'author') {
-        %customroles = &my_custom_roles();
+        %customroles = &my_custom_roles($crstype);
     }
 
     my %lt=&Apache::lonlocal::texthash(
@@ -1185,8 +1186,10 @@ sub default_role_selector {
                     'exs'  => "Existing sections",
                     'new'  => "New section",
                   );
-    $options = '<select name="defaultrole">'."\n".
-               ' <option value="">'.&mt('Please select').'</option>'."\n"; 
+    $options = '<select name="defaultrole">'."\n";
+    unless (($context eq 'course') && (&Apache::loncommon::needs_gci_custom())) {
+        $options .= ' <option value="">'.&mt('Please select').'</option>'."\n";
+    }
     if ($context eq 'course') {
         $options .= &default_course_roles($context,$checkpriv,$crstype,%customroles);
     } elsif ($context eq 'author') {
@@ -1202,16 +1205,16 @@ sub default_role_selector {
            $options .= '  <option value="'.$role.'">'.$plrole.'</option>';
         }
         my $courseform = &Apache::loncommon::selectcourse_link
-            ('studentform','dccourse','dcdomain','coursedesc',"$env{'request.role.domain'}",undef,'Course');
+            ('studentform','dccourse','dcdomain','coursedesc',"$env{'request.role.domain'}",undef,'Course/Community');
         $cb_jscript = 
-            &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform');
+            &Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'},'currsec','studentform','courserole','Course/Community');
         $coursepick = &Apache::loncommon::start_data_table().
                       &Apache::loncommon::start_data_table_header_row().
                       '<th>'.$courseform.'</th><th>'.$lt{'rol'}.'</th>'.
                       '<th>'.$lt{'grs'}.'</th>'.
                       &Apache::loncommon::end_data_table_header_row().
                       &Apache::loncommon::start_data_table_row()."\n".
-                      '<td><input type="text" name="coursedesc" value="" onfocus="this.blur();opencrsbrowser('."'studentform','dccourse','dcdomain','coursedesc',''".')" /></td>'."\n".
+                      '<td><input type="text" name="coursedesc" value="" onfocus="this.blur();opencrsbrowser('."'studentform','dccourse','dcdomain','coursedesc','','','','crstype'".')" /></td>'."\n".
                       '<td><select name="courserole">'."\n".
                       &default_course_roles($context,$checkpriv,'Course',%customroles)."\n".
                       '</select></td><td>'.
@@ -1229,6 +1232,7 @@ sub default_role_selector {
                       $env{'request.role.domain'}.'" />'.
                       '<input type="hidden" name="dccourse" value="" />'.
                       '<input type="hidden" name="dcdomain" value="" />'.
+                      '<input type="hidden" name="crstype" value="" />'.
                       '</td></tr></table></td>'.
                       &Apache::loncommon::end_data_table_row().
                       &Apache::loncommon::end_data_table()."\n";
@@ -1349,10 +1353,14 @@ sub curr_role_permissions {
 # ======================================================= Existing Custom Roles
 
 sub my_custom_roles {
+    my ($crstype) = @_;
     my %returnhash=();
     my %rolehash=&Apache::lonnet::dump('roles');
-    foreach my $key (keys %rolehash) {
+    foreach my $key (keys(%rolehash)) {
         if ($key=~/^rolesdef\_(\w+)$/) {
+            if ($crstype eq 'Community') {
+                next if ($rolehash{$key} =~ /bre\&S/); 
+            }
             $returnhash{$1}=$1;
         }
     }
@@ -1442,14 +1450,14 @@ sub print_userlist {
         return;
     }
     if (!(($context eq 'domain') && 
-        (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')))) {
+          (($env{'form.roletype'} eq 'course') || ($env{'form.roletype'} eq 'community')))) {
         $r->print('&nbsp;'.&list_submit_button(&mt('Update Display')).
                   "\n</p>\n");
     }
     my ($indexhash,$keylist) = &make_keylist_array();
     my (%userlist,%userinfo,$clearcoursepick);
     if (($context eq 'domain') && 
-        ($env{'form.roletype'} eq 'course') ||
+        ($env{'form.roletype'} eq 'course') || 
         ($env{'form.roletype'} eq 'community')) {
         my ($crstype,$numcodes,$title,$warning);
         if ($env{'form.roletype'} eq 'course') {
@@ -1553,7 +1561,8 @@ sub print_userlist {
                         }
                     }
                 }
-            } elsif ($env{'form.roletype'} eq 'course') {
+            } elsif (($env{'form.roletype'} eq 'course') ||
+                     ($env{'form.roletype'} eq 'community')) {
                 if (($env{'form.coursepick'}) && (!$clearcoursepick)) {
                     my %courses = &process_coursepick();
                     my %allusers;
@@ -1711,7 +1720,7 @@ sub section_group_filter {
             $env{'form.'.$name{$item}} = 'all';
         }
         if ($item eq 'sec') {
-            if ($env{'form.showrole'} eq 'cc') {
+            if (($env{'form.showrole'} eq 'cc') || ($env{'form.showrole'} eq 'co')) {
                 $env{'form.'.$name{$item}} = 'none';
             }
             my %sections_count = &Apache::loncommon::get_sections($cdom,$cnum);
@@ -1957,13 +1966,17 @@ sub process_coursepick {
     my $coursefilter = $env{'form.coursepick'};
     my $cdom = $env{'request.role.domain'};
     my %courses;
+    my $crssrch = 'Course';
+    if ($env{'form.roletype'} eq 'community') {
+        $crssrch = 'Community';
+    }
     if ($coursefilter eq 'all') {
         %courses = &Apache::lonnet::courseiddump($cdom,'.','.','.','.','.',
-                                                 undef,undef,'Course');
+                                                 undef,undef,$crssrch);
     } elsif ($coursefilter eq 'category') {
         my $instcode = &instcode_from_coursefilter();
         %courses = &Apache::lonnet::courseiddump($cdom,'.','.',$instcode,'.','.',
-                                                 undef,undef,'Course');
+                                                 undef,undef,$crssrch);
     } elsif ($coursefilter eq 'specific') {
         if ($env{'form.coursetotal'} > 1) {
             my @course_ids = split(/&&/,$env{'form.courselist'});
@@ -2083,6 +2096,7 @@ sub process_date_info {
 
 sub show_users_list {
     my ($r,$context,$mode,$permission,$statusmode,$userlist,$keylist,$formname)=@_;
+    my $custommenu; 
     if ($formname eq '') {
         $formname = 'studentform';
     }
@@ -2107,11 +2121,17 @@ sub show_users_list {
         $sortby = 'username';
     }
     my $setting = $env{'form.roletype'};
-    my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers,$crstype);
+    my ($cid,$cdom,$cnum,$classgroups,$displayphotos,$displayclickers,$crstype,
+        $clickersupport,$displaygroups);
     if ($context eq 'course') {
         $cid = $env{'request.course.id'};
         $crstype = &Apache::loncommon::course_type();
         ($cnum,$cdom) = &get_course_identity($cid);
+        $custommenu = &Apache::loncommon::needs_gci_custom();
+        unless ($custommenu) {
+            $clickersupport = 1;
+            $displaygroups = 1;
+        }
         ($classgroups) = &Apache::loncoursedata::get_group_memberships(
                                      $userlist,$keylist,$cdom,$cnum);
         if ($mode eq 'autoenroll') {
@@ -2148,7 +2168,7 @@ END
     } elsif ($context eq 'domain') {
         if ($setting eq 'community') {
             $crstype = 'Community';
-        } elsif ($crstype eq 'course') {
+        } elsif ($setting eq 'course') {
             $crstype = 'Course';
         }
     }
@@ -2232,6 +2252,8 @@ END
                        'role'       => "role",
                        'type'       => "enroll type/action",
                        'email'      => "e-mail address",
+                       'lastlogin'  => "last login",
+                       'submissions' => "test status",
                        'photo'      => "photo",
                        'extent'     => "extent",
                        'pr'         => "Proceed",
@@ -2261,7 +2283,7 @@ END
             push(@cols,'section');
         }
         if (!($context eq 'domain' && ($env{'form.roletype'} eq 'course')
-                              && ($env{'form.roletype'} eq 'community'))) {
+                              && ($env{'form.roletype'} eq 'community'))) { 
             push(@cols,('start','end'));
         }
         if ($env{'form.showrole'} eq 'Any' || $env{'form.showrole'} eq 'cr') {
@@ -2272,35 +2294,48 @@ END
                                     $env{'form.roletype'} eq 'community')) {
             push (@cols,'extent');
         }
-        if (($statusmode eq 'Any') &&
+        if (($statusmode eq 'Any') && 
             (!($context eq 'domain' && (($env{'form.roletype'} eq 'course')
              || ($env{'form.roletype'} eq 'community'))))) {
             push(@cols,'status');
         }
         if ($context eq 'course') {
-            push(@cols,'groups');
+            if ($displaygroups) {
+                push(@cols,'groups');
+            }
         }
         push(@cols,'email');
+        if ($context eq 'course') {
+            if ($custommenu) {
+                push(@cols,'lastlogin');
+                if (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'st')) {
+                    push(@cols,'submissions');
+                }
+            }
+        }
     }
 
     my $rolefilter = $env{'form.showrole'};
     if ($env{'form.showrole'} eq 'cr') {
         $rolefilter = &mt('custom');  
     } elsif ($env{'form.showrole'} ne 'Any') {
-        $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'});
+        $rolefilter = &Apache::lonnet::plaintext($env{'form.showrole'},$crstype);
     }
     my $results_description;
     if ($mode ne 'autoenroll') {
         $results_description = &results_header_row($rolefilter,$statusmode,
                                                    $context,$permission,$mode,$crstype);
-
         $r->print('<b>'.$results_description.'</b><br /><br />');
     }
     my ($output,$actionselect,%canchange,%canchangesec);
     if ($mode eq 'html' || $mode eq 'view' || $mode eq 'autoenroll' || $mode eq 'pickauthor') {
         if ($mode ne 'autoenroll' && $mode ne 'pickauthor') {
             if ($permission->{'cusr'}) {
-                $actionselect = &select_actions($context,$setting,$statusmode,$formname);
+                unless (($context eq 'domain') && 
+                        (($setting eq 'course') || ($setting eq 'community'))) {
+                    $actionselect = 
+                        &select_actions($context,$setting,$statusmode,$formname);
+                }
             }
             $r->print(<<END);
 <input type="hidden" name="srchby"  value="uname" />
@@ -2311,7 +2346,7 @@ END
 END
             if ($actionselect) {
                 $output .= <<"END";
-<div class="LC_left_float"><fieldset><legend><b>$lt{'ac'}</b></legend>
+<div class="LC_left_float"><fieldset><legend>$lt{'ac'}</legend>
 $actionselect
 <br/><br /><input type="button" value="$lt{'ca'}" onclick="javascript:checkAll(document.$formname.actionlist)" /> &nbsp;
 <input type="button" value="$lt{'ua'}" onclick="javascript:uncheckAll(document.$formname.actionlist)" /><br /><input type="button" value="$lt{'pr'}" onclick="javascript:verify_action('actionlist')" /></fieldset></div>
@@ -2356,7 +2391,7 @@ END
                     }
                 }
             }
-            $output .= '<div class="LC_left_float"><fieldset><legend><b>'.$lt{'link'}.'</b></legend>'.
+            $output .= '<div class="LC_left_float"><fieldset><legend>'.$lt{'link'}.'</legend>'.
                        '<table><tr>';
             my @linkdests = ('aboutme');
             if ($permission->{'cusr'}) {
@@ -2367,6 +2402,7 @@ END
                                          $env{'request.course.sec'})) {
                 push(@linkdests,'track');
             }
+
             $output .= '<td>';
             my $usernamelink = $env{'form.usernamelink'};
             if ($usernamelink eq '') {
@@ -2393,37 +2429,38 @@ END
  <th><a href=\"javascript:document.$formname.sortby.value='type';document.$formname.submit();\">$lt{'type'}</a></th>
             ";
         } else {
-            if ($mode eq 'pickauthor') {
-                $output .= "\n".'<th>&nbsp;</th>'."\n";
-            } else { 
-                $output .= "\n".'<th>'.&mt('Count').'</th>'."\n";
-            }
+            $output .= "\n".'<th>&nbsp;</th>'."\n";
             if ($actionselect) {
                 $output .= '<th>'.&mt('Select').'</th>'."\n";
             }
         }
         foreach my $item (@cols) {
-            $output .= "<th><a href=\"javascript:document.$formname.sortby.value='$item';document.$formname.submit();\">$lt{$item}</a></th>\n";
+            if (grep(/^\Q$item\E$/,@sortable)) {
+                $output .= "<th><a href=\"javascript:document.$formname.sortby.value='$item';document.$formname.submit();\">$lt{$item}</a></th>\n";
+            } else {
+                $output .= "<th>$lt{$item}</th>\n";
+            }
         }
         my %role_types = &role_type_names();
         if ($context eq 'course' && $mode ne 'autoenroll') {
             if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
                 # Clicker display on or off?
-                my %clicker_options = (
-                                        'on' => 'Show',
-                                        'off' => 'Hide',
-                                      );
-                my $clickerchg = 'on';
-                if ($displayclickers eq 'on') {
-                    $clickerchg = 'off';
-                }
-                $output .= '    <th>'."\n".'     '
-                        .&mt('[_1]'.$clicker_options{$clickerchg}.'[_2] clicker id'
+                if ($clickersupport) {
+                    my %clicker_options = (
+                                            'on' => 'Show',
+                                            'off' => 'Hide',
+                                          );
+                    my $clickerchg = 'on';
+                    if ($displayclickers eq 'on') {
+                        $clickerchg = 'off';
+                    }
+                    $output .= '    <th>'."\n".'     '
+                       .&mt('[_1]'.$clicker_options{$clickerchg}.'[_2] clicker id'
                             ,'<a href="javascript:document.'.$formname.'.displayclickers.value='
                              ."'".$clickerchg."'".';document.'.$formname.'.submit();">'
                             ,'</a>')
                         ."\n".'    </th>'."\n";
-
+                }
                 # Photo display on or off?
                 if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                     my %photo_options = &Apache::lonlocal::texthash(
@@ -2452,20 +2489,28 @@ END
                        time.'_'.rand(1000000000).'.csv';
         unless ($CSVfile = Apache::File->new('>/home/httpd'.$CSVfilename)) {
             $r->log_error("Couldn't open $CSVfilename for output $!");
-            $r->print(&mt('Problems occurred in writing the CSV file. '
-                         .'This error has been logged. '
-                         .'Please alert your LON-CAPA administrator.'));
+            $r->print(
+                '<p class="LC_error">'
+               .&mt('Problems occurred in writing the CSV file.')
+               .' '.&mt('This error has been logged.')
+               .' '.&mt('Please alert your LON-CAPA administrator.')
+               .'</p>'
+            );
             $CSVfile = undef;
         }
         #
-        push @cols,'clicker';
+        if ($clickersupport) {
+            push @cols,'clicker';
+        }
         # Write headers and data to file
         print $CSVfile '"'.$results_description.'"'."\n"; 
         print $CSVfile '"'.join('","',map {
             &Apache::loncommon::csv_translate($lt{$_})
             } (@cols))."\"\n";
     } elsif ($mode eq 'excel') {
-        push @cols,'clicker';
+        if ($clickersupport) {
+            push @cols,'clicker';
+        }
         # Create the excel spreadsheet
         ($excel_workbook,$excel_filename,$format) =
             &Apache::loncommon::create_workbook($r);
@@ -2501,6 +2546,40 @@ END
                                                 Future  => 'Future',
                                                 Expired => 'Expired',
                                                );
+    # If this is for a single course get last course "log-in" and submissions.
+    my (%crslogins,%stusubmissions,%elapsed,$numparts,%nummultipart,$multipart);
+    my $now = time;
+    if ($context eq 'course') {
+        if ($custommenu) {
+            %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum);
+            %stusubmissions=&Apache::lonnet::dump('nohist_submissiontracker',$cdom,$cnum);
+            %elapsed = &Apache::lonlocal::texthash(    
+                                         -1 => 'more than a month ago',
+                                    2592000 => 'within last 30 days',
+                                     604800 => 'within last 7 days',
+                                      86400 => 'within last 24 hours',
+                                   );
+            my $navmap = Apache::lonnavmaps::navmap->new();
+            if (defined($navmap)) {
+                my @allres=$navmap->retrieveResources('/uploaded/'.$cdom.'/'.$cnum.'/default_1261144274.sequence',sub { $_[0]->is_problem() },0);
+                foreach my $resource (@allres) {
+                    my @parts = $resource->parts();
+                    my $count = scalar(@parts);
+                    if ($count > 1) {
+                        $nummultipart{$count} ++;
+                    }
+                    $numparts += $count;
+                }
+                if (keys(%nummultipart) > 0) {
+                   $multipart = '<br />'.'contains';
+                   foreach my $key (sort {$a <=> $b} keys(%nummultipart)) {
+                       $multipart .= " nummultipart{$key} multipart questions (with $key parts)";
+                   }
+                }
+            }
+        }
+    }
+
     # Get groups, role, permanent e-mail so we can sort on them if
     # necessary.
     foreach my $user (keys(%{$userlist})) {
@@ -2636,7 +2715,7 @@ END
         if ($clickers!~/\w/) { $clickers='-'; }
         $in{'clicker'} = $clickers; 
 	my $role = $in{'role'};
-        $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype); 
+        $in{'role'}=&Apache::lonnet::plaintext($sdata->[$index{'role'}],$crstype);
         if (! defined($in{'start'}) || $in{'start'} == 0) {
             $in{'start'} = &mt('none');
         } else {
@@ -2647,6 +2726,34 @@ END
         } else {
             $in{'end'} = &Apache::lonlocal::locallocaltime($in{'end'});
         }
+        if ($context eq 'course') {
+            if ($custommenu) {
+                my $lastlogin = $crslogins{$in{'username'}.':'.$in{'domain'}.':'.$in{'section'}.':'.$role};
+                if ($lastlogin ne '') {
+                    my $sincelogin = $now - $lastlogin;
+                    if ($sincelogin < 86400) {
+                        $in{'lastlogin'} = $elapsed{'86400'};
+                    } elsif ($sincelogin < 604800) {
+                        $in{'lastlogin'} = $elapsed{'604800'};
+                    } elsif ($sincelogin < 2592000 ) {
+                        $in{'lastlogin'} = $elapsed{'2592000'};
+                    } else {
+                        $in{'lastlogin'} = $elapsed{'-1'};
+                    }
+                }
+            }
+            if ($role eq 'st') {
+                my $numsub = $stusubmissions{$in{'username'}.':'.$in{'domain'}."\0attempts"} + 
+                             $stusubmissions{$in{'username'}.':'.$in{'domain'}."\0pilotsubs"};
+                if (!$numsub) {
+                    $in{'submissions'} = 'not attempted';
+                } elsif ($numsub < $numparts) {
+                    $in{'submissions'} = 'incomplete ('.$numsub.'/'.$numparts.')';
+                } else {
+                    $in{'submissions'} = 'completed';
+                }
+            }
+        }
         if ($mode eq 'view' || $mode eq 'html' || $mode eq 'autoenroll' || $mode eq 'pickauthor') {
             $r->print(&Apache::loncommon::start_data_table_row());
             my $checkval;
@@ -2720,19 +2827,27 @@ END
                         $showitem = $ltstatus{$in{$item}};
                     }
                     $r->print('<td>'.$showitem.'</td>'."\n");
+                } elsif ($item eq 'submissions') {
+                    if ($in{$item} =~ /^incomplete/) { 
+                        $r->print('<td>'.$in{$item}.$multipart.'</td>');
+                    } else {
+                        $r->print('<td>'.$in{$item}.'</td>'."\n");
+                    }
                 } else {
                     $r->print('<td>'.$in{$item}.'</td>'."\n");
                 }
             }
             if (($context eq 'course') && ($mode ne 'autoenroll')) {
                 if ($env{'form.showrole'} eq 'st' || $env{'form.showrole'} eq 'Any') {
-                    if ($displayclickers eq 'on') {
-                        my $clickers =
+                    if ($clickersupport) {
+                        if ($displayclickers eq 'on') {
+                            my $clickers =
                    (&Apache::lonnet::userenvironment($in{'domain'},$in{'username'},'clickers'))[1];
-                        if ($clickers!~/\w/) { $clickers='-'; }
-                        $r->print('<td>'.$clickers.'</td>');
-                    } else {
-                        $r->print('    <td>&nbsp;</td>  ');
+                            if ($clickers!~/\w/) { $clickers='-'; }
+                            $r->print('<td>'.$clickers.'</td>');
+                        } else {
+                            $r->print('    <td>&nbsp;</td>  ');
+                        }
                     }
                     if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
                         if ($displayphotos eq 'on' && $role eq 'st' && $in{'photo'} ne '') {
@@ -2935,7 +3050,6 @@ sub role_type_names {
                          'author' => 'Co-Author Roles',
                          'course' => 'Course Roles',
                          'community' => 'Community Roles',
-
              );
     return %lt;
 }
@@ -3097,7 +3211,7 @@ END
         } else {
             opener.document.$callingform.retainsec.value = formname.retainsec.value;
         }
-        setSections(formname);
+        setSections(formname,'$crstype');
         if (seccheck == 'ok') {
             opener.document.$callingform.newsecs.value = formname.sections.value;
         }
@@ -3157,7 +3271,7 @@ ENDJS
                  fors => 'For student roles changing the section, will result in a section switch as students may only be in one section of a course at a time.',
                  forn => 'For a role in a course that is not a student role, a user may have roles in more than one section of a course at a time.',
                  reta => "Retain each user's current section affiliations?", 
-                 dnap => '(Does not apply to student roles).', 
+                 dnap => '(Does not apply to student roles).',
             );
     my ($date_items,$headertext);
     if ($env{'form.bulkaction'} eq 'chgsec') {
@@ -3178,6 +3292,12 @@ ENDJS
                 $date_items;
     if ($context eq 'course' && $env{'form.bulkaction'} eq 'chgsec') {
         my ($cnum,$cdom) = &get_course_identity();
+        my $crstype = &Apache::loncommon::course_type();
+        if ($crstype eq 'Community') {
+            $lt{'fors'} = &mt('For member roles changing the section, will result in a section switch as members may only be in one section of a community at a time.');
+            $lt{'forn'} = &mt('For a role in a community that is not a member role, a user may have roles in more than one section of a community at a time.');
+            $lt{'dnap'} = &mt('(Does not apply to member roles).'); 
+        }
         my $info;
         if ($env{'form.showrole'} eq 'st') {
             $output .= '<p>'.$lt{'fors'}.'</p>'; 
@@ -3294,7 +3414,7 @@ sub results_header_row {
         if ($viewablesec ne '') {
             if ($env{'form.showrole'} eq 'st') {
                 $constraint = &mt('only users in section "[_1]"',$viewablesec);
-            } elsif ($env{'form.showrole'} ne 'cc') {
+            } elsif (($env{'form.showrole'} ne 'cc') && ($env{'form.showrole'} ne 'co')) {
                 $constraint = &mt('only users affiliated with no section or section "[_1]"',$viewablesec);
             }
             if (($env{'form.grpfilter'} ne 'all') && ($env{'form.grpfilter'} ne '')) {
@@ -3384,7 +3504,6 @@ sub results_header_row {
             }
         } elsif (($env{'form.roletype'} eq 'course') || 
                  ($env{'form.roletype'} eq 'community')) {
-
             my $coursefilter = $env{'form.coursepick'};
             if ($env{'form.roletype'} eq 'course') {
                 if ($coursefilter eq 'category') {
@@ -3444,6 +3563,10 @@ sub show_drop_list {
     my ($r,$classlist,$nosort,$permission,$crstype) = @_;
     my $cid = $env{'request.course.id'};
     my ($cnum,$cdom) = &get_course_identity($cid);
+    my $displaygroups;
+    unless (&Apache::loncommon::needs_gci_custom()) {
+        $displaygroups = 1;
+    }
     if (! exists($env{'form.sortby'})) {
         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                                                 ['sortby']);
@@ -3521,8 +3644,10 @@ END
     <th>$lt{'sec'}</th>
     <th>$lt{'start'}</th>
     <th>$lt{'end'}</th>
-    <th>$lt{'groups'}</th>
 END
+        if ($displaygroups) {
+            $r->print("    <th>$lt{'groups'}</th>\n");
+        }
         $r->print(&Apache::loncommon::end_data_table_header_row());
     } else  {
         $r->print(&Apache::loncommon::start_data_table().
@@ -3543,10 +3668,13 @@ END
        <a href="/adm/createuser?action=$action&sortby=start">$lt{'start'}</a>
     </th><th>
        <a href="/adm/createuser?action=$action&sortby=end">$lt{'end'}</a>
-    </th><th>
-       <a href="/adm/createuser?action=$action&sortby=groups">$lt{'groups'}</a>
     </th>
 END
+       if ($displaygroups) {
+           $r->print("<th>
+       <a href=\"/adm/createuser?action=$action&sortby=groups\">$lt{'groups'}</a>
+    </th>\n");
+        }
         $r->print(&Apache::loncommon::end_data_table_header_row());
     }
     #
@@ -3599,8 +3727,10 @@ END
     <td>$section</td>
     <td>$start $startitem</td>
     <td>$end</td>
-    <td>$active_groups</td>
 END
+        if ($displaygroups) {
+            $r->print("    <td>$active_groups</td>\n");
+        }
         $r->print(&Apache::loncommon::end_data_table_row());
     }
     $r->print(&Apache::loncommon::end_data_table().'<br />');
@@ -3637,23 +3767,18 @@ sub print_first_users_upload_form {
     $str .= '<input type="hidden" name="action" value="upload" />';
     $str .= '<input type="hidden" name="state"  value="got_file" />';
 
-
-    $str .= '<h2>'.&mt('Upload a file containing information about users').'</h2>'."\n";
+    $str .= '<h3>'.&mt('Upload a file containing information about users').'</h3>'."\n";
 
     # Excel and CSV Help
-    $str .= '<p>'
+    $str .= '<div class="LC_left_float">'
            .&Apache::loncommon::help_open_topic("Course_Create_Class_List",
                 &mt("How do I create a users list from a spreadsheet"))
-           ."<br />\n"
+           .'</div><div class="LC_left_float">'."\n"
            .&Apache::loncommon::help_open_topic("Course_Convert_To_CSV",
                 &mt("How do I create a CSV file from a spreadsheet"))
-           ."</p>\n";
-
+           .'</div><br clear="all" />'."\n";
     $str .= &Apache::lonhtmlcommon::start_pick_box()
            .&Apache::lonhtmlcommon::row_title(&mt('File'))
-           .'<p class="LC_info">'."\n"
-           .&mt('Please upload an UTF8 encoded file to ensure a correct character encoding in your classlist.')."\n"
-           .'</p>'."\n"
            .&Apache::loncommon::upfile_select_html()
            .&Apache::lonhtmlcommon::row_closure()
            .&Apache::lonhtmlcommon::row_title(
@@ -3668,8 +3793,6 @@ sub print_first_users_upload_form {
            .'<input type="submit" name="fileupload" value="'.&mt('Next').'" />'
            .'</p>';
 
-    $str .= &Apache::loncommon::end_page();
-
     $r->print($str);
     return;
 }
@@ -3731,7 +3854,7 @@ sub upfile_drop_add {
     }
     my ($startdate,$enddate) = &get_dates_from_form();
     if ($env{'form.makedatesdefault'}) {
-        $r->print(&make_dates_default($startdate,$enddate,$context,$crstype);
+        $r->print(&make_dates_default($startdate,$enddate,$context,$crstype));
     }
     # Determine domain and desired host (home server)
     my $defdom=$env{'request.role.domain'};
@@ -3790,7 +3913,7 @@ sub upfile_drop_add {
         } elsif ($setting eq 'course') {
             $defaultrole = $env{'form.courserole'};
             $defaultsec = $env{'form.sections'};
-        }
+        }  
     } elsif ($context eq 'author') {
         $defaultrole = $env{'form.defaultrole'};
     } elsif ($context eq 'course') {
@@ -3898,7 +4021,7 @@ sub upfile_drop_add {
             }
         }
         my (%curr_rules,%got_rules,%alerts);
-        my %customroles = &my_custom_roles();
+        my %customroles = &my_custom_roles($crstype);
         my @permitted_roles = 
             &roles_on_upload($context,$setting,$crstype,%customroles); 
         # Get new users list
@@ -4142,7 +4265,7 @@ sub upfile_drop_add {
                                         $role = 'cr_'.$env{'user.domain'}.'_'.
                                                 $env{'user.name'}.'_'.$role;
                                     }
-                                    if ($role ne 'cc') { 
+                                    if (($role ne 'cc') && ($role ne 'co')) { 
                                         if (@secs > 1) {
                                             $multiple = 1;
                                             foreach my $sec (@secs) {
@@ -4503,7 +4626,7 @@ sub update_user_list {
                 }
             } elsif ($choice eq 'chgsec') {
                 my (@newsecs,$revresult,$nochg,@retained);
-                if ($role ne 'cc') {
+                if (($role ne 'cc') && ($role ne 'co')) {
                     @newsecs = split(/,/,$env{'form.newsecs'});
                 }
                 # remove existing section if not to be retained.   
@@ -4758,7 +4881,7 @@ sub get_groupslist {
 }
 
 sub setsections_javascript {
-    my ($formname,$groupslist,$mode,$checkauth) = @_;
+    my ($formname,$groupslist,$mode,$checkauth,$crstype) = @_;
     my ($checkincluded,$finish,$rolecode,$setsection_js);
     if ($mode eq 'upload') {
         $checkincluded = 'formname.name == "'.$formname.'"';
@@ -4797,8 +4920,11 @@ sub setsections_javascript {
     }
     my %alerts = &Apache::lonlocal::texthash(
                     secd => 'Section designations do not apply to Course Coordinator roles.',
+                    sedn => 'Section designations do not apply to Coordinator roles.',
                     accr => 'A course coordinator role will be added with access to all sections.',
+                    acor => 'A coordinator role will be added with access to all sections',
                     inea => 'In each course, each user may only have one student role at a time.',
+                    inec => 'In each community, each user may only have on member role at a time.',
                     youh => 'You had selected ',
                     secs => 'sections.',
                     plmo => 'Please modify your selections so they include no more than one section.',
@@ -4809,7 +4935,7 @@ sub setsections_javascript {
                  );                
     $setsection_js .= <<"ENDSECCODE";
 
-function setSections(formname) {
+function setSections(formname,crstype) {
     var re1 = /^currsec_/;
     var groups = new Array($groupslist);
     for (var i=0;i<formname.elements.length;i++) {
@@ -4818,10 +4944,13 @@ function setSections(formname) {
         if (checkcurr != null) {
             if ($checkincluded) {
                 $rolecode
-                if (role == 'cc') {
-                    alert("$alerts{'secd'}\\n$alerts{'accr'}");
-                }
-                else {
+                if (role == 'cc' || role == 'co') {
+                    if (role == 'cc') {
+                        alert("$alerts{'secd'}\\n$alerts{'accr'}");
+                    } else {
+                        alert("$alerts{'sedn'}\\n$alerts{'acor'}");
+                    }
+                } else {
                     var sections = '';
                     var numsec = 0;
                     var sections;
@@ -4857,7 +4986,11 @@ function setSections(formname) {
                     }
 
                     if ((role == 'st') && (numsec > 1)) {
-                        alert("$alerts{'inea'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}")
+                        if (crstype == 'Community') {
+                            alert("$alerts{'inea'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}");
+                        } else {
+                            alert("$alerts{'inco'} $alerts{'youh'} "+numsec+" $alerts{'secs'}\\n$alerts{'plmo'}");
+                        }
                         return;
                     }
                     else {
@@ -5002,14 +5135,22 @@ sub roles_by_context {
         if ($env{'request.role'} =~ m{^dc\./}) {
             push(@allroles,'ad');
         }
-        push(@allroles,('ta','ep','in'));
-        if ($crstype eq 'Community') {
-            push(@allroles,'co');
+        if (&Apache::loncommon::needs_gci_custom()) {
+            if ($crstype eq 'Community') {
+                push(@allroles,'co');
+            } else {
+                push(@allroles,'cc');
+            }
         } else {
-            push(@allroles,'cc');
-        }
-        if ($custom) {
-            push(@allroles,'cr');
+            push(@allroles,('ta','ep','in'));
+            if ($crstype eq 'Community') {
+                push(@allroles,'co');
+            } else {
+                push(@allroles,'cc');
+            }
+            if ($custom) {
+                push(@allroles,'cr');
+            }
         }
     } elsif ($context eq 'author') {
         @allroles = ('ca','aa');
@@ -5131,6 +5272,7 @@ sub dc_setcourse_js {
     my ($formname,$mode,$context) = @_;
     my ($dc_setcourse_code,$authen_check);
     my $cctext = &Apache::lonnet::plaintext('cc');
+    my $cotext = &Apache::lonnet::plaintext('co');
     my %alerts = &sectioncheck_alerts();
     my $role = 'role';
     if ($mode eq 'upload') {
@@ -5177,7 +5319,11 @@ function setCourse() {
             numsections = numsections + newsecs.length;
         }
         if ((userrole == 'st') && (numsections > 1)) {
-            alert("$alerts{'inea'}. $alerts{'youh'} "+numsections+" $alerts{'sect'}.\\n$alerts{'plsm'}.")
+            if (document.$formname.crstype.value == 'Community') {
+                alert("$alerts{'inco'}. $alerts{'youh'} "+numsections+" $alerts{'sect'}.\\n$alerts{'plsm'}.")
+            } else {
+                alert("$alerts{'inea'}. $alerts{'youh'} "+numsections+" $alerts{'sect'}.\\n$alerts{'plsm'}.")
+            }
             return;
         }
         for (var j=0; j<newsecs.length; j++) {
@@ -5189,7 +5335,11 @@ function setCourse() {
                 var groups = document.$formname.groups.value.split(/,/g);
                 for (var k=0; k<groups.length; k++) {
                     if (newsecs[j] == groups[k]) {
-                        alert("'"+newsecs[j]+"' $alerts{'mayt'}.\\n$alerts{'secn'}. $alerts{'plsc'}.");
+                        if (document.$formname.crstype.value == 'Community') {
+                            alert("'"+newsecs[j]+"' $alerts{'mayc'}.\\n$alerts{'secn'}. $alerts{'plsc'}.");
+                        } else {
+                            alert("'"+newsecs[j]+"' $alerts{'mayt'}.\\n$alerts{'secn'}. $alerts{'plsc'}.");
+                        }
                         return;
                     }
                 }
@@ -5199,13 +5349,21 @@ function setCourse() {
             alert("$alerts{'secd'} $cctext $alerts{'role'}.\\n$alerts{'accr'}.");
             section = "";
         }
+        if ((userrole == 'co') && (numsections > 0)) {
+            alert("$alerts{'secd'} $cotext $alerts{'role'}.\\n$alerts{'accr'}.");
+            section = "";
+        }
 SCRIPTTOP
     if ($mode ne 'upload') {
         $dc_setcourse_code .= (<<"ENDSCRIPT");
         var coursename = "_$env{'request.role.domain'}"+"_"+course+"_"+userrole
         var numcourse = getIndex(document.$formname.dccourse);
         if (numcourse == "-1") {
-            alert("$alerts{'thwa'}");
+            if (document.$formname.type == 'Community') {
+                alert("$alerts{'thwc'}");
+            } else {
+                alert("$alerts{'thwa'}");
+            }
             return;
         }
         else {
@@ -5314,19 +5472,22 @@ ENDSCRIPT
 
 sub sectioncheck_alerts {
     my %alerts = &Apache::lonlocal::texthash(
-                    curd => 'You must select a course in the current domain',
+                    curd => 'You must select a course or community in the current domain',
                     inea => 'In each course, each user may only have one student role at a time',
+                    inco => 'In each community, each user may only have one member role at a time', 
                     youh => 'You had selected',
                     sect => 'sections',
                     plsm => 'Please modify your selections so they include no more than one section',
                     mayn => 'may not be used as the name for a section, as it is a reserved word',
                     plsc => 'Please choose a different section name',
                     mayt => 'may not be used as the name for a section, as it is the name of a course group',
+                    mayc => 'may not be used as the name for a section, as it is the name of a community group',
                     secn => 'Section names and group names must be distinct',
                     secd => 'Section designations do not apply to ',
                     role => 'roles',
                     accr => 'role will be added with access to all sections',
-                    thwa => 'There was a problem with your course selection'
+                    thwa => 'There was a problem with your course selection',
+                    thwc => 'There was a problem with your community selection',
                  );
     return %alerts;
 }