File:  [LON-CAPA] / loncom / interface / lonfeedback.pm
Revision 1.84: download - view: text, annotated - select for diffs
Tue May 25 22:16:05 2004 UTC (20 years ago) by raeburn
Branches: MAIN
CVS tags: HEAD
Interface changes. User can toggle two settings:
1. display all posts/only new posts
2. new posts considered read when (a) users marks as read, or (b) automatically, following
display.
Settings for specific discussion override 'global' user preferences.  If no global or local preferences have been set, default is to display all posts, and require user to iclick a link to mark new posts as read.

    1: # The LearningOnline Network
    2: # Feedback
    3: #
    4: # $Id: lonfeedback.pm,v 1.84 2004/05/25 22:16:05 raeburn Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: ###
   29: 
   30: package Apache::lonfeedback;
   31: 
   32: use strict;
   33: use Apache::Constants qw(:common);
   34: use Apache::lonmsg();
   35: use Apache::loncommon();
   36: use Apache::lontexconvert();
   37: use Apache::lonlocal;
   38: 
   39: sub list_discussion {
   40:     my ($mode,$status,$symb)=@_;
   41: #    &Apache::lonnet::logthis("status is $status");
   42:     if (!($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
   43: 	  || $status eq 'OPEN')) {
   44: 	return '';
   45:     }
   46: 
   47:     my @bgcols = ("#cccccc","#eeeeee");
   48:     my $discussiononly=0;
   49:     if ($mode eq 'board') { $discussiononly=1; }
   50:     unless ($ENV{'request.course.id'}) { return ''; }
   51:     my $crs='/'.$ENV{'request.course.id'};
   52:     if ($ENV{'request.course.sec'}) {
   53: 	$crs.='_'.$ENV{'request.course.sec'};
   54:     }                 
   55:     $crs=~s/\_/\//g;
   56:     unless ($symb) {
   57: 	$symb=&Apache::lonnet::symbread();
   58:     }
   59:     unless ($symb) { return ''; }
   60: 
   61: # backward compatibility (bulletin boards used to be 'wrapped')
   62:     my $ressymb=$symb;
   63:     if ($mode eq 'board') {
   64:         unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
   65:             $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
   66:         }
   67:     }
   68: 
   69: # Get discussion display settings for this discussion
   70:     my $lastkey = $ressymb.'_lastread';
   71:     my $showkey = $ressymb.'_showonlyunread';
   72:     my $visitkey = $ressymb.'_visit';
   73:     my $ondispkey = $ressymb.'_markondisp';
   74:     my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$lastkey,$showkey,$visitkey,$ondispkey],$ENV{'user.domain'},$ENV{'user.name'});
   75:     my %discinfo = ();
   76:     my $showonlyunread = 0;
   77:     my $markondisp = 0;
   78:     my $prevread = 0;
   79:     my $previous = 0;
   80:     my $visit = 0;
   81:     my $newpostsflag = 0;
   82: 
   83: # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts.
   84:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous']);
   85:     $previous = $ENV{'form.previous'};
   86:     if ($previous > 0) {
   87:         $prevread = $previous;
   88:     } elsif (defined($dischash{$lastkey})) {
   89:         unless ($dischash{$lastkey} eq '') {
   90:             $prevread = $dischash{$lastkey};
   91:         }
   92:     }
   93: 
   94: # Get discussion display default settings for user
   95:     my %userenv = &Apache::lonnet::get('environment',['discdisplay','discmarkread'],$ENV{'user.domain'},$ENV{'user.name'});
   96:     my $discdisplay=$userenv{'discdisplay'};
   97:     if ($discdisplay eq 'unread') {
   98:         $showonlyunread = 1;
   99:     }
  100:     my $discmarkread=$userenv{'discmarkread'};
  101:     if ($discmarkread eq 'ondisp') {
  102:         $markondisp = 1;
  103:     }
  104: 
  105: # Override user's default if user specified display setting for this discussion
  106:     if (defined($dischash{$ondispkey})) {
  107:         $markondisp = $dischash{$ondispkey};
  108:     }
  109:     if ($markondisp) {
  110:         $discinfo{$lastkey} = time;
  111:     }
  112: 
  113:     if (defined($dischash{$showkey})) {
  114:         $showonlyunread = $dischash{$showkey};
  115:     }
  116: 
  117:     if (defined($dischash{$visitkey})) {
  118:         $visit = $dischash{$visitkey};
  119:     }
  120:     $visit ++;
  121: 
  122:     my $seeid=&Apache::lonnet::allowed('rin',$crs);
  123:     my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
  124: 	&& ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/));
  125:     my @discussionitems=();
  126:     my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
  127: 			  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  128: 			  $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  129:     my $visible=0;
  130:     my @depth=();
  131:     my @original=();
  132:     my @index=();
  133:     my @replies=();
  134:     my %alldiscussion=();
  135:     my %notshown = ();
  136:     my %newitem = ();
  137:     my $maxdepth=0;
  138: 
  139:     my $target='';
  140:     unless ($ENV{'browser.interface'} eq 'textual' ||
  141: 	    $ENV{'environment.remote'} eq 'off' ) {
  142: 	$target='target="LONcom"';
  143:     }
  144:     
  145:     my $now = time;
  146:     $discinfo{$visitkey} = $visit;
  147: 
  148:     &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
  149: 
  150:     if ($contrib{'version'}) {
  151:         my $oldest = $contrib{'1:timestamp'};
  152:         if ($prevread eq '0') {
  153:             $prevread = $oldest-1;
  154:         }
  155: 	for (my $id=1;$id<=$contrib{'version'};$id++) {
  156: 	    my $idx=$id;
  157:             my $posttime = $contrib{$idx.':timestamp'};
  158:             if ($prevread <= $posttime) {
  159:                 $newpostsflag = 1;
  160:             }
  161: 	    my $hidden=($contrib{'hidden'}=~/\.$idx\./);
  162: 	    my $deleted=($contrib{'deleted'}=~/\.$idx\./);
  163: 	    my $origindex='0.';
  164: 	    if (($contrib{$idx.':replyto'}) && ($ENV{'environment.threadeddiscussion'})) {
  165: # this is a follow-up message
  166: 		$original[$idx]=$original[$contrib{$idx.':replyto'}];
  167: 		$depth[$idx]=$depth[$contrib{$idx.':replyto'}]+1;
  168: 		$origindex=$index[$contrib{$idx.':replyto'}];
  169: 		if ($depth[$idx]>$maxdepth) { $maxdepth=$depth[$idx]; }
  170: 	    } else {
  171: # this is an original message
  172: 		$original[$idx]=0;
  173: 		$depth[$idx]=0;
  174: 	    }
  175: 	    if ($replies[$depth[$idx]]) {
  176: 		$replies[$depth[$idx]]++;
  177: 	    } else {
  178: 		$replies[$depth[$idx]]=1;
  179: 	    }
  180: 	    unless ((($hidden) && (!$seeid)) || ($deleted)) {
  181: 		$visible++;
  182: 		my $message=$contrib{$idx.':message'};
  183: 		$message=~s/\n/\<br \/\>/g;
  184: 		$message=&Apache::lontexconvert::msgtexconverted($message);
  185:                 my $subject=$contrib{$idx.':subject'};
  186:                 if (defined($subject)) {
  187:                     $subject=~s/\n/\<br \/\>/g;
  188:                     $subject=&Apache::lontexconvert::msgtexconverted($subject);
  189:                 }
  190: 		if ($contrib{$idx.':attachmenturl'}) {
  191: 		    my ($fname)
  192:                         =($contrib{$idx.':attachmenturl'}=~m|/([^/]+)$|);
  193: 		    &Apache::lonnet::allowuploaded('/adm/feedback',
  194: 					   $contrib{$idx.':attachmenturl'});
  195: 		    $message.='<p>'.&mt('Attachment').
  196: 			': <a href="'.$contrib{$idx.':attachmenturl'}.'"><tt>'.
  197: 			$fname.'</tt></a></p>';
  198: 		}
  199: 		if ($message) {
  200: 		    if ($hidden) {
  201: 			$message='<font color="#888888">'.$message.'</font>';
  202: 		    }
  203: 		    my $screenname=&Apache::loncommon::screenname(
  204: 					    $contrib{$idx.':sendername'},
  205: 					    $contrib{$idx.':senderdomain'});
  206: 		    my $plainname=&Apache::loncommon::nickname(
  207: 					    $contrib{$idx.':sendername'},
  208: 					    $contrib{$idx.':senderdomain'});
  209: 		    
  210: 		    my $sender=&mt('Anonymous');
  211: 		    if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
  212: 			$sender=&Apache::loncommon::aboutmewrapper(
  213: 					 $plainname,
  214: 					 $contrib{$idx.':sendername'},
  215: 					 $contrib{$idx.':senderdomain'}).' ('.
  216: 					 $contrib{$idx.':sendername'}.' at '.
  217: 					 $contrib{$idx.':senderdomain'}.')';
  218: 			if ($contrib{$idx.':anonymous'}) {
  219: 			    $sender.=' ['.&mt('anonymous').'] '.
  220: 				$screenname;
  221: 			}
  222: 			if ($seeid) {
  223: 			    if ($hidden) {
  224: 				$sender.=' <a href="/adm/feedback?unhide='.
  225: 				    $ressymb.':::'.$idx;
  226:                                 if ($newpostsflag) {
  227:                                     $sender .= '&previous='.$prevread;
  228:                                 }
  229:                                 $sender .= '">'.&mt('Make Visible').'</a>';
  230: 			    } else {
  231: 				$sender.=' <a href="/adm/feedback?hide='.
  232: 				    $ressymb.':::'.$idx;
  233:                                 if ($newpostsflag) {
  234:                                     $sender .= '&previous='.$prevread;
  235:                                 }
  236:                                 $sender .= '">'.&mt('Hide').'</a>';
  237: 			    }                     
  238: 			    $sender.=' <a href="/adm/feedback?deldisc='.
  239: 				$ressymb.':::'.$idx;
  240:                                 if ($newpostsflag) {
  241:                                     $sender .= '&previous='.$prevread;
  242:                                 }
  243:                                 $sender .= '">'.&mt('Delete').'</a>';
  244: 			}
  245: 		    } else {
  246: 			if ($screenname) {
  247: 			    $sender='<i>'.$screenname.'</i>';
  248: 			}
  249: 		    }
  250: 		    if (&Apache::lonnet::allowed('pch',
  251: 						 $ENV{'request.course.id'}.
  252: 						 ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  253: 			$sender.=' <a href="/adm/feedback?replydisc='.
  254: 			    $ressymb.':::'.$idx;
  255:                         if ($newpostsflag) {
  256:                             $sender .= '&previous='.$prevread;
  257:                         }
  258:                         $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
  259: 		    }
  260: 		    my $vgrlink;
  261: 		    if ($viewgrades) {
  262: 			$vgrlink=&Apache::loncommon::submlink('Submissions',
  263:             $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$symb);
  264: 		    }
  265: #figure out at what position this needs to print
  266: 		    my $thisindex=$idx;
  267: 		    if ($ENV{'environment.threadeddiscussion'}) {
  268: 			$thisindex=$origindex.substr('00'.$replies[$depth[$idx]],-2,2);	
  269: 		    }
  270: 		    $alldiscussion{$thisindex}=$idx;
  271: 		    $index[$idx]=$thisindex;
  272:                     my $spansize = 2;
  273:                     if ($showonlyunread && $prevread > $posttime) {
  274:                         $notshown{$idx} = 1;
  275:                     } else {
  276:                         if ($prevread > 0 && $prevread <= $posttime) {
  277:                             $newitem{$idx} = 1;
  278:                             $discussionitems[$idx] .= '
  279:                              <p><table border="0" width="100%">
  280:                               <tr><td align="left"><font color="#FF0000"><b>NEW</b></font></td>';
  281:                         } else {
  282:                             $newitem{$idx} = 0;
  283:                             $discussionitems[$idx] .= '
  284:                              <p><table border="0" width="100%">
  285:                               <tr><td align="left">&nbsp;</td>';
  286:                         }
  287:                         $discussionitems[$idx] .= '<td align ="left">&nbsp;&nbsp;'.
  288:                             '<b>'.$subject.'</b>&nbsp;&nbsp;'.
  289:                             $sender.'</b> '.$vgrlink.' ('.
  290:                             localtime($posttime).')</td></tr>'.
  291:                             '</table><blockquote>'.$message.'</blockquote></p>';
  292:                     }
  293:                 }
  294:             }
  295: 	}
  296:     }
  297: 
  298:     my $discussion='';
  299: 
  300:     my $function = &Apache::loncommon::get_users_function();
  301:     my $color = &Apache::loncommon::designparm($function.'.tabbg',
  302:                                                     $ENV{'user.domain'});
  303:     my %lt = &Apache::lonlocal::texthash(
  304:         'cuse' => 'Current settings for this discussion',
  305:         'allposts' => 'All posts',
  306:         'unread' => 'New posts only',
  307:         'ondisp' => 'Once displayed',
  308:         'onmark' => 'Once marked read',
  309:         'disa' => 'Posts to be displayed',
  310:         'npce' => 'Posts cease to be marked "NEW"',
  311:         'chgt' => 'Change to ',
  312:     );
  313: 
  314:     my $currdisp = $lt{'allposts'};
  315:     my $currmark = $lt{'onmark'};
  316:     my $dispchange = $lt{'unread'};
  317:     my $markchange = $lt{'ondisp'};
  318:     my $displink = '/adm/feedback?onlyunread='.$ressymb;
  319:     my $marklink = '/adm/feedback?markondisp='.$ressymb;
  320: 
  321:     if ($markondisp) {
  322:         $currmark = $lt{'ondisp'};
  323:         $markchange = $lt{'onmark'};
  324:         $marklink = '/adm/feedback?markonread='.$ressymb;
  325:         if ($newpostsflag) {
  326:             $marklink .= '&previous='.$prevread;
  327:         }
  328:     }
  329: 
  330:     if ($showonlyunread) {
  331:         $currdisp = $lt{'unread'};
  332:         $dispchange = $lt{'allposts'};
  333:         $displink = '/adm/feedback?allposts='.$ressymb;
  334:     }
  335: 
  336:     if ($newpostsflag) {
  337:         $displink .= '&previous='.$prevread;
  338:     }
  339: 
  340:     if ($visible) {
  341: # Print the discusssion
  342: 	$discussion.='<table bgcolor="#AAAAAA" cellpadding="2" cellspacing="2" border="0">';
  343: 	my $colspan=$maxdepth+1;
  344:         $discussion .= '<tr bgcolor="#FFFFFF"><td colspan="'.$colspan.'" valign="top">'.
  345:         '<table border="0" bgcolor="#FFFFFF" width="100%" cellspacing="2" cellpadding="2">'.
  346:         '<tr><td align="left"><b>'.$lt{'cuse'}.'</b></td><td>&nbsp;&nbsp;&nbsp;&nbsp;</td><td align="right"><b>'.$lt{'chgt'}.'</b></td></tr>'.
  347:         '<tr><td>'.$lt{'disa'}.':&nbsp;<i>'.$currdisp.'</i></td><td>&nbsp;&nbsp;&nbsp;&nbsp;</td><td align="right"><a href="'.$displink.'">'.$dispchange.'</a></td></tr>'.
  348:         '<tr><td>'.$lt{'npce'}.':&nbsp;<i>'.$currmark.'</i></td><td>&nbsp;&nbsp;&nbsp;&nbsp;</td><td align="right"><a href="'.$marklink.'">'.$markchange.'</a></td></tr>'.
  349:         '</table></td></tr>'.
  350:         '<tr><td bgcolor="#DDDDBB" colspan="'.$colspan.'">'.
  351:         '<table border="0" width="100%" bgcolor="#DDDDBB"><tr>';
  352:         if ($visible>2) {
  353: 	    $discussion.='<td align="left">'.
  354:             '<a href="/adm/feedback?threadedon='.$ressymb;
  355:             if ($newpostsflag) {
  356:                 $discussion .= '&previous='.$prevread;
  357:             }
  358:             $discussion .='">'.&mt('Threaded View').'</a>&nbsp;&nbsp;'.
  359:             '<a href="/adm/feedback?threadedoff='.$ressymb;
  360:             if ($newpostsflag) {
  361:                 $discussion .= '&previous='.$prevread;
  362:             }
  363:             $discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;</td>';
  364: 	} 
  365:         if ($newpostsflag) {
  366:             if (!$markondisp) {
  367:                 $discussion .='<td align="right"><a href="/adm/feedback?markread='.$ressymb.'">'.&mt('Mark new posts as read').'</a>&nbsp;&nbsp;';
  368:             } else {
  369:                 $discussion .= '<td>&nbsp;</td>';
  370:             }
  371:         } else {
  372:             $discussion .= '<td>&nbsp;</td>';
  373:         }
  374:         $discussion .= '</tr></table></td></tr>';
  375: 
  376:         my $numhidden = keys %notshown;
  377:         if ($numhidden > 0) {
  378:             my $colspan = $maxdepth+1;
  379:             $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">'.
  380:                          '<a href="/adm/feedback?allposts='.$ressymb;
  381:             if ($newpostsflag) {
  382:                 $discussion .= '&previous='.$prevread;
  383:             }
  384:             $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.
  385:                          $numhidden.' '.&mt('previously viewed posts').
  386:                          '<br/></td></tr>';
  387:         }
  388: 	foreach (sort { $a <=> $b } keys %alldiscussion) {
  389:             unless ($notshown{$alldiscussion{$_}} eq '1') {
  390: 	        $discussion.="\n<tr>";
  391: 	        my $thisdepth=$depth[$alldiscussion{$_}];
  392: 	        for (1..$thisdepth) {
  393: 		    $discussion.='<td>&nbsp;&nbsp;&nbsp;</td>';
  394: 	        }
  395: 	        my $colspan=$maxdepth-$thisdepth+1;
  396:                 $discussion.='<td  bgcolor="'.$bgcols[$newitem{$alldiscussion{$_}}].'" colspan="'.$colspan.'">'.
  397:                              $discussionitems[$alldiscussion{$_}].
  398: 	                     '</td></tr>';
  399: 	    }
  400:         }
  401:         $discussion.='</table><br /><br />';
  402:     }
  403:     if ($discussiononly) {
  404: 	$discussion.=(<<ENDDISCUSS);
  405: <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data">
  406: <input type="submit" name="discuss" value="Post Discussion" />
  407: <input type="submit" name="anondiscuss" value="Post Anonymous Discussion" />
  408: <input type="hidden" name="symb" value="$ressymb" />
  409: <input type="hidden" name="sendit" value="true" />
  410: <br />
  411: <font size="1">Note: in anonymous discussion, your name is visible only to
  412: course faculty</font><br />
  413: <b>Title:</b>&nbsp;<input type="text" name="subject" value="" size="30" /><br /><br />
  414: <textarea name="comment" cols="60" rows="10" wrap="hard"></textarea>
  415: <p>
  416: Attachment (128 KB max size): <input type="file" name="attachment" />
  417: </p>
  418: </form>
  419: ENDDISCUSS
  420:       $discussion.=&generate_preview_button();
  421:     } else {
  422: 	if (&Apache::lonnet::allowed('pch',
  423: 				   $ENV{'request.course.id'}.
  424: 	($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  425: 			    $discussion.='<table bgcolor="#BBBBBB"><tr><td><a href="/adm/feedback?replydisc='.
  426: 				$symb.':::" '.$target.'>'.
  427: 				'<img src="/adm/lonMisc/chat.gif" border="0" />'.
  428: 				&mt('Post Discussion').'</a></td></tr></table>';
  429: 			}
  430:     }
  431:    return $discussion;
  432: }
  433: 
  434: sub mail_screen {
  435:   my ($r,$feedurl,$options) = @_;
  436:   my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',
  437:                                           '','onLoad="window.focus();"');
  438:   my $title=&Apache::lonnet::gettitle($feedurl);
  439:   if (!$title) { $title = $feedurl; }
  440:   my $quote='';
  441:   my $subject = '';
  442:   my $prevtag = '';
  443:   if ($ENV{'form.replydisc'}) {
  444:       my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'});
  445:       my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
  446: 					   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  447: 					   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  448:       unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
  449: 	  my $message=$contrib{$idx.':message'};
  450: 	  $message=~s/\n/\<br \/\>/g;
  451: 	  $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($message).'</blockquote>';
  452:           if ($idx > 0) {
  453:               $subject = 'Re: '.$contrib{$idx.':subject'};
  454:           }
  455:       }
  456:       if ($ENV{'form.previous'}) {
  457:           $prevtag = '<input type="hidden" name="previous" value="'.$ENV{'form.previous'}.'" />';
  458:       }
  459:   }
  460:   my $latexHelp = Apache::loncommon::helpLatexCheatsheet();
  461:   my $send=&mt('Send');
  462:   $r->print(<<ENDDOCUMENT);
  463: <html>
  464: <head>
  465: <title>The LearningOnline Network with CAPA</title>
  466: <meta http-equiv="pragma" content="no-cache"></meta>
  467: <script type="text/javascript">
  468: //<!--
  469:     function gosubmit() {
  470:         var rec=0;
  471:         if (typeof(document.mailform.elements.author)!="undefined") {
  472:           if (document.mailform.elements.author.checked) {
  473:              rec=1;
  474:           } 
  475:         }
  476:         if (typeof(document.mailform.elements.question)!="undefined") {
  477:           if (document.mailform.elements.question.checked) {
  478:              rec=1;
  479:           } 
  480:         }
  481:         if (typeof(document.mailform.elements.course)!="undefined") {
  482:           if (document.mailform.elements.course.checked) {
  483:              rec=1;
  484:           } 
  485:         }
  486:         if (typeof(document.mailform.elements.policy)!="undefined") {
  487:           if (document.mailform.elements.policy.checked) {
  488:              rec=1;
  489:           } 
  490:         }
  491:         if (typeof(document.mailform.elements.discuss)!="undefined") {
  492:           if (document.mailform.elements.discuss.checked) {
  493:              rec=1;
  494:           } 
  495:         }
  496:         if (typeof(document.mailform.elements.anondiscuss)!="undefined") {
  497:           if (document.mailform.elements.anondiscuss.checked) {
  498:              rec=1;
  499:           } 
  500:         }
  501: 
  502:         if (rec) {
  503: 	    document.mailform.submit();
  504:         } else {
  505:             alert('Please check a feedback type.');
  506: 	}
  507:     }
  508: //-->
  509: </script>
  510: </head>
  511: $bodytag
  512: <h2><tt>$title</tt></h2>
  513: <form action="/adm/feedback" method="post" name="mailform"
  514: enctype="multipart/form-data">
  515: $prevtag
  516: <input type="hidden" name="postdata" value="$feedurl" />
  517: <input type="hidden" name="replydisc" value="$ENV{'form.replydisc'}" />
  518: Please check at least one of the following feedback types:
  519: $options<hr />
  520: $quote
  521: <p>My question/comment/feedback:</p>
  522: <p>
  523: $latexHelp
  524: Title: <input type="text" name="subject" size="30" value="$subject" /></p>
  525: <p>
  526: <textarea name="comment" cols="60" rows="10" wrap="hard">
  527: </textarea></p>
  528: <p>
  529: Attachment (128 KB max size): <input type="file" name="attachment" />
  530: </p>
  531: <p>
  532: <input type="hidden" name="sendit" value="1" />
  533: <input type="button" value="$send" onClick='gosubmit();' />
  534: </p>
  535: </form>
  536: ENDDOCUMENT
  537: $r->print(&generate_preview_button().'</body></html>');
  538: }
  539: 
  540: sub fail_redirect {
  541:   my ($r,$feedurl) = @_;
  542:   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
  543:   $r->print (<<ENDFAILREDIR);
  544: <html>
  545: <head><title>Feedback not sent</title>
  546: <meta http-equiv="pragma" content="no-cache" />
  547: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
  548: </head>
  549: <body bgcolor="#FFFFFF">
  550: <img align="right" src="/adm/lonIcons/lonlogos.gif" />
  551: <b>Sorry, no recipients  ...</b>
  552: </body>
  553: </html>
  554: ENDFAILREDIR
  555: }
  556: 
  557: sub redirect_back {
  558:   my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous) = @_;
  559:   my $prevtag = '';
  560:   my $qrystr = '';
  561:   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
  562:   if ($previous > 0) {
  563:       $qrystr = 'previous='.$previous;
  564:       if ($feedurl =~ /\?register=1/) {
  565:           $feedurl .= '&'.$qrystr;
  566:       } else {
  567:           $feedurl .= '?'.$qrystr;
  568:       }
  569:       $prevtag = '<input type="hidden" name="previous" value="'.$previous.'" />';
  570:   }
  571:   $r->print (<<ENDREDIR);
  572: <html>
  573: <head>
  574: <title>Feedback sent</title>
  575: <meta http-equiv="pragma" content="no-cache" />
  576: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
  577: </head>
  578: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>
  579: <img align="right" src="/adm/lonIcons/lonlogos.gif" />
  580: $typestyle
  581: <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
  582: <font color="red">$status</font>
  583: <form name="reldt" action="$feedurl" target="loncapaclient">
  584: $prevtag
  585: </form>
  586: </body>
  587: </html>
  588: ENDREDIR
  589: }
  590: 
  591: sub no_redirect_back {
  592:   my ($r,$feedurl) = @_;
  593:   $r->print (<<ENDNOREDIR);
  594: <html>
  595: <head><title>Feedback not sent</title>
  596: <meta http-equiv="pragma" content="no-cache" />
  597: ENDNOREDIR
  598: 
  599:   if ($feedurl!~/^\/adm\/feedback/) { 
  600:     $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2; url='.$feedurl.'">');
  601:   }
  602:   
  603:   $r->print (<<ENDNOREDIRTWO);
  604: </head>
  605: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'>
  606: <img align="right" src="/adm/lonIcons/lonlogos.gif" />
  607: <b>Sorry, no feedback possible on this resource  ...</b>
  608: </body>
  609: </html>
  610: ENDNOREDIRTWO
  611: }
  612: 
  613: sub screen_header {
  614:     my ($feedurl) = @_;
  615:     my $msgoptions='';
  616:     my $discussoptions='';
  617:     unless ($ENV{'form.replydisc'}) {
  618: 	if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) {
  619: 	    $msgoptions= 
  620: 		'<p><input type="checkbox" name="author" /> '.
  621: 		&mt('Feedback to resource author').'</p>';
  622: 	}
  623: 	if (&feedback_available(1)) {
  624: 	    $msgoptions.=
  625: 		'<br /><input type="checkbox" name="question" /> '.
  626: 		&mt('Question about resource content');
  627: 	}
  628: 	if (&feedback_available(0,1)) {
  629: 	    $msgoptions.=
  630: 		'<br /><input type="checkbox" name="course" /> '.
  631: 		&mt('Question/Comment/Feedback about course content');
  632: 	}
  633: 	if (&feedback_available(0,0,1)) {
  634: 	    $msgoptions.=
  635: 		'<br /><input type="checkbox" name="policy" /> '.
  636: 		&mt('Question/Comment/Feedback about course policy');
  637: 	}
  638:     }
  639:     if ($ENV{'request.course.id'}) {
  640: 	if (&Apache::lonnet::allowed('pch',
  641: 				     $ENV{'request.course.id'}.
  642: 				     ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  643: 	    $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '.
  644: 		($ENV{'form.replydisc'}?' checked="1"':'').' /> '.
  645: 		&mt('Contribution to course discussion of resource');
  646: 	    $discussoptions.='<br /><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '.
  647: 		&mt('Anonymous contribution to course discussion of resource').
  648: 		' <i>('.&mt('name only visible to course faculty').')</i>';
  649:       }
  650:     }
  651:     if ($msgoptions) { $msgoptions='<h2><img src="/adm/lonMisc/feedback.gif" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
  652:     if ($discussoptions) { 
  653: 	$discussoptions='<h2><img src="/adm/lonMisc/chat.gif" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
  654:     return $msgoptions.$discussoptions;
  655: }
  656: 
  657: sub resource_output {
  658:   my ($feedurl) = @_;
  659:   my $usersaw=&Apache::lonnet::ssi_body($feedurl);
  660:   $usersaw=~s/\<body[^\>]*\>//gi;
  661:   $usersaw=~s/\<\/body\>//gi;
  662:   $usersaw=~s/\<html\>//gi;
  663:   $usersaw=~s/\<\/html\>//gi;
  664:   $usersaw=~s/\<head\>//gi;
  665:   $usersaw=~s/\<\/head\>//gi;
  666:   $usersaw=~s/action\s*\=/would_be_action\=/gi;
  667:   return $usersaw;
  668: }
  669: 
  670: sub clear_out_html {
  671:   my ($message,$override)=@_;
  672:   my $cid=$ENV{'request.course.id'};
  673:   if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||
  674:       ($override)) {
  675:       # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG> 
  676:       # <BLOCKQUOTE> <DIV .*> <DIV> <IMG>
  677:       my %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,
  678: 		BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1,
  679:                 M=>1);
  680: 
  681:       $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/
  682: 	  {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\&lt;$1"}/ge;
  683:       $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/
  684: 	  {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\&gt;"}/ge;
  685:   } else {
  686:       $message=~s/\</\&lt\;/g;
  687:       $message=~s/\>/\&gt\;/g;
  688:   }
  689:   return $message;
  690: }
  691: 
  692: sub assemble_email {
  693:   my ($feedurl,$message,$prevattempts,$usersaw,$useranswer)=@_;
  694:   my $email=<<"ENDEMAIL";
  695: Refers to <a href="$feedurl">$feedurl</a>
  696: 
  697: $message
  698: ENDEMAIL
  699:     my $citations=<<"ENDCITE";
  700: <h2>Previous attempts of student (if applicable)</h2>
  701: $prevattempts
  702: <br /><hr />
  703: <h2>Original screen output (if applicable)</h2>
  704: $usersaw
  705: <h2>Correct Answer(s) (if applicable)</h2>
  706: $useranswer
  707: ENDCITE
  708:   return ($email,$citations);
  709: }
  710: 
  711: sub secapply {
  712:     my $rec=shift;
  713:     my $defaultflag=shift;
  714:     $rec=~s/\s+//g;
  715:     $rec=~s/\@/\:/g;
  716:     my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/);
  717:     if ($sections) {
  718: 	foreach (split(/\;/,$sections)) {
  719:             if (($_ eq $ENV{'request.course.sec'}) ||
  720:                 ($defaultflag && ($_ eq '*'))) {
  721:                 return $adr; 
  722:             }
  723:         }
  724:     } else {
  725:        return $rec;
  726:     }
  727:     return '';
  728: }
  729: 
  730: sub decide_receiver {
  731:   my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_;
  732:   my $typestyle='';
  733:   my %to=();
  734:   if ($ENV{'form.author'}||$author) {
  735:     $typestyle.='Submitting as Author Feedback<br>';
  736:     $feedurl=~/^\/res\/(\w+)\/(\w+)\//;
  737:     $to{$2.':'.$1}=1;
  738:   }
  739:   if ($ENV{'form.question'}||$question) {
  740:     $typestyle.='Submitting as Question<br>';
  741:     foreach (split(/\,/,
  742: 		   $ENV{'course.'.$ENV{'request.course.id'}.'.question.email'})
  743: 	     ) {
  744: 	my $rec=&secapply($_,$defaultflag);
  745:         if ($rec) { $to{$rec}=1; }
  746:     } 
  747:   }
  748:   if ($ENV{'form.course'}||$course) {
  749:     $typestyle.='Submitting as Comment<br />';
  750:     foreach (split(/\,/,
  751: 		   $ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'})
  752: 	     ) {
  753: 	my $rec=&secapply($_,$defaultflag);
  754:         if ($rec) { $to{$rec}=1; }
  755:     } 
  756:   }
  757:   if ($ENV{'form.policy'}||$policy) {
  758:     $typestyle.='Submitting as Policy Feedback<br />';
  759:     foreach (split(/\,/,
  760: 		   $ENV{'course.'.$ENV{'request.course.id'}.'.policy.email'})
  761: 	     ) {
  762: 	my $rec=&secapply($_,$defaultflag);
  763:         if ($rec) { $to{$rec}=1; }
  764:     } 
  765:   }
  766:   if ((scalar(%to) eq '0') && (!$defaultflag)) {
  767:      ($typestyle,%to)=
  768: 	 &decide_receiver($feedurl,$author,$question,$course,$policy,1);
  769:   }
  770:   return ($typestyle,%to);
  771: }
  772: 
  773: sub feedback_available {
  774:     my ($question,$course,$policy)=@_;
  775:     my ($typestyle,%to)=&decide_receiver('',0,$question,$course,$policy);
  776:     return scalar(%to);
  777: }
  778: 
  779: sub send_msg {
  780:   my ($feedurl,$email,$citations,$attachmenturl,%to)=@_;
  781:   my $status='';
  782:   my $sendsomething=0;
  783:   foreach (keys %to) {
  784:     if ($_) {
  785:       my $declutter=&Apache::lonnet::declutter($feedurl);
  786:       unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_),
  787:                'Feedback ['.$declutter.']',$email,$citations,$feedurl,
  788:                 $attachmenturl)=~/ok/) {
  789: 	$status.='<br />'.&mt('Error sending message to').' '.$_.'<br />';
  790:       } else {
  791: 	$sendsomething++;
  792:       }
  793:     }
  794:   }
  795: 
  796:     my %record=&Apache::lonnet::restore('_feedback');
  797:     my ($temp)=keys %record;
  798:     unless ($temp=~/^error\:/) {
  799:        my %newrecord=();
  800:        $newrecord{'resource'}=$feedurl;
  801:        $newrecord{'subnumber'}=$record{'subnumber'}+1;
  802:        unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
  803: 	   $status.='<br />'.&mt('Not registered').'<br />';
  804:        }
  805:     }
  806:        
  807:   return ($status,$sendsomething);
  808: }
  809: 
  810: sub adddiscuss {
  811:     my ($symb,$email,$anon,$attachmenturl,$subject)=@_;
  812:     my $status='';
  813:     if (&Apache::lonnet::allowed('pch',$ENV{'request.course.id'}.
  814:         ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  815: 
  816:     my %contrib=('message'      => $email,
  817:                  'sendername'   => $ENV{'user.name'},
  818:                  'senderdomain' => $ENV{'user.domain'},
  819:                  'screenname'   => $ENV{'environment.screenname'},
  820:                  'plainname'    => $ENV{'environment.firstname'}.' '.
  821: 		                   $ENV{'environment.middlename'}.' '.
  822:                                    $ENV{'environment.lastname'}.' '.
  823:                                    $ENV{'enrironment.generation'},
  824:                  'attachmenturl'=> $attachmenturl,
  825:                  'subject'      => $subject);
  826:     if ($ENV{'form.replydisc'}) {
  827: 	$contrib{'replyto'}=(split(/\:\:\:/,$ENV{'form.replydisc'}))[1];
  828:     }
  829:     if ($anon) {
  830: 	$contrib{'anonymous'}='true';
  831:     }
  832:     if (($symb) && ($email)) {
  833:        $status='Adding to class discussion'.($anon?' (anonymous)':'').': '.
  834:         &Apache::lonnet::store(\%contrib,$symb,$ENV{'request.course.id'},
  835:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  836: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  837:         my %storenewentry=($symb => time);
  838:         $status.='<br />'.&mt('Updating discussion time').': '.
  839:         &Apache::lonnet::put('discussiontimes',\%storenewentry,
  840:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  841: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  842:     }
  843:     my %record=&Apache::lonnet::restore('_discussion');
  844:     my ($temp)=keys %record;
  845:     unless ($temp=~/^error\:/) {
  846:        my %newrecord=();
  847:        $newrecord{'resource'}=$symb;
  848:        $newrecord{'subnumber'}=$record{'subnumber'}+1;
  849:        $status.='<br />'.&mt('Registering').': '.
  850:                &Apache::lonnet::cstore(\%newrecord,'_discussion');
  851:     }
  852:     } else {
  853: 	$status.='Failed.';
  854:     }
  855:     return $status.'<br />';   
  856: }
  857: 
  858: # ----------------------------------------------------------- Preview function
  859: 
  860: sub show_preview {
  861:     my $r=shift;
  862:     my $message=&clear_out_html($ENV{'form.comment'});
  863:     $message=~s/\n/\<br \/\>/g;
  864:     $message=&Apache::lontexconvert::msgtexconverted($message);
  865:     my $subject=&clear_out_html($ENV{'form.subject'});
  866:     $subject=~s/\n/\<br \/\>/g;
  867:     $subject=&Apache::lontexconvert::msgtexconverted($subject);
  868:     $r->print('<table border="2"><tr><td>'.
  869:        '<b>Subject:</b> '.$subject.'<br /><br />'.
  870:        $message.'</td></tr></table>');
  871: }
  872: 
  873: sub generate_preview_button {
  874:     my $pre=&mt("Show Preview");
  875:     return(<<ENDPREVIEW);
  876: <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview">
  877: <input type="hidden" name="subject">
  878: <input type="hidden" name="comment" />
  879: <input type="button" value="$pre"
  880: onClick="this.form.comment.value=document.mailform.comment.value;this.form.subject.value=document.mailform.subject.value;this.form.submit();" />
  881: </form>
  882: ENDPREVIEW
  883: }
  884: 
  885: sub handler {
  886:   my $r = shift;
  887:   if ($r->header_only) {
  888:      &Apache::loncommon::content_type($r,'text/html');
  889:      $r->send_http_header;
  890:      return OK;
  891:   }
  892: 
  893: # --------------------------- Get query string for limited number of parameters
  894: 
  895:    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  896:          ['hide','unhide','deldisc','postdata','preview','replydisc','threadedon','threadedoff','onlyunread','allposts','previous','markread','markonread','markondisp']);
  897: 
  898:   if (($ENV{'form.markondisp'}) || ($ENV{'form.markonread'})) {
  899: # ---------------------- Modify setting for identification of 'NEW' posts in this discussion
  900: 
  901:       &Apache::loncommon::content_type($r,'text/html');
  902:       $r->send_http_header;
  903:       my $symb=$ENV{'form.markondisp'}?$ENV{'form.markondisp'}:$ENV{'form.markonread'};
  904:       my $ressymb = $symb;
  905:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  906:       unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
  907:           $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
  908:       }
  909:                                                                                           
  910:       my %discinfo = ();
  911:       my $lastkey = $ressymb.'_lastread';
  912:       my $ondispkey = $ressymb.'_markondisp';
  913:       if ($ENV{'form.markondisp'}) {
  914:           $discinfo{$lastkey} = time;
  915:           $discinfo{$ondispkey} = 1;
  916:       } elsif ($ENV{'form.markonread'}) {
  917:           if ( defined($ENV{'previous'}) ) {
  918:               $discinfo{$lastkey} = $ENV{'previous'};
  919:           }
  920:           $discinfo{$ondispkey} = 0;
  921:       }
  922:       &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
  923:       if ($ENV{'form.markondisp'}) {
  924:           &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0');
  925:       } else {
  926:           &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0','',$ENV{'form.previous'});
  927:       }
  928:       return OK;
  929:   } elsif (($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'})) {
  930: # ----------------------------------------------------------------- Modify display setting for this discussion 
  931:       &Apache::loncommon::content_type($r,'text/html');
  932:       $r->send_http_header;
  933:       my $symb=$ENV{'form.allposts'}?$ENV{'form.allposts'}:$ENV{'form.onlyunread'};
  934:       my $ressymb = $symb;
  935:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  936:       unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
  937:           $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
  938:       }
  939:       my %discinfo = ();
  940:       if ($ENV{'form.allposts'}) {
  941:           $discinfo{$ressymb.'_showonlyunread'} = 0;
  942:       } elsif ($ENV{'form.onlyunread'}) {
  943:           $discinfo{$ressymb.'_showonlyunread'} = 1;
  944:       }
  945:       &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
  946:       &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0','',$ENV{'form.previous'});
  947:       return OK;
  948:   } elsif ($ENV{'form.markread'}) {
  949: # ----------------------------------------------------------------- Mark new posts as read
  950:       &Apache::loncommon::content_type($r,'text/html');
  951:       $r->send_http_header;
  952:       my $symb=$ENV{'form.markread'};
  953:       my $ressymb = $symb;
  954:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  955:       unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
  956:           $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
  957:       }
  958:       my %discinfo = ();
  959:       my $lastkey = $ressymb.'_lastread';
  960:       $discinfo{$lastkey} = time;
  961:       &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
  962:       &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed reading status').'<br />','0','0');
  963:       return OK;
  964:   } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) {
  965: # ----------------------------------------------------------------- Hide/unhide
  966:     &Apache::loncommon::content_type($r,'text/html');
  967:     $r->send_http_header;
  968: 
  969:     my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'};
  970: 
  971:     my ($symb,$idx)=split(/\:\:\:/,$entry);
  972:     my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  973: 
  974:     my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
  975:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  976: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  977: 
  978:         
  979:     my $currenthidden=$contrib{'hidden'};
  980:     
  981:     if ($ENV{'form.hide'}) {
  982: 	$currenthidden.='.'.$idx.'.';
  983:     } else {
  984:         $currenthidden=~s/\.$idx\.//g;
  985:     }
  986:     my %newhash=('hidden' => $currenthidden);
  987: 
  988:     &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
  989:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  990: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  991: 
  992:     &redirect_back($r,&Apache::lonnet::clutter($url),
  993:        &mt('Changed discussion status').'<br />','0','0','',$ENV{'form.previous'});
  994:   } elsif (($ENV{'form.threadedon'}) || ($ENV{'form.threadedoff'})) {
  995:       &Apache::loncommon::content_type($r,'text/html');
  996:       $r->send_http_header;
  997:       if ($ENV{'form.threadedon'}) {
  998: 	  &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
  999: 	  &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on');
 1000:       } else {
 1001:  	  &Apache::lonnet::del('environment',['threadeddiscussion']);
 1002: 	  &Apache::lonnet::delenv('environment\.threadeddiscussion');
 1003:       }
 1004:       my $symb=$ENV{'form.threadedon'}?$ENV{'form.threadedon'}:$ENV{'form.threadedoff'};
 1005:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
 1006:       &redirect_back($r,&Apache::lonnet::clutter($url),
 1007: 		     &mt('Changed discussion view mode').'<br />','0','0','',$ENV{'form.previous'});
 1008:   } elsif ($ENV{'form.deldisc'}) {
 1009: # --------------------------------------------------------------- Hide for good
 1010:     &Apache::loncommon::content_type($r,'text/html');
 1011:     $r->send_http_header;
 1012: 
 1013:     my $entry=$ENV{'form.deldisc'};
 1014: 
 1015:     my ($symb,$idx)=split(/\:\:\:/,$entry);
 1016:     my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
 1017: 
 1018:     my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
 1019:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
 1020: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
 1021: 
 1022:         
 1023:     my $currentdeleted=$contrib{'deleted'};
 1024:     
 1025:     $currentdeleted.='.'.$idx.'.';
 1026: 
 1027:     my %newhash=('deleted' => $currentdeleted);
 1028: 
 1029:     &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
 1030:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
 1031: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
 1032: 
 1033:     &redirect_back($r,&Apache::lonnet::clutter($url),
 1034:        &mt('Changed discussion status').'<br />','0','0','',$ENV{'form.previous'});
 1035:   } elsif ($ENV{'form.preview'}) {
 1036: # -------------------------------------------------------- User wants a preview
 1037:       $r->content_type('text/html');
 1038:       $r->send_http_header;
 1039:       &show_preview($r);
 1040:   } else {
 1041: # ------------------------------------------------------------- Normal feedback
 1042:   my $feedurl=$ENV{'form.postdata'};
 1043:   $feedurl=~s/^http\:\/\///;
 1044:   $feedurl=~s/^$ENV{'SERVER_NAME'}//;
 1045:   $feedurl=~s/^$ENV{'HTTP_HOST'}//;
 1046:   $feedurl=~s/\?.+$//;
 1047: 
 1048:   my $symb;
 1049:   if ($ENV{'form.replydisc'}) {
 1050:       $symb=(split(/\:\:\:/,$ENV{'form.replydisc'}))[0];
 1051:       my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
 1052:       $feedurl=&Apache::lonnet::clutter($url);
 1053:   } else {
 1054:       $symb=&Apache::lonnet::symbread($feedurl);
 1055:   }
 1056:   unless ($symb) {
 1057:       $symb=$ENV{'form.symb'};
 1058:       if ($symb) {
 1059: 	  my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
 1060:           $feedurl=&Apache::lonnet::clutter($url);
 1061:       }
 1062:   }
 1063:   my $goahead=1;
 1064:   if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) {
 1065:       unless ($symb) { $goahead=0; }
 1066:   }
 1067:   # backward compatibility (bulltin boards used to be 'wrapped')
 1068:   if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
 1069:       $feedurl=~s|^/adm/wrapper||;
 1070:   }
 1071:   if ($goahead) {
 1072: # Go ahead with feedback, no ambiguous reference
 1073:     &Apache::loncommon::content_type($r,'text/html');
 1074:     $r->send_http_header;
 1075:   
 1076:     if (
 1077:       (
 1078:        ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:)
 1079:       ) 
 1080:       || 
 1081:       ($ENV{'request.course.id'} && ($feedurl!~m:^/adm:))
 1082:       ||
 1083:       ($ENV{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))
 1084:      ) {
 1085: # --------------------------------------------------- Print login screen header
 1086:     unless ($ENV{'form.sendit'}) {
 1087:       my $options=&screen_header($feedurl);
 1088:       if ($options) {
 1089: 	&mail_screen($r,$feedurl,$options);
 1090:       } else {
 1091: 	&fail_redirect($r,$feedurl);
 1092:       }
 1093:     } else {
 1094:       
 1095: # Get previous user input
 1096:       my $prevattempts=&Apache::loncommon::get_previous_attempt(
 1097:             $symb,$ENV{'user.name'},$ENV{'user.domain'},
 1098:             $ENV{'request.course.id'});
 1099: 
 1100: # Get output from resource
 1101:       my $usersaw=&resource_output($feedurl);
 1102: 
 1103: # Get resource answer (need to allow student to view grades for this to work)
 1104:       &Apache::lonnet::appenv(('allowed.vgr'=>'F'));
 1105:       my $useranswer=&Apache::loncommon::get_student_answers(
 1106:                        $symb,$ENV{'user.name'},$ENV{'user.domain'},
 1107: 		       $ENV{'request.course.id'});
 1108:       &Apache::lonnet::delenv('allowed.vgr');
 1109: # Get attachments, if any, and not too large
 1110:       my $attachmenturl='';
 1111:       if ($ENV{'form.attachment.filename'}) {
 1112: 	  unless (length($ENV{'form.attachment'})>131072) {
 1113: 	      $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback');
 1114: 	  }
 1115:       }
 1116: # Filter HTML out of message (could be nasty)
 1117:       my $message=&clear_out_html($ENV{'form.comment'});
 1118: 
 1119: # Assemble email
 1120:       my ($email,$citations)=&assemble_email($feedurl,$message,$prevattempts,
 1121:           $usersaw,$useranswer);
 1122:  
 1123: # Who gets this?
 1124:       my ($typestyle,%to) = &decide_receiver($feedurl);
 1125: 
 1126: # Actually send mail
 1127:       my ($status,$numsent)=&send_msg($feedurl,$email,$citations,
 1128:           $attachmenturl,%to);
 1129: 
 1130: # Discussion? Store that.
 1131: 
 1132:       my $numpost=0;
 1133:       if ($ENV{'form.discuss'}) {
 1134:           my $subject = &clear_out_html($ENV{'form.subject'});
 1135: 	  $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl,$subject);
 1136: 	  $numpost++;
 1137:       }
 1138: 
 1139:       if ($ENV{'form.anondiscuss'}) {
 1140:           my $subject = &clear_out_html($ENV{'form.subject'});
 1141: 	  $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl,$subject);
 1142: 	  $numpost++;
 1143:       }
 1144: 
 1145: 
 1146: # Receipt screen and redirect back to where came from
 1147:       &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$ENV{'form.previous'});
 1148: 
 1149:     }
 1150:    } else {
 1151: # Unable to give feedback
 1152:     &no_redirect_back($r,$feedurl);
 1153:    }
 1154:   } else {
 1155: # Ambiguous Problem Resource
 1156:       if ( &Apache::lonnet::mod_perl_version() == 2 ) {
 1157: 	  &Apache::lonnet::cleanenv();
 1158:       }
 1159:       $r->internal_redirect('/adm/ambiguous');
 1160:   }
 1161: }
 1162:   return OK;
 1163: } 
 1164: 
 1165: 1;
 1166: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>