--- loncom/interface/lonfeedback.pm 2003/09/15 13:38:19 1.55 +++ loncom/interface/lonfeedback.pm 2004/08/04 18:04:57 1.113 @@ -1,7 +1,7 @@ # The LearningOnline Network # Feedback # -# $Id: lonfeedback.pm,v 1.55 2003/09/15 13:38:19 www Exp $ +# $Id: lonfeedback.pm,v 1.113 2004/08/04 18:04:57 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,11 +34,46 @@ use Apache::Constants qw(:common); use Apache::lonmsg(); use Apache::loncommon(); use Apache::lontexconvert(); +use Apache::lonlocal; # must not have () +use Apache::lonhtmlcommon(); +use HTML::LCParser(); +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 ($discussiononly,$symb)=@_; + 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'}; } @@ -64,36 +82,232 @@ 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 $discussion=''; - my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, + my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs) + && ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/)); + 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 $visible=0; + my @depth=(); + my @original=(); + 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'}) { - unless ($discussiononly) { - $discussion.= - '
Attachment: '.$fname.'.'.$ft.'';
+ if ($idx > 0) {
+ if ($contrib{$idx.':subject'} =~ /^ '.$sender.' '.$vgrlink.' ('.
- localtime($contrib{$idx.':timestamp'}).
- '):
Deleted by poster (student).';
+ }
}
my $screenname=&Apache::loncommon::screenname(
$contrib{$idx.':sendername'},
@@ -102,7 +316,21 @@ sub list_discussion {
$contrib{$idx.':sendername'},
$contrib{$idx.':senderdomain'});
- my $sender='Anonymous';
+ 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,
@@ -111,75 +339,742 @@ sub list_discussion {
$contrib{$idx.':sendername'}.' at '.
$contrib{$idx.':senderdomain'}.')';
if ($contrib{$idx.':anonymous'}) {
- $sender.=' [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) {
- $sender.=' Make Visible';
+ unless ($studenthidden) {
+ $sender.=' '.&mt('Make Visible').'';
+ }
} else {
$sender.=' Hide';
+ $ressymb.':::'.$idx;
+ if ($newpostsflag) {
+ $sender .= '&previous='.$prevread;
+ }
+ $sender .= '">'.&mt('Hide').'';
}
$sender.=' Delete';
+ $ressymb.':::'.$idx;
+ if ($newpostsflag) {
+ $sender .= '&previous='.$prevread;
+ }
+ $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);
}
- $discussion.=''.$message.
- '
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] .= '