File:
[LON-CAPA] /
loncom /
interface /
lonfeedback.pm
Revision
1.237:
download - view:
text,
annotated -
select for diffs
Sun Dec 24 22:13:19 2006 UTC (17 years, 5 months ago) by
raeburn
Branches:
MAIN
CVS tags:
HEAD
Include symb in msgid when sending feedback about a resource.
Include an error bit in msgid (1 if message is a "bomb" caused by an error when rendering a problem.
Include symb and resource title in messsage (<symb> and <resource_title> tags) when feedback is about a resource.
Navigate Contents page now checks for unread feedback or errors using symb instead of just resource url.
Navigate Contents page checks for resource context based on symb in msgid instead of in [url] included in message subject. Backwards compatibility with old-style messages retained.
Subject for feedback messages about resources appends message title instead of url inside [].
Title on feedback page now avoids leaking unencrypted file name in cases where no title was assigned to a resource with hidden url.
When displaying feedback messages about a resource in a course, "Refers to" link displayed when viewer has corresponding course role selected includes symb in the link. Link text is now resource title.
"Refers to" link points to unencrypted resource url if feedback message is viewed under role other than original course, only if user has bre privilege for the resource, otherwise "Refers to" link is not displayed.
lonfeedback -- Some replacement of decode_symb() and &clutter() and &dewrapper() with &get_feedurl_and_clean_symb() for replies and edits of discussion posts.
lonfeedback -- More work on in ensuring hidden urls are encrypted or unencrypted as required.
1: # The LearningOnline Network
2: # Feedback
3: #
4: # $Id: lonfeedback.pm,v 1.237 2006/12/24 22:13:19 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; # must not have ()
38: use Apache::lonnet;
39: use Apache::lonhtmlcommon();
40: use Apache::lonnavmaps;
41: use Apache::lonenc();
42: use Apache::lonrss();
43: use HTML::LCParser();
44: use Apache::lonspeller();
45: use Apache::longroup;
46: use Cwd;
47: use LONCAPA;
48:
49: sub discussion_open {
50: my ($status,$symb)=@_;
51: if ($env{'request.role.adv'}) { return 1; }
52: if (defined($status) &&
53: !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
54: || $status eq 'OPEN')) {
55: return 0;
56: }
57: my $close=&Apache::lonnet::EXT('resource.0.discussend',$symb);
58: if (defined($close) && $close ne '' && $close < time) {
59: return 0;
60: }
61: return 1;
62: }
63:
64: sub discussion_visible {
65: my ($status)=@_;
66: if (not &discussion_open($status)) {
67: my $hidden=&Apache::lonnet::EXT('resource.0.discusshide');
68: if (lc($hidden) eq 'yes' or $hidden eq '' or !defined($hidden)) {
69: if (!$env{'request.role.adv'}) { return 0; }
70: }
71: }
72: return 1;
73: }
74:
75: sub list_discussion {
76: my ($mode,$status,$ressymb,$imsextras,$group)=@_;
77: unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); }
78: unless ($ressymb) { return ''; }
79: $ressymb=&wrap_symb($ressymb);
80: my $outputtarget=$env{'form.grade_target'};
81: if (defined($env{'form.export'})) {
82: if($env{'form.export'}) {
83: $outputtarget = 'export';
84: }
85: }
86: if (defined($imsextras)) {
87: if ($$imsextras{'caller'} eq 'imsexport') {
88: $outputtarget = 'export';
89: }
90: }
91: if (not &discussion_visible($status)) {
92: if ($mode ne 'board') {
93: &Apache::lonenc::check_encrypt(\$ressymb);
94: return &send_message_link($ressymb);
95: }
96: }
97: if ($group ne '' && $mode eq 'board') {
98: if (&check_group_priv($group,'vgb') ne 'ok') {
99: return '';
100: }
101: }
102:
103: my ($blocked,$blocktext) =
104: &Apache::loncommon::blocking_status('boards');
105: if ($blocked) {
106: &Apache::lonenc::check_encrypt(\$ressymb);
107: if ($mode ne 'board') {
108: $blocktext.='<br />'.&send_message_link($ressymb);
109: }
110: return $blocktext;
111: }
112:
113: my @bgcols = ("#cccccc","#eeeeee");
114: my $discussiononly=0;
115: if ($mode eq 'board') { $discussiononly=1; }
116: unless ($env{'request.course.id'}) { return ''; }
117: my $crs='/'.$env{'request.course.id'};
118: my $cid=$env{'request.course.id'};
119: if ($env{'request.course.sec'}) {
120: $crs.='_'.$env{'request.course.sec'};
121: }
122: $crs=~s/\_/\//g;
123: my $encsymb=&Apache::lonenc::check_encrypt($ressymb);
124: my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
125: && ($ressymb=~/\.(problem|exam|quiz|assess|survey|form|task)$/));
126:
127: my %usernamesort = ();
128: my %namesort =();
129: my %subjectsort = ();
130:
131: # Get discussion display settings for this discussion
132: my $lastkey = $ressymb.'_lastread';
133: my $showkey = $ressymb.'_showonlyunread';
134: my $markkey = $ressymb.'_showonlyunmark',
135: my $visitkey = $ressymb.'_visit';
136: my $ondispkey = $ressymb.'_markondisp';
137: my $userpickkey = $ressymb.'_userpick';
138: my $toggkey = $ressymb.'_readtoggle';
139: my $readkey = $ressymb.'_read';
140: $ressymb=$encsymb;
141: my %dischash = &Apache::lonnet::get('nohist_'.$cid.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$env{'user.domain'},$env{'user.name'});
142: my %discinfo = ();
143: my $showonlyunread = 0;
144: my $showunmark = 0;
145: my $markondisp = 0;
146: my $prevread = 0;
147: my $previous = 0;
148: my $visit = 0;
149: my $newpostsflag = 0;
150: my @posters = split(/\&/,$dischash{$userpickkey});
151:
152: # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts.
153: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','grouppick','totposters']);
154: my $sortposts = $env{'form.sortposts'};
155: my $statusfilter = $env{'form.statusfilter'};
156: my @sectionpick = split(/,/,$env{'form.sectionpick'});
157: my @grouppick = split(/,/,$env{'form.grouppick'});
158: my @rolefilter = split(/,/,$env{'form.rolefilter'});
159:
160: my $totposters = $env{'form.totposters'};
161: $previous = $env{'form.previous'};
162: if ($previous > 0) {
163: $prevread = $previous;
164: } elsif (defined($dischash{$lastkey})) {
165: unless ($dischash{$lastkey} eq '') {
166: $prevread = $dischash{$lastkey};
167: }
168: }
169:
170: my $cdom = $env{'course.'.$cid.'.domain'};
171: my $cnum = $env{'course.'.$cid.'.num'};
172:
173: # Get information about students and non-students in course for filtering display of posts
174: my %roleshash = ();
175: my %roleinfo = ();
176: my ($classgroups,$studentgroups);
177: if ($env{'form.rolefilter'}) {
178: %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
179: foreach my $rolekey (keys(%roleshash)) {
180: my ($role,$uname,$udom,$sec) = split(/:/,$rolekey);
181: if ($role =~ /^cr/) {
182: $role = 'cr';
183: }
184: my ($end,$start) = split(/:/,$roleshash{$rolekey});
185: my $now = time;
186: my $status = 'Active';
187: if (($now < $start) || ($end > 0 && $now > $end)) {
188: $status = 'Expired';
189: }
190: if ($uname && $udom) {
191: push(@{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status);
192: }
193: }
194: my ($classlist,$keylist) =
195: &Apache::loncoursedata::get_classlist($cdom,$cnum);
196: my $sec_index = &Apache::loncoursedata::CL_SECTION();
197: my $status_index = &Apache::loncoursedata::CL_STATUS();
198: while (my ($student,$data) = each %$classlist) {
199: my ($section,$status) = ($data->[$sec_index],
200: $data->[$status_index]);
201: push(@{$roleinfo{$student}}, 'st:'.$section.':'.$status);
202: }
203: ($classgroups,$studentgroups) =
204: &Apache::loncoursedata::get_group_memberships($classlist,$keylist,
205: $cdom,$cnum);
206: }
207:
208: # Get discussion display default settings for user
209: if ($env{'environment.discdisplay'} eq 'unread') {
210: $showonlyunread = 1;
211: }
212: if ($env{'environment.discmarkread'} eq 'ondisp') {
213: $markondisp = 1;
214: }
215:
216: # Override user's default if user specified display setting for this discussion
217: if (defined($dischash{$ondispkey})) {
218: unless ($dischash{$ondispkey} eq '') {
219: $markondisp = $dischash{$ondispkey};
220: }
221: }
222: if ($markondisp) {
223: $discinfo{$lastkey} = time;
224: }
225:
226: if (defined($dischash{$showkey})) {
227: unless ($dischash{$showkey} eq '') {
228: $showonlyunread = $dischash{$showkey};
229: }
230: }
231:
232: if (defined($dischash{$markkey})) {
233: unless ($dischash{$markkey} eq '') {
234: $showunmark = $dischash{$markkey};
235: }
236: }
237:
238: if (defined($dischash{$visitkey})) {
239: unless ($dischash{$visitkey} eq '') {
240: $visit = $dischash{$visitkey};
241: }
242: }
243: $visit ++;
244:
245: my $seeid;
246: if (($group ne '') && ($mode eq 'board') &&
247: ($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {
248: if (&check_group_priv($group,'dgp') eq 'ok') {
249: $seeid = 1;
250: }
251: } else {
252: $seeid=&Apache::lonnet::allowed('rin',$crs);
253: }
254: my @discussionitems=();
255: my %shown = ();
256: my @posteridentity=();
257:
258: my $current=0;
259: my $visible=0;
260: my @depth=();
261: my @replies = ();
262: my %alldiscussion=();
263: my %imsitems=();
264: my %imsfiles=();
265: my %notshown = ();
266: my %newitem = ();
267: my $maxdepth=0;
268: my %anonhash=();
269: my $anoncnt=0;
270: my $target='';
271: unless ($env{'browser.interface'} eq 'textual' ||
272: $env{'environment.remote'} eq 'off' ) {
273: $target='target="LONcom"';
274: }
275:
276: my $now = time;
277: $discinfo{$visitkey} = $visit;
278:
279: &Apache::lonnet::put('nohist_'.$cid.'_discuss',\%discinfo,$env{'user.domain'},$env{'user.name'});
280: &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);
281:
282: my $discussion='';
283: my $manifestfile;
284: my $manifestok=0;
285: my $tempexport;
286: my $imsresources;
287: my $copyresult;
288:
289: my $function = &Apache::loncommon::get_users_function();
290: my $color = &Apache::loncommon::designparm($function.'.tabbg',
291: $env{'user.domain'});
292: my %lt = &Apache::lonlocal::texthash(
293: 'cuse' => 'Current discussion settings',
294: 'allposts' => 'All posts',
295: 'unread' => 'New posts only',
296: 'unmark' => 'Unread only',
297: 'ondisp' => 'Once displayed',
298: 'onmark' => 'Once marked not NEW',
299: 'toggoff' => 'Off',
300: 'toggon' => 'On',
301: 'disa' => 'Posts to be displayed',
302: 'npce' => 'Posts cease to be marked "NEW"',
303: 'epcb' => 'Each post can be toggled read/unread',
304: 'chgt' => 'Change',
305: 'disp' => 'Display',
306: 'nolo' => 'Not new',
307: 'togg' => 'Toggle read/unread',
308: 'aner' => 'An error occurred opening the manifest file.',
309: 'difo' => 'Discussion for',
310: 'aerr' => 'An error occurred opening the export file for posting',
311: 'aysu' => 'Are you sure you want to delete this post?',
312: 'dpwn' => 'Deleted posts will no longer be visible to you and other students',
313: 'bwco' => 'but will continue to be visible to your instructor',
314: 'depo' => 'Deleted posts will no longer be visible to you or anyone else.',
315: );
316:
317: my $currdisp = $lt{'allposts'};
318: my $currmark = $lt{'onmark'};
319: my $currtogg = $lt{'toggoff'};
320: my $dispchange = $lt{'unread'};
321: my $markchange = $lt{'ondisp'};
322: my $toggchange = $lt{'toggon'};
323: my $chglink = '/adm/feedback?modifydisp='.$ressymb;
324: my $displinkA = 'onlyunread';
325: my $displinkB = 'onlyunmark';
326: my $marklink = 'markondisp';
327: my $togglink = 'toggon';
328:
329: if ($markondisp) {
330: $currmark = $lt{'ondisp'};
331: $markchange = $lt{'onmark'};
332: $marklink = 'markonread';
333: }
334:
335: if ($showonlyunread) {
336: $currdisp = $lt{'unread'};
337: $dispchange = $lt{'allposts'};
338: $displinkA = 'allposts';
339: }
340:
341: if ($showunmark) {
342: $currdisp = $lt{'unmark'};
343: $dispchange = $lt{'unmark'};
344: $displinkA='allposts';
345: $displinkB='onlyunread';
346: $showonlyunread = 0;
347: }
348:
349: if ($dischash{$toggkey}) {
350: $currtogg = $lt{'toggon'};
351: $toggchange = $lt{'toggoff'};
352: $togglink = 'toggoff';
353: }
354:
355: $chglink .= '&changes='.$displinkA.'_'.$displinkB.'_'.$marklink.'_'.$togglink;
356:
357: if ($newpostsflag) {
358: $chglink .= '&previous='.$prevread;
359: }
360: $chglink.=&group_args($group);
361:
362: if ($visible) {
363: # Print the discusssion
364: if ($outputtarget eq 'tex') {
365: $discussion.='<tex>{\tiny \vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.
366: '\textbf{DISCUSSIONS}\makebox[2 cm][b]{\hrulefill}'.
367: '\vskip 0 mm\noindent\textbf{'.$lt{'cuse'}.'}:\vskip 0 mm'.
368: '\noindent\textbf{'.$lt{'disa'}.'}: \textit{'.$currdisp.'}\vskip 0 mm'.
369: '\noindent\textbf{'.$lt{'npce'}.'}: \textit{'.$currmark.'}}</tex>';
370: } elsif ($outputtarget eq 'export') {
371: # Create temporary directory if this is an export
372: my $now = time;
373: if ((defined($imsextras)) && ($$imsextras{'caller'} eq 'imsexport')) {
374: $tempexport = $$imsextras{'tempexport'};
375: if (!-e $tempexport) {
376: mkdir($tempexport,0700);
377: }
378: $tempexport .= '/'.$$imsextras{'count'};
379: if (!-e $tempexport) {
380: mkdir($tempexport,0700);
381: }
382: } else {
383: $tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
384: if (!-e $tempexport) {
385: mkdir($tempexport,0700);
386: }
387: $tempexport .= '/'.$now;
388: if (!-e $tempexport) {
389: mkdir($tempexport,0700);
390: }
391: $tempexport .= '/'.$env{'user.domain'}.'_'.$env{'user.name'};
392: }
393: if (!-e $tempexport) {
394: mkdir($tempexport,0700);
395: }
396: # open manifest file
397: my $manifest = '/imsmanifest.xml';
398: my $manifestfilename = $tempexport.$manifest;
399: if ($manifestfile = Apache::File->new('>'.$manifestfilename)) {
400: $manifestok=1;
401: print $manifestfile qq|
402: <?xml version="1.0" encoding="UTF-8"?>
403: <manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"
404: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
405: identifier="MANIFEST-$ressymb" xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1
406: imscp_v1p1.xsd http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">
407: <organizations default="$ressymb">
408: <organization identifier="$ressymb">
409: <title>$lt{'difo'} $ressymb</title>\n|;
410: } else {
411: $discussion .= $lt{'aner'}.'<br />';
412: }
413: } else {
414: my $colspan=$maxdepth+1;
415: $discussion.= qq|
416: <script>
417: function verifydelete (caller,symb,idx,newflag,previous,groupparm) {
418: var symbparm = symb+':::'+idx
419: var prevparm = ""
420: if (newflag == 1) {
421: prevparm = "&previous="+previous
422: }
423: if (caller == 'studentdelete') {
424: if (confirm("$lt{'aysu'}\\n$lt{'dpwn'},\\n$lt{'bwco'}")) {
425: document.location.href = "/adm/feedback?hide="+symbparm+prevparm+groupparm
426: }
427: } else {
428: if (caller == 'seeiddelete') {
429: if (confirm("$lt{'aysu'}\\n$lt{'depo'}")) {
430: document.location.href = "/adm/feedback?deldisc="+symbparm+prevparm+groupparm
431: }
432: }
433: }
434: }
435: </script>
436: |;
437: $discussion.='<form name="readchoices" method="post" action="/adm/feedback?chgreads='.$ressymb.'" ><table bgcolor="#AAAAAA" cellpadding="2" cellspacing="2" border="0">';
438: $discussion .= &action_links_bar($colspan,$ressymb,$visible,
439: $newpostsflag,$group,
440: $prevread,$markondisp);
441: my $escsymb=&escape($ressymb);
442: my $numhidden = keys(%notshown);
443: if ($numhidden > 0) {
444: my $colspan = $maxdepth+1;
445: $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">'.
446: '<a href="/adm/feedback?allposts=1&symb='.$escsymb;
447: if ($newpostsflag) {
448: $discussion .= '&previous='.$prevread;
449: }
450: $discussion .= &group_args($group);
451: $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.
452: $numhidden.' ';
453: if ($showunmark) {
454: $discussion .= &mt('posts previously marked read');
455: } else {
456: $discussion .= &mt('previously viewed posts');
457: }
458: $discussion .= '<br/></td></tr>';
459: }
460: }
461:
462: # Choose sort mechanism
463: my @showposts = ();
464: if ($sortposts eq 'descdate') {
465: @showposts = (sort { $b <=> $a } keys(%alldiscussion));
466: } elsif ($sortposts eq 'thread') {
467: @showposts = (sort { $a <=> $b } keys(%alldiscussion));
468: } elsif ($sortposts eq 'subject') {
469: foreach my $key (sort(keys(%subjectsort))) {
470: push(@showposts, @{$subjectsort{$key}});
471: }
472: } elsif ($sortposts eq 'username') {
473: foreach my $domain (sort(keys(%usernamesort))) {
474: foreach my $key (sort(keys(%{$usernamesort{$domain}}))) {
475: push(@showposts, @{$usernamesort{$domain}{$key}});
476: }
477: }
478: } elsif ($sortposts eq 'lastfirst') {
479: foreach my $last (sort(keys(%namesort))) {
480: foreach my $key (sort(keys(%{$namesort{$last}}))) {
481: push(@showposts, @{$namesort{$last}{$key}});
482: }
483: }
484: } else {
485: @showposts = (sort { $a <=> $b } keys(%alldiscussion));
486: }
487: my $currdepth = 0;
488: my $firstidx = $alldiscussion{$showposts[0]};
489: foreach my $post (@showposts) {
490: unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) {
491: $alldiscussion{$post} = $post;
492: }
493: unless ( ($notshown{$alldiscussion{$post}} eq '1') || ($shown{$alldiscussion{$post}} == 0) ) {
494: if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
495: $discussion.="\n<tr>";
496: }
497: my $thisdepth=$depth[$alldiscussion{$post}];
498: if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
499: for (1..$thisdepth) {
500: $discussion.='<td> </td>';
501: }
502: }
503: my $colspan=$maxdepth-$thisdepth+1;
504: if ($outputtarget eq 'tex') {
505: #cleanup block
506: $discussionitems[$alldiscussion{$post}]=~s/<table([^>]*)>/<table TeXwidth="90 mm">/;
507: $discussionitems[$alldiscussion{$post}]=~s/<tr([^>]*)><td([^>]*)>/<tr><td TeXwidth="20 mm" align="left">/;
508: my $threadinsert='';
509: if ($thisdepth > 0) {
510: $threadinsert='<br /><strong>Reply: '.$thisdepth.'</strong>';
511: }
512: $discussionitems[$alldiscussion{$post}]=~s/<\/td><td([^>]*)>/$threadinsert<\/td><td TeXwidth="65 mm" align="left">/;
513: $discussionitems[$alldiscussion{$post}]=~s/<a([^>]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g;
514: $discussionitems[$alldiscussion{$post}]=~s/(<b>|<\/b>|<\/a>|<a([^>]+)>)//g;
515:
516: $discussionitems[$alldiscussion{$post}]='<tex>\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}</tex>'.$discussionitems[$alldiscussion{$post}];
517: $discussion.=$discussionitems[$alldiscussion{$post}];
518: } elsif ($outputtarget eq 'export') {
519: my $postfilename = $alldiscussion{$post}.'-'.$imsitems{$alldiscussion{$post}}{'timestamp'}.'.html';
520: if ($manifestok) {
521: if (($depth[$alldiscussion{$post}] <= $currdepth) && ($alldiscussion{$post} != $firstidx)) {
522: print $manifestfile ' </item>'."\n";
523: }
524: $currdepth = $depth[$alldiscussion{$post}];
525: print $manifestfile "\n".
526: '<item identifier="ITEM-'.$ressymb.'-'.$alldiscussion{$post}.'" isvisible="'.
527: $imsitems{$alldiscussion{$post}}{'isvisible'}.'" identifieref="RES-'.$ressymb.'-'.$alldiscussion{$post}.'">'.
528: '<title>'.$imsitems{$alldiscussion{$post}}{'title'}.'</title>';
529: $imsresources .= "\n".
530: '<resource identifier="RES-'.$ressymb.'-'.$alldiscussion{$post}.'" type="webcontent" href="'.$postfilename.'">'."\n".
531: '<file href="'.$postfilename.'">'."\n".
532: $imsfiles{$alldiscussion{$post}}{$imsitems{$alldiscussion{$post}}{'currversion'}}."\n".
533: '</resource>';
534: }
535: my $postingfile;
536: my $postingfilename = $tempexport.'/'.$postfilename;
537: if ($postingfile = Apache::File->new('>'.$postingfilename)) {
538: print $postingfile '<html><head><title>Discussion Post</title></head><body>'.
539: $imsitems{$alldiscussion{$post}}{'title'}.' '.
540: $imsitems{$alldiscussion{$post}}{'sender'}.
541: $imsitems{$alldiscussion{$post}}{'timestamp'}.'<br /><br />'.
542: $imsitems{$alldiscussion{$post}}{'message'}.'<br />'.
543: $imsitems{$alldiscussion{$post}}{'attach'}.'</body></html>'."\n";
544: close($postingfile);
545: } else {
546: $discussion .= $lt{'aerr'}.' '.$alldiscussion{$post}.'<br />';
547: }
548: $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$post}}{'allattachments'},$tempexport);
549: } else {
550: $discussion.='<td bgcolor="'.$bgcols[$newitem{$alldiscussion{$post}}].
551: '" colspan="'.$colspan.'">'. $discussionitems[$alldiscussion{$post}].
552: '</td></tr>';
553: }
554: }
555: }
556: unless ($outputtarget eq 'tex' || $outputtarget eq 'export') {
557: my $colspan=$maxdepth+1;
558: $discussion .= <<END;
559: <tr bgcolor="#FFFFFF">
560: <td colspan="$colspan" valign="top">
561: <table border="0" bgcolor="#FFFFFF" width="100%" cellspacing="2" cellpadding="2">
562: <tr>
563: <td align="left">
564: <table border="0" cellpadding="0" cellspacing="4">
565: <tr>
566: <td>
567: <font size="-1"><b>$lt{'cuse'}</b>:</td>
568: <td> </td>
569: <td><font size="-1">
570: END
571: if ($newpostsflag) {
572: $discussion .=
573: '1. '.$lt{'disp'}.' - <i>'.$currdisp.'</i> 2. '.$lt{'nolo'}.' - <i>'.$currmark.'</i>';
574: if ($dischash{$toggkey}) {
575: $discussion .= ' 3. '.$lt{'togg'}.' - <i>'.$currtogg.'</i>';
576: }
577: } else {
578: if ($dischash{$toggkey}) {
579: $discussion .= '1. '.$lt{'disp'}.' - <i>'.$currdisp.'</i> 2. '.$lt{'togg'}.' - <i>'.$currtogg.'</i>';
580: } else {
581: $discussion .=
582: $lt{'disp'}.' - <i>'.$currdisp.'</i>';
583: }
584: }
585: $discussion .= <<END;
586: </font></td>
587: <td> </td>
588: <td align="left">
589: <font size="-1"><b><a href="$chglink">$lt{'chgt'}</a>?</font></b>
590: </td>
591: </tr>
592: </table>
593: </td>
594: END
595: if ($sortposts) {
596: my %sort_types = ();
597: my %role_types = ();
598: my %status_types = ();
599: &sort_filter_names(\%sort_types,\%role_types,\%status_types);
600:
601: $discussion .= '<td><font size="-1"><b>'.&mt('Sorted by').'</b>: '.$sort_types{$sortposts}.'<br />';
602: if (defined($env{'form.totposters'})) {
603: $discussion .= &mt('Posts by').':';
604: if ($totposters > 0) {
605: foreach my $poster (@posters) {
606: $discussion .= ' '.$poster.',';
607: }
608: $discussion =~ s/,$//;
609: } else {
610: $discussion .= &mt('None selected');
611: }
612: } else {
613: my $filterchoice ='';
614: if (@sectionpick > 0) {
615: $filterchoice = '<i>'.&mt('sections').'</i>- '.$env{'form.sectionpick'};
616: $filterchoice .= ' ';
617: }
618: if (@grouppick > 0) {
619: $filterchoice = '<i>'.&mt('groups').'</i>- '.$env{'form.grouppick'};
620: $filterchoice .= ' ';
621: }
622: if (@rolefilter > 0) {
623: $filterchoice .= '<i>'.&mt('roles').'</i>-';
624: foreach my $role (@rolefilter) {
625: $filterchoice .= ' '.$role_types{$role}.',';
626: }
627: $filterchoice =~ s/,$//;
628: $filterchoice .= '<br />     ';
629: }
630: if ($statusfilter) {
631: $filterchoice .= '<i>'.&mt('status').'</i>- '.$status_types{$statusfilter};
632: }
633: if ($filterchoice) {
634: $discussion .= '<b>'.&mt('Filters').'</b>: '.$filterchoice;
635: }
636: $discussion .= '</font></td>';
637: }
638: }
639: if ($dischash{$toggkey}) {
640: my $storebutton = &mt('Store read/unread changes');
641: $discussion.='<td align="right">'.
642: '<input type="hidden" name="discsymb" value="'.$ressymb.'">'."\n".
643: '<input type="button" name="readoptions" value="'.$storebutton.'"'.
644: ' onClick="this.form.submit();">'."\n".
645: '</td>';
646: }
647: $discussion .= (<<END);
648: </tr>
649: </table>
650: </td>
651: </tr>
652: END
653: $discussion .= &action_links_bar($colspan,$ressymb,$visible,
654: $newpostsflag,$group,
655: $prevread,$markondisp);
656: $discussion .= "
657: </table>
658: <br /><br /></form>\n";
659: }
660: if ($outputtarget eq 'export') {
661: if ($manifestok) {
662: while ($currdepth > 0) {
663: print $manifestfile " </item>\n";
664: $currdepth --;
665: }
666: print $manifestfile qq|
667: </organization>
668: </organizations>
669: <resources>
670: $imsresources
671: </resources>
672: </manifest>
673: |;
674: close($manifestfile);
675: if ((defined($imsextras)) && ($$imsextras{'caller'} eq 'imsexport')) {
676: $discussion = $copyresult;
677: } else {
678:
679: #Create zip file in prtspool
680:
681: my $imszipfile = '/prtspool/'.
682: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
683: time.'_'.rand(1000000000).'.zip';
684: my $cwd = &getcwd();
685: my $imszip = '/home/httpd/'.$imszipfile;
686: chdir $tempexport;
687: open(OUTPUT, "zip -r $imszip * 2> /dev/null |");
688: close(OUTPUT);
689: chdir $cwd;
690: $discussion .= &mt('Download the zip file from [_1]Discussion Posting Archive','<a href="'.$imszipfile.'">').'</a><br />';
691: if ($copyresult) {
692: $discussion .= &mt('The following errors occurred during export').' - <br />'.$copyresult;
693: }
694: }
695: } else {
696: $discussion .= '<br />'.&mt('Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating a manifest file.').'<br />';
697: }
698: return $discussion;
699: }
700: }
701: if ($discussiononly) {
702: my $now = time;
703: my $attachnum = 0;
704: my $currnewattach = [];
705: my $currdelold = [];
706: my $comment = '';
707: my $subject = '';
708: if ($env{'form.origpage'}) {
709: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['addnewattach','deloldattach','delnewattach','timestamp','idx','subject','comment']);
710: $subject = &unescape($env{'form.subject'});
711: $comment = &unescape($env{'form.comment'});
712: my @keepold = ();
713: &process_attachments($currnewattach,$currdelold,\@keepold);
714: if (@{$currnewattach} > 0) {
715: $attachnum += @{$currnewattach};
716: }
717: }
718: if (&discussion_open($status)) {
719: if (($group ne '') && ($mode eq 'board')) {
720: if (&check_group_priv($group,'pgd') eq 'ok') {
721: $discussion .=
722: &postingform_display($mode,$ressymb,$now,$subject,
723: $comment,$outputtarget,$attachnum,
724: $currnewattach,$currdelold,
725: $group);
726: }
727: } else {
728: $discussion.=
729: &postingform_display($mode,$ressymb,$now,$subject,
730: $comment,$outputtarget,$attachnum,
731: $currnewattach,$currdelold);
732: }
733: }
734: } else {
735: $discussion.='<table class="LC_feedback_link"><tr><td>';
736: if (&discussion_open($status) &&
737: &Apache::lonnet::allowed('pch',
738: $env{'request.course.id'}.
739: ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
740: if ($outputtarget ne 'tex') {
741: $discussion.= &send_feedback_link($ressymb,$target).
742: '<br />';
743: }
744: }
745: if ($outputtarget ne 'tex') {
746: $discussion.= &send_message_link($ressymb);
747: }
748: $discussion.='</td></tr></table>';
749: }
750: return $discussion;
751: }
752:
753: sub send_feedback_link {
754: my ($ressymb,$target) = @_;
755: my $output = '<span class="LC_feedback_link">'.
756: ' <a href="/adm/feedback?replydisc='.
757: &escape($ressymb).':::" '.$target.'>'.
758: '<img alt="" src="'.
759: &Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').
760: '" border="0" />'.&mt('Post Discussion').'</a></span>';
761: return $output;
762: }
763:
764: sub send_message_link {
765: my ($ressymb) = @_;
766: my $output = '<span class="LC_feedback_link">'.
767: ' <a href="/adm/feedback?sendmessageonly=1&symb='.
768: &escape($ressymb).'"><img alt="" src="'.
769: &Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').
770: '" border="0" />'.&mt('Send Message').'</a></span>';
771: return $output;
772: }
773:
774: sub action_links_bar {
775: my ($colspan,$ressymb,$visible,$newpostsflag,$group,$prevread,$markondisp) = @_;
776: my $discussion = '<tr><td bgcolor="#DDDDBB" colspan="'.$colspan.'">'.
777: '<table border="0" width="100%" bgcolor="#DDDDBB"><tr>';
778: my $escsymb=&escape($ressymb);
779: if ($visible>2) {
780: $discussion .= '<td align="left">'.
781: '<a href="/adm/feedback?cmd=threadedon&symb='.$escsymb;
782: if ($newpostsflag) {
783: $discussion .= '&previous='.$prevread;
784: }
785: $discussion .= &group_args($group);
786: $discussion .='">'.&mt('Threaded View').'</a> '.
787: '<a href="/adm/feedback?cmd=threadedoff&symb='.$escsymb;
788: if ($newpostsflag) {
789: $discussion .= '&previous='.$prevread;
790: }
791: $discussion .= &group_args($group);
792: $discussion .='">'.&mt('Chronological View').'</a>
793: <a href= "/adm/feedback?cmd=sortfilter&symb='.$escsymb;
794: if ($newpostsflag) {
795: $discussion .= '&previous='.$prevread;
796: }
797: $discussion .= &group_args($group);
798: $discussion .='">'.&mt('Sorting/Filtering options').'</a>  ';
799: } else {
800: $discussion .= '<td align="left">';
801: }
802: $discussion .='<a href= "/adm/feedback?export='.$escsymb;
803: if ($newpostsflag) {
804: $discussion .= '&previous='.$prevread;
805: }
806: $discussion .= &group_args($group);
807: $discussion .= '">'.&mt('Export').'?</a> </td>';
808: if ($newpostsflag) {
809: if (!$markondisp) {
810: $discussion .='<td align="right"><a href="/adm/preferences?action=changediscussions';
811: $discussion .= &group_args($group);
812: $discussion .= '">'.
813: &mt('Preferences on what is marked as NEW').
814: '</a><br /><a href="/adm/feedback?markread=1&symb='.$escsymb;
815: $discussion .= &group_args($group);
816: $discussion .= '">'.&mt('Mark NEW posts no longer new').'</a>';
817: } else {
818: $discussion .= '<td> </td>';
819: }
820: } else {
821: $discussion .= '<td> </td>';
822: }
823: $discussion .= '</tr></table></td></tr>';
824: return $discussion;
825: }
826:
827: sub postingform_display {
828: my ($mode,$ressymb,$now,$subject,$comment,$outputtarget,$attachnum,
829: $currnewattach,$currdelold,$group) = @_;
830: my $newattachmsg;
831: my %lt = &Apache::lonlocal::texthash(
832: 'note' => 'Note: in anonymous discussion, your name is visible only to course faculty',
833: 'title' => 'Title',
834: 'podi' => 'Post Discussion',
835: 'poan' => 'Post Anonymous Discussion',
836: 'newa' => 'New attachments',
837: );
838: my $postingform = (<<ENDDISCUSS);
839: <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data"> <input type="submit" name="discuss" value="$lt{'podi'}" />
840: <input type="submit" name="anondiscuss" value="$lt{'poan'}" /> <input type="hidden" name="symb" value="$ressymb" />
841: <input type="hidden" name="sendit" value="true" />
842: <input type="hidden" name="timestamp" value="$now" />
843: <br /><a name="newpost"></a>
844: <font size="1">$lt{'note'}</font><br />
845: <b>$lt{'title'}:</b> <input type="text" name="subject" value="$subject" size="30" /><br /><br />
846: <textarea name="comment" cols="80" rows="14" wrap="hard">$comment</textarea>
847: ENDDISCUSS
848: if ($env{'form.origpage'}) {
849: $postingform .= '<input type="hidden" name="origpage" value="'.
850: $env{'form.origpage'}.'" />'."\n";
851: foreach my $att (@{$currnewattach}) {
852: $postingform .= '<input type="hidden" name="currnewattach" '.
853: 'value="'.$att.'" />'."\n";
854: }
855: }
856: if (exists($env{'form.ref'})) {
857: $postingform .= '<input type="hidden" name="ref" value="'.
858: $env{'form.ref'}.'" />';
859: }
860: if ($group ne '') {
861: $postingform .='<input type="hidden" name="group" value="'.$group.'" />';
862: }
863: my $blockblog = &Apache::loncommon::blocking_status('blogs');
864: if (!$blockblog) {
865: $postingform .= &add_blog_checkbox();
866: }
867: $postingform .= "</form>\n";
868: if ($outputtarget ne 'tex') {
869: $postingform .= &generate_attachments_button('',$attachnum,$ressymb,
870: $now,$currnewattach,
871: $currdelold,'',$mode,
872: $blockblog);
873: if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
874: $newattachmsg = '<br /><b>'.$lt{'newa'}.'</b><br />';
875: if (@{$currnewattach} > 1) {
876: $newattachmsg .= '<ol>';
877: foreach my $item (@{$currnewattach}) {
878: $item =~ m#.*/([^/]+)$#;
879: $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
880: }
881: $newattachmsg .= '</ol>'."\n";
882: } else {
883: $$currnewattach[0] =~ m#.*/([^/]+)$#;
884: $newattachmsg .= '<a href="'.$$currnewattach[0].'">'.$1.'</a><br />'."\n";
885: }
886: }
887: $postingform .= $newattachmsg;
888: $postingform .= &generate_preview_button();
889: }
890: return $postingform;
891: }
892:
893: sub build_posting_display {
894: my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
895: my @original=();
896: my @index=();
897: my $skip_group_check = 0;
898: my $symb=&Apache::lonenc::check_decrypt($ressymb);
899: my $escsymb=&escape($ressymb);
900: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
901: $env{'course.'.$env{'request.course.id'}.'.domain'},
902: $env{'course.'.$env{'request.course.id'}.'.num'});
903:
904: if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {
905: $skip_group_check = 1;
906: }
907: if ($contrib{'version'}) {
908: my $oldest = $contrib{'1:timestamp'};
909: if ($prevread eq '0') {
910: $prevread = $oldest-1;
911: }
912: my ($skiptest,$rolematch,$roleregexp,$secregexp,$statusregexp);
913: if ($sortposts) {
914: ($skiptest,$roleregexp,$secregexp,$statusregexp) =
915: &filter_regexp($rolefilter,$sectionpick,$statusfilter);
916: $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
917: }
918: for (my $id=1;$id<=$contrib{'version'};$id++) {
919: my $idx=$id;
920: my $posttime = $contrib{$idx.':timestamp'};
921: if ($prevread <= $posttime) {
922: $$newpostsflag = 1;
923: }
924: my $hidden=($contrib{'hidden'}=~/\.$idx\./);
925: my $studenthidden=($contrib{'studenthidden'}=~/\.$idx\./);
926: my $deleted=($contrib{'deleted'}=~/\.$idx\./);
927: my $origindex='0.';
928: my $numoldver=0;
929: if ($contrib{$idx.':replyto'}) {
930: if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
931: # this is a follow-up message
932: $original[$idx]=$original[$contrib{$idx.':replyto'}];
933: $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1;
934: $origindex=$index[$contrib{$idx.':replyto'}];
935: if ($$depth[$idx]>$$maxdepth) { $$maxdepth=$$depth[$idx]; }
936: } else {
937: $original[$idx]=0;
938: $$depth[$idx]=0;
939: }
940: } else {
941: # this is an original message
942: $original[$idx]=0;
943: $$depth[$idx]=0;
944: }
945: if ($$replies[$$depth[$idx]]) {
946: $$replies[$$depth[$idx]]++;
947: } else {
948: $$replies[$$depth[$idx]]=1;
949: }
950: unless ((($hidden) && (!$seeid)) || ($deleted)) {
951: $$visible++;
952: if ($contrib{$idx.':history'}) {
953: if ($contrib{$idx.':history'} =~ /:/) {
954: my @oldversions = split(/:/,$contrib{$idx.':history'});
955: $numoldver = @oldversions;
956: } else {
957: $numoldver = 1;
958: }
959: }
960: $$current = $numoldver;
961: my %messages = ();
962: my %subjects = ();
963: my %attachtxt = ();
964: my %allattachments = ();
965: my ($screenname,$plainname);
966: my $sender = &mt('Anonymous');
967: # Anonymous users getting number within a discussion
968: # Since idx is in static order, this should give the same sequence every time.
969: my $key=$contrib{$idx.':sendername'}.'@'.$contrib{$idx.':senderdomain'};
970: unless ($$anonhash{$key}) {
971: $anoncnt++;
972: $$anonhash{$key}=&mt('Anonymous').' '.$anoncnt;
973: }
974: my ($message,$subject,$vgrlink,$ctlink);
975: &get_post_contents(\%contrib,$idx,$seeid,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,$numoldver);
976:
977:
978: # Set up for sorting by subject
979: unless ($outputtarget eq 'export') {
980: $message=$messages{$numoldver};
981: $message.=$attachtxt{$numoldver};
982: $subject=$subjects{$numoldver};
983: if ($message) {
984: if ($hidden) {
985: $message='<font color="#888888">'.$message.'</font>';
986: if ($studenthidden) {
987: $message .='<br /><br />Deleted by poster (student).';
988: }
989: }
990:
991: if ($subject eq '') {
992: if (defined($$subjectsort{'__No subject'})) {
993: push(@{$$subjectsort{'__No subject'}}, $idx);
994: } else {
995: @{$$subjectsort{'__No subject'}} = ("$idx");
996: }
997: } else {
998: if (defined($$subjectsort{$subject})) {
999: push(@{$$subjectsort{$subject}}, $idx);
1000: } else {
1001: @{$$subjectsort{$subject}} = ("$idx");
1002: }
1003: }
1004: if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
1005: $sender=&Apache::loncommon::aboutmewrapper(
1006: $plainname,
1007: $contrib{$idx.':sendername'},
1008: $contrib{$idx.':senderdomain'}).' ('.
1009: $contrib{$idx.':sendername'}.' at '.
1010: $contrib{$idx.':senderdomain'}.')';
1011: if ($contrib{$idx.':anonymous'}) {
1012: $sender.=' <font color="red"><b>['.$$anonhash{$key}.']</b></font> '.
1013: $screenname;
1014: }
1015:
1016: # Set up for sorting by domain, then username
1017: unless (defined($$usernamesort{$contrib{$idx.':senderdomain'}})) {
1018: %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = ();
1019: }
1020: if (defined($$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) {
1021: push(@{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx);
1022: } else {
1023: @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx");
1024: }
1025: # Set up for sorting by last name, then first name
1026: my %names = &Apache::lonnet::get('environment',
1027: ['firstname','lastname'],$contrib{$idx.':senderdomain'},
1028: ,$contrib{$idx.':sendername'});
1029: my $lastname = $names{'lastname'};
1030: my $firstname = $names{'firstname'};
1031: if ($lastname eq '') {
1032: $lastname = '_';
1033: }
1034: if ($firstname eq '') {
1035: $firstname = '_';
1036: }
1037: unless (defined($$namesort{$lastname})) {
1038: %{$$namesort{$lastname}} = ();
1039: }
1040: if (defined($$namesort{$lastname}{$firstname})) {
1041: push(@{$$namesort{$lastname}{$firstname}}, $idx);
1042: } else {
1043: @{$$namesort{$lastname}{$firstname}} = ("$idx");
1044: }
1045: if (&editing_allowed($escsymb.':::'.$idx,$group)) {
1046: if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
1047: $sender.=' <a href="/adm/feedback?editdisc='.
1048: $escsymb.':::'.$idx;
1049: if ($$newpostsflag) {
1050: $sender .= '&previous='.$prevread;
1051: }
1052: $sender .= &group_args($group);
1053: $sender .= '" '.$target.'>'.&mt('Edit').'</a>';
1054:
1055: unless ($seeid) {
1056: my $grpargs = &group_args($group);
1057: $sender.=" <a href=\"javascript:verifydelete('studentdelete','$escsymb','$idx','$$newpostsflag','$prevread','$grpargs')";
1058: $sender .= '">'.&mt('Delete').'</a>';
1059: }
1060: }
1061: }
1062: if ($seeid) {
1063: if ($hidden) {
1064: unless ($studenthidden) {
1065: $sender.=' <a href="/adm/feedback?unhide='.
1066: $escsymb.':::'.$idx;
1067: if ($$newpostsflag) {
1068: $sender .= '&previous='.$prevread;
1069: }
1070: $sender .= '">'.&mt('Make Visible').'</a>';
1071: }
1072: } else {
1073: $sender.=' <a href="/adm/feedback?hide='.
1074: $escsymb.':::'.$idx;
1075: if ($$newpostsflag) {
1076: $sender .= '&previous='.$prevread;
1077: }
1078: $sender .= &group_args($group);
1079: $sender .= '">'.&mt('Hide').'</a>';
1080: }
1081: my $grpargs = &group_args($group);
1082: $sender.=
1083: " <a href=\"javascript:verifydelete('seeiddelete','$escsymb','$idx','$$newpostsflag','$prevread','$grpargs')\">";
1084: $sender .= &mt('Delete').'</a>';
1085: }
1086: } else {
1087: if ($screenname) {
1088: $sender='<i>'.$screenname.'</i>';
1089: } else {
1090: $sender='<i>'.$$anonhash{$key}.'</i>';
1091: }
1092: # Set up for sorting by domain, then username for anonymous
1093: unless (defined($$usernamesort{'__anon'})) {
1094: %{$$usernamesort{'__anon'}} = ();
1095: }
1096: if (defined($$usernamesort{'__anon'}{'__anon'})) {
1097: push(@{$$usernamesort{'__anon'}{'__anon'}}, $idx);
1098: } else {
1099: @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx");
1100: }
1101: # Set up for sorting by last name, then first name for anonymous
1102: unless (defined($$namesort{'__anon'})) {
1103: %{$$namesort{'__anon'}} = ();
1104: }
1105: if (defined($$namesort{'__anon'}{'__anon'})) {
1106: push(@{$$namesort{'__anon'}{'__anon'}}, $idx);
1107: } else {
1108: @{$$namesort{'__anon'}{'__anon'}} = ("$idx");
1109: }
1110: }
1111: if (&discussion_open($status)) {
1112: if (($group ne '') &&
1113: (&check_group_priv($group,'pgd') eq 'ok')) {
1114: $sender.=' <a href="/adm/feedback?replydisc='.
1115: $escsymb.':::'.$idx;
1116: if ($$newpostsflag) {
1117: $sender .= '&previous='.$prevread;
1118: }
1119: $sender .= &group_args($group);
1120: $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
1121: } elsif (&Apache::lonnet::allowed('pch',
1122: $env{'request.course.id'}.
1123: ($env{'request.course.sec'}?'/'.
1124: $env{'request.course.sec'}:''))) {
1125: $sender.=' <a href="/adm/feedback?replydisc='.
1126: $escsymb.':::'.$idx;
1127: if ($$newpostsflag) {
1128: $sender .= '&previous='.$prevread;
1129: }
1130: $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
1131: }
1132: }
1133: if ($viewgrades) {
1134: $vgrlink=&Apache::loncommon::submlink('Submissions',
1135: $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb);
1136: }
1137: if ($$dischash{$readkey}=~/\.$idx\./) {
1138: $ctlink = '<label><b>'.&mt('Mark unread').'?</b> <input type="checkbox" name="postunread_'.$idx.'" /></label>';
1139: } else {
1140: $ctlink = '<label><b>'.&mt('Mark read').'?</b> <input type="checkbox" name="postread_'.$idx.'" /></label>';
1141: }
1142: }
1143: #figure out at what position this needs to print
1144: }
1145: if ($outputtarget eq 'export' || $message) {
1146: my $thisindex=$idx;
1147: if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
1148: $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2);
1149: }
1150: $$alldiscussion{$thisindex}=$idx;
1151: $$shown{$idx} = 0;
1152: $index[$idx]=$thisindex;
1153: }
1154: if ($outputtarget eq 'export') {
1155: %{$$imsitems{$idx}} = ();
1156: $$imsitems{$idx}{'isvisible'}='true';
1157: if ($hidden) {
1158: $$imsitems{$idx}{'isvisible'}='false';
1159: }
1160: $$imsitems{$idx}{'title'}=$subjects{$numoldver};
1161: $$imsitems{$idx}{'message'}=$messages{$numoldver};
1162: $$imsitems{$idx}{'attach'}=$attachtxt{$numoldver};
1163: $$imsitems{$idx}{'timestamp'}=$contrib{$idx.':timestamp'};
1164: $$imsitems{$idx}{'sender'}=$plainname.' ('.
1165: $contrib{$idx.':sendername'}.' at '.
1166: $contrib{$idx.':senderdomain'}.')';
1167: $$imsitems{$idx}{'isanonymous'}='false';
1168: if ($contrib{$idx.':anonymous'}) {
1169: $$imsitems{$idx}{'isanonymous'}='true';
1170: }
1171: $$imsitems{$idx}{'currversion'}=$numoldver;
1172: %{$$imsitems{$idx}{'allattachments'}}=%allattachments;
1173: unless ($messages{$numoldver} eq '' && $attachtxt{$numoldver} eq '') {
1174: $$shown{$idx} = 1;
1175: }
1176: } else {
1177: if ($message) {
1178: my $spansize = 2;
1179: if ($showonlyunread && $prevread > $posttime) {
1180: $$notshown{$idx} = 1;
1181: } elsif ($showunmark && $$dischash{$readkey}=~/\.$idx\./) {
1182: $$notshown{$idx} = 1;
1183: } else {
1184: # apply filters
1185: my $uname = $contrib{$idx.':sendername'};
1186: my $udom = $contrib{$idx.':senderdomain'};
1187: my $poster = $uname.':'.$udom;
1188: if ($env{'form.totposters'} ne '') {
1189: if ($totposters == 0) {
1190: $$shown{$idx} = 0;
1191: } elsif ($totposters > 0) {
1192: if (grep/^$poster$/,@{$posters}) {
1193: $$shown{$idx} = 1;
1194: }
1195: }
1196: } elsif ($sortposts) {
1197: if ($skiptest) {
1198: $$shown{$idx} = 1;
1199: } else {
1200: foreach my $role (@{$$roleinfo{$poster}}) {
1201: if ($role =~ /^cc:/) {
1202: my $cc_regexp = $roleregexp.':[^:]*:'.$statusregexp;
1203: if ($role =~ /$cc_regexp/) {
1204: $$shown{$idx} = 1;
1205: last;
1206: }
1207: } elsif ($role =~ /^$rolematch$/) {
1208: $$shown{$idx} = 1;
1209: last;
1210: }
1211: }
1212: }
1213: if ($$shown{$idx} && !$skip_group_check) {
1214: my $showflag = 0;
1215: if (ref($$classgroups{$poster}{active}) eq 'HASH') {
1216: foreach my $grp (@{$grouppick}) {
1217: if (grep/^\Q$grp\E$/,
1218: keys(%{$$classgroups{$poster}{active}})) {
1219: $showflag = 1;
1220: last;
1221: }
1222: }
1223: }
1224: if ($showflag) {
1225: $$shown{$idx} = 1;
1226: } else {
1227: $$shown{$idx} = 0;
1228: }
1229: }
1230: } else {
1231: $$shown{$idx} = 1;
1232: }
1233: }
1234: unless ($$notshown{$idx} == 1) {
1235: if ($prevread > 0 && $prevread <= $posttime) {
1236: $$newitem{$idx} = 1;
1237: $$discussionitems[$idx] .= '
1238: <p><table border="0" width="100%">
1239: <tr><td align="left"><font color="#FF0000"><b>NEW</b></font></td>';
1240: } else {
1241: $$newitem{$idx} = 0;
1242: $$discussionitems[$idx] .= '
1243: <p><table border="0" width="100%">
1244: <tr><td align="left"> </td>';
1245: }
1246: $$discussionitems[$idx] .= '<td align ="left"> '.
1247: '<b>'.$subject.'</b> '.
1248: $sender.'</b> '.$vgrlink.' ('.
1249: &Apache::lonlocal::locallocaltime($posttime).')</td>';
1250: if ($$dischash{$toggkey}) {
1251: $$discussionitems[$idx].='<td align="right"> '.
1252: $ctlink.'</td>';
1253: }
1254: $$discussionitems[$idx].= '</tr></table><blockquote>'.
1255: $message.'</blockquote></p>';
1256: if ($contrib{$idx.':history'}) {
1257: my @postversions = ();
1258: $$discussionitems[$idx] .= &mt('This post has been edited by the author.');
1259: if ($seeid) {
1260: $$discussionitems[$idx] .= ' <a href="/adm/feedback?allversions='.$escsymb.':::'.$idx;
1261: $$discussionitems[$idx] .= &group_args($group);
1262: $$discussionitems[$idx] .= '">'.&mt('Display all versions').'</a>';
1263: }
1264: $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
1265: if ($contrib{$idx.':history'} =~ m/:/) {
1266: @postversions = split(/:/,$contrib{$idx.':history'});
1267: } else {
1268: @postversions = ("$contrib{$idx.':history'}");
1269: }
1270: for (my $i=0; $i<@postversions; $i++) {
1271: my $version = $i+1;
1272: $$discussionitems[$idx] .= '<b>'.$version.'.</b> - '.&Apache::lonlocal::locallocaltime($postversions[$i]).' ';
1273: }
1274: }
1275: }
1276: }
1277: }
1278: }
1279: }
1280: }
1281: }
1282:
1283: sub filter_regexp {
1284: my ($rolefilter,$sectionpick,$statusfilter) = @_;
1285: my ($roleregexp,$secregexp,$statusregexp);
1286: my $skiptest = 1;
1287: if (@{$rolefilter} > 0) {
1288: my @okrolefilter = ();
1289: foreach my $role (@{$rolefilter}) {
1290: unless ($role eq '') {
1291: push(@okrolefilter, $role);
1292: }
1293: }
1294: if (@okrolefilter > 0) {
1295: if (grep/^all$/,@okrolefilter) {
1296: $roleregexp='[^:]+';
1297: } else {
1298: if (@okrolefilter == 1) {
1299: $roleregexp=$okrolefilter[0];
1300: } else {
1301: $roleregexp='('.join('|',@okrolefilter).')';
1302: }
1303: $skiptest = 0;
1304: }
1305: }
1306: }
1307: if (@{$sectionpick} > 0) {
1308: my @oksectionpick = ();
1309: foreach my $sec (@{$sectionpick}) {
1310: unless ($sec eq '') {
1311: push(@oksectionpick, $sec);
1312: }
1313: }
1314: if ((@oksectionpick > 0) && (!grep/^all$/,@oksectionpick)) {
1315: if (@oksectionpick == 1) {
1316: $secregexp = $oksectionpick[0];
1317: } else {
1318: $secregexp .= '('.join('|',@oksectionpick).')';
1319: }
1320: $skiptest = 0;
1321: } else {
1322: $secregexp .= '[^:]*';
1323: }
1324: }
1325:
1326: if (defined($statusfilter) && $statusfilter ne '') {
1327: if ($statusfilter eq 'all') {
1328: $statusregexp = '[^:]+';
1329: } else {
1330: $statusregexp = $statusfilter;
1331: $skiptest = 0;
1332: }
1333: }
1334: return ($skiptest,$roleregexp,$secregexp,$statusregexp);
1335: }
1336:
1337:
1338: sub get_post_contents {
1339: my ($contrib,$idx,$seeid,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$numver) = @_;
1340: my $discussion = '';
1341: my $start=$numver;
1342: my $end=$numver + 1;
1343: %{$$imsfiles{$idx}}=();
1344: if ($type eq 'allversions') {
1345: unless($seeid) {
1346: $discussion=&mt('You do not have privileges to view all versions of posts.').' '.&mt('Please select a different role.');
1347: return $discussion;
1348: }
1349: }
1350: # $$screenname=&Apache::loncommon::screenname(
1351: # $$contrib{$idx.':sendername'},
1352: # $$contrib{$idx.':senderdomain'});
1353: $$plainname=&Apache::loncommon::nickname(
1354: $$contrib{$idx.':sendername'},
1355: $$contrib{$idx.':senderdomain'});
1356: $$screenname=$$contrib{$idx.':screenname'};
1357:
1358: my $sender=&Apache::loncommon::aboutmewrapper(
1359: $$plainname,
1360: $$contrib{$idx.':sendername'},
1361: $$contrib{$idx.':senderdomain'}).' ('.
1362: $$contrib{$idx.':sendername'}.' at '.
1363: $$contrib{$idx.':senderdomain'}.')';
1364: my $attachmenturls = $$contrib{$idx.':attachmenturl'};
1365: my @postversions = ();
1366: if ($type eq 'allversions' || $type eq 'export') {
1367: $start = 0;
1368: if ($$contrib{$idx.':history'}) {
1369: @postversions = split(/:/,$$contrib{$idx.':history'});
1370: }
1371: &get_post_versions($messages,$$contrib{$idx.':message'},1);
1372: &get_post_versions($subjects,$$contrib{$idx.':subject'},1);
1373: push(@postversions,$$contrib{$idx.':timestamp'});
1374: $end = @postversions;
1375: } else {
1376: &get_post_versions($messages,$$contrib{$idx.':message'},1,$numver);
1377: &get_post_versions($subjects,$$contrib{$idx.':subject'},1,$numver);
1378: }
1379:
1380: if ($$contrib{$idx.':anonymous'}) {
1381: $sender.=' ['.&mt('anonymous').'] '.$$screenname;
1382: }
1383: if ($type eq 'allversions') {
1384: $discussion=('<b>'.$sender.'</b><br /><ul>');
1385: }
1386: for (my $i=$start; $i<$end; $i++) {
1387: my ($timesent,$attachmsg);
1388: my %currattach = ();
1389: $timesent = &Apache::lonlocal::locallocaltime($postversions[$i]);
1390: &newline_to_br(\$messages->{$i});
1391: $$messages{$i}=&Apache::lontexconvert::msgtexconverted($$messages{$i});
1392: $$subjects{$i}=~s/\n/\<br \/\>/g;
1393: $$subjects{$i}=&Apache::lontexconvert::msgtexconverted($$subjects{$i});
1394: if ($attachmenturls) {
1395: &extract_attachments($attachmenturls,$idx,$i,\$attachmsg,$allattachments,\%currattach);
1396: }
1397: if ($type eq 'export') {
1398: $$imsfiles{$idx}{$i} = '';
1399: if ($attachmsg) {
1400: $$attachtxt{$i} = '<br />'.&mt('Attachments').':<br />';
1401: foreach my $key (sort(keys(%currattach))) {
1402: if ($$allattachments{$key}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {
1403: my $fname = $1.$3.'/'.$4;
1404: $$imsfiles{$idx}{$i} .= '<file href="'.$fname.'">'."\n";
1405: $$attachtxt{$i}.= '<a href="'.$fname.'">'.$4.'</a><br />';
1406: }
1407: }
1408: }
1409: } else {
1410: if ($attachmsg) {
1411: $$attachtxt{$i} = '<br />'.&mt('Attachments').':'.$attachmsg.'<br />';
1412: } else {
1413: $$attachtxt{$i} = '';
1414: }
1415: }
1416: if ($type eq 'allversions') {
1417: $discussion.= <<"END";
1418: <li><b>$$subjects{$i}</b>, $timesent<br />
1419: $$messages{$i}<br />
1420: $$attachtxt{$i}</li>
1421: END
1422: }
1423: }
1424: if ($type eq 'allversions') {
1425: $discussion.='</ul>';
1426: return $discussion;
1427: } else {
1428: return;
1429: }
1430: }
1431:
1432: sub replicate_attachments {
1433: my ($attachrefs,$tempexport) = @_;
1434: my $response;
1435: foreach my $id (keys(%{$attachrefs})) {
1436: if ($$attachrefs{$id}{'filename'} =~ m-^/uploaded/([^/]+)/([^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {
1437: my $path = $tempexport;
1438: my $tail = $1.'/'.$2.$4;
1439: my @extras = split(/\//,$tail);
1440: my $destination = $tempexport.'/'.$1.'/'.$2.$4.'/'.$5;
1441: if (!-e $destination) {
1442: my $i= 0;
1443: while ($i<@extras) {
1444: $path .= '/'.$extras[$i];
1445: if (!-e $path) {
1446: mkdir($path,0700);
1447: }
1448: $i ++;
1449: }
1450: my ($content,$rtncode);
1451: my $uploadreply = &Apache::lonnet::getuploaded('GET',$$attachrefs{$id}{'filename'},$1,$2,$content,$rtncode);
1452: if ($uploadreply eq 'ok') {
1453: my $attachcopy;
1454: if ($attachcopy = Apache::File->new('>'.$destination)) {
1455: print $attachcopy $content;
1456: close($attachcopy);
1457: } else {
1458: $response .= &mt('Error copying file attachment - [_1] to IMS package',$5).': '.$!.'<br />'."\n";
1459: }
1460: } else {
1461: &Apache::lonnet::logthis("Replication of attachment failed when building IMS export of discussion posts - domain: $1, course: $2, file: $$attachrefs{$id}{'filename'} -error: $rtncode");
1462: $response .= &mt('Error copying file attachment - [_1] to IMS package: ',$5).$rtncode.'<br />'."\n";
1463: }
1464: }
1465: }
1466: }
1467: return $response;
1468: }
1469:
1470: sub mail_screen {
1471: my ($r,$feedurl,$options,$symb) = @_;
1472: if (exists($env{'form.origpage'})) {
1473: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog','group','ref']);
1474: }
1475:
1476: my %lt = &Apache::lonlocal::texthash(
1477: 'plch' => 'Please check at least one of the following feedback types:',
1478: 'myqu' => 'My question/comment/feedback:',
1479: 'title' => 'Title',
1480: 'reta' => 'Retained attachments',
1481: 'atta' => 'Attachment (128 KB max size)',
1482: );
1483: my $restitle = &get_resource_title($symb,$feedurl);
1484: my $quote='';
1485: my $subject = '';
1486: my $comment = '';
1487: my $prevtag = '';
1488: my $parentmsg = '';
1489: my ($symb,$idx,$attachmenturls);
1490: my $numoldver = 0;
1491: my $attachmsg = '';
1492: my $newattachmsg = '';
1493: my @currnewattach = ();
1494: my @currdelold = ();
1495: my @keepold = ();
1496: my %attachments = ();
1497: my %currattach = ();
1498: my $attachnum = 0;
1499: my $anonchk = (<<END);
1500: function anonchk() {
1501: for (var i=0; i < document.mailform.discuss.length; i++) {
1502: if (document.mailform.discuss[i].checked) {
1503: document.attachment.discuss.value =
1504: document.mailform.discuss[i].value;
1505: }
1506: }
1507: if (document.mailform.blog.checked) {
1508: document.attachment.blog.value = 1;
1509: }
1510: return
1511: }
1512: END
1513: my $anonscript;
1514: if (exists($env{'form.origpage'})) {
1515: $anonscript = (<<END);
1516: function setposttype() {
1517: var disc = "$env{'form.discuss'}";
1518: for (var i=0; i < document.mailform.discuss.length; i++) {
1519: if (disc == document.mailform.discuss[i].value) {
1520: document.mailform.discuss[i].checked = 1;
1521: }
1522: }
1523: var blog = "$env{'form.blog'}";
1524: if (blog == 1) {
1525: document.mailform.blog.checked=1;
1526: }
1527: return
1528: }
1529: END
1530: } else {
1531: $anonscript = (<<END);
1532: function setposttype() {
1533: return
1534: }
1535: END
1536: }
1537: if (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
1538: if ($env{'form.replydisc'}) {
1539: ($symb,$idx)=split(/\:\:\:/,$env{'form.replydisc'});
1540: } else {
1541: ($symb,$idx)=split(/\:\:\:/,$env{'form.editdisc'});
1542: }
1543: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
1544: $env{'course.'.$env{'request.course.id'}.'.domain'},
1545: $env{'course.'.$env{'request.course.id'}.'.num'});
1546: unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
1547: if ($contrib{$idx.':history'}) {
1548: if ($contrib{$idx.':history'} =~ /:/) {
1549: my @oldversions = split(/:/,$contrib{$idx.':history'});
1550: $numoldver = @oldversions;
1551: } else {
1552: $numoldver = 1;
1553: }
1554: }
1555: if ($env{'form.replydisc'}) {
1556: if ($contrib{$idx.':history'}) {
1557: if ($contrib{$idx.':history'} =~ /:/) {
1558: my @oldversions = split(/:/,$contrib{$idx.':history'});
1559: $numoldver = @oldversions;
1560: } else {
1561: $numoldver = 1;
1562: }
1563: }
1564: if ($idx > 0) {
1565: my %msgversions = ();
1566: &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
1567: $quote = $msgversions{$numoldver};
1568: }
1569: if ($idx > 0) {
1570: my %subversions = ();
1571: &get_post_versions(\%subversions,$contrib{$idx.':subject'},1,$numoldver);
1572: $subject = &mt('Re: ').$subversions{$numoldver};
1573: }
1574: $subject = &HTML::Entities::encode($subject,'<>&"');
1575: } else {
1576: $attachmenturls = $contrib{$idx.':attachmenturl'};
1577: if ($idx > 0) {
1578: my %msgversions = ();
1579: &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
1580: $comment = $msgversions{$numoldver};
1581: my %subversions = ();
1582: &get_post_versions(\%subversions,$contrib{$idx.':subject'},0,$numoldver);
1583: $subject = $subversions{$numoldver};
1584: }
1585: if (defined($contrib{$idx.':replyto'})) {
1586: $parentmsg = $contrib{$idx.':replyto'};
1587: }
1588: unless (exists($env{'form.origpage'})) {
1589: my $anonflag = 'nonanon';
1590: if ($contrib{$idx.':anonymous'}) {
1591: $anonflag = 'anon';
1592: }
1593: $anonscript = (<<END);
1594: function setposttype () {
1595: var currtype = "$anonflag";
1596: for (var i=0; i<document.mailform.discuss.length; i++) {
1597: if (document.mailform.elements.discuss[i].value == currtype ) {
1598: document.mailform.elements.discuss[i].checked=1;
1599: }
1600: }
1601: return
1602: }
1603: END
1604: }
1605: }
1606: }
1607: if ($env{'form.previous'}) {
1608: $prevtag = '<input type="hidden" name="previous" value="'.$env{'form.previous'}.'" />';
1609: }
1610: }
1611:
1612: if ($env{'form.origpage'}) {
1613: $subject = &unescape($env{'form.subject'});
1614: $comment = &unescape($env{'form.comment'});
1615: &process_attachments(\@currnewattach,\@currdelold,\@keepold);
1616: }
1617: my $latexHelp=&Apache::loncommon::helpLatexCheatsheet();
1618: my $send=&mt('Send');
1619: my $alert = &mt('Please select a feedback type.');
1620: my $js= <<END;
1621: <script type="text/javascript">
1622: //<!--
1623: function gosubmit() {
1624: var rec=0;
1625: if (typeof(document.mailform.elements.discuss)!="undefined") {
1626: if (typeof(document.mailform.elements.discuss.length) == "undefined") {
1627: if (document.mailform.elements.discuss.checked ) {
1628: rec=1;
1629: }
1630: } else {
1631: for (var i=0; i<document.mailform.elements.discuss.length; i++) {
1632: if (document.mailform.elements.discuss[i].checked ) {
1633: rec=1;
1634: }
1635: }
1636: }
1637: }
1638: if (typeof(document.mailform.elements.blog)!="undefined") {
1639: if (document.mailform.elements.blog.checked) {
1640: rec=1;
1641: }
1642: }
1643:
1644: if (rec) {
1645: if (typeof(document.mailform.onsubmit)=='function') {
1646: document.mailform.onsubmit();
1647: }
1648: document.mailform.submit();
1649: } else {
1650: alert('$alert');
1651: }
1652: }
1653: $anonchk
1654: $anonscript
1655: //-->
1656: </script>
1657: END
1658:
1659: my %onload = ('onload' => 'window.focus();setposttype();');
1660: my $start_page=
1661: &Apache::loncommon::start_page('Resource Feedback and Discussion',$js,
1662: {'add_entries' => \%onload});
1663:
1664: if ($quote ne '') {
1665: &newline_to_br(\$quote);
1666: $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($quote).'</blockquote>';
1667: }
1668:
1669: $r->print(<<END);
1670: $start_page
1671: <h2><tt>$restitle</tt></h2>
1672: <form action="/adm/feedback" method="post" name="mailform"
1673: enctype="multipart/form-data">
1674: $prevtag
1675: <input type="hidden" name="postdata" value="$feedurl" />
1676: END
1677: if ($env{'form.replydisc'}) {
1678: $r->print(<<END);
1679: <input type="hidden" name="replydisc" value="$env{'form.replydisc'}" />
1680: END
1681: } elsif ($env{'form.editdisc'}) {
1682: $r->print(<<END);
1683: <input type="hidden" name="editdisc" value ="$env{'form.editdisc'}" />
1684: <input type="hidden" name="parentmsg" value ="$parentmsg" />
1685: END
1686: }
1687: $r->print(<<END);
1688: $lt{'plch'}
1689: $options<hr />
1690: $quote
1691: <p>$lt{'myqu'}</p>
1692: <p>
1693: $latexHelp
1694: $lt{'title'}: <input type="text" name="subject" size="30" value="$subject" /></p>
1695: <p>
1696: <textarea name="comment" id="comment" cols="60" rows="10" wrap="hard">$comment
1697: </textarea></p>
1698: <p>
1699: END
1700: if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {
1701: if ($env{'form.origpage'}) {
1702: foreach my $attach (@currnewattach) {
1703: $r->print('<input type="hidden" name="currnewattach" value="'.$attach.'" />'."\n");
1704: }
1705: foreach my $oldatt (@currdelold) {
1706: $r->print('<input type="hidden" name="deloldattach" value="'.$oldatt.'" />'."\n");
1707: }
1708: }
1709: if ($env{'form.editdisc'}) {
1710: if ($attachmenturls) {
1711: &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold);
1712: $attachnum = scalar(keys(%currattach));
1713: foreach my $key (keys(%currattach)) {
1714: $r->print('<input type="hidden" name="keepold" value="'.$key.'" />'."\n");
1715: }
1716: }
1717: }
1718: } else {
1719: $r->print(<<END);
1720: $lt{'atta'}: <input type="file" name="attachment" />
1721: </p>
1722: END
1723: }
1724: if (exists($env{'form.group'})) {
1725: $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
1726: }
1727: if (exists($env{'form.ref'})) {
1728: $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
1729: }
1730: $r->print(<<END);
1731: <p>
1732: <input type="hidden" name="sendit" value="1" />
1733: <input type="button" value="$send" onClick='gosubmit();' />
1734: </p>
1735: </form>
1736: END
1737: if ($env{'form.editdisc'} || $env{'form.replydisc'}) {
1738: my $now = time;
1739: my $ressymb = $symb;
1740: &Apache::lonenc::check_encrypt(\$ressymb);
1741: my $postidx = '';
1742: if ($env{'form.editdisc'}) {
1743: $postidx = $idx;
1744: }
1745: if (@currnewattach > 0) {
1746: $attachnum += @currnewattach;
1747: }
1748: my $blockblog = &Apache::loncommon::blocking_status('blogs');
1749: $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver,'',$blockblog));
1750: if ($attachnum > 0) {
1751: if (@currnewattach > 0) {
1752: $newattachmsg .= '<br /><b>'.&mt('New attachments').'</b><br />';
1753: if (@currnewattach > 1) {
1754: $newattachmsg .= '<ol>';
1755: foreach my $item (@currnewattach) {
1756: $item =~ m#.*/([^/]+)$#;
1757: $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
1758: }
1759: $newattachmsg .= '</ol>'."\n";
1760: } else {
1761: $currnewattach[0] =~ m#.*/([^/]+)$#;
1762: $newattachmsg .= '<a href="'.$currnewattach[0].'">'.$1.'</a><br />'."\n";
1763: }
1764: }
1765: if ($attachmsg) {
1766: $r->print("<br /><b>$lt{'reta'}</b>:$attachmsg<br />\n");
1767: }
1768: if ($newattachmsg) {
1769: $r->print("$newattachmsg<br />");
1770: }
1771: }
1772: }
1773: $r->print(&generate_preview_button().
1774: &Apache::lonhtmlcommon::htmlareaselectactive('comment').
1775: &Apache::loncommon::end_page());
1776:
1777: }
1778:
1779: sub print_display_options {
1780: my ($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl) = @_;
1781: &Apache::loncommon::content_type($r,'text/html');
1782: $r->send_http_header;
1783:
1784: my $function = &Apache::loncommon::get_users_function();
1785: my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
1786: $env{'user.domain'});
1787:
1788: my %lt = &Apache::lonlocal::texthash(
1789: 'pref' => 'Display Preference',
1790: 'curr' => 'Current setting ',
1791: 'actn' => 'Action',
1792: 'deff' => 'Default for all discussions',
1793: 'prca' => 'Preferences can be set for this discussion that determine ....',
1794: 'whpo' => 'Which posts are displayed when you display this bulletin board or resource, and',
1795: 'unwh' => 'Under what circumstances posts are identified as "NEW", and',
1796: 'wipa' => 'Whether individual posts can be marked as read/unread',
1797: 'allposts' => 'All posts',
1798: 'unread' => 'New posts only',
1799: 'unmark' => 'Posts not marked read',
1800: 'ondisp' => 'Once displayed',
1801: 'onmark' => 'Once marked not NEW ',
1802: 'toggon' => 'Shown',
1803: 'toggoff' => 'Not shown',
1804: 'disa' => 'Posts displayed?',
1805: 'npmr' => 'New posts cease to be identified as "NEW"?',
1806: 'dotm' => 'Option to mark each post as read/unread?',
1807: 'chgt' => 'Change to ',
1808: 'mkdf' => 'Set to ',
1809: 'yhni' => 'You have not indicated that you wish to change any of the discussion settings',
1810: 'ywbr' => 'You will be returned to the previous page if you click OK.'
1811: );
1812:
1813: my $dispchangeA = $lt{'unread'};
1814: my $dispchangeB = $lt{'unmark'};
1815: my $markchange = $lt{'ondisp'};
1816: my $toggchange = $lt{'toggon'};
1817: my $currdisp = $lt{'allposts'};
1818: my $currmark = $lt{'onmark'};
1819: my $discdisp = 'allposts';
1820: my $discmark = 'onmark';
1821: my $currtogg = $lt{'toggoff'};
1822: my $disctogg = 'toggoff';
1823:
1824: if ($dispchgA eq 'allposts') {
1825: $dispchangeA = $lt{'allposts'};
1826: $currdisp = $lt{'unread'};
1827: $discdisp = 'unread';
1828: }
1829:
1830: if ($markchg eq 'markonread') {
1831: $markchange = $lt{'onmark'};
1832: $currmark = $lt{'ondisp'};
1833: $discmark = 'ondisp';
1834: }
1835:
1836: if ($dispchgB eq 'onlyunread') {
1837: $dispchangeB = $lt{'unread'};
1838: $currdisp = $lt{'unmark'};
1839: $discdisp = 'unmark';
1840: }
1841: if ($toggchg eq 'toggoff') {
1842: $toggchange = $lt{'toggoff'};
1843: $currtogg = $lt{'toggon'};
1844: $disctogg = 'toggon';
1845: }
1846:
1847: my $js = <<END;
1848: <script type="text/javascript">
1849: function discdispChk(caller) {
1850: var disctogg = '$toggchg'
1851: if (caller == 0) {
1852: if (document.modifydisp.discdisp[0].checked == true) {
1853: if (document.modifydisp.discdisp[1].checked == true) {
1854: document.modifydisp.discdisp[1].checked = false
1855: }
1856: }
1857: }
1858: if (caller == 1) {
1859: if (document.modifydisp.discdisp[1].checked == true) {
1860: if (document.modifydisp.discdisp[0].checked == true) {
1861: document.modifydisp.discdisp[0].checked = false
1862: }
1863: if (disctogg == 'toggon') {
1864: document.modifydisp.disctogg.checked = true
1865: }
1866: if (disctogg == 'toggoff') {
1867: document.modifydisp.disctogg.checked = false
1868: }
1869: }
1870: }
1871: if (caller == 2) {
1872: var dispchgB = '$dispchgB'
1873: if (disctogg == 'toggoff') {
1874: if (document.modifydisp.disctogg.checked == true) {
1875: if (dispchgB == 'onlyunmark') {
1876: document.modifydisp.discdisp[1].checked = false
1877: }
1878: }
1879: }
1880: }
1881: }
1882:
1883: function setDisp() {
1884: var prev = "$previous"
1885: var chktotal = 0
1886: if (document.modifydisp.discdisp[0].checked == true) {
1887: document.modifydisp.$dispchgA.value = "$symb"
1888: chktotal ++
1889: }
1890: if (document.modifydisp.discdisp[1].checked == true) {
1891: document.modifydisp.$dispchgB.value = "$symb"
1892: chktotal ++
1893: }
1894: if (document.modifydisp.discmark.checked == true) {
1895: document.modifydisp.$markchg.value = "$symb"
1896: chktotal ++
1897: }
1898: if (document.modifydisp.disctogg.checked == true) {
1899: document.modifydisp.$toggchg.value = "$symb"
1900: chktotal ++
1901: }
1902: if (chktotal > 0) {
1903: document.modifydisp.submit()
1904: } else {
1905: if(confirm("$lt{'yhni'}. \\n$lt{'ywbr'}")) {
1906: if (prev > 0) {
1907: location.href = "$feedurl?previous=$previous"
1908: } else {
1909: location.href = "$feedurl"
1910: }
1911: }
1912: }
1913: }
1914: </script>
1915: END
1916:
1917:
1918: my $start_page =
1919: &Apache::loncommon::start_page('Discussion display options',$js);
1920: my $end_page =
1921: &Apache::loncommon::end_page();
1922: $r->print(<<END);
1923: $start_page
1924: <form name="modifydisp" method="POST" action="/adm/feedback">
1925: $lt{'sdpf'}<br/> $lt{'prca'} <ol><li>$lt{'whpo'}</li><li>$lt{'unwh'}</li><li>$lt{'wipa'}</li></ol>
1926: <br />
1927: END
1928: $r->print(&Apache::loncommon::start_data_table());
1929: $r->print(<<END);
1930: <tr>
1931: <th>$lt{'pref'}</td>
1932: <th>$lt{'curr'}</td>
1933: <th>$lt{'actn'}?</td>
1934: </tr>
1935: END
1936: $r->print(&Apache::loncommon::start_data_table_row());
1937: $r->print(<<END);
1938: <td>$lt{'disa'}</td>
1939: <td>$lt{$discdisp}</td>
1940: <td><label><input type="checkbox" name="discdisp" onClick="discdispChk('0')" /> $lt{'chgt'} "$dispchangeA"</label>
1941: <br />
1942: <label><input type="checkbox" name="discdisp" onClick="discdispChk('1')" /> $lt{'chgt'} "$dispchangeB"</label>
1943: </td>
1944: END
1945: $r->print(&Apache::loncommon::end_data_table_row());
1946: $r->print(&Apache::loncommon::start_data_table_row());
1947: $r->print(<<END);
1948: <td>$lt{'npmr'}</td>
1949: <td>$lt{$discmark}</td>
1950: <td><label><input type="checkbox" name="discmark" />$lt{'chgt'} "$markchange"</label></td>
1951: END
1952: $r->print(&Apache::loncommon::end_data_table_row());
1953: $r->print(&Apache::loncommon::start_data_table_row());
1954: $r->print(<<END);
1955: <td>$lt{'dotm'}</td>
1956: <td>$lt{$disctogg}</td>
1957: <td><label><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</label></td>
1958: END
1959: $r->print(&Apache::loncommon::end_data_table_row());
1960: $r->print(&Apache::loncommon::end_data_table());
1961: $r->print(<<END);
1962: <br />
1963: <br />
1964: <input type="hidden" name="symb" value="$symb" />
1965: <input type="hidden" name="previous" value="$previous" />
1966: <input type="hidden" name="$dispchgA" value=""/>
1967: <input type="hidden" name="$dispchgB" value=""/>
1968: <input type="hidden" name="$markchg" value=""/>
1969: <input type="hidden" name="$toggchg" value="" />
1970: <input type="button" name="sub" value="Store Changes" onClick="javascript:setDisp()" />
1971: END
1972: if (exists($env{'form.group'})) {
1973: $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
1974: }
1975: if (exists($env{'form.ref'})) {
1976: $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
1977: }
1978: $r->print("
1979: <br />
1980: <br />
1981: </form>
1982: $end_page
1983: ");
1984: return;
1985: }
1986:
1987: sub print_sortfilter_options {
1988: my ($r,$symb,$previous,$feedurl) = @_;
1989:
1990: &Apache::loncommon::content_type($r,'text/html');
1991: $r->send_http_header;
1992:
1993: &Apache::lonenc::check_encrypt(\$symb);
1994: my @sections;
1995: my $section_sel = '';
1996: my $numvisible = 5;
1997: my @groups;
1998: my $group_sel = '';
1999: my $numgroupvis = 5;
2000: my %sectioncount = &Apache::loncommon::get_sections();
2001:
2002: if ($env{'request.course.sec'} !~ /^\s*$/) { #Restrict section choice to current section
2003: @sections = ('all',$env{'request.course.sec'});
2004: $numvisible = 2;
2005: } else {
2006: @sections = sort {$a cmp $b} keys(%sectioncount);
2007: if (scalar(@sections) < 4) {
2008: $numvisible = scalar(@sections) + 1;
2009: }
2010: unshift(@sections,'all'); # Put 'all' at the front of the list
2011:
2012: }
2013: foreach my $sec (@sections) {
2014: $section_sel .= " <option value=\"$sec\">$sec</option>\n";
2015: }
2016:
2017: if (&check_group_priv() eq 'ok') {
2018: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
2019: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
2020: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
2021: @groups = sort {$a cmp $b} keys(%curr_groups);
2022: if (scalar(@groups) < 4) {
2023: $numgroupvis = scalar(@groups) + 1;
2024: }
2025: unshift(@groups,'all'); # Put 'all' at the front of the list
2026: } else {
2027: my @coursegroups = split(/:/,$env{'request.course.groups'});
2028: if (@coursegroups > 0) {
2029: @coursegroups = sort {$a cmp $b} @coursegroups;
2030: @groups = ('all',@coursegroups);
2031: if (scalar(@groups) < 4) {
2032: $numgroupvis = scalar(@groups) + 1;
2033: }
2034: } else {
2035: @groups = ('all');
2036: $numgroupvis = 1;
2037: }
2038: }
2039: foreach my $group (@groups) {
2040: $group_sel .= " <option value=\"$group\">$group</option>\n";
2041: }
2042:
2043: my $function = &Apache::loncommon::get_users_function();
2044: my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
2045: $env{'user.domain'});
2046: my %lt = &Apache::lonlocal::texthash(
2047: 'diop' => 'Display Options',
2048: 'curr' => 'Current setting ',
2049: 'actn' => 'Action',
2050: 'prca' => 'Set options that control the sort order of posts, and/or which posts are displayed.',
2051: 'soor' => 'Sort order',
2052: 'spur' => 'Specific user roles',
2053: 'sprs' => 'Specific role status',
2054: 'spse' => 'Specific sections',
2055: 'spgr' => 'Specific groups',
2056: 'psub' => 'Pick specific users (by name)',
2057: 'shal' => 'Show a list of current posters',
2058: 'stor' => 'Store changes',
2059: );
2060:
2061: my %sort_types = ();
2062: my %role_types = ();
2063: my %status_types = ();
2064: &sort_filter_names(\%sort_types,\%role_types,\%status_types);
2065:
2066: my $js = <<END;
2067: <script type="text/javascript">
2068: function verifyFilter() {
2069: var rolenum = 0
2070: for (var i=0; i<document.modifyshown.rolefilter.length; i++) {
2071: if (document.modifyshown.rolefilter.options[i].selected == true) {
2072: rolenum ++
2073: }
2074: }
2075: if (rolenum == 0) {
2076: document.modifyshown.rolefilter.options[0].selected = true
2077: }
2078:
2079: var secnum = 0
2080: for (var i=0; i<document.modifyshown.sectionpick.length; i++) {
2081: if (document.modifyshown.sectionpick.options[i].selected == true) {
2082: secnum ++
2083: }
2084: }
2085: if (secnum == 0) {
2086: document.modifyshown.sectionpick.options[0].selected = true
2087: }
2088:
2089: var grpnum = 0
2090: for (var i=0; i<document.modifyshown.grouppick.length; i++) {
2091: if (document.modifyshown.grouppick.options[i].selected == true) {
2092: grpnum ++
2093: }
2094: }
2095: if (grpnum == 0) {
2096: document.modifyshown.grouppick.options[0].selected = true
2097: }
2098:
2099: document.modifyshown.submit();
2100: }
2101: </script>
2102: END
2103:
2104: my $start_page=
2105: &Apache::loncommon::start_page('Discussion options',$js);
2106: my $end_page=
2107: &Apache::loncommon::end_page();
2108:
2109: $r->print(<<END);
2110: $start_page
2111: <form name="modifyshown" method="POST" action="/adm/feedback">
2112: <b>$lt{'diso'}</b><br/> $lt{'prca'}
2113: <br /><br />
2114: <table border="0">
2115: <tr>
2116: <td><b>$lt{'soor'}</b></td>
2117: <td> </td>
2118: <td><b>$lt{'sprs'}</b></td>
2119: <td> </td>
2120: <td><b>$lt{'spur'}</b></td>
2121: <td> </td>
2122: <td><b>$lt{'spse'}</b></td>
2123: <td> </td>
2124: <td><b>$lt{'spgr'}</b></td>
2125: <td> </td>
2126: <td><b>$lt{'psub'}</b></td>
2127: </tr>
2128: <tr>
2129: <td align="center" valign="top">
2130: <select name="sortposts">
2131: <option value="ascdate" selected="selected">$sort_types{'ascdate'}</option>
2132: <option value="descdate">$sort_types{'descdate'}</option>
2133: <option value="thread">$sort_types{'thread'}</option>
2134: <option value="subject">$sort_types{'subject'}</option>
2135: <option value="username">$sort_types{'username'}</option>
2136: <option value="lastfirst">$sort_types{'lastfirst'}</option>
2137: </select>
2138: </td>
2139: <td> </td>
2140: <td align="center" valign="top">
2141: <select name="statusfilter">
2142: <option value="all" selected="selected">$status_types{'all'}</option>
2143: <option value="Active">$status_types{'Active'}</option>
2144: <option value="Expired">$status_types{'Expired'}</option>
2145: <option value="Future">$status_types{'Future'}</option>
2146: </select>
2147: </td>
2148: <td> </td>
2149: <td align="center" valign="top">
2150: <select name="rolefilter" multiple="true" size="5">
2151: <option value="all">$role_types{'all'}</option>
2152: <option value="st">$role_types{'st'}</option>
2153: <option value="cc">$role_types{'cc'}</option>
2154: <option value="in">$role_types{'in'}</option>
2155: <option value="ta">$role_types{'ta'}</option>
2156: <option value="ep">$role_types{'ep'}</option>
2157: <option value="cr">$role_types{'cr'}</option>
2158: </select>
2159: </td>
2160: <td> </td>
2161: <td align="center" valign="top">
2162: <select name="sectionpick" multiple="true" size="$numvisible">
2163: $section_sel
2164: </select>
2165: </td>
2166: <td> </td>
2167: <td align="center" valign="top">
2168: <select name="grouppick" multiple="true" size="$numvisible">
2169: $group_sel
2170: </select>
2171: </td>
2172: <td> </td>
2173: <td valign="top"><label><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</label></td>
2174: </tr>
2175: </table>
2176: <br />
2177: <br />
2178: <input type="hidden" name="previous" value="$previous" />
2179: <input type="hidden" name="applysort" value="$symb" />
2180: <input type="button" name="sub" value="$lt{'stor'}" onClick="verifyFilter()" />
2181: END
2182: if (exists($env{'form.group'})) {
2183: $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
2184: }
2185: if (exists($env{'form.ref'})) {
2186: $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
2187: }
2188: $r->print("
2189: <br />
2190: <br />
2191: </form>
2192: $end_page
2193: ");
2194: }
2195:
2196: sub print_showposters {
2197: my ($r,$symb,$previous,$feedurl,$sortposts) = @_;
2198:
2199: &Apache::loncommon::content_type($r,'text/html');
2200: $r->send_http_header;
2201:
2202: &Apache::lonenc::check_encrypt(\$symb);
2203: my $crs='/'.$env{'request.course.id'};
2204: if ($env{'request.course.sec'}) {
2205: $crs.='_'.$env{'request.course.sec'};
2206: }
2207: $crs=~s/\_/\//g;
2208: my $seeid;
2209: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
2210: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
2211: my $group = $env{'form.group'};
2212: my $ressymb = &wrap_symb($symb);
2213: if (($group ne '') &&
2214: ($ressymb =~ m|^bulletin___ \d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {
2215: if (&check_group_priv($group,'dgp') eq 'ok') {
2216: $seeid = 1;
2217: }
2218: } else {
2219: $seeid=&Apache::lonnet::allowed('rin',$crs);
2220: }
2221: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
2222: $cdom,$cnum);
2223: my %namesort = ();
2224: my %postcounts = ();
2225:
2226: my %lt = &Apache::lonlocal::texthash(
2227: sele => 'Select',
2228: full => 'Fullname',
2229: usdo => 'Username:domain',
2230: post => 'Posts',
2231: );
2232: if ($contrib{'version'}) {
2233: for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
2234: my $hidden=($contrib{'hidden'}=~/\.$idx\./);
2235: my $deleted=($contrib{'deleted'}=~/\.$idx\./);
2236: unless ((($hidden) && (!$seeid)) || ($deleted)) {
2237: if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
2238: my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
2239: my $lastname = $names{'lastname'};
2240: my $firstname = $names{'firstname'};
2241: if ($lastname eq '') {
2242: $lastname = '_';
2243: }
2244: if ($firstname eq '') {
2245: $firstname = '_';
2246: }
2247: unless (defined($namesort{$lastname})) {
2248: %{$namesort{$lastname}} = ();
2249: }
2250: my $poster = $contrib{$idx.':sendername'}.':'.$contrib{$idx.':senderdomain'};
2251: $postcounts{$poster} ++;
2252: if (defined($namesort{$lastname}{$firstname})) {
2253: if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) {
2254: push(@{$namesort{$lastname}{$firstname}}, $poster);
2255: }
2256: } else {
2257: @{$namesort{$lastname}{$firstname}} = ("$poster");
2258: }
2259: }
2260: }
2261: }
2262: }
2263:
2264: my $start_page = &Apache::loncommon::start_page('Discussion options');
2265: my $table_start =&Apache::loncommon::start_data_table();
2266: $r->print(<<END);
2267: $start_page
2268: <form name="pickpostersform" method="post">
2269: <br />
2270: $table_start
2271: <tr>
2272: <th>#</th>
2273: <th>$lt{'sele'}</th>
2274: <th>$lt{'full'} <font color="#999999">($lt{'usdo'})</font></th>
2275: <th>$lt{'post'}</th>
2276: </tr>
2277: END
2278: my $count = 0;
2279: foreach my $last (sort(keys(%namesort))) {
2280: foreach my $first (sort(keys(%{$namesort{$last}}))) {
2281: foreach my $user (sort(@{$namesort{$last}{$first}})) {
2282: my ($uname,$udom) = split(/:/,$user);
2283: if (!$uname || !$udom) {
2284: next;
2285: } else {
2286: $count ++;
2287: $r->print(&Apache::loncommon::start_data_table_row().
2288: '<td align="right">'.$count.'</td>
2289: <td align="center"><label><input name="stuinfo" type="checkbox" value="'.$user.'" /></td>
2290: <td>'.$last.', '.$first.' ('.$uname.':'.$udom.')</label></td>
2291: <td>'.$postcounts{$user}.'</td>'.
2292: &Apache::loncommon::end_data_table_row());
2293: }
2294: }
2295: }
2296: }
2297: $r->print(&Apache::loncommon::end_data_table());
2298: my $end_page = &Apache::loncommon::end_page();
2299: $r->print(<<END);
2300: <br />
2301: <input type="hidden" name="sortposts" value="$sortposts" />
2302: <input type="hidden" name="userpick" value="$symb" />
2303: <input type="button" name="store" value="Display posts" onClick="javascript:document.pickpostersform.submit()" />
2304: </form>
2305: $end_page
2306: END
2307: }
2308:
2309: sub get_post_versions {
2310: my ($versions,$incoming,$htmldecode,$numver) = @_;
2311: if ($incoming =~ /^<version num="0">/) {
2312: my $p = HTML::LCParser->new(\$incoming);
2313: my $done = 0;
2314:
2315: while ( (my $token = $p->get_tag("version")) && (!$done)) {
2316: my $num = $token->[1]{num};
2317: my $text = $p->get_text("/version");
2318: if (defined($numver)) {
2319: if ($num == $numver) {
2320: if ($htmldecode) {
2321: $text = &HTML::Entities::decode($text);
2322: }
2323: $$versions{$numver}=$text;
2324: $done = 1;
2325: }
2326: } else {
2327: if ($htmldecode) {
2328: $text = &HTML::Entities::decode($text);
2329: }
2330: $$versions{$num}=$text;
2331: }
2332: }
2333: } else {
2334: if (!defined($numver)) {
2335: $numver = 0;
2336: }
2337: if ($htmldecode) {
2338: $$versions{$numver} = $incoming;
2339: } else {
2340: $$versions{$numver} = &HTML::Entities::encode($incoming,'<>&"');
2341: }
2342: }
2343: return;
2344: }
2345:
2346: sub get_post_attachments {
2347: my ($attachments,$attachmenturls) = @_;
2348: my $num;
2349: if ($attachmenturls =~ m/^<attachment id="0">/) {
2350: my $p = HTML::LCParser->new(\$attachmenturls);
2351: while (my $token = $p->get_tag("attachment","filename","post")) {
2352: if ($token->[0] eq "attachment") {
2353: $num = $token->[1]{id};
2354: %{$$attachments{$num}} =();
2355: } elsif ($token->[0] eq "filename") {
2356: $$attachments{$num}{'filename'} = $p->get_text("/filename");
2357: } elsif ($token->[0] eq "post") {
2358: my $id = $token->[1]{id};
2359: $$attachments{$num}{$id} = $p->get_text("/post");
2360: }
2361: }
2362: } else {
2363: %{$$attachments{'0'}} = ();
2364: $$attachments{'0'}{'filename'} = $attachmenturls;
2365: $$attachments{'0'}{'0'} = 'n';
2366: }
2367:
2368: return;
2369: }
2370:
2371: sub fail_redirect {
2372: my ($r,$feedurl) = @_;
2373: if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
2374: my %lt = &Apache::lonlocal::texthash(
2375: 'sorr' => 'Sorry, no recipients ...',
2376: );
2377: my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
2378: $r->print(&Apache::loncommon::start_page('Feedback not sent',undef,
2379: {'redirect' => [2,$feedurl],
2380: 'only_body' => 1,}));
2381: $r->print(<<ENDFAILREDIR);
2382: <img align="right" src="$logo" />
2383: <b>$lt{'sorr'}</b>
2384: ENDFAILREDIR
2385: $r->print(&Apache::loncommon::end_page());
2386: }
2387:
2388: sub redirect_back {
2389: my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group) = @_;
2390: my $sorttag = '';
2391: my $roletag = '';
2392: my $statustag = '';
2393: my $sectag = '';
2394: my $grptag = '';
2395: my $userpicktag = '';
2396: my $qrystr = '';
2397: my $prevtag = '';
2398:
2399: &Apache::loncommon::content_type($r,'text/html');
2400: $r->send_http_header;
2401: &dewrapper(\$feedurl);
2402: if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
2403: if ($previous > 0) {
2404: $qrystr = 'previous='.$previous;
2405: if ($feedurl =~ /\?register=1/) {
2406: $feedurl .= '&'.$qrystr;
2407: } else {
2408: $feedurl .= '?'.$qrystr;
2409: }
2410: $prevtag = '<input type="hidden" name="previous" value="'.$previous.'" />';
2411: }
2412: if (defined($sort)) {
2413: my $sortqry = 'sortposts='.$sort;
2414: if (($feedurl =~ /\?register=1/) || ($feedurl =~ /\?previous=/)) {
2415: $feedurl .= '&'.$sortqry;
2416: } else {
2417: $feedurl .= '?'.$sortqry;
2418: }
2419: $sorttag = '<input type="hidden" name="sortposts" value="'.$sort.'" />';
2420: if (defined($numpicks)) {
2421: my $userpickqry = 'totposters='.$numpicks;
2422: $feedurl .= '&'.$userpickqry;
2423: $userpicktag = '<input type="hidden" name="totposters" value="'.$numpicks.'" />';
2424: } else {
2425: if (ref($sectionpick) eq 'ARRAY') {
2426: $feedurl .= '§ionpick=';
2427: $sectag .= '<input type="hidden" name="sectionpick" value="';
2428: foreach my $sec (@{$sectionpick}) {
2429: $feedurl .= $sec.',';
2430: $sectag .= $sec.',';
2431: }
2432: $feedurl =~ s/,$//;
2433: $sectag =~ s/,$//;
2434: $sectag .= '" />';
2435: } else {
2436: $feedurl .= '§ionpick='.$sectionpick;
2437: $sectag = '<input type="hidden" name="sectionpick" value="'.$sectionpick.'" />';
2438: }
2439: if (ref($grouppick) eq 'ARRAY') {
2440: $feedurl .= '&grouppick=';
2441: $sectag .= '<input type="hidden" name="grouppick" value="';
2442: foreach my $grp (@{$grouppick}) {
2443: $feedurl .= $grp.',';
2444: $grptag .= $grp.',';
2445: }
2446: $feedurl =~ s/,$//;
2447: $grptag =~ s/,$//;
2448: $grptag .= '" />';
2449: } else {
2450: $feedurl .= '&grouppick='.$grouppick;
2451: $grptag = '<input type="hidden" name="grouppick" value="'.$grouppick.'" />';
2452: }
2453: if (ref($rolefilter) eq 'ARRAY') {
2454: $feedurl .= '&rolefilter=';
2455: $roletag .= '<input type="hidden" name="rolefilter" value="';
2456: foreach my $role (@{$rolefilter}) {
2457: $feedurl .= $role.',';
2458: $roletag .= $role.',';
2459: }
2460: $feedurl =~ s/,$//;
2461: $roletag =~ s/,$//;
2462: $roletag .= '" />';
2463: } else {
2464: $feedurl .= '&rolefilter='.$rolefilter;
2465: $roletag = '<input type="hidden" name="rolefilter" value="'.$rolefilter.'" />';
2466: }
2467: $feedurl .= '&statusfilter='.$statusfilter;
2468: $statustag ='<input type="hidden" name="statusfilter" value="'.$statusfilter.'" />';
2469: }
2470: }
2471: my $grouptag;
2472: if ($group ne '') {
2473: $grouptag = '<input type="hidden" name="group" value="'.$group.'" />'; my $refarg;
2474: if (exists($env{'form.ref'})) {
2475: $refarg = '&ref='.$env{'form.ref'};
2476: $grouptag .= '<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />';
2477: }
2478: if ($feedurl =~ /\?/) {
2479: $feedurl .= '&group='.$group.$refarg;
2480: } else {
2481: $feedurl .= '?group='.$group.$refarg;
2482: }
2483: }
2484: &Apache::lonenc::check_encrypt(\$feedurl);
2485: my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
2486: my %onload;
2487: if ($env{'environment.remote'} ne 'off') {
2488: $onload{'onload'} =
2489: "if (window.name!='loncapaclient') { this.document.reldt.submit(); self.window.close(); }";
2490: }
2491: my $start_page=
2492: &Apache::loncommon::start_page('Feedback sent',undef,
2493: {'redirect' => [0,$feedurl],
2494: 'only_body' => 1,
2495: 'add_entries' => \%onload});
2496: my $end_page = &Apache::loncommon::end_page();
2497: $r->print(<<ENDREDIR);
2498: $start_page
2499: <img align="right" src="$logo" />
2500: $typestyle
2501: <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
2502: $blog
2503: <font color="red">$status</font>
2504: <form name="reldt" action="$feedurl" target="loncapaclient">
2505: $prevtag
2506: $sorttag
2507: $statustag
2508: $roletag
2509: $sectag
2510: $grptag
2511: $userpicktag
2512: $grouptag
2513: </form>
2514: $end_page
2515: ENDREDIR
2516: }
2517:
2518: sub no_redirect_back {
2519: my ($r,$feedurl) = @_;
2520: my $nofeed=&mt('Sorry, no feedback possible on this resource ...');
2521:
2522: my %onload;
2523: if ($env{'environment.remote'} ne 'off') {
2524: $onload{'onload'} =
2525: "if (window.name!='loncapaclient') { self.window.close(); }";
2526: }
2527:
2528: my %body_options = ('only_body' => 1,
2529: 'bgcolor' => '#FFFFFF',
2530: 'add_entries' => \%onload,);
2531:
2532: if ($feedurl !~ m{^/adm/feedback}) {
2533: $body_options{'rediect'} = [2,$feedurl];
2534: }
2535: my $start_page=
2536: &Apache::loncommon::start_page('Feedback not sent',undef,
2537: \%body_options);
2538:
2539: my $end_page = &Apache::loncommon::end_page();
2540:
2541: &Apache::lonenc::check_encrypt(\$feedurl);
2542: my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
2543: $r->print (<<ENDNOREDIRTWO);
2544: $start_page
2545: <img align="right" src="$logo" />
2546: <b>$nofeed</b>
2547: <br />
2548: $end_page
2549: ENDNOREDIRTWO
2550: }
2551:
2552: sub screen_header {
2553: my ($feedurl,$symb) = @_;
2554: my $msgoptions='';
2555: my $discussoptions='';
2556: unless (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
2557: if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/) && ($env{'user.adv'})) {
2558: $msgoptions=
2559: '<p><label><input type="radio" name="discuss" value="author" /> '.
2560: &mt('Feedback to resource author').'</label></p>';
2561: }
2562: if (&feedback_available(1)) {
2563: $msgoptions.=
2564: '<p><label><input type="radio" name="discuss" value="question" /> '.
2565: &mt('Question about resource content').'</label></p>';
2566: }
2567: if (&feedback_available(0,1)) {
2568: $msgoptions.=
2569: '<p><label><input type="radio" name="discuss" value="course" /> '.
2570: &mt('Question/Comment/Feedback about course content').
2571: '</label></p>';
2572: }
2573: if (&feedback_available(0,0,1)) {
2574: $msgoptions.=
2575: '<p><label><input type="radio" name="discuss" value="policy" /> '.
2576: &mt('Question/Comment/Feedback about course policy').
2577: '</label></p>';
2578: }
2579: }
2580: if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) {
2581: if (&discussion_open(undef,$symb) &&
2582: &Apache::lonnet::allowed('pch',
2583: $env{'request.course.id'}.
2584: ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
2585: $discussoptions='<label><input type="radio" name="discuss" value="nonanon" checked="checked" /> '.
2586: &mt('Contribution to course discussion of resource');
2587: $discussoptions.='</label><br /><label><input type="radio" name="discuss" value="anon" /> '.
2588: &mt('Anonymous contribution to course discussion of resource').
2589: ' <i>('.&mt('name only visible to course faculty').')</i></label> '.
2590: '<a href="/adm/preferences?action=changescreenname">'.&mt('Change Screenname').'</a>';
2591: }
2592: my $blockblog = &Apache::loncommon::blocking_status('blogs');
2593: if (!$blockblog) {
2594: $discussoptions.= &add_blog_checkbox();
2595: }
2596: }
2597: if ($msgoptions) { $msgoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').'" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
2598: if ($discussoptions) {
2599: $discussoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
2600: return $msgoptions.$discussoptions;
2601: }
2602:
2603: sub resource_output {
2604: my ($feedurl) = @_;
2605: my $usersaw=&Apache::lonnet::ssi_body($feedurl);
2606: $usersaw=~s/\<body[^\>]*\>//gi;
2607: $usersaw=~s/\<\/body\>//gi;
2608: $usersaw=~s/\<html\>//gi;
2609: $usersaw=~s/\<\/html\>//gi;
2610: $usersaw=~s/\<head\>//gi;
2611: $usersaw=~s/\<\/head\>//gi;
2612: $usersaw=~s/action\s*\=/would_be_action\=/gi;
2613: return $usersaw;
2614: }
2615:
2616: sub clear_out_html {
2617: my ($message,$override,$ignore_htmlarea)=@_;
2618: if (!$ignore_htmlarea
2619: && !&Apache::lonhtmlcommon::htmlareablocked()) { return $message; }
2620: # Always allow the <m>-tag
2621: my %html=(M=>1);
2622: # Check if more is allowed
2623: my $cid=$env{'request.course.id'};
2624: if (($env{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||
2625: ($override)) {
2626: # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG>
2627: # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB>
2628: # <SUP>
2629: %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,
2630: BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1,
2631: M=>1, ALGEBRA=>1, SUB=>1, SUP=>1, SPAN=>1,
2632: H1=>1, H2=>1, H3=>1, H4=>1, H5=>1);
2633: }
2634: # Do the substitution of everything that is not explicitly allowed
2635: $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/
2636: {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\<$1"}/ge;
2637: $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/
2638: {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\>"}/ge;
2639: return $message;
2640: }
2641:
2642: sub assemble_email {
2643: my ($message,$prevattempts,$usersaw,$useranswer)=@_;
2644: my %lt = &Apache::lonlocal::texthash(
2645: 'prev' => 'Previous attempts of student (if applicable)',
2646: 'orig' => 'Original screen output (if applicable)',
2647: 'corr' => 'Correct Answer(s) (if applicable)',
2648: );
2649: my $email=<<"ENDEMAIL";
2650: $message
2651: ENDEMAIL
2652: my $citations=<<"ENDCITE";
2653: <h2>$lt{'prev'}</h2>
2654: $prevattempts
2655: <br /><hr />
2656: <h2>$lt{'orig'}</h2>
2657: $usersaw
2658: <h2>$lt{'corr'}</h2>
2659: $useranswer
2660: ENDCITE
2661: return ($email,$citations);
2662: }
2663:
2664: sub secapply {
2665: my $rec=shift;
2666: my $defaultflag=shift;
2667: $rec=~s/\s+//g;
2668: $rec=~s/\@/\:/g;
2669: my ($adr,$sections_or_groups)=($rec=~/^([^\(]+)\(([^\)]+)\)/);
2670: if ($sections_or_groups) {
2671: foreach my $item (split(/\;/,$sections_or_groups)) {
2672: if (($item eq $env{'request.course.sec'}) ||
2673: ($defaultflag && ($item eq '*'))) {
2674: return $adr;
2675: } elsif ($env{'request.course.groups'}) {
2676: my @usersgroups = split(/:/,$env{'request.course.groups'});
2677: if (grep(/^\Q$item\E$/,@usersgroups)) {
2678: return $adr;
2679: }
2680: }
2681: }
2682: } else {
2683: return $rec;
2684: }
2685: return '';
2686: }
2687:
2688: =pod
2689:
2690: =over 4
2691:
2692: =item *
2693:
2694: decide_receiver($feedurl,$author,$question,$course,$policy,$defaultflag);
2695:
2696: Arguments
2697: $feedurl - /res/ url of resource (only need if $author is true)
2698: $author,$question,$course,$policy - all true/false parameters
2699: if true will attempt to find the addresses of user that should receive
2700: this type of feedback (author - feedback to author of resource $feedurl,
2701: $question 'Resource Content Questions', $course 'Course Content Question',
2702: $policy 'Course Policy')
2703: (Additionally it also checks $env for whether the corresponding form.<name>
2704: element exists, for ease of use in a html response context)
2705:
2706: $defaultflag - (internal should be left blank) if true gather addresses
2707: that aren't for a section even if I have a section
2708: (used for reccursion internally, first we look for
2709: addresses for our specific section then we recurse
2710: and look for non section addresses)
2711:
2712: Returns
2713: $typestyle - string of html text, describing what addresses were found
2714: %to - a hash, which keys are addresses of users to send messages to
2715: the keys will look like name:domain
2716:
2717: =cut
2718:
2719: sub decide_receiver {
2720: my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_;
2721: &Apache::lonenc::check_decrypt(\$feedurl);
2722: my $typestyle='';
2723: my %to=();
2724: if ($env{'form.discuss'} eq 'author' ||$author) {
2725: $typestyle.='Submitting as Author Feedback<br />';
2726: $feedurl=~ m{^/res/($LONCAPA::domain_re)/($LONCAPA::username_re)/};
2727: $to{$2.':'.$1}=1;
2728: }
2729: if ($env{'form.discuss'} eq 'question' ||$question) {
2730: $typestyle.=&mt('Submitting as Question').'<br />';
2731: foreach my $item (split(/\,/,
2732: $env{'course.'.$env{'request.course.id'}.'.question.email'})
2733: ) {
2734: my $rec=&secapply($item,$defaultflag);
2735: if ($rec) { $to{$rec}=1; }
2736: }
2737: }
2738: if ($env{'form.discuss'} eq 'course' ||$course) {
2739: $typestyle.=&mt('Submitting as Comment').'<br />';
2740: foreach my $item (split(/\,/,
2741: $env{'course.'.$env{'request.course.id'}.'.comment.email'})
2742: ) {
2743: my $rec=&secapply($item,$defaultflag);
2744: if ($rec) { $to{$rec}=1; }
2745: }
2746: }
2747: if ($env{'form.discuss'} eq 'policy' ||$policy) {
2748: $typestyle.=&mt('Submitting as Policy Feedback').'<br />';
2749: foreach my $item (split(/\,/,
2750: $env{'course.'.$env{'request.course.id'}.'.policy.email'})
2751: ) {
2752: my $rec=&secapply($item,$defaultflag);
2753: if ($rec) { $to{$rec}=1; }
2754: }
2755: }
2756: if ((scalar(%to) eq '0') && (!$defaultflag)) {
2757: ($typestyle,%to)=
2758: &decide_receiver($feedurl,$author,$question,$course,$policy,1);
2759: }
2760: return ($typestyle,%to);
2761: }
2762:
2763: sub feedback_available {
2764: my ($question,$course,$policy)=@_;
2765: my ($typestyle,%to)=&decide_receiver('',0,$question,$course,$policy);
2766: return scalar(%to);
2767: }
2768:
2769: sub send_msg {
2770: my ($title,$feedurl,$email,$citations,$attachmenturl,$symb,%to)=@_;
2771: my $status='';
2772: my $sendsomething=0;
2773: my $restitle = &get_resource_title($symb,$feedurl);
2774: if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }
2775: unless ($title=~/\w/) { $title=&mt('Feedback'); }
2776: foreach my $key (keys(%to)) {
2777: if ($key) {
2778: unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$key),
2779: $title.' ['.$restitle.']',$email,$citations,$feedurl,
2780: $attachmenturl,undef,undef,$symb,$restitle)=~/ok/) {
2781: $status.='<br />'.&mt('Error sending message to').' '.$key.'<br />';
2782: } else {
2783: $sendsomething++;
2784: }
2785: }
2786: }
2787:
2788: my %record=&Apache::lonnet::restore('_feedback');
2789: my ($temp)=keys(%record);
2790: unless ($temp=~/^error\:/) {
2791: my %newrecord=();
2792: $newrecord{'resource'}=$feedurl;
2793: $newrecord{'subnumber'}=$record{'subnumber'}+1;
2794: unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
2795: $status.='<br />'.&mt('Not registered').'<br />';
2796: }
2797: }
2798:
2799: return ($status,$sendsomething);
2800: }
2801:
2802: sub adddiscuss {
2803: my ($symb,$email,$anon,$attachmenturl,$subject)=@_;
2804: my $status='';
2805: my $realsymb;
2806: if ($symb=~/^bulletin___/) {
2807: my $filename=(&Apache::lonnet::decode_symb($symb))[2];
2808: $filename=~s|^adm/wrapper/||;
2809: $realsymb=&Apache::lonnet::symbread($filename);
2810: }
2811: if (&discussion_open(undef,$realsymb) &&
2812: &Apache::lonnet::allowed('pch',$env{'request.course.id'}.
2813: ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
2814:
2815: my %contrib=('message' => $email,
2816: 'sendername' => $env{'user.name'},
2817: 'senderdomain' => $env{'user.domain'},
2818: 'screenname' => $env{'environment.screenname'},
2819: 'plainname' => $env{'environment.firstname'}.' '.
2820: $env{'environment.middlename'}.' '.
2821: $env{'environment.lastname'}.' '.
2822: $env{'enrironment.generation'},
2823: 'attachmenturl'=> $attachmenturl,
2824: 'subject' => $subject);
2825: if ($env{'form.replydisc'}) {
2826: $contrib{'replyto'}=(split(/\:\:\:/,$env{'form.replydisc'}))[1];
2827: }
2828: if ($anon) {
2829: $contrib{'anonymous'}='true';
2830: }
2831: if (($symb) && ($email)) {
2832: my $now = time;
2833: if ($env{'form.editdisc'}) {
2834: $contrib{'ip'}=$ENV{'REMOTE_ADDR'};
2835: $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'};
2836: $contrib{'timestamp'} = $now;
2837: $contrib{'history'} = '';
2838: my $numoldver = 0;
2839: my ($oldsymb,$oldidx)=split(/\:\:\:/,$env{'form.editdisc'});
2840: &Apache::lonenc::check_decrypt(\$oldsymb);
2841: $oldsymb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
2842: # get timestamp for last post and history
2843: my %oldcontrib=&Apache::lonnet::restore($oldsymb,$env{'request.course.id'},
2844: $env{'course.'.$env{'request.course.id'}.'.domain'},
2845: $env{'course.'.$env{'request.course.id'}.'.num'});
2846: if (defined($oldcontrib{$oldidx.':replyto'})) {
2847: $contrib{'replyto'} = $oldcontrib{$oldidx.':replyto'};
2848: }
2849: if (defined($oldcontrib{$oldidx.':history'})) {
2850: if ($oldcontrib{$oldidx.':history'} =~ /:/) {
2851: my @oldversions = split(/:/,$oldcontrib{$oldidx.':history'});
2852: $numoldver = @oldversions;
2853: } else {
2854: $numoldver = 1;
2855: }
2856: $contrib{'history'} = $oldcontrib{$oldidx.':history'}.':';
2857: }
2858: my $numnewver = $numoldver + 1;
2859: if (defined($oldcontrib{$oldidx.':subject'})) {
2860: if ($oldcontrib{$oldidx.':subject'} =~ /^<version num="0">/) {
2861: $contrib{'subject'} = '<version num="'.$numnewver.'">'.&HTML::Entities::encode($contrib{'subject'},'<>&"').'</version>';
2862: $contrib{'subject'} = $oldcontrib{$oldidx.':subject'}.$contrib{'subject'};
2863: } else {
2864: $contrib{'subject'} = '<version num="0">'.&HTML::Entities::encode($oldcontrib{$oldidx.':subject'},'<>&"').'</version><version num="1">'.&HTML::Entities::encode($contrib{'subject'},'<>&"').'</version>';
2865: }
2866: }
2867: if (defined($oldcontrib{$oldidx.':message'})) {
2868: if ($oldcontrib{$oldidx.':message'} =~ /^<version num="0">/) {
2869: $contrib{'message'} = '<version num="'.$numnewver.'">'.&HTML::Entities::encode($contrib{'message'},'<>&"').'</version>';
2870: $contrib{'message'} = $oldcontrib{$oldidx.':message'}.$contrib{'message'};
2871: } else {
2872: $contrib{'message'} = '<version num="0">'.&HTML::Entities::encode($oldcontrib{$oldidx.':message'},'<>&"').'</version><version num="1">'.&HTML::Entities::encode($contrib{'message'},'<>&"').'</version>';
2873: }
2874: }
2875: $contrib{'history'} .= $oldcontrib{$oldidx.':timestamp'};
2876: my $put_reply = &Apache::lonnet::putstore($env{'request.course.id'},
2877: $oldsymb,$oldidx,\%contrib,
2878: $env{'course.'.$env{'request.course.id'}.'.domain'},
2879: $env{'course.'.$env{'request.course.id'}.'.num'});
2880: $status='Editing class discussion'.($anon?' (anonymous)':'');
2881: } else {
2882: $status='Adding to class discussion'.($anon?' (anonymous)':'').': '.
2883: &Apache::lonnet::store(\%contrib,$symb,$env{'request.course.id'},
2884: $env{'course.'.$env{'request.course.id'}.'.domain'},
2885: $env{'course.'.$env{'request.course.id'}.'.num'});
2886: }
2887: my %storenewentry=($symb => $now);
2888: $status.='<br />'.&mt('Updating discussion time').': '.
2889: &Apache::lonnet::put('discussiontimes',\%storenewentry,
2890: $env{'course.'.$env{'request.course.id'}.'.domain'},
2891: $env{'course.'.$env{'request.course.id'}.'.num'});
2892: }
2893: my %record=&Apache::lonnet::restore('_discussion');
2894: my ($temp)=keys(%record);
2895: unless ($temp=~/^error\:/) {
2896: my %newrecord=();
2897: $newrecord{'resource'}=$symb;
2898: $newrecord{'subnumber'}=$record{'subnumber'}+1;
2899: $status.='<br />'.&mt('Registering').': '.
2900: &Apache::lonnet::cstore(\%newrecord,'_discussion');
2901: }
2902: } else {
2903: $status.='Failed.';
2904: }
2905: return $status.'<br />';
2906: }
2907:
2908: sub get_discussion_info {
2909: my ($idx,%contrib) = @_;
2910: my $changelast = 0;
2911: my $count = 0;
2912: my $hiddenflag = 0;
2913: my $deletedflag = 0;
2914: my ($hidden,$deleted,%info,$newlastdisc);
2915: my $version = $contrib{'version'};
2916: if ($version) {
2917: for (my $id=$version; $id>0; $id--) {
2918: my $vkeys=$contrib{$id.':keys'};
2919: my @keys=split(/:/,$vkeys);
2920: if (grep(/^hidden$/,@keys)) {
2921: if (!$hiddenflag) {
2922: $hidden = $contrib{$id.':hidden'};
2923: $hiddenflag = 1;
2924: }
2925: } elsif (grep(/^deleted$/,@keys)) {
2926: if (!$deletedflag) {
2927: $deleted = $contrib{$id.':deleted'};
2928: $deletedflag = 1;
2929: }
2930: } else {
2931: if (($hidden !~/\.$id\./) && ($deleted !~/\.$id\./)) {
2932: $count++;
2933: $info{$count}{'id'} = $id;
2934: $info{$count}{'timestamp'}=$contrib{$id.':timestamp'};
2935: }
2936: }
2937: }
2938: if ($info{'1'}{'id'} == $idx) {
2939: $changelast = 1;
2940: if ($count > 1) {
2941: $newlastdisc = $info{'2'}{'timestamp'};
2942: } else {
2943: $newlastdisc = 0;
2944: }
2945: }
2946: }
2947: return ($changelast,$newlastdisc);
2948: }
2949:
2950: # ----------------------------------------------------------- Preview function
2951:
2952: sub show_preview {
2953: my ($r) = @_;
2954: &Apache::loncommon::content_type($r,'text/html');
2955: $r->send_http_header;
2956: my $start_page=
2957: &Apache::loncommon::start_page('Preview',undef,
2958: {'only_body' => 1,});
2959:
2960: my $message=&clear_out_html($env{'form.comment'});
2961: &newline_to_br(\$message);
2962: $message=&Apache::lonspeller::markeduptext($message);
2963: $message=&Apache::lontexconvert::msgtexconverted($message);
2964: my $subject=&clear_out_html($env{'form.subject'},undef,1);
2965: $subject=~s/\n/\<br \/\>/g;
2966: $subject=&Apache::lontexconvert::msgtexconverted($subject);
2967:
2968: my $end_page = &Apache::loncommon::end_page();
2969:
2970: $r->print($start_page.'<table border="2"><tr><td>'.
2971: '<b>'.&mt('Subject').':</b> '.$subject.'<br /><br />'.
2972: $message.'</td></tr></table>'.$end_page);
2973: }
2974:
2975:
2976: sub newline_to_br {
2977: my ($message)=@_;
2978: my $newmessage;
2979: my $parser=HTML::LCParser->new($message);
2980: while (my $token=$parser->get_token()) {
2981: if ($token->[0] eq 'T') {
2982: my $text=$token->[1];
2983: $text=~s/\n/\<br \/\>/g;
2984: $newmessage.=$text;
2985: } elsif ($token->[0] eq 'D' || $token->[0] eq 'C') {
2986: $newmessage.=$token->[1];
2987: } elsif ($token->[0] eq 'PI' || $token->[0] eq 'E') {
2988: $newmessage.=$token->[2];
2989: } elsif ($token->[0] eq 'S') {
2990: $newmessage.=$token->[4];
2991: }
2992:
2993: }
2994: $$message=$newmessage;
2995: }
2996:
2997: sub generate_preview_button {
2998: my ($formname,$fieldname)=@_;
2999: unless ($formname) { $formname='mailform'; }
3000: unless ($fieldname) { $fieldname='comment'; }
3001: my $pre=&mt("Show Preview and Check Spelling");
3002: return(<<ENDPREVIEW);
3003: <br />
3004: <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview">
3005: <input type="hidden" name="subject">
3006: <input type="hidden" name="comment" />
3007: <input type="button" value="$pre"
3008: onClick="if (typeof(document.$formname.onsubmit)=='function') {document.$formname.onsubmit();};this.form.comment.value=document.$formname.$fieldname.value;this.form.subject.value=document.$formname.subject.value;this.form.submit();" />
3009: </form>
3010: ENDPREVIEW
3011: }
3012:
3013: sub modify_attachments {
3014: my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
3015:
3016: my %lt = &Apache::lonlocal::texthash(
3017: 'subj' => 'Subject',
3018: 'thfo' => 'The following attachments were part of the most recent saved version of this posting.',
3019: 'chth' => 'Check the checkboxes for any you wish to remove.',
3020: 'thef' => 'The following attachments have been uploaded for inclusion with this posting.',
3021: 'adda' => 'Add a new attachment to this post.',
3022: 'stch' => 'Store Changes',
3023: );
3024: my $js = <<END;
3025: <script type="text/javascript">
3026: function setAction () {
3027: document.modattachments.action = document.modattachments.origpage.value;
3028: document.modattachments.submit();
3029: }
3030: </script>
3031: END
3032:
3033: my $start_page =
3034: &Apache::loncommon::start_page('Discussion Post Attachments',$js);
3035:
3036: my $orig_subject = &unescape($env{'form.subject'});
3037: my $subject=&clear_out_html($orig_subject,undef,1);
3038: $subject=~s/\n/\<br \/\>/g;
3039: $subject=&Apache::lontexconvert::msgtexconverted($subject);
3040: my $timestamp=$env{'form.timestamp'};
3041: my $numoldver=$env{'form.numoldver'};
3042:
3043: my $msg = '';
3044: my %attachments = ();
3045: my %currattach = ();
3046: if ($idx) {
3047: &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold);
3048: }
3049: &Apache::lonenc::check_encrypt(\$symb);
3050:
3051: my $end_page =
3052: &Apache::loncommon::end_page();
3053:
3054: $r->print(<<END);
3055: $start_page
3056: <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb">
3057: <table border="2">
3058: <tr>
3059: <td>
3060: <b>Subject:</b> $subject</b><br /><br />
3061: END
3062: if ($idx) {
3063: if ($attachmenturls) {
3064: my @currold = keys(%currattach);
3065: if (@currold > 0) {
3066: $r->print($lt{'thfo'}.'<br />'.$lt{'chth'}.'<br />'."\n");
3067: foreach my $id (@currold) {
3068: my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'});
3069: $attachurl =~ m#/([^/]+)$#;
3070: $r->print('<label><input type="checkbox" name="deloldattach" value="'.$id.'" /> '.$1.'</label><br />'."\n");
3071: }
3072: $r->print("<br />");
3073: }
3074: }
3075: }
3076: if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
3077: $r->print($lt{'thef'}.'<br />'.$lt{'chth'}.'<br />'."\n");
3078: foreach my $attach (@{$currnewattach}) {
3079: $attach =~ m#/([^/]+)$#;
3080: $r->print('<label><input type="checkbox" name="delnewattach" value="'.$attach.'" /> '.$1.'</label><br />'."\n");
3081: }
3082: $r->print("<br />");
3083: }
3084: $r->print(<<END);
3085: $lt{'adda'} <input type="file" name="addnewattach" /><input type="button" name="upload" value="Upload" onClick="this.form.submit()" />
3086: </td>
3087: </tr>
3088: </table>
3089: <input type="hidden" name="subject" value="$env{'form.subject'}" />
3090: <input type="hidden" name="comment" value="$env{'form.comment'}" />
3091: <input type="hidden" name="timestamp" value="$env{'form.timestamp'}" />
3092: <input type="hidden" name="idx" value="$env{'form.idx'}" />
3093: <input type="hidden" name="numoldver" value="$env{'form.numoldver'}" />
3094: <input type="hidden" name="origpage" value="$env{'form.origpage'}" />
3095: <input type="hidden" name="blog" value="$env{'form.blog'}" />
3096: <input type="hidden" name="discuss" value="$env{'form.discuss'}" />
3097: END
3098: foreach my $item (@{$currnewattach}) {
3099: $r->print('<input type="hidden" name="currnewattach" value="'.$item.'" />'."\n");
3100: }
3101: foreach my $item (@{$currdelold}) {
3102: $r->print('<input type="hidden" name="deloldattach" value="'.$item.'" />'."\n");
3103: }
3104: $r->print(<<END);
3105: <input type="button" name="rtntoedit" value="$lt{'stch'}" onClick="setAction()"/>
3106: </form>
3107: $end_page
3108: END
3109: return;
3110: }
3111:
3112: sub process_attachments {
3113: my ($currnewattach,$currdelold,$keepold) = @_;
3114:
3115: @{$currnewattach}=
3116: &Apache::loncommon::get_env_multiple('form.currnewattach');
3117: @{$currdelold}=
3118: &Apache::loncommon::get_env_multiple('form.deloldattach');
3119: if (exists($env{'form.delnewattach'})) {
3120: my @currdelnew =
3121: &Apache::loncommon::get_env_multiple('form.delnewattach');
3122: my @currnew = ();
3123: foreach my $newone (@{$currnewattach}) {
3124: my $delflag = 0;
3125: foreach my $item (@currdelnew) {
3126: if ($newone eq $item) {
3127: $delflag = 1;
3128: last;
3129: }
3130: }
3131: unless ($delflag) {
3132: push(@currnew, $newone);
3133: }
3134: }
3135: @{$currnewattach} = @currnew;
3136: }
3137: @{$keepold} = &Apache::loncommon::get_env_multiple('form.keepold');
3138: }
3139:
3140: sub generate_attachments_button {
3141: my ($idx,$attachnum,$ressymb,$now,$currnewattach,$deloldattach,
3142: $numoldver,$mode,$blockblog) = @_;
3143: my $origpage = $ENV{'REQUEST_URI'};
3144: my $att=$attachnum.' '.&mt("attachments");
3145: my %lt = &Apache::lonlocal::texthash(
3146: 'clic' => 'Click to add/remove attachments',
3147: );
3148: my $response = (<<END);
3149: <br />
3150: <form name="attachment" action="/adm/feedback?attach=$ressymb" method="post">
3151: $lt{'clic'}: <input type="button" value="$att"
3152: onClick="if (typeof(document.mailform.onsubmit)=='function') {document.mailform.onsubmit();};this.form.comment.value=escape(document.mailform.comment.value);this.form.subject.value=escape(document.mailform.subject.value);
3153: END
3154: if (!$blockblog) {
3155: $response .= 'setblogvalue();';
3156: }
3157: unless ($mode eq 'board') {
3158: $response .= 'javascript:anonchk();';
3159: }
3160: $response .= (<<ENDATTACH);
3161: this.form.submit();" />
3162: <input type="hidden" name="origpage" value="$origpage" />
3163: <input type="hidden" name="idx" value="$idx" />
3164: <input type="hidden" name="timestamp" value="$now" />
3165: <input type="hidden" name="subject" />
3166: <input type="hidden" name="comment" />
3167: <input type="hidden" name="blog" value = "0" />
3168: <input type="hidden" name="discuss" value = "0" />
3169: <input type="hidden" name="numoldver" value="$numoldver" />
3170: ENDATTACH
3171: if (defined($deloldattach)) {
3172: if (@{$deloldattach} > 0) {
3173: foreach my $delatt (@{$deloldattach}) {
3174: $response .= '<input type="hidden" name="deloldattach" value="'.$delatt.'" />'."\n";
3175: }
3176: }
3177: }
3178: if (defined($currnewattach)) {
3179: if (@{$currnewattach} > 0) {
3180: foreach my $attach (@{$currnewattach}) {
3181: $response .= '<input type="hidden" name="currnewattach" value="'.$attach.'" />'."\n";
3182: }
3183: }
3184: }
3185: $response .= '</form>';
3186: return $response;
3187: }
3188:
3189: sub extract_attachments {
3190: my ($attachmenturls,$idx,$numoldver,$message,$attachments,$currattach,$currdelold) = @_;
3191: %{$attachments}=();
3192: &get_post_attachments($attachments,$attachmenturls);
3193: foreach my $id (sort(keys(%{$attachments}))) {
3194: if (exists($$attachments{$id}{$numoldver})) {
3195: if (defined($currdelold)) {
3196: if (@{$currdelold} > 0) {
3197: unless (grep/^$id$/,@{$currdelold}) {
3198: $$currattach{$id} = $$attachments{$id}{$numoldver};
3199: }
3200: } else {
3201: $$currattach{$id} = $$attachments{$id}{$numoldver};
3202: }
3203: } else {
3204: $$currattach{$id} = $$attachments{$id}{$numoldver};
3205: }
3206: }
3207: }
3208: my @attached = (sort { $a <=> $b } keys(%{$currattach}));
3209: if (@attached == 1) {
3210: my $id = $attached[0];
3211: my $attachurl;
3212: if ($attachmenturls =~ m/^<attachment id="0">/) {
3213: $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'});
3214: } else {
3215: $attachurl = $$attachments{$id}{'filename'};
3216: }
3217: $attachurl=~m|/([^/]+)$|;
3218: $$message.='<br /><a href="'.$attachurl.'"><tt>'.
3219: $1.'</tt></a><br />';
3220: &Apache::lonnet::allowuploaded('/adm/feedback',
3221: $attachurl);
3222: } elsif (@attached > 1) {
3223: $$message.='<ol>';
3224: foreach my $attach (@attached) {
3225: my $id = $attach;
3226: my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'});
3227: my ($fname)
3228: =($attachurl=~m|/([^/]+)$|);
3229: $$message .= '<li><a href="'.$attachurl.
3230: '"><tt>'.
3231: $fname.'</tt></a></li>';
3232: &Apache::lonnet::allowuploaded('/adm/feedback',
3233: $attachurl);
3234: }
3235: $$message .= '</ol>';
3236: }
3237: }
3238:
3239: sub construct_attachmenturl {
3240: my ($currnewattach,$keepold,$symb,$idx)=@_;
3241: my $oldattachmenturl;
3242: my $newattachmenturl;
3243: my $startnum = 0;
3244: my $currver = 0;
3245: if (($env{'form.editdisc'}) && ($idx)) {
3246: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
3247: $env{'course.'.$env{'request.course.id'}.'.domain'},
3248: $env{'course.'.$env{'request.course.id'}.'.num'});
3249: $oldattachmenturl = $contrib{$idx.':attachmenturl'};
3250: if ($contrib{$idx.':history'}) {
3251: if ($contrib{$idx.':history'} =~ /:/) {
3252: my @oldversions = split(/:/,$contrib{$idx.':history'});
3253: $currver = 1 + scalar(@oldversions);
3254: } else {
3255: $currver = 2;
3256: }
3257: } else {
3258: $currver = 1;
3259: }
3260: if ($oldattachmenturl) {
3261: if ($oldattachmenturl =~ m/^<attachment id="0">/) {
3262: my %attachments = ();
3263: my $prevver = $currver-1;
3264: &get_post_attachments(\%attachments,$oldattachmenturl);
3265: my $numattach = scalar(keys(%attachments));
3266: $startnum += $numattach;
3267: foreach my $num (sort {$a <=> $b} keys(%attachments)) {
3268: $newattachmenturl .= '<attachment id="'.$num.'"><filename>'.$attachments{$num}{'filename'}.'</filename>';
3269: foreach my $item (sort {$a <=> $b} keys(%{$attachments{$num}})) {
3270: unless ($item eq 'filename') {
3271: $newattachmenturl .= '<post id="'.$item.'">'.$attachments{$num}{$item}.'</post>';
3272: }
3273: }
3274: if (grep/^$num$/,@{$keepold}) {
3275: $newattachmenturl .= '<post id="'.$currver.'">'.$attachments{$num}{$prevver}.'</post>';
3276: }
3277: $newattachmenturl .= '</attachment>';
3278: }
3279: } else {
3280: $newattachmenturl = '<attachment id="0"><filename>'.&HTML::Entities::encode($oldattachmenturl).'</filename><post id="0">n</post>';
3281: unless (grep/^0$/,@{$keepold}) {
3282: $newattachmenturl .= '<post id="1">n</post>';
3283: }
3284: $newattachmenturl .= '</attachment>';
3285: $startnum ++;
3286: }
3287: }
3288: }
3289: for (my $i=0; $i<@{$currnewattach}; $i++) {
3290: my $attachnum = $startnum + $i;
3291: $newattachmenturl .= '<attachment id="'.$attachnum.'"><filename>'.&HTML::Entities::encode($$currnewattach[$i]).'</filename><post id="'.$currver.'">n</post></attachment>';
3292: }
3293: return $newattachmenturl;
3294: }
3295:
3296: sub add_blog_checkbox {
3297: my ($checkstatus);
3298: if ($env{'form.blog'}) {
3299: $checkstatus = 'checked="checked"';
3300: }
3301: my $output = '
3302: <script type="text/javascript">
3303: function setblogvalue() {
3304: if (document.mailform.blog.checked) {
3305: document.attachment.blog.value = 1;
3306: } else {
3307: document.attachment.blog.value = 0;
3308: }
3309: }
3310: </script><br />
3311: <label><input type="checkbox" name="blog" '.$checkstatus.' /> '.
3312: &mt('Add to my public course blog').'</label><br />'."\n";
3313: return $output;
3314: }
3315:
3316: sub has_discussion {
3317: my $resourcesref = shift;
3318: my $navmap = Apache::lonnavmaps::navmap->new();
3319: my @allres=$navmap->retrieveResources();
3320: foreach my $resource (@allres) {
3321: if ($resource->hasDiscussion()) {
3322: my $ressymb = $resource->wrap_symb();
3323: push(@{$resourcesref}, $ressymb);
3324: }
3325: }
3326: return;
3327: }
3328:
3329: sub sort_filter_names {
3330: my ($sort_types,$role_types,$status_types) = @_;
3331: %{$sort_types} = (
3332: ascdate => 'Date order - oldest first',
3333: descdate => 'Date order - newest first',
3334: thread => 'Threaded',
3335: subject => 'By subject',
3336: username => 'By domain and username',
3337: lastfirst => 'By last name, first name'
3338: );
3339: %{$role_types} = (
3340: all => 'All roles',
3341: st => 'Students',
3342: cc => 'Course Coordinators',
3343: in => 'Instructors',
3344: ta => 'TAs',
3345: ep => 'Exam proctors',
3346: ad => 'Administrators',
3347: cr => 'Custom roles'
3348: );
3349: %{$status_types} = (
3350: all => 'Roles of any status',
3351: Active => 'Only active roles',
3352: Expired => 'Only past roles',
3353: Future => 'Only future roles',
3354: );
3355: }
3356:
3357: sub handler {
3358: my $r = shift;
3359: if ($r->header_only) {
3360: &Apache::loncommon::content_type($r,'text/html');
3361: $r->send_http_header;
3362: return OK;
3363: }
3364:
3365: # --------------------------- Get query string for limited number of parameters
3366:
3367: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
3368: ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']);
3369: my $group = $env{'form.group'};
3370: if ($env{'form.editdisc'}) {
3371: if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) {
3372: my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
3373: my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
3374: my $feedurl=&Apache::lonnet::clutter($url);
3375: &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />', '0','0','','',$env{'form.previous'},undef,undef,undef,
3376: undef,undef,undef,$group);
3377: return OK;
3378: }
3379: }
3380: if ($env{'form.discsymb'}) {
3381: my ($symb,$feedurl) = &get_feedurl_and_clean_symb($env{'form.discsymb'});
3382: my $readkey = $symb.'_read';
3383: my $chgcount = 0;
3384: my %readinghash = &Apache::lonnet::get('nohist_'.$env{'request.course.id'}.'_discuss',[$readkey],$env{'user.domain'},$env{'user.name'});
3385: foreach my $key (keys(%env)) {
3386: if ($key =~ m/^form\.postunread_(\d+)/) {
3387: if ($readinghash{$readkey} =~ /\.$1\./) {
3388: $readinghash{$readkey} =~ s/\.$1\.//;
3389: $chgcount ++;
3390: }
3391: } elsif ($key =~ m/^form\.postread_(\d+)/) {
3392: unless ($readinghash{$readkey} =~ /\.$1\./) {
3393: $readinghash{$readkey} .= '.'.$1.'.';
3394: $chgcount ++;
3395: }
3396: }
3397: }
3398: if ($chgcount > 0) {
3399: &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
3400: \%readinghash,$env{'user.domain'},$env{'user.name'});
3401: }
3402: &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'<br />',
3403: '0','0','','',$env{'form.previous'},'','','',
3404: undef,undef,undef,$group);
3405: return OK;
3406: }
3407: if ($env{'form.allversions'}) {
3408: &Apache::loncommon::content_type($r,'text/html');
3409: &Apache::loncommon::no_cache($r);
3410: $r->send_http_header;
3411:
3412: $r->print(&Apache::loncommon::start_page('Discussion Post Versions'));
3413:
3414: my $crs='/'.$env{'request.course.id'};
3415: if ($env{'request.course.sec'}) {
3416: $crs.='_'.$env{'request.course.sec'};
3417: }
3418: $crs=~s|_|/|g;
3419: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
3420: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
3421: my ($symb,$idx)=split(/\:\:\:/,$env{'form.allversions'});
3422: ($symb)=&get_feedurl_and_clean_symb($symb);
3423: my $ressymb = &wrap_symb($symb);
3424: my $group = $env{'form.group'};
3425: my $seeid;
3426: if (($group ne '') && (($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|))) {
3427: if (&check_group_priv($group,'dgp') eq 'ok') {
3428: $seeid = 1;
3429: }
3430: } else {
3431: $seeid = &Apache::lonnet::allowed('rin',$crs);
3432: }
3433: if ($idx > 0) {
3434: my %messages = ();
3435: my %subjects = ();
3436: my %attachmsgs = ();
3437: my %allattachments = ();
3438: my %imsfiles = ();
3439: my ($screenname,$plainname);
3440: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
3441: $env{'course.'.$env{'request.course.id'}.'.domain'},
3442: $env{'course.'.$env{'request.course.id'}.'.num'});
3443: $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname));
3444: }
3445: $r->print(&Apache::loncommon::end_page());
3446: return OK;
3447: }
3448: if ($env{'form.posterlist'}) {
3449: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.applysort'});
3450: &print_showposters($r,$symb,$env{'form.previous'},$feedurl,
3451: $env{'form.sortposts'});
3452: return OK;
3453: }
3454: if ($env{'form.userpick'}) {
3455: my @posters = &Apache::loncommon::get_env_multiple('form.stuinfo');
3456: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.userpick'});
3457: my $numpicks = @posters;
3458: my %discinfo;
3459: $discinfo{$symb.'_userpick'} = join('&',@posters);
3460: &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
3461: \%discinfo,$env{'user.domain'},$env{'user.name'});
3462: &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',
3463: '',$env{'form.previous'},$env{'form.sortposts'},'','','',
3464: '',$numpicks,$group);
3465: return OK;
3466: }
3467: if ($env{'form.applysort'}) {
3468: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.applysort'});
3469: &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',
3470: '',$env{'form.previous'},$env{'form.sortposts'},
3471: $env{'form.rolefilter'},$env{'form.statusfilter'},
3472: $env{'form.sectionpick'},$env{'form.grouppick'},
3473: undef,$group);
3474: return OK;
3475: } elsif ($env{'form.cmd'} eq 'sortfilter') {
3476: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
3477: &print_sortfilter_options($r,$symb,$env{'form.previous'},$feedurl);
3478: return OK;
3479: } elsif ($env{'form.navtime'}) {
3480: my %discinfo = ();
3481: my @resources = ();
3482: if (defined($env{'form.navmaps'})) {
3483: if ($env{'form.navmaps'} =~ /:/) {
3484: @resources = split(/:/,$env{'form.navmaps'});
3485: } else {
3486: @resources = ("$env{'form.navmaps'}");
3487: }
3488: } else {
3489: &has_discussion(\@resources);
3490: }
3491: my $numitems = @resources;
3492: my $feedurl = '/adm/navmaps';
3493: if ($env{'form.navurl'}) { $feedurl .= '?'.$env{'form.navurl'}; }
3494: my %lt = &Apache::lonlocal::texthash(
3495: 'mnpa' => 'Marked "New" posts as read in a total of',
3496: 'robb' => 'resources/bulletin boards.',
3497: 'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.'
3498: );
3499: foreach my $res (@resources) {
3500: my $ressymb=$res;
3501: &Apache::lonenc::check_decrypt(\$ressymb);
3502: my $lastkey = $ressymb.'_lastread';
3503: $discinfo{$lastkey} = $env{'form.navtime'};
3504: }
3505: my $textline = "<b>$lt{'mnpa'} $numitems $lt{'robb'}</b>";
3506: if ($numitems > 0) {
3507: &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
3508: \%discinfo,$env{'user.domain'},$env{'user.name'});
3509: } else {
3510: $textline = "<b>$lt{'twnp'}</b>";
3511: }
3512: &Apache::loncommon::content_type($r,'text/html');
3513: $r->send_http_header;
3514: my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
3515: my %onload;
3516: if ($env{'environment.remote'} ne 'off') {
3517: $onload{'onload'} =
3518: "if (window.name!='loncapaclient') { this.document.reldt.submit(); self.window.close(); }";
3519: }
3520:
3521: my $start_page=
3522: &Apache::loncommon::start_page('New posts marked as read',undef,
3523: {'redirect' => [2,$feedurl],
3524: 'only_body' => 1,
3525: 'add_entries' => \%onload});
3526: my $end_page = &Apache::loncommon::end_page();
3527: $r->print (<<ENDREDIR);
3528: $start_page
3529: <img align="right" src="$logo" />
3530: $textline
3531: <form name="reldt" action="$feedurl" target="loncapaclient">
3532: </form>
3533: <br />
3534: $end_page
3535: ENDREDIR
3536: return OK;
3537: } elsif ($env{'form.modifydisp'}) {
3538: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.modifydisp'});
3539: my ($dispchgA,$dispchgB,$markchg,$toggchg) =
3540: split(/_/,$env{'form.changes'});
3541: &print_display_options($r,$symb,$env{'form.previous'},$dispchgA,
3542: $dispchgB,$markchg,$toggchg,$feedurl);
3543: return OK;
3544: } elsif ($env{'form.markondisp'} || $env{'form.markonread'} ||
3545: $env{'form.allposts'} || $env{'form.onlyunread'} ||
3546: $env{'form.onlyunmark'} || $env{'form.toggoff'} ||
3547: $env{'form.toggon'} || $env{'form.markread'}) {
3548: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
3549: my %discinfo;
3550: # ------------------------ Modify setting for read/unread toggle for each post
3551: if ($env{'form.toggoff'}) { $discinfo{$symb.'_readtoggle'}=0; }
3552: if ($env{'form.toggon'}) { $discinfo{$symb.'_readtoggle'}=1; }
3553: # --------- Modify setting for identification of 'NEW' posts in this discussion
3554: if ($env{'form.markondisp'}) {
3555: $discinfo{$symb.'_lastread'} = time;
3556: $discinfo{$symb.'_markondisp'} = 1;
3557: }
3558: if ($env{'form.markonread'}) {
3559: if ( $env{'form.previous'} > 0 ) {
3560: $discinfo{$symb.'_lastread'} = $env{'form.previous'};
3561: }
3562: $discinfo{$symb.'_markondisp'} = 0;
3563: }
3564: # --------------------------------- Modify display setting for this discussion
3565: if ($env{'form.allposts'}) {
3566: $discinfo{$symb.'_showonlyunread'} = 0;
3567: $discinfo{$symb.'_showonlyunmark'} = 0;
3568: }
3569: if ($env{'form.onlyunread'}) { $discinfo{$symb.'_showonlyunread'} = 1; }
3570: if ($env{'form.onlyunmark'}) { $discinfo{$symb.'_showonlyunmark'} = 1; }
3571: # ----------------------------------------------------- Mark new posts not NEW
3572: if ($env{'form.markread'}) { $discinfo{$symb.'_lastread'} = time; }
3573: &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
3574: \%discinfo,$env{'user.domain'},$env{'user.name'});
3575: my $previous=$env{'form.previous'};
3576: if ($env{'form.markondisp'}) { $previous=undef; }
3577: &redirect_back($r,$feedurl,&mt('Changed display status').'<br />',
3578: '0','0','','',$previous,'','','','','','',$group);
3579: return OK;
3580: } elsif (($env{'form.hide'}) || ($env{'form.unhide'})) {
3581: # ----------------------------------------------------------------- Hide/unhide
3582: my $entry=$env{'form.hide'}?$env{'form.hide'}:$env{'form.unhide'};
3583: my ($symb,$idx)=split(/\:\:\:/,$entry);
3584: ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
3585:
3586: my $crs='/'.$env{'request.course.id'};
3587: if ($env{'request.course.sec'}) {
3588: $crs.='_'.$env{'request.course.sec'};
3589: }
3590: $crs=~s/\_/\//g;
3591: my $seeid=&Apache::lonnet::allowed('rin',$crs);
3592:
3593: if ($env{'form.hide'} && !$seeid && !(&editing_allowed($env{'form.hide'},$env{'form.group'}))) {
3594: &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />', '0','0','','',$env{'form.previous'},'','','','',
3595: undef,undef,$group,);
3596: return OK;
3597: }
3598:
3599: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
3600: $env{'course.'.$env{'request.course.id'}.'.domain'},
3601: $env{'course.'.$env{'request.course.id'}.'.num'});
3602:
3603: my $currenthidden=$contrib{'hidden'};
3604: my $currentstudenthidden=$contrib{'studenthidden'};
3605:
3606: if ($env{'form.hide'}) {
3607: $currenthidden.='.'.$idx.'.';
3608: unless ($seeid) {
3609: $currentstudenthidden.='.'.$idx.'.';
3610: }
3611: } else {
3612: $currenthidden=~s/\.$idx\.//g;
3613: }
3614: my %newhash=('hidden' => $currenthidden);
3615: if ( ($env{'form.hide'}) && (!$seeid) ) {
3616: $newhash{'studenthidden'} = $currentstudenthidden;
3617: }
3618: if ($env{'form.hide'}) {
3619: my $changelast = 0;
3620: my $newlast;
3621: ($changelast,$newlast) = &get_discussion_info($idx,%contrib);
3622: if ($changelast) {
3623: &Apache::lonnet::put('discussiontimes',{$symb => $newlast},
3624: $env{'course.'.$env{'request.course.id'}.'.domain'},
3625: $env{'course.'.$env{'request.course.id'}.'.num'});
3626: }
3627: }
3628: &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
3629: $env{'course.'.$env{'request.course.id'}.'.domain'},
3630: $env{'course.'.$env{'request.course.id'}.'.num'});
3631:
3632: &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
3633: '0','0','','',$env{'form.previous'},undef,undef,undef,
3634: undef,undef,undef,$group);
3635: return OK;
3636: } elsif ($env{'form.cmd'}=~/^(threadedoff|threadedon)$/) {
3637: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
3638: if ($env{'form.cmd'} eq 'threadedon') {
3639: &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
3640: &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on');
3641: } else {
3642: &Apache::lonnet::del('environment',['threadeddiscussion']);
3643: &Apache::lonnet::delenv('environment\.threadeddiscussion');
3644: }
3645: &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />',
3646: '0','0','','',$env{'form.previous'},undef,undef,undef,
3647: undef,undef,undef,$group);
3648: return OK;
3649: } elsif ($env{'form.deldisc'}) {
3650: # --------------------------------------------------------------- Hide for good
3651: my ($symb,$idx)=split(/\:\:\:/,$env{'form.deldisc'});
3652: ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
3653: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
3654: $env{'course.'.$env{'request.course.id'}.'.domain'},
3655: $env{'course.'.$env{'request.course.id'}.'.num'});
3656: my ($changelast,$newlast) = &get_discussion_info($idx,%contrib);
3657: if ($changelast) {
3658: &Apache::lonnet::put('discussiontimes',{$symb => $newlast},
3659: $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'});
3660: }
3661: my %newhash=('deleted' => $contrib{'deleted'}.".$idx.");
3662: &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
3663: $env{'course.'.$env{'request.course.id'}.'.domain'},
3664: $env{'course.'.$env{'request.course.id'}.'.num'});
3665: &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
3666: '0','0','','',$env{'form.previous'},undef,undef,undef,
3667: undef,undef,undef,$group);
3668: return OK;
3669: } elsif ($env{'form.preview'}) {
3670: # -------------------------------------------------------- User wants a preview
3671: &show_preview($r);
3672: return OK;
3673: } elsif ($env{'form.attach'}) {
3674: # -------------------------------------------------------- Work on attachments
3675: &Apache::loncommon::content_type($r,'text/html');
3676: $r->send_http_header;
3677: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','addnewattach','delnewattach','timestamp','numoldver','idx','discuss','blog']);
3678: my (@currnewattach,@currdelold,@keepold);
3679: &process_attachments(\@currnewattach,\@currdelold,\@keepold);
3680: if (exists($env{'form.addnewattach.filename'})) {
3681: unless (length($env{'form.addnewattach'})>131072) {
3682: my $subdir = 'feedback/'.$env{'form.timestamp'};
3683: my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir);
3684: push(@currnewattach, $newattachment);
3685: }
3686: }
3687: my $attachmenturls;
3688: my ($symb) = &get_feedurl_and_clean_symb($env{'form.attach'});
3689: my $idx = $env{'form.idx'};
3690: if ($idx) {
3691: my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
3692: $env{'course.'.$env{'request.course.id'}.'.domain'},
3693: $env{'course.'.$env{'request.course.id'}.'.num'});
3694: $attachmenturls = $contrib{$idx.':attachmenturl'};
3695: }
3696: &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,
3697: $attachmenturls);
3698: return OK;
3699: } elsif ($env{'form.export'}) {
3700: &Apache::loncommon::content_type($r,'text/html');
3701: $r->send_http_header;
3702: my ($symb,$feedurl) = &get_feedurl_and_clean_symb($env{'form.export'});
3703: my $mode='board';
3704: my $status='OPEN';
3705: my $previous=$env{'form.previous'};
3706: if ($feedurl =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) {
3707: $mode='problem';
3708: $status=$Apache::inputtags::status[-1];
3709: }
3710: my $discussion = &list_discussion($mode,$status,$symb);
3711: my $start_page =
3712: &Apache::loncommon::start_page('Resource Feedback and Discussion');
3713: my $end_page =
3714: &Apache::loncommon::end_page();
3715: $r->print($start_page.$discussion.$end_page);
3716: return OK;
3717: } else {
3718: # ------------------------------------------------------------- Normal feedback
3719: my $feedurl=$env{'form.postdata'};
3720: $feedurl=~s/^http\:\/\///;
3721: $feedurl=~s/^$ENV{'SERVER_NAME'}//;
3722: $feedurl=~s/^$ENV{'HTTP_HOST'}//;
3723: $feedurl=~s/\?.+$//;
3724:
3725: my $symb;
3726: if ($env{'form.replydisc'}) {
3727: $symb=(split(/\:\:\:/,$env{'form.replydisc'}))[0];
3728: } elsif ($env{'form.editdisc'}) {
3729: $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
3730: } elsif ($env{'form.origpage'}) {
3731: $symb="";
3732: } else {
3733: $symb=&Apache::lonnet::symbread($feedurl);
3734: }
3735: unless ($symb) {
3736: $symb=$env{'form.symb'};
3737: }
3738: if (defined($symb)) {
3739: ($symb,$feedurl)=&get_feedurl_and_clean_symb($symb);
3740: } else {
3741: # backward compatibility (bulletin boards used to be 'wrapped')
3742: &Apache::lonenc::check_decrypt(\$feedurl);
3743: &dewrapper(\$feedurl);
3744: }
3745: my $goahead=1;
3746: if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form|task)$/) {
3747: unless ($symb) { $goahead=0; }
3748: }
3749: if (!$goahead) {
3750: # Ambiguous Problem Resource
3751: $r->internal_redirect('/adm/ambiguous');
3752: return OK;
3753: }
3754: # Go ahead with feedback, no ambiguous reference
3755: unless (
3756: (
3757: ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:)
3758: )
3759: ||
3760: ($env{'request.course.id'} && ($feedurl!~m:^/adm:))
3761: ||
3762: ($env{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))
3763: ) {
3764: &Apache::loncommon::content_type($r,'text/html');
3765: $r->send_http_header;
3766: # Unable to give feedback
3767: &Apache::lonenc::check_encrypt(\$feedurl);
3768: &no_redirect_back($r,$feedurl);
3769: return OK;
3770: }
3771: # --------------------------------------------------- Print login screen header
3772: unless ($env{'form.sendit'}) {
3773: &Apache::lonenc::check_encrypt(\$feedurl);
3774: &Apache::loncommon::content_type($r,'text/html');
3775: $r->send_http_header;
3776: if (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
3777: my ($blocked,$blocktext) =
3778: &Apache::loncommon::blocking_status('boards');
3779: if ($blocked) {
3780: $r->print(&blocked_reply_or_edit($blocktext));
3781: return OK;
3782: }
3783: }
3784: my $options=&screen_header($feedurl,$symb);
3785: if ($options) {
3786: &mail_screen($r,$feedurl,$options,$symb);
3787: } else {
3788: &fail_redirect($r,$feedurl);
3789: }
3790: return OK;
3791: }
3792:
3793: # Get previous user input
3794: my $prevattempts=&Apache::loncommon::get_previous_attempt(
3795: $symb,$env{'user.name'},$env{'user.domain'},
3796: $env{'request.course.id'});
3797:
3798: # Get output from resource
3799: &Apache::lonenc::check_encrypt(\$feedurl);
3800: my $usersaw=&resource_output($feedurl);
3801:
3802: # Get resource answer (need to allow student to view grades for this to work)
3803: &Apache::lonnet::appenv(('allowed.vgr'=>'F'));
3804: my $usersymmb = &Apache::lonenc::check_encrypt($symb);
3805: my $useranswer=
3806: &Apache::loncommon::get_student_answers(
3807: $usersymb),$env{'user.name'},$env{'user.domain'},
3808: $env{'request.course.id'});
3809: &Apache::lonnet::delenv('allowed.vgr');
3810: # Get attachments, if any, and not too large
3811: my $attachmenturl='';
3812: if (($env{'form.origpage'}) || ($env{'form.editdisc'}) ||
3813: ($env{'form.replydisc'})) {
3814: my ($symb,$idx);
3815: if ($env{'form.replydisc'}) {
3816: ($symb,$idx)=split(/\:\:\:/,$env{'form.replydisc'});
3817: } elsif ($env{'form.editdisc'}) {
3818: ($symb,$idx)=split(/\:\:\:/,$env{'form.editdisc'});
3819: } elsif ($env{'form.origpage'}) {
3820: $symb = $env{'form.symb'};
3821: }
3822: &Apache::lonenc::check_decrypt(\$symb);
3823: my @currnewattach = ();
3824: my @deloldattach = ();
3825: my @keepold = ();
3826: &process_attachments(\@currnewattach,\@deloldattach,\@keepold);
3827: $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
3828: $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx);
3829: } elsif ($env{'form.attachment.filename'}) {
3830: unless (length($env{'form.attachment'})>131072) {
3831: $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback');
3832: }
3833: }
3834: # Filter HTML out of message (could be nasty)
3835: my $message=&clear_out_html($env{'form.comment'});
3836:
3837: # Assemble email
3838: my ($email,$citations)=&assemble_email($message,$prevattempts,
3839: $usersaw,$useranswer);
3840:
3841: # Who gets this?
3842: my ($typestyle,%to) = &decide_receiver($feedurl);
3843:
3844: # Actually send mail
3845: my ($status,$numsent)=&send_msg(&clear_out_html($env{'form.subject'},
3846: undef,1),
3847: $feedurl,$email,$citations,
3848: $attachmenturl,$symb,%to);
3849:
3850: # Discussion? Store that.
3851: my $numpost=0;
3852: if ( ($env{'form.discuss'} ne ''
3853: && $env{'form.discuss'} !~ /^(?:author|question|course|policy)/)
3854: || $env{'form.anondiscuss'} ne '') {
3855: my $subject = &clear_out_html($env{'form.subject'},undef,1);
3856: my $anonmode=($env{'form.discuss'} eq 'anon' || $env{'form.anondiscuss'} );
3857: $typestyle.=&adddiscuss($symb,$message,$anonmode,$attachmenturl,
3858: $subject);
3859: $numpost++;
3860: }
3861:
3862: # Add to blog?
3863:
3864: my $blog='';
3865: if ($env{'form.blog'}) {
3866: my $subject = &clear_out_html($env{'form.subject'},undef,1);
3867: $status.=&Apache::lonrss::addentry($env{'user.name'},
3868: $env{'user.domain'},
3869: 'CourseBlog_'.$env{'request.course.id'},
3870: $subject,$message,$feedurl,'public');
3871: $blog='<br />'.&mt('Added to my course blog').'<br />';
3872: }
3873:
3874: # Receipt screen and redirect back to where came from
3875: &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group);
3876: }
3877: return OK;
3878: }
3879:
3880: sub blocked_reply_or_edit {
3881: my ($blocktext) = @_;
3882: return
3883: &Apache::loncommon::start_page('Resource Feedback and Discussion').
3884: $blocktext.'<br /><br /><a href="javascript:history.go(-1)">'.
3885: &mt('Back to previous page').
3886: &Apache::loncommon::end_page();
3887: }
3888:
3889: sub wrap_symb {
3890: my ($ressymb)=@_;
3891: if ($ressymb =~ /bulletin___\d+___/) {
3892: unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
3893: $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
3894: }
3895: }
3896: return $ressymb;
3897: }
3898: sub dewrapper {
3899: my ($feedurl)=@_;
3900: if ($$feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
3901: $$feedurl=~s|^/adm/wrapper||;
3902: }
3903: }
3904:
3905: sub get_feedurl {
3906: my ($symb)=@_;
3907: my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
3908: my $feedurl = &Apache::lonnet::clutter($url);
3909: &dewrapper(\$feedurl);
3910: return $feedurl;
3911: }
3912:
3913: sub get_feedurl_and_clean_symb {
3914: my ($symb)=@_;
3915: &Apache::lonenc::check_decrypt(\$symb);
3916: # backward compatibility (bulletin boards used to be 'wrapped')
3917: unless ($symb =~ m|bulletin___\d+___adm/wrapper|) {
3918: $symb=~s|(bulletin___\d+___)|$1adm/wrapper|;
3919: }
3920: my $feedurl = &get_feedurl($symb);
3921: return ($symb,$feedurl);
3922: }
3923:
3924: sub editing_allowed {
3925: my ($postid,$group) = @_;
3926: $postid = &unescape($postid);
3927: my $can_edit = 0;
3928: if ($group ne '') {
3929: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
3930: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
3931: if ($postid =~ m|^bulletin___\d+___adm/wrapper(/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard)|) {
3932: if (&check_group_priv($group,'egp') eq 'ok') {
3933: $can_edit = 1;
3934: }
3935: return $can_edit;
3936: }
3937: }
3938: my $cid = $env{'request.course.id'};
3939: my $role = (split(/\./,$env{'request.role'}))[0];
3940: my $section = $env{'request.course.sec'};
3941: my $allow_editing_config =
3942: $env{'course.'.$cid.'.allow_discussion_post_editing'};
3943: if ($allow_editing_config =~ m/^\s*yes\s*$/i) {
3944: $can_edit = 1;
3945: } else {
3946: foreach my $editor (split(/,/,$allow_editing_config)) {
3947: my ($editor_role,$editor_sec) = split(/:/,$editor);
3948: if ($editor_role eq $role
3949: && defined($editor_sec)
3950: && defined($section)
3951: && $editor_sec eq $section) {
3952: $can_edit = 1;
3953: last;
3954: }
3955: if ($editor_role eq $role
3956: && !defined($editor_sec)) {
3957: $can_edit = 1;
3958: }
3959: }
3960: }
3961: return $can_edit;
3962: }
3963:
3964: sub check_group_priv {
3965: my ($group,$grp_priv) = @_;
3966: foreach my $priv ('mdg','vcg') {
3967: my $checkcourse = $env{'request.course.id'}.
3968: ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'');
3969: if (&Apache::lonnet::allowed($priv,$checkcourse)) {
3970: return 'ok';
3971: }
3972: }
3973: if ($grp_priv && $group ne '') {
3974: if (&Apache::lonnet::allowed($grp_priv,$env{'request.course.id'}.'/'.$group)) {
3975: return 'ok';
3976: }
3977: }
3978: return '';
3979: }
3980:
3981: sub group_args {
3982: my ($group) = @_;
3983: if ($group eq '') { return ''; }
3984: my $extra_args = '&group='.$group;
3985: if (exists($env{'form.ref'})) {
3986: $extra_args .= '&ref='.$env{'form.ref'};
3987: }
3988: return $extra_args;
3989: }
3990:
3991: sub get_resource_title {
3992: my ($symb,$feedurl) = @_;
3993: my ($restitle,$plainurl);
3994: if (defined($symb)) {
3995: my $plain_symb = &Apache::lonenc::check_decrypt($symb);
3996: $restitle = &Apache::lonnet::gettitle($plain_symb);
3997: }
3998: if (defined($feedurl)) {
3999: $plainurl = &Apache::lonenc::check_decrypt($feedurl);
4000: }
4001: if (!defined($restitle)) {
4002: if (defined($feedurl)) {
4003: $restitle = &Apache::lonnet::gettitle($plainurl);
4004: }
4005: }
4006: if ($plainurl ne $feedurl) {
4007: my ($plain_filename) = ($plainurl =~ m-/([^/]+)$-);
4008: if ($plain_filename eq $restitle) {
4009: $restitle = &mt('Untitled resource');
4010: }
4011: }
4012: if ($restitle eq '') {
4013: $restitle = &mt('Untitled resource');
4014: }
4015: return $restitle;
4016: }
4017:
4018: 1;
4019: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>