--- loncom/interface/lonfeedback.pm 2003/11/07 16:37:23 1.68
+++ loncom/interface/lonfeedback.pm 2004/08/01 16:05:14 1.111
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Feedback
#
-# $Id: lonfeedback.pm,v 1.68 2003/11/07 16:37:23 www Exp $
+# $Id: lonfeedback.pm,v 1.111 2004/08/01 16:05:14 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -25,24 +25,7 @@
#
# http://www.lon-capa.org/
#
-# (Internal Server Error Handler
-#
-# (Login Screen
-# 5/21/99,5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14,
-# 1/14/00,5/29,5/30,6/1,6/29,7/1,11/9 Gerd Kortemeyer)
-#
-# 3/1/1 Gerd Kortemeyer)
-#
-# 3/1,2/3,2/5,2/6,2/8 Gerd Kortemeyer
-# 2/9 Guy Albertelli
-# 2/10 Gerd Kortemeyer
-# 2/13 Guy Albertelli
-# 7/25 Gerd Kortemeyer
-# 7/26 Guy Albertelli
-# 7/26,8/10,10/1,11/5,11/6,12/27,12/29 Gerd Kortemeyer
-# YEAR=2002
-# 1/1,1/16 Gerd Kortemeyer
-#
+###
package Apache::lonfeedback;
@@ -51,14 +34,45 @@ use Apache::Constants qw(:common);
use Apache::lonmsg();
use Apache::loncommon();
use Apache::lontexconvert();
-use Apache::lonlocal;
+use Apache::lonlocal; # must not have ()
+use Apache::lonhtmlcommon();
+use Apache::lonspeller();
+
+sub discussion_open {
+ my ($status)=@_;
+ if (defined($status) &&
+ !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
+ || $status eq 'OPEN')) {
+ return 0;
+ }
+ my $close=&Apache::lonnet::EXT('resource.0.discussend');
+ if (defined($close) && $close ne '' && $close < time) {
+ return 0;
+ }
+ return 1;
+}
+
+sub discussion_visible {
+ my ($status)=@_;
+ 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;
+ }
+ }
+ return 1;
+}
sub list_discussion {
my ($mode,$status,$symb)=@_;
+ my $outputtarget=$ENV{'form.grade_target'};
+ if (not &discussion_visible($status)) { return ''; }
+ my @bgcols = ("#cccccc","#eeeeee");
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'};
}
@@ -67,10 +81,121 @@ sub list_discussion {
$symb=&Apache::lonnet::symbread();
}
unless ($symb) { return ''; }
+ 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 $toggkey = $ressymb.'_readtoggle';
+ my $readkey = $ressymb.'_read';
+
+ my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_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};
+
+# 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'};
+ if ($previous > 0) {
+ $prevread = $previous;
+ } elsif (defined($dischash{$lastkey})) {
+ unless ($dischash{$lastkey} eq '') {
+ $prevread = $dischash{$lastkey};
+ }
+ }
+
+# 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 $now = time;
+ my $status = 'Active';
+ if (($now < $start) || ($end > 0 && $now > $end)) {
+ $status = 'Expired';
+ }
+ 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 $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;
+ }
+ }
+
+# 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') {
+ $showonlyunread = 1;
+ }
+ my $discmarkread=$userenv{'discmarkread'};
+ if ($discmarkread eq 'ondisp') {
+ $markondisp = 1;
+ }
+
+# Override user's default if user specified display setting for this discussion
+ if (defined($dischash{$ondispkey})) {
+ $markondisp = $dischash{$ondispkey};
+ }
+ if ($markondisp) {
+ $discinfo{$lastkey} = time;
+ }
+
+ if (defined($dischash{$showkey})) {
+ $showonlyunread = $dischash{$showkey};
+ }
+
+ if (defined($dischash{$markkey})) {
+ $showunmark = $dischash{$markkey};
+ }
+
+ if (defined($dischash{$visitkey})) {
+ $visit = $dischash{$visitkey};
+ }
+ $visit ++;
+
my $seeid=&Apache::lonnet::allowed('rin',$crs);
- my $viewgrades=&Apache::lonnet::allowed('vgr',$crs);
+ my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
+ && ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/));
my @discussionitems=();
- my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
+ 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 $visible=0;
@@ -79,20 +204,48 @@ sub list_discussion {
my @index=();
my @replies=();
my %alldiscussion=();
+ my %notshown = ();
+ my %newitem = ();
my $maxdepth=0;
+ my $target='';
+ 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]; }
+ $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;
@@ -105,20 +258,51 @@ sub list_discussion {
}
unless ((($hidden) && (!$seeid)) || ($deleted)) {
$visible++;
- my $message=$contrib{$idx.':message'};
+ 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 ($contrib{$idx.':attachmenturl'}) {
- my ($fname,$ft)
- =($contrib{$idx.':attachmenturl'}=~/\/(\w+)\.(\w+)$/);
- $message.='
'.&mt('Attachment').': '.$fname.'.'.$ft.'
'; + 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/\'.$sender.' '.$vgrlink.' ('. - localtime($contrib{$idx.':timestamp'}). - '):
'.$message. - ''; - } - } + $shown{$idx} = 0; + $index[$idx]=$thisindex; + 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; + 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] .= ' +
NEW | '; + } else { + $newitem{$idx} = 0; + $discussionitems[$idx] .= ' +
'; + } + $discussionitems[$idx] .= ' | '. + ''.$subject.' '. + $sender.' '.$vgrlink.' ('. + &Apache::lonlocal::locallocaltime($posttime).') | '; + if ($dischash{$toggkey}) { + $discussionitems[$idx].=''. + $ctlink.' | '; + } + $discussionitems[$idx].= '
'.$message.''; + if ($contrib{$idx.':history'}) { + my @postversions = (); + $discussionitems[$idx] .= '
".$discussionitems[$alldiscussion{$_}]. - " |