[LON-CAPA-cvs] cvs: loncom /interface lonfeedback.pm

raeburn lon-capa-cvs@mail.lon-capa.org
Mon, 17 Jul 2006 23:02:34 -0000


This is a MIME encoded message

--raeburn1153177354
Content-Type: text/plain

raeburn		Mon Jul 17 19:02:34 2006 EDT

  Modified files:              
    /loncom/interface	lonfeedback.pm 
  Log:
  Access to edit/hide/delete functionality in discussions in group bulletin boards dependent on group privileges.  Breadcrumbs include link back to all grups list when discussion was accessed via 'Groups' link.  For both bulletin boards and discussion attached to resources, filtered display of posts can now be based on group affiliation. For users with mdg or vcg privileges in the course, selection is from all groups, for others selection is from user's own active groups.
  
  
--raeburn1153177354
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20060717190234.txt"

Index: loncom/interface/lonfeedback.pm
diff -u loncom/interface/lonfeedback.pm:1.207 loncom/interface/lonfeedback.pm:1.208
--- loncom/interface/lonfeedback.pm:1.207	Fri Jun 30 00:49:03 2006
+++ loncom/interface/lonfeedback.pm	Mon Jul 17 19:02:33 2006
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.207 2006/06/30 04:49:03 albertel Exp $
+# $Id: lonfeedback.pm,v 1.208 2006/07/17 23:02:33 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -42,6 +42,7 @@
 use Apache::lonrss();
 use HTML::LCParser();
 use Apache::lonspeller();
+use Apache::longroup;
 use Cwd;
 use lib '/home/httpd/lib/perl/';
 use LONCAPA;
@@ -73,7 +74,7 @@
 }
 
 sub list_discussion {
-    my ($mode,$status,$ressymb,$imsextras)=@_;
+    my ($mode,$status,$ressymb,$imsextras,$group)=@_;
     my $outputtarget=$env{'form.grade_target'};
     if (defined($env{'form.export'})) {
 	if($env{'form.export'}) {
@@ -86,6 +87,11 @@
         }
     }
     if (not &discussion_visible($status)) { return ''; }
+    if ($group ne '' && $mode eq 'board') {
+        if (&check_group_priv($group,'vgb') ne 'ok') {
+            return '';
+        }
+    }
     my @bgcols = ("#cccccc","#eeeeee");
     my $discussiononly=0;
     if ($mode eq 'board') { $discussiononly=1; }
@@ -129,7 +135,7 @@
     my @posters = split/\&/,$dischash{$userpickkey};
 
 # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts.
-    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','totposters']);
+    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','grouppick','totposters']);
     my $sortposts = $env{'form.sortposts'};
     my $statusfilter = $env{'form.statusfilter'};
     my @sectionpick = ();
@@ -138,6 +144,13 @@
     } else {
         $sectionpick[0] = $env{'form.sectionpick'};
     }
+    my @grouppick = ();
+    if ($env{'form.grouppick'} =~ /,/) {
+        @grouppick = split/,/,$env{'form.grouppick'};
+    } else {
+        $grouppick[0] = $env{'form.grouppick'};
+    }
+
     my @rolefilter = ();
     if ($env{'form.rolefilter'} =~ /,/) {
         @rolefilter = split/,/,$env{'form.rolefilter'};
@@ -154,13 +167,15 @@
         }
     }
 
+    my $cdom = $env{'course.'.$cid.'.domain'};
+    my $cnum = $env{'course.'.$cid.'.num'};
+
 # Get information about students and non-students in course for filtering display of posts
     my %roleshash = ();
     my %roleinfo = ();
+    my ($classgroups,$studentgroups);
     if ($env{'form.rolefilter'}) {
-        %roleshash = &Apache::lonnet::dump('nohist_userroles',
-					   $env{'course.'.$cid.'.domain'},
-					   $env{'course.'.$cid.'.num'});
+        %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
         foreach (keys %roleshash) {
             my ($role,$uname,$udom,$sec) = split/:/,$_;
             if ($role =~ /^cr/) {
@@ -176,9 +191,8 @@
                 push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;
             }
         }
-        my ($classlist) = &Apache::loncoursedata::get_classlist(
-                              $env{'course.'.$cid.'.domain'},
-                              $env{'course.'.$cid.'.num'});
+        my ($classlist,$keylist) =
+                         &Apache::loncoursedata::get_classlist($cdom,$cnum);
         my $sec_index = &Apache::loncoursedata::CL_SECTION();
         my $status_index = &Apache::loncoursedata::CL_STATUS();
         while (my ($student,$data) = each %$classlist) {
@@ -186,6 +200,9 @@
                                  $data->[$status_index]);
             push @{$roleinfo{$student}}, 'st:'.$section.':'.$status;
         }
+	($classgroups,$studentgroups) = 
+         &Apache::loncoursedata::get_group_memberships($classlist,$keylist,
+                                                       $cdom,$cnum);
     }
 
 # Get discussion display default settings for user
@@ -225,7 +242,15 @@
     }
     $visit ++;
 
-    my $seeid=&Apache::lonnet::allowed('rin',$crs);
+    my $seeid;
+    if (($group ne '') && ($mode eq 'board') && 
+        ($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {
+        if (&check_group_priv($group,'dgp') eq 'ok') {
+            $seeid = 1;
+        }
+    } else {
+        $seeid=&Apache::lonnet::allowed('rin',$crs);
+    }
     my @discussionitems=();
     my %shown = ();
     my @posteridentity=();
@@ -252,7 +277,7 @@
     $discinfo{$visitkey} = $visit;
 
     &Apache::lonnet::put('nohist_'.$cid.'_discuss',\%discinfo,$env{'user.domain'},$env{'user.name'});
-    &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt);
+    &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);
 
     my $discussion='';
     my $manifestfile;
@@ -261,6 +286,11 @@
     my $imsresources;
     my $copyresult;
 
+    my $grp_arg;
+    if ($group ne '') {
+        $grp_arg = &grp_args($group);
+    } 
+
     my $function = &Apache::loncommon::get_users_function();
     my $color = &Apache::loncommon::designparm($function.'.tabbg',
                                                     $env{'user.domain'});
@@ -325,6 +355,9 @@
     if ($newpostsflag) {
         $chglink .= '&previous='.$prevread;
     }
+    if ($group ne '') {
+        $chglink.='&'.$grp_arg;
+    }
 
     if ($visible) {
 # Print the discusssion
@@ -403,16 +436,25 @@
 		if ($newpostsflag) {
 		    $discussion .= '&previous='.$prevread;
 		}
+                if ($group ne '') {
+                    $discussion .= '&'.$grp_arg;
+                }
 		$discussion .='">'.&mt('Threaded View').'</a>&nbsp;&nbsp;'.
 		    '<a href="/adm/feedback?cmd=threadedoff&amp;symb='.$escsymb;
 		if ($newpostsflag) {
 		    $discussion .= '&previous='.$prevread;
 		}
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
 		$discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;
                               <a href= "/adm/feedback?cmd=sortfilter&amp;symb='.$escsymb;
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
                 $discussion .='">'.&mt('Sorting/Filtering options').'</a>&nbsp;&nbsp';
             } else {
                 $discussion .= '<td align="left">';
@@ -421,12 +463,23 @@
             if ($newpostsflag) {
                 $discussion .= '&previous='.$prevread;
             }
+            if ($group ne '') {
+                $discussion .= '&amp;'.$grp_arg;
+            }
             $discussion .= '">'.&mt('Export').'?</a>&nbsp;&nbsp;</td>';
 	    if ($newpostsflag) {
 		if (!$markondisp) {
-		    $discussion .='<td align="right"><a href="/adm/preferences?action=changediscussions">'.
-			&mt('Preferences on what is marked as NEW').
-			'</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb.'">'.&mt('Mark NEW posts no longer new').'</a>';
+		    $discussion .='<td align="right"><a href="/adm/preferences?action=changediscussions';
+                    if ($group ne '') {
+                        $discussion .= '&amp;'.$grp_arg;
+                    }
+		    $discussion .= '">'.
+                        &mt('Preferences on what is marked as NEW').
+			'</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb;
+                    if ($group ne '') {
+                        $discussion .= '&amp;'.$grp_arg;
+                    }
+                    $discussion .= '">'.&mt('Mark NEW posts no longer new').'</a>';
 		} else {
 		    $discussion .= '<td>&nbsp;</td>';
 		}
@@ -443,6 +496,9 @@
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
                 $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.
                          $numhidden.' ';
                 if ($showunmark) {
@@ -611,6 +667,10 @@
                         $filterchoice = '<i>'.&mt('sections').'</i>-&nbsp;'.$env{'form.sectionpick'};
                         $filterchoice .= '&nbsp;&nbsp;&nbsp; ';
                     }
+                    if (@grouppick > 0) {
+                        $filterchoice = '<i>'.&mt('groups').'</i>-&nbsp;'.$env{'form.grouppick'};
+                        $filterchoice .= '&nbsp;&nbsp;&nbsp; ';
+                    }
                     if (@rolefilter > 0) {
                         $filterchoice .= '<i>'.&mt('roles').'</i>-';
                         foreach (@rolefilter) {
@@ -689,9 +749,8 @@
     if ($discussiononly) {
         my $now = time;
         my $attachnum = 0;
-        my $newattachmsg = '';
-        my @currnewattach = ();
-        my @currdelold = ();
+        my $currnewattach;
+        my $currdelold;
         my $comment = '';
         my $subject = '';
         if ($env{'form.origpage'}) {
@@ -699,51 +758,25 @@
             $subject = &unescape($env{'form.subject'});
             $comment = &unescape($env{'form.comment'});
             my @keepold = ();
-            &process_attachments(\@currnewattach,\@currdelold,\@keepold);
-            if (@currnewattach > 0) {
-                $attachnum += @currnewattach;
+            &process_attachments($currnewattach,$currdelold,\@keepold);
+            if (@{$currnewattach} > 0) {
+                $attachnum += @{$currnewattach};
             }
         }
 	if (&discussion_open($status)) {
-	    $discussion.=(<<ENDDISCUSS);
-<form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data">
-<input type="submit" name="discuss" value="Post Discussion" />
-<input type="submit" name="anondiscuss" value="Post Anonymous Discussion" />
-<input type="hidden" name="symb" value="$ressymb" />
-<input type="hidden" name="sendit" value="true" />
-<input type="hidden" name="timestamp" value="$now" />
-<br /><a name="newpost"></a>
-<font size="1">Note: in anonymous discussion, your name is visible only 
-to course faculty</font><br />
-<b>Title:</b>&nbsp;<input type="text" name="subject" value="$subject" size="30" /><br /><br />
-<textarea name="comment" cols="80" rows="14" wrap="hard">$comment</textarea>
-ENDDISCUSS
-            if ($env{'form.origpage'}) {
-                $discussion.='<input type="hidden" name="origpage" value="'.$env{'form.origpage'}.'" />'."\n";
-                foreach (@currnewattach) {
-                    $discussion.='<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n";
-                }
-            }
-            $discussion.="</form>\n";
-            if ($outputtarget ne 'tex') {
-                $discussion.=&generate_attachments_button('',$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,'',$mode);
-                if (@currnewattach > 0) {
-                    $newattachmsg .= '<br /><b>New attachments</b><br />';
-                    if (@currnewattach > 1) {
-                        $newattachmsg .= '<ol>';
-                        foreach my $item (@currnewattach) {
-                            $item =~ m#.*/([^/]+)$#;
-                            $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
-                        }
-                        $newattachmsg .= '</ol>'."\n";
-                    } else {
-                        $currnewattach[0] =~ m#.*/([^/]+)$#;
-                        $newattachmsg .= '<a href="'.$currnewattach[0].'">'.$1.'</a><br />'."\n";
-                    }
+            if (($group ne '') && ($mode eq 'board')) {  
+                if (&check_group_priv($group,'pgd') eq 'ok') {
+                    $discussion .=
+         &postingform_display($mode,$ressymb,$now,$subject,$comment,
+                              $outputtarget,$attachnum,$currnewattach,
+                              $currdelold,$group);
                 }
-                $discussion.=$newattachmsg;
-	        $discussion.=&generate_preview_button();
-	    }
+            } else {
+	        $discussion.= 
+         &postingform_display($mode,$ressymb,$now,$subject,$comment,
+                              $outputtarget,$attachnum,$currnewattach,
+                              $currdelold);
+            }
 	}
     } else {
 	$discussion.='<table bgcolor="#BBBBBB"><tr><td>';
@@ -766,16 +799,75 @@
     return $discussion;
 }
 
+sub postingform_display {
+    my ($mode,$ressymb,$now,$subject,$comment,$outputtarget,$attachnum,
+        $currnewattach,$currdelold,$group) = @_;
+    my $newattachmsg;
+    my $postingform = (<<ENDDISCUSS);
+<form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data"> <input type="submit" name="discuss" value="Post Discussion" />
+<input type="submit" name="anondiscuss" value="Post Anonymous Discussion" /> <input type="hidden" name="symb" value="$ressymb" />
+<input type="hidden" name="sendit" value="true" />
+<input type="hidden" name="timestamp" value="$now" />
+<br /><a name="newpost"></a>
+<font size="1">Note: in anonymous discussion, your name is visible only
+to course faculty</font><br />
+<b>Title:</b>&nbsp;<input type="text" name="subject" value="$subject" size="30" /><br /><br />
+<textarea name="comment" cols="80" rows="14" wrap="hard">$comment</textarea>
+ENDDISCUSS
+    if ($env{'form.origpage'}) {
+        $postingform .= '<input type="hidden" name="origpage" value="'.
+                        $env{'form.origpage'}.'" />'."\n";
+        foreach my $att (@{$currnewattach}) {
+            $postingform .= '<input type="hidden" name="currnewattach" '.
+                            'value="'.$att.'" />'."\n";
+        }
+    }
+    if (exists($env{'form.ref'})) {
+        $postingform .= '<input type="hidden" name="ref" value="'.
+                        $env{'form.ref'}.'" />';
+    }
+    if ($group ne '') {
+        $postingform .='<input type="hidden" name="group" value="'.$group.'" />';
+    }
+    $postingform .= "</form>\n";
+    if ($outputtarget ne 'tex') {
+        $postingform .= &generate_attachments_button('',$attachnum,$ressymb,
+                                                     $now,$currnewattach,
+                                                     $currdelold,'',$mode);
+        if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
+            $newattachmsg = '<br /><b>New attachments</b><br />';
+            if (@{$currnewattach} > 1) {
+                $newattachmsg .= '<ol>';
+                foreach my $item (@{$currnewattach}) {
+                    $item =~ m#.*/([^/]+)$#;
+                    $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
+                }
+                $newattachmsg .= '</ol>'."\n";
+            } else {
+                $$currnewattach[0] =~ m#.*/([^/]+)$#;
+                $newattachmsg .= '<a href="'.$$currnewattach[0].'">'.$1.'</a><br />'."\n";
+            }
+        }
+        $postingform .= $newattachmsg;
+        $postingform .= &generate_preview_button();
+    }
+    return $postingform;
+}
+
 sub build_posting_display {
-    my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt) = @_;
+    my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
     my @original=();
     my @index=();
+    my $skipgrpcheck = 0;
     my $symb=&Apache::lonenc::check_decrypt($ressymb);
     my $escsymb=&escape($ressymb);
     my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
 			  $env{'course.'.$env{'request.course.id'}.'.domain'},
 			  $env{'course.'.$env{'request.course.id'}.'.num'});
 
+    if ((@{$grouppick} == 0) || (grep/^all$/,@{$grouppick})) {
+        $skipgrpcheck = 1;
+    }
     if ($contrib{'version'}) {
         my $oldest = $contrib{'1:timestamp'};
         if ($prevread eq '0') {
@@ -783,7 +875,8 @@
         }
         my ($skiptest,$rolematch,$roleregexp,$secregexp,$statusregexp);
         if ($sortposts) {
-            ($skiptest,$roleregexp,$secregexp,$statusregexp) = &filter_regexp($rolefilter,$sectionpick,$statusfilter);
+            ($skiptest,$roleregexp,$secregexp,$statusregexp) = 
+                     &filter_regexp($rolefilter,$sectionpick,$statusfilter);
             $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
         } 
 	for (my $id=1;$id<=$contrib{'version'};$id++) {
@@ -872,7 +965,7 @@
                                @{$$subjectsort{$subject}} = ("$idx");
                             }
                         }
-		        if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
+		        if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
 			    $sender=&Apache::loncommon::aboutmewrapper(
 					 $plainname,
 					 $contrib{$idx.':sendername'},
@@ -913,14 +1006,18 @@
                             } else {
                                 @{$$namesort{$lastname}{$firstname}} = ("$idx");
                             }
-                            if (&editing_allowed()) {
+                            if (&editing_allowed($escsymb.':::'.$idx,$group)) {
                                 if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
                                     $sender.=' <a href="/adm/feedback?editdisc='.
                                          $escsymb.':::'.$idx;
                                     if ($$newpostsflag) {
                                         $sender .= '&previous='.$prevread;
                                     }
-                                    $sender .= '" '.$target.'>'.&mt('Edit').'</a>';                                             
+                                    if ($group ne '') {
+                                        $sender.='&amp;'.&grp_args($group);
+                                    }
+                                    $sender .= '" '.$target.'>'.&mt('Edit').'</a>';
+                                    
                                     unless ($seeid) {
                                         $sender.=" <a href=\"javascript:studentdelete('$escsymb','$idx','$$newpostsflag','$prevread')";
                                         $sender .= '">'.&mt('Delete').'</a>';
@@ -943,6 +1040,9 @@
                                     if ($$newpostsflag) {
                                         $sender .= '&previous='.$prevread;
                                     }
+                                    if ($group ne '') {
+                                        $sender.='&amp;'.&grp_args($group);
+                                    }
                                     $sender .= '">'.&mt('Hide').'</a>';
 			        }                     
 			        $sender.=' <a href="/adm/feedback?deldisc='.
@@ -950,6 +1050,9 @@
                                 if ($$newpostsflag) {
                                     $sender .= '&previous='.$prevread;
                                 }
+                                if ($group ne '') {
+                                    $sender .= '&amp;'.&grp_args($group);
+                                }
                                 $sender .= '">'.&mt('Delete').'</a>';
                             }
 		        } else {
@@ -977,16 +1080,27 @@
                                 @{$$namesort{'__anon'}{'__anon'}} = ("$idx");
                             }
 		        }
-		        if (&discussion_open($status) &&
-			        &Apache::lonnet::allowed('pch',
-						 $env{'request.course.id'}.
-						 ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
-			    $sender.=' <a href="/adm/feedback?replydisc='.
-			            $escsymb.':::'.$idx;
-                            if ($$newpostsflag) {
-                                $sender .= '&previous='.$prevread;
+		        if (&discussion_open($status)) {
+                            if (($group ne '') && 
+                                (&check_group_priv($group,'pgd') eq 'ok')) {
+                                 $sender.=' <a href="/adm/feedback?replydisc='.
+                                          $escsymb.':::'.$idx;
+                                if ($$newpostsflag) {
+                                    $sender .= '&previous='.$prevread;
+                                }
+                                $sender .= '&amp;'.&grp_args($group);
+                                $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
+                            } elsif (&Apache::lonnet::allowed('pch', 
+				 $env{'request.course.id'}.
+				 ($env{'request.course.sec'}?'/'.
+                                  $env{'request.course.sec'}:''))) {
+			         $sender.=' <a href="/adm/feedback?replydisc='.
+			                  $escsymb.':::'.$idx;
+                                if ($$newpostsflag) {
+                                    $sender .= '&previous='.$prevread;
+                                }
+                                $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
                             }
-                            $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
                         }
 		        if ($viewgrades) {
 			        $vgrlink=&Apache::loncommon::submlink('Submissions',
@@ -1043,7 +1157,7 @@
                             my $uname = $contrib{$idx.':sendername'};
                             my $udom = $contrib{$idx.':senderdomain'};
                             my $poster = $uname.':'.$udom;
-                            if (defined($env{'form.totposters'})) {
+                            if ($env{'form.totposters'} ne '') {
                                 if ($totposters == 0) {
                                     $$shown{$idx} = 0;
                                 } elsif ($totposters > 0) {
@@ -1068,6 +1182,23 @@
                                         }
                                     }
                                 }
+                                if ($$shown{$idx} && !$skipgrpcheck) {
+                                    my $showflag = 0;
+                                    if (ref($$classgroups{$poster}{active}) eq 'HASH') {
+                                        foreach my $grp (@{$grouppick}) {
+                                            if (grep/^\Q$grp\E$/,
+                                 keys(%{$$classgroups{$poster}{active}})) {
+                                                $showflag = 1;
+                                                last;
+                                            }
+                                        }
+                                    }
+                                    if ($showflag) {
+                                        $$shown{$idx} = 1;
+                                    } else {
+                                        $$shown{$idx} = 0;
+                                    }
+                                }
                             } else {
                                 $$shown{$idx} = 1;
                             }
@@ -1098,7 +1229,11 @@
                                 my @postversions = ();
                                 $$discussionitems[$idx] .= &mt('This post has been edited by the author.');
                                 if ($seeid) {
-                                    $$discussionitems[$idx] .= '&nbsp;&nbsp;<a href="/adm/feedback?allversions='.$escsymb.':::'.$idx.'">'.&mt('Display all versions').'</a>';
+                                    $$discussionitems[$idx] .= '&nbsp;&nbsp;<a href="/adm/feedback?allversions='.$escsymb.':::'.$idx;
+                                    if ($group ne '') {
+                                        $$discussionitems[$idx] .= '&amp;'.&grp_args($group);
+                                    }
+                                    $$discussionitems[$idx] .= '">'.&mt('Display all versions').'</a>';
                                 }
                                 $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
                                 if ($contrib{$idx.':history'} =~ m/:/) {
@@ -1161,6 +1296,7 @@
             $secregexp .= '[^:]*';
         }
     }
+
     if (defined($statusfilter) && $statusfilter ne '') {
         if ($statusfilter eq 'all') {
             $statusregexp = '[^:]+';
@@ -1181,7 +1317,7 @@
     %{$$imsfiles{$idx}}=();
     if ($type eq 'allversions') {
        unless($seeid) {
-           $discussion=&mt('You do not have privileges to view all versions of posts.').&mt('Please select a different role');
+           $discussion=&mt('You do not have privileges to view all versions of posts.').' '.&mt('Please select a different role.');
            return $discussion;
        } 
     }
@@ -1308,7 +1444,7 @@
 sub mail_screen {
   my ($r,$feedurl,$options) = @_;
   if (exists($env{'form.origpage'})) {
-      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog']);
+      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog','group','ref']);
   }
 
   my $title=&Apache::lonnet::gettitle($feedurl);
@@ -1550,6 +1686,12 @@
 </p>
 END
     }
+    if (exists($env{'form.group'})) {
+        $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
+    }
+    if (exists($env{'form.ref'})) {
+        $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
+    }
     $r->print(<<END);
 <p>
 <input type="hidden" name="sendit" value="1" />
@@ -1789,11 +1931,19 @@
 <input type="hidden" name="$markchg" value=""/>
 <input type="hidden" name="$toggchg" value="" />
 <input type="button" name="sub" value="Store Changes" onClick="javascript:setDisp()" />
+END
+    if (exists($env{'form.group'})) {
+        $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
+    }
+    if (exists($env{'form.ref'})) {
+        $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
+    }
+    $r->print("
 <br />
 <br />
 </form>
 $end_page
-END
+    ");
     return;
 }
 
@@ -1807,6 +1957,9 @@
     my @sections;
     my $section_sel = '';
     my $numvisible = 5;
+    my @groups;
+    my $group_sel = '';
+    my $numgroupvis = 5;
     my %sectioncount = &Apache::loncommon::get_sections();
 
     if ($env{'request.course.sec'} !~ /^\s*$/) {  #Restrict section choice to current section 
@@ -1823,7 +1976,33 @@
     foreach (@sections) {
         $section_sel .= "  <option value=\"$_\" />$_\n";
     }
-                                                                                   
+
+    if (&check_group_priv() eq 'ok') {
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; 
+        my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
+        @groups = sort {$a cmp $b} keys(%curr_groups);
+        if (scalar(@groups) < 4) {
+            $numgroupvis = scalar(@groups) + 1;
+        }
+        unshift(@groups,'all'); # Put 'all' at the front of the list
+    } else { 
+        my @coursegroups = split(/:/,$env{'request.course.groups'});
+        if (@coursegroups > 0) {
+            @coursegroups = sort {$a cmp $b} @coursegroups;
+            @groups = ('all',@coursegroups);
+            if (scalar(@groups) < 4) {
+                $numgroupvis = scalar(@groups) + 1;
+            }
+        } else {
+            @groups = ('all');
+            $numgroupvis = 1;
+        }
+    }
+    foreach (@groups) {
+        $group_sel .= "  <option value=\"$_\" />$_\n";
+    }
+
     my $function = &Apache::loncommon::get_users_function();
     my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
                                                     $env{'user.domain'});
@@ -1836,6 +2015,7 @@
         'spur' => 'Specific user roles',
         'sprs' => 'Specific role status',
         'spse' => 'Specific sections',
+        'spgr' => 'Specific groups',
         'psub' => 'Pick specific users (by name)',
         'shal' => 'Show a list of current posters'
     );
@@ -1867,6 +2047,17 @@
     if (secnum == 0) {
         document.modifyshown.sectionpick.options[0].selected = true
     }
+
+    var grpnum = 0
+    for (var i=0; i<document.modifyshown.grouppick.length; i++) {
+        if (document.modifyshown.grouppick.options[i].selected == true) {
+            grpnum ++
+        }
+    }
+    if (grpnum == 0) {
+        document.modifyshown.grouppick.options[0].selected = true
+    }
+
     document.modifyshown.submit();
 }
 </script>
@@ -1892,10 +2083,12 @@
   <td>&nbsp;</td>
   <td><b>$lt{'spse'}</b></td>
   <td>&nbsp;</td>
+  <td><b>$lt{'spgr'}</b></td>
+  <td>&nbsp;</td>
   <td><b>$lt{'psub'}</b></td>
  </tr>
  <tr>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="sortposts">
     <option value="ascdate" selected="selected" />$sort_types{'ascdate'}
     <option value="descdate" />$sort_types{'descdate'}
@@ -1906,7 +2099,7 @@
    </select>
   </td>
   <td>&nbsp;</td>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="statusfilter">
     <option value="all" selected="selected" />$status_types{'all'}
     <option value="Active" />$status_types{'Active'}
@@ -1914,7 +2107,7 @@
    </select>
   </td>
   <td>&nbsp;</td>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="rolefilter" multiple="true" size="5">
     <option value="all" />$role_types{'all'}
     <option value="st" />$role_types{'st'}
@@ -1922,18 +2115,23 @@
     <option value="in" />$role_types{'in'}
     <option value="ta" />$role_types{'ta'}
     <option value="ep" />$role_types{'ep'}
-    <option value="ad" />$role_types{'ad'}
     <option value="cr" />$role_types{'cr'}
    </select>
   </td>
   <td>&nbsp;</td>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="sectionpick" multiple="true" size="$numvisible">
     $section_sel
    </select>
   </td>
   <td>&nbsp;</td>
-  <td><label><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</label></td>
+  <td align="center" valign="top">
+   <select name="grouppick" multiple="true" size="$numvisible">
+    $group_sel
+   </select>
+  </td>
+  <td>&nbsp;</td>
+  <td valign="top"><label><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</label></td>
  </tr>
 </table>
 <br />
@@ -1941,11 +2139,19 @@
 <input type="hidden" name="previous" value="$previous" />
 <input type="hidden" name="applysort" value="$symb" />
 <input type="button" name="sub" value="Store Changes" onClick="verifyFilter()" />
+END
+    if (exists($env{'form.group'})) {
+        $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
+    }
+    if (exists($env{'form.ref'})) {
+        $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
+    }
+    $r->print("
 <br />
 <br />
 </form>
 $end_page
-END
+");
 }
 
 sub print_showposters {
@@ -1960,19 +2166,36 @@
         $crs.='_'.$env{'request.course.sec'};
     }
     $crs=~s/\_/\//g;
-    my $seeid=&Apache::lonnet::allowed('rin',$crs);
+    my $seeid;
+    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+    my $group = $env{'form.group'};
+    my $ressymb = &wrap_symb($symb);
+    if (($group ne '') &&
+        ($ressymb =~ m|^bulletin___ \d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {
+        if (&check_group_priv($group,'dgp') eq 'ok') {
+            $seeid = 1;
+        }
+    } else {
+        $seeid=&Apache::lonnet::allowed('rin',$crs);
+    }
     my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
-                          $env{'course.'.$env{'request.course.id'}.'.domain'},
-                          $env{'course.'.$env{'request.course.id'}.'.num'});
+                                         $cdom,$cnum);
     my %namesort = ();
     my %postcounts = ();
 
+    my %lt = &Apache::lonlocal::texthash(
+                                          sele => 'Select',
+                                          full => 'Fullname',
+                                          usdo => 'Username/domain',
+                                          post => 'Posts',
+                                        );
     if ($contrib{'version'}) {
         for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
             my $hidden=($contrib{'hidden'}=~/\.$idx\./);
             my $deleted=($contrib{'deleted'}=~/\.$idx\./);
             unless ((($hidden) && (!$seeid)) || ($deleted)) {
-                if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
+                if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
                     my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
                     my $lastname = $names{'lastname'};
                     my $firstname = $names{'firstname'};
@@ -2007,10 +2230,10 @@
  <br />
     $table_start
       <tr>
-       <th>No.</th>
-       <th>Select</th>
-       <th>Fullname<font color="#999999">(Username/domain)</font></th>
-       <th>Posts</th>
+       <th>#</th>
+       <th>$lt{'sele'}</th>
+       <th>$lt{'full'} <font color="#999999">($lt{'usdo'})</font></th>
+       <th>$lt{'post'}</th>
       </tr>
 END
     my $count = 0;
@@ -2121,18 +2344,18 @@
 }
 
 sub redirect_back {
-  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$numpicks) = @_;
+  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group) = @_;
   my $sorttag = '';
   my $roletag = '';
   my $statustag = '';
   my $sectag = '';
+  my $grptag = '';
   my $userpicktag = '';
   my $qrystr = '';
   my $prevtag = '';
 
   &Apache::loncommon::content_type($r,'text/html');
   $r->send_http_header;
-
   &dewrapper(\$feedurl);
   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
   if ($previous > 0) {
@@ -2171,6 +2394,20 @@
               $feedurl .= '&sectionpick='.$sectionpick;
               $sectag = '<input type="hidden" name="sectionpick" value="'.$sectionpick.'" />';
           }
+          if (ref($grouppick) eq 'ARRAY') {
+              $feedurl .= '&grouppick=';
+              $sectag .=  '<input type="hidden" name="grouppick" value="';
+              foreach my $grp (@{$grouppick}) {
+                  $feedurl .= $grp.',';
+                  $grptag .= $grp.',';
+              }
+              $feedurl =~ s/,$//;
+              $grptag =~ s/,$//;
+              $grptag .= '" />';
+          } else {
+              $feedurl .= '&grouppick='.$grouppick;
+              $grptag = '<input type="hidden" name="grouppick" value="'.$grouppick.'" />';
+          }
           if (ref($rolefilter) eq 'ARRAY') {
               $feedurl .= '&rolefilter=';
               $roletag .=  '<input type="hidden" name="rolefilter" value="';
@@ -2189,6 +2426,19 @@
           $statustag ='<input type="hidden" name="statusfilter" value="'.$statusfilter.'" />';
       }
   }
+  my $grouptag;
+  if ($group ne '') {
+      $grouptag = '<input type="hidden" name="group" value="'.$group.'" />';      my $refarg;
+      if (exists($env{'form.ref'})) {
+          $refarg = '&amp;ref='.$env{'form.ref'};
+          $grouptag .= '<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />';
+      }
+      if ($feedurl =~ /\?/) {
+          $feedurl .= '&amp;group='.$group.$refarg;
+      } else {
+          $feedurl .= '?group='.$group.$refarg;
+      }
+  } 
   $feedurl=&Apache::lonenc::check_encrypt($feedurl);
   my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
   my %onload;
@@ -2198,11 +2448,10 @@
   }
   my $start_page=
       &Apache::loncommon::start_page('Feedback sent',undef,
-				     {'redirect'    => [2,$feedurl],
+				     {'redirect'    => [0,$feedurl],
 				      'only_body'   => 1,
 				      'add_entries' => \%onload});
   my $end_page = &Apache::loncommon::end_page();
-
   $r->print(<<ENDREDIR);
 $start_page
 <img align="right" src="$logo" />
@@ -2216,7 +2465,9 @@
 $statustag
 $roletag
 $sectag
+$grptag
 $userpicktag
+$grouptag
 </form>
 $end_page
 ENDREDIR
@@ -2976,13 +3227,15 @@
 # --------------------------- Get query string for limited number of parameters
 
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-         ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly']);
+         ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']);
+  my $group = $env{'form.group'};
   if ($env{'form.editdisc'}) {
-      if (!(&editing_allowed())) {
+      if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) {
           my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
           my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
           my $feedurl=&Apache::lonnet::clutter($url);
-          &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />',                     '0','0','','',$env{'form.previous'},'','','',);
+          &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />',                     '0','0','','',$env{'form.previous'},undef,undef,undef,
+                    undef,undef,undef,$group);
           return OK;
       }
   } 
@@ -3009,7 +3262,8 @@
 			  \%readinghash,$env{'user.domain'},$env{'user.name'});
       }
       &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'<br />',
-		     '0','0','','',$env{'form.previous'},'','','',);
+		     '0','0','','',$env{'form.previous'},'','','',
+                     undef,undef,undef,$group);
       return OK;
   }
   if ($env{'form.allversions'}) {
@@ -3024,9 +3278,20 @@
           $crs.='_'.$env{'request.course.sec'};
       }
       $crs=~s|_|/|g;
-      my $seeid=&Apache::lonnet::allowed('rin',$crs);
+      my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+      my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
       my ($symb,$idx)=split(/\:\:\:/,$env{'form.allversions'});
       ($symb)=&get_feedurl_and_clean_symb($symb);
+      my $ressymb = &wrap_symb($symb);
+      my $group = $env{'form.group'};
+      my $seeid;
+      if (($group ne '') && (($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|))) {
+          if (&check_group_priv($group,'dgp') eq 'ok') {
+              $seeid = 1;
+          }
+      } else {
+          $seeid = &Apache::lonnet::allowed('rin',$crs);
+      }
       if ($idx > 0) {
           my %messages = ();
           my %subjects = ();
@@ -3058,7 +3323,7 @@
 			   \%discinfo,$env{'user.domain'},$env{'user.name'});
       &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',
 		     '',$env{'form.previous'},$env{'form.sortposts'},'','','',
-		     $numpicks);
+		     '',$numpicks,$group);
       return OK;
   }
   if ($env{'form.applysort'}) {
@@ -3066,7 +3331,8 @@
       &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',
 		     '',$env{'form.previous'},$env{'form.sortposts'},
 		     $env{'form.rolefilter'},$env{'form.statusfilter'},
-		     $env{'form.sectionpick'});
+		     $env{'form.sectionpick'},$env{'form.grouppick'},
+                     undef,$group);
       return OK;
   } elsif ($env{'form.cmd'} eq 'sortfilter') {
       my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
@@ -3171,7 +3437,7 @@
       my $previous=$env{'form.previous'};
       if ($env{'form.markondisp'}) { $previous=undef; }
       &redirect_back($r,$feedurl,&mt('Changed display status').'<br />',
-		     '0','0','','',$previous);
+		     '0','0','','',$previous,'','','','','','',$group);
       return OK;
   } elsif (($env{'form.hide'}) || ($env{'form.unhide'})) {
 # ----------------------------------------------------------------- Hide/unhide
@@ -3186,8 +3452,9 @@
       $crs=~s/\_/\//g;
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
 
-      if ($env{'form.hide'} && !$seeid && !(&editing_allowed())) {
-          &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',                 '0','0','','',$env{'form.previous'},'','','',);
+      if ($env{'form.hide'} && !$seeid && !(&editing_allowed($env{'form.hide'},$env{'form.group'}))) {
+          &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',                 '0','0','','',$env{'form.previous'},'','','','',
+                 undef,undef,$group,);
           return OK;
       }
 
@@ -3216,7 +3483,8 @@
 			   $env{'course.'.$env{'request.course.id'}.'.num'});
 
       &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
-		     '0','0','','',$env{'form.previous'});
+		     '0','0','','',$env{'form.previous'},undef,undef,undef,
+                     undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.cmd'}=~/^(threadedoff|threadedon)$/) {
       my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
@@ -3228,7 +3496,8 @@
 	  &Apache::lonnet::delenv('environment\.threadeddiscussion');
       }
       &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />',
-		     '0','0','','',$env{'form.previous'});
+		     '0','0','','',$env{'form.previous'},undef,undef,undef,
+                     undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.deldisc'}) {
 # --------------------------------------------------------------- Hide for good
@@ -3242,7 +3511,8 @@
 			   $env{'course.'.$env{'request.course.id'}.'.domain'},
 			   $env{'course.'.$env{'request.course.id'}.'.num'});
       &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
-		     '0','0','','',$env{'form.previous'});
+		     '0','0','','',$env{'form.previous'},undef,undef,undef,
+                     undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.preview'}) {
 # -------------------------------------------------------- User wants a preview
@@ -3441,7 +3711,7 @@
       }
 	  
 # Receipt screen and redirect back to where came from
-      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'});
+      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group);
   }
   return OK;
 } 
@@ -3482,7 +3752,19 @@
 }
 
 sub editing_allowed {
+    my ($postid,$group) = @_;
+    $postid = &unescape($postid);
     my $can_edit = 0;
+    if ($group ne '') {
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+        if ($postid =~ m|^bulletin___\d+___adm/wrapper(/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard)|) {
+            if (&check_group_priv($group,'egp') eq 'ok') {
+                $can_edit = 1;
+            }
+            return $can_edit;
+        }     
+    } 
     my $cid = $env{'request.course.id'};
     my $role = (split(/\./,$env{'request.role'}))[0];
     my $section = $env{'request.course.sec'};
@@ -3509,5 +3791,31 @@
     return $can_edit;
 }
 
+sub check_group_priv {
+    my ($group,$grp_priv) = @_;
+    foreach my $priv ('mdg','vcg') {
+        my $checkcourse = $env{'request.course.id'}.
+            ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'');
+        if (&Apache::lonnet::allowed($priv,$checkcourse)) {
+            return 'ok';
+        }
+    }
+    if ($grp_priv && $group ne '') {
+        if (&Apache::lonnet::allowed($grp_priv,$env{'request.course.id'}.'/'.$group)) {
+            return 'ok';
+        }
+    }
+    return '';
+}
+
+sub grp_args { 
+    my ($group) = @_;
+    my $extra_args = 'group='.$group;
+    if (exists($env{'form.ref'})) {
+        $extra_args .= '&ref='.$env{'form.ref'};
+    }
+    return $extra_args;
+}
+
 1;
 __END__

--raeburn1153177354--