Commit 424b21e3 authored by Simon Green's avatar Simon Green

Bug 1012506 - Allow a bug to have multiple aliases

r=dkl, a=sgreen
parent 6dbcec07
...@@ -49,7 +49,7 @@ use parent qw(Bugzilla::Object Exporter); ...@@ -49,7 +49,7 @@ use parent qw(Bugzilla::Object Exporter);
use constant DB_TABLE => 'bugs'; use constant DB_TABLE => 'bugs';
use constant ID_FIELD => 'bug_id'; use constant ID_FIELD => 'bug_id';
use constant NAME_FIELD => 'alias'; use constant NAME_FIELD => 'bug_id';
use constant LIST_ORDER => ID_FIELD; use constant LIST_ORDER => ID_FIELD;
# Bugs have their own auditing table, bugs_activity. # Bugs have their own auditing table, bugs_activity.
use constant AUDIT_CREATES => 0; use constant AUDIT_CREATES => 0;
...@@ -65,7 +65,6 @@ sub DB_COLUMNS { ...@@ -65,7 +65,6 @@ sub DB_COLUMNS {
my @custom_names = map {$_->name} @custom; my @custom_names = map {$_->name} @custom;
my @columns = (qw( my @columns = (qw(
alias
assigned_to assigned_to
bug_file_loc bug_file_loc
bug_id bug_id
...@@ -208,7 +207,6 @@ sub UPDATE_COLUMNS { ...@@ -208,7 +207,6 @@ sub UPDATE_COLUMNS {
Bugzilla->active_custom_fields; Bugzilla->active_custom_fields;
my @custom_names = map {$_->name} @custom; my @custom_names = map {$_->name} @custom;
my @columns = qw( my @columns = qw(
alias
assigned_to assigned_to
bug_file_loc bug_file_loc
bug_severity bug_severity
...@@ -318,7 +316,16 @@ sub new { ...@@ -318,7 +316,16 @@ sub new {
|| (ref($param) && $param->{id} =~ /\D/)) || (ref($param) && $param->{id} =~ /\D/))
{ {
if ($param) { if ($param) {
$param = { name => ref($param) ? $param->{id} : $param, my $alias = ref($param) ? $param->{id} : $param;
my $bug_id = bug_alias_to_id($alias);
if (! $bug_id) {
my $error_self = {};
bless $error_self, $class;
$error_self->{'bug_id'} = $alias;
$error_self->{'error'} = 'InvalidBugId';
return $error_self;
}
$param = { id => $bug_id,
cache => ref($param) ? $param->{cache} : 0 }; cache => ref($param) ? $param->{cache} : 0 };
} }
else { else {
...@@ -690,6 +697,7 @@ sub create { ...@@ -690,6 +697,7 @@ sub create {
# These are not a fields in the bugs table, so we don't pass them to # These are not a fields in the bugs table, so we don't pass them to
# insert_create_data. # insert_create_data.
my $bug_aliases = delete $params->{alias};
my $cc_ids = delete $params->{cc}; my $cc_ids = delete $params->{cc};
my $groups = delete $params->{groups}; my $groups = delete $params->{groups};
my $depends_on = delete $params->{dependson}; my $depends_on = delete $params->{dependson};
...@@ -788,6 +796,13 @@ sub create { ...@@ -788,6 +796,13 @@ sub create {
# but sometimes it's blank. # but sometimes it's blank.
Bugzilla::Comment->insert_create_data($creation_comment); Bugzilla::Comment->insert_create_data($creation_comment);
# Set up aliases
my $sth_aliases = $dbh->prepare('INSERT INTO bugs_aliases (alias, bug_id) VALUES (?, ?)');
foreach my $alias (@$bug_aliases) {
trick_taint($alias);
$sth_aliases->execute($alias, $bug->bug_id);
}
Bugzilla::Hook::process('bug_end_of_create', { bug => $bug, Bugzilla::Hook::process('bug_end_of_create', { bug => $bug,
timestamp => $timestamp, timestamp => $timestamp,
}); });
...@@ -907,7 +922,26 @@ sub update { ...@@ -907,7 +922,26 @@ sub update {
my $added_names = join(', ', (map {$_->login} @$added_users)); my $added_names = join(', ', (map {$_->login} @$added_users));
$changes->{cc} = [$removed_names, $added_names]; $changes->{cc} = [$removed_names, $added_names];
} }
# Aliases
my $old_aliases = $old_bug->alias;
my $new_aliases = $self->alias;
my ($removed_aliases, $added_aliases) = diff_arrays($old_aliases, $new_aliases);
foreach my $alias (@$removed_aliases) {
$dbh->do('DELETE FROM bugs_aliases WHERE bug_id = ? AND alias = ?',
undef, $self->id, $alias);
}
foreach my $alias (@$added_aliases) {
trick_taint($alias);
$dbh->do('INSERT INTO bugs_aliases (bug_id, alias) VALUES (?,?)',
undef, $self->id, $alias);
}
# If any changes were found, record it in the activity log
if (scalar @$removed_aliases || scalar @$added_aliases) {
$changes->{alias} = [join(', ', @$removed_aliases), join(', ', @$added_aliases)];
}
# Keywords # Keywords
my @old_kw_ids = map { $_->id } @{$old_bug->keyword_objects}; my @old_kw_ids = map { $_->id } @{$old_bug->keyword_objects};
my @new_kw_ids = map { $_->id } @{$self->keyword_objects}; my @new_kw_ids = map { $_->id } @{$self->keyword_objects};
...@@ -1311,32 +1345,38 @@ sub _send_bugmail { ...@@ -1311,32 +1345,38 @@ sub _send_bugmail {
##################################################################### #####################################################################
sub _check_alias { sub _check_alias {
my ($invocant, $alias) = @_; my ($invocant, $aliases) = @_;
$alias = trim($alias); $aliases = ref $aliases ? $aliases : [split(/[\s,]+/, $aliases)];
return undef if (!$alias);
# Remove empty aliases
# Make sure the alias isn't too long. @$aliases = grep { $_ } @$aliases;
if (length($alias) > 20) {
ThrowUserError("alias_too_long"); foreach my $alias (@$aliases) {
} $alias = trim($alias);
# Make sure the alias isn't just a number.
if ($alias =~ /^\d+$/) { # Make sure the alias isn't too long.
ThrowUserError("alias_is_numeric", { alias => $alias }); if (length($alias) > 40) {
} ThrowUserError("alias_too_long");
# Make sure the alias has no commas or spaces. }
if ($alias =~ /[, ]/) { # Make sure the alias isn't just a number.
ThrowUserError("alias_has_comma_or_space", { alias => $alias }); if ($alias =~ /^\d+$/) {
} ThrowUserError("alias_is_numeric", { alias => $alias });
# Make sure the alias is unique, or that it's already our alias. }
my $other_bug = new Bugzilla::Bug($alias); # Make sure the alias has no commas or spaces.
if (!$other_bug->{error} if ($alias =~ /[, ]/) {
&& (!ref $invocant || $other_bug->id != $invocant->id)) ThrowUserError("alias_has_comma_or_space", { alias => $alias });
{ }
ThrowUserError("alias_in_use", { alias => $alias, # Make sure the alias is unique, or that it's already our alias.
bug_id => $other_bug->id }); my $other_bug = new Bugzilla::Bug($alias);
if (!$other_bug->{error}
&& (!ref $invocant || $other_bug->id != $invocant->id))
{
ThrowUserError("alias_in_use", { alias => $alias,
bug_id => $other_bug->id });
}
} }
return $alias; return $aliases;
} }
sub _check_assigned_to { sub _check_assigned_to {
...@@ -2376,6 +2416,13 @@ sub set_all { ...@@ -2376,6 +2416,13 @@ sub set_all {
work_time => $params->{'work_time'} }); work_time => $params->{'work_time'} });
} }
if (exists $params->{alias} && $params->{alias}{set}) {
$params->{alias} = {
add => $params->{alias}{set},
remove => $self->alias,
};
}
my %normal_set_all; my %normal_set_all;
foreach my $name (keys %$params) { foreach my $name (keys %$params) {
# These are handled separately below. # These are handled separately below.
...@@ -2400,6 +2447,7 @@ sub set_all { ...@@ -2400,6 +2447,7 @@ sub set_all {
} }
$self->_add_remove($params, 'cc'); $self->_add_remove($params, 'cc');
$self->_add_remove($params, 'alias');
# Theoretically you could move a product without ever specifying # Theoretically you could move a product without ever specifying
# a new assignee or qa_contact, or adding/removing any CCs. So, # a new assignee or qa_contact, or adding/removing any CCs. So,
...@@ -2416,14 +2464,13 @@ sub _add_remove { ...@@ -2416,14 +2464,13 @@ sub _add_remove {
my ($self, $params, $name) = @_; my ($self, $params, $name) = @_;
my @add = @{ $params->{$name}->{add} || [] }; my @add = @{ $params->{$name}->{add} || [] };
my @remove = @{ $params->{$name}->{remove} || [] }; my @remove = @{ $params->{$name}->{remove} || [] };
$name =~ s/s$//; $name =~ s/s$// if $name ne 'alias';
my $add_method = "add_$name"; my $add_method = "add_$name";
my $remove_method = "remove_$name"; my $remove_method = "remove_$name";
$self->$add_method($_) foreach @add; $self->$add_method($_) foreach @add;
$self->$remove_method($_) foreach @remove; $self->$remove_method($_) foreach @remove;
} }
sub set_alias { $_[0]->set('alias', $_[1]); }
sub set_assigned_to { sub set_assigned_to {
my ($self, $value) = @_; my ($self, $value) = @_;
$self->set('assigned_to', $value); $self->set('assigned_to', $value);
...@@ -2840,6 +2887,21 @@ sub remove_cc { ...@@ -2840,6 +2887,21 @@ sub remove_cc {
@$cc_users = grep { $_->id != $user->id } @$cc_users; @$cc_users = grep { $_->id != $user->id } @$cc_users;
} }
sub add_alias {
my ($self, $alias) = @_;
return if !$alias;
my $aliases = $self->_check_alias($alias);
$alias = $aliases->[0];
my $bug_aliases = $self->alias;
push(@$bug_aliases, $alias) if !grep($_ eq $alias, @$bug_aliases);
}
sub remove_alias {
my ($self, $alias) = @_;
my $bug_aliases = $self->alias;
@$bug_aliases = grep { $_ ne $alias } @$bug_aliases;
}
# $bug->add_comment("comment", {isprivate => 1, work_time => 10.5, # $bug->add_comment("comment", {isprivate => 1, work_time => 10.5,
# type => CMT_NORMAL, extra_data => $data}); # type => CMT_NORMAL, extra_data => $data});
sub add_comment { sub add_comment {
...@@ -3167,7 +3229,6 @@ sub tags { ...@@ -3167,7 +3229,6 @@ sub tags {
# These are accessors that don't need to access the database. # These are accessors that don't need to access the database.
# Keep them in alphabetical order. # Keep them in alphabetical order.
sub alias { return $_[0]->{alias} }
sub bug_file_loc { return $_[0]->{bug_file_loc} } sub bug_file_loc { return $_[0]->{bug_file_loc} }
sub bug_id { return $_[0]->{bug_id} } sub bug_id { return $_[0]->{bug_id} }
sub bug_severity { return $_[0]->{bug_severity} } sub bug_severity { return $_[0]->{bug_severity} }
...@@ -3277,6 +3338,24 @@ sub actual_time { ...@@ -3277,6 +3338,24 @@ sub actual_time {
return $self->{'actual_time'}; return $self->{'actual_time'};
} }
sub alias {
my ($self) = @_;
return $self->{'alias'} if exists $self->{'alias'};
return [] if $self->{'error'};
my $dbh = Bugzilla->dbh;
$self->{'alias'} = $dbh->selectcol_arrayref(
q{SELECT alias
FROM bugs_aliases
WHERE bug_id = ?
ORDER BY alias},
undef, $self->bug_id);
$self->{'alias'} = [] if !scalar(@{$self->{'alias'}});
return $self->{'alias'};
}
sub any_flags_requesteeble { sub any_flags_requesteeble {
my ($self) = @_; my ($self) = @_;
return $self->{'any_flags_requesteeble'} return $self->{'any_flags_requesteeble'}
...@@ -3868,7 +3947,7 @@ sub bug_alias_to_id { ...@@ -3868,7 +3947,7 @@ sub bug_alias_to_id {
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
trick_taint($alias); trick_taint($alias);
return $dbh->selectrow_array( return $dbh->selectrow_array(
"SELECT bug_id FROM bugs WHERE alias = ?", undef, $alias); "SELECT bug_id FROM bugs_aliases WHERE alias = ?", undef, $alias);
} }
##################################################################### #####################################################################
...@@ -4497,6 +4576,16 @@ __END__ ...@@ -4497,6 +4576,16 @@ __END__
Ensures the accessors for custom fields are always created. Ensures the accessors for custom fields are always created.
=item C<add_alias($alias)>
Adds an alias to the internal respresentation of the bug. You will need to
call L<update> to make the changes permanent.
=item C<remove_alias($alias)>
Removes an alias from the internal respresentation of the bug. You will need to
call L<update> to make the changes permanent.
=item C<update_user_last_visit($user, $last_visit)> =item C<update_user_last_visit($user, $last_visit)>
Creates or updates a L<Bugzilla::BugUserLastVisit> for this bug and the supplied Creates or updates a L<Bugzilla::BugUserLastVisit> for this bug and the supplied
...@@ -4664,8 +4753,6 @@ $user, the timestamp given as $last_visit. ...@@ -4664,8 +4753,6 @@ $user, the timestamp given as $last_visit.
=item remove_group =item remove_group
=item set_alias
=item set_dup_id =item set_dup_id
=item set_target_milestone =item set_target_milestone
......
...@@ -278,11 +278,8 @@ use constant ABSTRACT_SCHEMA => { ...@@ -278,11 +278,8 @@ use constant ABSTRACT_SCHEMA => {
remaining_time => {TYPE => 'decimal(7,2)', remaining_time => {TYPE => 'decimal(7,2)',
NOTNULL => 1, DEFAULT => '0'}, NOTNULL => 1, DEFAULT => '0'},
deadline => {TYPE => 'DATETIME'}, deadline => {TYPE => 'DATETIME'},
alias => {TYPE => 'varchar(20)'},
], ],
INDEXES => [ INDEXES => [
bugs_alias_idx => {FIELDS => ['alias'],
TYPE => 'UNIQUE'},
bugs_assigned_to_idx => ['assigned_to'], bugs_assigned_to_idx => ['assigned_to'],
bugs_creation_ts_idx => ['creation_ts'], bugs_creation_ts_idx => ['creation_ts'],
bugs_delta_ts_idx => ['delta_ts'], bugs_delta_ts_idx => ['delta_ts'],
...@@ -359,6 +356,21 @@ use constant ABSTRACT_SCHEMA => { ...@@ -359,6 +356,21 @@ use constant ABSTRACT_SCHEMA => {
], ],
}, },
bugs_aliases => {
FIELDS => [
alias => {TYPE => 'varchar(40)', NOTNULL => 1},
bug_id => {TYPE => 'INT3',
REFERENCES => {TABLE => 'bugs',
COLUMN => 'bug_id',
DELETE => 'CASCADE'}},
],
INDEXES => [
bugs_aliases_bug_id_idx => ['bug_id'],
bugs_aliases_alias_idx => {FIELDS => ['alias'],
TYPE => 'UNIQUE'},
],
},
cc => { cc => {
FIELDS => [ FIELDS => [
bug_id => {TYPE => 'INT3', NOTNULL => 1, bug_id => {TYPE => 'INT3', NOTNULL => 1,
......
...@@ -727,6 +727,9 @@ sub update_table_definitions { ...@@ -727,6 +727,9 @@ sub update_table_definitions {
# 2014-07-27 LpSolit@gmail.com - Bug 1044561 # 2014-07-27 LpSolit@gmail.com - Bug 1044561
_fix_user_api_keys_indexes(); _fix_user_api_keys_indexes();
# 2014-08-11 sgreen@redhat.com - Bug 1012506
_update_alias();
################################################################ ################################################################
# New --TABLE-- changes should go *** A B O V E *** this point # # New --TABLE-- changes should go *** A B O V E *** this point #
################################################################ ################################################################
...@@ -3899,6 +3902,19 @@ sub _fix_user_api_keys_indexes { ...@@ -3899,6 +3902,19 @@ sub _fix_user_api_keys_indexes {
} }
} }
sub _update_alias {
my $dbh = Bugzilla->dbh;
return unless $dbh->bz_column_info('bugs', 'alias');
# We need to move the aliases from the bugs table to the bugs_aliases table
$dbh->do(q{
INSERT INTO bugs_aliases (bug_id, alias)
SELECT bug_id, alias FROM bugs WHERE alias IS NOT NULL
});
$dbh->bz_drop_column('bugs', 'alias');
}
1; 1;
__END__ __END__
......
...@@ -265,7 +265,7 @@ use constant OPERATOR_FIELD_OVERRIDE => { ...@@ -265,7 +265,7 @@ use constant OPERATOR_FIELD_OVERRIDE => {
}, },
# General Bug Fields # General Bug Fields
alias => { _non_changed => \&_nullable }, alias => { _non_changed => \&_alias_nonchanged },
'attach_data.thedata' => MULTI_SELECT_OVERRIDE, 'attach_data.thedata' => MULTI_SELECT_OVERRIDE,
# We check all attachment fields against this. # We check all attachment fields against this.
attachments => MULTI_SELECT_OVERRIDE, attachments => MULTI_SELECT_OVERRIDE,
...@@ -456,6 +456,10 @@ sub COLUMN_JOINS { ...@@ -456,6 +456,10 @@ sub COLUMN_JOINS {
. ' FROM longdescs GROUP BY bug_id)', . ' FROM longdescs GROUP BY bug_id)',
join => 'INNER', join => 'INNER',
}, },
alias => {
table => 'bugs_aliases',
as => 'map_alias',
},
assigned_to => { assigned_to => {
from => 'assigned_to', from => 'assigned_to',
to => 'userid', to => 'userid',
...@@ -586,6 +590,7 @@ sub COLUMNS { ...@@ -586,6 +590,7 @@ sub COLUMNS {
# like "bugs.bug_id". # like "bugs.bug_id".
my $total_time = "(map_actual_time.total + bugs.remaining_time)"; my $total_time = "(map_actual_time.total + bugs.remaining_time)";
my %special_sql = ( my %special_sql = (
alias => $dbh->sql_group_concat('DISTINCT map_alias.alias'),
deadline => $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d'), deadline => $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d'),
actual_time => 'map_actual_time.total', actual_time => 'map_actual_time.total',
...@@ -2727,6 +2732,15 @@ sub _product_nonchanged { ...@@ -2727,6 +2732,15 @@ sub _product_nonchanged {
"products.id", "products", $term); "products.id", "products", $term);
} }
sub _alias_nonchanged {
my ($self, $args) = @_;
$args->{full_field} = "bugs_aliases.alias";
$self->_do_operator_function($args);
$args->{term} = build_subselect("bugs.bug_id",
"bugs_aliases.bug_id", "bugs_aliases", $args->{term});
}
sub _classification_nonchanged { sub _classification_nonchanged {
my ($self, $args) = @_; my ($self, $args) = @_;
my $joins = $args->{joins}; my $joins = $args->{joins};
......
...@@ -322,7 +322,7 @@ sub _handle_alias { ...@@ -322,7 +322,7 @@ sub _handle_alias {
my $alias = $1; my $alias = $1;
# We use this direct SQL because we want quicksearch to be VERY fast. # We use this direct SQL because we want quicksearch to be VERY fast.
my $bug_id = Bugzilla->dbh->selectrow_array( my $bug_id = Bugzilla->dbh->selectrow_array(
q{SELECT bug_id FROM bugs WHERE alias = ?}, undef, $alias); q{SELECT bug_id FROM bugs_aliases WHERE alias = ?}, undef, $alias);
# If the user cannot see the bug or if we are using a webservice, # If the user cannot see the bug or if we are using a webservice,
# do not resolve its alias. # do not resolve its alias.
if ($bug_id && Bugzilla->user->can_see_bug($bug_id) && !i_am_webservice()) { if ($bug_id && Bugzilla->user->can_see_bug($bug_id) && !i_am_webservice()) {
......
...@@ -468,7 +468,7 @@ sub history { ...@@ -468,7 +468,7 @@ sub history {
# alias is returned in case users passes a mixture of ids and aliases # alias is returned in case users passes a mixture of ids and aliases
# then they get to know which bug activity relates to which value # then they get to know which bug activity relates to which value
# they passed # they passed
$item{alias} = $self->type('string', $bug->alias); $item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
push(@return, \%item); push(@return, \%item);
} }
...@@ -632,6 +632,16 @@ sub update { ...@@ -632,6 +632,16 @@ sub update {
# called using those field names. # called using those field names.
delete $values{dependencies}; delete $values{dependencies};
# For backwards compatibility, treat alias string or array as a set action
if (exists $values{alias}) {
if (not ref $values{alias}) {
$values{alias} = { set => [ $values{alias} ] };
}
elsif (ref $values{alias} eq 'ARRAY') {
$values{alias} = { set => $values{alias} };
}
}
my $flags = delete $values{flags}; my $flags = delete $values{flags};
foreach my $bug (@bugs) { foreach my $bug (@bugs) {
...@@ -669,7 +679,7 @@ sub update { ...@@ -669,7 +679,7 @@ sub update {
# alias is returned in case users pass a mixture of ids and aliases, # alias is returned in case users pass a mixture of ids and aliases,
# so that they can know which set of changes relates to which value # so that they can know which set of changes relates to which value
# they passed. # they passed.
$hash{alias} = $self->type('string', $bug->alias); $hash{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
my %changes = %{ $all_changes{$bug->id} }; my %changes = %{ $all_changes{$bug->id} };
foreach my $field (keys %changes) { foreach my $field (keys %changes) {
...@@ -1163,7 +1173,6 @@ sub _bug_to_hash { ...@@ -1163,7 +1173,6 @@ sub _bug_to_hash {
# A bug attribute is "basic" if it doesn't require an additional # A bug attribute is "basic" if it doesn't require an additional
# database call to get the info. # database call to get the info.
my %item = %{ filter $params, { my %item = %{ filter $params, {
alias => $self->type('string', $bug->alias),
creation_time => $self->type('dateTime', $bug->creation_ts), creation_time => $self->type('dateTime', $bug->creation_ts),
# No need to format $bug->deadline specially, because Bugzilla::Bug # No need to format $bug->deadline specially, because Bugzilla::Bug
# already does it for us. # already does it for us.
...@@ -1187,6 +1196,9 @@ sub _bug_to_hash { ...@@ -1187,6 +1196,9 @@ sub _bug_to_hash {
# First we handle any fields that require extra SQL calls. # First we handle any fields that require extra SQL calls.
# We don't do the SQL calls at all if the filter would just # We don't do the SQL calls at all if the filter would just
# eliminate them anyway. # eliminate them anyway.
if (filter_wants $params, 'alias') {
$item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
}
if (filter_wants $params, 'assigned_to') { if (filter_wants $params, 'assigned_to') {
$item{'assigned_to'} = $self->type('email', $bug->assigned_to->login); $item{'assigned_to'} = $self->type('email', $bug->assigned_to->login);
$item{'assigned_to_detail'} = $self->_user_to_hash($bug->assigned_to, $params, undef, 'assigned_to'); $item{'assigned_to_detail'} = $self->_user_to_hash($bug->assigned_to, $params, undef, 'assigned_to');
...@@ -2168,7 +2180,8 @@ in the return value. ...@@ -2168,7 +2180,8 @@ in the return value.
=item C<alias> =item C<alias>
C<string> The unique alias of this bug. C<array> of C<string>s The unique aliases of this bug. An empty array will be
returned if this bug has no aliases.
=item C<assigned_to> =item C<assigned_to>
...@@ -2613,7 +2626,8 @@ C<int> The numeric id of the bug. ...@@ -2613,7 +2626,8 @@ C<int> The numeric id of the bug.
=item alias =item alias
C<string> The alias of this bug. If there is no alias, this will be undef. C<array> of C<string>s The unique aliases of this bug. An empty array will be
returned if this bug has no aliases.
=item history =item history
...@@ -2796,7 +2810,8 @@ just reuse the query parameter portion in the REST call itself. ...@@ -2796,7 +2810,8 @@ just reuse the query parameter portion in the REST call itself.
=item C<alias> =item C<alias>
C<string> The unique alias for this bug. C<array> of C<string>s The unique aliases of this bug. An empty array will be
returned if this bug has no aliases.
=item C<assigned_to> =item C<assigned_to>
...@@ -3053,7 +3068,7 @@ in by the developer, compared to the developer's other bugs. ...@@ -3053,7 +3068,7 @@ in by the developer, compared to the developer's other bugs.
=item C<severity> (string) B<Defaulted> - How severe the bug is. =item C<severity> (string) B<Defaulted> - How severe the bug is.
=item C<alias> (string) - A brief alias for the bug that can be used =item C<alias> (array) - A brief alias for the bug that can be used
instead of a bug number when accessing this bug. Must be unique in instead of a bug number when accessing this bug. Must be unique in
all of this Bugzilla. all of this Bugzilla.
...@@ -3754,9 +3769,29 @@ bugs you are updating. ...@@ -3754,9 +3769,29 @@ bugs you are updating.
=item C<alias> =item C<alias>
(string) The alias of the bug. You can only set this if you are modifying C<hash> These specify the aliases of a bug that can be used instead of a bug
a single bug. If there is more than one bug specified in C<ids>, passing in number when acessing this bug. To set these, you should pass a hash as the
a value for C<alias> will cause an error to be thrown. value. The hash may contain the following fields:
=over
=item C<add> An array of C<string>s. Aliases to add to this field.
=item C<remove> An array of C<string>s. Aliases to remove from this field.
If the aliases are not already in the field, they will be ignored.
=item C<set> An array of C<string>s. An exact set of aliases to set this
field to, overriding the current value. If you specify C<set>, then C<add>
and C<remove> will be ignored.
=back
You can only set this if you are modifying a single bug. If there is more
than one bug specified in C<ids>, passing in a value for C<alias> will cause
an error to be thrown.
For backwards compatibility, you can also specify a single string. This will
be treated as if you specified the set key above.
=item C<assigned_to> =item C<assigned_to>
...@@ -4075,7 +4110,8 @@ C<int> The id of the bug that was updated. ...@@ -4075,7 +4110,8 @@ C<int> The id of the bug that was updated.
=item C<alias> =item C<alias>
C<string> The alias of the bug that was updated, if this bug has an alias. C<array> of C<string>s The aliases of the bug that was updated, if this bug
has any alias.
=item C<last_change_time> =item C<last_change_time>
...@@ -4109,7 +4145,7 @@ Here's an example of what a return value might look like: ...@@ -4109,7 +4145,7 @@ Here's an example of what a return value might look like:
bugs => [ bugs => [
{ {
id => 123, id => 123,
alias => 'foo', alias => [ 'foo' ],
last_change_time => '2010-01-01T12:34:56', last_change_time => '2010-01-01T12:34:56',
changes => { changes => {
status => { status => {
......
...@@ -295,7 +295,7 @@ function checkForChangedFieldValues(e, ContainerInputArray ) { ...@@ -295,7 +295,7 @@ function checkForChangedFieldValues(e, ContainerInputArray ) {
if ( el ) { if ( el ) {
if ( !ContainerInputArray[4] if ( !ContainerInputArray[4]
&& (el.value != ContainerInputArray[3] && (el.value != ContainerInputArray[3]
|| (el.value == "" && el.id != "alias" && el.id != "qa_contact")) ) || (el.value == "" && el.id != "qa_contact")) )
{ {
unhide = true; unhide = true;
} }
...@@ -316,17 +316,6 @@ function checkForChangedFieldValues(e, ContainerInputArray ) { ...@@ -316,17 +316,6 @@ function checkForChangedFieldValues(e, ContainerInputArray ) {
} }
function hideAliasAndSummary(short_desc_value, alias_value) {
// check the short desc field
hideEditableField( 'summary_alias_container','summary_alias_input',
'editme_action','short_desc', short_desc_value);
// check that the alias hasn't changed
var bz_alias_check_array = new Array('summary_alias_container',
'summary_alias_input', 'alias', alias_value);
YAHOO.util.Event.addListener( window, 'load', checkForChangedFieldValues,
bz_alias_check_array);
}
function showPeopleOnChange( field_id_list ) { function showPeopleOnChange( field_id_list ) {
for(var i = 0; i < field_id_list.length; i++) { for(var i = 0; i < field_id_list.length; i++) {
YAHOO.util.Event.addListener( field_id_list[i],'change', showEditableField, YAHOO.util.Event.addListener( field_id_list[i],'change', showEditableField,
......
...@@ -289,8 +289,17 @@ if (defined $cgi->param('newcc') ...@@ -289,8 +289,17 @@ if (defined $cgi->param('newcc')
if (defined $cgi->param('id')) { if (defined $cgi->param('id')) {
# Since aliases are unique (like bug numbers), they can only be changed # Since aliases are unique (like bug numbers), they can only be changed
# for one bug at a time. # for one bug at a time.
if (defined $cgi->param('alias')) { if (defined $cgi->param('newalias') || defined $cgi->param('removealias')) {
$set_all_fields{alias} = $cgi->param('alias'); my @alias_add = split /[, ]+/, $cgi->param('newalias');
# We came from bug_form which uses a select box to determine what
# aliases need to be removed...
my @alias_remove = ();
if ($cgi->param('removealias') && $cgi->param('alias')) {
@alias_remove = $cgi->param('alias');
}
$set_all_fields{alias} = { add => \@alias_add, remove => \@alias_remove };
} }
} }
......
...@@ -114,7 +114,7 @@ table#attachment_flags th, table#attachment_flags td { ...@@ -114,7 +114,7 @@ table#attachment_flags th, table#attachment_flags td {
/* show_bug.cgi (start) */ /* show_bug.cgi (start) */
.bz_alias_short_desc_container { .bz_short_desc_container {
margin: 8px 0; margin: 8px 0;
padding: 0.3em; padding: 0.3em;
background-color: rgb(208, 208, 208); background-color: rgb(208, 208, 208);
...@@ -231,7 +231,7 @@ table#flags { ...@@ -231,7 +231,7 @@ table#flags {
.text_input, .bz_userfield, #keywords_container, #tag_container { .text_input, .bz_userfield, #keywords_container, #tag_container {
width: 100%; width: 100%;
} }
.bz_bug .bz_alias_short_desc_container { .bz_bug .bz_short_desc_container {
width: inherit; width: inherit;
} }
......
...@@ -66,9 +66,13 @@ ...@@ -66,9 +66,13 @@
<table> <table>
[%# *** ID, product, component, status, resolution, Hardware, and OS *** %] [%# *** ID, product, component, status, resolution, Hardware, and OS *** %]
[% PROCESS section_status %] [% PROCESS section_status %]
[% PROCESS section_spacer %] [% PROCESS section_spacer %]
[% PROCESS section_aliases %]
[% PROCESS section_spacer %]
[% PROCESS section_details1 %] [% PROCESS section_details1 %]
[% PROCESS section_spacer %] [% PROCESS section_spacer %]
...@@ -173,61 +177,37 @@ ...@@ -173,61 +177,37 @@
[% BLOCK section_title %] [% BLOCK section_title %]
[%# That's the main table, which contains all editable fields. %] [%# That's the main table, which contains all editable fields. %]
<div class="bz_alias_short_desc_container edit_form"> <div class="bz_short_desc_container edit_form">
[% PROCESS commit_button id="_top"%] [% PROCESS commit_button id="_top"%]
<a href="show_bug.cgi?id=[% bug.bug_id %]"> <a href="show_bug.cgi?id=[% bug.bug_id %]">
[%-# %]<b>[% terms.Bug %]&nbsp;[% bug.bug_id FILTER html %]</b> [%-# %]<b>[% terms.Bug %]&nbsp;[% bug.bug_id FILTER html %]</b>
[%-# %]</a> <span id="summary_alias_container" class="bz_default_hidden"> [%-# %]</a> <span id="summary_container" class="bz_default_hidden">
[% IF bug.alias != "" %] [% IF bug.alias.size > 0 %]
(<span id="alias_nonedit_display">[% bug.alias FILTER html %]</span>) (<span id="alias_nonedit_display">[% bug.alias.join(', ') FILTER html %]</span>)
[% END %] [% END %]
- <span id="short_desc_nonedit_display">[% bug.short_desc FILTER quoteUrls(bug) %]</span> - <span id="short_desc_nonedit_display">[% bug.short_desc FILTER quoteUrls(bug) %]</span>
[% IF bug.check_can_change_field('short_desc', 0, 1) || [% IF bug.check_can_change_field('short_desc', 0, 1) %]
bug.check_can_change_field('alias', 0, 1) %] <small>(<a href="#" id="summary_edit_action">edit</a>)</small>
<small class="editme">(<a href="#" id="editme_action">edit</a>)</small>
[% END %] [% END %]
</span> </span>
<div id="summary_input">
<div id="summary_alias_input"> [% INCLUDE "bug/field-label.html.tmpl"
<table id="summary"> field = bug_fields.short_desc
<tr> editable = 1
[% IF bug.check_can_change_field('alias', 0, 1) %] accesskey = "s"
[% INCLUDE "bug/field-label.html.tmpl" tag_name = 'span'
field = bug_fields.alias %]
editable = 1 [% PROCESS input inputname => "short_desc" size => "80"
%] maxlength => 255 spellcheck => "true" no_td => 1 %]
<td>
[% ELSIF bug.alias %]
<td colspan="2">(
[% ELSE %]
<td colspan="2">
[% END %]
[% PROCESS input inputname => "alias"
size => "20"
maxlength => "20"
no_td => 1
%][% ")" IF NOT bug.check_can_change_field('alias', 0, 1)
&& bug.alias %]
</td>
</tr>
[%# *** Summary *** %]
<tr>
[% INCLUDE "bug/field-label.html.tmpl"
field = bug_fields.short_desc
editable = 1
accesskey = "s"
%]
<td>
[% PROCESS input inputname => "short_desc" size => "80" colspan => 2
maxlength => 255 spellcheck => "true" no_td => 1 %]
</td>
</tr>
</table>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
hideAliasAndSummary('[% bug.short_desc FILTER js %]', '[% bug.alias FILTER js %]'); hideEditableField('summary_container',
'summary_input',
'summary_edit_action',
'short_desc',
'[% bug.short_desc FILTER js %]' );
</script> </script>
[% END %] [% END %]
...@@ -867,6 +847,56 @@ ...@@ -867,6 +847,56 @@
[% END %] [% END %]
[% END %] [% END %]
[% BLOCK section_aliases %]
<tr>
[% INCLUDE "bug/field-label.html.tmpl"
field = bug_fields.alias, editable = 1
%]
<td>
[% IF bug.alias.size %]
[% bug.alias.join(', ') FILTER html %]
[% ELSE %]
None
[% END %]
[% IF bug.check_can_change_field('alias', 0, 1) %]
<span id="alias_edit_area_showhide_container" class="bz_default_hidden">
(<a href="#" id="alias_edit_area_showhide">edit</a>)
</span>
<br>
<div id="alias_edit_area">
<div>
<div>
<label for="aliases">
<b>Add</b>
</label>
</div>
<input name="newalias" id="newalias" size="20">
</div>
[% IF bug.alias.size %]
<select id="alias" name="alias" multiple="multiple" size="5">
[% FOREACH a = bug.alias %]
<option value="[% a FILTER html %]">[% a FILTER html %]</option>
[% END %]
</select>
<br>
<input type="checkbox" id="removealias" name="removealias">
<label for="removealias">Remove selected aliases</label>
[% END %]
</div>
<script type="text/javascript">
hideEditableField( 'alias_edit_area_showhide_container',
'alias_edit_area',
'alias_edit_area_showhide',
'',
'');
</script>
[% END %]
</td>
</tr>
[% END %]
[%############################################################################%] [%############################################################################%]
[%# Block for FLAGS #%] [%# Block for FLAGS #%]
[%############################################################################%] [%############################################################################%]
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
# be overridden by the calling templates. # be overridden by the calling templates.
#%] #%]
[% filtered_alias = bug.alias FILTER html %] [% filtered_alias = bug.alias.join(', ') FILTER html %]
[% filtered_desc = bug.short_desc FILTER html %] [% filtered_desc = bug.short_desc FILTER html %]
[% filtered_timestamp = bug.delta_ts FILTER time %] [% filtered_timestamp = bug.delta_ts FILTER time %]
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
[% header_addl_info = "Last modified: $filtered_timestamp" %] [% header_addl_info = "Last modified: $filtered_timestamp" %]
[% unfiltered_title = "$bug.bug_id – " %] [% unfiltered_title = "$bug.bug_id – " %]
[% IF bug.alias != '' %] [% IF bug.alias != '' %]
[% unfiltered_title = unfiltered_title _ "($bug.alias) " %] [% unfiltered_title = unfiltered_title _ "(" _ bug.alias.join(', ') _ ") " %]
[% END %] [% END %]
[% unfiltered_title = unfiltered_title _ bug.short_desc %] [% unfiltered_title = unfiltered_title _ bug.short_desc %]
[% javascript = BLOCK %] [% javascript = BLOCK %]
......
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