Commit 46c9fb47 authored by myk%mozilla.org's avatar myk%mozilla.org

Fix for bug 99203: Implements bug aliases feature.

r=bbaetz,jouni
parent 69083950
...@@ -33,7 +33,7 @@ package Bug; ...@@ -33,7 +33,7 @@ package Bug;
use CGI::Carp qw(fatalsToBrowser); use CGI::Carp qw(fatalsToBrowser);
my %ok_field; my %ok_field;
for my $key (qw (bug_id product version rep_platform op_sys bug_status for my $key (qw (bug_id alias product version rep_platform op_sys bug_status
resolution priority bug_severity component assigned_to resolution priority bug_severity component assigned_to
reporter bug_file_loc short_desc target_milestone reporter bug_file_loc short_desc target_milestone
qa_contact status_whiteboard creation_ts groupset qa_contact status_whiteboard creation_ts groupset
...@@ -74,9 +74,12 @@ sub initBug { ...@@ -74,9 +74,12 @@ sub initBug {
my $self = shift(); my $self = shift();
my ($bug_id, $user_id) = (@_); my ($bug_id, $user_id) = (@_);
# If the bug ID isn't numeric, it might be an alias, so try to convert it.
$bug_id = &::BugAliasToID($bug_id) if $bug_id !~ /^[1-9][0-9]*$/;
my $old_bug_id = $bug_id; my $old_bug_id = $bug_id;
if ((! defined $bug_id) || (!$bug_id) || (!&::detaint_natural($bug_id))) { if ((! defined $bug_id) || (!$bug_id) || (!&::detaint_natural($bug_id))) {
# no bug number given # no bug number given or the alias didn't match a bug
$self->{'bug_id'} = $old_bug_id; $self->{'bug_id'} = $old_bug_id;
$self->{'error'} = "InvalidBugId"; $self->{'error'} = "InvalidBugId";
return $self; return $self;
...@@ -108,7 +111,7 @@ sub initBug { ...@@ -108,7 +111,7 @@ sub initBug {
my $query = " my $query = "
select select
bugs.bug_id, product, version, rep_platform, op_sys, bug_status, bugs.bug_id, alias, product, version, rep_platform, op_sys, bug_status,
resolution, priority, bug_severity, component, assigned_to, reporter, resolution, priority, bug_severity, component, assigned_to, reporter,
bug_file_loc, short_desc, target_milestone, qa_contact, bug_file_loc, short_desc, target_milestone, qa_contact,
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'), status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
...@@ -123,7 +126,7 @@ sub initBug { ...@@ -123,7 +126,7 @@ sub initBug {
if (@row = &::FetchSQLData()) { if (@row = &::FetchSQLData()) {
my $count = 0; my $count = 0;
my %fields; my %fields;
foreach my $field ("bug_id", "product", "version", "rep_platform", foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
"op_sys", "bug_status", "resolution", "priority", "op_sys", "bug_status", "resolution", "priority",
"bug_severity", "component", "assigned_to", "reporter", "bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone", "bug_file_loc", "short_desc", "target_milestone",
...@@ -248,7 +251,7 @@ sub emitXML { ...@@ -248,7 +251,7 @@ sub emitXML {
$xml .= "<bug>\n"; $xml .= "<bug>\n";
foreach my $field ("bug_id", "bug_status", "product", foreach my $field ("bug_id", "alias", "bug_status", "product",
"priority", "version", "rep_platform", "assigned_to", "delta_ts", "priority", "version", "rep_platform", "assigned_to", "delta_ts",
"component", "reporter", "target_milestone", "bug_severity", "component", "reporter", "target_milestone", "bug_severity",
"creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc", "creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc",
......
...@@ -33,7 +33,7 @@ package Bug; ...@@ -33,7 +33,7 @@ package Bug;
use CGI::Carp qw(fatalsToBrowser); use CGI::Carp qw(fatalsToBrowser);
my %ok_field; my %ok_field;
for my $key (qw (bug_id product version rep_platform op_sys bug_status for my $key (qw (bug_id alias product version rep_platform op_sys bug_status
resolution priority bug_severity component assigned_to resolution priority bug_severity component assigned_to
reporter bug_file_loc short_desc target_milestone reporter bug_file_loc short_desc target_milestone
qa_contact status_whiteboard creation_ts groupset qa_contact status_whiteboard creation_ts groupset
...@@ -74,9 +74,12 @@ sub initBug { ...@@ -74,9 +74,12 @@ sub initBug {
my $self = shift(); my $self = shift();
my ($bug_id, $user_id) = (@_); my ($bug_id, $user_id) = (@_);
# If the bug ID isn't numeric, it might be an alias, so try to convert it.
$bug_id = &::BugAliasToID($bug_id) if $bug_id !~ /^[1-9][0-9]*$/;
my $old_bug_id = $bug_id; my $old_bug_id = $bug_id;
if ((! defined $bug_id) || (!$bug_id) || (!&::detaint_natural($bug_id))) { if ((! defined $bug_id) || (!$bug_id) || (!&::detaint_natural($bug_id))) {
# no bug number given # no bug number given or the alias didn't match a bug
$self->{'bug_id'} = $old_bug_id; $self->{'bug_id'} = $old_bug_id;
$self->{'error'} = "InvalidBugId"; $self->{'error'} = "InvalidBugId";
return $self; return $self;
...@@ -108,7 +111,7 @@ sub initBug { ...@@ -108,7 +111,7 @@ sub initBug {
my $query = " my $query = "
select select
bugs.bug_id, product, version, rep_platform, op_sys, bug_status, bugs.bug_id, alias, product, version, rep_platform, op_sys, bug_status,
resolution, priority, bug_severity, component, assigned_to, reporter, resolution, priority, bug_severity, component, assigned_to, reporter,
bug_file_loc, short_desc, target_milestone, qa_contact, bug_file_loc, short_desc, target_milestone, qa_contact,
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'), status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
...@@ -123,7 +126,7 @@ sub initBug { ...@@ -123,7 +126,7 @@ sub initBug {
if (@row = &::FetchSQLData()) { if (@row = &::FetchSQLData()) {
my $count = 0; my $count = 0;
my %fields; my %fields;
foreach my $field ("bug_id", "product", "version", "rep_platform", foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
"op_sys", "bug_status", "resolution", "priority", "op_sys", "bug_status", "resolution", "priority",
"bug_severity", "component", "assigned_to", "reporter", "bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone", "bug_file_loc", "short_desc", "target_milestone",
...@@ -248,7 +251,7 @@ sub emitXML { ...@@ -248,7 +251,7 @@ sub emitXML {
$xml .= "<bug>\n"; $xml .= "<bug>\n";
foreach my $field ("bug_id", "bug_status", "product", foreach my $field ("bug_id", "alias", "bug_status", "product",
"priority", "version", "rep_platform", "assigned_to", "delta_ts", "priority", "version", "rep_platform", "assigned_to", "delta_ts",
"component", "reporter", "target_milestone", "bug_severity", "component", "reporter", "target_milestone", "bug_severity",
"creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc", "creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc",
......
...@@ -248,21 +248,54 @@ sub CheckFormFieldDefined (\%$) { ...@@ -248,21 +248,54 @@ sub CheckFormFieldDefined (\%$) {
} }
} }
sub BugAliasToID {
# Queries the database for the bug with a given alias, and returns
# the ID of the bug if it exists or the undefined value if it doesn't.
my ($alias) = @_;
return undef unless Param("usebugaliases");
PushGlobalSQLState();
SendSQL("SELECT bug_id FROM bugs WHERE alias = " . SqlQuote($alias));
my $id = FetchOneColumn();
PopGlobalSQLState();
return $id;
}
sub ValidateBugID { sub ValidateBugID {
# Validates and verifies a bug ID, making sure the number is a # Validates and verifies a bug ID, making sure the number is a
# positive integer, that it represents an existing bug in the # positive integer, that it represents an existing bug in the
# database, and that the user is authorized to access that bug. # database, and that the user is authorized to access that bug.
# We detaint the number here, too # We detaint the number here, too
$_[0] = trim($_[0]); # Allow whitespace arround the number my ($id, $skip_authorization) = @_;
detaint_natural($_[0])
|| DisplayError("The bug number is invalid. If you are trying to use " . # Get rid of white-space around the ID.
"QuickSearch, you need to enable JavaScript in your " . $id = trim($id);
"browser. To help us fix this limitation, look " .
"<a href=\"http://bugzilla.mozilla.org/show_bug.cgi?id=70907\">here</a>.") # If the ID isn't a number, it might be an alias, so try to convert it.
&& exit; if ($id !~ /^[1-9][0-9]*$/) {
$id = BugAliasToID($id);
if (!$id) {
my $html_id = html_quote($_[0]);
my $alias_specific_message = Param("usebugaliases") ?
" (it is neither a bug number nor an alias to a bug number)" : "";
DisplayError(qq|
The bug number <em>$html_id</em> is invalid$alias_specific_message.
If you are trying to use QuickSearch, you need to enable JavaScript
in your browser. To help us fix this limitation, add your comments
to <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=70907">bug
70907</a>.
|);
exit;
}
}
my ($id) = @_; # Modify the calling code's original variable to contain the trimmed,
# converted-from-alias ID.
$_[0] = $id;
# Get the values of the usergroupset and userid global variables # Get the values of the usergroupset and userid global variables
# and write them to local variables for use within this function, # and write them to local variables for use within this function,
...@@ -276,6 +309,8 @@ sub ValidateBugID { ...@@ -276,6 +309,8 @@ sub ValidateBugID {
|| DisplayError("Bug #$id does not exist.") || DisplayError("Bug #$id does not exist.")
&& exit; && exit;
return if $skip_authorization;
return if CanSeeBug($id, $::userid, $::usergroupset); return if CanSeeBug($id, $::userid, $::usergroupset);
# The user did not pass any of the authorization tests, which means they # The user did not pass any of the authorization tests, which means they
......
...@@ -77,7 +77,7 @@ sub show_bug { ...@@ -77,7 +77,7 @@ sub show_bug {
# Populate the bug hash with the info we get directly from the DB. # Populate the bug hash with the info we get directly from the DB.
my $query = " my $query = "
SELECT bugs.bug_id, product, version, rep_platform, SELECT bugs.bug_id, alias, product, version, rep_platform,
op_sys, bug_status, resolution, priority, op_sys, bug_status, resolution, priority,
bug_severity, component, assigned_to, reporter, bug_severity, component, assigned_to, reporter,
bug_file_loc, short_desc, target_milestone, bug_file_loc, short_desc, target_milestone,
...@@ -92,7 +92,7 @@ sub show_bug { ...@@ -92,7 +92,7 @@ sub show_bug {
my $value; my $value;
my @row = FetchSQLData(); my @row = FetchSQLData();
foreach my $field ("bug_id", "product", "version", "rep_platform", foreach my $field ("bug_id", "alias", "product", "version", "rep_platform",
"op_sys", "bug_status", "resolution", "priority", "op_sys", "bug_status", "resolution", "priority",
"bug_severity", "component", "assigned_to", "reporter", "bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone", "bug_file_loc", "short_desc", "target_milestone",
......
...@@ -5,11 +5,12 @@ ...@@ -5,11 +5,12 @@
maintainer CDATA #REQUIRED maintainer CDATA #REQUIRED
exporter CDATA #IMPLIED exporter CDATA #IMPLIED
> >
<!ELEMENT bug (bug_id, (bug_status, product, priority, version, rep_platform, assigned_to, delta_ts, component, reporter, target_milestone?, bug_severity, creation_ts, qa_contact?, op_sys, resolution?, bug_file_loc?, short_desc?, keywords*, status_whiteboard?, dependson*, blocks*, cc*, long_desc*, attachment*)?)> <!ELEMENT bug (bug_id, (alias?, bug_status, product, priority, version, rep_platform, assigned_to, delta_ts, component, reporter, target_milestone?, bug_severity, creation_ts, qa_contact?, op_sys, resolution?, bug_file_loc?, short_desc?, keywords*, status_whiteboard?, dependson*, blocks*, cc*, long_desc*, attachment*)?)>
<!ATTLIST bug <!ATTLIST bug
error (NotFound | NotPermitted | InvalidBugId) #IMPLIED error (NotFound | NotPermitted | InvalidBugId) #IMPLIED
> >
<!ELEMENT bug_id (#PCDATA)> <!ELEMENT bug_id (#PCDATA)>
<!ELEMENT alias (#PCDATA)>
<!ELEMENT exporter (#PCDATA)> <!ELEMENT exporter (#PCDATA)>
<!ELEMENT urlbase (#PCDATA)> <!ELEMENT urlbase (#PCDATA)>
<!ELEMENT bug_status (#PCDATA)> <!ELEMENT bug_status (#PCDATA)>
......
...@@ -1134,7 +1134,7 @@ my $drh = DBI->install_driver($db_base) ...@@ -1134,7 +1134,7 @@ my $drh = DBI->install_driver($db_base)
if ($my_db_check) { if ($my_db_check) {
# Do we have the database itself? # Do we have the database itself?
my $sql_want = "3.22.5"; # minimum version of MySQL my $sql_want = "3.23.6"; # minimum version of MySQL
# original DSN line was: # original DSN line was:
# my $dsn = "DBI:$db_base:$my_db_name;$my_db_host;$my_db_port"; # my $dsn = "DBI:$db_base:$my_db_name;$my_db_host;$my_db_port";
...@@ -1332,6 +1332,7 @@ $table{bugs} = ...@@ -1332,6 +1332,7 @@ $table{bugs} =
everconfirmed tinyint not null, everconfirmed tinyint not null,
reporter_accessible tinyint not null default 1, reporter_accessible tinyint not null default 1,
cclist_accessible tinyint not null default 1, cclist_accessible tinyint not null default 1,
alias varchar(20),
index (assigned_to), index (assigned_to),
index (creation_ts), index (creation_ts),
...@@ -1347,7 +1348,9 @@ $table{bugs} = ...@@ -1347,7 +1348,9 @@ $table{bugs} =
index (resolution), index (resolution),
index (target_milestone), index (target_milestone),
index (qa_contact), index (qa_contact),
index (votes)'; index (votes),
unique(alias)';
$table{cc} = $table{cc} =
...@@ -1564,6 +1567,30 @@ $table{tokens} = ...@@ -1564,6 +1567,30 @@ $table{tokens} =
# Create tables # Create tables
########################################################################### ###########################################################################
# Figure out if any existing tables are of type ISAM and convert them
# to type MyISAM if so. ISAM tables are deprecated in MySQL 3.23,
# which Bugzilla now requires, and they don't support more than 16
# indexes per table, which Bugzilla needs.
my $sth = $dbh->prepare("SHOW TABLE STATUS FROM $::db_name");
$sth->execute;
my @isam_tables = ();
while (my ($name, $type) = $sth->fetchrow_array) {
push(@isam_tables, $name) if $type eq "ISAM";
}
if(scalar(@isam_tables)) {
print "One or more of the tables in your existing MySQL database are of type ISAM.\n" .
"ISAM tables are deprecated in MySQL 3.23 and don't support more than 16 indexes\n" .
"per table, which Bugzilla needs. Converting your ISAM tables to type MyISAM:\n\n";
foreach my $table (@isam_tables) {
print "Converting table $table... ";
$dbh->do("ALTER TABLE $table TYPE = MYISAM");
print "done.\n";
}
print "\nISAM->MyISAM table conversion done.\n\n";
}
# Get a list of the existing tables (if any) in the database # Get a list of the existing tables (if any) in the database
my @tables = map { $_ =~ s/.*\.//; $_ } $dbh->tables; my @tables = map { $_ =~ s/.*\.//; $_ } $dbh->tables;
#print 'Tables: ', join " ", @tables, "\n"; #print 'Tables: ', join " ", @tables, "\n";
...@@ -1592,10 +1619,6 @@ while (my ($tabname, $fielddef) = each %table) { ...@@ -1592,10 +1619,6 @@ while (my ($tabname, $fielddef) = each %table) {
or die "Could not create table '$tabname'. Please check your '$db_base' access.\n"; or die "Could not create table '$tabname'. Please check your '$db_base' access.\n";
} }
########################################################################### ###########################################################################
# Populate groups table # Populate groups table
########################################################################### ###########################################################################
...@@ -1733,6 +1756,7 @@ AddFDef("delta_ts", "Last changed date", 0); ...@@ -1733,6 +1756,7 @@ AddFDef("delta_ts", "Last changed date", 0);
AddFDef("(to_days(now()) - to_days(bugs.delta_ts))", "Days since bug changed", AddFDef("(to_days(now()) - to_days(bugs.delta_ts))", "Days since bug changed",
0); 0);
AddFDef("longdesc", "Comment", 0); AddFDef("longdesc", "Comment", 0);
AddFDef("alias", "Alias", 0);
...@@ -1861,7 +1885,7 @@ sub bailout { # this is just in case we get interrupted while getting passwd ...@@ -1861,7 +1885,7 @@ sub bailout { # this is just in case we get interrupted while getting passwd
exit 1; exit 1;
} }
my $sth = $dbh->prepare(<<_End_Of_SQL_); $sth = $dbh->prepare(<<_End_Of_SQL_);
SELECT login_name SELECT login_name
FROM profiles FROM profiles
WHERE groupset=9223372036854775807 WHERE groupset=9223372036854775807
...@@ -2955,6 +2979,14 @@ if (GetFieldDef("logincookies", "hostname")) { ...@@ -2955,6 +2979,14 @@ if (GetFieldDef("logincookies", "hostname")) {
AddField("logincookies", "ipaddr", "varchar(40) NOT NULL"); AddField("logincookies", "ipaddr", "varchar(40) NOT NULL");
} }
# 2002-07-03 myk@mozilla.org bug99203:
# Add a bug alias field to the bugs table so bugs can be referenced by alias
# in addition to ID.
if (!GetFieldDef("bugs", "alias")) {
AddField("bugs", "alias", "VARCHAR(20)");
$dbh->do("ALTER TABLE bugs ADD UNIQUE (alias)");
}
# If you had to change the --TABLE-- definition in any way, then add your # If you had to change the --TABLE-- definition in any way, then add your
# differential change code *** A B O V E *** this comment. # differential change code *** A B O V E *** this comment.
# #
......
...@@ -400,6 +400,12 @@ DefParam("usedependencies", ...@@ -400,6 +400,12 @@ DefParam("usedependencies",
"b", "b",
1); 1);
DefParam("usebugaliases",
"Do you wish to use bug aliases, which allow you to assign bugs
an easy-to-remember name by which you can refer to them?",
"b",
0);
DefParam("webdotbase", DefParam("webdotbase",
"It is possible to show graphs of dependent bugs. You may set this parameter to "It is possible to show graphs of dependent bugs. You may set this parameter to
any of the following: any of the following:
......
...@@ -101,6 +101,24 @@ if (defined $::FORM{'dup_id'} && $::FORM{'knob'} eq "duplicate") { ...@@ -101,6 +101,24 @@ if (defined $::FORM{'dup_id'} && $::FORM{'knob'} eq "duplicate") {
ValidateComment($::FORM{'comment'}); ValidateComment($::FORM{'comment'});
# If the bug(s) being modified have dependencies, validate them
# and rebuild the list with the validated values. This is important
# because there are situations where validation changes the value
# instead of throwing an error, f.e. when one or more of the values
# is a bug alias that gets converted to its corresponding bug ID
# during validation.
foreach my $field ("dependson", "blocked") {
if (defined($::FORM{$field}) && $::FORM{$field} ne "") {
my @validvalues;
foreach my $id (split(/[\s,]+/, $::FORM{$field})) {
next unless $id;
ValidateBugID($id, 1);
push(@validvalues, $id);
}
$::FORM{$field} = join(",", @validvalues);
}
}
###################################################################### ######################################################################
# End Data/Security Validation # End Data/Security Validation
###################################################################### ######################################################################
...@@ -497,6 +515,63 @@ foreach my $field ("rep_platform", "priority", "bug_severity", ...@@ -497,6 +515,63 @@ foreach my $field ("rep_platform", "priority", "bug_severity",
} }
} }
# If this installation uses bug aliases, and the user is changing the alias,
# add this change to the query.
if (Param("usebugaliases") && defined($::FORM{'alias'})) {
my $alias = trim($::FORM{'alias'});
# Since aliases are unique (like bug numbers), they can only be changed
# for one bug at a time, so ignore the alias change unless only a single
# bug is being changed.
if (scalar(@idlist) == 1) {
# Validate the alias if the user entered one.
if ($alias ne "") {
# Make sure the alias isn't too long.
if (length($alias) > 20) {
ThrowUserError("Bug aliases cannot be longer than 20 characters.
Please choose a shorter alias.");
}
# Make sure the alias is unique.
my $escaped_alias = SqlQuote($alias);
SendSQL("SELECT bug_id FROM bugs WHERE alias = $escaped_alias " .
"AND bug_id != $idlist[0]");
my $id = FetchOneColumn();
if ($id) {
my $escaped_alias = html_quote($alias);
my $bug_link = GetBugLink($id, "Bug $id");
ThrowUserError("$bug_link has already taken the alias
<em>$escaped_alias</em>. Please choose another one.");
}
# Make sure the alias isn't just a number.
if ($alias =~ /^\d+$/) {
ThrowUserError("You gave this bug the alias <em>$alias</em>,
but aliases cannot be merely numbers, since they could
then be confused with bug IDs. Please choose another
alias containing at least one letter.");
}
# Make sure the alias has no commas or spaces.
if ($alias =~ /[, ]/) {
my $escaped_alias = html_quote($alias);
ThrowUserError("The alias you entered, <em>$escaped_alias</em>,
contains one or more commas or spaces. Aliases cannot contain
commas or spaces because those characters are used to separate
aliases from each other in lists. Please choose another alias
that does not contain commas and spaces.");
}
}
# Add the alias change to the query. If the field contains the blank
# value, make the field be NULL to indicate that the bug has no alias.
# Otherwise, if the field contains a value, update the record
# with that value.
DoComma();
$::query .= "alias = ";
$::query .= ($alias eq "") ? "NULL" : SqlQuote($alias);
}
}
if (defined $::FORM{'qa_contact'}) { if (defined $::FORM{'qa_contact'}) {
my $name = trim($::FORM{'qa_contact'}); my $name = trim($::FORM{'qa_contact'});
...@@ -909,23 +984,8 @@ foreach my $id (@idlist) { ...@@ -909,23 +984,8 @@ foreach my $id (@idlist) {
$deptree{$target} = []; $deptree{$target} = [];
my %seen; my %seen;
foreach my $i (split('[\s,]+', $::FORM{$target})) { foreach my $i (split('[\s,]+', $::FORM{$target})) {
if ($i eq "") { next if $i eq "";
next;
}
my $orig = $i;
if (!detaint_natural($i)) {
ThrowUserError("$orig is not a legal bug number", undef, "abort");
}
# Don't use CanSeeBug, since we want to keep deps to bugs a
# user can't see
SendSQL("select bug_id from bugs where bug_id = " .
SqlQuote($i));
my $comp = FetchOneColumn();
if ($comp ne $i) {
ThrowUserError("$i is not a legal bug number", undef, "abort");
}
if ($id eq $i) { if ($id eq $i) {
ThrowUserError("You can't make a bug blocked or dependent on itself.", ThrowUserError("You can't make a bug blocked or dependent on itself.",
undef, undef,
......
...@@ -49,6 +49,12 @@ ...@@ -49,6 +49,12 @@
<td> <td>
<a href="[% Param('urlbase') %]show_bug.cgi?id=[% bug.bug_id %]"> <a href="[% Param('urlbase') %]show_bug.cgi?id=[% bug.bug_id %]">
[% bug.bug_id %]</a> [% bug.bug_id %]</a>
[% IF Param("usebugaliases") %]
<label title="a name for the bug that can be used in place of its ID number, f.e. when adding it to a list of dependencies">
<b>alias:</b>
<input name="alias" value="[% bug.alias FILTER html %]" size="20" maxlength="20">
</label>
[% END %]
</td> </td>
<td>&nbsp;</td> <td>&nbsp;</td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment