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

raeburn raeburn at source.lon-capa.org
Sun Apr 29 23:51:40 EDT 2012


raeburn		Mon Apr 30 03:51:40 2012 EDT

  Modified files:              (Branch: loncapaMITrelate_1)
    /loncom/interface	lonfeedback.pm 
  Log:
  - Customization for MITrelate
    - Backport 1.331 (part), 1.332, 1.333, 1.339, 1.344, 1.345, 1.346, 1.347, 
               1.348, 1.349, 1.351, 1.352, 1.353.
  
  
-------------- next part --------------
Index: loncom/interface/lonfeedback.pm
diff -u loncom/interface/lonfeedback.pm:1.290.2.7.2.3 loncom/interface/lonfeedback.pm:1.290.2.7.2.4
--- loncom/interface/lonfeedback.pm:1.290.2.7.2.3	Fri Mar  9 15:09:39 2012
+++ loncom/interface/lonfeedback.pm	Mon Apr 30 03:51:40 2012
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.290.2.7.2.3 2012/03/09 15:09:39 raeburn Exp $
+# $Id: lonfeedback.pm,v 1.290.2.7.2.4 2012/04/30 03:51:40 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -82,6 +82,26 @@
     return 1;
 }
 
+sub discussion_vote_available {
+    my ($status,$symb)=@_;
+    my $canvote=&Apache::lonnet::EXT('resource.0.discussvote',$symb);
+    if ((lc($canvote) eq 'yes') ||
+        ((lc($canvote) eq 'notended') && (&discussion_open($status,$symb)))) {
+        return 1;
+    }
+}
+
+sub get_realsymb {
+    my ($symb) = @_;
+    my $realsymb = $symb;
+    if ($symb=~/^bulletin___/) {
+        my $filename=(&Apache::lonnet::decode_symb($symb))[2];
+        $filename=~s{^adm/wrapper/}{};
+        $realsymb=&Apache::lonnet::symbread($filename);
+    }
+    return $realsymb;
+}
+
 sub list_discussion {
     my ($mode,$status,$ressymb,$imsextras,$group)=@_;
     unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); }
@@ -257,14 +277,14 @@
     $visit ++;
 
     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);
+    if (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
+        $seeid = 1;
     }
+    my $seehidden = &can_see_hidden($mode,$ressymb,undef,$group,$cdom,$cnum,$crs);
+# Is voting on discussions available
+    my $realsymb = &get_realsymb($ressymb);
+    my $canvote = &discussion_vote_available($status,$realsymb);
+
     my @discussionitems=();
     my %shown = ();
     my @posteridentity=();
@@ -291,7 +311,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,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);
+    &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,$seehidden,$canvote,$prevread,$sortposts,$encsymb,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);
 
     my $discussion='';
     my $manifestfile;
@@ -450,7 +470,7 @@
                          "\n".'<table class="LC_discussion">';
             $discussion .= &action_links_bar($colspan,$ressymb,$visible,
                                              $newpostsflag,$group,
-                                             $prevread,$markondisp);
+                                             $prevread,$markondisp,$seehidden);
             my $escsymb=&escape($ressymb);
             my $numhidden = keys(%notshown);
             if ($numhidden > 0) {
@@ -664,7 +684,7 @@
 END
             $discussion .= &action_links_bar($colspan,$ressymb,$visible,
                                              $newpostsflag,$group,
-                                             $prevread,$markondisp);
+                                             $prevread,$markondisp,$seehidden);
             $discussion .= "
            </table>
            <br /><br /></form>\n";
@@ -764,9 +784,15 @@
 	    $discussion.= &send_feedback_link($ressymb,$target);
             if ($env{'request.role.adv'}) {
                 my $close = &Apache::lonnet::EXT('resource.0.discussend',$ressymb);
+                my $canvote = &Apache::lonnet::EXT('resource.0.discussvote',$ressymb);
                 if (defined($close) && $close ne '' && $close < time) {
-                    $discussion .= ' '.&mt('(Closed for [_1] roles)',
-                                                &Apache::lonnet::plaintext('st',$crstype));
+                    if ($canvote eq 'notended') {
+                        $discussion .= ' '.&mt('(Posting and voting closed for [_1] roles)',
+                                                    &Apache::lonnet::plaintext('st',$crstype)); 
+                    } else {
+                        $discussion .= ' '.&mt('(Closed for [_1] roles)',
+                                                    &Apache::lonnet::plaintext('st',$crstype));
+                    }
                 }
             }
         } else {
@@ -777,6 +803,39 @@
     return $discussion;
 }
 
+sub can_see_hidden {
+    my ($mode,$ressymb,$feedurl,$group,$cdom,$cnum,$crs) = @_;
+    my $seehidden;
+    if ($env{'request.course.id'}) {
+        unless ($cdom ne '' && $cnum ne '') {
+            $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+        }
+        if ($crs eq '') {
+            $crs = '/'.$env{'request.course.id'};
+            if ($env{'request.course.sec'}) {
+                $crs.='_'.$env{'request.course.sec'};
+            }
+            $crs=~s{_}{/}g;
+        }
+        if ($mode eq '') {
+            $mode='board';
+            if ($feedurl =~ /$LONCAPA::assess_re/) {
+                $mode='problem';
+            }
+        }
+        if (($group ne '') && ($mode eq 'board') &&
+            ($ressymb =~ m{^bulletin___\d+\Q___adm/wrapper/adm/$cdom/$cnum/\E\d+/bulletinboard$})) {
+            if (&check_group_priv($group,'dgp') eq 'ok') {
+                $seehidden = 1;
+            }
+        } else {
+            $seehidden=&Apache::lonnet::allowed('rin',$crs);
+        }
+    }
+    return $seehidden;
+}
+
 sub discussion_link {
     my ($ressymb,$linktext,$cmd,$item,$flag,$prev,$adds,$title) = @_;
     my $link = '<a href="/adm/feedback?'.$cmd.'='.&escape($ressymb).':::'.$item;
@@ -810,7 +869,8 @@
 }
 
 sub action_links_bar {
-    my ($colspan,$ressymb,$visible,$newpostsflag,$group,$prevread,$markondisp) = @_;
+    my ($colspan,$ressymb,$visible,$newpostsflag,$group,$prevread,$markondisp,
+        $seehidden) = @_;
     my $discussion = '<tr><td class="LC_disc_action_links_bar" colspan="'.$colspan.'">'.
                      '<table width="100%" class="LC_disc_action_table"><tr>'.
                      '<td class="LC_disc_action_left">';
@@ -840,7 +900,17 @@
         $discussion .= '&previous='.$prevread;
     }
     $discussion .= &group_args($group);
-    $discussion .= '">'.&mt('Export').'?</a>  </td>';
+    $discussion .= '">'.&mt('Export').'</a>';
+    if ($seehidden) {
+        $discussion .= '  ';
+        $discussion .='<a href="/adm/feedback?undeleteall='.$escsymb;
+        if ($newpostsflag) {
+            $discussion .= '&previous='.$prevread;
+        }
+        $discussion .= &group_args($group);
+        $discussion .= '">'.&mt('Undelete all deleted entries').'</a>';
+    }
+    $discussion.='</td>';
     if ($newpostsflag) {
         if (!$markondisp) {
             $discussion .='<td class="LC_disc_action_right"><a href="/adm/preferences?action=changediscussions';
@@ -938,7 +1008,7 @@
 }
 
 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,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
+    my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$seehidden,$canvote,$prevread,$sortposts,$ressymb,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
     my @original=();
     my @index=();
     my $skip_group_check = 0;
@@ -948,17 +1018,20 @@
     my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
 			  $env{'course.'.$env{'request.course.id'}.'.domain'},
 			  $env{'course.'.$env{'request.course.id'}.'.num'});
+    my (%likes,%userlikes,%userunlikes, at theselikes,$oneplus,$twoplus,$oneminus,$twominus);
 # And these are the likes/unlikes
-    my %likes=&Apache::lonnet::dump('disclikes',
+    my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
+    if ($seeid || $canvote) {
+        %likes=&Apache::lonnet::dump('disclikes',
                           $env{'course.'.$env{'request.course.id'}.'.domain'},
                           $env{'course.'.$env{'request.course.id'}.'.num'},
                           '^'.$symb.':');
-    my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
 # Array with likes to figure out averages, etc.
-    my @theselikes=();
+        @theselikes=();
 # Hashes containing likes and unlikes for this user.
-    my %userlikes=();
-    my %userunlikes=();
+        %userlikes=();
+        %userunlikes=();
+    }
 # Is the user allowed to see the real name behind anonymous postings?
     my $see_anonymous = 
 	&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
@@ -990,50 +1063,52 @@
                      &filter_regexp($rolefilter,$sectionpick,$statusfilter);
             $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
         }
+        if ($seeid || $canvote) {
 # We need to go through this twice, first to get the likes/dislikes, then to actually build the display
-        for (my $id=1;$id<=$contrib{'version'};$id++) {
-            my $idx=$id;
-            next if ($contrib{$idx.':deleted'});
-            next if ($contrib{$idx.':hidden'});
-            unless ((($hiddens{$idx}) && (!$seeid)) || ($deletions{$idx}) || (!$contrib{$idx.':message'})) {
-                if ($likes{$symb.':'.$idx.':likes'} ne '') {
-                    push(@theselikes,$likes{$symb.':'.$idx.':likes'});
-                    if (ref($likes{$symb.':'.$idx.':likers'}) eq 'HASH') {
-                        if (exists($likes{$symb.':'.$idx.':likers'}{$thisuser})) {
-                            $userlikes{$idx} = 1;
+            for (my $id=1;$id<=$contrib{'version'};$id++) {
+                my $idx=$id;
+                next if ($contrib{$idx.':deleted'});
+                next if ($contrib{$idx.':hidden'});
+                unless ((($hiddens{$idx}) && (!$seehidden)) || ($deletions{$idx}) || (!$contrib{$idx.':message'})) {
+                    if ($likes{$symb.':'.$idx.':likes'} ne '') {
+                        push(@theselikes,$likes{$symb.':'.$idx.':likes'});
+                        if (ref($likes{$symb.':'.$idx.':likers'}) eq 'HASH') {
+                            if (exists($likes{$symb.':'.$idx.':likers'}{$thisuser})) {
+                                $userlikes{$idx} = 1;
+                            }
                         }
-                    }
-                    if (ref($likes{$symb.':'.$idx.':unlikers'}) eq 'HASH') {
-                        if (exists($likes{$symb.':'.$idx.':unlikers'}{$thisuser})) {
-                            $userunlikes{$idx} = 1;
+                        if (ref($likes{$symb.':'.$idx.':unlikers'}) eq 'HASH') {
+                            if (exists($likes{$symb.':'.$idx.':unlikers'}{$thisuser})) {
+                                $userunlikes{$idx} = 1;
+                            }
                         }
                     }
                 }
             }
-        }
 # Figure out average likes and standard deviation if there are enough 
 # discussions to warrant that
-        my $ave=0;
-        my $stddev=10000;
-        if ($#theselikes>1) {
-            my $sum=0;
-            my $num=$#theselikes+1;
-            foreach my $thislike (@theselikes) {
-                $sum+=$thislike;
-            }
-            $ave=$sum/$num;
-            my $sumsq=0;
-            foreach my $thislike (@theselikes) {
-                $sumsq+=($thislike-$ave)*($thislike-$ave);
+            my $ave=0;
+            my $stddev=10000;
+            if ($#theselikes>1) {
+                my $sum=0;
+                my $num=$#theselikes+1;
+                foreach my $thislike (@theselikes) {
+                    $sum+=$thislike;
+                }
+                $ave=$sum/$num;
+                my $sumsq=0;
+                foreach my $thislike (@theselikes) {
+                   $sumsq+=($thislike-$ave)*($thislike-$ave);
+                }
+                $stddev=sqrt($sumsq/$num);
             }
-            $stddev=sqrt($sumsq/$num);
-        }
 # Now we know the average likes $ave and the standard deviation $stddev
 # Get the boundaries for markup
-        my $oneplus=$ave+$stddev;
-        my $twoplus=$ave+2.*$stddev;
-        my $oneminus=$ave-$stddev;
-        my $twominus=$ave-2.*$stddev;
+            $oneplus=$ave+$stddev;
+            $twoplus=$ave+2.*$stddev;
+            $oneminus=$ave-$stddev;
+            $twominus=$ave-2.*$stddev;
+        }
 #
 # This is now the real loop. Go through all entries, pick up what we need
 #
@@ -1069,7 +1144,7 @@
 	    } else {
 		$$replies[$$depth[$idx]]=1;
 	    }
-            unless ((($hiddens{$idx}) && (!$seeid)) || ($deletions{$idx})) {
+            unless ((($hiddens{$idx}) && (!$seehidden)) || ($deletions{$idx})) {
 		$$visible++;
                 if ($contrib{$idx.':history'}) {
                     if ($contrib{$idx.':history'} =~ /:/) {
@@ -1094,7 +1169,7 @@
 		    $$anonhash{$key}=&mt('Anonymous').' '.$anoncnt;
 		}
                 my ($message,$subject,$vgrlink,$ctlink);
-                &get_post_contents(\%contrib,$idx,$seeid,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,\$showaboutme,$numoldver);
+                &get_post_contents(\%contrib,$idx,$seeid,$seehidden,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,\$showaboutme,$numoldver);
 
 
 # Set up for sorting by subject
@@ -1184,14 +1259,14 @@
 				        $sender .= &group_args($group);
                                         $sender .= '" '.$target.'>'.&mt('Edit').'</a>';
                                     
-                                        unless ($seeid) {
+                                        unless ($seehidden) {
                                             my $grpargs = &group_args($group);
                                             $sender.=" <a href=\"javascript:verifydelete('studentdelete','$escsymb','$idx','$$newpostsflag','$prevread','$grpargs')";
                                             $sender .= '">'.&mt('Delete').'</a>';
                                         }
                                     }
                                 }
-                                if ($seeid) {
+                                if ($seehidden) {
 			            if ($hiddens{$idx}) {
                                         unless ($studenthidden) {
 			                    $sender.=' <a href="/adm/feedback?unhide='.
@@ -1312,14 +1387,15 @@
                 } else {
                     if ($message) {
                         my $spansize = 2;
+                        my ($uname,$udom);
                         if ($showonlyunread && $prevread > $posttime) {
                             $$notshown{$idx} = 1;
                         } elsif ($showunmark && $$dischash{$readkey}=~/\.$idx\./) {
                             $$notshown{$idx} = 1;
                         } else {
 # apply filters
-                            my $uname = $contrib{$idx.':sendername'};
-                            my $udom = $contrib{$idx.':senderdomain'};
+                            $uname = $contrib{$idx.':sendername'};
+                            $udom = $contrib{$idx.':senderdomain'};
                             my $poster = $uname.':'.$udom;
                             if ($env{'form.totposters'} ne '') {
                                 if ($totposters == 0) {
@@ -1387,45 +1463,70 @@
                                 $$discussionitems[$idx].='<td align="right">  '.
                                   $ctlink.'</td>';
                             }
+                            if ($seeid || $canvote) {
 # Figure out size based on likes
-                            my $thislikes=$likes{$symb.':'.$idx.':likes'};
-                            my $likesize="100";
-                            if ($thislikes>$twoplus) {
-                                $likesize="200";
-                            } elsif ($thislikes>$oneplus) {
-                                $likesize="150";
-                            }
-                            if ($thislikes<$twominus) {
-                                $likesize="50";
-                            } elsif ($thislikes<$oneminus) {
-                                $likesize="75";
+                                my $thislikes=$likes{$symb.':'.$idx.':likes'};
+                                my $likesize="100";
+                                if ($thislikes>$twoplus) {
+                                    $likesize="200";
+                                } elsif ($thislikes>$oneplus) {
+                                    $likesize="150";
+                                }
+                                if ($thislikes<$twominus) {
+                                    $likesize="50";
+                                } elsif ($thislikes<$oneminus) {
+                                    $likesize="75";
+                                }
                             }
 # Actually glue in the message itself
                             $$discussionitems[$idx].= '</tr></table><blockquote>'.
                                     "<div style='font-size:$likesize%'>".
                                     $message.
                                     '</div></blockquote>';
+                            if ($canvote) {
+                                my $ownpost;
+                                if (($uname eq $env{'user.name'}) &&
+                                    ($udom eq $env{'user.domain'})) {
+                                    $ownpost = 1;
+                                }
 # Put in the like and unlike buttons
-                            if ($userlikes{$idx}) {
-                                $$discussionitems[$idx].='<img border="0" src="/res/adm/pages/thumbsup_gray.png" alt="'.&mt('You like this posting').'" />';
-                            } else {
-                                $$discussionitems[$idx].=' '.&discussion_link($symb,'<img border="0" src="/res/adm/pages/thumbsup.png" alt="'.&mt('Like').'" />','like',$idx,$$newpostsflag,$prevread,&group_args($group),&mt("Like this posting")); 
-                            }
-                            if ($userunlikes{$idx}) {
-                                $$discussionitems[$idx].='<img border="0" src="/res/adm/pages/thumbsdown_gray.png" alt="'.&mt('You unlike this posting').'" />';
-                            } else {
-                                $$discussionitems[$idx].=' '.&discussion_link($symb,'<img border="0" src="/res/adm/pages/thumbsdown.png" alt="'.&mt('Unlike').'" />','unlike',$idx,$$newpostsflag,$prevread,&group_args($group),&mt("Unlike this posting"));
+                                if ($ownpost || (($hiddens{$idx}) && ($seehidden))) {
+                                    my $novote;
+                                    if ($ownpost) {
+                                        $novote = &mt('No voting for your own posts.');
+                                    } else {
+                                        $novote = &mt('No voting for hidden posts.');
+                                    }
+                                    $$discussionitems[$idx].=
+                                        '<a href="javascript:alert('."'$novote'".');" style="text-decoration: none;">'.
+                                        '<img border="0" src="/res/adm/pages/thumbsup_novote.png" alt="'.$novote.'" /> '.
+                                        '<img border="0" src="/res/adm/pages/thumbsdown_novote.png" alt="'.$novote.'" /></a>';
+                                } else {
+                                    if ($userlikes{$idx}) {
+                                        $$discussionitems[$idx].='<img border="0" src="/res/adm/pages/thumbsup_gray.png" alt="'.&mt('You like this posting').'" />';
+                                    } else {
+                                        $$discussionitems[$idx].=' '.&discussion_link($symb,'<img border="0" src="/res/adm/pages/thumbsup.png" alt="'.&mt('Like').'" />','like',$idx,$$newpostsflag,$prevread,&group_args($group),&mt("Like this posting")); 
+                                    }
+                                    if ($userunlikes{$idx}) {
+                                        $$discussionitems[$idx].='<img border="0" src="/res/adm/pages/thumbsdown_gray.png" alt="'.&mt('You unlike this posting').'" />';
+                                    } else {
+                                        $$discussionitems[$idx].=' '.&discussion_link($symb,'<img border="0" src="/res/adm/pages/thumbsdown.png" alt="'.&mt('Unlike').'" />','unlike',$idx,$$newpostsflag,$prevread,&group_args($group),&mt("Unlike this posting"));
+                                    }
+                                }
                             }
-                            my $thislikes=$likes{$symb.':'.$idx.':likes'};
-                            if ($thislikes>0) {
-                                $$discussionitems[$idx].=' ('.&mt("[_1] likes",$thislikes).')';
-                            } elsif ($thislikes<0) {
-                                $$discussionitems[$idx].=' ('.&mt("[_1] unlikes",abs($thislikes)).')';
+                            if ($seeid || $canvote) {
+                                my $thislikes=$likes{$symb.':'.$idx.':likes'};
+                                if ($thislikes>0) {
+                                    $$discussionitems[$idx].=' ('.&mt("[_1] likes",$thislikes).')';
+                                } elsif ($thislikes<0) {
+                                    $$discussionitems[$idx].=' ('.&mt("[_1] unlikes",abs($thislikes)).')';
+                                }
                             }
+# If there is any history to this post, inform the reader
                             if ($contrib{$idx.':history'}) {
                                 my @postversions = ();
                                 $$discussionitems[$idx] .= &mt('This post has been edited by the author.');
-                                if ($seeid) {
+                                if ($seehidden) {
                                     $$discussionitems[$idx] .= '  <a href="/adm/feedback?allversions='.$escsymb.':::'.$idx;
 				    $$discussionitems[$idx] .= &group_args($group);
                                     $$discussionitems[$idx] .= '">'.&mt('Display all versions').'</a>';
@@ -1505,13 +1606,13 @@
 
 
 sub get_post_contents {
-    my ($contrib,$idx,$seeid,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$showaboutme,$numver) = @_;
+    my ($contrib,$idx,$seeid,$seehidden,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$showaboutme,$numver) = @_;
     my $discussion = '';
     my $start=$numver;
     my $end=$numver + 1;
     %{$$imsfiles{$idx}}=();
     if ($type eq 'allversions') {
-       unless($seeid) {
+       unless($seehidden) {
            $discussion=&mt('You do not have privileges to view all versions of posts.').' '.&mt('Please select a different role.');
            return $discussion;
        } 
@@ -1721,6 +1822,7 @@
 					   $env{'course.'.$env{'request.course.id'}.'.domain'},
 					   $env{'course.'.$env{'request.course.id'}.'.num'});
       unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
+          my $numoldver = 0;
           if ($contrib{$idx.':history'}) {
               if ($contrib{$idx.':history'} =~ /:/) {
                   my @oldversions = split(/:/,$contrib{$idx.':history'});
@@ -1729,36 +1831,25 @@
                   $numoldver = 1;
               }
           }
-          if ($env{'form.replydisc'}) {
-              if ($contrib{$idx.':history'}) {
-                  if ($contrib{$idx.':history'} =~ /:/) {
-                      my @oldversions = split(/:/,$contrib{$idx.':history'});
-                      $numoldver = @oldversions;
-                  } else {
-                      $numoldver = 1;
-                  }
+          if ($idx > 0) {
+              my (%msgversions,%subversions,$htmldecode);
+              $htmldecode = 0;
+              if ($env{'form.replydisc'}) {
+                  $htmldecode = 1;
               }
-              if ($idx > 0) {
-                  my %msgversions = ();
-                  &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
+              &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
+              &get_post_versions(\%subversions,$contrib{$idx.':subject'},$htmldecode,
+                                 $numoldver);
+              $subject = $subversions{$numoldver};
+              if ($env{'form.replydisc'}) {
                   $quote = $msgversions{$numoldver};
-              }
-              if ($idx > 0) {
-                  my %subversions = ();
-                  &get_post_versions(\%subversions,$contrib{$idx.':subject'},1,$numoldver);
-                  $subject = &mt('Re: ').$subversions{$numoldver};
-              }
-              $subject = &HTML::Entities::encode($subject,'<>&"');
-          } else {
-              $attachmenturls = $contrib{$idx.':attachmenturl'};
-              if ($idx > 0) {
-                  my %msgversions = ();
-                  &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
+                  $subject = &HTML::Entities::encode(&mt('Re: ').$subject,'<>&"');
+              } else {
                   $comment = $msgversions{$numoldver};
-                  my %subversions = ();
-                  &get_post_versions(\%subversions,$contrib{$idx.':subject'},0,$numoldver);
-                  $subject = $subversions{$numoldver}; 
               }
+          }
+          if ($env{'form.editdisc'}) {
+              $attachmenturls = $contrib{$idx.':attachmenturl'};
               if (defined($contrib{$idx.':replyto'})) {
                   $parentmsg = $contrib{$idx.':replyto'};
               }
@@ -2407,24 +2498,11 @@
     $r->send_http_header;
 
     &Apache::lonenc::check_encrypt(\$symb);
-    my $crs='/'.$env{'request.course.id'};
-    if ($env{'request.course.sec'}) {
-        $crs.='_'.$env{'request.course.sec'};
-    }
-    $crs=~s/\_/\//g;
-    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 $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
     my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                                          $cdom,$cnum);
     my %namesort = ();
@@ -2440,7 +2518,7 @@
         for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
             my $hidden=($contrib{'hidden'}=~/\.$idx\./);
             my $deleted=($contrib{'deleted'}=~/\.$idx\./);
-            unless ((($hidden) && (!$seeid)) || ($deleted)) {
+            unless ((($hidden) && (!$seehidden)) || ($deleted)) {
                 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'};
@@ -2739,7 +2817,7 @@
 		      'add_entries' => \%onload,);
 
   if ($feedurl !~ m{^/adm/feedback}) { 
-      $body_options{'rediect'} = [2,$feedurl];
+      $body_options{'redirect'} = [2,$feedurl];
   }
   my $start_page=
       &Apache::loncommon::start_page('Feedback not sent',undef,
@@ -2810,12 +2888,7 @@
         my ($blocked,$blocktext) = &Apache::loncommon::blocking_status('boards');
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
-        my $realsymb = $symb;
-        if ($symb=~/^bulletin___/) {
-            my $filename=(&Apache::lonnet::decode_symb($symb))[2];
-            $filename=~s|^adm/wrapper/||;
-            $realsymb=&Apache::lonnet::symbread($filename);
-        }
+        my $realsymb = &get_realsymb($symb);
         if (!$blocked && &discussion_open(undef,$realsymb) && 
 	    (&Apache::lonnet::allowed('pch',
 				     $env{'request.course.id'}.
@@ -2981,17 +3054,13 @@
 sub adddiscuss {
     my ($symb,$email,$anon,$attachmenturl,$subject,$group)=@_;
     my $status='';
-    my $realsymb;
-    if ($symb=~/^bulletin___/) {
-	my $filename=(&Apache::lonnet::decode_symb($symb))[2];
-	$filename=~s|^adm/wrapper/||;
-	$realsymb=&Apache::lonnet::symbread($filename);
-    }
+    my $realsymb = &get_realsymb($symb);
     my ($cnum,$cdom);
     if ($env{'request.course.id'}) {
         $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     }
+    my $realsymb;
     if (&discussion_open(undef,$realsymb) &&
         (&Apache::lonnet::allowed('pch',$env{'request.course.id'}.
          ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')) ||
@@ -3084,6 +3153,7 @@
        $newrecord{'subnumber'}=$record{'subnumber'}+1;
        $status.='<br />'.&mt('Registering').': '.
                &Apache::lonnet::cstore(\%newrecord,'_discussion');
+       &updatekarma();
     }
     } else {
 	$status.='Failed.';
@@ -3102,27 +3172,93 @@
     return %record;
 }
 
+# Routine to get discussion statistics
+
+sub getdiscussionstats {
+    my %record=&getdiscussionrecords(@_);
+    my $totalvotes = $record{'totallikes'} + $record{'totalunlikes'};
+    return ($record{'subnumber'},$record{'points'},$record{'totallikes'},$totalvotes);
+}
+
+# Calculate discussion karma
+
+sub calcdiscussionkarma {
+    my ($subs,$pts,$likes,$votes)=&getdiscussionstats(@_);
+    my $karma=0;
+    if ($votes>0) {
+        $karma=int(.1+5.*(1.-exp(-$subs/10.))*$likes/$votes);
+        if ($karma<0) { $karma=0; }
+        if ($karma>5) { $karma=5; }
+    }
+    return $karma;
+}
+
+# Update karma
+
+sub updatekarma {
+    my ($uname,$udom,$course)=@_;
+    unless ($uname) { $uname=$env{'user.name'}; }
+    unless ($udom)  { $udom=$env{'user.domain'}; }
+    unless ($course) { $course=$env{'request.course.id'}; }
+    my $karma=&calcdiscussionkarma($uname,$udom,$course);
+    &Apache::lonnet::cstore({ 'karma' => $karma },'_discussion',$course,$udom,$uname);
+    &Apache::lonnet::do_cache_new('karma',$uname.':'.$udom.':'.$course,$karma,3600);
+    return $karma;
+}
+
+# Retrieve karma
+
+sub userkarma {
+    my ($uname,$udom,$course)=@_;
+    unless ($uname) { $uname=$env{'user.name'}; }
+    unless ($udom)  { $udom=$env{'user.domain'}; }
+    unless ($course) { $course=$env{'request.course.id'}; }
+    my $hashkey=$uname.':'.$udom.':'.$course;
+    my ($karma,$cached)=&Apache::lonnet::is_cached_new('karma',$hashkey);
+    if ($cached) {
+        return $karma;
+    }
+    my %userdisc=&getdiscussionrecords($uname,$udom,$course);
+    $karma=$userdisc{'karma'};
+    &Apache::lonnet::do_cache_new('karma',$hashkey,$karma,3600);
+    return $karma;
+}
+
+# Store discussion credit
+
+sub storediscussionpoints {
+    my ($points,$uname,$udom,$course)=@_;
+    unless ($points) { $points=0; }
+    unless ($uname) { $uname=$env{'user.name'}; }
+    unless ($udom)  { $udom=$env{'user.domain'}; }
+    unless ($course) { $course=$env{'request.course.id'}; }
+    my %record=('grader_user'   => $env{'user.name'},
+                'grader_domain' => $env{'user.domain'},
+                'points' => $points);
+    return &Apache::lonnet::cstore(\%record,'_discussion',$course,$udom,$uname);
+}
+
 # Store discussion "likes"
 
 sub storediscussionlikes {
-    my ($likes,$uname,$udom,$course)=@_;
-    unless ($likes) { $likes=0; }
-    if ($likes>0) { $likes=1; }
-    if ($likes<0) { $likes=-1; }
+    my ($chglikes,$chgunlikes,$uname,$udom,$course,$context)=@_;
     unless ($uname) { $uname=$env{'user.name'}; }
     unless ($udom)  { $udom=$env{'user.domain'}; }
     unless ($course) { $course=$env{'request.course.id'}; }
     my %record=&getdiscussionrecords($uname,$udom,$course);
     my $totallikes=$record{'totallikes'};
-    my $totalvotes=$record{'totalvotes'};
-    $totallikes+=$likes;
-    $totalvotes++;
+    my $totalunlikes=$record{'totalunlikes'};
+    $totallikes += $chglikes;
+    $totalunlikes += $chgunlikes;
     my %newrecord=('likes_user'   => $env{'user.name'},
                    'likes_domain' => $env{'user.domain'},
-                   'likes' => $likes,
-                   'totallikes' => $totallikes,
-                   'totalvotes' => $totalvotes);
+                   'totallikes'   => $totallikes,
+                   'totalunlikes' => $totalunlikes,
+                   'context'      => $context);
     my $status=&Apache::lonnet::cstore(\%newrecord,'_discussion',$course,$udom,$uname);
+    if ($status eq 'ok') {
+        &updatekarma($uname,$udom,$course);
+    }
     return $status;
 }
 
@@ -3652,14 +3788,16 @@
 # --------------------------- Get query string for limited number of parameters
 
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-         ['like','unlike','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']);
+         ['like','unlike','hide','unhide','deldisc','undeleteall','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'};
+  my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+  my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
   my %attachmax = (
                     text => &mt('(128 KB max size)'),
                     num  => 131072,
                   );
   if ($env{'form.editdisc'}) {
-      if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) {
+      if (!(&editing_allowed($env{'form.editdisc'},$group))) {
           my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
           my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
           my $feedurl=&Apache::lonnet::clutter($url);
@@ -3708,25 +3846,14 @@
                                                {'bread_crumbs' => $brcrum,})
       );
 
-      my $crs='/'.$env{'request.course.id'};
-      if ($env{'request.course.sec'}) {
-          $crs.='_'.$env{'request.course.sec'};
-      }
-      $crs=~s|_|/|g;
-      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);
+      ($symb, my $feedurl)=&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 (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
+          $seeid = 1;
       }
+      my $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
       if ($idx > 0) {
           my %messages = ();
           my %subjects = ();
@@ -3735,9 +3862,8 @@
           my %imsfiles = ();
           my ($screenname,$plainname,$showaboutme);
           my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
-                           $env{'course.'.$env{'request.course.id'}.'.domain'},
-                           $env{'course.'.$env{'request.course.id'}.'.num'});
-          $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname,\$showaboutme));
+                                               $cdom,$cnum);
+          $r->print(&get_post_contents(\%contrib,$idx,$seeid,$seehidden,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname,\$showaboutme));
       }
       $r->print(&Apache::loncommon::end_page());
       return OK;
@@ -3879,37 +4005,32 @@
       my $entry=$env{'form.hide'}?$env{'form.hide'}:$env{'form.unhide'};
       my ($symb,$idx)=split(/\:\:\:/,$entry);
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
+      my $ressymb = &wrap_symb($symb);
 
-      my $crs='/'.$env{'request.course.id'};
-      if ($env{'request.course.sec'}) {
-          $crs.='_'.$env{'request.course.sec'};
-      }
-      $crs=~s/\_/\//g;
-      my $seeid=&Apache::lonnet::allowed('rin',$crs);
-
-      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,);
+      my $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
+      unless (($seehidden) || (&editing_allowed($env{'form.hide'},$group))) {
+          &redirect_back($r,$feedurl,&mt('Hiding not permitted').'<br />',
+                         '0','0','','',$env{'form.previous'},'','','','',
+                         undef,undef,$group,);
           return OK;
       }
 
       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 $currenthidden=$contrib{'hidden'};
       my $currentstudenthidden=$contrib{'studenthidden'};
 
       if ($env{'form.hide'}) {
 	  $currenthidden.='.'.$idx.'.';
-	  unless ($seeid) {
+	  unless ($seehidden) {
 	      $currentstudenthidden.='.'.$idx.'.';
 	  }
       } else {
 	  $currenthidden=~s/\.$idx\.//g;
       }
       my %newhash=('hidden' => $currenthidden);
-      if ( ($env{'form.hide'}) && (!$seeid) ) {
+      if ( ($env{'form.hide'}) && (!$seehidden) ) {
 	  $newhash{'studenthidden'} = $currentstudenthidden;
       }
       if ($env{'form.hide'}) {
@@ -3918,16 +4039,46 @@
           ($changelast,$newlast) = &get_discussion_info($idx,%contrib);
           if ($changelast) {
               &Apache::lonnet::put('discussiontimes',{$symb => $newlast},
-                     $env{'course.'.$env{'request.course.id'}.'.domain'},
-                     $env{'course.'.$env{'request.course.id'}.'.num'});
+                                   $cdom,$cnum);
           }
       }
-      &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
-                           $env{'course.'.$env{'request.course.id'}.'.domain'},
-			   $env{'course.'.$env{'request.course.id'}.'.num'});
+      my $result;
+      if (&Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
+                                 $cdom,$cnum) eq 'ok') {
+          my $prefix=$symb.':'.$idx.':';
+          my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,
+                                          '^'.$prefix);
+          my ($totallikes,$totalunlikes);
+          if (ref($likes{$prefix.'likers'}) eq 'HASH') {
+              $totallikes = scalar(keys(%{$likes{$prefix.'likers'}}));
+          }
+          if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
+              $totalunlikes = scalar(keys(%{$likes{$prefix.'unlikers'}}));
+          }
+          if ($totallikes || $totalunlikes) {
+              my ($chglikes,$chgunlikes,$context);
+              if ($env{'form.hide'}) {
+                  $chglikes = -1 * $totallikes;
+                  $chgunlikes = -1 * $totalunlikes;
+                  $context = 'hide';
+              } else {
+                  $chglikes = $totallikes;
+                  $chgunlikes = $totalunlikes;
+                  $context = 'unhide';
+              }
+              &storediscussionlikes($chglikes,$chgunlikes,
+                                    $contrib{$idx.':sendername'},
+                                    $contrib{$idx.':senderdomain'},
+                                    $env{'request.course.id'},
+                                    $context);
 
-      &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
-		     '0','0','','',$env{'form.previous'},undef,undef,undef,
+          }
+          $result = &mt('Changed discussion status');
+      } else {
+          $result = &mt('Discussion status unchanged');
+      }
+      &redirect_back($r,$feedurl,$result.'<br />','0','0','','',
+                     $env{'form.previous'},undef,undef,undef,
                      undef,undef,undef,$group);
       return OK;
   } elsif (($env{'form.like'}) || ($env{'form.unlike'})) {
@@ -3935,90 +4086,145 @@
       my $entry=$env{'form.like'}?$env{'form.like'}:$env{'form.unlike'};
       my ($symb,$idx)=split(/\:\:\:/,$entry);
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
-     
+      my $result;
+      if ($idx > 0) {
+          my $realsymb = &get_realsymb($symb);
+          my $status='OPEN';
+          if ($Apache::lonhomework::parsing_a_problem ||
+              $Apache::lonhomework::parsing_a_task) {
+              $status=$Apache::inputtags::status[-1];
+          }
+          if (&discussion_vote_available($status,$realsymb)) {
+              my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                                                   $cdom,$cnum);
+              my $ownpost;
+              if (($contrib{$idx.':sendername'} eq $env{'user.name'}) &&
+                  ($contrib{$idx.':senderdomain'} eq $env{'user.domain'})) {
+                  $ownpost = 1;
+              }
+              if ($ownpost || $contrib{$idx.':hidden'} || $contrib{$idx.':deleted'}) {
+                  $result = &mt('Vote not registered.').' ';
+              }
+              if ($ownpost) {
+                  $result .= &mt('No voting for your own posts.');
+              } elsif ($contrib{$idx.':hidden'}) {
+                  $result .= &mt('No voting for hidden posts.');
+              } elsif ($contrib{$idx.':deleted'}) {
+                  $result .= &mt('No voting for deleted posts.');
+              } else {
 #
 # Likes and unlikes are in db-file "disclikes" of the course
 # The prefix is the $symb to identify the resource discussion,
 # and the $idx to identify the entry
 #
-      my $prefix=$symb.':'.$idx.':';
-      my %contrib=&Apache::lonnet::dump('disclikes',
-                                        $env{'course.'.$env{'request.course.id'}.'.domain'},
-                                        $env{'course.'.$env{'request.course.id'}.'.num'},
-                                        '^'.$prefix);
-# Get current like or unlike status for the $idx for this user.
-      my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
-      my ($userlikes,$userunlikes);
-      if (ref($contrib{$prefix.'likers'}) eq 'HASH') {
-          if (exists($contrib{$prefix.'likers'}{$thisuser})) {
-              $userlikes = 1;
-          }
-      }
-      if (ref($contrib{$prefix.'unlikers'}) eq 'HASH') {
-          if (exists($contrib{$prefix.'unlikers'}{$thisuser})) {
-              $userunlikes = 1;
-          }
-      }
+                  my $prefix=$symb.':'.$idx.':';
+                  my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,
+                                                  '^'.$prefix);
 
+# Get current like or unlike status for the $idx for this user.
+                  my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
+                  my ($userlikes,$userunlikes);
+                  if (ref($likes{$prefix.'likers'}) eq 'HASH') {
+                      if (exists($likes{$prefix.'likers'}{$thisuser})) {
+                          $userlikes = 1;
+                      }
+                  }
+                  if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
+                      if (exists($likes{$prefix.'unlikers'}{$thisuser})) {
+                          $userunlikes = 1;
+                      }
+                  }
 # Get the current "likes" count
-      my $likes=$contrib{$prefix.'likes'};
+                  my $likescount=$likes{$prefix.'likes'};
 # Find out if they already voted
 # Users cannot like a post twice, or unlike it twice.
 # They can change their mind, though.
-      my $alreadyflag=0;
-      my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
-      if ($env{'form.like'}) {
-          if ($userlikes) {
-              $alreadyflag=1;
-          } elsif ($userunlikes) {
-              delete($contrib{$prefix.'unlikers'}{$thisuser});
-              $likes++;
-          } else {
-              if (ref($contrib{$prefix.'likers'}) eq 'HASH') {
-                  $contrib{$prefix.'likers'}{$thisuser} = 1;
-              } else {
-                  $contrib{$prefix.'likers'} = {$thisuser => 1};
-              }
-              $likes++;
-          }
-      } else {
-          if ($userunlikes) {
-              $alreadyflag=1;
-          } elsif ($userlikes) {
-              delete($contrib{$prefix.'likers'}{$thisuser});
-              $likes--;
-          } else {
-              if (ref($contrib{$prefix.'unlikers'}) eq 'HASH') {
-                  $contrib{$prefix.'unlikers'}{$thisuser} = 1;
-              } else {
-                  $contrib{$prefix.'unlikers'} = {$thisuser => 1};
-              }
-              $likes--;
-          }
-      }
-      my $result;
+                  my $alreadyflag=0;
+                  my $votetype;
+                  if ($env{'form.like'}) {
+                      if ($userlikes) {
+                          $alreadyflag=1;
+                      } elsif ($userunlikes) {
+                          delete($likes{$prefix.'unlikers'}{$thisuser});
+                          $votetype = 'switch';
+                          $likescount++;
+                      } else {
+                          if (ref($likes{$prefix.'likers'}) eq 'HASH') {
+                              $likes{$prefix.'likers'}{$thisuser} = 1;
+                          } else {
+                              $likes{$prefix.'likers'} = {$thisuser => 1};
+                          }
+                          $likescount++;
+                      }
+                  } else {
+                      if ($userunlikes) {
+                          $alreadyflag=1;
+                      } elsif ($userlikes) {
+                          delete($likes{$prefix.'likers'}{$thisuser});
+                          $votetype = 'switch';
+                          $likescount--;
+                      } else {
+                          if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
+                              $likes{$prefix.'unlikers'}{$thisuser} = 1;
+                          } else {
+                              $likes{$prefix.'unlikers'} = {$thisuser => 1};
+                          }
+                          $likescount--;
+                      }
+                  }
 # $alreadyflag would be 1 if they tried to double-like or double-unlike
-      unless ($alreadyflag) {
-          my %newhash=($prefix.'likes'    => $likes,
-                       $prefix.'likers'   => $contrib{$prefix.'likers'},
-                       $prefix.'unlikers' => $contrib{$prefix.'unlikers'});
+                  if ($alreadyflag) {
+                      if ($env{'form.like'}) {
+                          $result= &mt("'Like' already registered");
+                      } else {
+                          $result= &mt("'Unlike' already registered");
+                      }
+                  } else {
+                      my %newhash=($prefix.'likes'    => $likescount,
+                                   $prefix.'likers'   => $likes{$prefix.'likers'},
+                                   $prefix.'unlikers' => $likes{$prefix.'unlikers'});
 # Store data in db-file "disclikes"
-          if (&Apache::lonnet::put('disclikes',
-                                   \%newhash,
-                                   $env{'course.'.$env{'request.course.id'}.'.domain'},
-                                   $env{'course.'.$env{'request.course.id'}.'.num'}) eq 'ok') {
+                      if (&Apache::lonnet::put('disclikes',\%newhash,$cdom,$cnum) eq 'ok') {
 # Also store with the person who posted the liked/unliked entry
-              if ($env{'form.like'}) {
-                  &storediscussionlikes(1,$contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'});
-                  $result=&mt("Registered 'Like'");
-              } else {
-                  &storediscussionlikes(-1,$contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'});
-                  $result=&mt("Registered 'Unlike'");
+                          my ($chglike,$chgunlike);
+                          if ($env{'form.like'}) {
+                              if ($votetype eq 'switch') {
+                                  $chglike = 0;
+                                  $chgunlike = -1;
+                              } else {
+                                  $chglike = 1;
+                                  $chgunlike = 0;
+                              }
+                              &storediscussionlikes($chglike,$chgunlike,
+                                                    $contrib{$idx.':sendername'},
+                                                    $contrib{$idx.':senderdomain'},
+                                                    $env{'request.course.id'},'like');
+                              $result=&mt("Registered 'Like'");
+                          } else {
+                              if ($votetype eq 'switch') {
+                                  $chglike = -1;
+                                  $chgunlike = 0;
+                              } else {
+                                  $chglike = 0;
+                                  $chgunlike = 1;
+                              }
+                             &storediscussionlikes($chglike,$chgunlike,
+                                                   $contrib{$idx.':sendername'},
+                                                   $contrib{$idx.':senderdomain'},
+                                                   $env{'request.course.id'},'unlike');
+                             $result=&mt("Registered 'Unlike'");
+                          }
+                      } else {
+# Oops, something went wrong
+                          $result=&mt("Failed to register vote");
+                      }
+                  }
               }
           } else {
-# Oops, something went wrong
-              $result=&mt("Failed to register vote");
+              $result=&mt('Voting unavailable for this discussion');
           }
+      } else {
+          $result=&mt('Invalid post number');
       }
       &redirect_back($r,$feedurl,$result.'<br />',
                      '0','0','','',$env{'form.previous'},undef,undef,undef,
@@ -4041,20 +4247,50 @@
 # --------------------------------------------------------------- Hide for good
       my ($symb,$idx)=split(/\:\:\:/,$env{'form.deldisc'});
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
+      my $ressymb=&wrap_symb($symb);
+      unless (&can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum)) {
+          &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',
+                         '0','0','','',$env{'form.previous'},'','','','',
+                         undef,undef,$group);
+          return OK;
+      }
       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 ($changelast,$newlast) = &get_discussion_info($idx,%contrib);
       if ($changelast) {
           &Apache::lonnet::put('discussiontimes',{$symb => $newlast},
-                   $env{'course.'.$env{'request.course.id'}.'.domain'},                   $env{'course.'.$env{'request.course.id'}.'.num'});
+                               $cdom,$cnum);
       }
       my %newhash=('deleted' => $contrib{'deleted'}.".$idx.");
-      &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
-			   $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'},undef,undef,undef,
+
+      my $result;
+      if (&Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
+                             $cdom,$cnum) eq 'ok') {
+          $result = &mt('Changed discussion status');
+          my $prefix=$symb.':'.$idx.':';
+          my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,
+                                          '^'.$prefix);
+          my ($totallikes,$totalunlikes);
+          if (ref($likes{$prefix.'likers'}) eq 'HASH') {
+              $totallikes = scalar(keys(%{$likes{$prefix.'likers'}}));
+          }
+          if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
+              $totalunlikes = scalar(keys(%{$likes{$prefix.'unlikers'}}));
+          }
+          if ($totallikes || $totalunlikes) {
+              my $chglikes = -1 * $totallikes;
+              my $chgunlikes = -1 * $totalunlikes;
+              &storediscussionlikes($chglikes,$chgunlikes,
+                                    $contrib{$idx.':sendername'},
+                                    $contrib{$idx.':senderdomain'},
+                                    $env{'request.course.id'},
+                                    'delete');
+          }
+      } else {
+          $result = &mt('Discussion status unchanged');
+      }
+      &redirect_back($r,$feedurl,$result.'<br />','0','0','','',
+                     $env{'form.previous'},undef,undef,undef,
                      undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.preview'}) {
@@ -4082,8 +4318,7 @@
       my $idx = $env{'form.idx'};
       if ($idx) {
           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);
           $attachmenturls = $contrib{$idx.':attachmenturl'};
       }
       &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,
@@ -4107,6 +4342,55 @@
 	  &Apache::loncommon::end_page();
       $r->print($start_page.$discussion.$end_page);
       return OK;
+  } elsif ($env{'form.undeleteall'}) {
+      &Apache::loncommon::content_type($r,'text/html');
+      $r->send_http_header;
+      my ($symb,$feedurl) = &get_feedurl_and_clean_symb($env{'form.undeleteall'});
+      my $ressymb=&wrap_symb($symb);
+      $r->print(&Apache::loncommon::start_page('Undelete all deleted discussion entries'));
+      if (&can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum)) {
+          my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                                                $cdom,$cnum);
+          $contrib{'deleted'} =~ s/^\.//;
+          $contrib{'deleted'} =~ s/\.$//;
+          if ($contrib{'deleted'} ne '') {
+              if (&Apache::lonnet::store({'deleted' => ''},$symb,$env{'request.course.id'},
+                                          $cdom,$cnum) eq 'ok') {
+                  my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,'^'.$symb.':');
+                  my @ids = split(/\.\./,$contrib{'deleted'});
+                  my (%chglikes,%chgunlikes);
+                  foreach my $idx (@ids) {
+                      my $uname = $contrib{$idx.':sendername'};
+                      my $udom = $contrib{$idx.':senderdomain'};
+                      my ($totallikes,$totalunlikes);
+                      if (ref($likes{$symb.':'.$idx.':likers'}) eq 'HASH') {
+                          $totallikes = scalar(keys(%{$likes{$symb.':'.$idx.':likers'}}));
+                      }
+                      if (ref($likes{$symb.':'.$idx.':unlikers'}) eq 'HASH') {
+                          $totalunlikes = scalar(keys(%{$likes{$symb.':'.$idx.':unlikers'}}));
+                      }
+                      if ($totallikes || $totalunlikes) {
+                          $chglikes{$uname.':'.$udom} += $totallikes;
+                          $chgunlikes{$uname.':'.$udom} += $totalunlikes;
+                      }
+                  }
+                  foreach my $user (keys(%chglikes)) {
+                      my ($uname,$udom) = split(/:/,$user);
+                      &storediscussionlikes($chglikes{$user},$chgunlikes{$user},
+                                            $uname,$udom,$env{'request.course.id'},
+                                            'undelete');
+                  }
+                  $r->print(&Apache::lonhtmlcommon::confirm_success(&mt("Undeleted all entries")));
+              } else {
+                  $r->print(&Apache::lonhtmlcommon::confirm_success(&mt("Failed to undelete entries"),1));
+              }
+          } else {
+              $r->print(&Apache::lonhtmlcommon::confirm_success(&mt("No entries to undelete"),1));
+          }
+          $r->print("<br /><a href='$feedurl'>".&mt("Return and reload")."</a>");
+      }
+      $r->print(&Apache::loncommon::end_page());
+      return OK;
   } else {
 # ------------------------------------------------------------- Normal feedback
       my $feedurl=$env{'form.postdata'};
@@ -4121,7 +4405,7 @@
       } elsif ($env{'form.editdisc'}) {
 	  $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
       } elsif ($env{'form.origpage'}) {
-	  $symb=""; 
+	  $symb="";
       } else {
 	  $symb=&Apache::lonnet::symbread($feedurl);
       }
@@ -4301,6 +4585,7 @@
     }
     return $ressymb;
 }
+
 sub dewrapper {
     my ($feedurl)=@_;
     if ($$feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
@@ -4454,8 +4739,16 @@
 
 =item discussion_visible()
 
+=item discussion_vote_available()
+
+=item get_realsymb()
+
 =item list_discussion()
 
+=item can_see_hidden()
+
+=item discussion_link()
+
 =item send_feedback_link()
 
 =item send_message_link()


More information about the LON-CAPA-cvs mailing list