Diff for /loncom/interface/lonfeedback.pm between versions 1.290.2.7 and 1.370.2.5.2.2

version 1.290.2.7, 2010/12/24 23:18:57 version 1.370.2.5.2.2, 2022/01/19 18:08:38
Line 44  use HTML::LCParser(); Line 44  use HTML::LCParser();
 #use HTML::Tidy::libXML;  #use HTML::Tidy::libXML;
 use Apache::lonspeller();  use Apache::lonspeller();
 use Apache::longroup;  use Apache::longroup;
 use Cwd;  use Archive::Zip qw( :ERROR_CODES );
 use LONCAPA;  use LONCAPA qw(:DEFAULT :match);
   
 sub discussion_open {  sub discussion_open {
     my ($status,$symb)=@_;      my ($status,$symb)=@_;
Line 58  sub discussion_open { Line 58  sub discussion_open {
         return 1;          return 1;
     }      }
 # It was not explicitly open, check if the problem is available.  # It was not explicitly open, check if the problem is available.
 # If the problem is not available, close the discussion  # If the problem is not available, close the discussion 
     if (defined($status) &&      if (defined($status) &&
         !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'   !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
           || $status eq 'OPEN')) {    || $status eq 'OPEN')) {
         return 0;   return 0;
     }      }
 # The problem is available, but check if the instructor explictly closed discussion  # The problem is available, but check if the instructor explictly closed discussion
     if (defined($close) && $close ne '' && $close < time) {      if (defined($close) && $close ne '' && $close < time) {
         return 0;   return 0;
     }      }
     return 1;      return 1;
 }  }
Line 82  sub discussion_visible { Line 82  sub discussion_visible {
     return 1;      return 1;
 }  }
   
   sub discussion_vote_available {
       my ($status,$symb)=@_;
       my $canvote=&Apache::lonnet::EXT('resource.0.discussvote',$symb);
       if ((lc($canvote) eq 'yes') || 
           ((lc($canvote) eq 'notended') && (&discussion_open($status,$symb)))) {
           return 1;
       }
   }
   
   sub get_realsymb {
       my ($symb) = @_;
       my $realsymb = $symb;
       if ($symb=~/^bulletin___/) {
           my $filename=(&Apache::lonnet::decode_symb($symb))[2];
           $filename=~s{^adm/wrapper/}{};
           $realsymb=&Apache::lonnet::symbread($filename);
       }
       return $realsymb;
   }
   
 sub list_discussion {  sub list_discussion {
     my ($mode,$status,$ressymb,$imsextras,$group)=@_;      my ($mode,$status,$ressymb,$imsextras,$group)=@_;
     unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); }      unless ($ressymb) { $ressymb=&Apache::lonnet::symbread(); }
Line 98  sub list_discussion { Line 118  sub list_discussion {
             $outputtarget = 'export';              $outputtarget = 'export';
         }          }
     }      }
       my ($nofooter,$nodisclink,$nofdbklink);
     if (not &discussion_visible($status)) {      if (not &discussion_visible($status)) {
         if ($mode ne 'board') {          if ($mode ne 'board') {
             &Apache::lonenc::check_encrypt(\$ressymb);               ($nofooter,$nodisclink,$nofdbklink) = &check_menucoll();
             return '<br /><div class="LC_feedback_link">'.&send_message_link($ressymb)."</div>";              if ($nofooter || $nofdbklink) {
                   return '<br />';
               } else {
                   &Apache::lonenc::check_encrypt(\$ressymb);
                   return '<br /><div class="LC_feedback_link">'.&send_message_link($ressymb)."</div>";
               }
         }          }
     }      }
     if ($group ne '' && $mode eq 'board') {      if ($group ne '' && $mode eq 'board') {
Line 110  sub list_discussion { Line 136  sub list_discussion {
         }          }
     }      }
   
     my ($blocked,$blocktext) =       unless ($outputtarget eq 'export') {
         &Apache::loncommon::blocking_status('boards');          ($nofooter,$nodisclink,$nofdbklink) = &check_menucoll();
     if ($blocked) {      }
         $blocktext = '<br /><div class="LC_feedback_link"><span class="LC_feedback_link">'.$blocktext."</span>";  
         &Apache::lonenc::check_encrypt(\$ressymb);      unless ($nofooter) {
         if ($mode ne 'board') {          my ($blocked,$blocktext) = 
             $blocktext.=&send_message_link($ressymb).'</div>';              &Apache::loncommon::blocking_status('boards');
         }else{          if ($blocked) {
             $blocktext.="</div>";              my $footer = '<br /><div class="LC_feedback_link">';
               unless ($nodisclink) {
                   $footer .= '<span class="LC_feedback_link">'.$blocktext.'</span>';
               }
               &Apache::lonenc::check_encrypt(\$ressymb);
               if ($mode ne 'board') {
                   unless ($nofdbklink) {
                       $footer.=&send_message_link($ressymb);
                   }
               }
               $footer.='</div>';
               return $footer;
         }          }
         return $blocktext;   
     }      }
   
     my @bgcols = ("LC_disc_old_item","LC_disc_new_item");      my @bgcols = ("LC_disc_old_item","LC_disc_new_item");
Line 135  sub list_discussion { Line 171  sub list_discussion {
     $crs=~s/\_/\//g;      $crs=~s/\_/\//g;
     my $encsymb=&Apache::lonenc::check_encrypt($ressymb);      my $encsymb=&Apache::lonenc::check_encrypt($ressymb);
     my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)      my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
   && ($ressymb=~/\.(problem|exam|quiz|assess|survey|form|task)$/));    && ($ressymb=~/$LONCAPA::assess_re/));
           
     my %usernamesort = ();      my %usernamesort = ();
     my %namesort =();      my %namesort =();
Line 257  sub list_discussion { Line 293  sub list_discussion {
     $visit ++;      $visit ++;
   
     my $seeid;      my $seeid;
     if (($group ne '') && ($mode eq 'board') &&       if (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
         ($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {          $seeid = 1;
         if (&check_group_priv($group,'dgp') eq 'ok') {  
             $seeid = 1;  
         }  
     } else {  
         $seeid=&Apache::lonnet::allowed('rin',$crs);  
     }      }
       my $seehidden = &can_see_hidden($mode,$ressymb,undef,$group,$cdom,$cnum,$crs);
   
   # Is voting on discussions available
       my $realsymb = &get_realsymb($ressymb);
       my $canvote = &discussion_vote_available($status,$realsymb);
   
     my @discussionitems=();      my @discussionitems=();
     my %shown = ();      my %shown = ();
     my @posteridentity=();      my @posteridentity=();
Line 281  sub list_discussion { Line 318  sub list_discussion {
     my $maxdepth=0;      my $maxdepth=0;
     my %anonhash=();      my %anonhash=();
     my $anoncnt=0;      my $anoncnt=0;
     my $target='';  
     unless ($env{'browser.interface'} eq 'textual' ||  
     $env{'environment.remote'} eq 'off' ) {  
  $target='target="LONcom"';  
     }  
   
     my $now = time;      my $now = time;
     $discinfo{$visitkey} = $visit;      $discinfo{$visitkey} = $visit;
   
     &Apache::lonnet::put('nohist_'.$cid.'_discuss',\%discinfo,$env{'user.domain'},$env{'user.name'});      &Apache::lonnet::put('nohist_'.$cid.'_discuss',\%discinfo,$env{'user.domain'},$env{'user.name'});
     &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);      &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,$seehidden,$canvote,$prevread,$sortposts,$encsymb,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);
   
     my $discussion='';      my $discussion='';
     my $manifestfile;      my $manifestfile;
Line 301  sub list_discussion { Line 333  sub list_discussion {
     my $copyresult;      my $copyresult;
   
     my $function = &Apache::loncommon::get_users_function();      my $function = &Apache::loncommon::get_users_function();
     my $color = &Apache::loncommon::designparm($function.'.tabbg',  
                                                     $env{'user.domain'});  
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
         'cuse' => 'Current discussion settings',          'cuse' => 'My settings for this discussion',
         'allposts' => 'All posts',          'allposts' => 'All posts',
         'unread' => 'New posts only',          'unread' => 'New posts only',
         'unmark' => 'Unread only',          'unmark' => 'Unread only',
Line 322  sub list_discussion { Line 352  sub list_discussion {
         'aner' => 'An error occurred opening the manifest file.',          'aner' => 'An error occurred opening the manifest file.',
         'difo' => 'Discussion for',          'difo' => 'Discussion for',
         'aerr' => 'An error occurred opening the export file for posting',          'aerr' => 'An error occurred opening the export file for posting',
           'discussions' => 'DISCUSSIONS'
       );
       my %js_lt = &Apache::lonlocal::texthash(
         'aysu' => 'Are you sure you want to delete this post?',          'aysu' => 'Are you sure you want to delete this post?',
         'dpwn' => 'Deleted posts will no longer be visible to you and other students',          'dpwn' => 'Deleted posts will no longer be visible to you and other students',
         'bwco' => 'but will continue to be visible to your instructor',          'bwco' => 'but will continue to be visible to your instructor',
         'depo' => 'Deleted posts will no longer be visible to you or anyone else.',          'depo' => 'Deleted posts will no longer be visible to you or anyone else.',
         'discussions' => 'DISCUSSIONS'  
     );      );
       &js_escape(\%js_lt);
   
     my $currdisp = $lt{'allposts'};      my $currdisp = $lt{'allposts'};
     my $currmark = $lt{'onmark'};      my $currmark = $lt{'onmark'};
Line 425  imscp_v1p1.xsd http://www.imsglobal.org/ Line 458  imscp_v1p1.xsd http://www.imsglobal.org/
             }              }
  } else {   } else {
             my $colspan=$maxdepth+1;              my $colspan=$maxdepth+1;
 #JW  
             $discussion.= &Apache::lonhtmlcommon::scripttag(qq|              $discussion.= &Apache::lonhtmlcommon::scripttag(qq|
    function verifydelete (caller,symb,idx,newflag,previous,groupparm) {     function verifydelete (caller,symb,idx,newflag,previous,groupparm) {
        var symbparm = symb+':::'+idx         var symbparm = symb+':::'+idx
Line 434  imscp_v1p1.xsd http://www.imsglobal.org/ Line 466  imscp_v1p1.xsd http://www.imsglobal.org/
            prevparm = "&amp;previous="+previous             prevparm = "&amp;previous="+previous
        }         }
        if (caller == 'studentdelete') {         if (caller == 'studentdelete') {
            if (confirm("$lt{'aysu'}\\n$lt{'dpwn'},\\n$lt{'bwco'}")) {             if (confirm("$js_lt{'aysu'}\\n$js_lt{'dpwn'},\\n$js_lt{'bwco'}")) {
                document.location.href = "/adm/feedback?hide="+symbparm+prevparm+groupparm                 document.location.href = "/adm/feedback?hide="+symbparm+prevparm+groupparm
            }             }
        } else {         } else {
            if (caller == 'seeiddelete') {             if (caller == 'seeiddelete') {
                if (confirm("$lt{'aysu'}\\n$lt{'depo'}")) {                 if (confirm("$js_lt{'aysu'}\\n$js_lt{'depo'}")) {
                    document.location.href = "/adm/feedback?deldisc="+symbparm+prevparm+groupparm                     document.location.href = "/adm/feedback?deldisc="+symbparm+prevparm+groupparm
                }                 }
            }             }
Line 447  imscp_v1p1.xsd http://www.imsglobal.org/ Line 479  imscp_v1p1.xsd http://www.imsglobal.org/
    }     }
             |);              |);
     $discussion.='<form name="readchoices" method="post" action="/adm/feedback?chgreads='.$ressymb.'" >'.      $discussion.='<form name="readchoices" method="post" action="/adm/feedback?chgreads='.$ressymb.'" >'.
                          "\n".'<table class="LC_discussion">';                           "\n".'<table width="100%" class="LC_discussion">';
             $discussion .= &action_links_bar($colspan,$ressymb,$visible,              $discussion .= &action_links_bar($colspan,$ressymb,$visible,
                                              $newpostsflag,$group,                                               $newpostsflag,$group,
                                              $prevread,$markondisp);                                               $prevread,$markondisp,$seehidden);
             my $escsymb=&escape($ressymb);              my $escsymb=&escape($ressymb);
             my $numhidden = keys(%notshown);              my $numhidden = keys(%notshown);
             if ($numhidden > 0) {              if ($numhidden > 0) {
                 my $colspan = $maxdepth+1;                  my $colspan = $maxdepth+1;
                 $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">'.                  $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">';
                          '<a href="/adm/feedback?allposts=1&amp;symb='.$escsymb;                  my $href = '/adm/feedback?allposts=1&amp;symb='.$escsymb;
                 if ($newpostsflag) {                  if ($newpostsflag) {
                     $discussion .= '&amp;previous='.$prevread;                      $href .= '&amp;previous='.$prevread;
                 }                  }
  $discussion .= &group_args($group);   $href .= &group_args($group);
                 $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.  
                          $numhidden.' ';  
                 if ($showunmark) {                  if ($showunmark) {
                     $discussion .= &mt('posts previously marked read');                      $discussion .= &mt('[_1]Show all posts[_2] to display [quant,_3,post] previously marked read',
                                          '<a href="'.$href.'">','</a>',$numhidden);
                 } else {                  } else {
                     $discussion .= &mt('previously viewed posts');                      $discussion .= &mt('[_1]Show all posts[_2] to display [quant,_3,post] previously viewed',
                                          '<a href="'.$href.'">','</a>',$numhidden);
                 }                  }
                 $discussion .= '<br/></td></tr>';                  $discussion .= '<br/></td></tr>';
             }              }
Line 500  imscp_v1p1.xsd http://www.imsglobal.org/ Line 532  imscp_v1p1.xsd http://www.imsglobal.org/
         my $currdepth = 0;          my $currdepth = 0;
         my $firstidx = $alldiscussion{$showposts[0]};          my $firstidx = $alldiscussion{$showposts[0]};
         foreach my $post (@showposts) {          foreach my $post (@showposts) {
             unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) {              unless (($sortposts eq 'thread') || 
                       (($sortposts eq '') && (!$env{'environment.unthreadeddiscussion'})) || 
                       ($outputtarget eq 'export')) {
                 $alldiscussion{$post} = $post;                  $alldiscussion{$post} = $post;
             }              }
             unless ( ($notshown{$alldiscussion{$post}} eq '1') || ($shown{$alldiscussion{$post}} == 0) ) {              unless ( ($notshown{$alldiscussion{$post}} eq '1') || ($shown{$alldiscussion{$post}} == 0) ) {
Line 510  imscp_v1p1.xsd http://www.imsglobal.org/ Line 544  imscp_v1p1.xsd http://www.imsglobal.org/
         my $thisdepth=$depth[$alldiscussion{$post}];          my $thisdepth=$depth[$alldiscussion{$post}];
                 if ($outputtarget ne 'tex' && $outputtarget ne 'export') {                  if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
     for (1..$thisdepth) {      for (1..$thisdepth) {
  $discussion.='<td>&nbsp;&nbsp;&nbsp;</td>';   $discussion.='<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>';
     }      }
  }   }
         my $colspan=$maxdepth-$thisdepth+1;          my $colspan=$maxdepth-$thisdepth+1;
Line 547  imscp_v1p1.xsd http://www.imsglobal.org/ Line 581  imscp_v1p1.xsd http://www.imsglobal.org/
                     my $postingfile;                      my $postingfile;
                     my $postingfilename = $tempexport.'/'.$postfilename;                      my $postingfilename = $tempexport.'/'.$postfilename;
                     if ($postingfile = Apache::File->new('>'.$postingfilename)) {                      if ($postingfile = Apache::File->new('>'.$postingfilename)) {
                         print $postingfile '<html><head><title>Discussion Post</title></head><body>'.                          print $postingfile '<html><head><title>'.&mt('Discussion Post').'</title></head><body>'.
                                            $imsitems{$alldiscussion{$post}}{'title'}.' '.                                             $imsitems{$alldiscussion{$post}}{'title'}.' '.
                                            $imsitems{$alldiscussion{$post}}{'sender'}.                                             $imsitems{$alldiscussion{$post}}{'sender'}.
                                            $imsitems{$alldiscussion{$post}}{'timestamp'}.'<br /><br />'.                                             $imsitems{$alldiscussion{$post}}{'timestamp'}.'<br /><br />'.
Line 568  imscp_v1p1.xsd http://www.imsglobal.org/ Line 602  imscp_v1p1.xsd http://www.imsglobal.org/
  unless ($outputtarget eq 'tex' || $outputtarget eq 'export') {   unless ($outputtarget eq 'tex' || $outputtarget eq 'export') {
             my $colspan=$maxdepth+1;              my $colspan=$maxdepth+1;
             $discussion .= <<END;              $discussion .= <<END;
             <tr bgcolor="#FFFFFF">              <tr>
              <td colspan="$colspan" class="LC_disc_action_links_bar">               <td colspan="$colspan">
               <table class="LC_disc_action_table">                <table width="100%">
                <tr>                 <tr>
                 <td align="left">                  <td class="LC_disc_action_left">
                  <table border="0" cellpadding="0" cellspacing="4">                      <font size="-1"><b>$lt{'cuse'}</b>:&nbsp;
                   <tr>  
                    <td>  
                     <font size="-1"><b>$lt{'cuse'}</b>:</font></td>  
                    <td>&nbsp;</td>  
                    <td><font size="-1">  
 END  END
             if ($newpostsflag) {              if ($newpostsflag) {
                 $discussion .=                   $discussion .= 
Line 595  END Line 624  END
                 }                  }
             }              }
             $discussion .= <<END;              $discussion .= <<END;
                    </font></td>                     &nbsp;&nbsp;<b><a href="$chglink">$lt{'chgt'}</a></b></font>
                    <td>&nbsp;</td>  
                    <td align="left">  
                     <font size="-1"><b><a href="$chglink">$lt{'chgt'}</a>?</b></font>  
                    </td>  
                   </tr>  
                  </table>  
                 </td>                  </td>
 END  END
             if ($sortposts) {              if ($sortposts) {
Line 610  END Line 633  END
                 my %status_types = ();                  my %status_types = ();
                 &sort_filter_names(\%sort_types,\%role_types,\%status_types,$crstype);                  &sort_filter_names(\%sort_types,\%role_types,\%status_types,$crstype);
   
                 $discussion .= '<td><font size="-1"><b>'.&mt('Sorted by').'</b>: '.$sort_types{$sortposts}.'<br />';                  $discussion .= '<td class="LC_disc_action_right"><font size="-1"><b>'.&mt('Sorted by').'</b>: '.$sort_types{$sortposts}.'<br />';
                 if (defined($env{'form.totposters'})) {                  if (defined($env{'form.totposters'})) {
                     $discussion .= &mt('Posts by').':';                      $discussion .= &mt('Posts by').':';
                     if ($totposters > 0) {                      if ($totposters > 0) {
Line 645  END Line 668  END
                     if ($filterchoice) {                      if ($filterchoice) {
                         $discussion .= '<b>'.&mt('Filters').'</b>:&nbsp;'.$filterchoice;                          $discussion .= '<b>'.&mt('Filters').'</b>:&nbsp;'.$filterchoice;
                     }                      }
                     $discussion .= '</font></td>';  
                 }                  }
                   $discussion .= '</font></td>';
   
             }              }
             if ($dischash{$toggkey}) {              if ($dischash{$toggkey}) {
                 my $storebutton = &mt('Save read/unread changes');                  my $storebutton = &mt('Save read/unread changes');
Line 664  END Line 688  END
 END  END
             $discussion .= &action_links_bar($colspan,$ressymb,$visible,              $discussion .= &action_links_bar($colspan,$ressymb,$visible,
                                              $newpostsflag,$group,                                               $newpostsflag,$group,
                                              $prevread,$markondisp);                                               $prevread,$markondisp,$seehidden);
             $discussion .= "              $discussion .= "</table></form>\n";
            </table>          }
            <br /><br /></form>\n";  
         }   
         if ($outputtarget eq 'export') {          if ($outputtarget eq 'export') {
             if ($manifestok) {              if ($manifestok) {
                 while ($currdepth > 0) {                  while ($currdepth > 0) {
Line 690  END Line 712  END
   
 #Create zip file in prtspool  #Create zip file in prtspool
   
                     my $imszipfile = '/prtspool/'.                      if (($env{'user.name'} =~ /^$match_username$/)
                     $env{'user.name'}.'_'.$env{'user.domain'}.'_'.                          && ($env{'user.domain'} =~ /^$match_domain$/)) {
                          time.'_'.rand(1000000000).'.zip';                          my $now = time();
                     my $cwd = &getcwd();                           my $imszipfile = '/prtspool/'.
                     my $imszip = '/home/httpd/'.$imszipfile;                                        join('_',$env{'user.name'},$env{'user.domain'},$now).
                     chdir $tempexport;                                        '_'.rand(1000000000).'.zip';
                     open(OUTPUT, "zip -r $imszip *  2> /dev/null |");                          my $zip = Archive::Zip->new();
                     close(OUTPUT);                          $zip->addTree($tempexport);
                     chdir $cwd;                          my $imszip = '/home/httpd/'.$imszipfile;
                     $discussion .= &mt('Download the zip file from [_1]Discussion Posting Archive','<a href="'.$imszipfile.'">').'</a><br />';                          if ($zip->writeToFileNamed($imszip) == AZ_OK) {
                     if ($copyresult) {                              $discussion .= &mt('Download the zip file from [_1]Discussion Posting Archive[_2]',
                         $discussion .= &mt('The following errors occurred during export').' - <br />'.$copyresult;                                             '<a href="'.$imszipfile.'">','</a>').'<br />';
                           } else {
                               $discussion .=  &mt('Failed to create zip file').'<br />';
                           }
                           if ($copyresult) {
                               $discussion .= '<span class="LC_error">'.
                                              &mt('The following errors occurred during export:').
                                              '</span><br />'.$copyresult;
                           }
                       } else {
                           $discussion .= '<p class="LC_error">'.
                                          &mt('Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating the zip file.').'</p>';
                     }                      }
                 }                  }
             } else {              } else {
                 $discussion .= '<br />'.&mt('Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating a manifest file.').'<br />';                  $discussion .= '<p class="LC_error">'.
                                  &mt('Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating a manifest file.').'</p>';
             }              }
             return $discussion;              return $discussion;
         }          }
Line 728  END Line 762  END
             }              }
         }          }
  if ((&discussion_open($status)) && ($outputtarget ne 'tex')) {   if ((&discussion_open($status)) && ($outputtarget ne 'tex')) {
             if (($group ne '') && ($mode eq 'board')) {              if (($group ne '') && ($mode eq 'board')) {  
                 if ((&check_group_priv($group,'pgd') eq 'ok') &&                  if ((&check_group_priv($group,'pgd') eq 'ok') && 
                    ($ressymb =~ m{^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$})) {                     ($ressymb =~ m{^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$})) {
                     $discussion .=                      $discussion .=
  &postingform_display($mode,$ressymb,$now,$subject,   &postingform_display($mode,$ressymb,$now,$subject,
Line 741  END Line 775  END
                 if (&Apache::lonnet::allowed('pch',$env{'request.course.id'}.                  if (&Apache::lonnet::allowed('pch',$env{'request.course.id'}.
                     ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {                      ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
   
                     $discussion.=              $discussion.= 
                         &postingform_display($mode,$ressymb,$now,$subject,          &postingform_display($mode,$ressymb,$now,$subject,
                                              $comment,$outputtarget,$attachnum,       $comment,$outputtarget,$attachnum,
                                              $currnewattach,$currdelold,'',$crstype);       $currnewattach,$currdelold,'',$crstype);
                 } else {                  } else {
                     $discussion.= '<span class="LC_feedback_link">'.                      $discussion.= '<span class="LC_feedback_link">'.
                                   &mt('This discussion is closed.').'</span>';                                    &mt('This discussion is closed.').'</span>';
Line 756  END Line 790  END
                           &mt('This discussion is closed.').'</span>';                            &mt('This discussion is closed.').'</span>';
         }          }
     } elsif ($outputtarget ne 'tex') {      } elsif ($outputtarget ne 'tex') {
         $discussion.='<div class="LC_feedback_link">';          unless ($nofooter) {
         if (&discussion_open($status) &&              $discussion.='<div class="LC_feedback_link">';
             &Apache::lonnet::allowed('pch',              unless ($nodisclink) {
            $env{'request.course.id'}.                  if (&discussion_open($status) &&
         ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {                      &Apache::lonnet::allowed('pch',
     $discussion.= &send_feedback_link($ressymb,$target);                     $env{'request.course.id'}.
             if ($env{'request.role.adv'}) {                  ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
                 my $close = &Apache::lonnet::EXT('resource.0.discussend',$ressymb);                      $discussion.= &send_feedback_link($ressymb);
                 if (defined($close) && $close ne '' && $close < time) {                      if ($env{'request.role.adv'}) {
                     $discussion .= '&nbsp;'.&mt('(Closed for [_1] roles)',                          my $close = &Apache::lonnet::EXT('resource.0.discussend',$ressymb);
                                                 &Apache::lonnet::plaintext('st',$crstype));                          my $canvote = &Apache::lonnet::EXT('resource.0.discussvote',$ressymb);
                           if (defined($close) && $close ne '' && $close < time) {
                               if ($canvote eq 'notended') {
                                   $discussion .= '&nbsp;'.&mt('(Posting and voting closed for [_1] roles)',
                                                               &Apache::lonnet::plaintext('st',$crstype));
                               } else {
                                   $discussion .= '&nbsp;'.&mt('(Closed for [_1] roles)',
                                                               &Apache::lonnet::plaintext('st',$crstype));
                               }
                           }
                       }
           } else {
                       $discussion.= '<span class="LC_feedback_link">'.&mt('This discussion is closed.').'</span>';
                 }                  }
             }              }
         } else {              unless ($nofdbklink) {
             $discussion.= '<span class="LC_feedback_link">'.&mt('This discussion is closed.').'</span>';          $discussion.= &send_message_link($ressymb);
               }
               $discussion.='</div>';
         }          }
  $discussion.= &send_message_link($ressymb).'</div>';  
     }      }
     return $discussion;      return $discussion;
 }  }
   
   sub check_menucoll {
       my ($nofooter,$nodisclink,$nofdbklink);
       my ($menucoll,$deeplinkmenu,$menuref) = &Apache::loncommon::menucoll_in_effect();
       if ($menucoll) {
           if (ref($menuref) eq 'HASH') {
               if ($menuref->{'foot'} eq 'n') {
                   $nofooter = 1;
               } else {
                   unless ($menuref->{'disc'}) {
                       $nodisclink = 1;
                   }
                   unless ($menuref->{'fdbk'}) {
                       $nofdbklink = 1;
                   }
               }
           }
       }
       return ($nofooter,$nodisclink,$nofdbklink);
   }
   
   sub can_see_hidden {
       my ($mode,$ressymb,$feedurl,$group,$cdom,$cnum,$crs) = @_;
       my $seehidden;
       if ($env{'request.course.id'}) {
           unless ($cdom ne '' && $cnum ne '') {
               $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
           }
           if ($crs eq '') {
               $crs = '/'.$env{'request.course.id'};
               if ($env{'request.course.sec'}) {
                   $crs.='_'.$env{'request.course.sec'};
               }
               $crs=~s{_}{/}g;
           }
           if ($mode eq '') {
               $mode='board';
               if ($feedurl =~ /$LONCAPA::assess_re/) {
                   $mode='problem';
               }
           }
           if (($group ne '') && ($mode eq 'board') &&
               ($ressymb =~ m{^bulletin___\d+\Q___adm/wrapper/adm/$cdom/$cnum/\E\d+/bulletinboard$})) {
               if (&check_group_priv($group,'dgp') eq 'ok') {
                   $seehidden = 1;
               }
           } else {
               $seehidden=&Apache::lonnet::allowed('rin',$crs);
           }
       }
       return $seehidden;
   }
   
   sub discussion_link {
      my ($ressymb,$linktext,$cmd,$item,$flag,$prev,$adds,$title)=@_;
      my $link='/adm/feedback?inhibitmenu=yes&amp;modal=yes&amp;'.$cmd.'='.&escape($ressymb).':::'.$item;
      if ($flag) { $link .= '&amp;previous='.$prev; }
      if ($adds) { $link .= $adds; }
      my $width=600;
      my $height=600;
      if (($cmd eq 'hide') || ($cmd eq 'unhide') || ($cmd eq 'like') || ($cmd eq 'unlike')) {
          $width=300;
          $height=200;
      }
      return &Apache::loncommon::modal_link($link,$linktext,$width,$height,undef,undef,$title);
   }
   
   
 sub send_feedback_link {  sub send_feedback_link {
     my ($ressymb,$target) = @_;      my ($ressymb) = @_;
     my $output = '<span class="LC_feedback_link">'.      return '<span class="LC_feedback_link">'.
                  ' <a href="/adm/feedback?replydisc='.                   &discussion_link($ressymb,
                  &escape($ressymb).':::" '.$target.'>'.                      '<img alt="" class="LC_noBorder" src="'.
                  '<img alt="" class="LC_noBorder" src="'.                      &Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').
                  &Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').                      '" /><span class="LC_menubuttons_inline_text">'.&mt('Post Discussion').'</span>',
                  '" border="0" /><span class="LC_menubuttons_inline_text">'.&mt('Post Discussion').'</span></a></span>';                      'replydisc').
     return $output;             '</span>';
 }  }
   
 sub send_message_link {  sub send_message_link {
     my ($ressymb) = @_;      my ($ressymb) = @_;
     my $output = '<span class="LC_message_link">'.      my $output = '<span class="LC_message_link">'.
                  '  <a href="/adm/feedback?sendmessageonly=1&amp;symb='.                   &discussion_link($ressymb,
                  &escape($ressymb).'"><img alt="" class="LC_noBorder" src="'.                      '<img alt="" class="LC_noBorder" src="'.
                  &Apache::loncommon::lonhttpdurl('/res/adm/pages/feedback.png').                      &Apache::loncommon::lonhttpdurl('/res/adm/pages/feedback.png').
                  '" border="0" /><span class="LC_menubuttons_inline_text">'.&mt('Send Feedback').'</span></a></span>';                      '" /><span class="LC_menubuttons_inline_text">'.&mt('Send Feedback').'</span>',
                       'sendmessageonly').
                    '</span>';
     return $output;      return $output;
 }  }
   
 sub action_links_bar {  sub action_links_bar {
     my ($colspan,$ressymb,$visible,$newpostsflag,$group,$prevread,$markondisp) = @_;      my ($colspan,$ressymb,$visible,$newpostsflag,$group,$prevread,$markondisp,
     my $discussion = '<tr><td class="LC_disc_action_links_bar" colspan="'.$colspan.'">'.          $seehidden) = @_;
                      '<table width="100%" class="LC_disc_action_table"><tr>'.      my $discussion = '<tr><td colspan="'.$colspan.'">'.
                        '<table width="100%"><tr>'.
                      '<td class="LC_disc_action_left">';                       '<td class="LC_disc_action_left">';
     my $escsymb=&escape($ressymb);      my $escsymb=&escape($ressymb);
     if ($visible) {      if ($visible) {
Line 816  sub action_links_bar { Line 934  sub action_links_bar {
             $discussion .= '&amp;previous='.$prevread;              $discussion .= '&amp;previous='.$prevread;
         }          }
         $discussion .= &group_args($group);          $discussion .= &group_args($group);
         $discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;          $discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;';
                        <a href="/adm/feedback?cmd=sortfilter&amp;symb='.$escsymb;  
           my $otherviewurl='/adm/feedback?cmd=sortfilter&amp;symb='.$escsymb.'&amp;inhibitmenu=yes&amp;modal=yes';
         if ($newpostsflag) {          if ($newpostsflag) {
             $discussion .= '&amp;previous='.$prevread;              $otherviewurl .= '&amp;previous='.$prevread;
         }          }
         $discussion .= &group_args($group);          $otherviewurl .= &group_args($group);
         $discussion .='">'.&mt('Sorting/Filtering options').'</a>'.('&nbsp;' x2);          $discussion .= &Apache::loncommon::modal_link($otherviewurl,&mt('Other Views ...'),800,340);
           $discussion .= '<br />';
     }      }
     $discussion .='<a href="/adm/feedback?export='.$escsymb;      $discussion .='<a href="/adm/feedback?export='.$escsymb;
     if ($newpostsflag) {      if ($newpostsflag) {
         $discussion .= '&amp;previous='.$prevread;          $discussion .= '&amp;previous='.$prevread;
     }      }
     $discussion .= &group_args($group);      $discussion .= &group_args($group);
     $discussion .= '">'.&mt('Export').'?</a>&nbsp;&nbsp;</td>';      $discussion .= '">'.&mt('Export').'</a>';
       if ($seehidden) {
           $discussion .= '&nbsp;&nbsp;';
           $discussion .='<a href="/adm/feedback?undeleteall='.$escsymb;
           if ($newpostsflag) {
               $discussion .= '&amp;previous='.$prevread;
           }
           $discussion .= &group_args($group);
           $discussion .= '">'.&mt('Undelete all deleted entries').'</a>';
       }
       $discussion.='</td>';
     if ($newpostsflag) {      if ($newpostsflag) {
         if (!$markondisp) {          if (!$markondisp) {
             $discussion .='<td class="LC_disc_action_right"><a href="/adm/preferences?action=changediscussions';              $discussion .='<td class="LC_disc_action_right"><a href="/adm/preferences?action=changediscussions';
             $discussion .= &group_args($group);              $discussion .= &group_args($group);
             $discussion .= '">'.              $discussion .= '">'.
                            &mt('Preferences on what is marked as NEW').                             &mt('My general preferences on what is marked as NEW').
                            '</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb;                             '</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb;
             $discussion .= &group_args($group);              $discussion .= &group_args($group);
             $discussion .= '">'.&mt('Mark NEW posts no longer new').'</a></td>';              $discussion .= '">'.&mt('Mark NEW posts no longer new').'</a></td>';
Line 854  sub postingform_display { Line 984  sub postingform_display {
         $currnewattach,$currdelold,$group,$crstype) = @_;          $currnewattach,$currdelold,$group,$crstype) = @_;
     my $newattachmsg;      my $newattachmsg;
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
               'note' => 'Note: in anonymous discussion, your name is visible only to course faculty',               'note' => 'Note: in anonymous discussion, your name is visible only to course faculty',
              'title' => 'Title',               'title' => 'Title',
              'podi' => 'Post Discussion',               'podi' => 'Post Discussion',
              'poan' => 'Post Anonymous Discussion',               'poan' => 'Post Anonymous Discussion',
Line 878  sub postingform_display { Line 1008  sub postingform_display {
 <input type="submit" name="anondiscuss" value="$lt{'poan'}" /> <input type="hidden" name="symb" value="$ressymb" />  <input type="submit" name="anondiscuss" value="$lt{'poan'}" /> <input type="hidden" name="symb" value="$ressymb" />
 <input type="hidden" name="sendit" value="true" />  <input type="hidden" name="sendit" value="true" />
 <input type="hidden" name="timestamp" value="$now" />  <input type="hidden" name="timestamp" value="$now" />
 <br /><a name="newpost"></a>  <a name="newpost"></a>
 <font size="1">$lt{'note'}</font><br />  <font size="1">$lt{'note'}</font><br />
 <b>$lt{'title'}:</b>&nbsp;<input type="text" name="subject" value="$subject" size="30" /><br /><br />  <b>$lt{'title'}:</b>&nbsp;<input type="text" name="subject" value="$subject" size="30" /><br />
 <textarea name="comment" cols="80" rows="14" id="comment" $textareaclass>$comment</textarea>  <textarea name="comment" cols="80" rows="14" id="comment" $textareaclass>$comment</textarea>
 ENDDISCUSS  ENDDISCUSS
     if ($env{'form.origpage'}) {      if ($env{'form.origpage'}) {
Line 904  ENDDISCUSS Line 1034  ENDDISCUSS
     }      }
     $postingform .= "</form>\n";      $postingform .= "</form>\n";
     $postingform .= &generate_attachments_button('',$attachnum,$ressymb,      $postingform .= &generate_attachments_button('',$attachnum,$ressymb,
                                                  $now,$currnewattach,                                                       $now,$currnewattach,
                                                  $currdelold,'',$mode,                                                       $currdelold,'',$mode,
                                                  $blockblog);                                                       $blockblog);
     if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {      if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
         $newattachmsg = '<br /><b>'.$lt{'newa'}.'</b><br />';          $newattachmsg = '<br /><b>'.$lt{'newa'}.'</b><br />';
         if (@{$currnewattach} > 1) {          if (@{$currnewattach} > 1) {
             $newattachmsg .= '<ol>';               $newattachmsg .= '<ol>';
             foreach my $item (@{$currnewattach}) {               foreach my $item (@{$currnewattach}) {
                 $item =~ m#.*/([^/]+)$#;                  $item =~ m#.*/([^/]+)$#;
                 $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";                  $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
             }               }
             $newattachmsg .= '</ol>'."\n";               $newattachmsg .= '</ol>'."\n";
         } else {           } else {
             $$currnewattach[0] =~ m#.*/([^/]+)$#;               $$currnewattach[0] =~ m#.*/([^/]+)$#;
             $newattachmsg .= '<a href="'.$$currnewattach[0].'">'.$1.'</a><br />'."\n";               $newattachmsg .= '<a href="'.$$currnewattach[0].'">'.$1.'</a><br />'."\n";
         }           }
     }      }
     $postingform .= $newattachmsg;      $postingform .= $newattachmsg;
     $postingform .= &generate_preview_button();      $postingform .= &generate_preview_button();
Line 927  ENDDISCUSS Line 1057  ENDDISCUSS
 }  }
   
 sub build_posting_display {  sub build_posting_display {
     my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;      my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$seehidden,$canvote,$prevread,$sortposts,$ressymb,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
     my @original=();      my @original=();
     my @index=();      my @index=();
     my $skip_group_check = 0;      my $skip_group_check = 0;
     my $symb=&Apache::lonenc::check_decrypt($ressymb);      my $symb=&Apache::lonenc::check_decrypt($ressymb);
     my $escsymb=&escape($ressymb);      my $escsymb=&escape($ressymb);
   # These are the discussion contributions
     my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},      my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
   $env{'course.'.$env{'request.course.id'}.'.domain'},    $env{'course.'.$env{'request.course.id'}.'.domain'},
   $env{'course.'.$env{'request.course.id'}.'.num'});    $env{'course.'.$env{'request.course.id'}.'.num'});
       my (%likes,%userlikes,%userunlikes,@theselikes,$oneplus,$twoplus,$oneminus,$twominus);
       my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
       if ($seeid || $canvote) {
   # And these are the likes/unlikes
           %likes=&Apache::lonnet::dump('disclikes',
                             $env{'course.'.$env{'request.course.id'}.'.domain'},
                             $env{'course.'.$env{'request.course.id'}.'.num'},
                             '^'.$symb.':');
   # Array with likes to figure out averages, etc.
           @theselikes=();
   # Hashes containing likes and unlikes for this user.
           %userlikes=();
           %userunlikes=();
       }
   # Is the user allowed to see the real name behind anonymous postings?
     my $see_anonymous =       my $see_anonymous = 
  &Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));   &Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
   
     if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {      if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {
         $skip_group_check = 1;          $skip_group_check = 1;
     }      }
   # Deletions and hiddens are just lists. Split them up into a hash for quicker lookup
     my (%deletions,%hiddens);      my (%deletions,%hiddens);
     if ($contrib{'deleted'}) {      if ($contrib{'deleted'}) {
        my $deleted = $contrib{'deleted'};         my $deleted = $contrib{'deleted'};
Line 956  sub build_posting_display { Line 1102  sub build_posting_display {
        $hidden =~ s/\.$//;         $hidden =~ s/\.$//;
        %hiddens = map { $_ => 1 } (split(/\.\./,$hidden));         %hiddens = map { $_ => 1 } (split(/\.\./,$hidden));
     }      }
   # Versions if store/restore are used to actually store the messages. 
     if ($contrib{'version'}) {      if ($contrib{'version'}) {
         my $oldest = $contrib{'1:timestamp'};          my $oldest = $contrib{'1:timestamp'};
         if ($prevread eq '0') {          if ($prevread eq '0') {
Line 966  sub build_posting_display { Line 1113  sub build_posting_display {
             ($skiptest,$roleregexp,$secregexp,$statusregexp) =               ($skiptest,$roleregexp,$secregexp,$statusregexp) = 
                      &filter_regexp($rolefilter,$sectionpick,$statusfilter);                       &filter_regexp($rolefilter,$sectionpick,$statusfilter);
             $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;              $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
         }           }
           my %votestyle;
           if ($seeid || $canvote) {
   # We need to go through this twice, first to get the likes/dislikes, then to actually build the display
               for (my $id=1;$id<=$contrib{'version'};$id++) {
                   my $idx=$id;
                   next if ($contrib{$idx.':deleted'});
                   next if ($contrib{$idx.':hidden'});
                   unless ((($hiddens{$idx}) && (!$seehidden)) || ($deletions{$idx}) || (!$contrib{$idx.':message'})) {
                       push(@theselikes,$likes{$symb.':'.$idx.':likes'});
                       if ($likes{$symb.':'.$idx.':likes'} ne '') {
                           if (ref($likes{$symb.':'.$idx.':likers'}) eq 'HASH') {
                               if (exists($likes{$symb.':'.$idx.':likers'}{$thisuser})) {
                                   $userlikes{$idx} = 1;
                               }
                           }
                           if (ref($likes{$symb.':'.$idx.':unlikers'}) eq 'HASH') {
                               if (exists($likes{$symb.':'.$idx.':unlikers'}{$thisuser})) {
                                   $userunlikes{$idx} = 1;
                               }
                           }
                       }
                   }
               }
   # Figure out average likes and standard deviation if there are enough 
   # discussions to warrant that
               my $ave=0;
               my $stddev=10000;
               if ($#theselikes>1) {
                   my $sum=0;
                   my $num=$#theselikes+1;
                   foreach my $thislike (@theselikes) {
                       $sum+=$thislike;
                   }
                   $ave=$sum/$num;
                   my $sumsq=0;
                   foreach my $thislike (@theselikes) {
                       $sumsq+=($thislike-$ave)*($thislike-$ave);
                   }
                   $stddev=sqrt($sumsq/$num);
               }
   # Now we know the average likes $ave and the standard deviation $stddev
   # Get the boundaries for markup
               $oneplus=$ave+$stddev;
               $twoplus=$ave+2.*$stddev;
               $oneminus=$ave-$stddev;
               $twominus=$ave-2.*$stddev;
               if ($#theselikes>1) {
                   foreach my $class ('twoplus','oneplus','zero','oneminus','twominus') {
                       my $fontstyle = $env{'course.'.$env{'request.course.id'}.'.discussion_post_fonts_'.$class};
                       if ($fontstyle ne '') {
                           my ($size,$weight,$style,$other) = split(/,/,$fontstyle);
                           if ($size ne '') {
                               $votestyle{$class} .= 'font-size: '.$size.';';
                           }
                           if ($weight ne '') {
                               $votestyle{$class} .= 'font-weight: '.$weight.';';
                           }
                           if ($style ne '') {
                               $votestyle{$class} .= 'font-style: '.$style.';';
                           }
                           if ($other ne '') {
                               $votestyle{$class} .= $other;
                           }
                           if ($votestyle{$class} ne '') {
                               $votestyle{$class} = 'style="'.$votestyle{$class}.'"';
                           }
                       }
                   }
               }
           }
   #
   # This is now the real loop. Go through all entries, pick up what we need
   #
  for (my $id=1;$id<=$contrib{'version'};$id++) {   for (my $id=1;$id<=$contrib{'version'};$id++) {
     my $idx=$id;      my $idx=$id;
             next if ($contrib{$idx.':deleted'});              next if ($contrib{$idx.':deleted'});
             next if ($contrib{$idx.':hidden'});              next if ($contrib{$idx.':hidden'});
   # If we get here, we are actually going to display the message - we don't know where and we don't know if we display
   # previous edits, but it counts as one entry
             my $posttime = $contrib{$idx.':timestamp'};              my $posttime = $contrib{$idx.':timestamp'};
             if ($prevread <= $posttime) {              if ($prevread <= $posttime) {
                 $$newpostsflag = 1;                  $$newpostsflag = 1;
Line 979  sub build_posting_display { Line 1201  sub build_posting_display {
     my $origindex='0.';      my $origindex='0.';
             my $numoldver=0;              my $numoldver=0;
     if ($contrib{$idx.':replyto'}) {      if ($contrib{$idx.':replyto'}) {
                 if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {                  if ( ((!$env{'environment.unthreadeddiscussion'}) && ($sortposts eq '')) || 
                        ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
 # this is a follow-up message  # this is a follow-up message
     $original[$idx]=$original[$contrib{$idx.':replyto'}];      $original[$idx]=$original[$contrib{$idx.':replyto'}];
     $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1;      $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1;
Line 999  sub build_posting_display { Line 1222  sub build_posting_display {
     } else {      } else {
  $$replies[$$depth[$idx]]=1;   $$replies[$$depth[$idx]]=1;
     }      }
     unless ((($hiddens{$idx}) && (!$seeid)) || ($deletions{$idx})) {              unless ((($hiddens{$idx}) && (!$seehidden)) || ($deletions{$idx})) {
  $$visible++;   $$visible++;
                 if ($contrib{$idx.':history'}) {                  if ($contrib{$idx.':history'}) {
                     if ($contrib{$idx.':history'} =~ /:/) {                      if ($contrib{$idx.':history'} =~ /:/) {
Line 1014  sub build_posting_display { Line 1237  sub build_posting_display {
                 my %subjects = ();                  my %subjects = ();
                 my %attachtxt = ();                  my %attachtxt = ();
                 my %allattachments = ();                  my %allattachments = ();
                 my ($screenname,$plainname);                  my ($screenname,$plainname,$showaboutme);
                 my $sender = &mt('Anonymous');                  my $sender = &mt('Anonymous');
 # Anonymous users getting number within a discussion  # Anonymous users getting number within a discussion
 # Since idx is in static order, this should give the same sequence every time.   # Since idx is in static order, this should give the same sequence every time. 
Line 1024  sub build_posting_display { Line 1247  sub build_posting_display {
     $$anonhash{$key}=&mt('Anonymous').' '.$anoncnt;      $$anonhash{$key}=&mt('Anonymous').' '.$anoncnt;
  }   }
                 my ($message,$subject,$vgrlink,$ctlink);                  my ($message,$subject,$vgrlink,$ctlink);
                 &get_post_contents(\%contrib,$idx,$seeid,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,$numoldver);                  &get_post_contents(\%contrib,$idx,$seeid,$seehidden,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,\$showaboutme,$numoldver);
   
   
 # Set up for sorting by subject  # Set up for sorting by subject
Line 1054  sub build_posting_display { Line 1277  sub build_posting_display {
                             }                              }
                         }                          }
         if (!$contrib{$idx.':anonymous'} || $see_anonymous) {          if (!$contrib{$idx.':anonymous'} || $see_anonymous) {
     $sender=&Apache::loncommon::aboutmewrapper(                              if ($showaboutme) {
  $plainname,                                  $sender = &Apache::loncommon::aboutmewrapper(
  $contrib{$idx.':sendername'},                                                $plainname,
  $contrib{$idx.':senderdomain'}).' ('.                                                $contrib{$idx.':sendername'},
  $contrib{$idx.':sendername'}.':'.                                                $contrib{$idx.':senderdomain'});
  $contrib{$idx.':senderdomain'}.')';                              } else {
                                   $sender = $plainname;
                               }
                               if ($see_anonymous) {
                                   $sender .= ' ('.$contrib{$idx.':sendername'}.':'.
      $contrib{$idx.':senderdomain'}.')';
                               }
                             $sender = '<b>'.$sender.'</b>';                              $sender = '<b>'.$sender.'</b>';
     if ($contrib{$idx.':anonymous'}) {      if ($contrib{$idx.':anonymous'}) {
         $sender.=' <font color="red"><b>['.$$anonhash{$key}.']</b></font> '.          $sender.=' <font color="red"><b>['.$$anonhash{$key}.']</b></font> '.
Line 1098  sub build_posting_display { Line 1327  sub build_posting_display {
                                 @{$$namesort{$lastname}{$firstname}} = ("$idx");                                  @{$$namesort{$lastname}{$firstname}} = ("$idx");
                             }                              }
                             if ($outputtarget ne 'tex') {                              if ($outputtarget ne 'tex') {
   # Add karma stars
                                   my $karma=&userkarma($contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'});
                                   for (my $i=1;$i<=$karma;$i++) {
                                       $sender.='<img border="0" src="/res/adm/pages/star.gif" alt="'.&mt('Contributor Kudos').'" />';
                                   }
   # Can people edit this?
                                 if (&editing_allowed($escsymb.':::'.$idx,$group)) {                                  if (&editing_allowed($escsymb.':::'.$idx,$group)) {
                                     if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {                                      if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
                                         $sender.=' <a href="/adm/feedback?editdisc='.                                          $sender.=' '.
                                              $escsymb.':::'.$idx;                                           &discussion_link($ressymb,&mt('Edit'),'editdisc',$idx,$$newpostsflag,$prevread,&group_args($group));
                                         if ($$newpostsflag) {                                          unless ($seehidden) {
                                             $sender .= '&amp;previous='.$prevread;  
                                         }  
         $sender .= &group_args($group);  
                                         $sender .= '" '.$target.'>'.&mt('Edit').'</a>';  
                                       
                                         unless ($seeid) {  
                                             my $grpargs = &group_args($group);                                              my $grpargs = &group_args($group);
                                             $sender.=" <a href=\"javascript:verifydelete('studentdelete','$escsymb','$idx','$$newpostsflag','$prevread','$grpargs')";                                              $sender.=" <a href=\"javascript:verifydelete('studentdelete','$escsymb','$idx','$$newpostsflag','$prevread','$grpargs')";
                                             $sender .= '">'.&mt('Delete').'</a>';                                              $sender .= '">'.&mt('Delete').'</a>';
                                         }                                          }
                                     }                                      }
                                 }                                  }
                                 if ($seeid) {          if ($seehidden) {
             if ($hiddens{$idx}) {              if ($hiddens{$idx}) {
                                         unless ($studenthidden) {                                          unless ($studenthidden) {
                     $sender.=' <a href="/adm/feedback?unhide='.                              $sender.=' '.
                     $escsymb.':::'.$idx;                                              &discussion_link($ressymb,&mt('Make Visible'),'unhide',$idx,$$newpostsflag,$prevread,&group_args($group));
                                             if ($$newpostsflag) {  
                                                 $sender .= '&amp;previous='.$prevread;  
                                             }  
                                             $sender .= '">'.&mt('Make Visible').'</a>';  
                                         }                                          }
             } else {              } else {
         $sender.=' <a href="/adm/feedback?hide='.                                          $sender.=' '.
             $escsymb.':::'.$idx;                                           &discussion_link($ressymb,&mt('Hide'),'hide',$idx,$$newpostsflag,$prevread,&group_args($group));
                                         if ($$newpostsflag) {  
                                             $sender .= '&amp;previous='.$prevread;  
                                         }  
         $sender .= &group_args($group);  
                                         $sender .= '">'.&mt('Hide').'</a>';  
             }              }
                                     my $grpargs = &group_args($group);                                      my $grpargs = &group_args($group);
             $sender.=               $sender.= 
Line 1140  sub build_posting_display { Line 1360  sub build_posting_display {
                                     $sender .= &mt('Delete').'</a>';                                      $sender .= &mt('Delete').'</a>';
                                 }                                  }
                             }                              }
         } else {                          } else {
     if ($screenname) {      if ($screenname) {
         $sender='<i>'.$screenname.'</i>';          $sender='<i>'.$screenname.'</i>';
     } else {      } else {
Line 1167  sub build_posting_display { Line 1387  sub build_posting_display {
                             }                              }
         }          }
                         if ($outputtarget ne 'tex') {                          if ($outputtarget ne 'tex') {
                             if (&discussion_open($status)) {              if (&discussion_open($status)) {
                                 if (($group ne '') &&                                   if (($group ne '') && 
                                     (&check_group_priv($group,'pgd') eq 'ok')) {                                      (&check_group_priv($group,'pgd') eq 'ok')) {
                                      $sender.=' <a href="/adm/feedback?replydisc='.                                       $sender.=' '.
                                               $escsymb.':::'.$idx;                                           &discussion_link($ressymb,&mt('Reply'),'replydisc',$idx,$$newpostsflag,$prevread,&group_args($group));
                                     if ($$newpostsflag) {  
                                         $sender .= '&amp;previous='.$prevread;  
                                     }  
                                     $sender .= &group_args($group);  
                                     $sender .= '" '.$target.'>'.&mt('Reply').'</a>';  
                                 } elsif (&Apache::lonnet::allowed('pch',                                   } elsif (&Apache::lonnet::allowed('pch', 
      $env{'request.course.id'}.       $env{'request.course.id'}.
      ($env{'request.course.sec'}?'/'.       ($env{'request.course.sec'}?'/'.
                                       $env{'request.course.sec'}:''))) {                                        $env{'request.course.sec'}:''))) {
              $sender.=' <a href="/adm/feedback?replydisc='.               $sender.=' '.
                       $escsymb.':::'.$idx;                                           &discussion_link($ressymb,&mt('Reply'),'replydisc',$idx,$$newpostsflag,$prevread);
                                     if ($$newpostsflag) {  
                                         $sender .= '&amp;previous='.$prevread;  
                                     }  
                                     $sender .= '" '.$target.'>'.&mt('Reply').'</a>';  
                                 }                                  }
                             }                              }
                             if ($viewgrades) {              if ($viewgrades) {
         $vgrlink=&Apache::loncommon::submlink(&mt('Submissions'),          $vgrlink=&Apache::loncommon::submlink(&mt('Submissions'),
                                 $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb);                                  $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb);
             }              }
                             if ($$dischash{$readkey}=~/\.$idx\./) {                              if ($$dischash{$readkey}=~/\.$idx\./) { 
                                 $ctlink = '<label><b>'.&mt('Mark unread').'?</b>&nbsp;<input type="checkbox" name="postunread_'.$idx.'" /></label>';                                  $ctlink = '<label><b>'.&mt('Mark unread').'?</b>&nbsp;<input type="checkbox" name="postunread_'.$idx.'" /></label>';
                             } else {                              } else {
                                 $ctlink = '<label><b>'.&mt('Mark read').'?</b>&nbsp;<input type="checkbox" name="postread_'.$idx.'" /></label>';                                  $ctlink = '<label><b>'.&mt('Mark read').'?</b>&nbsp;<input type="checkbox" name="postread_'.$idx.'" /></label>';
Line 1204  sub build_posting_display { Line 1415  sub build_posting_display {
                 }                  }
                 if ($outputtarget eq 'export' || $message) {                  if ($outputtarget eq 'export' || $message) {
     my $thisindex=$idx;      my $thisindex=$idx;
     if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {      if ( ((!$env{'environment.unthreadeddiscussion'}) && ($sortposts eq '')) || 
                            ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
  $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2);   $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2);
     }      }
     $$alldiscussion{$thisindex}=$idx;      $$alldiscussion{$thisindex}=$idx;
Line 1236  sub build_posting_display { Line 1448  sub build_posting_display {
                 } else {                  } else {
                     if ($message) {                      if ($message) {
                         my $spansize = 2;                          my $spansize = 2;
                           my ($uname,$udom);
                         if ($showonlyunread && $prevread > $posttime) {                          if ($showonlyunread && $prevread > $posttime) {
                             $$notshown{$idx} = 1;                              $$notshown{$idx} = 1;
                         } elsif ($showunmark && $$dischash{$readkey}=~/\.$idx\./) {                          } elsif ($showunmark && $$dischash{$readkey}=~/\.$idx\./) {
                             $$notshown{$idx} = 1;                              $$notshown{$idx} = 1;
                         } else {                          } else {
 # apply filters  # apply filters
                             my $uname = $contrib{$idx.':sendername'};                              $uname = $contrib{$idx.':sendername'};
                             my $udom = $contrib{$idx.':senderdomain'};                              $udom = $contrib{$idx.':senderdomain'};
                             my $poster = $uname.':'.$udom;                              my $poster = $uname.':'.$udom;
                             if ($env{'form.totposters'} ne '') {                              if ($env{'form.totposters'} ne '') {
                                 if ($totposters == 0) {                                  if ($totposters == 0) {
Line 1294  sub build_posting_display { Line 1507  sub build_posting_display {
                         unless ($$notshown{$idx} == 1) {                          unless ($$notshown{$idx} == 1) {
                             if ($prevread > 0 && $prevread <= $posttime) {                              if ($prevread > 0 && $prevread <= $posttime) {
                                 $$newitem{$idx} = 1;                                  $$newitem{$idx} = 1;
                                 $$discussionitems[$idx] .= '                                  $$discussionitems[$idx] .= '<font color="#FF0000"><b>'.&mt('NEW').'&nbsp;&nbsp;</b></font>';
                                   <table border="0" width="100%">  
                                   <tr><td align="left"><font color="#FF0000"><b>'.&mt('NEW').'&nbsp;</b></font></td>';  
                             } else {                              } else {
                                 $$newitem{$idx} = 0;                                  $$newitem{$idx} = 0;
                                 $$discussionitems[$idx] .= '  
                                   <table border="0" width="100%">  
                                   <tr><td align="left">&nbsp;</td>';  
                             }                              }
                             $$discussionitems[$idx] .= '<td align="left">&nbsp;&nbsp;'.                              $$discussionitems[$idx] .= '<b>'.$subject.'</b>&nbsp;&nbsp;'.
                                 '<b>'.$subject.'</b>&nbsp;&nbsp;'.  
                                 $sender.' '.$vgrlink.' ('.                                  $sender.' '.$vgrlink.' ('.
                                 &Apache::lonlocal::locallocaltime($posttime).')</td>';                                  &Apache::lonlocal::locallocaltime($posttime).')';
                             if ($$dischash{$toggkey}) {                              if ($$dischash{$toggkey}) {
                                 $$discussionitems[$idx].='<td align="right">&nbsp;&nbsp;'.                                  $$discussionitems[$idx].='&nbsp;&nbsp;'.$ctlink;
                                   $ctlink.'</td>';                              }
                               my $thislikes=$likes{$symb.':'.$idx.':likes'};
                               my $likestyle;
                               if ($seeid || $canvote) {
   # Figure out size based on likes
                                   my $class = 'zero';
                                   my $thislikes=$likes{$symb.':'.$idx.':likes'};
                                   if ($thislikes>$twoplus) {
                                       $class = 'twoplus';
                                   } elsif ($thislikes>$oneplus) {
                                       $class = 'oneplus';
                                   }
                                   if ($thislikes<$twominus) {
                                       $class = 'twominus';
                                   } elsif ($thislikes<$oneminus) {
                                       $class = 'oneminus';
                                   }
                                   $likestyle = $votestyle{$class};
                               }
   # Actually glue in the message itself
                               $$discussionitems[$idx].= '<br /><blockquote>'.
                                       "<div $likestyle>".
                                       $message.
                                       '</div></blockquote>';
                               if ($canvote) {
                                   my $ownpost;
                                   if (($uname eq $env{'user.name'}) &&
                                       ($udom eq $env{'user.domain'})) {
                                       $ownpost = 1;
                                   }   
   # Put in the like and unlike buttons
                                   if ($ownpost || (($hiddens{$idx}) && ($seehidden))) { 
                                       my $novote;
                                       if ($ownpost) { 
                                           $novote = &mt('No voting for your own posts.');
                                       } else {
                                           $novote = &mt('No voting for hidden posts.');
                                       }
                                       &html_escape(\$novote);
                                       $$discussionitems[$idx].=
                                           '<a href="javascript:alert('."'$novote'".');" style="text-decoration: none;">'.
                                           '<img border="0" src="/res/adm/pages/thumbsup_novote.png" alt="'.$novote.'" />&nbsp;'.
                                           '<img border="0" src="/res/adm/pages/thumbsdown_novote.png" alt="'.$novote.'" /></a>'; 
   
                                   } else {
                                       if ($userlikes{$idx}) {
                                           $$discussionitems[$idx].='<img border="0" src="/res/adm/pages/thumbsup_gray.png" alt="'.&mt('You like this posting').'" />';
                                       } else {
                                           $$discussionitems[$idx].='&nbsp;'.&discussion_link($ressymb,'<img border="0" src="/res/adm/pages/thumbsup.png" alt="'.&mt('Like').'" />','like',$idx,$$newpostsflag,$prevread,&group_args($group),&mt("Like this posting"));
                                       }
                                       if ($userunlikes{$idx}) {
                                           $$discussionitems[$idx].='<img border="0" src="/res/adm/pages/thumbsdown_gray.png" alt="'.&mt('You unlike this posting').'" />';
                                       } else {
                                           $$discussionitems[$idx].='&nbsp;'.&discussion_link($ressymb,'<img border="0" src="/res/adm/pages/thumbsdown.png" alt="'.&mt('Unlike').'" />','unlike',$idx,$$newpostsflag,$prevread,&group_args($group),&mt("Unlike this posting"));
                                       }
                                   }
                               }
                               if ($seeid || $canvote) {
                                   my $thislikes=$likes{$symb.':'.$idx.':likes'};
                                   if ($thislikes>0) {
                                       $$discussionitems[$idx].='&nbsp;('.&mt("[_1] likes",$thislikes).')';
                                   } elsif ($thislikes<0) {
                                       $$discussionitems[$idx].='&nbsp;('.&mt("[_1] unlikes",abs($thislikes)).')';
                                   }
                             }                              }
                             $$discussionitems[$idx].= '</tr></table><blockquote>'.  # If there is any history to this post, inform the reader
                                     $message.'</blockquote>';  
                             if ($contrib{$idx.':history'}) {                              if ($contrib{$idx.':history'}) {
                                 my @postversions = ();                                  my @postversions = ();
                                 $$discussionitems[$idx] .= &mt('This post has been edited by the author.');                                  $$discussionitems[$idx] .= '&nbsp;&nbsp;'.&mt('This post has been edited by the author.');
                                 if ($seeid) {                                  if ($seehidden) {
                                     $$discussionitems[$idx] .= '&nbsp;&nbsp;<a href="/adm/feedback?allversions='.$escsymb.':::'.$idx;                                      $$discussionitems[$idx] .= '&nbsp;&nbsp;'.
     $$discussionitems[$idx] .= &group_args($group);                                           &discussion_link($ressymb,&mt('Display all versions'),'allversions',$idx,$$newpostsflag,$prevread,&group_args($group));
                                     $$discussionitems[$idx] .= '">'.&mt('Display all versions').'</a>';  
                                 }                                  }
                                 $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');                                  $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
                                 if ($contrib{$idx.':history'} =~ m/:/) {                                  if ($contrib{$idx.':history'} =~ m/:/) {
Line 1332  sub build_posting_display { Line 1600  sub build_posting_display {
                                     $$discussionitems[$idx] .= '<b>'.$version.'.</b> - '.&Apache::lonlocal::locallocaltime($postversions[$i]).'  ';                                      $$discussionitems[$idx] .= '<b>'.$version.'.</b> - '.&Apache::lonlocal::locallocaltime($postversions[$i]).'  ';
                                 }                                  }
                             }                              }
   # end of unless ($$notshown ...)
                         }                          }
   # end of if ($message) ...
                     }                      }
   # end of the else-branch of target being export
                 }                  }
   # end of unless hidden or deleted
             }              }
   # end of the loop over all discussion entries
  }   }
   # end of "if there actually are any discussions
     }      }
   # end of subroutine "build_posting_display" 
 }  }
   
 sub filter_regexp {  sub filter_regexp {
Line 1396  sub filter_regexp { Line 1671  sub filter_regexp {
   
   
 sub get_post_contents {  sub get_post_contents {
     my ($contrib,$idx,$seeid,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$numver) = @_;      my ($contrib,$idx,$seeid,$seehidden,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$showaboutme,$numver) = @_;
     my $discussion = '';      my $discussion = '';
     my $start=$numver;      my $start=$numver;
     my $end=$numver + 1;      my $end=$numver + 1;
     %{$$imsfiles{$idx}}=();      %{$$imsfiles{$idx}}=();
     if ($type eq 'allversions') {      if ($type eq 'allversions') {
        unless($seeid) {         unless($seehidden) {
            $discussion=&mt('You do not have privileges to view all versions of posts.').' '.&mt('Please select a different role.');             $discussion=&mt('You do not have privileges to view all versions of posts.').' '.&mt('Please select a different role.');
            return $discussion;             return $discussion;
        }          } 
Line 1414  sub get_post_contents { Line 1689  sub get_post_contents {
                                         $$contrib{$idx.':sendername'},                                          $$contrib{$idx.':sendername'},
                                         $$contrib{$idx.':senderdomain'});                                          $$contrib{$idx.':senderdomain'});
     $$screenname=$$contrib{$idx.':screenname'};      $$screenname=$$contrib{$idx.':screenname'};
       $$showaboutme = &Apache::lonnet::usertools_access($$contrib{$idx.':sendername'},
     my $sender=&Apache::loncommon::aboutmewrapper(                                                        $$contrib{$idx.':senderdomain'},
                                                         'aboutme');
       my $sender = $$plainname;
       if ($$showaboutme) {
           $sender = &Apache::loncommon::aboutmewrapper(
                                  $$plainname,                                   $$plainname,
                                  $$contrib{$idx.':sendername'},                                   $$contrib{$idx.':sendername'},
                                  $$contrib{$idx.':senderdomain'}).' ('.                                   $$contrib{$idx.':senderdomain'});
                                  $$contrib{$idx.':sendername'}.':'.      }
                                  $$contrib{$idx.':senderdomain'}.')';      if ($seeid) {
           $sender .= ' ('.$$contrib{$idx.':sendername'}.':'.
                      $$contrib{$idx.':senderdomain'}.')';
       }
     my $attachmenturls = $$contrib{$idx.':attachmenturl'};      my $attachmenturls = $$contrib{$idx.':attachmenturl'};
     my @postversions = ();      my @postversions = ();
     if ($type eq 'allversions' || $type eq 'export') {      if ($type eq 'allversions' || $type eq 'export') {
Line 1536  sub mail_screen { Line 1818  sub mail_screen {
   }    }
   
   my %lt = &Apache::lonlocal::texthash(    my %lt = &Apache::lonlocal::texthash(
             'myqu' => 'My question/comment/feedback:',              'myqu' => 'Question/comment/feedback:',
             'title' => 'Title',  
             'reta' => 'Retained attachments',              'reta' => 'Retained attachments',
             'atta' => 'Attachment',              'atta' => 'Attachment',
            );             );
     if ($env{'form.editdisc'} || $env{'form.replydisc'}){
         $lt{'myqu'} = &mt('Post Discussion');
     }
   my $restitle = &get_resource_title($caller_symb,$feedurl);    my $restitle = &get_resource_title($caller_symb,$feedurl);
   my $quote='';    my $quote='';
   my $subject = '';    my $subject = '';
Line 1605  END Line 1889  END
    $env{'course.'.$env{'request.course.id'}.'.domain'},     $env{'course.'.$env{'request.course.id'}.'.domain'},
    $env{'course.'.$env{'request.course.id'}.'.num'});     $env{'course.'.$env{'request.course.id'}.'.num'});
       unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {        unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
             my $numoldver = 0;
           if ($contrib{$idx.':history'}) {            if ($contrib{$idx.':history'}) {
               if ($contrib{$idx.':history'} =~ /:/) {                if ($contrib{$idx.':history'} =~ /:/) {
                   my @oldversions = split(/:/,$contrib{$idx.':history'});                    my @oldversions = split(/:/,$contrib{$idx.':history'});
Line 1613  END Line 1898  END
                   $numoldver = 1;                    $numoldver = 1;
               }                }
           }            }
           if ($env{'form.replydisc'}) {            if ($idx > 0) {
               if ($contrib{$idx.':history'}) {                my (%msgversions,%subversions,$htmldecode);
                   if ($contrib{$idx.':history'} =~ /:/) {                $htmldecode = 0;
                       my @oldversions = split(/:/,$contrib{$idx.':history'});                if ($env{'form.replydisc'}) {
                       $numoldver = @oldversions;                    $htmldecode = 1;
                   } else {  
                       $numoldver = 1;  
                   }  
               }                }
               if ($idx > 0) {                &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
                   my %msgversions = ();                &get_post_versions(\%subversions,$contrib{$idx.':subject'},$htmldecode,
                   &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);                                   $numoldver);
                 $subject = $subversions{$numoldver};
                 if ($env{'form.replydisc'}) {
                   $quote = $msgversions{$numoldver};                    $quote = $msgversions{$numoldver};
               }                    $subject = &HTML::Entities::encode(&mt('Re: ').$subject,'<>&"');
               if ($idx > 0) {                } else {
                   my %subversions = ();  
                   &get_post_versions(\%subversions,$contrib{$idx.':subject'},1,$numoldver);  
                   $subject = &mt('Re: ').$subversions{$numoldver};  
               }  
               $subject = &HTML::Entities::encode($subject,'<>&"');  
           } else {  
               $attachmenturls = $contrib{$idx.':attachmenturl'};  
               if ($idx > 0) {  
                   my %msgversions = ();  
                   &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);  
                   $comment = $msgversions{$numoldver};                    $comment = $msgversions{$numoldver};
                   my %subversions = ();  
                   &get_post_versions(\%subversions,$contrib{$idx.':subject'},0,$numoldver);  
                   $subject = $subversions{$numoldver};   
               }                }
             }
             if ($env{'form.editdisc'}) {
                 $attachmenturls = $contrib{$idx.':attachmenturl'};
               if (defined($contrib{$idx.':replyto'})) {                if (defined($contrib{$idx.':replyto'})) {
                   $parentmsg = $contrib{$idx.':replyto'};                    $parentmsg = $contrib{$idx.':replyto'};
               }                }
Line 1675  END Line 1949  END
       $comment = &unescape($env{'form.comment'});        $comment = &unescape($env{'form.comment'});
       &process_attachments(\@currnewattach,\@currdelold,\@keepold);        &process_attachments(\@currnewattach,\@currdelold,\@keepold);
   }    }
   my $latexHelp=&Apache::loncommon::helpLatexCheatsheet(undef,undef,1);    my $latexHelp=&Apache::loncommon::helpLatexCheatsheet(undef,undef,1,($env{'form.modal'}?'popup':0));
   my $send=&mt('Send');    my $send=&mt('Send');
   my $alert = &mt('Please select a feedback type.');    my $alert = &mt('Please select a feedback type.');
     &js_escape(\$alert);
   my $js= <<END;    my $js= <<END;
 <script type="text/javascript">  <script type="text/javascript">
 //<!--  //<!--
Line 1715  END Line 1990  END
     $anonscript      $anonscript
 //-->  //-->
 </script>  </script>
   <script type="text/javascript" src="/res/adm/includes/file_upload.js"></script>
 END  END
   
   my ($textareaheader,$textareaclass);    my ($textareaheader,$textareaclass);
Line 1733  END Line 2009  END
                  'text' => 'Resource Feedback and Discussion'}];                   'text' => 'Resource Feedback and Discussion'}];
   
   my %onload = ('onload' => 'window.focus();setposttype();');    my %onload = ('onload' => 'window.focus();setposttype();');
     my %parms=('add_entries' => \%onload);
     if ($env{'form.modal'} ne 'yes') { $parms{'bread_crumbs'} = $brcrum; }
   my $start_page=    my $start_page=
       &Apache::loncommon::start_page('Resource Feedback and Discussion',$js,        &Apache::loncommon::start_page('Resource Feedback and Discussion',$js,\%parms);
                                      {'add_entries' => \%onload,  
                                       'bread_crumbs' => $brcrum,});  
   
   if ($quote ne '') {    if ($quote ne '') {
       $quote = &HTML::Entities::decode($quote);        $quote = &HTML::Entities::decode($quote);
       unless (&contains_block_html($quote)) {        unless (&contains_block_html($quote)) {
           &newline_to_br(\$quote);            &newline_to_br(\$quote);
       }        }
       $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($quote).'</blockquote>';          $quote=&Apache::lonhtmlcommon::start_pick_box().
                  &Apache::lonhtmlcommon::row_title(&mt('Quote')).
                  &Apache::lontexconvert::msgtexconverted($quote).
                  &Apache::lonhtmlcommon::row_closure(1).
                  &Apache::lonhtmlcommon::end_pick_box();
     }
     my $header='';
     unless ($env{'form.modal'}) {
        $header="<h2><tt>$restitle</tt></h2>";
   }    }
   
   $r->print(<<END);    $r->print(<<END);
 $start_page  $start_page
 <h2><tt>$restitle</tt></h2>  <h1>$lt{'myqu'}</h1>
   $header
 <form action="/adm/feedback" method="post" name="mailform"  <form action="/adm/feedback" method="post" name="mailform"
 enctype="multipart/form-data">  enctype="multipart/form-data">
 $prevtag  $prevtag
 <input type="hidden" name="postdata" value="$feedurl" />  <input type="hidden" name="postdata" value="$feedurl" />
   <input type="hidden" name="modal" value="$env{'form.modal'}" />
 END  END
   if ($env{'form.replydisc'}) {    if ($env{'form.replydisc'}) {
       $r->print(<<END);        $r->print(<<END);
Line 1765  END Line 2050  END
 END  END
   }    }
   $r->print(<<END);    $r->print(<<END);
 $options<hr />  $options
   <br />
   END
   $r->print(&Apache::lonhtmlcommon::start_pick_box());
   $r->print(<<END);
 $quote  $quote
 <p>$lt{'myqu'}  <p>
 $textareaheader  $textareaheader
 </p>  </p>
 <p>  <p>
 $latexHelp  $latexHelp
 </p>  </p>
 <p>  <p>
 $lt{'title'}: <input type="text" name="subject" size="30" value="$subject" /></p>  
 <p>  
 <textarea name="comment" id="comment" cols="60" rows="10"  $textareaclass>$comment  
 </textarea></p>  
 END  END
   
       
       $r->print(&Apache::lonhtmlcommon::row_title(&mt('Subject')));
       $r->print('<input type="text" name="subject" size="30" value="'.
                 $subject.'" /></p>');
       $r->print(&Apache::lonhtmlcommon::row_closure());
       $r->print(&Apache::lonhtmlcommon::row_title(&mt('Message')));
       $r->print('<textarea name="comment" id="comment" cols="55" rows="10" '.
                 $textareaclass.'>'.$comment.
                 '</textarea>');
       $r->print(&Apache::lonhtmlcommon::row_closure(1));
       $r->print(&Apache::lonhtmlcommon::end_pick_box());
   
     if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {      if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {
         if ($env{'form.origpage'}) {          if ($env{'form.origpage'}) {
             foreach my $attach (@currnewattach) {              foreach my $attach (@currnewattach) {
Line 1800  END Line 2098  END
     } else {      } else {
         $r->print(<<END);          $r->print(<<END);
 <p>  <p>
 $lt{'atta'} $attachmaxtext: <input type="file" name="attachment" />  $lt{'atta'} $attachmaxtext: <input type="file" name="attachment" class="LC_flUpload" />
   <input type="hidden" id="LC_free_space" value="131072" />
 </p>  </p>
 END  END
     }      }
Line 1811  END Line 2110  END
         $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');          $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
     }      }
     $r->print(<<END);      $r->print(<<END);
 <p>  
 <input type="hidden" name="sendit" value="1" />  <input type="hidden" name="sendit" value="1" />
 <input type="button" value="$send" onclick='gosubmit();' />  <input type="button" value="$send" onclick='gosubmit();' />
 </p>  
 </form>  </form>
 END  END
     if ($env{'form.editdisc'} || $env{'form.replydisc'}) {      if ($env{'form.editdisc'} || $env{'form.replydisc'}) {
Line 1829  END Line 2126  END
             $attachnum += @currnewattach;              $attachnum += @currnewattach;
         }          }
         my $blockblog = &Apache::loncommon::blocking_status('blogs');          my $blockblog = &Apache::loncommon::blocking_status('blogs');
         $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver,'',$blockblog));  
         if ($attachnum > 0) {          if ($attachnum > 0) {
             if (@currnewattach > 0) {              if (@currnewattach > 0) {
                 $newattachmsg .= '<br /><b>'.&mt('New attachments').'</b><br />';                  $newattachmsg .= '<br /><b>'.&mt('New attachments').'</b><br />';
Line 1849  END Line 2145  END
                 $r->print("<br /><b>$lt{'reta'}</b>:$attachmsg<br />\n");                  $r->print("<br /><b>$lt{'reta'}</b>:$attachmsg<br />\n");
             }              }
             if ($newattachmsg) {              if ($newattachmsg) {
                 $r->print("$newattachmsg<br />");                  $r->print("$newattachmsg");
             }              }
         }          }
           $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver,'',$blockblog));
     }      }
     $r->print(&generate_preview_button().      $r->print(&generate_preview_button().
       &Apache::loncommon::end_page());        &Apache::loncommon::end_page());
Line 1891  sub print_display_options { Line 2188  sub print_display_options {
         'yhni' => 'You have not indicated that you wish to change any of the discussion settings',          'yhni' => 'You have not indicated that you wish to change any of the discussion settings',
         'ywbr' => 'You will be returned to the previous page if you click OK.'          'ywbr' => 'You will be returned to the previous page if you click OK.'
     );      );
       my %js_lt = &Apache::lonlocal::texthash(
           'yhni' => 'You have not indicated that you wish to change any of the discussion settings',
           'ywbr' => 'You will be returned to the previous page if you click OK.'
       );
       &js_escape(\%js_lt);
   
     my $dispchangeA = $lt{'unread'};      my $dispchangeA = $lt{'unread'};
     my $dispchangeB = $lt{'unmark'};      my $dispchangeB = $lt{'unmark'};
Line 1984  function setDisp() { Line 2286  function setDisp() {
     if (chktotal > 0) {       if (chktotal > 0) { 
         document.modifydisp.submit()          document.modifydisp.submit()
     } else {      } else {
         if(confirm("$lt{'yhni'}. \\n$lt{'ywbr'}"))      {          if(confirm("$js_lt{'yhni'}. \\n$js_lt{'ywbr'}"))      {
             if (prev > 0) {              if (prev > 0) {
                 location.href = "$feedurl?previous=$previous"                  location.href = "$feedurl?previous=$previous"
             } else {              } else {
Line 2200  END Line 2502  END
 $start_page  $start_page
 <form name="modifyshown" method="post" action="/adm/feedback">  <form name="modifyshown" method="post" action="/adm/feedback">
 <b>$lt{'diso'}</b><br/> $lt{'prca'}  <b>$lt{'diso'}</b><br/> $lt{'prca'}
 <br /><br />  <br />
 <table border="0">  <table border="0">
  <tr>   <tr>
   <th>$lt{'soor'}</th>    <th>$lt{'soor'}</th>
Line 2265  $start_page Line 2567  $start_page
  </tr>   </tr>
 </table>  </table>
 <br />  <br />
 <br />  <input type="hidden" name="inhibitmenu" value="$env{'form.inhibitmenu'}" />
   <input type="hidden" name="modal" value="$env{'form.modal'}" />
 <input type="hidden" name="previous" value="$previous" />  <input type="hidden" name="previous" value="$previous" />
 <input type="hidden" name="applysort" value="$symb" />  <input type="hidden" name="applysort" value="$symb" />
 <input type="button" name="sub" value="$lt{'stor'}" onclick="verifyFilter()" />  <input type="button" name="sub" value="$lt{'stor'}" onclick="verifyFilter()" />
Line 2291  sub print_showposters { Line 2594  sub print_showposters {
     $r->send_http_header;      $r->send_http_header;
   
     &Apache::lonenc::check_encrypt(\$symb);      &Apache::lonenc::check_encrypt(\$symb);
     my $crs='/'.$env{'request.course.id'};  
     if ($env{'request.course.sec'}) {  
         $crs.='_'.$env{'request.course.sec'};  
     }  
     $crs=~s/\_/\//g;  
     my $seeid;  
     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};      my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};      my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     my $group = $env{'form.group'};      my $group = $env{'form.group'};
     my $ressymb = &wrap_symb($symb);      my $ressymb = &wrap_symb($symb);
     if (($group ne '') &&      my $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
         ($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {  
         if (&check_group_priv($group,'dgp') eq 'ok') {  
             $seeid = 1;  
         }  
     } else {  
         $seeid=&Apache::lonnet::allowed('rin',$crs);  
     }  
     my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},      my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                                          $cdom,$cnum);                                           $cdom,$cnum);
     my %namesort = ();      my %namesort = ();
Line 2324  sub print_showposters { Line 2614  sub print_showposters {
         for (my $idx=1;$idx<=$contrib{'version'};$idx++) {          for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
             my $hidden=($contrib{'hidden'}=~/\.$idx\./);              my $hidden=($contrib{'hidden'}=~/\.$idx\./);
             my $deleted=($contrib{'deleted'}=~/\.$idx\./);              my $deleted=($contrib{'deleted'}=~/\.$idx\./);
             unless ((($hidden) && (!$seeid)) || ($deleted)) {              unless ((($hidden) && (!$seehidden)) || ($deleted)) {
                 if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {                  if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
                     my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});                      my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
                     my $lastname = $names{'lastname'};                      my $lastname = $names{'lastname'};
Line 2349  sub print_showposters { Line 2639  sub print_showposters {
                     }                      }
                 }                  }
             }              }
         }          }       
     }      }
   
     my $start_page = &Apache::loncommon::start_page('Discussion options');      my $start_page = &Apache::loncommon::start_page('Discussion options');
     my $table_start =&Apache::loncommon::start_data_table();      my $table_start =&Apache::loncommon::start_data_table();
     $r->print(<<END);      $r->print(<<END);
 $start_page  $start_page
  <form name="pickpostersform" method="post">   <form name="pickpostersform" method="post" action="">
  <br />   <br />
     $table_start      $table_start
       <tr>        <tr>
Line 2390  END Line 2680  END
     $r->print(<<END);      $r->print(<<END);
 <br />  <br />
 <input type="hidden" name="sortposts" value="$sortposts" />  <input type="hidden" name="sortposts" value="$sortposts" />
   <input type="hidden" name="modal" value="$env{'form.modal'}" />
 <input type="hidden" name="userpick" value="$symb" />  <input type="hidden" name="userpick" value="$symb" />
 <input type="button" name="store" value="Display posts" onclick="javascript:document.pickpostersform.submit()" />  <input type="button" name="store" value="Display posts" onclick="javascript:document.pickpostersform.submit()" />
 </form>  </form>
Line 2455  sub get_post_attachments { Line 2746  sub get_post_attachments {
         $$attachments{'0'}{'filename'} = $attachmenturls;          $$attachments{'0'}{'filename'} = $attachmenturls;
         $$attachments{'0'}{'0'} = 'n';          $$attachments{'0'}{'0'} = 'n';
     }      }
   
     return;      return;
 }  }
   
 sub fail_redirect {  sub fail_redirect {
   my ($r,$feedurl) = @_;    my ($r,$feedurl,$delay) = @_;
   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };    if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
   my %lt = &Apache::lonlocal::texthash(    my %lt = &Apache::lonlocal::texthash(
                  'sorr' => 'Sorry, no recipients ...',                   'sorr' => 'Sorry, no recipients ...',
   );    );
   my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');    my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
   $r->print(&Apache::loncommon::start_page('Feedback not sent',undef,    my %parms=('only_body'   => 1);
    {'redirect'  => [2,$feedurl],    if ($delay !~ /^\d+(|\.\d+)$/) {
     'only_body' => 1,}));        $delay = 2;
     }
     if ($env{'form.modal'}) {
         my $onload = 'document.forms.reldt.submit()';
         if ($delay) {
             my $js_delay = int(1000 * $delay);
             $onload = "setTimeout(function(){
                        document.forms.reldt.submit();
                        },$js_delay);";
         }
         $parms{'add_entries'}={'onload' => $onload};
     } else {
         $parms{'redirect'}=[$delay,$feedurl];
     }
     $r->print(&Apache::loncommon::start_page('Feedback not sent',undef,\%parms));
     my $windowname = 'loncapaclient';
   $r->print(<<ENDFAILREDIR);    $r->print(<<ENDFAILREDIR);
 <img align="right" src="$logo" />  <img align="right" src="$logo" />
 <b>$lt{'sorr'}</b>  <p class="LC_warning">$lt{'sorr'}</p>
   <form name="reldt" action="$feedurl" target="$windowname">
   </form>
 ENDFAILREDIR  ENDFAILREDIR
   $r->print(&Apache::loncommon::end_page());    $r->print(&Apache::loncommon::end_page());
 }  }
   
 sub redirect_back {  sub redirect_back {
   my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group,$toolarge) = @_;    my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,
         $rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group,$toolarge,$delay) = @_;
   my $sorttag = '';    my $sorttag = '';
   my $roletag = '';    my $roletag = '';
   my $statustag = '';    my $statustag = '';
Line 2575  sub redirect_back { Line 2883  sub redirect_back {
   }     } 
   &Apache::lonenc::check_encrypt(\$feedurl);    &Apache::lonenc::check_encrypt(\$feedurl);
   my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');    my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
   my %onload;    my %parms=('only_body'   => 1);
   if ($env{'environment.remote'} ne 'off') {    if ($delay !~ /^\d+(|\.\d+)$/) {
       $onload{'onload'} =        $delay = 0;
   "if (window.name!='loncapaclient') { this.document.reldt.submit(); self.window.close(); }";    }
     if ($env{'form.modal'}) {
         my $onload = 'document.forms.reldt.submit()';
         if ($delay) {
             my $js_delay = int(1000 * $delay);
             $onload = "setTimeout(function(){
                           document.forms.reldt.submit();
                        },$js_delay);";
         }
         $parms{'add_entries'}={'onload' => $onload};
     } else {
         $parms{'redirect'}=[$delay,$feedurl];
   }    }
   my $start_page=    my $start_page=
       &Apache::loncommon::start_page('Feedback sent',undef,        &Apache::loncommon::start_page('Feedback sent',undef,\%parms);
      {'redirect'    => [0,$feedurl],  
       'only_body'   => 1,  
       'add_entries' => \%onload});  
   my $end_page = &Apache::loncommon::end_page();    my $end_page = &Apache::loncommon::end_page();
   $r->print(<<ENDREDIR);    $r->print(<<ENDREDIR);
 $start_page  $start_page
Line 2609  ENDREDIR Line 2925  ENDREDIR
 }  }
   
 sub no_redirect_back {  sub no_redirect_back {
   my ($r,$feedurl) = @_;    my ($r,$feedurl,$delay) = @_;
   my $nofeed=&mt('Sorry, no feedback possible on this resource ...');    my $nofeed=&mt('Sorry, no feedback possible on this resource ...');
      my $form_for_modal;
   my %onload;    my %parms=('only_body'   => 1,
   if ($env{'environment.remote'} ne 'off') {               'bgcolor'     => '#FFFFFF',);
       $onload{'onload'} =     if ($delay !~ /^\d+(|\.\d+)$/) {
   "if (window.name!='loncapaclient') { self.window.close(); }";        $delay = 0;
   }    }
     if ($env{'form.modal'}) {
   my %body_options = ('only_body'   => 1,        if (($feedurl !~ m{^/adm/feedback}) && ($feedurl ne '')) {
       'bgcolor'     => '#FFFFFF',            my $onload = 'document.forms.reldt.submit()';
       'add_entries' => \%onload,);            if ($delay) {
                 my $js_delay = int(1000 * $delay);
   if ($feedurl !~ m{^/adm/feedback}) {                 $onload = "setTimeout(function(){
       $body_options{'rediect'} = [2,$feedurl];                           document.forms.reldt.submit();
                            },$js_delay);";
             }
             $parms{'add_entries'}={'onload' => $onload};
             my $windowname = 'loncapaclient'; 
             $form_for_modal = <<ENDFORM;
   <form name="reldt" action="$feedurl" target="$windowname">
   </form>
   ENDFORM
         }
     } else {
         if (($feedurl !~ m{^/adm/feedback}) && ($feedurl ne '')) {
             $parms{'redirect'}=[$delay,$feedurl];
         }
   }    }
   my $start_page=    my $start_page=
       &Apache::loncommon::start_page('Feedback not sent',undef,        &Apache::loncommon::start_page('Feedback not sent',undef,
      \%body_options);       \%parms);
         
   my $end_page = &Apache::loncommon::end_page();    my $end_page = &Apache::loncommon::end_page();
   
   &Apache::lonenc::check_encrypt(\$feedurl);  
   my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');    my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
   $r->print (<<ENDNOREDIRTWO);    $r->print (<<ENDNOREDIRTWO);
 $start_page  $start_page
 <img align="right" src="$logo" />  <img align="right" src="$logo" />
 <b>$nofeed</b>  <b>$nofeed</b>
 <br />  <br />
   $form_for_modal
 $end_page  $end_page
 ENDNOREDIRTWO  ENDNOREDIRTWO
 }  }
   
 sub screen_header {  sub screen_header {
     my ($feedurl,$symb,$group) = @_;      my ($feedurl,$symb,$group) = @_;
     my $crscontent = &mt('Question/Comment/Feedback about course content');      my %default = &Apache::lonlocal::texthash (
     my $crspolicy = &mt('Question/Comment/Feedback about course policy');                      question => 'Question about resource content',
                       comment => 'Question/Comment/Feedback about course content',
                       policy => 'Question/Comment/Feedback about course policy',
                     );
     my $contribdisc = &mt('Contribution to course discussion of resource');      my $contribdisc = &mt('Contribution to course discussion of resource');
     my $anoncontrib = &mt('Anonymous contribution to course discussion of resource');      my $anoncontrib = &mt('Anonymous contribution to course discussion of resource');
     my $namevis = &mt('name only visible to course faculty');      my $namevis = &mt('name only visible to course faculty');
Line 2653  sub screen_header { Line 2985  sub screen_header {
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         $crstype = &Apache::loncommon::course_type();          $crstype = &Apache::loncommon::course_type();
         if ($crstype eq 'Community') {          if ($crstype eq 'Community') {
             $crscontent = &mt('Question/Comment/Feedback about community content');              $default{'comment'} = &mt('Question/Comment/Feedback about community content');
             $crspolicy = &mt('Question/Comment/Feedback about community policy');              $default{'policy'} = &mt('Question/Comment/Feedback about community policy');
             $contribdisc = &mt('Contribution to community discussion of resource');              $contribdisc = &mt('Contribution to community discussion of resource');
             $anoncontrib = &mt('Anonymous contribution to community discussion of resource');              $anoncontrib = &mt('Anonymous contribution to community discussion of resource');
             $namevis = &mt('name only visible to community facilitators');              $namevis = &mt('name only visible to community facilitators');
Line 2662  sub screen_header { Line 2994  sub screen_header {
     }      }
     my $msgoptions='';      my $msgoptions='';
     my $discussoptions='';      my $discussoptions='';
       my $checkradio = '';
       my $blockblog;
       my (%fdbkoptions,%discoptions);
     unless (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {      unless (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
  if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/) && ($env{'user.adv'})) {          if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/) && ($env{'user.adv'})) {
     $msgoptions=               $fdbkoptions{'author'} = 1;
  '<p><label><input type="radio" name="discuss" value="author" /> '.          }
  &mt('Feedback to resource author').'</label></p>';          if (&feedback_available(1)) {
  }              $fdbkoptions{'question'} = 1;
         my %optionhash=();          }
         foreach my $type ('question','comment','policy') {          if (&feedback_available(0,1)) {
     $optionhash{$type}=$env{'course.'.$env{'request.course.id'}.'.'.$type.'.email.text'};              $fdbkoptions{'course'} = 1;
  }          }
  if (&feedback_available(1)) {          if (&feedback_available(0,0,1)) {
     $msgoptions.=              $fdbkoptions{'policy'} = 1;
  '<p><label><input type="radio" name="discuss" value="question" /> '.          }
  ($optionhash{'question'}?$optionhash{'question'}:&mt('Question about resource content')).'</label></p>';  
  }  
  if (&feedback_available(0,1)) {  
     $msgoptions.=  
  '<p><label><input type="radio" name="discuss" value="course" /> '.  
  ($optionhash{'comment'}?$optionhash{'comment'}:$crscontent).  
  '</label></p>';  
  }  
  if (&feedback_available(0,0,1)) {  
     $msgoptions.=  
  '<p><label><input type="radio" name="discuss" value="policy" /> '.  
  ($optionhash{'policy'}?$optionhash{'policy'}:$crspolicy).  
  '</label></p>';  
  }  
     }      }
     if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) {      if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) {
         my ($blocked,$blocktext) = &Apache::loncommon::blocking_status('boards');          my ($blocked,$blocktext) = &Apache::loncommon::blocking_status('boards');
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};          my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};          my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
         my $realsymb = $symb;          my $realsymb = &get_realsymb($symb);
         if ($symb=~/^bulletin___/) {          if (!$blocked && &discussion_open(undef,$realsymb) &&
             my $filename=(&Apache::lonnet::decode_symb($symb))[2];              (&Apache::lonnet::allowed('pch',
             $filename=~s|^adm/wrapper/||;                                        $env{'request.course.id'}.
             $realsymb=&Apache::lonnet::symbread($filename);                                        ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')) || 
         }  
         if (!$blocked && &discussion_open(undef,$realsymb) &&   
     (&Apache::lonnet::allowed('pch',  
      $env{'request.course.id'}.  
      ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')) ||  
             (($group ne '') && ($symb =~ m{^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$}) && (&check_group_priv($group,'pgd') eq 'ok')))) {              (($group ne '') && ($symb =~ m{^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$}) && (&check_group_priv($group,'pgd') eq 'ok')))) {
     $discussoptions='<label><input type="radio" name="discuss" value="nonanon" checked="checked" /> '.              $discoptions{'nonanon'} = 1;
  $contribdisc.              $discoptions{'anon'} = 1;
         '</label><br /><label><input type="radio" name="discuss" value="anon" /> '.              $blockblog = &Apache::loncommon::blocking_status('blogs');
  $anoncontrib.          }
  ' <i>('.$namevis.')</i></label> '.      }
  '<a href="/adm/preferences?action=changescreenname">'.&mt('Change Screenname').'</a>';      my $total = scalar(keys(%fdbkoptions)) + scalar(keys(%discoptions));
             my $blockblog = &Apache::loncommon::blocking_status('blogs');      return if (!$total);
             if (!$blockblog) {      if ($total == 1) {
                 $discussoptions.= &add_blog_checkbox($crstype);          $checkradio = ' checked="checked"';
       }
       if (keys(%fdbkoptions)) {
           if ($fdbkoptions{'author'}) {
               $msgoptions =
                   '<label><input type="radio" name="discuss" value="author"'.$checkradio.' /> '.
                   &mt('Feedback to resource author').'</label><br />';
           }
           foreach my $item ('question','comment','policy') {
               my $type = $item;
               if ($item eq 'comment') {
                   $type = 'course';
               }
               my $optionhash=$env{'course.'.$env{'request.course.id'}.'.'.$item.'.email.text'};
               if ($fdbkoptions{$type}) {
                   $msgoptions .=
                       '<label><input type="radio" name="discuss" value="'.$type.'"'.$checkradio.' />'.
                       ($optionhash?$optionhash:$default{$item}).'</label><br />';
             }              }
         }          }
     }      }
       if (keys(%discoptions)) {
           if ($discoptions{'nonanon'}) {
               $discussoptions='<label><input type="radio" name="discuss" value="nonanon" checked="checked" /> '.
                               $contribdisc.
                               '</label>';
           }
           if ($discoptions{'anon'}) {
               $discussoptions .= '<br /><label><input type="radio" name="discuss" value="anon"'.$checkradio.' /> '.
                                  $anoncontrib.
                                  ' <i>('.$namevis.')</i></label> '.
                                  '<a href="/adm/preferences?action=changescreenname">'.&mt('Change Screenname').'</a>';
           }
           if (!$blockblog) {
               $discussoptions.= &add_blog_checkbox($crstype);
           }
       }
     if ($msgoptions) {      if ($msgoptions) {
         $msgoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/feedback.png').'" />'          $msgoptions='<tr><th><img src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/feedback.png').'" />'
                    .' '.&mt('Send Feedback').'</h2><p>'.&Apache::lonhtmlcommon::coursepreflink(&mt('Feedback Settings'),'feedback').'</p>'                     .'<br />'.&mt('Send Feedback').'<br />'.&Apache::lonhtmlcommon::coursepreflink(&mt('Feedback Settings'),'feedback').'</th>'.
                    .$msgoptions;                     '<td>'.$msgoptions.'</td></tr>';
     }      }
     if ($discussoptions) {       if ($discussoptions) { 
  $discussoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" alt="" />'   $discussoptions='<tr><th><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" alt="" />'
                         .' '.&mt('Discussion Contributions').'</h2><p>'.&Apache::lonhtmlcommon::coursepreflink(&mt('Discussion Settings'),'discussion').'</p>'                          .'<br />'.&mt('Discussion Contributions').'<br />'.&Apache::lonhtmlcommon::coursepreflink(&mt('Discussion Settings'),'discussion').'</th>'.
                         .$discussoptions;                          '<td>'.$discussoptions.'</td></tr>';
     }      }
     return $msgoptions.$discussoptions;      return  &Apache::loncommon::start_data_table().$msgoptions.$discussoptions.&Apache::loncommon::end_data_table();
 }  }
   
 sub resource_output {  sub resource_output {
Line 2755  sub clear_out_html { Line 3104  sub clear_out_html {
       # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB>        # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB>
       # <SUP> <TABLE> <TR> <TD> <TH> <TBODY>        # <SUP> <TABLE> <TR> <TD> <TH> <TBODY>
       %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,        %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,
              BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, PRE=>1, DIV=>1, IMG=>1,       BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, PRE=>1, DIV=>1, IMG=>1,
              M=>1, CHEM=>1, ALGEBRA=>1, SUB=>1, SUP=>1, SPAN=>1,       M=>1, CHEM=>1, ALGEBRA=>1, SUB=>1, SUP=>1, SPAN=>1,  
      H1=>1, H2=>1, H3=>1, H4=>1, H5=>1, H6=>1,        H1=>1, H2=>1, H3=>1, H4=>1, H5=>1, H6=>1, 
      TABLE=>1, TR=>1, TD=>1, TH=>1, TBODY=>1);       TABLE=>1, TR=>1, TD=>1, TH=>1, TBODY=>1);
   }    }
Line 2802  sub feedback_available { Line 3151  sub feedback_available {
 }  }
   
 sub send_msg {  sub send_msg {
     my ($title,$feedurl,$email,$citations,$attachmenturl,$symb,%to)=@_;      my ($title,$feedurl,$email,$citations,$attachmenturl,$symb,$clientip,%to)=@_;
     my $status='';      my $status='';
     my $sendsomething=0;      my $sendsomething=0;
       my $delay;
       my $senthide;
       my %setters;
       my ($startblock,$endblock,$triggerblock,$by_ip,$blockdom) =
           &Apache::loncommon::blockcheck(\%setters,'com',$clientip);
       if ($by_ip) {
           $senthide = 1;
       }
     my $restitle = &get_resource_title($symb,$feedurl);      my $restitle = &get_resource_title($symb,$feedurl);
     if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }      if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }
     unless ($title=~/\w/) { $title=&mt('Feedback'); }      unless ($title=~/\w/) { $title=&mt('Feedback'); }
Line 2818  sub send_msg { Line 3175  sub send_msg {
     } else {      } else {
  unless (&Apache::lonmsg::user_normal_msg($user,$domain,   unless (&Apache::lonmsg::user_normal_msg($user,$domain,
  $title.' ['.$restitle.']',$email,$citations,$feedurl,   $title.' ['.$restitle.']',$email,$citations,$feedurl,
  $attachmenturl,undef,undef,$symb,$restitle)=~/ok/) {   $attachmenturl,undef,undef,$symb,$restitle,undef,
                                                            undef,undef,undef,$senthide)=~/ok/) {
     $status.='<br />'.&mt('Error sending message to').' '.$key.'<br />';      $status.='<br />'.&mt('Error sending message to').' '.$key.'<br />';
  } else {   } else {
     $sendsomething++;      $sendsomething++;
Line 2826  sub send_msg { Line 3184  sub send_msg {
     }      }
  }   }
     }      }
       if ($sendsomething && $senthide) {
           if ($by_ip) {
               my $showdom = &Apache::lonnet::domain($blockdom);
               if ($showdom eq '') {
                   $showdom = $blockdom;
               }
               $delay = 4;
               $status.='<br />'.&mt("Message content of feedback you send to instructor(s) from your current IP address: [_1] will be unavailable in your 'Sent' folder.",$clientip).
                        '<ul><li>'.
                        &mt('This does not affect delivery of feedback to your instructor(s).').
                        '</li><li>'.
                        &mt('Note: some types of communication functionality are blocked for certain IP address(es).').
                        '</li><li>'.
                        &mt('This restriction was set by an administrator in the [_1] LON-CAPA domain.',
                            $showdom).
                        '</li></ul><br />';
           }
       }
   
   # Records of number of feedback messages are kept under the "symb" called "_feedback"
     my %record=&Apache::lonnet::restore('_feedback');  # There are two entries within the framework of a course:
     my ($temp)=keys(%record);  # - the URLs for which feedback was provided
     unless ($temp=~/^error\:/) {  # - the total number of contributions
  my %newrecord=();      if ($sendsomething) {
  $newrecord{'resource'}=$feedurl;          my %record=&getfeedbackrecords();
  $newrecord{'subnumber'}=$record{'subnumber'}+1;          my ($temp)=keys(%record);
  unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {          unless ($temp=~/^error\:/) {
     $status.='<br />'.&mt('Not registered').'<br />';      my %newrecord=();
  }      $newrecord{'resource'}=$feedurl;
       $newrecord{'subnumber'}=$record{'subnumber'}+1;
       unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
           $status.='<br />'.&mt('Not registered').'<br />';
       }
           }
     }      }
           return ($status,$sendsomething,$delay);
     return ($status,$sendsomething);  
 }  }
   
   # Routine to get the complete feedback records
   
   sub getfeedbackrecords {
       my ($uname,$udom,$course)=@_;
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my %record=&Apache::lonnet::restore('_feedback',$course,$udom,$uname);
       return %record;
   }
   
   # Routine to get feedback statistics
   
   sub getfeedbackstats {
       my %record=&getfeedbackrecords(@_);
       return ($record{'subnumber'},$record{'points'},$record{'totallikes'});
   }
   
   # Store feedback credit
   
   sub storefeedbackpoints {
       my ($points,$uname,$udom,$course)=@_;
       unless ($points) { $points=0; }
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my %record=('grader_user'   => $env{'user.name'},
                   'grader_domain' => $env{'user.domain'},
                   'points' => $points);
       return &Apache::lonnet::cstore(\%record,'_feedback',$course,$udom,$uname);
   }
   
   # Store feedback "likes"
   
   sub storefeedbacklikes {
       my ($likes,$uname,$udom,$course)=@_;
       unless ($likes) { $likes=0; }
       if ($likes>0) { $likes=1; }
       if ($likes<0) { $likes=-1; }
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my %record=&getfeedbackrecords($uname,$udom,$course);
       my $totallikes=$record{'totallikes'};
       $totallikes+=$likes;
       my %newrecord=('likes_user'   => $env{'user.name'},
                      'likes_domain' => $env{'user.domain'},
                      'likes' => $likes,
                      'totallikes' => $totallikes);
       return &Apache::lonnet::cstore(\%newrecord,'_feedback',$course,$udom,$uname);
   }
   
   
 sub adddiscuss {  sub adddiscuss {
     my ($symb,$email,$anon,$attachmenturl,$subject,$group)=@_;      my ($symb,$email,$anon,$attachmenturl,$subject,$group)=@_;
     my $status='';      my $status='';
     my $realsymb;      my $realsymb = &get_realsymb($symb);
     if ($symb=~/^bulletin___/) {  
  my $filename=(&Apache::lonnet::decode_symb($symb))[2];  
  $filename=~s|^adm/wrapper/||;  
  $realsymb=&Apache::lonnet::symbread($filename);  
     }  
     my ($cnum,$cdom);      my ($cnum,$cdom);
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};          $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};          $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     }      }
     if (&discussion_open(undef,$realsymb) &&      if (&discussion_open(undef,$realsymb) &&
         (&Apache::lonnet::allowed('pch',$env{'request.course.id'}.   (&Apache::lonnet::allowed('pch',$env{'request.course.id'}.
          ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')) ||           ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')) || 
          (($group ne '') && (&check_group_priv($group,'pgd') eq 'ok') &&           (($group ne '') && (&check_group_priv($group,'pgd') eq 'ok') && 
          ($symb =~ m{^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$})))) {           ($symb =~ m{^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$})))) {
   
     my %contrib=('message'      => $email,      my %contrib=('message'      => $email,
Line 2881  sub adddiscuss { Line 3309  sub adddiscuss {
     if (($symb) && ($email)) {      if (($symb) && ($email)) {
         my $now = time;          my $now = time;
         if ($env{'form.editdisc'}) {          if ($env{'form.editdisc'}) {
             $contrib{'ip'}=$ENV{'REMOTE_ADDR'};              $contrib{'ip'}=&Apache::lonnet::get_requestor_ip();
             $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'};              $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'};
             $contrib{'timestamp'} = $now;              $contrib{'timestamp'} = $now;
             $contrib{'history'} = '';              $contrib{'history'} = '';
Line 2940  sub adddiscuss { Line 3368  sub adddiscuss {
                      $env{'course.'.$env{'request.course.id'}.'.domain'},                       $env{'course.'.$env{'request.course.id'}.'.domain'},
      $env{'course.'.$env{'request.course.id'}.'.num'});       $env{'course.'.$env{'request.course.id'}.'.num'});
     }      }
     my %record=&Apache::lonnet::restore('_discussion');      my %record=&getdiscussionrecords();
     my ($temp)=keys(%record);      my ($temp)=keys(%record);
     unless ($temp=~/^error\:/) {      unless ($temp=~/^error\:/) {
        my %newrecord=();         my %newrecord=();
Line 2948  sub adddiscuss { Line 3376  sub adddiscuss {
        $newrecord{'subnumber'}=$record{'subnumber'}+1;         $newrecord{'subnumber'}=$record{'subnumber'}+1;
        $status.='<br />'.&mt('Registering').': '.         $status.='<br />'.&mt('Registering').': '.
                &Apache::lonnet::cstore(\%newrecord,'_discussion');                 &Apache::lonnet::cstore(\%newrecord,'_discussion');
          &updatekarma();
     }      }
     } else {      } else {
  $status.='Failed.';   $status.='Failed.';
Line 2955  sub adddiscuss { Line 3384  sub adddiscuss {
     return $status.'<br />';         return $status.'<br />';   
 }  }
   
   
   # Routine to get the complete discussion records
   
   sub getdiscussionrecords {
       my ($uname,$udom,$course)=@_;
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my %record=&Apache::lonnet::restore('_discussion',$course,$udom,$uname);
       return %record;
   }
   
   # Routine to get discussion statistics
   
   sub getdiscussionstats {
       my %record=&getdiscussionrecords(@_);
       my $totalvotes = $record{'totallikes'} + $record{'totalunlikes'};
       return ($record{'subnumber'},$record{'points'},$record{'totallikes'},$totalvotes);
   }
   
   # Calculate discussion karma
   
   sub calcdiscussionkarma {    
       my ($subs,$pts,$likes,$votes)=&getdiscussionstats(@_);
       my $karma=0;
       if ($votes>0) {
           $karma=int(.1+5.*(1.-exp(-$subs/10.))*$likes/$votes);
           if ($karma<0) { $karma=0; }
           if ($karma>5) { $karma=5; }
       }
       return $karma;
   }
   
   # Update karma
   
   sub updatekarma {
       my ($uname,$udom,$course)=@_;
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my $karma=&calcdiscussionkarma($uname,$udom,$course);
       &Apache::lonnet::cstore({ 'karma' => $karma },'_discussion',$course,$udom,$uname);
       &Apache::lonnet::do_cache_new('karma',$uname.':'.$udom.':'.$course,$karma,3600);
       return $karma;
   }
   
   # Retrieve karma
   
   sub userkarma {
       my ($uname,$udom,$course)=@_;
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my $hashkey=$uname.':'.$udom.':'.$course;
       my ($karma,$cached)=&Apache::lonnet::is_cached_new('karma',$hashkey);
       if ($cached) {
           return $karma;
       }
       my %userdisc=&getdiscussionrecords($uname,$udom,$course);
       $karma=$userdisc{'karma'};
       &Apache::lonnet::do_cache_new('karma',$hashkey,$karma,3600);
       return $karma;
   }
   
   # Store discussion credit
   
   sub storediscussionpoints {
       my ($points,$uname,$udom,$course)=@_;
       unless ($points) { $points=0; }
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my %record=('grader_user'   => $env{'user.name'},
                   'grader_domain' => $env{'user.domain'},
                   'points' => $points);
       return &Apache::lonnet::cstore(\%record,'_discussion',$course,$udom,$uname);
   }
   
   # Store discussion "likes"
   
   sub storediscussionlikes {
       my ($chglikes,$chgunlikes,$uname,$udom,$course,$context)=@_;
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       unless ($course) { $course=$env{'request.course.id'}; }
       my %record=&getdiscussionrecords($uname,$udom,$course);
       my $totallikes=$record{'totallikes'};
       my $totalunlikes=$record{'totalunlikes'};
       $totallikes += $chglikes;
       $totalunlikes += $chgunlikes;
       my %newrecord=('likes_user'   => $env{'user.name'},
                      'likes_domain' => $env{'user.domain'},
                      'totallikes'   => $totallikes,
                      'totalunlikes' => $totalunlikes,
                      'context'      => $context);
       my $status=&Apache::lonnet::cstore(\%newrecord,'_discussion',$course,$udom,$uname);
       if ($status eq 'ok') {
           &updatekarma($uname,$udom,$course);
       }
       return $status;
   }
   
 sub get_discussion_info {  sub get_discussion_info {
     my ($idx,%contrib) = @_;      my ($idx,%contrib) = @_;
     my $changelast = 0;      my $changelast = 0;
Line 3100  sub modify_attachments { Line 3631  sub modify_attachments {
   
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
                'subj' => 'Subject',                 'subj' => 'Subject',
                'thfo' => 'The following attachments were part of the most recent saved version of this posting.',  
                'chth' => 'Check the checkboxes for any you wish to remove.',                 'chth' => 'Check the checkboxes for any you wish to remove.',
                'thef' => 'The following attachments have been uploaded for inclusion with this posting.',                 'thef' => 'The following attachments have been uploaded for inclusion with this posting.',
                'adda' => 'Add a new attachment to this post.',                 'adda' => 'Add a new attachment to this post',
                'stch' => 'Save Changes',                 'stch' => 'Save Changes',
                  'clic' => 'Add/remove attachments',
              );               );
     my $js = <<END;      my $js = <<END;
 <script type="text/javascript">  <script type="text/javascript">
Line 3112  sub modify_attachments { Line 3643  sub modify_attachments {
    document.modattachments.action = document.modattachments.origpage.value;     document.modattachments.action = document.modattachments.origpage.value;
    document.modattachments.submit();     document.modattachments.submit();
  }   }
 </script>   </script>
   <script type="text/javascript" src="/res/adm/includes/file_upload.js"></script>
 END  END
   
     # Breadcrumbs      # Breadcrumbs
     my $brcrum = [{'href' => '',      my $brcrum = [{'href' => '',
                    'text' => 'Discussion Post Attachments'}];                     'text' => 'Discussion Post Attachments'}];
       my %parms=('only_body' => 1);
       if ($env{'form.modal'} ne 'yes') { $parms{'bread_crumbs'} = $brcrum; }
   
     my $start_page =       my $start_page = 
  &Apache::loncommon::start_page('Discussion Post Attachments',$js,   &Apache::loncommon::start_page('Discussion Post Attachments',$js,\%parms);
                                    {'bread_crumbs' => $brcrum,});  
   
     my $orig_subject = &unescape($env{'form.subject'});      my $orig_subject = &unescape($env{'form.subject'});
     my $subject=&clear_out_html($orig_subject);      my $subject=&clear_out_html($orig_subject);
Line 3144  END Line 3678  END
 $start_page  $start_page
 $toolarge  $toolarge
 <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb">  <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb">
  <br />  
  <table class="LC_data_table">   <h1>$lt{'clic'}</h1>
   <tr>  
    <td colspan="2">  
     <b>Subject:</b> <b>$subject</b><br /><br />  
 END  END
     if ($idx) {      $r->print(&Apache::lonhtmlcommon::start_pick_box());
         if ($attachmenturls) {      $r->print(&Apache::lonhtmlcommon::row_title(&mt('Subject')));
             my @currold = keys(%currattach);      $r->print('<b>'.$subject.'</b>');
             if (@currold > 0) {      $r->print(&Apache::lonhtmlcommon::row_closure());
                 $r->print($lt{'thfo'}.'<br />'.$lt{'chth'}.'<br />'."\n");        $r->print(&Apache::lonhtmlcommon::row_title($lt{'adda'}));
                 foreach my $id (@currold) {      $r->print('<input type="file" name="addnewattach" class="LC_flUpload" />'
                     my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'});           .'<input type="hidden" id="LC_free_space" value="131072" />'
                     $attachurl =~ m#/([^/]+)$#;          .'<input type="button" name="upload" value="Upload" '
                     $r->print('<label><input type="checkbox" name="deloldattach" value="'.$id.'" />&nbsp;'.$1.'</label><br />'."\n");          .'onclick="this.form.submit()" />  '.$attachmaxtext);
       if(($idx)||(ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)){
           $r->print(&Apache::lonhtmlcommon::row_closure());
           $r->print(&Apache::lonhtmlcommon::row_title(&mt('Attachments')));
           if ($idx) {
               if ($attachmenturls) {
                   my @currold = keys(%currattach);
                   if (@currold > 0) {
                       $r->print($lt{'thfo'}.'<br />'.$lt{'chth'}.'<br />'."\n");
                       foreach my $id (@currold) {
                           my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'});
                           $attachurl =~ m#/([^/]+)$#;
                           $r->print('<label><input type="checkbox" name="deloldattach" value="'.$id.'" />&nbsp;'.$1.'</label><br />'."\n");
                       }
                       $r->print("<br />");
                 }                  }
                 $r->print("<br />");  
             }              }
         }          }
     }          if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
     if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {              $r->print($lt{'chth'}.'<br />'."\n");
         $r->print($lt{'thef'}.'<br />'.$lt{'chth'}.'<br />'."\n");              foreach my $attach (@{$currnewattach}) {
         foreach my $attach (@{$currnewattach}) {                  $attach =~ m#/([^/]+)$#;
             $attach =~ m#/([^/]+)$#;                  $r->print('<label><input type="checkbox" name="delnewattach" value="'.$attach.'" />&nbsp;'.$1.'</label><br />'."\n");
             $r->print('<label><input type="checkbox" name="delnewattach" value="'.$attach.'" />&nbsp;'.$1.'</label><br />'."\n");              }
         }          }
         $r->print("<br />");   
     }      }
       $r->print(&Apache::lonhtmlcommon::row_closure(1));
       $r->print(&Apache::lonhtmlcommon::end_pick_box());
     $r->print(<<END);      $r->print(<<END);
    </td></tr>  
    <tr>  
     <td>  
    $lt{'adda'}</td><td><input type="file" name="addnewattach" /><input type="button" name="upload" value="Upload" onclick="this.form.submit()" />      
    </td>  
   </tr>  
   <tr>  
    <td colspan="2">$attachmaxtext</td>  
   </tr>  
  </table>  
 <input type="hidden" name="subject" value="$env{'form.subject'}" />  <input type="hidden" name="subject" value="$env{'form.subject'}" />
 <input type="hidden" name="comment" value="$env{'form.comment'}" />  <input type="hidden" name="comment" value="$env{'form.comment'}" />
 <input type="hidden" name="timestamp" value="$env{'form.timestamp'}" />  <input type="hidden" name="timestamp" value="$env{'form.timestamp'}" />
Line 3240  sub generate_attachments_button { Line 3775  sub generate_attachments_button {
     my $origpage = $ENV{'REQUEST_URI'};      my $origpage = $ENV{'REQUEST_URI'};
     my $att=$attachnum.' '.&mt("attachments");      my $att=$attachnum.' '.&mt("attachments");
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
                 'clic' => 'Click to add/remove attachments',                  'clic' => 'Add/remove attachments',
     );       ); 
     my $response = (<<END);      my $response = (<<END);
 <br />  <br />
 <form name="attachment" action="/adm/feedback?attach=$ressymb" method="post">  <form name="attachment" action="/adm/feedback?attach=$ressymb" method="post">
 $lt{'clic'}:&nbsp;<input type="button" value="$att"  <input type="button" value="$lt{'clic'}"
 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);  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);
 END  END
     if (!$blockblog) {      if (!$blockblog) {
Line 3481  sub handler { Line 4016  sub handler {
 # --------------------------- Get query string for limited number of parameters  # --------------------------- Get query string for limited number of parameters
   
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
          ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']);           ['like','unlike','modal','hide','unhide','deldisc','undeleteall','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']);
   my $group = $env{'form.group'};    my $group = $env{'form.group'};
     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
   
   my %attachmax = (    my %attachmax = (
                     text => &mt('(128 KB max size)'),                      text => &mt('(128 KB max size)'),
                     num  => 131072,                      num  => 131072,
                   );                    );
   if ($env{'form.editdisc'}) {    if ($env{'form.editdisc'}) {
       if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) {        if (!(&editing_allowed($env{'form.editdisc'},$group))) {
           my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];            my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
           my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);            my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
           my $feedurl=&Apache::lonnet::clutter($url);            my $feedurl=&Apache::lonnet::clutter($url);
           &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />',                     '0','0','','',$env{'form.previous'},undef,undef,undef,            &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />',
                     undef,undef,undef,$group);                           '0','0','','',$env{'form.previous'},undef,undef,undef,
                            undef,undef,undef,$group);
           return OK;            return OK;
       }        }
   }     } 
Line 3532  sub handler { Line 4071  sub handler {
       # Breadcrumbs        # Breadcrumbs
       my $brcrum = [{'href' => '',        my $brcrum = [{'href' => '',
                      'text' => 'Discussion Post Versions'}];                       'text' => 'Discussion Post Versions'}];
         
         my %parms=();
         if ($env{'form.modal'} ne 'yes') { $parms{'bread_crumbs'} = $brcrum; }
   
         $r->print(&Apache::loncommon::start_page('Discussion Post Versions',undef,\%parms));
   
       $r->print(&Apache::loncommon::start_page('Discussion Post Versions',undef,  
                                                {'bread_crumbs' => $brcrum,})  
       );  
   
       my $crs='/'.$env{'request.course.id'};  
       if ($env{'request.course.sec'}) {  
           $crs.='_'.$env{'request.course.sec'};  
       }  
       $crs=~s|_|/|g;  
       my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
       my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
       my ($symb,$idx)=split(/\:\:\:/,$env{'form.allversions'});        my ($symb,$idx)=split(/\:\:\:/,$env{'form.allversions'});
       ($symb)=&get_feedurl_and_clean_symb($symb);        ($symb, my $feedurl)=&get_feedurl_and_clean_symb($symb);
       my $ressymb = &wrap_symb($symb);        my $ressymb = &wrap_symb($symb);
       my $group = $env{'form.group'};  
       my $seeid;        my $seeid;
       if (($group ne '') && (($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|))) {        if (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
           if (&check_group_priv($group,'dgp') eq 'ok') {            $seeid = 1;
               $seeid = 1;  
           }  
       } else {  
           $seeid = &Apache::lonnet::allowed('rin',$crs);  
       }        }
         my $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
       if ($idx > 0) {        if ($idx > 0) {
           my %messages = ();            my %messages = ();
           my %subjects = ();            my %subjects = ();
           my %attachmsgs = ();            my %attachmsgs = ();
           my %allattachments = ();            my %allattachments = ();
           my %imsfiles = ();            my %imsfiles = ();
           my ($screenname,$plainname);            my ($screenname,$plainname,$showaboutme);
           my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},            my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                            $env{'course.'.$env{'request.course.id'}.'.domain'},                                                 $cdom,$cnum);
                            $env{'course.'.$env{'request.course.id'}.'.num'});            $r->print(&get_post_contents(\%contrib,$idx,$seeid,$seehidden,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname,\$showaboutme));
           $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname));  
       }        }
       $r->print(&Apache::loncommon::end_page());        $r->print(&Apache::loncommon::end_page());
       return OK;        return OK;
Line 3618  sub handler { Line 4146  sub handler {
       my $feedurl = '/adm/navmaps';        my $feedurl = '/adm/navmaps';
       if ($env{'form.navurl'}) { $feedurl .= '?'.$env{'form.navurl'}; }        if ($env{'form.navurl'}) { $feedurl .= '?'.$env{'form.navurl'}; }
       my %lt = &Apache::lonlocal::texthash(        my %lt = &Apache::lonlocal::texthash(
           'mnpa' => 'Marked "New" posts as read in a total of',  
           'robb' => 'resources/bulletin boards.',  
           'twnp' => 'There are currently no resources or discussion boards with unread discussion postings.'            'twnp' => 'There are currently no resources or discussion boards with unread discussion postings.'
       );               );       
       foreach my $res (@resources) {        foreach my $res (@resources) {
Line 3628  sub handler { Line 4154  sub handler {
           my $lastkey = $ressymb.'_lastread';            my $lastkey = $ressymb.'_lastread';
           $discinfo{$lastkey} = $env{'form.navtime'};            $discinfo{$lastkey} = $env{'form.navtime'};
       }        }
       my $textline = "<b>$lt{'mnpa'} $numitems $lt{'robb'}</b>";        my $textline = '<b>'.
                        &mt('Marked "New" posts as read in a total of [_1] resources/discussion boards.',
                            $numitems).
                        '</b>';
       if ($numitems > 0) {        if ($numitems > 0) {
           &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',            &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
      \%discinfo,$env{'user.domain'},$env{'user.name'});       \%discinfo,$env{'user.domain'},$env{'user.name'});
Line 3639  sub handler { Line 4168  sub handler {
       $r->send_http_header;        $r->send_http_header;
       my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');        my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
       my %onload;        my %onload;
       if ($env{'environment.remote'} ne 'off') {  
   $onload{'onload'} =  
       "if (window.name!='loncapaclient') { this.document.reldt.submit(); self.window.close(); }";  
       }  
   
       my $start_page=        my $start_page=
   &Apache::loncommon::start_page('New posts marked as read',undef,    &Apache::loncommon::start_page('New posts marked as read',undef,
Line 3708  ENDREDIR Line 4233  ENDREDIR
       my $entry=$env{'form.hide'}?$env{'form.hide'}:$env{'form.unhide'};        my $entry=$env{'form.hide'}?$env{'form.hide'}:$env{'form.unhide'};
       my ($symb,$idx)=split(/\:\:\:/,$entry);        my ($symb,$idx)=split(/\:\:\:/,$entry);
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);        ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
         my $ressymb = &wrap_symb($symb);
   
       my $crs='/'.$env{'request.course.id'};        my $seehidden = &can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum);
       if ($env{'request.course.sec'}) {        unless (($seehidden) || (&editing_allowed($env{'form.hide'},$group))) {
           $crs.='_'.$env{'request.course.sec'};            &redirect_back($r,$feedurl,&mt('Hiding not permitted').'<br />',
       }                           '0','0','','',$env{'form.previous'},'','','','',
       $crs=~s/\_/\//g;                           undef,undef,$group);
       my $seeid=&Apache::lonnet::allowed('rin',$crs);  
   
       if ($env{'form.hide'} && !$seeid && !(&editing_allowed($env{'form.hide'},$env{'form.group'}))) {  
           &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',                 '0','0','','',$env{'form.previous'},'','','','',  
                  undef,undef,$group,);  
           return OK;            return OK;
       }        }
   
       my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},        my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                           $env{'course.'.$env{'request.course.id'}.'.domain'},                                             $cdom,$cnum);
           $env{'course.'.$env{'request.course.id'}.'.num'});  
   
       my $currenthidden=$contrib{'hidden'};        my $currenthidden=$contrib{'hidden'};
       my $currentstudenthidden=$contrib{'studenthidden'};        my $currentstudenthidden=$contrib{'studenthidden'};
   
       if ($env{'form.hide'}) {        if ($env{'form.hide'}) {
   $currenthidden.='.'.$idx.'.';    $currenthidden.='.'.$idx.'.';
   unless ($seeid) {    unless ($seehidden) {
       $currentstudenthidden.='.'.$idx.'.';        $currentstudenthidden.='.'.$idx.'.';
   }    }
       } else {        } else {
   $currenthidden=~s/\.$idx\.//g;    $currenthidden=~s/\.$idx\.//g;
       }        }
       my %newhash=('hidden' => $currenthidden);        my %newhash=('hidden' => $currenthidden);
       if ( ($env{'form.hide'}) && (!$seeid) ) {        if ( ($env{'form.hide'}) && (!$seehidden) ) {
   $newhash{'studenthidden'} = $currentstudenthidden;    $newhash{'studenthidden'} = $currentstudenthidden;
       }        }
       if ($env{'form.hide'}) {        if ($env{'form.hide'}) {
Line 3747  ENDREDIR Line 4267  ENDREDIR
           ($changelast,$newlast) = &get_discussion_info($idx,%contrib);            ($changelast,$newlast) = &get_discussion_info($idx,%contrib);
           if ($changelast) {            if ($changelast) {
               &Apache::lonnet::put('discussiontimes',{$symb => $newlast},                &Apache::lonnet::put('discussiontimes',{$symb => $newlast},
                      $env{'course.'.$env{'request.course.id'}.'.domain'},                                     $cdom,$cnum);
                      $env{'course.'.$env{'request.course.id'}.'.num'});  
           }            }
       }        }
       &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},        my $result;
                            $env{'course.'.$env{'request.course.id'}.'.domain'},        if (&Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
    $env{'course.'.$env{'request.course.id'}.'.num'});                                   $cdom,$cnum) eq 'ok') {
             my $prefix=$symb.':'.$idx.':';
       &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',            my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,
      '0','0','','',$env{'form.previous'},undef,undef,undef,                                            '^'.$prefix);
             my ($totallikes,$totalunlikes);
             if (ref($likes{$prefix.'likers'}) eq 'HASH') {
                 $totallikes = scalar(keys(%{$likes{$prefix.'likers'}}));
             }
             if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
                 $totalunlikes = scalar(keys(%{$likes{$prefix.'unlikers'}}));
             }
             if ($totallikes || $totalunlikes) {
                 my ($chglikes,$chgunlikes,$context);
                 if ($env{'form.hide'}) {
                     $chglikes = -1 * $totallikes;
                     $chgunlikes = -1 * $totalunlikes;
                     $context = 'hide';
                 } else {
                     $chglikes = $totallikes;
                     $chgunlikes = $totalunlikes;
                     $context = 'unhide';
                 }
                 &storediscussionlikes($chglikes,$chgunlikes,
                                       $contrib{$idx.':sendername'},
                                       $contrib{$idx.':senderdomain'},
                                       $env{'request.course.id'},
                                       $context);
             
             }
             $result = &mt('Changed discussion status');
         } else {
             $result = &mt('Discussion status unchanged'); 
         }
         &redirect_back($r,$feedurl,$result.'<br />','0','0','','',
        $env{'form.previous'},undef,undef,undef,
                        undef,undef,undef,$group);
         return OK;
     } elsif (($env{'form.like'}) || ($env{'form.unlike'})) {
   # ----------------------------------------------------------------- Like/unlike
         my $entry=$env{'form.like'}?$env{'form.like'}:$env{'form.unlike'};
         my ($symb,$idx)=split(/\:\:\:/,$entry);
         ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
         my $result;
         if ($idx > 0) {
             my $realsymb = &get_realsymb($symb);
             my $status='OPEN';
             if ($Apache::lonhomework::parsing_a_problem ||
                 $Apache::lonhomework::parsing_a_task) {
                 $status=$Apache::inputtags::status[-1];
             }
             if (&discussion_vote_available($status,$realsymb)) {
                 my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                                                      $cdom,$cnum);
                 my $ownpost;
                 if (($contrib{$idx.':sendername'} eq $env{'user.name'}) && 
                     ($contrib{$idx.':senderdomain'} eq $env{'user.domain'})) {
                     $ownpost = 1;
                 }
                 if ($ownpost || $contrib{$idx.':hidden'} || $contrib{$idx.':deleted'}) {
                     $result = &mt('Vote not registered.').' ';
                 }
                 if ($ownpost) {
                     $result .= &mt('No voting for your own posts.');
                 } elsif ($contrib{$idx.':hidden'}) {
                     $result .= &mt('No voting for hidden posts.');
                 } elsif ($contrib{$idx.':deleted'}) {
                     $result .= &mt('No voting for deleted posts.');
                 } else {
   #
   # Likes and unlikes are in db-file "disclikes" of the course
   # The prefix is the $symb to identify the resource discussion,
   # and the $idx to identify the entry
   #
                     my $prefix=$symb.':'.$idx.':';
                     my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,
                                                     '^'.$prefix);
   
   # Get current like or unlike status for the $idx for this user.
                     my $thisuser=$env{'user.name'}.':'.$env{'user.domain'};
                     my ($userlikes,$userunlikes);
                     if (ref($likes{$prefix.'likers'}) eq 'HASH') {
                         if (exists($likes{$prefix.'likers'}{$thisuser})) {
                             $userlikes = 1;
                         }
                     }
                     if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
                         if (exists($likes{$prefix.'unlikers'}{$thisuser})) {
                             $userunlikes = 1;
                         }
                     }
   # Get the current "likes" count
                     my $likescount=$likes{$prefix.'likes'};
   # Find out if they already voted
   # Users cannot like a post twice, or unlike it twice.
   # They can change their mind, though.
                     my $alreadyflag=0;
                     my $votetype;
                     if ($env{'form.like'}) {
                         if ($userlikes) {
                             $alreadyflag=1;
                         } elsif ($userunlikes) {
                             delete($likes{$prefix.'unlikers'}{$thisuser});
                             $votetype = 'switch';
                             $likescount++;
                         } else {
                             if (ref($likes{$prefix.'likers'}) eq 'HASH') {
                                 $likes{$prefix.'likers'}{$thisuser} = 1;
                             } else {
                                 $likes{$prefix.'likers'} = {$thisuser => 1};
                             }
                             $likescount++;
                         }
                     } else {
                         if ($userunlikes) {
                             $alreadyflag=1;
                         } elsif ($userlikes) {
                             delete($likes{$prefix.'likers'}{$thisuser});
                             $votetype = 'switch';
                             $likescount--;
                         } else {
                             if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
                                 $likes{$prefix.'unlikers'}{$thisuser} = 1;
                             } else {
                                 $likes{$prefix.'unlikers'} = {$thisuser => 1};
                             }
                             $likescount--;
                         }
                     }
   # $alreadyflag would be 1 if they tried to double-like or double-unlike
                     if ($alreadyflag) {
                         if ($env{'form.like'}) {
                             $result= &mt("'Like' already registered");
                         } else {
                             $result= &mt("'Unlike' already registered");
                         }
                     } else {
                         my %newhash=($prefix.'likes'    => $likescount,
                                      $prefix.'likers'   => $likes{$prefix.'likers'},
                                      $prefix.'unlikers' => $likes{$prefix.'unlikers'});
   # Store data in db-file "disclikes"
                         if (&Apache::lonnet::put('disclikes',\%newhash,$cdom,$cnum) eq 'ok') {
   # Also store with the person who posted the liked/unliked entry
                             my ($chglike,$chgunlike);
                             if ($env{'form.like'}) {
                                 if ($votetype eq 'switch') {
                                     $chglike = 0;
                                     $chgunlike = -1;
                                 } else {
                                     $chglike = 1;
                                     $chgunlike = 0;
                                 } 
                                 &storediscussionlikes($chglike,$chgunlike,
                                                       $contrib{$idx.':sendername'},
                                                       $contrib{$idx.':senderdomain'},
                                                       $env{'request.course.id'},'like');
                                 $result=&mt("Registered 'Like'");
                             } else {
                                 if ($votetype eq 'switch') {
                                     $chglike = -1;
                                     $chgunlike = 0;
                                 } else {
                                     $chglike = 0;
                                     $chgunlike = 1;
                                 }
                                &storediscussionlikes($chglike,$chgunlike,
                                                      $contrib{$idx.':sendername'},
                                                      $contrib{$idx.':senderdomain'},
                                                      $env{'request.course.id'},'unlike');
                                $result=&mt("Registered 'Unlike'");
                             }
                         } else {
   # Oops, something went wrong
                             $result=&mt("Failed to register vote");
                         }
                     }
                 }
             } else {
                 $result=&mt('Voting unavailable for this discussion');
             }
         } else {
             $result=&mt('Invalid post number'); 
         }
         &redirect_back($r,$feedurl,$result.'<br />',
                        '0','0','','',$env{'form.previous'},undef,undef,undef,
                      undef,undef,undef,$group);                       undef,undef,undef,$group);
       return OK;        return OK;
   } elsif ($env{'form.cmd'}=~/^(threadedoff|threadedon)$/) {    } elsif ($env{'form.cmd'}=~/^(threadedoff|threadedon)$/) {
       my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});        my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
       if ($env{'form.cmd'} eq 'threadedon') {        if ($env{'form.cmd'} eq 'threadedoff') {
     &Apache::lonnet::put('environment',{'unthreadeddiscussion' => 'on'});
     &Apache::lonnet::appenv({'environment.unthreadeddiscussion' => 'on'});
     &Apache::lonnet::del('environment',['threadeddiscussion']);
     &Apache::lonnet::delenv('environment.threadeddiscussion');
         } else {
   &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});    &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
   &Apache::lonnet::appenv({'environment.threadeddiscussion' => 'on'});    &Apache::lonnet::appenv({'environment.threadeddiscussion' => 'on'});
       } else {    &Apache::lonnet::del('environment',['unthreadeddiscussion']);
    &Apache::lonnet::del('environment',['threadeddiscussion']);    &Apache::lonnet::delenv('environment.unthreadeddiscussion');
   &Apache::lonnet::delenv('environment.threadeddiscussion');  
       }        }
       &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />',        &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />',
      '0','0','','',$env{'form.previous'},undef,undef,undef,       '0','0','','',$env{'form.previous'},undef,undef,undef,
Line 3776  ENDREDIR Line 4479  ENDREDIR
 # --------------------------------------------------------------- Hide for good  # --------------------------------------------------------------- Hide for good
       my ($symb,$idx)=split(/\:\:\:/,$env{'form.deldisc'});        my ($symb,$idx)=split(/\:\:\:/,$env{'form.deldisc'});
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);        ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
         my $ressymb=&wrap_symb($symb);
   
         unless (&can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum)) {
             &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',
                            '0','0','','',$env{'form.previous'},'','','','',
                            undef,undef,$group);
             return OK;
         }
       my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},        my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                           $env{'course.'.$env{'request.course.id'}.'.domain'},                                             $cdom,$cnum);
           $env{'course.'.$env{'request.course.id'}.'.num'});  
       my ($changelast,$newlast) = &get_discussion_info($idx,%contrib);        my ($changelast,$newlast) = &get_discussion_info($idx,%contrib);
       if ($changelast) {        if ($changelast) {
           &Apache::lonnet::put('discussiontimes',{$symb => $newlast},            &Apache::lonnet::put('discussiontimes',{$symb => $newlast},
                    $env{'course.'.$env{'request.course.id'}.'.domain'},                   $env{'course.'.$env{'request.course.id'}.'.num'});                                 $cdom,$cnum);
       }        }
       my %newhash=('deleted' => $contrib{'deleted'}.".$idx.");        my %newhash=('deleted' => $contrib{'deleted'}.".$idx.");
       &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},  
    $env{'course.'.$env{'request.course.id'}.'.domain'},        my $result;
    $env{'course.'.$env{'request.course.id'}.'.num'});        if (&Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
       &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',                               $cdom,$cnum) eq 'ok') {
      '0','0','','',$env{'form.previous'},undef,undef,undef,            $result = &mt('Changed discussion status');
             my $prefix=$symb.':'.$idx.':';
             my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,
                                             '^'.$prefix);
             my ($totallikes,$totalunlikes);
             if (ref($likes{$prefix.'likers'}) eq 'HASH') {
                 $totallikes = scalar(keys(%{$likes{$prefix.'likers'}}));
             }
             if (ref($likes{$prefix.'unlikers'}) eq 'HASH') {
                 $totalunlikes = scalar(keys(%{$likes{$prefix.'unlikers'}}));
             }
             if ($totallikes || $totalunlikes) {
                 my $chglikes = -1 * $totallikes;
                 my $chgunlikes = -1 * $totalunlikes;
                 &storediscussionlikes($chglikes,$chgunlikes,
                                       $contrib{$idx.':sendername'},
                                       $contrib{$idx.':senderdomain'},
                                       $env{'request.course.id'},
                                       'delete');
             }
         } else {
             $result = &mt('Discussion status unchanged');
         } 
         &redirect_back($r,$feedurl,$result.'<br />','0','0','','',
        $env{'form.previous'},undef,undef,undef,
                      undef,undef,undef,$group);                       undef,undef,undef,$group);
       return OK;        return OK;
   } elsif ($env{'form.preview'}) {    } elsif ($env{'form.preview'}) {
Line 3817  ENDREDIR Line 4551  ENDREDIR
       my $idx = $env{'form.idx'};        my $idx = $env{'form.idx'};
       if ($idx) {        if ($idx) {
           my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},            my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                          $env{'course.'.$env{'request.course.id'}.'.domain'},                                                 $cdom,$cnum);
                          $env{'course.'.$env{'request.course.id'}.'.num'});  
           $attachmenturls = $contrib{$idx.':attachmenturl'};            $attachmenturls = $contrib{$idx.':attachmenturl'};
       }        }
       &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,        &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,
Line 3831  ENDREDIR Line 4564  ENDREDIR
       my $mode='board';        my $mode='board';
       my $status='OPEN';        my $status='OPEN';
       my $previous=$env{'form.previous'};        my $previous=$env{'form.previous'};
       if ($feedurl =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) {        if ($feedurl =~ /$LONCAPA::assess_re/) {
           $mode='problem';            $mode='problem';
           $status=$Apache::inputtags::status[-1];            $status=$Apache::inputtags::status[-1];
       }        }
          
       my $discussion = &list_discussion($mode,$status,$symb);         my $discussion = &list_discussion($mode,$status,$symb); 
       my $start_page =         my $start_page = 
   &Apache::loncommon::start_page('Resource Feedback and Discussion');    &Apache::loncommon::start_page('Resource Feedback and Discussion');
Line 3842  ENDREDIR Line 4576  ENDREDIR
   &Apache::loncommon::end_page();    &Apache::loncommon::end_page();
       $r->print($start_page.$discussion.$end_page);        $r->print($start_page.$discussion.$end_page);
       return OK;        return OK;
   
     } elsif ($env{'form.undeleteall'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my ($symb,$feedurl) = &get_feedurl_and_clean_symb($env{'form.undeleteall'});
         my $ressymb=&wrap_symb($symb);
         $r->print(&Apache::loncommon::start_page('Undelete all deleted discussion entries'));
         if (&can_see_hidden('',$ressymb,$feedurl,$group,$cdom,$cnum)) {
             my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
                                                   $cdom,$cnum);
             $contrib{'deleted'} =~ s/^\.//;
             $contrib{'deleted'} =~ s/\.$//;
             my $confirm_msg;
             if ($contrib{'deleted'} ne '') {
                 if (&Apache::lonnet::store({'deleted' => ''},$symb,$env{'request.course.id'},
                                             $cdom,$cnum) eq 'ok') {
                     my %likes=&Apache::lonnet::dump('disclikes',$cdom,$cnum,'^'.$symb.':');
                     my @ids = split(/\.\./,$contrib{'deleted'});
                     my (%chglikes,%chgunlikes);
                     foreach my $idx (@ids) {
                         my $uname = $contrib{$idx.':sendername'};
                         my $udom = $contrib{$idx.':senderdomain'};
                         my ($totallikes,$totalunlikes);
                         if (ref($likes{$symb.':'.$idx.':likers'}) eq 'HASH') {
                             $totallikes = scalar(keys(%{$likes{$symb.':'.$idx.':likers'}}));
                         }
                         if (ref($likes{$symb.':'.$idx.':unlikers'}) eq 'HASH') {
                             $totalunlikes = scalar(keys(%{$likes{$symb.':'.$idx.':unlikers'}}));
                         }
                         if ($totallikes || $totalunlikes) {
                             $chglikes{$uname.':'.$udom} += $totallikes;
                             $chgunlikes{$uname.':'.$udom} += $totalunlikes;
                         }
                     }
                     foreach my $user (keys(%chglikes)) {
                         my ($uname,$udom) = split(/:/,$user);
                         &storediscussionlikes($chglikes{$user},$chgunlikes{$user},
                                               $uname,$udom,$env{'request.course.id'},
                                               'undelete');
                     }
                     $confirm_msg = &Apache::lonhtmlcommon::confirm_success(&mt("Undeleted all entries"));
                 } else {
                     $confirm_msg = &Apache::lonhtmlcommon::confirm_success(&mt("Failed to undelete entries"),1);
                 }
             } else {
                 $confirm_msg = &Apache::lonhtmlcommon::confirm_success(&mt("No entries to undelete"),1);
             }
             $r->print(
                 '<br />'
                .&Apache::loncommon::confirmwrapper($confirm_msg)
                .&Apache::lonhtmlcommon::actionbox(
                     ["<a href='$feedurl'>".&mt("Return and reload")."</a>"])
             );
         }
         $r->print(&Apache::loncommon::end_page());
         return OK;
   } else {    } else {
 # ------------------------------------------------------------- Normal feedback  # ------------------------------------------------------------- Normal feedback
       my $feedurl=$env{'form.postdata'};        my $feedurl=$env{'form.postdata'};
Line 3857  ENDREDIR Line 4647  ENDREDIR
   $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];    $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
       } elsif ($env{'form.origpage'}) {        } elsif ($env{'form.origpage'}) {
   $symb="";     $symb=""; 
         } elsif ($env{'form.sendmessageonly'}) {
             $symb=(split(/\:\:\:/,$env{'form.sendmessageonly'}))[0];
       } else {        } else {
   $symb=&Apache::lonnet::symbread($feedurl);    $symb=&Apache::lonnet::symbread($feedurl);
       }        }
Line 3871  ENDREDIR Line 4663  ENDREDIR
           &dewrapper(\$feedurl);            &dewrapper(\$feedurl);
       }        }
       my $goahead=1;        my $goahead=1;
       if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form|task)$/) {        if ($feedurl=~/$LONCAPA::assess_re/) {
   unless ($symb) { $goahead=0; }    unless ($symb) { $goahead=0; }
       }        }
       if (!$goahead) {        if (!$goahead) {
Line 3879  ENDREDIR Line 4671  ENDREDIR
   $r->internal_redirect('/adm/ambiguous');    $r->internal_redirect('/adm/ambiguous');
   return OK;    return OK;
       }        }
         if ($feedurl eq '') {
             &Apache::loncommon::content_type($r,'text/html');
             $r->send_http_header;
             &no_redirect_back($r);
             return OK;
         }
 # Go ahead with feedback, no ambiguous reference  # Go ahead with feedback, no ambiguous reference
       unless (        unless (
   (    (
Line 3888  ENDREDIR Line 4686  ENDREDIR
   ($env{'request.course.id'} && ($feedurl!~m:^/adm:))    ($env{'request.course.id'} && ($feedurl!~m:^/adm:))
   ||    ||
   ($env{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))    ($env{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))
             ||
             (($env{'request.course.id'}) && ($feedurl =~ /ext\.tool$/))
   ) {    ) {
   &Apache::loncommon::content_type($r,'text/html');    &Apache::loncommon::content_type($r,'text/html');
   $r->send_http_header;    $r->send_http_header;
 # Unable to give feedback  # Unable to give feedback
           &Apache::lonenc::check_encrypt(\$feedurl);            &Apache::lonenc::check_encrypt(\$feedurl);
   &no_redirect_back($r,$feedurl);    &no_redirect_back($r,$feedurl,2);
   return OK;    return OK;
       }        }
 # --------------------------------------------------- Print login screen header  # --------------------------------------------------- Print login screen header
Line 3913  ENDREDIR Line 4713  ENDREDIR
   if ($options) {    if ($options) {
       &mail_screen($r,$feedurl,$options,$symb,$attachmax{'text'});        &mail_screen($r,$feedurl,$options,$symb,$attachmax{'text'});
   } else {    } else {
       &fail_redirect($r,$feedurl);        &fail_redirect($r,$feedurl,2);
   }    }
   return OK;    return OK;
       }        }
Line 3979  ENDREDIR Line 4779  ENDREDIR
       my ($typestyle,%to) = &Apache::lonmsg::decide_receiver($feedurl);        my ($typestyle,%to) = &Apache::lonmsg::decide_receiver($feedurl);
   
 # Actually send mail  # Actually send mail
       my ($status,$numsent)=&send_msg(&clear_out_html($env{'form.subject'}),        my $clientip = &Apache::lonnet::get_requestor_ip($r);
       $feedurl,$email,$citations,        my ($status,$numsent,$delay)=&send_msg(&clear_out_html($env{'form.subject'}),
       $attachmenturl,$usersymb,%to);               $feedurl,$email,$citations,
                $attachmenturl,$usersymb,$clientip,%to);
   
 # Discussion? Store that.  # Discussion? Store that.
       my $numpost=0;        my $numpost=0;
Line 4012  ENDREDIR Line 4813  ENDREDIR
       }        }
       
 # Receipt screen and redirect back to where came from  # Receipt screen and redirect back to where came from
       &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group,$toolarge);        &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},
                        undef,undef,undef,undef,undef,undef,$group,$toolarge,$delay);
   }    }
   return OK;    return OK;
 }  }
Line 4035  sub wrap_symb { Line 4837  sub wrap_symb {
     }      }
     return $ressymb;      return $ressymb;
 }  }
   
 sub dewrapper {  sub dewrapper {
     my ($feedurl)=@_;      my ($feedurl)=@_;
     if ($$feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {      if ($$feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
Line 4188  None Line 4991  None
   
 =item discussion_visible()  =item discussion_visible()
   
   =item discussion_vote_available()
   
   =item get_realsymb()
   
 =item list_discussion()  =item list_discussion()
   
   =item can_see_hidden()
   
   =item discussion_link()
   
 =item send_feedback_link()  =item send_feedback_link()
   
 =item send_message_link()  =item send_message_link()

Removed from v.1.290.2.7  
changed lines
  Added in v.1.370.2.5.2.2


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