# of hashes in which each hash represents a single attachment.
&::SendSQL("
SELECT attach_id, creation_ts, mimetype, description, ispatch,
- isobsolete, submitter_id
+ isobsolete, isprivate, submitter_id
FROM attachments WHERE bug_id = $bugid ORDER BY attach_id
");
my @attachments = ();
my %a;
my $submitter_id;
($a{'attachid'}, $a{'date'}, $a{'contenttype'}, $a{'description'},
- $a{'ispatch'}, $a{'isobsolete'}, $submitter_id) = &::FetchSQLData();
+ $a{'ispatch'}, $a{'isobsolete'}, $a{'isprivate'}, $submitter_id)
+ = &::FetchSQLData();
# Format the attachment's creation/modification date into a standard
# format (YYYY-MM-DD HH:MM)
# of hashes in which each hash represents a single attachment.
&::SendSQL("
SELECT attach_id, creation_ts, mimetype, description, ispatch,
- isobsolete, submitter_id
+ isobsolete, isprivate, submitter_id
FROM attachments WHERE bug_id = $bugid ORDER BY attach_id
");
my @attachments = ();
my %a;
my $submitter_id;
($a{'attachid'}, $a{'date'}, $a{'contenttype'}, $a{'description'},
- $a{'ispatch'}, $a{'isobsolete'}, $submitter_id) = &::FetchSQLData();
+ $a{'ispatch'}, $a{'isobsolete'}, $a{'isprivate'}, $submitter_id)
+ = &::FetchSQLData();
# Format the attachment's creation/modification date into a standard
# format (YYYY-MM-DD HH:MM)
"^long_?desc," => sub {
my $table = "longdescs_$chartid";
push(@supptables, "longdescs $table");
+ if (Param("insidergroup") && !UserInGroup(Param("insidergroup"))) {
+ push(@wherepart, "$table.isprivate < 1") ;
+ }
push(@wherepart, "$table.bug_id = bugs.bug_id");
$f = "$table.thetext";
},
}
AppendComment($id, DBID_to_name($who),
- "*** This bug has been confirmed by popular vote. ***");
+ "*** This bug has been confirmed by popular vote. ***", 0);
$vars->{'type'} = "votes";
$vars->{'id'} = $id;
validateIsPatch();
validateContentType() unless $::FORM{'ispatch'};
validateIsObsolete();
+ validatePrivate();
validateStatuses();
update();
}
sub validateID
{
- # Validate the value of the "id" form field, which must contain an
- # integer that is the ID of an existing attachment.
+ # Validate the value of the "id" form field, which must contain an
+ # integer that is the ID of an existing attachment.
- detaint_natural($::FORM{'id'})
- || DisplayError("You did not enter a valid attachment number.")
+ detaint_natural($::FORM{'id'})
+ || DisplayError("You did not enter a valid attachment number.")
&& exit;
- # Make sure the attachment exists in the database.
- SendSQL("SELECT bug_id FROM attachments WHERE attach_id = $::FORM{'id'}");
- MoreSQLData()
- || DisplayError("Attachment #$::FORM{'id'} does not exist.")
- && exit;
+ # Make sure the attachment exists in the database.
+ SendSQL("SELECT bug_id, isprivate FROM attachments WHERE attach_id = $::FORM{'id'}");
+ MoreSQLData()
+ || DisplayError("Attachment #$::FORM{'id'} does not exist.")
+ && exit;
- # Make sure the user is authorized to access this attachment's bug.
- my ($bugid) = FetchSQLData();
- ValidateBugID($bugid);
+ # Make sure the user is authorized to access this attachment's bug.
+ my ($bugid, $isprivate) = FetchSQLData();
+ ValidateBugID($bugid);
+ if (($isprivate > 0 ) && Param("insidergroup") && !(UserInGroup(Param("insidergroup")))) {
+ ThrowUserError("You are not permitted access to this attachment.");
+ }
}
sub validateCanEdit
$::FORM{'isobsolete'} = $::FORM{'isobsolete'} ? 1 : 0;
}
+sub validatePrivate
+{
+ # Set the isprivate flag to zero if it is undefined, since the UI uses
+ # an HTML checkbox to represent this flag, and unchecked HTML checkboxes
+ # do not get sent in HTML requests.
+ $::FORM{'isprivate'} = $::FORM{'isprivate'} ? 1 : 0;
+}
+
sub validateStatuses
{
# Get a list of attachment statuses that are valid for this attachment.
sub view
{
- # Display an attachment.
+ # Display an attachment.
- # Retrieve the attachment content and its content type from the database.
- SendSQL("SELECT mimetype, thedata FROM attachments WHERE attach_id = $::FORM{'id'}");
- my ($contenttype, $thedata) = FetchSQLData();
+ # Retrieve the attachment content and its content type from the database.
+ SendSQL("SELECT mimetype, thedata FROM attachments WHERE attach_id = $::FORM{'id'}");
+ my ($contenttype, $thedata) = FetchSQLData();
- # Return the appropriate HTTP response headers.
- print "Content-Type: $contenttype\n\n";
+ # Return the appropriate HTTP response headers.
+ print "Content-Type: $contenttype\n\n";
- print $thedata;
+ print $thedata;
}
# Retrieve the attachments from the database and write them into an array
# of hashes where each hash represents one attachment.
- SendSQL("SELECT attach_id, creation_ts, mimetype, description, ispatch, isobsolete
- FROM attachments WHERE bug_id = $::FORM{'bugid'} ORDER BY attach_id");
+ my $privacy = "";
+ if (Param("insidergroup") && !(UserInGroup(Param("insidergroup")))) {
+ $privacy = "AND isprivate < 1 ";
+ }
+ SendSQL("SELECT attach_id, creation_ts, mimetype, description,
+ ispatch, isobsolete, isprivate
+ FROM attachments WHERE bug_id = $::FORM{'bugid'} $privacy
+ ORDER BY attach_id");
my @attachments; # the attachments array
while (MoreSQLData())
{
my %a; # the attachment hash
($a{'attachid'}, $a{'date'}, $a{'contenttype'},
- $a{'description'}, $a{'ispatch'}, $a{'isobsolete'}) = FetchSQLData();
+ $a{'description'}, $a{'ispatch'}, $a{'isobsolete'}, $a{'isprivate'}) = FetchSQLData();
# Flag attachments as to whether or not they can be viewed (as opposed to
# being downloaded). Currently I decide they are viewable if their MIME type
if (!UserInGroup("editbugs")) {
$canEdit = "AND submitter_id = $::userid";
}
- SendSQL("SELECT attach_id, description
+ SendSQL("SELECT attach_id, description, isprivate
FROM attachments
WHERE bug_id = $::FORM{'bugid'}
AND isobsolete = 0 $canEdit
my @attachments; # the attachments array
while ( MoreSQLData() ) {
my %a; # the attachment hash
- ($a{'id'}, $a{'description'}) = FetchSQLData();
+ ($a{'id'}, $a{'description'}, $a{'isprivate'}) = FetchSQLData();
# Add the hash representing the attachment to the array of attachments.
push @attachments, \%a;
my $description = SqlQuote($::FORM{'description'});
my $contenttype = SqlQuote($::FORM{'contenttype'});
my $thedata = SqlQuote($::FORM{'data'});
+ my $isprivate = $::FORM{'isprivate'} ? 1 : 0;
# Insert the attachment into the database.
- SendSQL("INSERT INTO attachments (bug_id, creation_ts, filename, description, mimetype, ispatch, submitter_id, thedata)
- VALUES ($::FORM{'bugid'}, now(), $filename, $description, $contenttype, $::FORM{'ispatch'}, $::userid, $thedata)");
+ SendSQL("INSERT INTO attachments (bug_id, creation_ts, filename, description, mimetype, ispatch, isprivate, submitter_id, thedata)
+ VALUES ($::FORM{'bugid'}, now(), $filename, $description, $contenttype, $::FORM{'ispatch'}, $isprivate, $::userid, $thedata)");
# Retrieve the ID of the newly created attachment record.
SendSQL("SELECT LAST_INSERT_ID()");
AppendComment($::FORM{'bugid'},
$::COOKIE{"Bugzilla_login"},
- $comment);
+ $comment,
+ $isprivate);
# Make existing attachments obsolete.
my $fieldid = GetFieldID('attachments.isobsolete');
foreach my $attachid (@{$::MFORM{'obsolete'}}) {
- SendSQL("UPDATE attachments SET isobsolete = 1 WHERE attach_id = $attachid");
- SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
- VALUES ($::FORM{'bugid'}, $attachid, $::userid, NOW(), $fieldid, '0', '1')");
+ SendSQL("UPDATE attachments SET isobsolete = 1 WHERE attach_id = $attachid");
+ SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
+ VALUES ($::FORM{'bugid'}, $attachid, $::userid, NOW(), $fieldid, '0', '1')");
}
# Send mail to let people know the attachment has been created. Uses a
# Users cannot edit the content of the attachment itself.
# Retrieve the attachment from the database.
- SendSQL("SELECT description, mimetype, bug_id, ispatch, isobsolete
+ SendSQL("SELECT description, mimetype, bug_id, ispatch, isobsolete, isprivate
FROM attachments WHERE attach_id = $::FORM{'id'}");
- my ($description, $contenttype, $bugid, $ispatch, $isobsolete) = FetchSQLData();
+ my ($description, $contenttype, $bugid, $ispatch, $isobsolete, $isprivate) = FetchSQLData();
# Flag attachment as to whether or not it can be viewed (as opposed to
# being downloaded). Currently I decide it is viewable if its content
$vars->{'bugsummary'} = $bugsummary;
$vars->{'ispatch'} = $ispatch;
$vars->{'isobsolete'} = $isobsolete;
+ $vars->{'isprivate'} = $isprivate;
$vars->{'isviewable'} = $isviewable;
$vars->{'statuses'} = \%statuses;
$vars->{'statusdefs'} = \@statusdefs;
# Lock database tables in preparation for updating the attachment.
SendSQL("LOCK TABLES attachments WRITE , attachstatuses WRITE ,
attachstatusdefs READ , fielddefs READ , bugs_activity WRITE");
-
# Get a copy of the attachment record before we make changes
# so we can record those changes in the activity table.
- SendSQL("SELECT description, mimetype, ispatch, isobsolete
+ SendSQL("SELECT description, mimetype, ispatch, isobsolete, isprivate
FROM attachments WHERE attach_id = $::FORM{'id'}");
- my ($olddescription, $oldcontenttype, $oldispatch, $oldisobsolete) = FetchSQLData();
+ my ($olddescription, $oldcontenttype, $oldispatch, $oldisobsolete,
+ $oldisprivate ) = FetchSQLData();
# Get the list of old status flags.
SendSQL("SELECT attachstatusdefs.name
mimetype = $quotedcontenttype ,
ispatch = $::FORM{'ispatch'} ,
isobsolete = $::FORM{'isobsolete'}
+ isprivate = $::FORM{'isprivate'} ,
WHERE attach_id = $::FORM{'id'}
");
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $oldisobsolete, $::FORM{'isobsolete'})");
}
+ if ($oldisprivate ne $::FORM{'isprivate'}) {
+ my $fieldid = GetFieldID('attachments.isprivate');
+ SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
+ VALUES ($bugid, $::FORM{'id'}, $::userid, NOW(), $fieldid, $oldisprivate, $::FORM{'isprivate'})");
+ }
if ($oldstatuslist ne $newstatuslist) {
my ($removed, $added) = DiffStrings($oldstatuslist, $newstatuslist);
my $quotedremoved = SqlQuote($removed);
my $neverused = $::userid;
# Append the comment to the list of comments in the database.
- AppendComment($bugid, $who, $wrappedcomment);
+ AppendComment($bugid, $who, $wrappedcomment, $::FORM{'isprivate'});
}
thedata longblob not null,
submitter_id mediumint not null,
isobsolete tinyint not null default 0,
+ isprivate tinyint not null default 0,
index(bug_id),
index(creation_ts)';
who mediumint not null,
bug_when datetime not null,
thetext mediumtext,
-
+ isprivate tinyint not null default 0,
index(bug_id),
index(who),
index(bug_when)';
AddFDef("attachments.mimetype", "Attachment mime type", 0);
AddFDef("attachments.ispatch", "Attachment is patch", 0);
AddFDef("attachments.isobsolete", "Attachment is obsolete", 0);
+AddFDef("attachments.isprivate", "Attachment is private", 0);
AddFDef("attachstatusdefs.name", "Attachment Status", 0);
AddFDef("target_milestone", "Target Milestone", 0);
AddFDef("delta_ts", "Last changed date", 0);
DropField('bugs_activity', 'field');
}
+
+# 2002-05-10 - enhanchment bug 143826
+# Add private comments and private attachments on less-private bugs
+AddField('longdescs', 'isprivate', 'tinyint not null default 0');
+AddField('attachments', 'isprivate', 'tinyint not null default 0');
+
# 2000-01-18 New email-notification scheme uses a new field in the bug to
"t" ,
'1000');
+DefParam("insidergroup",
+ "The name of the group of users who can see/change private comments
+ and attachments.",
+ "t",
+ '');
1;
+
"status", "resolution", "summary");
sub AppendComment {
- my ($bugid,$who,$comment) = (@_);
+ my ($bugid,$who,$comment,$isprivate) = (@_);
$comment =~ s/\r\n/\n/g; # Get rid of windows-style line endings.
$comment =~ s/\r/\n/g; # Get rid of mac-style line endings.
if ($comment =~ /^\s*$/) { # Nothin' but whitespace.
}
my $whoid = DBNameToIdAndCheck($who);
-
- SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext) " .
- "VALUES($bugid, $whoid, now(), " . SqlQuote($comment) . ")");
+ my $privacyval = $isprivate ? 1 : 0 ;
+ SendSQL("INSERT INTO longdescs (bug_id, who, bug_when, thetext, isprivate) " .
+ "VALUES($bugid, $whoid, now(), " . SqlQuote($comment) . ", " .
+ $privacyval . ")");
SendSQL("UPDATE bugs SET delta_ts = now() WHERE bug_id = $bugid");
}
my ($id, $start, $end) = (@_);
my $result = "";
my $count = 0;
+ my $anyprivate = 0;
my ($query) = ("SELECT profiles.login_name, longdescs.bug_when, " .
- " longdescs.thetext " .
+ " longdescs.thetext, longdescs.isprivate " .
"FROM longdescs, profiles " .
"WHERE profiles.userid = longdescs.who " .
"AND longdescs.bug_id = $id ");
$query .= "ORDER BY longdescs.bug_when";
SendSQL($query);
while (MoreSQLData()) {
- my ($who, $when, $text) = (FetchSQLData());
+ my ($who, $when, $text, $isprivate) = (FetchSQLData());
if ($count) {
$result .= "\n\n------- Additional Comments From $who".Param('emailsuffix')." ".
time2str("%Y-%m-%d %H:%M", str2time($when)) . " -------\n";
}
+ if (($isprivate > 0) && Param("insidergroup")) {
+ $anyprivate = 1;
+ }
$result .= $text;
$count++;
}
- return $result;
+ return ($result, $anyprivate);
}
sub GetComments {
my ($id) = (@_);
my @comments;
-
SendSQL("SELECT profiles.realname, profiles.login_name,
date_format(longdescs.bug_when,'%Y-%m-%d %H:%i'),
- longdescs.thetext
+ longdescs.thetext,
+ isprivate,
+ date_format(longdescs.bug_when,'%Y%m%d%H%i%s')
FROM longdescs, profiles
WHERE profiles.userid = longdescs.who
AND longdescs.bug_id = $id
while (MoreSQLData()) {
my %comment;
- ($comment{'name'}, $comment{'email'}, $comment{'time'}, $comment{'body'}) = FetchSQLData();
+ ($comment{'name'}, $comment{'email'}, $comment{'time'}, $comment{'body'},
+ $comment{'isprivate'}, $comment{'when'}) = FetchSQLData();
$comment{'email'} .= Param('emailsuffix');
$comment{'name'} = $comment{'name'} || $comment{'email'};
}
}
+if ($::FORM{'id'} &&
+ (Param("insidergroup") && UserInGroup(Param("insidergroup")))) {
+ detaint_natural($::FORM{'id'});
+ foreach my $field (keys %::FORM) {
+ if ($field =~ /when-([0-9]+)/) {
+ my $sequence = $1;
+ my $private = $::FORM{"isprivate-$sequence"} ? 1 : 0 ;
+ if ($private != $::FORM{"oisprivate-$sequence"}) {
+ detaint_natural($::FORM{"$field"});
+ SendSQL("UPDATE longdescs SET isprivate = $private
+ WHERE bug_id = $::FORM{'id'} AND bug_when = " . $::FORM{"$field"});
+ }
+ }
+
+ }
+}
my $duplicate = 0;
$timestamp = FetchOneColumn();
if (defined $::FORM{'comment'}) {
- AppendComment($id, $::COOKIE{'Bugzilla_login'}, $::FORM{'comment'});
+ AppendComment($id, $::COOKIE{'Bugzilla_login'}, $::FORM{'comment'},
+ $::FORM{'commentprivacy'});
}
my $removedCcString = "";
LogActivityEntry($duplicate,"cc","",DBID_to_name($reporter));
SendSQL("INSERT INTO cc (who, bug_id) VALUES ($reporter, " . SqlQuote($duplicate) . ")");
}
- AppendComment($duplicate, $::COOKIE{'Bugzilla_login'}, "*** Bug $::FORM{'id'} has been marked as a duplicate of this bug. ***");
+ AppendComment($duplicate, $::COOKIE{'Bugzilla_login'}, "*** Bug $::FORM{'id'} has been marked as a duplicate of this bug. ***", 1);
CheckFormFieldDefined(\%::FORM,'comment');
SendSQL("INSERT INTO duplicates VALUES ($duplicate, $::FORM{'id'})");
}
- my $newcomments = GetLongDescriptionAsText($id, $start, $end);
+ my ($newcomments, $anyprivate) = GetLongDescriptionAsText($id, $start, $end);
#
# Start of email filtering code
\@reasons, \%values,
\%defmailhead,
\%fielddescription, $difftext,
- $newcomments, $start, $id,
+ $newcomments, $anyprivate,
+ $start, $id,
\@depbugs)))
{
return @recipients;
}
-sub NewProcessOnePerson ($$$$$$$$$$$$) {
+sub NewProcessOnePerson ($$$$$$$$$$$$$) {
my ($person, $count, $hlRef, $reasonsRef, $valueRef, $dmhRef, $fdRef, $difftext,
- $newcomments, $start, $id, $depbugsRef) = @_;
+ $newcomments, $anyprivate, $start, $id, $depbugsRef) = @_;
my %values = %$valueRef;
my @headerlist = @$hlRef;
# quietly disappear from their radar.
#
return unless CanSeeBug($id, $userid, $groupset);
-
+
+ # Drop any non-insiders if the comment is private
+ if (Param("insidergroup") && ($anyprivate != 0)) {
+ ConnectToDatabase();
+ PushGlobalSQLState();
+ SendSQL("select (bit & $groupset ) != 0 from groups where name = " . SqlQuote(Param("insidergroup")));
+ my $bit = FetchOneColumn();
+ PopGlobalSQLState();
+ if (!$bit) {
+ return;
+ }
+ }
+
# We shouldn't send changedmail if this is a dependency mail, and any of
# the depending bugs is not visible to the user.
foreach my $dep_id (@depbugs) {
onchange="if (this.value) this.form.contenttypemethod[2].checked = true;">
</td>
</tr>
+ [% IF (Param("insidergroup") && UserInGroup(Param("insidergroup"))) %]
+ <tr>
+ <th>Privacy:</th>
+ <td>
+ <em>If the attachment is private, check the box below.</em><br>
+ <input type="checkbox" name="isprivate" id="isprivate" value="1">
+ <label for="isprivate">Private</label>
+ </td>
+ </tr>
+ [% END %]
<tr>
<th>Obsoletes:</th>
<td>
<em>(optional) Check each existing attachment made obsolete by your new attachment.</em><br>
[% IF attachments.size %]
[% FOREACH attachment = attachments %]
- <input type="checkbox" id="[% attachment.id %]"
+ [% IF ((attachment.isprivate == 0) || (Param("insidergroup")
+ && UserInGroup(Param("insidergroup")))) %]
+ <input type="checkbox" id="[% attachment.id %]"
name="obsolete" value="[% attachment.id %]">
- <a href="attachment.cgi?id=[% attachment.id %]&action=edit">[% attachment.id %]: [% attachment.description FILTER html %]</a><br>
+ <a href="attachment.cgi?id=[% attachment.id %]&action=edit">[% attachment.id %]: [% attachment.description FILTER html %]</a><br>
+ [% END %]
[% END %]
[% ELSE %]
[no attachments can be made obsolete]
<input type="checkbox" id="isobsolete" name="isobsolete" value="1"
[% 'checked="checked"' IF isobsolete %]>
<label for="isobsolete">obsolete</label><br>
+ [% IF (Param("insidergroup") && UserInGroup(Param("insidergroup"))) %]
+ <input type="checkbox" name="isprivate" value="1"[% " checked" IF isprivate %]> private<br><br>
+ [% END %]
[% IF statusdefs.size %]
<b>Status:</b><br>
<th bgcolor="#cccccc" align="left">Status</th>
<th bgcolor="#cccccc" align="left">Actions</th>
</tr>
-
+ [% canseeprivate = !Param("insidergroup") || UserInGroup(Param("insidergroup")) %]
[% FOREACH attachment = attachments %]
- <tr>
+ [% IF !attachment.isprivate || canseeprivate %]
+ <tr [% "class=\"bz_private\"" IF attachment.isprivate %]>
<td valign="top">
[% IF attachment.isobsolete %]
<strike><a href="attachment.cgi?id=[% attachment.attachid %]&action=view">[% attachment.description FILTER html %]</a></strike>
[% END %]
</td>
</tr>
+ [% END %]
[% END %]
<tr>
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
-[% DEFAULT start_at = 0 %]
+[% DEFAULT start_at = 0 mode = "show" %]
[% count = 0 %]
+[% isinsider = Param("insidergroup") && UserInGroup(Param("insidergroup")) %]
[% FOREACH comment = comments %]
[% IF count >= start_at %]
[% PROCESS a_comment %]
[%############################################################################%]
[% BLOCK a_comment %]
- [% IF count > 0 %]
- <br>
- <i>------- Additional Comment
- <a name="c[% count %]" href="#c[% count %]">#[% count %]</a> From
- <a href="mailto:[% comment.email FILTER html %]">[% comment.name FILTER html %]</a>
- [%+ comment.time %] -------
- </i>
- [% END %]
+ [% IF NOT comment.isprivate || isinsider %]
+ <div [% "class=\"bz_private\"" IF comment.isprivate %]>
+ [% IF count > 0 %]
+ <br>
+ <i>------- Additional Comment
+ <a name="c[% count %]" href="#c[% count %]">#[% count %]</a> From
+ <a href="mailto:[% comment.email FILTER html %]">[% comment.name FILTER html %]</a>
+ [%+ comment.time %] -------
+ </i>
+ [% END %]
+ [% IF mode == "edit" && isinsider %]
+ <i>
+ <input type=hidden name="oisprivate-[% count %]"
+ value="[% comment.isprivate %]">
+ <input type=hidden name="when-[% count %]" value="[% comment.when %]">
+ <input type=checkbox name="isprivate-[% count %]" value="1"
+ [% " checked=\"checked\"" IF comment.isprivate %]> Private
+ </i>
+ [% END %]
[%# Don't indent the <pre> block, since then the spaces are displayed in the
# generated HTML
<pre>
[%- quoteUrls(comment.body) -%]
</pre>
+ </div>
+ [% END %]
[% END %]
h2 = filtered_desc
h3 = "Last modified: $bug.calc_disp_date"
header_html = navigation_links
+ style_urls = [ "css/edit_bug.css" ]
%]
[% END %]
<br>
<b>Additional <u>C</u>omments:</b>
+ [% IF Param("insidergroup") && UserInGroup(Param("insidergroup")) %]
+ <input type="checkbox" name="commentprivacy" value="1"> Private
+ [% END %]
<br>
<textarea wrap="hard" name="comment" rows="10" cols="80"
accesskey="c"></textarea>
value="[% Param("move-button-text") %]">
[% END %]
</p>
-</form>
[%# *** Additional Comments *** %]
[% PROCESS bug/comments.html.tmpl
comments = bug.comments
+ mode = "edit"
%]
+</form>
<hr>
[% PROCESS bug/navigate.html.tmpl %]
[% PROCESS global/header.html.tmpl
title = "Full Text Bug Listing"
+ style_urls = [ "css/show_multiple.css" ]
%]
-
[% IF bugs.first %]
[% FOREACH bug = bugs %]
[% PROCESS bug_display %]