--- loncom/interface/lonfeedback.pm 2003/11/03 23:23:34 1.66 +++ loncom/interface/lonfeedback.pm 2004/06/04 22:54:36 1.93 @@ -1,7 +1,7 @@ # The LearningOnline Network # Feedback # -# $Id: lonfeedback.pm,v 1.66 2003/11/03 23:23:34 www Exp $ +# $Id: lonfeedback.pm,v 1.93 2004/06/04 22:54:36 albertel 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,10 +34,39 @@ 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(); + +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)=@_; + + 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 ''; } @@ -67,28 +79,144 @@ sub list_discussion { $symb=&Apache::lonnet::symbread(); } unless ($symb) { return ''; } + +# 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 $visitkey = $ressymb.'_visit'; + my $ondispkey = $ressymb.'_markondisp'; + my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$lastkey,$showkey,$visitkey,$ondispkey],$ENV{'user.domain'},$ENV{'user.name'}); + my %discinfo = (); + my $showonlyunread = 0; + my $markondisp = 0; + my $prevread = 0; + my $previous = 0; + my $visit = 0; + my $newpostsflag = 0; + +# Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts. + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous']); + $previous = $ENV{'form.previous'}; + if ($previous > 0) { + $prevread = $previous; + } elsif (defined($dischash{$lastkey})) { + unless ($dischash{$lastkey} eq '') { + $prevread = $dischash{$lastkey}; + } + } + +# 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{$visitkey})) { + $visit = $dischash{$visitkey}; + } + $visit ++; + my $seeid=&Apache::lonnet::allowed('rin',$crs); - my $viewgrades=&Apache::lonnet::allowed('vgr',$crs); - my %discussionitems=(); - 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 %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'}) { + 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 $deleted=($contrib{'deleted'}=~/\.$idx\./); + my $origindex='0.'; + if (($contrib{$idx.':replyto'}) && ($ENV{'environment.threadeddiscussion'})) { +# 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 { +# 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++; my $message=$contrib{$idx.':message'}; $message=~s/\n/\<br \/\>/g; $message=&Apache::lontexconvert::msgtexconverted($message); + my $subject=$contrib{$idx.':subject'}; + if (defined($subject)) { + $subject=~s/\n/\<br \/\>/g; + $subject=&Apache::lontexconvert::msgtexconverted($subject); + } if ($contrib{$idx.':attachmenturl'}) { - my ($fname,$ft) - =($contrib{$idx.':attachmenturl'}=~/\/(\w+)\.(\w+)$/); - $message.='<p>'.&mt('Attachment').': <a href="'. - &Apache::lonnet::tokenwrapper( - $contrib{$idx.':attachmenturl'}). - '"><tt>'.$fname.'.'.$ft.'</tt></a></p>'; + my ($fname) + =($contrib{$idx.':attachmenturl'}=~m|/([^/]+)$|); + &Apache::lonnet::allowuploaded('/adm/feedback', + $contrib{$idx.':attachmenturl'}); + $message.='<p>'.&mt('Attachment'). + ': <a href="'.$contrib{$idx.':attachmenturl'}.'"><tt>'. + $fname.'</tt></a></p>'; } if ($message) { if ($hidden) { @@ -116,60 +244,214 @@ sub list_discussion { if ($seeid) { if ($hidden) { $sender.=' <a href="/adm/feedback?unhide='. - $symb.':::'.$idx.'">'.&mt('Make Visible').'</a>'; + $ressymb.':::'.$idx; + if ($newpostsflag) { + $sender .= '&previous='.$prevread; + } + $sender .= '">'.&mt('Make Visible').'</a>'; } else { $sender.=' <a href="/adm/feedback?hide='. - $symb.':::'.$idx.'">'.&mt('Hide').'</a>'; + $ressymb.':::'.$idx; + if ($newpostsflag) { + $sender .= '&previous='.$prevread; + } + $sender .= '">'.&mt('Hide').'</a>'; } $sender.=' <a href="/adm/feedback?deldisc='. - $symb.':::'.$idx.'">'.&mt('Delete').'</a>'; - } - if (&Apache::lonnet::allowed('pch', - $ENV{'request.course.id'}. - ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { - $sender.=' <a href="/adm/feedback?replydisc='. - $symb.':::'.$idx.'">'.&mt('Reply').'</a>'; + $ressymb.':::'.$idx; + if ($newpostsflag) { + $sender .= '&previous='.$prevread; + } + $sender .= '">'.&mt('Delete').'</a>'; } } else { if ($screenname) { $sender='<i>'.$screenname.'</i>'; } } + if (&discussion_open($status) && + &Apache::lonnet::allowed('pch', + $ENV{'request.course.id'}. + ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { + $sender.=' <a href="/adm/feedback?replydisc='. + $ressymb.':::'.$idx; + if ($newpostsflag) { + $sender .= '&previous='.$prevread; + } + $sender .= '" '.$target.'>'.&mt('Reply').'</a>'; + } my $vgrlink; if ($viewgrades) { $vgrlink=&Apache::loncommon::submlink('Submissions', $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$symb); } - $discussionitems{$idx}='<p><b>'.$sender.'</b> '.$vgrlink.' ('. - localtime($contrib{$idx.':timestamp'}). - '):<blockquote>'.$message. - '</blockquote></p>'; - } - } +#figure out at what position this needs to print + my $thisindex=$idx; + if ($ENV{'environment.threadeddiscussion'}) { + $thisindex=$origindex.substr('00'.$replies[$depth[$idx]],-2,2); + } + $alldiscussion{$thisindex}=$idx; + $index[$idx]=$thisindex; + my $spansize = 2; + if ($showonlyunread && $prevread > $posttime) { + $notshown{$idx} = 1; + } else { + if ($prevread > 0 && $prevread <= $posttime) { + $newitem{$idx} = 1; + $discussionitems[$idx] .= ' + <p><table border="0" width="100%"> + <tr><td align="left"><font color="#FF0000"><b>NEW</b></font></td>'; + } else { + $newitem{$idx} = 0; + $discussionitems[$idx] .= ' + <p><table border="0" width="100%"> + <tr><td align="left"> </td>'; + } + $discussionitems[$idx] .= '<td align ="left"> '. + '<b>'.$subject.'</b> '. + $sender.'</b> '.$vgrlink.' ('. + localtime($posttime).')</td></tr>'. + '</table><blockquote>'.$message.'</blockquote></p>'; + } + } + } } } - my $discussion='<hr />'; - foreach (sort { $a <=> $b } keys %discussionitems) { - $discussion.=$discussionitems{$_}; + + my $discussion=''; + + my $function = &Apache::loncommon::get_users_function(); + my $color = &Apache::loncommon::designparm($function.'.tabbg', + $ENV{'user.domain'}); + my %lt = &Apache::lonlocal::texthash( + 'cuse' => 'Current settings for this discussion', + 'allposts' => 'All posts', + 'unread' => 'New posts only', + 'ondisp' => 'Once displayed', + 'onmark' => 'Once marked read', + 'disa' => 'Posts to be displayed', + 'npce' => 'Posts cease to be marked "NEW"', + 'chgt' => 'Change to ', + ); + + my $currdisp = $lt{'allposts'}; + my $currmark = $lt{'onmark'}; + my $dispchange = $lt{'unread'}; + my $markchange = $lt{'ondisp'}; + my $displink = '/adm/feedback?onlyunread='.$ressymb; + my $marklink = '/adm/feedback?markondisp='.$ressymb; + + if ($markondisp) { + $currmark = $lt{'ondisp'}; + $markchange = $lt{'onmark'}; + $marklink = '/adm/feedback?markonread='.$ressymb; + if ($newpostsflag) { + $marklink .= '&previous='.$prevread; + } + } + + if ($showonlyunread) { + $currdisp = $lt{'unread'}; + $dispchange = $lt{'allposts'}; + $displink = '/adm/feedback?allposts='.$ressymb; + } + + if ($newpostsflag) { + $displink .= '&previous='.$prevread; + } + + if ($visible) { +# Print the discusssion + $discussion.='<table bgcolor="#AAAAAA" cellpadding="2" cellspacing="2" border="0">'; + my $colspan=$maxdepth+1; + $discussion .= '<tr bgcolor="#FFFFFF"><td colspan="'.$colspan.'" valign="top">'. + '<table border="0" bgcolor="#FFFFFF" width="100%" cellspacing="2" cellpadding="2">'. + '<tr><td align="left"><b>'.$lt{'cuse'}.'</b></td><td> </td><td align="right"><b>'.$lt{'chgt'}.'</b></td></tr>'. + '<tr><td>'.$lt{'disa'}.': <i>'.$currdisp.'</i></td><td> </td><td align="right"><a href="'.$displink.'">'.$dispchange.'</a></td></tr>'. + '<tr><td>'.$lt{'npce'}.': <i>'.$currmark.'</i></td><td> </td><td align="right"><a href="'.$marklink.'">'.$markchange.'</a></td></tr>'. + '</table></td></tr>'. + '<tr><td bgcolor="#DDDDBB" colspan="'.$colspan.'">'. + '<table border="0" width="100%" bgcolor="#DDDDBB"><tr>'; + if ($visible>2) { + $discussion.='<td align="left">'. + '<a href="/adm/feedback?threadedon='.$ressymb; + if ($newpostsflag) { + $discussion .= '&previous='.$prevread; + } + $discussion .='">'.&mt('Threaded View').'</a> '. + '<a href="/adm/feedback?threadedoff='.$ressymb; + if ($newpostsflag) { + $discussion .= '&previous='.$prevread; + } + $discussion .='">'.&mt('Chronological View').'</a> </td>'; + } + if ($newpostsflag) { + if (!$markondisp) { + $discussion .='<td align="right"><a href="/adm/feedback?markread='.$ressymb.'">'.&mt('Mark new posts as read').'</a> '; + } else { + $discussion .= '<td> </td>'; + } + } else { + $discussion .= '<td> </td>'; + } + $discussion .= '</tr></table></td></tr>'; + + my $numhidden = keys %notshown; + if ($numhidden > 0) { + my $colspan = $maxdepth+1; + $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">'. + '<a href="/adm/feedback?allposts='.$ressymb; + if ($newpostsflag) { + $discussion .= '&previous='.$prevread; + } + $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '. + $numhidden.' '.&mt('previously viewed posts'). + '<br/></td></tr>'; + } + foreach (sort { $a <=> $b } keys %alldiscussion) { + unless ($notshown{$alldiscussion{$_}} eq '1') { + $discussion.="\n<tr>"; + my $thisdepth=$depth[$alldiscussion{$_}]; + for (1..$thisdepth) { + $discussion.='<td> </td>'; + } + my $colspan=$maxdepth-$thisdepth+1; + $discussion.='<td bgcolor="'.$bgcols[$newitem{$alldiscussion{$_}}].'" colspan="'.$colspan.'">'. + $discussionitems[$alldiscussion{$_}]. + '</td></tr>'; + } + } + $discussion.='</table><br /><br />'; } if ($discussiononly) { $discussion.=(<<ENDDISCUSS); <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data"> <input type="submit" name="discuss" value="Post Discussion" /> <input type="submit" name="anondiscuss" value="Post Anonymous Discussion" /> -<input type="hidden" name="symb" value="$symb" /> +<input type="hidden" name="symb" value="$ressymb" /> <input type="hidden" name="sendit" value="true" /> <br /> <font size="1">Note: in anonymous discussion, your name is visible only to course faculty</font><br /> -<textarea name="comment" cols="60" rows="10" wrap="hard"></textarea> +<b>Title:</b> <input type="text" name="subject" value="" size="30" /><br /><br /> +<textarea name="comment" cols="60" rows="12" wrap="hard"></textarea> <p> Attachment (128 KB max size): <input type="file" name="attachment" /> </p> </form> ENDDISCUSS $discussion.=&generate_preview_button(); - } + } else { + if (&discussion_open($status) && + &Apache::lonnet::allowed('pch', + $ENV{'request.course.id'}. + ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { + $discussion.='<table bgcolor="#BBBBBB"><tr><td><a href="/adm/feedback?replydisc='. + $symb.':::" '.$target.'>'. + '<img src="/adm/lonMisc/chat.gif" border="0" />'. + &mt('Post Discussion').'</a></td></tr></table>'; + } + } return $discussion; } @@ -179,12 +461,35 @@ sub mail_screen { '','onLoad="window.focus();"'); my $title=&Apache::lonnet::gettitle($feedurl); if (!$title) { $title = $feedurl; } - my $latexHelp = Apache::loncommon::helpLatexCheatsheet(); + my $quote=''; + my $subject = ''; + my $prevtag = ''; + if ($ENV{'form.replydisc'}) { + my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'}); + my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) { + my $message=$contrib{$idx.':message'}; + $message=~s/\n/\<br \/\>/g; + $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($message).'</blockquote>'; + if ($idx > 0) { + $subject = 'Re: '.$contrib{$idx.':subject'}; + } + } + if ($ENV{'form.previous'}) { + $prevtag = '<input type="hidden" name="previous" value="'.$ENV{'form.previous'}.'" />'; + } + } + my $latexHelp=&Apache::loncommon::helpLatexCheatsheet(); + my $htmlheader=&Apache::lonhtmlcommon::htmlareaheaders(); + my $send=&mt('Send'); $r->print(<<ENDDOCUMENT); <html> <head> <title>The LearningOnline Network with CAPA</title> <meta http-equiv="pragma" content="no-cache"></meta> +$htmlheader <script type="text/javascript"> //<!-- function gosubmit() { @@ -221,6 +526,7 @@ sub mail_screen { } if (rec) { + document.mailform.onsubmit(); document.mailform.submit(); } else { alert('Please check a feedback type.'); @@ -233,12 +539,17 @@ $bodytag <h2><tt>$title</tt></h2> <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data"> +$prevtag <input type="hidden" name="postdata" value="$feedurl" /> +<input type="hidden" name="replydisc" value="$ENV{'form.replydisc'}" /> Please check at least one of the following feedback types: $options<hr /> +$quote <p>My question/comment/feedback:</p> <p> $latexHelp +Title: <input type="text" name="subject" size="30" value="$subject" /></p> +<p> <textarea name="comment" cols="60" rows="10" wrap="hard"> </textarea></p> <p> @@ -246,21 +557,24 @@ Attachment (128 KB max size): <input typ </p> <p> <input type="hidden" name="sendit" value="1" /> -<input type="button" value="Send Feedback" onClick='gosubmit();' /> +<input type="button" value="$send" onClick='gosubmit();' /> </p> </form> ENDDOCUMENT -$r->print(&generate_preview_button().'</body></html>'); +$r->print(&generate_preview_button(). +&Apache::lonhtmlcommon::htmlareaactive(). +'</body></html>'); } sub fail_redirect { my ($r,$feedurl) = @_; + if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; $r->print (<<ENDFAILREDIR); +<html> <head><title>Feedback not sent</title> <meta http-equiv="pragma" content="no-cache" /> <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" /> </head> -<html> <body bgcolor="#FFFFFF"> <img align="right" src="/adm/lonIcons/lonlogos.gif" /> <b>Sorry, no recipients ...</b> @@ -270,20 +584,33 @@ ENDFAILREDIR } sub redirect_back { - my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status) = @_; + my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous) = @_; + my $prevtag = ''; + my $qrystr = ''; + if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; + if ($previous > 0) { + $qrystr = 'previous='.$previous; + if ($feedurl =~ /\?register=1/) { + $feedurl .= '&'.$qrystr; + } else { + $feedurl .= '?'.$qrystr; + } + $prevtag = '<input type="hidden" name="previous" value="'.$previous.'" />'; + } $r->print (<<ENDREDIR); +<html> <head> <title>Feedback sent</title> <meta http-equiv="pragma" content="no-cache" /> -<meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl"> +<meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" /> </head> -<html> <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'> <img align="right" src="/adm/lonIcons/lonlogos.gif" /> $typestyle <b>Sent $sendsomething message(s), and $sendposts post(s).</b> <font color="red">$status</font> <form name="reldt" action="$feedurl" target="loncapaclient"> +$prevtag </form> </body> </html> @@ -293,6 +620,7 @@ ENDREDIR sub no_redirect_back { my ($r,$feedurl) = @_; $r->print (<<ENDNOREDIR); +<html> <head><title>Feedback not sent</title> <meta http-equiv="pragma" content="no-cache" /> ENDNOREDIR @@ -303,7 +631,6 @@ ENDNOREDIR $r->print (<<ENDNOREDIRTWO); </head> -<html> <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'> <img align="right" src="/adm/lonIcons/lonlogos.gif" /> <b>Sorry, no feedback possible on this resource ...</b> @@ -339,19 +666,21 @@ sub screen_header { } } if ($ENV{'request.course.id'}) { - if (&Apache::lonnet::allowed('pch', + if (&discussion_open() && + &Apache::lonnet::allowed('pch', $ENV{'request.course.id'}. ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { - $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" /> '. + $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '. + ($ENV{'form.replydisc'}?' checked="1"':'').' /> '. &mt('Contribution to course discussion of resource'); $discussoptions.='<br /><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '. &mt('Anonymous contribution to course discussion of resource'). ' <i>('.&mt('name only visible to course faculty').')</i>'; } } - if ($msgoptions) { $msgoptions='<h2>'.&mt('Sending Messages').'</h2>'.$msgoptions; } + if ($msgoptions) { $msgoptions='<h2><img src="/adm/lonMisc/feedback.gif" />'.&mt('Sending Messages').'</h2>'.$msgoptions; } if ($discussoptions) { - $discussoptions='<h2>'.&mt('Discussion Contributions').'</h2>'.$discussoptions; } + $discussoptions='<h2><img src="/adm/lonMisc/chat.gif" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; } return $msgoptions.$discussoptions; } @@ -370,14 +699,17 @@ sub resource_output { sub clear_out_html { my ($message,$override)=@_; + unless (&Apache::lonhtmlcommon::htmlareablocked()) { return $message; } my $cid=$ENV{'request.course.id'}; if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) || ($override)) { # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG> - # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> + # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB> + # <SUP> my %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1, BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1, - M=>1); + M=>1, SUB=>1, SUP=>1, SPAN=>1, + H1=>1, H2=>1, H3=>1, H4=>1, H5=>1); $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/ {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\<$1"}/ge; @@ -509,9 +841,10 @@ sub send_msg { } sub adddiscuss { - my ($symb,$email,$anon,$attachmenturl)=@_; + my ($symb,$email,$anon,$attachmenturl,$subject)=@_; my $status=''; - if (&Apache::lonnet::allowed('pch',$ENV{'request.course.id'}. + if (&discussion_open() && + &Apache::lonnet::allowed('pch',$ENV{'request.course.id'}. ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { my %contrib=('message' => $email, @@ -522,7 +855,8 @@ sub adddiscuss { $ENV{'environment.middlename'}.' '. $ENV{'environment.lastname'}.' '. $ENV{'enrironment.generation'}, - 'attachmenturl'=> $attachmenturl); + 'attachmenturl'=> $attachmenturl, + 'subject' => $subject); if ($ENV{'form.replydisc'}) { $contrib{'replyto'}=(split(/\:\:\:/,$ENV{'form.replydisc'}))[1]; } @@ -562,7 +896,11 @@ sub show_preview { my $message=&clear_out_html($ENV{'form.comment'}); $message=~s/\n/\<br \/\>/g; $message=&Apache::lontexconvert::msgtexconverted($message); + my $subject=&clear_out_html($ENV{'form.subject'}); + $subject=~s/\n/\<br \/\>/g; + $subject=&Apache::lontexconvert::msgtexconverted($subject); $r->print('<table border="2"><tr><td>'. + '<b>Subject:</b> '.$subject.'<br /><br />'. $message.'</td></tr></table>'); } @@ -570,16 +908,18 @@ sub generate_preview_button { my $pre=&mt("Show Preview"); return(<<ENDPREVIEW); <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview"> +<input type="hidden" name="subject"> <input type="hidden" name="comment" /> <input type="button" value="$pre" -onClick="this.form.comment.value=document.mailform.comment.value;this.form.submit();" /> +onClick="document.mailform.onsubmit();this.form.comment.value=document.mailform.comment.value;this.form.subject.value=document.mailform.subject.value;this.form.submit();" /> </form> ENDPREVIEW } + sub handler { my $r = shift; if ($r->header_only) { - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK; } @@ -587,11 +927,77 @@ sub handler { # --------------------------- Get query string for limited number of parameters &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['hide','unhide','deldisc','postdata','preview','replydisc']); + ['hide','unhide','deldisc','postdata','preview','replydisc','threadedon','threadedoff','onlyunread','allposts','previous','markread','markonread','markondisp']); - if (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) { + if (($ENV{'form.markondisp'}) || ($ENV{'form.markonread'})) { +# ---------------------- Modify setting for identification of 'NEW' posts in this discussion + + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + my $symb=$ENV{'form.markondisp'}?$ENV{'form.markondisp'}:$ENV{'form.markonread'}; + my $ressymb = $symb; + my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { + $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; + } + + my %discinfo = (); + my $lastkey = $ressymb.'_lastread'; + my $ondispkey = $ressymb.'_markondisp'; + if ($ENV{'form.markondisp'}) { + $discinfo{$lastkey} = time; + $discinfo{$ondispkey} = 1; + } elsif ($ENV{'form.markonread'}) { + if ( defined($ENV{'previous'}) ) { + $discinfo{$lastkey} = $ENV{'previous'}; + } + $discinfo{$ondispkey} = 0; + } + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); + if ($ENV{'form.markondisp'}) { + &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0'); + } else { + &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0','',$ENV{'form.previous'}); + } + return OK; + } elsif (($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'})) { +# ----------------------------------------------------------------- Modify display setting for this discussion + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + my $symb=$ENV{'form.allposts'}?$ENV{'form.allposts'}:$ENV{'form.onlyunread'}; + my $ressymb = $symb; + my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { + $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; + } + my %discinfo = (); + if ($ENV{'form.allposts'}) { + $discinfo{$ressymb.'_showonlyunread'} = 0; + } elsif ($ENV{'form.onlyunread'}) { + $discinfo{$ressymb.'_showonlyunread'} = 1; + } + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); + &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0','',$ENV{'form.previous'}); + return OK; + } elsif ($ENV{'form.markread'}) { +# ----------------------------------------------------------------- Mark new posts as read + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + my $symb=$ENV{'form.markread'}; + my $ressymb = $symb; + my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { + $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; + } + my %discinfo = (); + my $lastkey = $ressymb.'_lastread'; + $discinfo{$lastkey} = time; + &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); + &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed reading status').'<br />','0','0'); + return OK; + } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) { # ----------------------------------------------------------------- Hide/unhide - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'}; @@ -618,10 +1024,24 @@ sub handler { $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); &redirect_back($r,&Apache::lonnet::clutter($url), - &mt('Changed discussion status').'<br />','0','0'); + &mt('Changed discussion status').'<br />','0','0','',$ENV{'form.previous'}); + } elsif (($ENV{'form.threadedon'}) || ($ENV{'form.threadedoff'})) { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + if ($ENV{'form.threadedon'}) { + &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'}); + &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on'); + } else { + &Apache::lonnet::del('environment',['threadeddiscussion']); + &Apache::lonnet::delenv('environment\.threadeddiscussion'); + } + my $symb=$ENV{'form.threadedon'}?$ENV{'form.threadedon'}:$ENV{'form.threadedoff'}; + my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + &redirect_back($r,&Apache::lonnet::clutter($url), + &mt('Changed discussion view mode').'<br />','0','0','',$ENV{'form.previous'}); } elsif ($ENV{'form.deldisc'}) { # --------------------------------------------------------------- Hide for good - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; my $entry=$ENV{'form.deldisc'}; @@ -645,9 +1065,11 @@ sub handler { $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); &redirect_back($r,&Apache::lonnet::clutter($url), - &mt('Changed discussion status').'<br />','0','0'); + &mt('Changed discussion status').'<br />','0','0','',$ENV{'form.previous'}); } elsif ($ENV{'form.preview'}) { # -------------------------------------------------------- User wants a preview + $r->content_type('text/html'); + $r->send_http_header; &show_preview($r); } else { # ------------------------------------------------------------- Normal feedback @@ -676,10 +1098,13 @@ sub handler { if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) { unless ($symb) { $goahead=0; } } - + # backward compatibility (bulltin boards used to be 'wrapped') + if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { + $feedurl=~s|^/adm/wrapper||; + } if ($goahead) { # Go ahead with feedback, no ambiguous reference - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; if ( @@ -719,7 +1144,7 @@ sub handler { my $attachmenturl=''; if ($ENV{'form.attachment.filename'}) { unless (length($ENV{'form.attachment'})>131072) { - $attachmenturl=&Apache::lonnet::userfileupload('attachment'); + $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback'); } } # Filter HTML out of message (could be nasty) @@ -740,18 +1165,20 @@ sub handler { my $numpost=0; if ($ENV{'form.discuss'}) { - $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl); + my $subject = &clear_out_html($ENV{'form.subject'}); + $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl,$subject); $numpost++; } if ($ENV{'form.anondiscuss'}) { - $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl); + my $subject = &clear_out_html($ENV{'form.subject'}); + $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl,$subject); $numpost++; } # Receipt screen and redirect back to where came from - &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status); + &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$ENV{'form.previous'}); } } else {