+$lt{'title'}:
ENDDISCUSS
if ($env{'form.origpage'}) {
@@ -931,21 +943,26 @@ sub build_posting_display {
my $skip_group_check = 0;
my $symb=&Apache::lonenc::check_decrypt($ressymb);
my $escsymb=&escape($ressymb);
+# These are the discussion contributions
my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
$env{'course.'.$env{'request.course.id'}.'.domain'},
$env{'course.'.$env{'request.course.id'}.'.num'});
+# And these are the likes/unlikes
my %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=();
+# 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'}:''));
if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {
$skip_group_check = 1;
}
+# Deletions and hiddens are just lists. Split them up into a hash for quicker lookup
my (%deletions,%hiddens);
if ($contrib{'deleted'}) {
my $deleted = $contrib{'deleted'};
@@ -959,6 +976,7 @@ sub build_posting_display {
$hidden =~ s/\.$//;
%hiddens = map { $_ => 1 } (split(/\.\./,$hidden));
}
+# Versions if store/restore are used to actually store the messages.
if ($contrib{'version'}) {
my $oldest = $contrib{'1:timestamp'};
if ($prevread eq '0') {
@@ -969,11 +987,48 @@ sub build_posting_display {
($skiptest,$roleregexp,$secregexp,$statusregexp) =
&filter_regexp($rolefilter,$sectionpick,$statusfilter);
$rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
- }
+ }
+# 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'})) {
+ push(@theselikes,$likes{$symb.':'.$idx.':likes'});
+ }
+ }
+# 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);
+ }
+ $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;
+# &Apache::lonnet::logthis(join(',',@theselikes)." Ave $ave StdDev $stddev $twominus $oneminus $oneplus $twoplus");
+#
+# This is now the real loop. Go through all entries, pick up what we need
+#
for (my $id=1;$id<=$contrib{'version'};$id++) {
my $idx=$id;
next if ($contrib{$idx.':deleted'});
next if ($contrib{$idx.':hidden'});
+# If we get here, we are actually going to display the message - we don't know where and we don't know if we display
+# previous edits, but it counts as one entry
my $posttime = $contrib{$idx.':timestamp'};
if ($prevread <= $posttime) {
$$newpostsflag = 1;
@@ -1107,6 +1162,12 @@ sub build_posting_display {
unless ($likes{$symb.':'.$idx.':unlikers'}=~/\,\Q$thisuser\E\,/) {
$sender.=' '.&discussion_link($symb,&mt('Unlike'),'unlike',$idx,$$newpostsflag,$prevread,&group_args($group));
}
+ my $thislikes=$likes{$symb.':'.$idx.':likes'};
+ if ($thislikes>0) {
+ $sender.=' ('.&mt("[_1] likes",$thislikes).')';
+ } elsif ($thislikes<0) {
+ $sender.=' ('.&mt("[_1] unlikes",abs($thislikes)).')';
+ }
if (&editing_allowed($escsymb.':::'.$idx,$group)) {
if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
$sender.=' '.
@@ -1289,8 +1350,23 @@ sub build_posting_display {
if ($$dischash{$toggkey}) {
$$discussionitems[$idx].=' '.$ctlink;
}
+# 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";
+ }
$$discussionitems[$idx].= '
'.
- $message.'
';
+ "
".
+ $message.
+ '
';
if ($contrib{$idx.':history'}) {
my @postversions = ();
$$discussionitems[$idx] .= &mt('This post has been edited by the author.');
@@ -1309,12 +1385,19 @@ sub build_posting_display {
$$discussionitems[$idx] .= ''.$version.'. - '.&Apache::lonlocal::locallocaltime($postversions[$i]).' ';
}
}
+# end of unless ($$notshown ...)
}
+# end of if ($message) ...
}
+# end of the else-branch of target being export
}
+# end of unless hidden or deleted
}
+# end of the loop over all discussion entries
}
+# end of "if there actually are any discussions
}
+# end of subroutine "build_posting_display"
}
sub filter_regexp {
@@ -2642,8 +2725,8 @@ sub screen_header {
unless (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/) && ($env{'user.adv'})) {
$msgoptions=
- '';
+ ' ';
}
my %optionhash=();
foreach my $type ('question','comment','policy') {
@@ -2651,20 +2734,20 @@ sub screen_header {
}
if (&feedback_available(1)) {
$msgoptions.=
- '';
+ ' ';
}
if (&feedback_available(0,1)) {
$msgoptions.=
- '';
+ ' ';
}
if (&feedback_available(0,0,1)) {
$msgoptions.=
- '
';
+ ' ';
}
}
if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) {
@@ -3571,7 +3654,7 @@ sub handler {
# --------------------------- Get query string for limited number of parameters
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['like','unlike','modal','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','modal','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 %attachmax = (
text => &mt('(128 KB max size)'),
@@ -3851,6 +3934,11 @@ ENDREDIR
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);
+#
+# 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'},
@@ -3859,8 +3947,10 @@ ENDREDIR
# Get all who like or unlike this
my $currentlikers=$contrib{$prefix.'likers'};
my $currentunlikers=$contrib{$prefix.'unlikers'};
+# Get the current "likes" count
my $likes=$contrib{$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'}) {
@@ -3868,7 +3958,7 @@ ENDREDIR
$alreadyflag=1;
} else {
if ($currentunlikers=~/\,\Q$thisuser\E\,/) {
- $currentunlikers=~s/\,\Q$thisuser\E\,//;
+ $currentunlikers=~s/\,\Q$thisuser\E\,//g;
} else {
$currentlikers.=','.$thisuser.',';
}
@@ -3879,7 +3969,7 @@ ENDREDIR
$alreadyflag=1;
} else {
if ($currentlikers=~/\,\Q$thisuser\E\,/) {
- $currentlikers=~s/\,\Q$thisuser\E\,//;
+ $currentlikers=~s/\,\Q$thisuser\E\,//g;
} else {
$currentunlikers.=','.$thisuser.',';
}
@@ -3887,14 +3977,17 @@ ENDREDIR
}
}
my $result;
+# $alreadyflag would be 1 if they tried to double-like or double-unlike
unless ($alreadyflag) {
my %newhash=($prefix.'likes' => $likes,
$prefix.'likers' => $currentlikers,
$prefix.'unlikers' => $currentunlikers);
+# 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') {
+# 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'");
@@ -3903,6 +3996,7 @@ ENDREDIR
$result=&mt("Registered 'Unlike'");
}
} else {
+# Oops, something went wrong
$result=&mt("Failed to register vote");
}
}
@@ -3993,6 +4087,24 @@ ENDREDIR
&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'});
+ $r->print(&Apache::loncommon::start_page('Undelete all deleted discussion entries'));
+ if (&Apache::lonnet::allowed('rin',$env{'request.course.id'})) {
+ if (&Apache::lonnet::store({'deleted' => ''},$symb,$env{'request.course.id'},
+ $env{'course.'.$env{'request.course.id'}.'.domain'},
+ $env{'course.'.$env{'request.course.id'}.'.num'}) eq 'ok') {
+ $r->print(&Apache::lonhtmlcommon::confirm_success(&mt("Undeleted all entries")));
+ } else {
+ $r->print(&Apache::lonhtmlcommon::confirm_success(&mt("Failed to undelete entries"),1));
+ }
+ $r->print(" ".&mt("Return and reload")."");
+ }
+ $r->print(&Apache::loncommon::end_page());
+ return OK;
} else {
# ------------------------------------------------------------- Normal feedback
my $feedurl=$env{'form.postdata'};
@@ -4008,6 +4120,8 @@ ENDREDIR
$symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
} elsif ($env{'form.origpage'}) {
$symb="";
+ } elsif ($env{'form.sendmessageonly'}) {
+ $symb=(split(/\:\:\:/,$env{'form.sendmessageonly'}))[0];
} else {
$symb=&Apache::lonnet::symbread($feedurl);
}