use CGI::Carp qw(fatalsToBrowser);
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
reporter bug_file_loc short_desc target_milestone
qa_contact status_whiteboard creation_ts groupset
my $self = shift();
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;
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->{'error'} = "InvalidBugId";
return $self;
my $query = "
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,
bug_file_loc, short_desc, target_milestone, qa_contact,
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
if (@row = &::FetchSQLData()) {
my $count = 0;
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",
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
$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",
"component", "reporter", "target_milestone", "bug_severity",
"creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc",
use CGI::Carp qw(fatalsToBrowser);
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
reporter bug_file_loc short_desc target_milestone
qa_contact status_whiteboard creation_ts groupset
my $self = shift();
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;
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->{'error'} = "InvalidBugId";
return $self;
my $query = "
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,
bug_file_loc, short_desc, target_milestone, qa_contact,
status_whiteboard, date_format(creation_ts,'%Y-%m-%d %H:%i'),
if (@row = &::FetchSQLData()) {
my $count = 0;
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",
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
$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",
"component", "reporter", "target_milestone", "bug_severity",
"creation_ts", "qa_contact", "op_sys", "resolution", "bug_file_loc",
}
}
+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 {
# Validates and verifies a bug ID, making sure the number is a
# positive integer, that it represents an existing bug in the
# database, and that the user is authorized to access that bug.
# We detaint the number here, too
- $_[0] = trim($_[0]); # Allow whitespace arround the number
- detaint_natural($_[0])
- || DisplayError("The bug number is invalid. If you are trying to use " .
- "QuickSearch, you need to enable JavaScript in your " .
- "browser. To help us fix this limitation, look " .
- "<a href=\"http://bugzilla.mozilla.org/show_bug.cgi?id=70907\">here</a>.")
- && exit;
-
- my ($id) = @_;
-
+ my ($id, $skip_authorization) = @_;
+
+ # Get rid of white-space around the ID.
+ $id = trim($id);
+
+ # If the ID isn't a number, it might be an alias, so try to convert it.
+ 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;
+ }
+ }
+
+ # 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
# and write them to local variables for use within this function,
# setting those local variables to the default value of zero if
|| DisplayError("Bug #$id does not exist.")
&& exit;
+ return if $skip_authorization;
+
return if CanSeeBug($id, $::userid, $::usergroupset);
# The user did not pass any of the authorization tests, which means they
# Populate the bug hash with the info we get directly from the DB.
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,
bug_severity, component, assigned_to, reporter,
bug_file_loc, short_desc, target_milestone,
my $value;
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",
"bug_severity", "component", "assigned_to", "reporter",
"bug_file_loc", "short_desc", "target_milestone",
maintainer CDATA #REQUIRED
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
error (NotFound | NotPermitted | InvalidBugId) #IMPLIED
>
<!ELEMENT bug_id (#PCDATA)>
+<!ELEMENT alias (#PCDATA)>
<!ELEMENT exporter (#PCDATA)>
<!ELEMENT urlbase (#PCDATA)>
<!ELEMENT bug_status (#PCDATA)>
if ($my_db_check) {
# 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:
# my $dsn = "DBI:$db_base:$my_db_name;$my_db_host;$my_db_port";
everconfirmed tinyint not null,
reporter_accessible tinyint not null default 1,
cclist_accessible tinyint not null default 1,
-
+ alias varchar(20),
+
index (assigned_to),
index (creation_ts),
index (delta_ts),
index (resolution),
index (target_milestone),
index (qa_contact),
- index (votes)';
+ index (votes),
+
+ unique(alias)';
$table{cc} =
# 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
my @tables = map { $_ =~ s/.*\.//; $_ } $dbh->tables;
#print 'Tables: ', join " ", @tables, "\n";
or die "Could not create table '$tabname'. Please check your '$db_base' access.\n";
}
-
-
-
-
###########################################################################
# Populate groups table
###########################################################################
AddFDef("(to_days(now()) - to_days(bugs.delta_ts))", "Days since bug changed",
0);
AddFDef("longdesc", "Comment", 0);
+AddFDef("alias", "Alias", 0);
exit 1;
}
-my $sth = $dbh->prepare(<<_End_Of_SQL_);
+$sth = $dbh->prepare(<<_End_Of_SQL_);
SELECT login_name
FROM profiles
WHERE groupset=9223372036854775807
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
# differential change code *** A B O V E *** this comment.
#
"b",
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",
"It is possible to show graphs of dependent bugs. You may set this parameter to
any of the following:
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
######################################################################
}
}
+# 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'}) {
my $name = trim($::FORM{'qa_contact'});
$deptree{$target} = [];
my %seen;
foreach my $i (split('[\s,]+', $::FORM{$target})) {
- 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");
- }
+ next if $i eq "";
+
if ($id eq $i) {
ThrowUserError("You can't make a bug blocked or dependent on itself.",
undef,
<td>
<a href="[% Param('urlbase') %]show_bug.cgi?id=[% bug.bug_id %]">
[% 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>