--- loncom/interface/lonfeedback.pm 2004/07/29 22:42:25 1.110
+++ loncom/interface/lonfeedback.pm 2012/03/09 15:09:39 1.290.2.7.2.3
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Feedback
#
-# $Id: lonfeedback.pm,v 1.110 2004/07/29 22:42:25 raeburn Exp $
+# $Id: lonfeedback.pm,v 1.290.2.7.2.3 2012/03/09 15:09:39 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -35,19 +35,38 @@ use Apache::lonmsg();
use Apache::loncommon();
use Apache::lontexconvert();
use Apache::lonlocal; # must not have ()
+use Apache::lonnet;
use Apache::lonhtmlcommon();
+use Apache::lonnavmaps;
+use Apache::lonenc();
+use Apache::lonrss();
+use HTML::LCParser();
+#use HTML::Tidy::libXML;
use Apache::lonspeller();
+use Apache::longroup;
+use Cwd;
+use LONCAPA;
sub discussion_open {
- my ($status)=@_;
+ my ($status,$symb)=@_;
+# Advanced roles can always discuss
+ if ($env{'request.role.adv'}) { return 1; }
+# Get discussion closing date
+ my $close=&Apache::lonnet::EXT('resource.0.discussend',$symb);
+# If it is defined and in the future, the instructor wants this discussion to be open
+ if (defined($close) && $close ne '' && $close > time) {
+ return 1;
+ }
+# It was not explicitly open, check if the problem is available.
+# If the problem is not available, close the discussion
if (defined($status) &&
- !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
- || $status eq 'OPEN')) {
- return 0;
+ !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
+ || $status eq 'OPEN')) {
+ return 0;
}
- my $close=&Apache::lonnet::EXT('resource.0.discussend');
+# The problem is available, but check if the instructor explictly closed discussion
if (defined($close) && $close ne '' && $close < time) {
- return 0;
+ return 0;
}
return 1;
}
@@ -57,66 +76,102 @@ sub discussion_visible {
if (not &discussion_open($status)) {
my $hidden=&Apache::lonnet::EXT('resource.0.discusshide');
if (lc($hidden) eq 'yes' or $hidden eq '' or !defined($hidden)) {
- return 0;
+ if (!$env{'request.role.adv'}) { return 0; }
}
}
return 1;
}
sub list_discussion {
- my ($mode,$status,$symb)=@_;
+ my ($mode,$status,$ressymb,$imsextras,$group)=@_;
+ unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); }
+ unless ($ressymb) { return ''; }
+ $ressymb=&wrap_symb($ressymb);
+ my $outputtarget=$env{'form.grade_target'};
+ if (defined($env{'form.export'})) {
+ if($env{'form.export'}) {
+ $outputtarget = 'export';
+ }
+ }
+ if (defined($imsextras)) {
+ if ($$imsextras{'caller'} eq 'imsexport') {
+ $outputtarget = 'export';
+ }
+ }
+ if (not &discussion_visible($status)) {
+ if ($mode ne 'board') {
+ &Apache::lonenc::check_encrypt(\$ressymb);
+ return '
'.&send_message_link($ressymb)."
";
+ }
+ }
+ if ($group ne '' && $mode eq 'board') {
+ if (&check_group_priv($group,'vgb') ne 'ok') {
+ return '';
+ }
+ }
- my $outputtarget=$ENV{'form.grade_target'};
- if (not &discussion_visible($status)) { return ''; }
- my @bgcols = ("#cccccc","#eeeeee");
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('boards');
+ if ($blocked) {
+ $blocktext = '
'.$blocktext."";
+ &Apache::lonenc::check_encrypt(\$ressymb);
+ if ($mode ne 'board') {
+ $blocktext.=&send_message_link($ressymb).'
';
+ }else{
+ $blocktext.="";
+ }
+ return $blocktext;
+ }
+
+ my @bgcols = ("LC_disc_old_item","LC_disc_new_item");
my $discussiononly=0;
if ($mode eq 'board') { $discussiononly=1; }
- unless ($ENV{'request.course.id'}) { return ''; }
- my $crs='/'.$ENV{'request.course.id'};
- my $cid=$ENV{'request.course.id'};
- if ($ENV{'request.course.sec'}) {
- $crs.='_'.$ENV{'request.course.sec'};
- }
- $crs=~s/\_/\//g;
- unless ($symb) {
- $symb=&Apache::lonnet::symbread();
+ unless ($env{'request.course.id'}) { return ''; }
+ my $crs='/'.$env{'request.course.id'};
+ my $cid=$env{'request.course.id'};
+ if ($env{'request.course.sec'}) {
+ $crs.='_'.$env{'request.course.sec'};
}
- unless ($symb) { return ''; }
+ $crs=~s/\_/\//g;
+ my $encsymb=&Apache::lonenc::check_encrypt($ressymb);
+ my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
+ && ($ressymb=~/\.(problem|exam|quiz|assess|survey|form|task)$/));
+
my %usernamesort = ();
my %namesort =();
my %subjectsort = ();
-# backward compatibility (bulletin boards used to be 'wrapped')
- my $ressymb=$symb;
- if ($mode eq 'board') {
- unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
- $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
- }
- }
# Get discussion display settings for this discussion
my $lastkey = $ressymb.'_lastread';
my $showkey = $ressymb.'_showonlyunread';
+ my $markkey = $ressymb.'_showonlyunmark',
my $visitkey = $ressymb.'_visit';
my $ondispkey = $ressymb.'_markondisp';
my $userpickkey = $ressymb.'_userpick';
- my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$lastkey,$showkey,$visitkey,$ondispkey,$userpickkey],$ENV{'user.domain'},$ENV{'user.name'});
+ my $toggkey = $ressymb.'_readtoggle';
+ my $readkey = $ressymb.'_read';
+ $ressymb=$encsymb;
+ my %dischash = &Apache::lonnet::get('nohist_'.$cid.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$env{'user.domain'},$env{'user.name'});
my %discinfo = ();
my $showonlyunread = 0;
+ my $showunmark = 0;
my $markondisp = 0;
my $prevread = 0;
my $previous = 0;
my $visit = 0;
my $newpostsflag = 0;
- my @posters = split/\&/,$dischash{$userpickkey};
+ 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']);
- my $sortposts = $ENV{'form.sortposts'};
- my $rolefilter = $ENV{'form.rolefilter'};
- my $statusfilter = $ENV{'form.statusfilter'};
- my $sectionpick = $ENV{'form.sectionpick'};
- my $totposters = $ENV{'form.totposters'};
- $previous = $ENV{'form.previous'};
+ &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 = split(/,/,$env{'form.sectionpick'});
+ my @grouppick = split(/,/,$env{'form.grouppick'});
+ my @rolefilter = split(/,/,$env{'form.rolefilter'});
+
+ my $totposters = $env{'form.totposters'};
+ $previous = $env{'form.previous'};
if ($previous > 0) {
$prevread = $previous;
} elsif (defined($dischash{$lastkey})) {
@@ -125,439 +180,166 @@ sub list_discussion {
}
}
+ my $cdom = $env{'course.'.$cid.'.domain'};
+ my $cnum = $env{'course.'.$cid.'.num'};
+ my $crstype = &Apache::loncommon::course_type();
+
# Get information about students and non-students in course for filtering display of posts
my %roleshash = ();
my %roleinfo = ();
- if ($rolefilter) {
- %roleshash = &Apache::lonnet::dump('nohist_userroles',$ENV{'course.'.$ENV{'request.course.id'}.'.domain'},$ENV{'course.'.$ENV{'request.course.id'}.'.num'});
- foreach (keys %roleshash) {
- my ($role,$uname,$udom,$sec) = split/:/,$_;
- my ($end,$start) = split/:/,$roleshash{$_};
+ my ($classgroups,$studentgroups);
+ if ($env{'form.rolefilter'}) {
+ %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
+ foreach my $rolekey (keys(%roleshash)) {
+ my ($role,$uname,$udom,$sec) = split(/:/,$rolekey);
+ if ($role =~ /^cr/) {
+ $role = 'cr';
+ }
+ my ($end,$start) = split(/:/,$roleshash{$rolekey});
my $now = time;
my $status = 'Active';
if (($now < $start) || ($end > 0 && $now > $end)) {
$status = 'Expired';
}
- push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;
+ if ($uname && $udom) {
+ push(@{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status);
+ }
}
- my ($classlist) = &Apache::loncoursedata::get_classlist(
- $ENV{'request.course.id'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.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) {
my ($section,$status) = ($data->[$sec_index],
$data->[$status_index]);
- push @{$roleinfo{$student}}, 'st:'.$section.':'.$status;
+ push(@{$roleinfo{$student}}, 'st:'.$section.':'.$status);
}
+ ($classgroups,$studentgroups) =
+ &Apache::loncoursedata::get_group_memberships($classlist,$keylist,
+ $cdom,$cnum);
}
# Get discussion display default settings for user
- my %userenv = &Apache::lonnet::get('environment',['discdisplay','discmarkread'],$ENV{'user.domain'},$ENV{'user.name'});
- my $discdisplay=$userenv{'discdisplay'};
- if ($discdisplay eq 'unread') {
+ if ($env{'environment.discdisplay'} eq 'unread') {
$showonlyunread = 1;
}
- my $discmarkread=$userenv{'discmarkread'};
- if ($discmarkread eq 'ondisp') {
+ if ($env{'environment.discmarkread'} eq 'ondisp') {
$markondisp = 1;
}
# Override user's default if user specified display setting for this discussion
if (defined($dischash{$ondispkey})) {
- $markondisp = $dischash{$ondispkey};
+ unless ($dischash{$ondispkey} eq '') {
+ $markondisp = $dischash{$ondispkey};
+ }
}
if ($markondisp) {
$discinfo{$lastkey} = time;
}
if (defined($dischash{$showkey})) {
- $showonlyunread = $dischash{$showkey};
+ unless ($dischash{$showkey} eq '') {
+ $showonlyunread = $dischash{$showkey};
+ }
+ }
+
+ if (defined($dischash{$markkey})) {
+ unless ($dischash{$markkey} eq '') {
+ $showunmark = $dischash{$markkey};
+ }
}
if (defined($dischash{$visitkey})) {
- $visit = $dischash{$visitkey};
+ unless ($dischash{$visitkey} eq '') {
+ $visit = $dischash{$visitkey};
+ }
}
$visit ++;
- my $seeid=&Apache::lonnet::allowed('rin',$crs);
- my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
- && ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/));
+ 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=();
- my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+
+ my $current=0;
my $visible=0;
my @depth=();
- my @original=();
- my @index=();
- my @replies=();
+ my @replies = ();
my %alldiscussion=();
+ my %imsitems=();
+ my %imsfiles=();
my %notshown = ();
my %newitem = ();
my $maxdepth=0;
-
+ my %anonhash=();
+ my $anoncnt=0;
my $target='';
- unless ($ENV{'browser.interface'} eq 'textual' ||
- $ENV{'environment.remote'} eq 'off' ) {
+ unless ($env{'browser.interface'} eq 'textual' ||
+ $env{'environment.remote'} eq 'off' ) {
$target='target="LONcom"';
}
-
+
my $now = time;
$discinfo{$visitkey} = $visit;
- &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
-
- if ($contrib{'version'}) {
- my $oldest = $contrib{'1:timestamp'};
- if ($prevread eq '0') {
- $prevread = $oldest-1;
- }
- for (my $id=1;$id<=$contrib{'version'};$id++) {
- my $idx=$id;
- my $posttime = $contrib{$idx.':timestamp'};
- if ($prevread <= $posttime) {
- $newpostsflag = 1;
- }
- my $hidden=($contrib{'hidden'}=~/\.$idx\./);
- my $studenthidden=($contrib{'studenthidden'}=~/\.$idx\./);
- my $deleted=($contrib{'deleted'}=~/\.$idx\./);
- my $origindex='0.';
- my $numoldver=0;
- if ($contrib{$idx.':replyto'}) {
- if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread')) {
-# this is a follow-up message
- $original[$idx]=$original[$contrib{$idx.':replyto'}];
- $depth[$idx]=$depth[$contrib{$idx.':replyto'}]+1;
- $origindex=$index[$contrib{$idx.':replyto'}];
- if ($depth[$idx]>$maxdepth) { $maxdepth=$depth[$idx]; }
- } else {
- $original[$idx]=0;
- $depth[$idx]=0;
- }
- } else {
-# this is an original message
- $original[$idx]=0;
- $depth[$idx]=0;
- }
- if ($replies[$depth[$idx]]) {
- $replies[$depth[$idx]]++;
- } else {
- $replies[$depth[$idx]]=1;
- }
- unless ((($hidden) && (!$seeid)) || ($deleted)) {
- $visible++;
- if ($contrib{$idx.':history'}) {
- if ($contrib{$idx.':history'} =~ /:/) {
- my @oldversions = split/:/,$contrib{$idx.':history'};
- $numoldver = @oldversions;
- } else {
- $numoldver = 1;
- }
- }
- my ($message,$subject);
- if ($idx > 0) {
- if ($contrib{$idx.':message'} =~ /.*::::\Q$numoldver\E::::(.+?)$/si) {
- $message = $1;
- } else {
- $message = $contrib{$idx.':message'};
- }
- } else {
- $message=$contrib{$idx.':message'};
- }
- my $attachmenturls = $contrib{$idx.':attachmenturl'};
- $message=~s/\n/\ /g;
- $message=&Apache::lontexconvert::msgtexconverted($message);
- if ($idx > 0) {
- if ($contrib{$idx.':subject'} =~ /.*::::\Q$numoldver\E::::(.+?)$/si) {
- $subject = $1;
- } else {
- $subject = $contrib{$idx.':subject'};
- }
- } else {
- $subject=$contrib{$idx.':subject'};
- }
- if (defined($subject)) {
- $subject=~s/\n/\ /g;
- $subject=&Apache::lontexconvert::msgtexconverted($subject);
- }
- if ($attachmenturls) {
- my @attachments = ();
- my %currattach = ();
- &extract_attachments($attachmenturls,$idx,$numoldver,\$message,\@attachments,\%currattach);
- }
- if ($message) {
- if ($hidden) {
- $message=''.$message.'';
- if ($studenthidden) {
- $message .='
Deleted by poster (student).';
- }
- }
- my $screenname=&Apache::loncommon::screenname(
- $contrib{$idx.':sendername'},
- $contrib{$idx.':senderdomain'});
- my $plainname=&Apache::loncommon::nickname(
- $contrib{$idx.':sendername'},
- $contrib{$idx.':senderdomain'});
-
- my $sender=&mt('Anonymous');
-# Set up for sorting by subject
- if ($contrib{$idx.':subject'} eq '') {
- if (defined($subjectsort{'__No subject'})) {
- push @{$subjectsort{'__No subject'}}, $idx;
- } else {
- @{$subjectsort{'__No subject'}} = ("$idx");
- }
- } else {
- if (defined($subjectsort{$contrib{$idx.':subject'}})) {
- push @{$subjectsort{$contrib{$idx.':subject'}}}, $idx;
- } else {
- @{$subjectsort{$contrib{$idx.':subject'}}} = ("$idx");
- }
- }
- if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
- $sender=&Apache::loncommon::aboutmewrapper(
- $plainname,
- $contrib{$idx.':sendername'},
- $contrib{$idx.':senderdomain'}).' ('.
- $contrib{$idx.':sendername'}.' at '.
- $contrib{$idx.':senderdomain'}.')';
- if ($contrib{$idx.':anonymous'}) {
- $sender.=' ['.&mt('anonymous').'] '.
- $screenname;
- }
-# Set up for sorting by domain, then username
- unless (defined($usernamesort{$contrib{$idx.':senderdomain'}})) {
- %{$usernamesort{$contrib{$idx.':senderdomain'}}} = ();
- }
- if (defined($usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) {
- push @{$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx;
- } else {
- @{$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx");
- }
-# Set up for sorting by last name, then first name
- my %names = &Apache::lonnet::get('environment',['firstname','lastname'],
- $contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
- my $lastname = $names{'lastname'};
- my $firstname = $names{'firstname'};
- if ($lastname eq '') {
- $lastname = '_';
- }
- if ($firstname eq '') {
- $firstname = '_';
- }
- unless (defined($namesort{$lastname})) {
- %{$namesort{$lastname}} = ();
- }
- if (defined($namesort{$lastname}{$firstname})) {
- push @{$namesort{$lastname}{$firstname}}, $idx;
- } else {
- @{$namesort{$lastname}{$firstname}} = ("$idx");
- }
- if ($ENV{"course.$cid.allow_discussion_post_editing"} =~ m/yes/i) {
- if (($ENV{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($ENV{'user.name'} eq $contrib{$idx.':sendername'})) {
- $sender.=' '.&mt('Edit').''; unless ($seeid) {
- $sender.=" ';
- }
- }
- }
- if ($seeid) {
- if ($hidden) {
- unless ($studenthidden) {
- $sender.=' '.&mt('Make Visible').'';
- }
- } else {
- $sender.=' '.&mt('Hide').'';
- }
- $sender.=' '.&mt('Delete').'';
- }
- } else {
- if ($screenname) {
- $sender=''.$screenname.'';
- }
-# Set up for sorting by domain, then username for anonymous
- unless (defined($usernamesort{'__anon'})) {
- %{$usernamesort{'__anon'}} = ();
- }
- if (defined($usernamesort{'__anon'}{'__anon'})) {
- push @{$usernamesort{'__anon'}{'__anon'}}, $idx;
- } else {
- @{$usernamesort{'__anon'}{'__anon'}} = ("$idx");
- }
-# Set up for sorting by last name, then first name for anonymous
- unless (defined($namesort{'__anon'})) {
- %{$namesort{'__anon'}} = ();
- }
- if (defined($namesort{'__anon'}{'__anon'})) {
- push @{$namesort{'__anon'}{'__anon'}}, $idx;
- } else {
- @{$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.=' '.&mt('Reply').'';
- }
- my $vgrlink;
- if ($viewgrades) {
- $vgrlink=&Apache::loncommon::submlink('Submissions',
- $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$symb);
- }
-#figure out at what position this needs to print
- my $thisindex=$idx;
- if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread')) {
- $thisindex=$origindex.substr('00'.$replies[$depth[$idx]],-2,2);
- }
- $alldiscussion{$thisindex}=$idx;
- $shown{$idx} = 0;
- $index[$idx]=$thisindex;
- my $spansize = 2;
- if ($showonlyunread && $prevread > $posttime) {
- $notshown{$idx} = 1;
- } else {
-# apply filters
- my $uname = $contrib{$idx.':sendername'};
- my $udom = $contrib{$idx.':senderdomain'};
- my $poster = $uname.':'.$udom;
- my $rolematch = '';
- my $skiptest = 1;
- if ($totposters > 0) {
- if (grep/^$poster$/,@posters) {
- $shown{$idx} = 1;
- }
- } else {
- if ($rolefilter) {
- if ($rolefilter eq 'all') {
- $rolematch = '([^:]+)';
- } else {
- $rolematch = $rolefilter;
- $skiptest = 0;
- }
- }
- if ($sectionpick) {
- if ($sectionpick eq 'all') {
- $rolematch .= ':([^:]*)';
- } else {
- $rolematch .= ':'.$sectionpick;
- $skiptest = 0;
- }
- }
- if ($statusfilter) {
- if ($statusfilter eq 'all') {
- $rolematch .= ':([^:]+)';
- } else {
- $rolematch .= ':'.$statusfilter;
- $skiptest = 0;
- }
- }
- if ($skiptest) {
- $shown{$idx} = 1;
- } else {
- foreach my $role (@{$roleinfo{$poster}}) {
- if ($role =~ m/^$rolematch$/) {
- $shown{$idx} = 1;
- last;
- }
- }
- }
- }
- }
- unless ($notshown{$idx} == 1) {
- if ($prevread > 0 && $prevread <= $posttime) {
- $newitem{$idx} = 1;
- $discussionitems[$idx] .= '
-
";
- } else {
- $discussion.='\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}';
}
- my $thisdepth=$depth[$alldiscussion{$_}];
- if ($outputtarget ne 'tex') {
+ my $thisdepth=$depth[$alldiscussion{$post}];
+ if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
for (1..$thisdepth) {
$discussion.='
';
}
}
my $colspan=$maxdepth-$thisdepth+1;
- if ($outputtarget ne 'tex') {
- $discussion.='
'."\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,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
+ my @original=();
+ my @index=();
+ 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=();
+# Hashes containing likes and unlikes for this user.
+ my %userlikes=();
+ my %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'}:''));
+
+ if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {
+ $skip_group_check = 1;
+ }
+ my (%deletions,%hiddens);
+ if ($contrib{'deleted'}) {
+ my $deleted = $contrib{'deleted'};
+ $deleted =~ s/^\.//;
+ $deleted =~ s/\.$//;
+ %deletions = map { $_ => 1 } (split(/\.\./,$deleted));
+ }
+ if ($contrib{'hidden'}) {
+ my $hidden = $contrib{'hidden'};
+ $hidden =~ s/^\.//;
+ $hidden =~ s/\.$//;
+ %hiddens = map { $_ => 1 } (split(/\.\./,$hidden));
+ }
+ if ($contrib{'version'}) {
+ my $oldest = $contrib{'1:timestamp'};
+ if ($prevread eq '0') {
+ $prevread = $oldest-1;
+ }
+ my ($skiptest,$rolematch,$roleregexp,$secregexp,$statusregexp);
+ if ($sortposts) {
+ ($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'})) {
+ 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;
+ }
}
- $newattachmsg .= ''."\n";
+ 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);
+ }
+ $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;
+#
+# 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'});
+ my $posttime = $contrib{$idx.':timestamp'};
+ if ($prevread <= $posttime) {
+ $$newpostsflag = 1;
+ }
+ my $studenthidden=($contrib{'studenthidden'}=~/\.$idx\./);
+ my $origindex='0.';
+ my $numoldver=0;
+ if ($contrib{$idx.':replyto'}) {
+ if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
+# this is a follow-up message
+ $original[$idx]=$original[$contrib{$idx.':replyto'}];
+ $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1;
+ $origindex=$index[$contrib{$idx.':replyto'}];
+ if ($$depth[$idx]>$$maxdepth) { $$maxdepth=$$depth[$idx]; }
} else {
- $currnewattach[0] =~ m#.*/([^/]+)$#;
- $newattachmsg .= ''.$1.' '."\n";
+ $original[$idx]=0;
+ $$depth[$idx]=0;
+ }
+ } else {
+# this is an original message
+ $original[$idx]=0;
+ $$depth[$idx]=0;
+ }
+ if ($$replies[$$depth[$idx]]) {
+ $$replies[$$depth[$idx]]++;
+ } else {
+ $$replies[$$depth[$idx]]=1;
+ }
+ unless ((($hiddens{$idx}) && (!$seeid)) || ($deletions{$idx})) {
+ $$visible++;
+ if ($contrib{$idx.':history'}) {
+ if ($contrib{$idx.':history'} =~ /:/) {
+ my @oldversions = split(/:/,$contrib{$idx.':history'});
+ $numoldver = @oldversions;
+ } else {
+ $numoldver = 1;
+ }
+ }
+ $$current = $numoldver;
+ my %messages = ();
+ my %subjects = ();
+ my %attachtxt = ();
+ my %allattachments = ();
+ my ($screenname,$plainname,$showaboutme);
+ my $sender = &mt('Anonymous');
+# Anonymous users getting number within a discussion
+# Since idx is in static order, this should give the same sequence every time.
+ my $key=$contrib{$idx.':sendername'}.'@'.$contrib{$idx.':senderdomain'};
+ unless ($$anonhash{$key}) {
+ $anoncnt++;
+ $$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);
+
+
+# Set up for sorting by subject
+ unless ($outputtarget eq 'export') {
+ $message=$messages{$numoldver};
+ $message.=$attachtxt{$numoldver};
+ $subject=$subjects{$numoldver};
+ if ($message) {
+ if ($hiddens{$idx}) {
+ $message=''.$message.'';
+ if ($studenthidden) {
+ $message .='
Deleted by poster (student).';
+ }
+ }
+
+ if ($subject eq '') {
+ if (defined($$subjectsort{'__No subject'})) {
+ push(@{$$subjectsort{'__No subject'}}, $idx);
+ } else {
+ @{$$subjectsort{'__No subject'}} = ("$idx");
+ }
+ } else {
+ if (defined($$subjectsort{$subject})) {
+ push(@{$$subjectsort{$subject}}, $idx);
+ } else {
+ @{$$subjectsort{$subject}} = ("$idx");
+ }
+ }
+ if (!$contrib{$idx.':anonymous'} || $see_anonymous) {
+ if ($showaboutme) {
+ $sender = &Apache::loncommon::aboutmewrapper(
+ $plainname,
+ $contrib{$idx.':sendername'},
+ $contrib{$idx.':senderdomain'});
+ } else {
+ $sender = $plainname;
+ }
+ if ($see_anonymous) {
+ $sender .= ' ('.$contrib{$idx.':sendername'}.':'.
+ $contrib{$idx.':senderdomain'}.')';
+ }
+ $sender = ''.$sender.'';
+ if ($contrib{$idx.':anonymous'}) {
+ $sender.=' ['.$$anonhash{$key}.'] '.
+ $screenname;
+ }
+ if ($see_anonymous) {
+ $sender.=&Apache::loncommon::student_image_tag($contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
+ }
+# Set up for sorting by domain, then username
+ unless (defined($$usernamesort{$contrib{$idx.':senderdomain'}})) {
+ %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = ();
+ }
+ if (defined($$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) {
+ push(@{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx);
+ } else {
+ @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx");
+ }
+# Set up for sorting by last name, then first name
+ my %names = &Apache::lonnet::get('environment',
+ ['firstname','lastname'],$contrib{$idx.':senderdomain'},
+ ,$contrib{$idx.':sendername'});
+ my $lastname = $names{'lastname'};
+ my $firstname = $names{'firstname'};
+ if ($lastname eq '') {
+ $lastname = '_';
+ }
+ if ($firstname eq '') {
+ $firstname = '_';
+ }
+ unless (defined($$namesort{$lastname})) {
+ %{$$namesort{$lastname}} = ();
+ }
+ if (defined($$namesort{$lastname}{$firstname})) {
+ push(@{$$namesort{$lastname}{$firstname}}, $idx);
+ } else {
+ @{$$namesort{$lastname}{$firstname}} = ("$idx");
+ }
+ if ($outputtarget ne 'tex') {
+ if (&editing_allowed($escsymb.':::'.$idx,$group)) {
+ if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
+ $sender.=' '.&mt('Edit').'';
+
+ unless ($seeid) {
+ my $grpargs = &group_args($group);
+ $sender.=" ';
+ }
+ }
+ }
+ if ($seeid) {
+ if ($hiddens{$idx}) {
+ unless ($studenthidden) {
+ $sender.=' '.&mt('Make Visible').'';
+ }
+ } else {
+ $sender.=' '.&mt('Hide').'';
+ }
+ my $grpargs = &group_args($group);
+ $sender.=
+ " ";
+ $sender .= &mt('Delete').'';
+ }
+ }
+ } else {
+ if ($screenname) {
+ $sender=''.$screenname.'';
+ } else {
+ $sender=''.$$anonhash{$key}.'';
+ }
+ $sender = ''.$sender.'';
+# Set up for sorting by domain, then username for anonymous
+ unless (defined($$usernamesort{'__anon'})) {
+ %{$$usernamesort{'__anon'}} = ();
+ }
+ if (defined($$usernamesort{'__anon'}{'__anon'})) {
+ push(@{$$usernamesort{'__anon'}{'__anon'}}, $idx);
+ } else {
+ @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx");
+ }
+# Set up for sorting by last name, then first name for anonymous
+ unless (defined($$namesort{'__anon'})) {
+ %{$$namesort{'__anon'}} = ();
+ }
+ if (defined($$namesort{'__anon'}{'__anon'})) {
+ push(@{$$namesort{'__anon'}{'__anon'}}, $idx);
+ } else {
+ @{$$namesort{'__anon'}{'__anon'}} = ("$idx");
+ }
+ }
+ if ($outputtarget ne 'tex') {
+ if (&discussion_open($status)) {
+ if (($group ne '') &&
+ (&check_group_priv($group,'pgd') eq 'ok')) {
+ $sender.=' '.&mt('Reply').'';
+ } elsif (&Apache::lonnet::allowed('pch',
+ $env{'request.course.id'}.
+ ($env{'request.course.sec'}?'/'.
+ $env{'request.course.sec'}:''))) {
+ $sender.=' '.&mt('Reply').'';
+ }
+ }
+ if ($viewgrades) {
+ $vgrlink=&Apache::loncommon::submlink(&mt('Submissions'),
+ $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb);
+ }
+ if ($$dischash{$readkey}=~/\.$idx\./) {
+ $ctlink = '';
+ } else {
+ $ctlink = '';
+ }
+ }
+ }
+#figure out at what position this needs to print
+ }
+ if ($outputtarget eq 'export' || $message) {
+ my $thisindex=$idx;
+ if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
+ $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2);
+ }
+ $$alldiscussion{$thisindex}=$idx;
+ $$shown{$idx} = 0;
+ $index[$idx]=$thisindex;
+ }
+ if ($outputtarget eq 'export') {
+ %{$$imsitems{$idx}} = ();
+ $$imsitems{$idx}{'isvisible'}='true';
+ if ($hiddens{$idx}) {
+ $$imsitems{$idx}{'isvisible'}='false';
+ }
+ $$imsitems{$idx}{'title'}=$subjects{$numoldver};
+ $$imsitems{$idx}{'message'}=$messages{$numoldver};
+ $$imsitems{$idx}{'attach'}=$attachtxt{$numoldver};
+ $$imsitems{$idx}{'timestamp'}=$contrib{$idx.':timestamp'};
+ $$imsitems{$idx}{'sender'}=$plainname.' ('.
+ $contrib{$idx.':sendername'}.':'.
+ $contrib{$idx.':senderdomain'}.')';
+ $$imsitems{$idx}{'isanonymous'}='false';
+ if ($contrib{$idx.':anonymous'}) {
+ $$imsitems{$idx}{'isanonymous'}='true';
+ }
+ $$imsitems{$idx}{'currversion'}=$numoldver;
+ %{$$imsitems{$idx}{'allattachments'}}=%allattachments;
+ unless ($messages{$numoldver} eq '' && $attachtxt{$numoldver} eq '') {
+ $$shown{$idx} = 1;
+ }
+ } else {
+ if ($message) {
+ my $spansize = 2;
+ 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'};
+ my $poster = $uname.':'.$udom;
+ if ($env{'form.totposters'} ne '') {
+ if ($totposters == 0) {
+ $$shown{$idx} = 0;
+ } elsif ($totposters > 0) {
+ if (grep/^$poster$/,@{$posters}) {
+ $$shown{$idx} = 1;
+ }
+ }
+ } elsif ($sortposts) {
+ if ($skiptest) {
+ $$shown{$idx} = 1;
+ } else {
+ foreach my $role (@{$$roleinfo{$poster}}) {
+ if ($role =~ /^cc:/) {
+ my $cc_regexp = $roleregexp.':[^:]*:'.$statusregexp;
+ if ($role =~ /$cc_regexp/) {
+ $$shown{$idx} = 1;
+ last;
+ }
+ } elsif ($role =~ /^$rolematch$/) {
+ $$shown{$idx} = 1;
+ last;
+ }
+ }
+ }
+ if ($$shown{$idx} && !$skip_group_check) {
+ 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;
+ }
+ }
+ unless ($$notshown{$idx} == 1) {
+ if ($prevread > 0 && $prevread <= $posttime) {
+ $$newitem{$idx} = 1;
+ $$discussionitems[$idx] .= '
+