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