![]() ![]() | ![]() |
- making few more logos go against lonhttpd
1: # The LearningOnline Network 2: # Feedback 3: # 4: # $Id: lonfeedback.pm,v 1.148 2005/02/13 22:52:48 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>\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 = '<b>'.&mt('Mark unread').'?</b> <input type="checkbox" name="postunread_'.$idx.'" />'; 978: } else { 979: $ctlink = '<b>'.&mt('Mark read').'?</b> <input type="checkbox" name="postread_'.$idx.'" />'; 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: $r->print(<<END); 1440: <html> 1441: <head> 1442: <title>The LearningOnline Network with CAPA</title> 1443: <meta http-equiv="pragma" content="no-cache"></meta> 1444: $htmlheader 1445: <script type="text/javascript"> 1446: //<!-- 1447: function gosubmit() { 1448: var rec=0; 1449: if (typeof(document.mailform.elements.author)!="undefined") { 1450: if (document.mailform.elements.author.checked) { 1451: rec=1; 1452: } 1453: } 1454: if (typeof(document.mailform.elements.question)!="undefined") { 1455: if (document.mailform.elements.question.checked) { 1456: rec=1; 1457: } 1458: } 1459: if (typeof(document.mailform.elements.course)!="undefined") { 1460: if (document.mailform.elements.course.checked) { 1461: rec=1; 1462: } 1463: } 1464: if (typeof(document.mailform.elements.policy)!="undefined") { 1465: if (document.mailform.elements.policy.checked) { 1466: rec=1; 1467: } 1468: } 1469: if (typeof(document.mailform.elements.discuss)!="undefined") { 1470: if (document.mailform.elements.discuss.checked) { 1471: rec=1; 1472: } 1473: } 1474: if (typeof(document.mailform.elements.anondiscuss)!="undefined") { 1475: if (document.mailform.elements.anondiscuss.checked) { 1476: rec=1; 1477: } 1478: } 1479: 1480: if (rec) { 1481: if (typeof(document.mailform.onsubmit)=='function') { 1482: document.mailform.onsubmit(); 1483: } 1484: document.mailform.submit(); 1485: } else { 1486: alert('Please check a feedback type.'); 1487: } 1488: } 1489: $anonchk 1490: $anonscript 1491: //--> 1492: </script> 1493: </head> 1494: $bodytag 1495: <h2><tt>$title</tt></h2> 1496: <form action="/adm/feedback" method="post" name="mailform" 1497: enctype="multipart/form-data"> 1498: $prevtag 1499: <input type="hidden" name="postdata" value="$feedurl" /> 1500: END 1501: if ($ENV{'form.replydisc'}) { 1502: $r->print(<<END); 1503: <input type="hidden" name="replydisc" value="$ENV{'form.replydisc'}" /> 1504: END 1505: } elsif ($ENV{'form.editdisc'}) { 1506: $r->print(<<END); 1507: <input type="hidden" name="editdisc" value ="$ENV{'form.editdisc'}" /> 1508: <input type="hidden" name="parentmsg" value ="$parentmsg" /> 1509: END 1510: } 1511: $r->print(<<END); 1512: Please check at least one of the following feedback types: 1513: $options<hr /> 1514: $quote 1515: <p>My question/comment/feedback:</p> 1516: <p> 1517: $latexHelp 1518: Title: <input type="text" name="subject" size="30" value="$subject" /></p> 1519: <p> 1520: <textarea name="comment" id="comment" cols="60" rows="10" wrap="hard">$comment 1521: </textarea></p> 1522: <p> 1523: END 1524: if ( ($ENV{'form.editdisc'}) || ($ENV{'form.replydisc'}) ) { 1525: if ($ENV{'form.origpage'}) { 1526: foreach (@currnewattach) { 1527: $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n"); 1528: } 1529: foreach (@currdelold) { 1530: $r->print('<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n"); 1531: } 1532: } 1533: if ($ENV{'form.editdisc'}) { 1534: if ($attachmenturls) { 1535: &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold); 1536: $attachnum = scalar(keys %currattach); 1537: foreach (keys %currattach) { 1538: $r->print('<input type="hidden" name="keepold" value="'.$_.'" />'."\n"); 1539: } 1540: } 1541: } 1542: } else { 1543: $r->print(<<END); 1544: Attachment (128 KB max size): <input type="file" name="attachment" /> 1545: </p> 1546: END 1547: } 1548: $r->print(<<END); 1549: <p> 1550: <input type="hidden" name="sendit" value="1" /> 1551: <input type="button" value="$send" onClick='gosubmit();' /> 1552: </p> 1553: </form> 1554: END 1555: if ($ENV{'form.editdisc'} || $ENV{'form.replydisc'}) { 1556: my $now = time; 1557: my $ressymb = $symb; 1558: my $postidx = ''; 1559: if ($ENV{'form.editdisc'}) { 1560: $postidx = $idx; 1561: } 1562: if (@currnewattach > 0) { 1563: $attachnum += @currnewattach; 1564: } 1565: $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver)); 1566: if ($attachnum > 0) { 1567: if (@currnewattach > 0) { 1568: $newattachmsg .= '<b>New attachments</b><br />'; 1569: if (@currnewattach > 1) { 1570: $newattachmsg .= '<ol>'; 1571: foreach my $item (@currnewattach) { 1572: $item =~ m#.*/([^/]+)$#; 1573: $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n"; 1574: } 1575: $newattachmsg .= '</ol>'."\n"; 1576: } else { 1577: $currnewattach[0] =~ m#.*/([^/]+)$#; 1578: $newattachmsg .= '<a href="'.$currnewattach[0].'">'.$1.'</a><br />'."\n"; 1579: } 1580: } 1581: if ($attachmsg) { 1582: $r->print("<b>Retained attachments</b>:$attachmsg<br />\n"); 1583: } 1584: if ($newattachmsg) { 1585: $r->print("$newattachmsg<br />"); 1586: } 1587: } 1588: } 1589: $r->print(&generate_preview_button(). 1590: &Apache::lonhtmlcommon::htmlareaselectactive('comment'). 1591: '</body></html>'); 1592: } 1593: 1594: sub print_display_options { 1595: my ($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl) = @_; 1596: &Apache::loncommon::content_type($r,'text/html'); 1597: $r->send_http_header; 1598: 1599: my $function = &Apache::loncommon::get_users_function(); 1600: my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg', 1601: $ENV{'user.domain'}); 1602: my $bodytag=&Apache::loncommon::bodytag('Discussion options', 1603: '',''); 1604: 1605: my %lt = &Apache::lonlocal::texthash( 1606: 'dido' => 'Discussion display options', 1607: 'pref' => 'Display Preference', 1608: 'curr' => 'Current setting ', 1609: 'actn' => 'Action', 1610: 'deff' => 'Default for all discussions', 1611: 'prca' => 'Preferences can be set for this discussion that determine ....', 1612: 'whpo' => 'Which posts are displayed when you display this bulletin board or resource, and', 1613: 'unwh' => 'Under what circumstances posts are identified as "NEW", and', 1614: 'wipa' => 'Whether individual posts can be marked as read/unread', 1615: 'allposts' => 'All posts', 1616: 'unread' => 'New posts only', 1617: 'unmark' => 'Posts not marked read', 1618: 'ondisp' => 'Once displayed', 1619: 'onmark' => 'Once marked not NEW ', 1620: 'toggon' => 'Shown', 1621: 'toggoff' => 'Not shown', 1622: 'disa' => 'Posts displayed?', 1623: 'npmr' => 'New posts cease to be identified as "NEW"?', 1624: 'dotm' => 'Option to mark each post as read/unread?', 1625: 'chgt' => 'Change to ', 1626: 'mkdf' => 'Set to ', 1627: 'yhni' => 'You have not indicated that you wish to change any of the discussion settings', 1628: 'ywbr' => 'You will be returned to the previous page if you click OK.' 1629: ); 1630: 1631: my $dispchangeA = $lt{'unread'}; 1632: my $dispchangeB = $lt{'unmark'}; 1633: my $markchange = $lt{'ondisp'}; 1634: my $toggchange = $lt{'toggon'}; 1635: my $currdisp = $lt{'allposts'}; 1636: my $currmark = $lt{'onmark'}; 1637: my $discdisp = 'allposts'; 1638: my $discmark = 'onmark'; 1639: my $currtogg = $lt{'toggoff'}; 1640: my $disctogg = 'toggoff'; 1641: 1642: if ($dispchgA eq 'allposts') { 1643: $dispchangeA = $lt{'allposts'}; 1644: $currdisp = $lt{'unread'}; 1645: $discdisp = 'unread'; 1646: } 1647: 1648: if ($markchg eq 'markonread') { 1649: $markchange = $lt{'onmark'}; 1650: $currmark = $lt{'ondisp'}; 1651: $discmark = 'ondisp'; 1652: } 1653: 1654: if ($dispchgB eq 'onlyunread') { 1655: $dispchangeB = $lt{'unread'}; 1656: $currdisp = $lt{'unmark'}; 1657: $discdisp = 'unmark'; 1658: } 1659: if ($toggchg eq 'toggoff') { 1660: $toggchange = $lt{'toggoff'}; 1661: $currtogg = $lt{'toggon'}; 1662: $disctogg = 'toggon'; 1663: } 1664: $r->print(<<END); 1665: <html> 1666: <head> 1667: <title>$lt{'dido'}</title> 1668: <meta http-equiv="pragma" content="no-cache" /> 1669: <script> 1670: function discdispChk(caller) { 1671: var disctogg = '$toggchg' 1672: if (caller == 0) { 1673: if (document.modifydisp.discdisp[0].checked == true) { 1674: if (document.modifydisp.discdisp[1].checked == true) { 1675: document.modifydisp.discdisp[1].checked = false 1676: } 1677: } 1678: } 1679: if (caller == 1) { 1680: if (document.modifydisp.discdisp[1].checked == true) { 1681: if (document.modifydisp.discdisp[0].checked == true) { 1682: document.modifydisp.discdisp[0].checked = false 1683: } 1684: if (disctogg == 'toggon') { 1685: document.modifydisp.disctogg.checked = true 1686: } 1687: if (disctogg == 'toggoff') { 1688: document.modifydisp.disctogg.checked = false 1689: } 1690: } 1691: } 1692: if (caller == 2) { 1693: var dispchgB = '$dispchgB' 1694: if (disctogg == 'toggoff') { 1695: if (document.modifydisp.disctogg.checked == true) { 1696: if (dispchgB == 'onlyunmark') { 1697: document.modifydisp.discdisp[1].checked = false 1698: } 1699: } 1700: } 1701: } 1702: } 1703: 1704: function setDisp() { 1705: var prev = "$previous" 1706: var chktotal = 0 1707: if (document.modifydisp.discdisp[0].checked == true) { 1708: document.modifydisp.$dispchgA.value = "$symb" 1709: chktotal ++ 1710: } 1711: if (document.modifydisp.discdisp[1].checked == true) { 1712: document.modifydisp.$dispchgB.value = "$symb" 1713: chktotal ++ 1714: } 1715: if (document.modifydisp.discmark.checked == true) { 1716: document.modifydisp.$markchg.value = "$symb" 1717: chktotal ++ 1718: } 1719: if (document.modifydisp.disctogg.checked == true) { 1720: document.modifydisp.$toggchg.value = "$symb" 1721: chktotal ++ 1722: } 1723: if (chktotal > 0) { 1724: document.modifydisp.submit() 1725: } else { 1726: if(confirm("$lt{'yhni'}. \\n$lt{'ywbr'}")) { 1727: if (prev > 0) { 1728: location.href = "$feedurl?previous=$previous" 1729: } else { 1730: location.href = "$feedurl" 1731: } 1732: } 1733: } 1734: } 1735: </script> 1736: </head> 1737: $bodytag 1738: <form name="modifydisp" method="post" action="/adm/feedback"> 1739: $lt{'sdpf'}<br/> $lt{'prca'} <ol><li>$lt{'whpo'}</li><li>$lt{'unwh'}</li><li>$lt{'wipa'}</li></ol> 1740: <br /> 1741: <table border="0" cellpadding="0" cellspacing="0"> 1742: <tr> 1743: <td width="100%" bgcolor="#000000"> 1744: <table width="100%" border="0" cellpadding="1" cellspacing="0"> 1745: <tr> 1746: <td width="100%" bgcolor="#000000"> 1747: <table border="0" cellpadding="3" cellspacing="1" bgcolor="#FFFFFF"> 1748: <tr bgcolor="$tabcolor"> 1749: <td><b>$lt{'pref'}</b></td> 1750: <td><b>$lt{'curr'}</b></td> 1751: <td><b>$lt{'actn'}?</b></td> 1752: </tr> 1753: <tr bgcolor="#dddddd"> 1754: <td>$lt{'disa'}</td> 1755: <td>$lt{$discdisp}</td> 1756: <td><input type="checkbox" name="discdisp" onClick="discdispChk('0')" /> $lt{'chgt'} "$dispchangeA" 1757: <br /> 1758: <input type="checkbox" name="discdisp" onClick="discdispChk('1')" /> $lt{'chgt'} "$dispchangeB" 1759: </td> 1760: </tr><tr bgcolor="#eeeeee"> 1761: <td>$lt{'npmr'}</td> 1762: <td>$lt{$discmark}</td> 1763: <td><input type="checkbox" name="discmark" />$lt{'chgt'} "$markchange"</td> 1764: </tr><tr bgcolor="#dddddd"> 1765: <td>$lt{'dotm'}</td> 1766: <td>$lt{$disctogg}</td> 1767: <td><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</td> 1768: </tr> 1769: </table> 1770: </td> 1771: </tr> 1772: </table> 1773: </td> 1774: </tr> 1775: </table> 1776: <br /> 1777: <br /> 1778: <input type="hidden" name="symb" value="$symb" /> 1779: <input type="hidden" name="previous" value="$previous" /> 1780: <input type="hidden" name="$dispchgA" value=""/> 1781: <input type="hidden" name="$dispchgB" value=""/> 1782: <input type="hidden" name="$markchg" value=""/> 1783: <input type="hidden" name="$toggchg" value="" /> 1784: <input type="button" name="sub" value="Store Changes" onClick="javascript:setDisp()" /> 1785: <br /> 1786: <br /> 1787: </form> 1788: </body> 1789: </html> 1790: END 1791: return; 1792: } 1793: 1794: sub print_sortfilter_options { 1795: my ($r,$symb,$previous,$feedurl) = @_; 1796: 1797: &Apache::loncommon::content_type($r,'text/html'); 1798: $r->send_http_header; 1799: 1800: &Apache::lonenc::check_encrypt(\$symb); 1801: my @sections = (); 1802: my $section_sel = ''; 1803: my $numsections = 0; 1804: my $numvisible = 5; 1805: my %sectioncount = (); 1806: 1807: $numsections = &Apache::loncommon::get_sections($ENV{'course.'.$ENV{'request.course.id'}.'.domain'},$ENV{'course.'.$ENV{'request.course.id'}.'.num'},\%sectioncount); 1808: 1809: if ($ENV{'request.course.sec'} !~ /^\s*$/) { #Restrict section choice to current section 1810: @sections = ('all',$ENV{'request.course.sec'}); 1811: $numvisible = 2; 1812: } else { 1813: @sections = sort {$a cmp $b} keys(%sectioncount); 1814: unshift(@sections,'all'); # Put 'all' at the front of the list 1815: if ($numsections < 4) { 1816: $numvisible = $numsections + 1; 1817: } 1818: } 1819: foreach (@sections) { 1820: $section_sel .= " <option value=\"$_\" />$_\n"; 1821: } 1822: 1823: my $function = &Apache::loncommon::get_users_function(); 1824: my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg', 1825: $ENV{'user.domain'}); 1826: my $bodytag=&Apache::loncommon::bodytag('Discussion options', 1827: '',''); 1828: my %lt = &Apache::lonlocal::texthash( 1829: 'diso' => 'Discussion sorting and filtering options', 1830: 'diop' => 'Display Options', 1831: 'curr' => 'Current setting ', 1832: 'actn' => 'Action', 1833: 'prca' => 'Set options that control the sort order of posts, and/or which posts are displayed.', 1834: 'soor' => 'Sort order', 1835: 'spur' => 'Specific user roles', 1836: 'sprs' => 'Specific role status', 1837: 'spse' => 'Specific sections', 1838: 'psub' => 'Pick specific users (by name)', 1839: 'shal' => 'Show a list of current posters' 1840: ); 1841: 1842: my %sort_types = (); 1843: my %role_types = (); 1844: my %status_types = (); 1845: &sort_filter_names(\%sort_types,\%role_types,\%status_types); 1846: 1847: $r->print(<<END); 1848: <html> 1849: <head> 1850: <title>$lt{'diso'}</title> 1851: <meta http-equiv="pragma" content="no-cache" /> 1852: <script type="text/javascript"> 1853: function verifyFilter() { 1854: var rolenum = 0 1855: for (var i=0; i<document.modifyshown.rolefilter.length; i++) { 1856: if (document.modifyshown.rolefilter.options[i].selected == true) { 1857: rolenum ++ 1858: } 1859: } 1860: if (rolenum == 0) { 1861: document.modifyshown.rolefilter.options[0].selected = true 1862: } 1863: 1864: var secnum = 0 1865: for (var i=0; i<document.modifyshown.sectionpick.length; i++) { 1866: if (document.modifyshown.sectionpick.options[i].selected == true) { 1867: secnum ++ 1868: } 1869: } 1870: if (secnum == 0) { 1871: document.modifyshown.sectionpick.options[0].selected = true 1872: } 1873: document.modifyshown.submit(); 1874: } 1875: </script> 1876: </head> 1877: $bodytag 1878: <form name="modifyshown" method="post" action="/adm/feedback"> 1879: <b>$lt{'diso'}</b><br/> $lt{'prca'} 1880: <br /><br /> 1881: <table border="0"> 1882: <tr> 1883: <td><b>$lt{'soor'}</b></td> 1884: <td> </td> 1885: <td><b>$lt{'sprs'}</b></td> 1886: <td> </td> 1887: <td><b>$lt{'spur'}</b></td> 1888: <td> </td> 1889: <td><b>$lt{'spse'}</b></td> 1890: <td> </td> 1891: <td><b>$lt{'psub'}</b></td> 1892: </tr> 1893: <tr> 1894: <td align="center"> 1895: <select name="sortposts"> 1896: <option value="ascdate" selected="selected" />$sort_types{'ascdate'} 1897: <option value="descdate" />$sort_types{'descdate'} 1898: <option value="thread" />$sort_types{'thread'} 1899: <option value="subject" />$sort_types{'subject'} 1900: <option value="username" />$sort_types{'username'} 1901: <option value="lastfirst" />$sort_types{'lastfirst'} 1902: </select> 1903: </td> 1904: <td> </td> 1905: <td align="center"> 1906: <select name="statusfilter"> 1907: <option value="all" selected="selected" />$status_types{'all'} 1908: <option value="Active" />$status_types{'Active'} 1909: <option value="Expired" />$status_types{'Expired'} 1910: </select> 1911: </td> 1912: <td> </td> 1913: <td align="center"> 1914: <select name="rolefilter" multiple="true" size="5"> 1915: <option value="all" />$role_types{'all'} 1916: <option value="st" />$role_types{'st'} 1917: <option value="cc" />$role_types{'cc'} 1918: <option value="in" />$role_types{'in'} 1919: <option value="ta" />$role_types{'ta'} 1920: <option value="ep" />$role_types{'ep'} 1921: <option value="ad" />$role_types{'ad'} 1922: <option value="cr" />$role_types{'cr'} 1923: </select> 1924: </td> 1925: <td> </td> 1926: <td align="center"> 1927: <select name="sectionpick" multiple="true" size="$numvisible"> 1928: $section_sel 1929: </select> 1930: </td> 1931: <td> </td> 1932: <td><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</td> 1933: </tr> 1934: </table> 1935: <br /> 1936: <br /> 1937: <input type="hidden" name="previous" value="$previous" /> 1938: <input type="hidden" name="applysort" value="$symb" /> 1939: <input type="button" name="sub" value="Store Changes" onClick="verifyFilter()" /> 1940: <br /> 1941: <br /> 1942: </form> 1943: </body> 1944: </html> 1945: END 1946: } 1947: 1948: sub print_showposters { 1949: my ($r,$symb,$previous,$feedurl,$sortposts) = @_; 1950: 1951: &Apache::lonenc::check_encrypt(\$symb); 1952: my $crs='/'.$ENV{'request.course.id'}; 1953: if ($ENV{'request.course.sec'}) { 1954: $crs.='_'.$ENV{'request.course.sec'}; 1955: } 1956: $crs=~s/\_/\//g; 1957: my $seeid=&Apache::lonnet::allowed('rin',$crs); 1958: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 1959: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 1960: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 1961: my %namesort = (); 1962: my %postcounts = (); 1963: my %lt=&Apache::lonlocal::texthash( 1964: 'diso' => 'Discussion filtering options', 1965: ); 1966: my $bodytag=&Apache::loncommon::bodytag('Discussion options', 1967: '',''); 1968: if ($contrib{'version'}) { 1969: for (my $idx=1;$idx<=$contrib{'version'};$idx++) { 1970: my $hidden=($contrib{'hidden'}=~/\.$idx\./); 1971: my $deleted=($contrib{'deleted'}=~/\.$idx\./); 1972: unless ((($hidden) && (!$seeid)) || ($deleted)) { 1973: if ((!$contrib{$idx.':anonymous'}) || ($seeid)) { 1974: my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'}); 1975: my $lastname = $names{'lastname'}; 1976: my $firstname = $names{'firstname'}; 1977: if ($lastname eq '') { 1978: $lastname = '_'; 1979: } 1980: if ($firstname eq '') { 1981: $firstname = '_'; 1982: } 1983: unless (defined($namesort{$lastname})) { 1984: %{$namesort{$lastname}} = (); 1985: } 1986: my $poster = $contrib{$idx.':sendername'}.':'.$contrib{$idx.':senderdomain'}; 1987: $postcounts{$poster} ++; 1988: if (defined($namesort{$lastname}{$firstname})) { 1989: if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) { 1990: push @{$namesort{$lastname}{$firstname}}, $poster; 1991: } 1992: } else { 1993: @{$namesort{$lastname}{$firstname}} = ("$poster"); 1994: } 1995: } 1996: } 1997: } 1998: } 1999: $r->print(<<END); 2000: <html> 2001: <head> 2002: <title>$lt{'diso'}</title> 2003: <meta http-equiv="pragma" content="no-cache" /> 2004: </head> 2005: $bodytag 2006: <form name="pickpostersform" method="post"> 2007: <table border="0"> 2008: <tr> 2009: <td bgcolor="#777777"> 2010: <table border="0" cellpadding="3"> 2011: <tr bgcolor="#e6ffff"> 2012: <td><b>No.</b></td> 2013: <td><b>Select</b></td> 2014: <td><b>Fullname</b><font color="#999999">(Username/domain)</font></td> 2015: <td><b>Posts</td> 2016: </tr> 2017: END 2018: my $count = 0; 2019: foreach my $last (sort keys %namesort) { 2020: foreach my $first (sort keys %{$namesort{$last}}) { 2021: foreach (sort @{$namesort{$last}{$first}}) { 2022: my ($uname,$udom) = split/:/,$_; 2023: if (!$uname || !$udom) { 2024: next; 2025: } else { 2026: $count ++; 2027: $r->print('<tr bgcolor="#ffffe6"><td align="right">'.$count.'</td><td align="center"><input name="stuinfo" type="checkbox" value="'.$_.'" /></td><td>'.$last.', '.$first.' ('.$uname.','.$udom.')</td><td>'.$postcounts{$_}.'</td></tr>'); 2028: } 2029: } 2030: } 2031: } 2032: $r->print(<<END); 2033: </table> 2034: </td> 2035: </tr> 2036: </table> 2037: <br /> 2038: <input type="hidden" name="sortposts" value="$sortposts" /> 2039: <input type="hidden" name="userpick" value="$symb" /> 2040: <input type="button" name="store" value="Display posts" onClick="javascript:document.pickpostersform.submit()" /> 2041: </form> 2042: </body> 2043: </html> 2044: END 2045: } 2046: 2047: sub get_post_versions { 2048: my ($versions,$incoming,$htmldecode,$numver) = @_; 2049: if ($incoming =~ /^<version num="0">/) { 2050: my $p = HTML::LCParser->new(\$incoming); 2051: my $done = 0; 2052: while ( (my $token = $p->get_tag("version")) && (!$done)) { 2053: my $num = $token->[1]{num}; 2054: my $text = $p->get_text("/version"); 2055: if (defined($numver)) { 2056: if ($num == $numver) { 2057: if ($htmldecode) { 2058: $text = &HTML::Entities::decode($text); 2059: } 2060: $$versions{$numver}=$text; 2061: $done = 1; 2062: } 2063: } else { 2064: if ($htmldecode) { 2065: $text = &HTML::Entities::decode($text); 2066: } 2067: $$versions{$num}=$text; 2068: } 2069: } 2070: } else { 2071: if (!defined($numver)) { 2072: $numver = 0; 2073: } 2074: if ($htmldecode) { 2075: $$versions{$numver} = $incoming; 2076: } else { 2077: $$versions{$numver} = &HTML::Entities::encode($incoming,'<>&"'); 2078: } 2079: } 2080: return; 2081: } 2082: 2083: sub get_post_attachments { 2084: my ($attachments,$attachmenturls) = @_; 2085: my $num; 2086: if ($attachmenturls =~ m/^<attachment id="0">/) { 2087: my $p = HTML::LCParser->new(\$attachmenturls); 2088: while (my $token = $p->get_tag("attachment","filename","post")) { 2089: if ($token->[0] eq "attachment") { 2090: $num = $token->[1]{id}; 2091: %{$$attachments{$num}} =(); 2092: } elsif ($token->[0] eq "filename") { 2093: $$attachments{$num}{'filename'} = $p->get_text("/filename"); 2094: } elsif ($token->[0] eq "post") { 2095: my $id = $token->[1]{id}; 2096: $$attachments{$num}{$id} = $p->get_text("/post"); 2097: } 2098: } 2099: } else { 2100: %{$$attachments{'0'}} = (); 2101: $$attachments{'0'}{'filename'} = $attachmenturls; 2102: $$attachments{'0'}{'0'} = 'n'; 2103: } 2104: 2105: return; 2106: } 2107: 2108: sub fail_redirect {; 2109: my ($r,$feedurl) = @_; 2110: if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; 2111: $r->print (<<ENDFAILREDIR); 2112: <html> 2113: <head><title>Feedback not sent</title> 2114: <meta http-equiv="pragma" content="no-cache" /> 2115: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" /> 2116: </head> 2117: <body bgcolor="#FFFFFF"> 2118: <img align="right" src="/adm/lonIcons/lonlogos.gif" /> 2119: <b>Sorry, no recipients ...</b> 2120: <br /><a href="$feedurl">Continue</a> 2121: </body> 2122: </html> 2123: ENDFAILREDIR 2124: } 2125: 2126: sub redirect_back { 2127: my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$numpicks) = @_; 2128: my $sorttag = ''; 2129: my $roletag = ''; 2130: my $statustag = ''; 2131: my $sectag = ''; 2132: my $userpicktag = ''; 2133: my $qrystr = ''; 2134: my $prevtag = ''; 2135: 2136: &Apache::loncommon::content_type($r,'text/html'); 2137: $r->send_http_header; 2138: 2139: &dewrapper(\$feedurl); 2140: if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' }; 2141: if ($previous > 0) { 2142: $qrystr = 'previous='.$previous; 2143: if ($feedurl =~ /\?register=1/) { 2144: $feedurl .= '&'.$qrystr; 2145: } else { 2146: $feedurl .= '?'.$qrystr; 2147: } 2148: $prevtag = '<input type="hidden" name="previous" value="'.$previous.'" />'; 2149: } 2150: if (defined($sort)) { 2151: my $sortqry = 'sortposts='.$sort; 2152: if (($feedurl =~ /\?register=1/) || ($feedurl =~ /\?previous=/)) { 2153: $feedurl .= '&'.$sortqry; 2154: } else { 2155: $feedurl .= '?'.$sortqry; 2156: } 2157: $sorttag = '<input type="hidden" name="sortposts" value="'.$sort.'" />'; 2158: if (defined($numpicks)) { 2159: my $userpickqry = 'totposters='.$numpicks; 2160: $feedurl .= '&'.$userpickqry; 2161: $userpicktag = '<input type="hidden" name="totposters" value="'.$numpicks.'" />'; 2162: } else { 2163: if (ref($sectionpick) eq 'ARRAY') { 2164: $feedurl .= '§ionpick='; 2165: $sectag .= '<input type="hidden" name="sectionpick" value="'; 2166: foreach (@{$sectionpick}) { 2167: $feedurl .= $_.','; 2168: $sectag .= $_.','; 2169: } 2170: $feedurl =~ s/,$//; 2171: $sectag =~ s/,$//; 2172: $sectag .= '" />'; 2173: } else { 2174: $feedurl .= '§ionpick='.$sectionpick; 2175: $sectag = '<input type="hidden" name="sectionpick" value="'.$sectionpick.'" />'; 2176: } 2177: if (ref($rolefilter) eq 'ARRAY') { 2178: $feedurl .= '&rolefilter='; 2179: $roletag .= '<input type="hidden" name="rolefilter" value="'; 2180: foreach (@{$rolefilter}) { 2181: $feedurl .= $_.','; 2182: $roletag .= $_.','; 2183: } 2184: $feedurl =~ s/,$//; 2185: $roletag =~ s/,$//; 2186: $roletag .= '" />'; 2187: } else { 2188: $feedurl .= '&rolefilter='.$rolefilter; 2189: $roletag = '<input type="hidden" name="rolefilter" value="'.$rolefilter.'" />'; 2190: } 2191: $feedurl .= '&statusfilter='.$statusfilter; 2192: $statustag ='<input type="hidden" name="statusfilter" value="'.$statusfilter.'" />'; 2193: } 2194: } 2195: $feedurl=&Apache::lonenc::check_encrypt($feedurl); 2196: $r->print (<<ENDREDIR); 2197: <html> 2198: <head> 2199: <title>Feedback sent</title> 2200: <meta http-equiv="pragma" content="no-cache" /> 2201: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" /> 2202: </head> 2203: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'> 2204: <img align="right" src="/adm/lonIcons/lonlogos.gif" /> 2205: $typestyle 2206: <b>Sent $sendsomething message(s), and $sendposts post(s).</b> 2207: <font color="red">$status</font> 2208: <form name="reldt" action="$feedurl" target="loncapaclient"> 2209: $prevtag 2210: $sorttag 2211: $statustag 2212: $roletag 2213: $sectag 2214: $userpicktag 2215: </form> 2216: <br /><a href="$feedurl">Continue</a> 2217: </body> 2218: </html> 2219: ENDREDIR 2220: } 2221: 2222: sub no_redirect_back { 2223: my ($r,$feedurl) = @_; 2224: my $nofeed=&mt('Sorry, no feedback possible on this resource ...'); 2225: my $continue=&mt('Continue'); 2226: $r->print (<<ENDNOREDIR); 2227: <html> 2228: <head><title>Feedback not sent</title> 2229: <meta http-equiv="pragma" content="no-cache" /> 2230: ENDNOREDIR 2231: 2232: if ($feedurl!~/^\/adm\/feedback/) { 2233: $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2; url='. 2234: &Apache::lonenc::check_encrypt($feedurl).'">'); 2235: } 2236: $feedurl=&Apache::lonenc::check_encrypt($feedurl); 2237: $r->print (<<ENDNOREDIRTWO); 2238: </head> 2239: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'> 2240: <img align="right" src="/adm/lonIcons/lonlogos.gif" /> 2241: <b>$nofeed</b> 2242: <br /><a href="$feedurl">$continue</a> 2243: </body> 2244: </html> 2245: ENDNOREDIRTWO 2246: } 2247: 2248: sub screen_header { 2249: my ($feedurl,$symb) = @_; 2250: my $msgoptions=''; 2251: my $discussoptions=''; 2252: unless (($ENV{'form.replydisc'}) || ($ENV{'form.editdisc'})) { 2253: if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) { 2254: $msgoptions= 2255: '<p><input type="checkbox" name="author" /> '. 2256: &mt('Feedback to resource author').'</p>'; 2257: } 2258: if (&feedback_available(1)) { 2259: $msgoptions.= 2260: '<br /><input type="checkbox" name="question" /> '. 2261: &mt('Question about resource content'); 2262: } 2263: if (&feedback_available(0,1)) { 2264: $msgoptions.= 2265: '<br /><input type="checkbox" name="course" /> '. 2266: &mt('Question/Comment/Feedback about course content'); 2267: } 2268: if (&feedback_available(0,0,1)) { 2269: $msgoptions.= 2270: '<br /><input type="checkbox" name="policy" /> '. 2271: &mt('Question/Comment/Feedback about course policy'); 2272: } 2273: } 2274: if ($ENV{'request.course.id'}) { 2275: if (&discussion_open(undef,$symb) && 2276: &Apache::lonnet::allowed('pch', 2277: $ENV{'request.course.id'}. 2278: ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { 2279: $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '. 2280: ($ENV{'form.replydisc'}?' checked="1"':'').' /> '. 2281: &mt('Contribution to course discussion of resource'); 2282: $discussoptions.='<br /><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '. 2283: &mt('Anonymous contribution to course discussion of resource'). 2284: ' <i>('.&mt('name only visible to course faculty').')</i>'; 2285: } 2286: } 2287: if ($msgoptions) { $msgoptions='<h2><img src="/adm/lonMisc/feedback.gif" />'.&mt('Sending Messages').'</h2>'.$msgoptions; } 2288: if ($discussoptions) { 2289: $discussoptions='<h2><img src="/adm/lonMisc/chat.gif" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; } 2290: return $msgoptions.$discussoptions; 2291: } 2292: 2293: sub resource_output { 2294: my ($feedurl) = @_; 2295: my $usersaw=&Apache::lonnet::ssi_body($feedurl); 2296: $usersaw=~s/\<body[^\>]*\>//gi; 2297: $usersaw=~s/\<\/body\>//gi; 2298: $usersaw=~s/\<html\>//gi; 2299: $usersaw=~s/\<\/html\>//gi; 2300: $usersaw=~s/\<head\>//gi; 2301: $usersaw=~s/\<\/head\>//gi; 2302: $usersaw=~s/action\s*\=/would_be_action\=/gi; 2303: return $usersaw; 2304: } 2305: 2306: sub clear_out_html { 2307: my ($message,$override)=@_; 2308: unless (&Apache::lonhtmlcommon::htmlareablocked()) { return $message; } 2309: # Always allow the <m>-tag 2310: my %html=(M=>1); 2311: # Check if more is allowed 2312: my $cid=$ENV{'request.course.id'}; 2313: if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) || 2314: ($override)) { 2315: # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG> 2316: # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB> 2317: # <SUP> 2318: %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1, 2319: BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1, 2320: M=>1, SUB=>1, SUP=>1, SPAN=>1, 2321: H1=>1, H2=>1, H3=>1, H4=>1, H5=>1); 2322: } 2323: # Do the substitution of everything that is not explicitly allowed 2324: $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/ 2325: {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\<$1"}/ge; 2326: $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/ 2327: {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\>"}/ge; 2328: return $message; 2329: } 2330: 2331: sub assemble_email { 2332: my ($feedurl,$message,$prevattempts,$usersaw,$useranswer)=@_; 2333: my $email=<<"ENDEMAIL"; 2334: $message 2335: ENDEMAIL 2336: my $citations=<<"ENDCITE"; 2337: <h2>Previous attempts of student (if applicable)</h2> 2338: $prevattempts 2339: <br /><hr /> 2340: <h2>Original screen output (if applicable)</h2> 2341: $usersaw 2342: <h2>Correct Answer(s) (if applicable)</h2> 2343: $useranswer 2344: ENDCITE 2345: return ($email,$citations); 2346: } 2347: 2348: sub secapply { 2349: my $rec=shift; 2350: my $defaultflag=shift; 2351: $rec=~s/\s+//g; 2352: $rec=~s/\@/\:/g; 2353: my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/); 2354: if ($sections) { 2355: foreach (split(/\;/,$sections)) { 2356: if (($_ eq $ENV{'request.course.sec'}) || 2357: ($defaultflag && ($_ eq '*'))) { 2358: return $adr; 2359: } 2360: } 2361: } else { 2362: return $rec; 2363: } 2364: return ''; 2365: } 2366: 2367: sub decide_receiver { 2368: my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_; 2369: my $typestyle=''; 2370: my %to=(); 2371: if ($ENV{'form.author'}||$author) { 2372: $typestyle.='Submitting as Author Feedback<br>'; 2373: $feedurl=~/^\/res\/(\w+)\/(\w+)\//; 2374: $to{$2.':'.$1}=1; 2375: } 2376: if ($ENV{'form.question'}||$question) { 2377: $typestyle.='Submitting as Question<br>'; 2378: foreach (split(/\,/, 2379: $ENV{'course.'.$ENV{'request.course.id'}.'.question.email'}) 2380: ) { 2381: my $rec=&secapply($_,$defaultflag); 2382: if ($rec) { $to{$rec}=1; } 2383: } 2384: } 2385: if ($ENV{'form.course'}||$course) { 2386: $typestyle.='Submitting as Comment<br />'; 2387: foreach (split(/\,/, 2388: $ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'}) 2389: ) { 2390: my $rec=&secapply($_,$defaultflag); 2391: if ($rec) { $to{$rec}=1; } 2392: } 2393: } 2394: if ($ENV{'form.policy'}||$policy) { 2395: $typestyle.='Submitting as Policy Feedback<br />'; 2396: foreach (split(/\,/, 2397: $ENV{'course.'.$ENV{'request.course.id'}.'.policy.email'}) 2398: ) { 2399: my $rec=&secapply($_,$defaultflag); 2400: if ($rec) { $to{$rec}=1; } 2401: } 2402: } 2403: if ((scalar(%to) eq '0') && (!$defaultflag)) { 2404: ($typestyle,%to)= 2405: &decide_receiver($feedurl,$author,$question,$course,$policy,1); 2406: } 2407: return ($typestyle,%to); 2408: } 2409: 2410: sub feedback_available { 2411: my ($question,$course,$policy)=@_; 2412: my ($typestyle,%to)=&decide_receiver('',0,$question,$course,$policy); 2413: return scalar(%to); 2414: } 2415: 2416: sub send_msg { 2417: my ($feedurl,$email,$citations,$attachmenturl,%to)=@_; 2418: my $status=''; 2419: my $sendsomething=0; 2420: foreach (keys %to) { 2421: if ($_) { 2422: my $declutter=&Apache::lonnet::declutter($feedurl); 2423: unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_), 2424: 'Feedback ['.$declutter.']',$email,$citations,$feedurl, 2425: $attachmenturl)=~/ok/) { 2426: $status.='<br />'.&mt('Error sending message to').' '.$_.'<br />'; 2427: } else { 2428: $sendsomething++; 2429: } 2430: } 2431: } 2432: 2433: my %record=&Apache::lonnet::restore('_feedback'); 2434: my ($temp)=keys %record; 2435: unless ($temp=~/^error\:/) { 2436: my %newrecord=(); 2437: $newrecord{'resource'}=$feedurl; 2438: $newrecord{'subnumber'}=$record{'subnumber'}+1; 2439: unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') { 2440: $status.='<br />'.&mt('Not registered').'<br />'; 2441: } 2442: } 2443: 2444: return ($status,$sendsomething); 2445: } 2446: 2447: sub adddiscuss { 2448: my ($symb,$email,$anon,$attachmenturl,$subject)=@_; 2449: my $status=''; 2450: my $realsymb; 2451: if ($symb=~/^bulletin___/) { 2452: my $filename=(&Apache::lonnet::decode_symb($symb))[2]; 2453: $filename=~s|^adm/wrapper/||; 2454: $realsymb=&Apache::lonnet::symbread($filename); 2455: } 2456: if (&discussion_open(undef,$realsymb) && 2457: &Apache::lonnet::allowed('pch',$ENV{'request.course.id'}. 2458: ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) { 2459: 2460: my %contrib=('message' => $email, 2461: 'sendername' => $ENV{'user.name'}, 2462: 'senderdomain' => $ENV{'user.domain'}, 2463: 'screenname' => $ENV{'environment.screenname'}, 2464: 'plainname' => $ENV{'environment.firstname'}.' '. 2465: $ENV{'environment.middlename'}.' '. 2466: $ENV{'environment.lastname'}.' '. 2467: $ENV{'enrironment.generation'}, 2468: 'attachmenturl'=> $attachmenturl, 2469: 'subject' => $subject); 2470: if ($ENV{'form.replydisc'}) { 2471: $contrib{'replyto'}=(split(/\:\:\:/,$ENV{'form.replydisc'}))[1]; 2472: } 2473: if ($anon) { 2474: $contrib{'anonymous'}='true'; 2475: } 2476: if (($symb) && ($email)) { 2477: if ($ENV{'form.editdisc'}) { 2478: my %newcontrib = (); 2479: $contrib{'ip'}=$ENV{'REMOTE_ADDR'}; 2480: $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'}; 2481: $contrib{'timestamp'} = time; 2482: $contrib{'history'} = ''; 2483: my $numoldver = 0; 2484: my ($oldsymb,$oldidx)=split(/\:\:\:/,$ENV{'form.editdisc'}); 2485: &Apache::lonenc::check_decrypt(\$oldsymb); 2486: $oldsymb=~s|(bulletin___\d+___)adm/wrapper/|$1|; 2487: # get timestamp for last post and history 2488: my %oldcontrib=&Apache::lonnet::restore($oldsymb,$ENV{'request.course.id'}, 2489: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 2490: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 2491: if (defined($oldcontrib{$oldidx.':replyto'})) { 2492: $contrib{'replyto'} = $oldcontrib{$oldidx.':replyto'}; 2493: } 2494: if (defined($oldcontrib{$oldidx.':history'})) { 2495: if ($oldcontrib{$oldidx.':history'} =~ /:/) { 2496: my @oldversions = split/:/,$oldcontrib{$oldidx.':history'}; 2497: $numoldver = @oldversions; 2498: } else { 2499: $numoldver = 1; 2500: } 2501: $contrib{'history'} = $oldcontrib{$oldidx.':history'}.':'; 2502: } 2503: my $numnewver = $numoldver + 1; 2504: if (defined($oldcontrib{$oldidx.':subject'})) { 2505: if ($oldcontrib{$oldidx.':subject'} =~ /^<version num="0">/) { 2506: $contrib{'subject'} = '<version num="'.$numnewver.'">'.&HTML::Entities::encode($contrib{'subject'},'<>&"').'</version>'; 2507: $contrib{'subject'} = $oldcontrib{$oldidx.':subject'}.$contrib{'subject'}; 2508: } else { 2509: $contrib{'subject'} = '<version num="0">'.&HTML::Entities::encode($oldcontrib{$oldidx.':subject'},'<>&"').'</version><version num="1">'.&HTML::Entities::encode($contrib{'subject'},'<>&"').'</version>'; 2510: } 2511: } 2512: if (defined($oldcontrib{$oldidx.':message'})) { 2513: if ($oldcontrib{$oldidx.':message'} =~ /^<version num="0">/) { 2514: $contrib{'message'} = '<version num="'.$numnewver.'">'.&HTML::Entities::encode($contrib{'message'},'<>&"').'</version>'; 2515: $contrib{'message'} = $oldcontrib{$oldidx.':message'}.$contrib{'message'}; 2516: } else { 2517: $contrib{'message'} = '<version num="0">'.&HTML::Entities::encode($oldcontrib{$oldidx.':message'},'<>&"').'</version><version num="1">'.&HTML::Entities::encode($contrib{'message'},'<>&"').'</version>'; 2518: } 2519: } 2520: $contrib{'history'} .= $oldcontrib{$oldidx.':timestamp'}; 2521: foreach (keys %contrib) { 2522: my $key = $oldidx.':'.&Apache::lonnet::escape($oldsymb).':'.$_; 2523: $newcontrib{$key} = $contrib{$_}; 2524: } 2525: my $put_reply = &Apache::lonnet::putstore($ENV{'request.course.id'}, 2526: \%newcontrib, 2527: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 2528: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 2529: $status='Editing class discussion'.($anon?' (anonymous)':''); 2530: } else { 2531: $status='Adding to class discussion'.($anon?' (anonymous)':'').': '. 2532: &Apache::lonnet::store(\%contrib,$symb,$ENV{'request.course.id'}, 2533: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 2534: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 2535: } 2536: my %storenewentry=($symb => time); 2537: $status.='<br />'.&mt('Updating discussion time').': '. 2538: &Apache::lonnet::put('discussiontimes',\%storenewentry, 2539: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 2540: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 2541: } 2542: my %record=&Apache::lonnet::restore('_discussion'); 2543: my ($temp)=keys %record; 2544: unless ($temp=~/^error\:/) { 2545: my %newrecord=(); 2546: $newrecord{'resource'}=$symb; 2547: $newrecord{'subnumber'}=$record{'subnumber'}+1; 2548: $status.='<br />'.&mt('Registering').': '. 2549: &Apache::lonnet::cstore(\%newrecord,'_discussion'); 2550: } 2551: } else { 2552: $status.='Failed.'; 2553: } 2554: return $status.'<br />'; 2555: } 2556: 2557: # ----------------------------------------------------------- Preview function 2558: 2559: sub show_preview { 2560: my $r=shift; 2561: &Apache::loncommon::content_type($r,'text/html'); 2562: $r->send_http_header; 2563: my $message=&clear_out_html($ENV{'form.comment'}); 2564: $message=~s/\n/\<br \/\>/g; 2565: $message=&Apache::lonspeller::markeduptext($message); 2566: $message=&Apache::lontexconvert::msgtexconverted($message); 2567: my $subject=&clear_out_html($ENV{'form.subject'}); 2568: $subject=~s/\n/\<br \/\>/g; 2569: $subject=&Apache::lontexconvert::msgtexconverted($subject); 2570: $r->print('<table border="2"><tr><td>'. 2571: '<b>Subject:</b> '.$subject.'<br /><br />'. 2572: $message.'</td></tr></table>'); 2573: } 2574: 2575: sub generate_preview_button { 2576: my $pre=&mt("Show Preview and Check Spelling"); 2577: return(<<ENDPREVIEW); 2578: <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview"> 2579: <input type="hidden" name="subject"> 2580: <input type="hidden" name="comment" /> 2581: <input type="button" value="$pre" 2582: 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();" /> 2583: </form> 2584: ENDPREVIEW 2585: } 2586: 2587: sub modify_attachments { 2588: my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_; 2589: my $orig_subject = &Apache::lonnet::unescape($ENV{'form.subject'}); 2590: my $subject=&clear_out_html($orig_subject); 2591: $subject=~s/\n/\<br \/\>/g; 2592: $subject=&Apache::lontexconvert::msgtexconverted($subject); 2593: my $timestamp=$ENV{'form.timestamp'}; 2594: my $numoldver=$ENV{'form.numoldver'}; 2595: my $bodytag=&Apache::loncommon::bodytag('Discussion Post Attachments', 2596: '',''); 2597: my $msg = ''; 2598: my %attachments = (); 2599: my %currattach = (); 2600: if ($idx) { 2601: &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold); 2602: } 2603: &Apache::lonenc::check_encrypt(\$symb); 2604: $r->print(<<END); 2605: <html> 2606: <head> 2607: <title>Managing Attachments</title> 2608: <script> 2609: function setAction () { 2610: document.modattachments.action = document.modattachments.origpage.value; 2611: document.modattachments.submit(); 2612: } 2613: </script> 2614: </head> 2615: $bodytag 2616: <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb"> 2617: <table border="2"> 2618: <tr> 2619: <td> 2620: <b>Subject:</b> $subject</b><br /><br /> 2621: END 2622: if ($idx) { 2623: if ($attachmenturls) { 2624: my @currold = keys %currattach; 2625: if (@currold > 0) { 2626: $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"); 2627: foreach my $id (@currold) { 2628: my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'}); 2629: $attachurl =~ m#/([^/]+)$#; 2630: $r->print('<input type="checkbox" name="deloldattach" value="'.$id.'" /> '.$1.'<br />'."\n"); 2631: } 2632: $r->print("<br />"); 2633: } 2634: } 2635: } 2636: if (@{$currnewattach} > 0) { 2637: $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"); 2638: foreach (@{$currnewattach}) { 2639: $_ =~ m#/([^/]+)$#; 2640: $r->print('<input type="checkbox" name="delnewattach" value="'.$_.'" /> '.$1.'<br />'."\n"); 2641: } 2642: $r->print("<br />"); 2643: } 2644: $r->print(<<END); 2645: Add a new attachment to this post. <input type="file" name="addnewattach" /><input type="button" name="upload" value="Upload" onClick="this.form.submit()" /> 2646: </td> 2647: </tr> 2648: </table> 2649: <input type="hidden" name="subject" value="$ENV{'form.subject'}" /> 2650: <input type="hidden" name="comment" value="$ENV{'form.comment'}" /> 2651: <input type="hidden" name="timestamp" value="$ENV{'form.timestamp'}" /> 2652: <input type="hidden" name="idx" value="$ENV{'form.idx'}" /> 2653: <input type="hidden" name="numoldver" value="$ENV{'form.numoldver'}" /> 2654: <input type="hidden" name="origpage" value="$ENV{'form.origpage'}" /> 2655: <input type="hidden" name="anondiscuss" value="$ENV{'form.anondiscuss'}" /> 2656: <input type="hidden" name="discuss" value="$ENV{'form.discuss'}" /> 2657: END 2658: foreach (@{$currnewattach}) { 2659: $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n"); 2660: } 2661: foreach (@{$currdelold}) { 2662: $r->print('<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n"); 2663: } 2664: $r->print(<<END); 2665: <input type="button" name="rtntoedit" value="Store Changes" onClick="setAction()"/> 2666: </form> 2667: </body> 2668: </html> 2669: END 2670: return; 2671: } 2672: 2673: sub process_attachments { 2674: my ($currnewattach,$currdelold,$keepold) = @_; 2675: if (exists($ENV{'form.currnewattach'})) { 2676: if (ref($ENV{'form.currnewattach'}) eq 'ARRAY') { 2677: @{$currnewattach} = @{$ENV{'form.currnewattach'}}; 2678: } else { 2679: $$currnewattach[0] = $ENV{'form.currnewattach'}; 2680: } 2681: } 2682: if (exists($ENV{'form.deloldattach'})) { 2683: if (ref($ENV{'form.deloldattach'}) eq 'ARRAY') { 2684: @{$currdelold} = @{$ENV{'form.deloldattach'}}; 2685: } else { 2686: $$currdelold[0] = $ENV{'form.deloldattach'}; 2687: } 2688: } 2689: if (exists($ENV{'form.delnewattach'})) { 2690: my @currdelnew = (); 2691: my @currnew = (); 2692: if (ref($ENV{'form.delnewattach'}) eq 'ARRAY') { 2693: @currdelnew = @{$ENV{'form.delnewattach'}}; 2694: } else { 2695: $currdelnew[0] = $ENV{'form.delnewattach'}; 2696: } 2697: foreach my $newone (@{$currnewattach}) { 2698: my $delflag = 0; 2699: foreach (@currdelnew) { 2700: if ($newone eq $_) { 2701: $delflag = 1; 2702: last; 2703: } 2704: } 2705: unless ($delflag) { 2706: push @currnew, $newone; 2707: } 2708: } 2709: @{$currnewattach} = @currnew; 2710: } 2711: if (exists($ENV{'form.keepold'})) { 2712: if (ref($ENV{'form.keepold'}) eq 'ARRAY') { 2713: @{$keepold} = @{$ENV{'form.keepold'}}; 2714: } else { 2715: $$keepold[0] = $ENV{'form.keepold'}; 2716: } 2717: } 2718: } 2719: 2720: sub generate_attachments_button { 2721: my ($idx,$attachnum,$ressymb,$now,$currnewattach,$deloldattach,$numoldver,$mode) = @_; 2722: my $origpage = $ENV{'REQUEST_URI'}; 2723: my $att=$attachnum.' '.&mt("attachments"); 2724: my $response = (<<END); 2725: <form name="attachment" action="/adm/feedback?attach=$ressymb" method="post"> 2726: Click to add/remove attachments: <input type="button" value="$att" 2727: 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); 2728: END 2729: unless ($mode eq 'board') { 2730: $response .= 'javascript:anonchk();'; 2731: } 2732: $response .= (<<ENDATTACH); 2733: this.form.submit();" /> 2734: <input type="hidden" name="origpage" value="$origpage" /> 2735: <input type="hidden" name="idx" value="$idx" /> 2736: <input type="hidden" name="timestamp" value="$now" /> 2737: <input type="hidden" name="subject" /> 2738: <input type="hidden" name="comment" /> 2739: <input type="hidden" name="anondiscuss" value = "0"; 2740: <input type="hidden" name="discuss" value = "0"; 2741: <input type="hidden" name="numoldver" value="$numoldver" /> 2742: ENDATTACH 2743: if (defined($deloldattach)) { 2744: if (@{$deloldattach} > 0) { 2745: foreach (@{$deloldattach}) { 2746: $response .= '<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n"; 2747: } 2748: } 2749: } 2750: if (defined($currnewattach)) { 2751: if (@{$currnewattach} > 0) { 2752: foreach (@{$currnewattach}) { 2753: $response .= '<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n"; 2754: } 2755: } 2756: } 2757: $response .= '</form>'; 2758: return $response; 2759: } 2760: 2761: sub extract_attachments { 2762: my ($attachmenturls,$idx,$numoldver,$message,$attachments,$currattach,$currdelold) = @_; 2763: %{$attachments}=(); 2764: &get_post_attachments($attachments,$attachmenturls); 2765: foreach my $id (sort keys %{$attachments}) { 2766: if (exists($$attachments{$id}{$numoldver})) { 2767: if (defined($currdelold)) { 2768: if (@{$currdelold} > 0) { 2769: unless (grep/^$id$/,@{$currdelold}) { 2770: $$currattach{$id} = $$attachments{$id}{$numoldver}; 2771: } 2772: } else { 2773: $$currattach{$id} = $$attachments{$id}{$numoldver}; 2774: } 2775: } else { 2776: $$currattach{$id} = $$attachments{$id}{$numoldver}; 2777: } 2778: } 2779: } 2780: my @attached = (sort { $a <=> $b } keys %{$currattach}); 2781: if (@attached == 1) { 2782: my $id = $attached[0]; 2783: my $attachurl; 2784: if ($attachmenturls =~ m/^<attachment id="0">/) { 2785: $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'}); 2786: } else { 2787: $attachurl = $$attachments{$id}{'filename'}; 2788: } 2789: $attachurl=~m|/([^/]+)$|; 2790: $$message.='<br /><a href="'.$attachurl.'"><tt>'. 2791: $1.'</tt></a><br />'; 2792: &Apache::lonnet::allowuploaded('/adm/feedback', 2793: $attachurl); 2794: } elsif (@attached > 1) { 2795: $$message.='<ol>'; 2796: foreach (@attached) { 2797: my $id = $_; 2798: my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'}); 2799: my ($fname) 2800: =($attachurl=~m|/([^/]+)$|); 2801: $$message .= '<li><a href="'.$attachurl. 2802: '"><tt>'. 2803: $fname.'</tt></a></li>'; 2804: &Apache::lonnet::allowuploaded('/adm/feedback', 2805: $attachurl); 2806: } 2807: $$message .= '</ol>'; 2808: } 2809: } 2810: 2811: sub construct_attachmenturl { 2812: my ($currnewattach,$keepold,$symb,$idx)=@_; 2813: my $oldattachmenturl; 2814: my $newattachmenturl; 2815: my $startnum = 0; 2816: my $currver = 0; 2817: if (($ENV{'form.editdisc'}) && ($idx)) { 2818: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 2819: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 2820: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 2821: $oldattachmenturl = $contrib{$idx.':attachmenturl'}; 2822: if ($contrib{$idx.':history'}) { 2823: if ($contrib{$idx.':history'} =~ /:/) { 2824: my @oldversions = split/:/,$contrib{$idx.':history'}; 2825: $currver = 1 + scalar(@oldversions); 2826: } else { 2827: $currver = 2; 2828: } 2829: } else { 2830: $currver = 1; 2831: } 2832: if ($oldattachmenturl) { 2833: if ($oldattachmenturl =~ m/^<attachment id="0">/) { 2834: my %attachments = (); 2835: my $prevver = $currver-1; 2836: &get_post_attachments(\%attachments,$oldattachmenturl); 2837: my $numattach = scalar(keys %attachments); 2838: $startnum += $numattach; 2839: foreach my $num (sort {$a <=> $b} keys %attachments) { 2840: $newattachmenturl .= '<attachment id="'.$num.'"><filename>'.$attachments{$num}{'filename'}.'</filename>'; 2841: foreach $_ (sort {$a <=> $b} keys %{$attachments{$num}}) { 2842: unless ($_ eq 'filename') { 2843: $newattachmenturl .= '<post id="'.$_.'">'.$attachments{$num}{$_}.'</post>'; 2844: } 2845: } 2846: if (grep/^$num$/,@{$keepold}) { 2847: $newattachmenturl .= '<post id="'.$currver.'">'.$attachments{$num}{$prevver}.'</post>'; 2848: } 2849: $newattachmenturl .= '</attachment>'; 2850: } 2851: } else { 2852: $newattachmenturl = '<attachment id="0"><filename>'.&HTML::Entities::encode($oldattachmenturl).'</filename><post id="0">n</post>'; 2853: unless (grep/^0$/,@{$keepold}) { 2854: $newattachmenturl .= '<post id="1">n</post>'; 2855: } 2856: $newattachmenturl .= '</attachment>'; 2857: $startnum ++; 2858: } 2859: } 2860: } 2861: for (my $i=0; $i<@{$currnewattach}; $i++) { 2862: my $attachnum = $startnum + $i; 2863: $newattachmenturl .= '<attachment id="'.$attachnum.'"><filename>'.&HTML::Entities::encode($$currnewattach[$i]).'</filename><post id="'.$currver.'">n</post></attachment>'; 2864: } 2865: return $newattachmenturl; 2866: } 2867: 2868: sub has_discussion { 2869: my $resourcesref = shift; 2870: my $navmap = Apache::lonnavmaps::navmap->new(); 2871: my @allres=$navmap->retrieveResources(); 2872: foreach my $resource (@allres) { 2873: if ($resource->hasDiscussion()) { 2874: my $ressymb; 2875: if ($resource->symb() =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) { 2876: $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard'; 2877: } else { 2878: $ressymb = $resource->symb(); 2879: } 2880: push @{$resourcesref}, $ressymb; 2881: } 2882: } 2883: return; 2884: } 2885: 2886: sub sort_filter_names { 2887: my ($sort_types,$role_types,$status_types) = @_; 2888: %{$sort_types} = ( 2889: ascdate => 'Date order - oldest first', 2890: descdate => 'Date order - newest first', 2891: thread => 'Threaded', 2892: subject => 'By subject', 2893: username => 'By domain and username', 2894: lastfirst => 'By last name, first name' 2895: ); 2896: %{$role_types} = ( 2897: all => 'All roles', 2898: st => 'Students', 2899: cc => 'Course Coordinators', 2900: in => 'Instructors', 2901: ta => 'TAs', 2902: ep => 'Exam proctors', 2903: ad => 'Administrators', 2904: cr => 'Custom roles' 2905: ); 2906: %{$status_types} = ( 2907: all => 'Roles of any status', 2908: Active => 'Only active roles', 2909: Expired => 'Only inactive roles' 2910: ); 2911: } 2912: 2913: sub handler { 2914: my $r = shift; 2915: if ($r->header_only) { 2916: &Apache::loncommon::content_type($r,'text/html'); 2917: $r->send_http_header; 2918: return OK; 2919: } 2920: 2921: # --------------------------- Get query string for limited number of parameters 2922: 2923: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, 2924: ['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']); 2925: 2926: if ($ENV{'form.discsymb'}) { 2927: my ($symb,$feedurl) = &get_feedurl_and_clean_symb($ENV{'form.discsymb'}); 2928: my $readkey = $symb.'_read'; 2929: my $chgcount = 0; 2930: my %readinghash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$readkey],$ENV{'user.domain'},$ENV{'user.name'}); 2931: foreach my $key (keys %ENV) { 2932: if ($key =~ m/^form\.postunread_(\d+)/) { 2933: if ($readinghash{$readkey} =~ /\.$1\./) { 2934: $readinghash{$readkey} =~ s/\.$1\.//; 2935: $chgcount ++; 2936: } 2937: } elsif ($key =~ m/^form\.postread_(\d+)/) { 2938: unless ($readinghash{$readkey} =~ /\.$1\./) { 2939: $readinghash{$readkey} .= '.'.$1.'.'; 2940: $chgcount ++; 2941: } 2942: } 2943: } 2944: if ($chgcount > 0) { 2945: &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', 2946: \%readinghash,$ENV{'user.domain'},$ENV{'user.name'}); 2947: } 2948: &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'<br />', 2949: '0','0','',$ENV{'form.previous'},'','','',); 2950: return OK; 2951: } 2952: if ($ENV{'form.allversions'}) { 2953: &Apache::loncommon::content_type($r,'text/html'); 2954: $r->send_http_header; 2955: my $bodytag=&Apache::loncommon::bodytag('Discussion Post Versions'); 2956: $r->print(<<END); 2957: <html> 2958: <head> 2959: <title>Post Versions</title> 2960: <meta http-equiv="pragma" content="no-cache" /> 2961: </head> 2962: $bodytag 2963: END 2964: my $crs='/'.$ENV{'request.course.id'}; 2965: if ($ENV{'request.course.sec'}) { 2966: $crs.='_'.$ENV{'request.course.sec'}; 2967: } 2968: $crs=~s|_|/|g; 2969: my $seeid=&Apache::lonnet::allowed('rin',$crs); 2970: my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.allversions'}); 2971: ($symb)=&get_feedurl_and_clean_symb($symb); 2972: if ($idx > 0) { 2973: my %messages = (); 2974: my %subjects = (); 2975: my %attachmsgs = (); 2976: my %allattachments = (); 2977: my %imsfiles = (); 2978: my ($screenname,$plainname); 2979: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 2980: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 2981: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 2982: $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname)); 2983: } 2984: return OK; 2985: } 2986: if ($ENV{'form.posterlist'}) { 2987: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.applysort'}); 2988: &print_showposters($r,$symb,$ENV{'form.previous'},$feedurl, 2989: $ENV{'form.sortposts'}); 2990: return OK; 2991: } 2992: if ($ENV{'form.userpick'}) { 2993: my @posters = &Apache::loncommon::get_env_multiple('form.stuinfo'); 2994: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.userpick'}); 2995: my $numpicks = @posters; 2996: my %discinfo; 2997: $discinfo{$symb.'_userpick'} = join('&',@posters); 2998: &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', 2999: \%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); 3000: &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0', 3001: '',$ENV{'form.previous'},$ENV{'form.sortposts'},'','','', 3002: $numpicks); 3003: return OK; 3004: } 3005: if ($ENV{'form.applysort'}) { 3006: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.applysort'}); 3007: &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0', 3008: '',$ENV{'form.previous'},$ENV{'form.sortposts'}, 3009: $ENV{'form.rolefilter'},$ENV{'form.statusfilter'}, 3010: $ENV{'form.sectionpick'}); 3011: return OK; 3012: } elsif ($ENV{'form.cmd'} eq 'sortfilter') { 3013: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'}); 3014: &print_sortfilter_options($r,$symb,$ENV{'form.previous'},$feedurl); 3015: return OK; 3016: } elsif ($ENV{'form.navtime'}) { 3017: my %discinfo = (); 3018: my @resources = (); 3019: if (defined($ENV{'form.navmaps'})) { 3020: if ($ENV{'form.navmaps'} =~ /:/) { 3021: @resources = split/:/,$ENV{'form.navmaps'}; 3022: } else { 3023: @resources = ("$ENV{'form.navmaps'}"); 3024: } 3025: } else { 3026: &has_discussion(\@resources); 3027: } 3028: my $numitems = @resources; 3029: my $feedurl = '/adm/navmaps'; 3030: if ($ENV{'form.navurl'}) { $feedurl .= '?'.$ENV{'form.navurl'}; } 3031: my %lt = &Apache::lonlocal::texthash( 3032: 'mnpa' => 'Marked "New" posts as read in a total of', 3033: 'robb' => 'resources/bulletin boards.', 3034: 'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.' 3035: ); 3036: foreach (@resources) { 3037: # backward compatibility (bulletin boards used to be 'wrapped') 3038: my $ressymb=$_; 3039: &Apache::lonenc::check_decrypt(\$ressymb); 3040: if ($ressymb =~ m/bulletin___\d+___/) { 3041: unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { 3042: $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper/|; 3043: } 3044: } 3045: my $lastkey = $ressymb.'_lastread'; 3046: $discinfo{$lastkey} = $ENV{'form.navtime'}; 3047: } 3048: my $textline = "<b>$lt{'mnpa'} $numitems $lt{'robb'}</b>"; 3049: if ($numitems > 0) { 3050: &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', 3051: \%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); 3052: } else { 3053: $textline = "<b>$lt{'twnp'}</b>"; 3054: } 3055: &Apache::loncommon::content_type($r,'text/html'); 3056: $r->send_http_header; 3057: $r->print (<<ENDREDIR); 3058: <html> 3059: <head> 3060: <title>New posts marked as read</title> 3061: <meta http-equiv="pragma" content="no-cache" /> 3062: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" /> 3063: </head> 3064: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'> 3065: <img align="right" src="/adm/lonIcons/lonlogos.gif" /> 3066: $textline 3067: <form name="reldt" action="$feedurl" target="loncapaclient"> 3068: </form> 3069: <br /><a href="$feedurl">Continue</a> 3070: </body> 3071: </html> 3072: ENDREDIR 3073: return OK; 3074: } elsif ($ENV{'form.modifydisp'}) { 3075: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.modifydisp'}); 3076: my ($dispchgA,$dispchgB,$markchg,$toggchg) = 3077: split(/_/,$ENV{'form.changes'}); 3078: &print_display_options($r,$symb,$ENV{'form.previous'},$dispchgA, 3079: $dispchgB,$markchg,$toggchg,$feedurl); 3080: return OK; 3081: } elsif ($ENV{'form.markondisp'} || $ENV{'form.markonread'} || 3082: $ENV{'form.allposts'} || $ENV{'form.onlyunread'} || 3083: $ENV{'form.onlyunmark'} || $ENV{'form.toggoff'} || 3084: $ENV{'form.toggon'} || $ENV{'form.markread'}) { 3085: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'}); 3086: my %discinfo; 3087: # ------------------------ Modify setting for read/unread toggle for each post 3088: if ($ENV{'form.toggoff'}) { $discinfo{$symb.'_readtoggle'}=0; } 3089: if ($ENV{'form.toggon'}) { $discinfo{$symb.'_readtoggle'}=1; } 3090: # --------- Modify setting for identification of 'NEW' posts in this discussion 3091: if ($ENV{'form.markondisp'}) { 3092: $discinfo{$symb.'_lastread'} = time; 3093: $discinfo{$symb.'_markondisp'} = 1; 3094: } 3095: if ($ENV{'form.markonread'}) { 3096: if ( $ENV{'form.previous'} > 0 ) { 3097: $discinfo{$symb.'_lastread'} = $ENV{'form.previous'}; 3098: } 3099: $discinfo{$symb.'_markondisp'} = 0; 3100: } 3101: # --------------------------------- Modify display setting for this discussion 3102: if ($ENV{'form.allposts'}) { 3103: $discinfo{$symb.'_showonlyunread'} = 0; 3104: $discinfo{$symb.'_showonlyunmark'} = 0; 3105: } 3106: if ($ENV{'form.onlyunread'}) { $discinfo{$symb.'_showonlyunread'} = 1; } 3107: if ($ENV{'form.onlyunmark'}) { $discinfo{$symb.'_showonlyunmark'} = 1; } 3108: # ----------------------------------------------------- Mark new posts not NEW 3109: if ($ENV{'form.markread'}) { $discinfo{$symb.'_lastread'} = time; } 3110: &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss', 3111: \%discinfo,$ENV{'user.domain'},$ENV{'user.name'}); 3112: my $previous=$ENV{'form.previous'}; 3113: if ($ENV{'form.markondisp'}) { $previous=undef; } 3114: &redirect_back($r,$feedurl,&mt('Changed display status').'<br />', 3115: '0','0','',$previous); 3116: return OK; 3117: } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) { 3118: # ----------------------------------------------------------------- Hide/unhide 3119: my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'}; 3120: my ($symb,$idx)=split(/\:\:\:/,$entry); 3121: ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb); 3122: 3123: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 3124: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 3125: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 3126: 3127: my $currenthidden=$contrib{'hidden'}; 3128: my $currentstudenthidden=$contrib{'studenthidden'}; 3129: 3130: my $crs='/'.$ENV{'request.course.id'}; 3131: if ($ENV{'request.course.sec'}) { 3132: $crs.='_'.$ENV{'request.course.sec'}; 3133: } 3134: $crs=~s/\_/\//g; 3135: my $seeid=&Apache::lonnet::allowed('rin',$crs); 3136: 3137: if ($ENV{'form.hide'}) { 3138: $currenthidden.='.'.$idx.'.'; 3139: unless ($seeid) { 3140: $currentstudenthidden.='.'.$idx.'.'; 3141: } 3142: } else { 3143: $currenthidden=~s/\.$idx\.//g; 3144: } 3145: my %newhash=('hidden' => $currenthidden); 3146: if ( ($ENV{'form.hide'}) && (!$seeid) ) { 3147: $newhash{'studenthidden'} = $currentstudenthidden; 3148: } 3149: 3150: &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'}, 3151: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 3152: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 3153: 3154: &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />', 3155: '0','0','',$ENV{'form.previous'}); 3156: return OK; 3157: } elsif ($ENV{'form.cmd'}=~/^(threadedoff|threadedon)$/) { 3158: my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'}); 3159: if ($ENV{'form.cmd'} eq 'threadedon') { 3160: &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'}); 3161: &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on'); 3162: } else { 3163: &Apache::lonnet::del('environment',['threadeddiscussion']); 3164: &Apache::lonnet::delenv('environment\.threadeddiscussion'); 3165: } 3166: &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />', 3167: '0','0','',$ENV{'form.previous'}); 3168: return OK; 3169: } elsif ($ENV{'form.deldisc'}) { 3170: # --------------------------------------------------------------- Hide for good 3171: my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.deldisc'}); 3172: ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb); 3173: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 3174: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 3175: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 3176: my %newhash=('deleted' => $contrib{'deleted'}.".$idx."); 3177: &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'}, 3178: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 3179: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 3180: &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />', 3181: '0','0','',$ENV{'form.previous'}); 3182: return OK; 3183: } elsif ($ENV{'form.preview'}) { 3184: # -------------------------------------------------------- User wants a preview 3185: &show_preview($r); 3186: return OK; 3187: } elsif ($ENV{'form.attach'}) { 3188: # -------------------------------------------------------- Work on attachments 3189: &Apache::loncommon::content_type($r,'text/html'); 3190: $r->send_http_header; 3191: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','addnewattach','delnewattach','timestamp','numoldver','idx','anondiscuss','discuss']); 3192: my (@currnewattach,@currdelold,@keepold); 3193: &process_attachments(\@currnewattach,\@currdelold,\@keepold); 3194: if (exists($ENV{'form.addnewattach.filename'})) { 3195: unless (length($ENV{'form.addnewattach'})>131072) { 3196: my $subdir = 'feedback/'.$ENV{'form.timestamp'}; 3197: my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir); 3198: push @currnewattach, $newattachment; 3199: } 3200: } 3201: my $attachmenturls; 3202: my ($symb) = &get_feedurl_and_clean_symb($ENV{'form.attach'}); 3203: my $idx = $ENV{'form.idx'}; 3204: if ($idx) { 3205: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 3206: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 3207: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 3208: $attachmenturls = $contrib{$idx.':attachmenturl'}; 3209: } 3210: &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx, 3211: $attachmenturls); 3212: return OK; 3213: } elsif ($ENV{'form.export'}) { 3214: &Apache::loncommon::content_type($r,'text/html'); 3215: $r->send_http_header; 3216: my ($symb,$feedurl) = &get_feedurl_and_clean_symb($ENV{'form.export'}); 3217: my $mode='board'; 3218: my $status='OPEN'; 3219: my $previous=$ENV{'form.previous'}; 3220: if ($feedurl =~ /\.(problem|exam|quiz|assess|survey|form|library)$/) { 3221: $mode='problem'; 3222: $status=$Apache::inputtags::status[-1]; 3223: } 3224: my $discussion = &list_discussion($mode,$status,$symb); 3225: my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion'); 3226: $r->print($bodytag.$discussion); 3227: return OK; 3228: } else { 3229: # ------------------------------------------------------------- Normal feedback 3230: my $feedurl=$ENV{'form.postdata'}; 3231: $feedurl=~s/^http\:\/\///; 3232: $feedurl=~s/^$ENV{'SERVER_NAME'}//; 3233: $feedurl=~s/^$ENV{'HTTP_HOST'}//; 3234: $feedurl=~s/\?.+$//; 3235: 3236: my $symb; 3237: if ($ENV{'form.replydisc'}) { 3238: $symb=(split(/\:\:\:/,$ENV{'form.replydisc'}))[0]; 3239: my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb); 3240: $feedurl=&Apache::lonnet::clutter($url); 3241: } elsif ($ENV{'form.editdisc'}) { 3242: $symb=(split(/\:\:\:/,$ENV{'form.editdisc'}))[0]; 3243: my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb); 3244: $feedurl=&Apache::lonnet::clutter($url); 3245: } elsif ($ENV{'form.origpage'}) { 3246: $symb=""; 3247: } else { 3248: $symb=&Apache::lonnet::symbread($feedurl); 3249: } 3250: unless ($symb) { 3251: $symb=$ENV{'form.symb'}; 3252: if ($symb) { 3253: my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb); 3254: $feedurl=&Apache::lonnet::clutter($url); 3255: } 3256: } 3257: &Apache::lonenc::check_decrypt(\$symb); 3258: my $goahead=1; 3259: if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) { 3260: unless ($symb) { $goahead=0; } 3261: } 3262: # backward compatibility (bulletin boards used to be 'wrapped') 3263: if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { 3264: $feedurl=~s|^/adm/wrapper||; 3265: } 3266: if (!$goahead) { 3267: # Ambiguous Problem Resource 3268: $r->internal_redirect('/adm/ambiguous'); 3269: return OK; 3270: } 3271: # Go ahead with feedback, no ambiguous reference 3272: unless ( 3273: ( 3274: ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:) 3275: ) 3276: || 3277: ($ENV{'request.course.id'} && ($feedurl!~m:^/adm:)) 3278: || 3279: ($ENV{'request.course.id'} && ($symb=~/^bulletin\_\_\_/)) 3280: ) { 3281: &Apache::loncommon::content_type($r,'text/html'); 3282: $r->send_http_header; 3283: # Unable to give feedback 3284: &no_redirect_back($r,$feedurl); 3285: } 3286: # --------------------------------------------------- Print login screen header 3287: unless ($ENV{'form.sendit'}) { 3288: &Apache::loncommon::content_type($r,'text/html'); 3289: $r->send_http_header; 3290: my $options=&screen_header($feedurl,$symb); 3291: if ($options) { 3292: &mail_screen($r,$feedurl,$options); 3293: } else { 3294: &fail_redirect($r,$feedurl); 3295: } 3296: return OK; 3297: } 3298: 3299: # Get previous user input 3300: my $prevattempts=&Apache::loncommon::get_previous_attempt( 3301: $symb,$ENV{'user.name'},$ENV{'user.domain'}, 3302: $ENV{'request.course.id'}); 3303: 3304: # Get output from resource 3305: my $usersaw=&resource_output($feedurl); 3306: 3307: # Get resource answer (need to allow student to view grades for this to work) 3308: &Apache::lonnet::appenv(('allowed.vgr'=>'F')); 3309: my $useranswer=&Apache::loncommon::get_student_answers( 3310: $symb,$ENV{'user.name'},$ENV{'user.domain'}, 3311: $ENV{'request.course.id'}); 3312: &Apache::lonnet::delenv('allowed.vgr'); 3313: # Get attachments, if any, and not too large 3314: my $attachmenturl=''; 3315: if (($ENV{'form.origpage'}) || ($ENV{'form.editdisc'}) || 3316: ($ENV{'form.replydisc'})) { 3317: my ($symb,$idx); 3318: if ($ENV{'form.replydisc'}) { 3319: ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'}); 3320: } elsif ($ENV{'form.editdisc'}) { 3321: ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'}); 3322: } elsif ($ENV{'form.origpage'}) { 3323: $symb = $ENV{'form.symb'}; 3324: } 3325: &Apache::lonenc::check_decrypt(\$symb); 3326: my @currnewattach = (); 3327: my @deloldattach = (); 3328: my @keepold = (); 3329: &process_attachments(\@currnewattach,\@deloldattach,\@keepold); 3330: $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|; 3331: $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx); 3332: } elsif ($ENV{'form.attachment.filename'}) { 3333: unless (length($ENV{'form.attachment'})>131072) { 3334: $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback'); 3335: } 3336: } 3337: # Filter HTML out of message (could be nasty) 3338: my $message=&clear_out_html($ENV{'form.comment'}); 3339: 3340: # Assemble email 3341: my ($email,$citations)=&assemble_email($feedurl,$message,$prevattempts, 3342: $usersaw,$useranswer); 3343: 3344: # Who gets this? 3345: my ($typestyle,%to) = &decide_receiver($feedurl); 3346: 3347: # Actually send mail 3348: my ($status,$numsent)=&send_msg($feedurl,$email,$citations, 3349: $attachmenturl,%to); 3350: 3351: # Discussion? Store that. 3352: 3353: my $numpost=0; 3354: if ($ENV{'form.discuss'} || $ENV{'form.anondiscuss'}) { 3355: my $subject = &clear_out_html($ENV{'form.subject'}); 3356: my $anonmode=(defined($ENV{'form.anondiscuss'})); 3357: $typestyle.=&adddiscuss($symb,$message,$anonmode,$attachmenturl, 3358: $subject); 3359: $numpost++; 3360: } 3361: 3362: # Receipt screen and redirect back to where came from 3363: &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$ENV{'form.previous'}); 3364: } 3365: return OK; 3366: } 3367: 3368: sub wrap_symb { 3369: my ($ressymb)=@_; 3370: if ($ressymb =~ /bulletin___\d+___/) { 3371: unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) { 3372: $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|; 3373: } 3374: } 3375: return $ressymb; 3376: } 3377: sub dewrapper { 3378: my ($feedurl)=@_; 3379: if ($$feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) { 3380: $$feedurl=~s|^/adm/wrapper||; 3381: } 3382: } 3383: 3384: sub get_feedurl { 3385: my ($symb)=@_; 3386: my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); 3387: my $feedurl = &Apache::lonnet::clutter($url); 3388: &dewrapper(\$feedurl); 3389: return $feedurl; 3390: } 3391: 3392: sub get_feedurl_and_clean_symb { 3393: my ($symb)=@_; 3394: &Apache::lonenc::check_decrypt(\$symb); 3395: # backward compatibility (bulletin boards used to be 'wrapped') 3396: unless ($symb =~ m|bulletin___\d+___adm/wrapper|) { 3397: $symb=~s|(bulletin___\d+___)|$1adm/wrapper|; 3398: } 3399: my $feedurl = &get_feedurl($symb); 3400: return ($symb,$feedurl); 3401: } 3402: 1; 3403: __END__