]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1012506 - Allow a bug to have multiple aliases
authorSimon Green <sgreen@redhat.com>
Wed, 13 Aug 2014 23:40:47 +0000 (09:40 +1000)
committerSimon Green <sgreen@redhat.com>
Wed, 13 Aug 2014 23:40:47 +0000 (09:40 +1000)
r=dkl, a=sgreen

Bugzilla/Bug.pm
Bugzilla/DB/Schema.pm
Bugzilla/Install/DB.pm
Bugzilla/Search.pm
Bugzilla/Search/Quicksearch.pm
Bugzilla/WebService/Bug.pm
js/field.js
process_bug.cgi
skins/standard/bug.css
template/en/default/bug/edit.html.tmpl
template/en/default/bug/show-header.html.tmpl

index c4ddb943c94a3fa26243b9d0b8d7f0541a303789..07266da9cfa6aa3615c483c30ad1209c2757f9e2 100644 (file)
@@ -49,7 +49,7 @@ use parent qw(Bugzilla::Object Exporter);
 
 use constant DB_TABLE   => 'bugs';
 use constant ID_FIELD   => 'bug_id';
-use constant NAME_FIELD => 'alias';
+use constant NAME_FIELD => 'bug_id';
 use constant LIST_ORDER => ID_FIELD;
 # Bugs have their own auditing table, bugs_activity.
 use constant AUDIT_CREATES => 0;
@@ -65,7 +65,6 @@ sub DB_COLUMNS {
     my @custom_names = map {$_->name} @custom;
 
     my @columns = (qw(
-        alias
         assigned_to
         bug_file_loc
         bug_id
@@ -208,7 +207,6 @@ sub UPDATE_COLUMNS {
                       Bugzilla->active_custom_fields;
     my @custom_names = map {$_->name} @custom;
     my @columns = qw(
-        alias
         assigned_to
         bug_file_loc
         bug_severity
@@ -318,7 +316,16 @@ sub new {
         || (ref($param) && $param->{id} =~ /\D/))
     {
         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 };
         }
         else {
@@ -690,6 +697,7 @@ sub create {
 
     # These are not a fields in the bugs table, so we don't pass them to
     # insert_create_data.
+    my $bug_aliases      = delete $params->{alias};
     my $cc_ids           = delete $params->{cc};
     my $groups           = delete $params->{groups};
     my $depends_on       = delete $params->{dependson};
@@ -788,6 +796,13 @@ sub create {
     # but sometimes it's blank.
     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,
                                                    timestamp => $timestamp,
                                                  });
@@ -907,7 +922,26 @@ sub update {
         my $added_names   = join(', ', (map {$_->login} @$added_users));
         $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
     my @old_kw_ids = map { $_->id } @{$old_bug->keyword_objects};
     my @new_kw_ids = map { $_->id } @{$self->keyword_objects};
@@ -1311,32 +1345,38 @@ sub _send_bugmail {
 #####################################################################
 
 sub _check_alias {
-   my ($invocant, $alias) = @_;
-   $alias = trim($alias);
-   return undef if (!$alias);
-
-    # Make sure the alias isn't too long.
-    if (length($alias) > 20) {
-        ThrowUserError("alias_too_long");
-    }
-    # Make sure the alias isn't just a number.
-    if ($alias =~ /^\d+$/) {
-        ThrowUserError("alias_is_numeric", { alias => $alias });
-    }
-    # Make sure the alias has no commas or spaces.
-    if ($alias =~ /[, ]/) {
-        ThrowUserError("alias_has_comma_or_space", { alias => $alias });
-    }
-    # Make sure the alias is unique, or that it's already our alias.
-    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 });
+    my ($invocant, $aliases) = @_;
+    $aliases = ref $aliases ? $aliases : [split(/[\s,]+/, $aliases)];
+
+    # Remove empty aliases
+    @$aliases = grep { $_ } @$aliases;
+
+    foreach my $alias (@$aliases) {
+        $alias = trim($alias);
+
+        # Make sure the alias isn't too long.
+        if (length($alias) > 40) {
+            ThrowUserError("alias_too_long");
+        }
+        # Make sure the alias isn't just a number.
+        if ($alias =~ /^\d+$/) {
+            ThrowUserError("alias_is_numeric", { alias => $alias });
+        }
+        # Make sure the alias has no commas or spaces.
+        if ($alias =~ /[, ]/) {
+            ThrowUserError("alias_has_comma_or_space", { alias => $alias });
+        }
+        # Make sure the alias is unique, or that it's already our alias.
+        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 {
@@ -2376,6 +2416,13 @@ sub set_all {
               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;
     foreach my $name (keys %$params) {
         # These are handled separately below.
@@ -2400,6 +2447,7 @@ sub set_all {
     }
 
     $self->_add_remove($params, 'cc');
+    $self->_add_remove($params, 'alias');
 
     # Theoretically you could move a product without ever specifying
     # a new assignee or qa_contact, or adding/removing any CCs. So,
@@ -2416,14 +2464,13 @@ sub _add_remove {
     my ($self, $params, $name) = @_;
     my @add    = @{ $params->{$name}->{add}    || [] };
     my @remove = @{ $params->{$name}->{remove} || [] };
-    $name =~ s/s$//;
+    $name =~ s/s$// if $name ne 'alias';
     my $add_method = "add_$name";
     my $remove_method = "remove_$name";
     $self->$add_method($_) foreach @add;
     $self->$remove_method($_) foreach @remove;
 }
 
-sub set_alias { $_[0]->set('alias', $_[1]); }
 sub set_assigned_to {
     my ($self, $value) = @_;
     $self->set('assigned_to', $value);
@@ -2840,6 +2887,21 @@ sub remove_cc {
     @$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,
 #                               type => CMT_NORMAL, extra_data => $data});
 sub add_comment {
@@ -3167,7 +3229,6 @@ sub tags {
 # These are accessors that don't need to access the database.
 # Keep them in alphabetical order.
 
-sub alias               { return $_[0]->{alias}               }
 sub bug_file_loc        { return $_[0]->{bug_file_loc}        }
 sub bug_id              { return $_[0]->{bug_id}              }
 sub bug_severity        { return $_[0]->{bug_severity}        }
@@ -3277,6 +3338,24 @@ sub 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 {
     my ($self) = @_;
     return $self->{'any_flags_requesteeble'} 
@@ -3868,7 +3947,7 @@ sub bug_alias_to_id {
     my $dbh = Bugzilla->dbh;
     trick_taint($alias);
     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__
 
 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)>
 
 Creates or updates a L<Bugzilla::BugUserLastVisit> for this bug and the supplied
@@ -4664,8 +4753,6 @@ $user, the timestamp given as $last_visit.
 
 =item remove_group
 
-=item set_alias
-
 =item set_dup_id
 
 =item set_target_milestone
index 8c81f7a5938669e939142d65cdd7f534b01840a4..d1c1dc7e90a3dd24e94e1173792cf399f2ef04f1 100644 (file)
@@ -278,11 +278,8 @@ use constant ABSTRACT_SCHEMA => {
             remaining_time      => {TYPE => 'decimal(7,2)',
                                     NOTNULL => 1, DEFAULT => '0'},
             deadline            => {TYPE => 'DATETIME'},
-            alias               => {TYPE => 'varchar(20)'},
         ],
         INDEXES => [
-            bugs_alias_idx            => {FIELDS => ['alias'],
-                                          TYPE => 'UNIQUE'},
             bugs_assigned_to_idx      => ['assigned_to'],
             bugs_creation_ts_idx      => ['creation_ts'],
             bugs_delta_ts_idx         => ['delta_ts'],
@@ -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 => {
         FIELDS => [
             bug_id => {TYPE => 'INT3', NOTNULL => 1,
index dd0f3608be838236c3debb1cbaae17c7af23d88a..b136e6d83a24339a75b480ed5e8f61299ed453c8 100644 (file)
@@ -727,6 +727,9 @@ sub update_table_definitions {
     # 2014-07-27 LpSolit@gmail.com - Bug 1044561
     _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 #
     ################################################################
@@ -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;
 
 __END__
index 59d7f86ec9f0fbdeab12b1b41cccd104ad33591c..b2e8da0967d445f24630589d93d3b224e6f0e236 100644 (file)
@@ -265,7 +265,7 @@ use constant OPERATOR_FIELD_OVERRIDE => {
     },
 
     # General Bug Fields
-    alias        => { _non_changed => \&_nullable },
+    alias        => { _non_changed => \&_alias_nonchanged },
     'attach_data.thedata' => MULTI_SELECT_OVERRIDE,
     # We check all attachment fields against this.
     attachments  => MULTI_SELECT_OVERRIDE,
@@ -456,6 +456,10 @@ sub COLUMN_JOINS {
                      . ' FROM longdescs GROUP BY bug_id)',
             join  => 'INNER',
         },
+        alias => {
+            table => 'bugs_aliases',
+            as => 'map_alias',
+        },
         assigned_to => {
             from  => 'assigned_to',
             to    => 'userid',
@@ -586,6 +590,7 @@ sub COLUMNS {
     # like "bugs.bug_id".
     my $total_time = "(map_actual_time.total + bugs.remaining_time)";
     my %special_sql = (
+        alias       => $dbh->sql_group_concat('DISTINCT map_alias.alias'),
         deadline    => $dbh->sql_date_format('bugs.deadline', '%Y-%m-%d'),
         actual_time => 'map_actual_time.total',
 
@@ -2727,6 +2732,15 @@ sub _product_nonchanged {
         "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 {
     my ($self, $args) = @_;
     my $joins = $args->{joins};
index c00f1835162dc41006781b0262c527350582392f..830177f8b513bc80a271356702587870608d9a7e 100644 (file)
@@ -322,7 +322,7 @@ sub _handle_alias {
         my $alias = $1;
         # We use this direct SQL because we want quicksearch to be VERY fast.
         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,
         # do not resolve its alias.
         if ($bug_id && Bugzilla->user->can_see_bug($bug_id) && !i_am_webservice()) {
index 4689ae0f28cef0c50198bbd5febe261033441c69..334be105792e0077634440f8b77ce723e6909e74 100644 (file)
@@ -468,7 +468,7 @@ sub history {
         # 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  
         # they passed
-        $item{alias} = $self->type('string', $bug->alias);
+        $item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
 
         push(@return, \%item);
     }
@@ -632,6 +632,16 @@ sub update {
     # called using those field names.
     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};
 
     foreach my $bug (@bugs) {
@@ -669,7 +679,7 @@ sub update {
         # 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
         # they passed.
-        $hash{alias} = $self->type('string', $bug->alias);
+        $hash{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
 
         my %changes = %{ $all_changes{$bug->id} };
         foreach my $field (keys %changes) {
@@ -1163,7 +1173,6 @@ sub _bug_to_hash {
     # A bug attribute is "basic" if it doesn't require an additional
     # database call to get the info.
     my %item = %{ filter $params, {
-        alias            => $self->type('string', $bug->alias),
         creation_time    => $self->type('dateTime', $bug->creation_ts),
         # No need to format $bug->deadline specially, because Bugzilla::Bug
         # already does it for us.
@@ -1187,6 +1196,9 @@ sub _bug_to_hash {
     # First we handle any fields that require extra SQL calls.
     # We don't do the SQL calls at all if the filter would just
     # eliminate them anyway.
+    if (filter_wants $params, 'alias') {
+        $item{alias} = [ map { $self->type('string', $_) } @{ $bug->alias } ];
+    }
     if (filter_wants $params, 'assigned_to') {
         $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');
@@ -2168,7 +2180,8 @@ in the return value.
 
 =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>
 
@@ -2613,7 +2626,8 @@ C<int> The numeric id of the bug.
 
 =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
 
@@ -2796,7 +2810,8 @@ just reuse the query parameter portion in the REST call itself.
 
 =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>
 
@@ -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<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
 all of this Bugzilla.
 
@@ -3754,9 +3769,29 @@ bugs you are updating.
 
 =item C<alias>
 
-(string) The alias of the bug. 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.
+C<hash> These specify the aliases of a bug that can be used instead of a bug
+number when acessing this bug. To set these, you should pass a hash as the
+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>
 
@@ -4075,7 +4110,8 @@ C<int> The id of the bug that was updated.
 
 =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>
 
@@ -4109,7 +4145,7 @@ Here's an example of what a return value might look like:
    bugs => [
      {
        id    => 123,
-       alias => 'foo',
+       alias => [ 'foo' ],
        last_change_time => '2010-01-01T12:34:56',
        changes => {
          status => {
index f865a141fa89c562715a15be0dbba79545813691..7c5c5b64e3a1803d7b23b24259f45854492e07a6 100644 (file)
@@ -295,7 +295,7 @@ function checkForChangedFieldValues(e, ContainerInputArray ) {
     if ( el ) {
         if ( !ContainerInputArray[4]
              && (el.value != ContainerInputArray[3]
-                 || (el.value == "" && el.id != "alias" && el.id != "qa_contact")) )
+                 || (el.value == "" && el.id != "qa_contact")) )
         {
             unhide = true;
         }
@@ -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 ) {
     for(var i = 0; i < field_id_list.length; i++) {
         YAHOO.util.Event.addListener( field_id_list[i],'change', showEditableField,
index bc558682ed2a4c7b1994b9d34f33586118f19a0d..37beee14a5412d47b92328f520d1f9bab184e718 100755 (executable)
@@ -289,8 +289,17 @@ if (defined $cgi->param('newcc')
 if (defined $cgi->param('id')) {
     # Since aliases are unique (like bug numbers), they can only be changed
     # for one bug at a time.
-    if (defined $cgi->param('alias')) {
-        $set_all_fields{alias} = $cgi->param('alias');
+    if (defined $cgi->param('newalias') || defined $cgi->param('removealias')) {
+        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 };
     }
 }
 
index e23475a3596ab1721c8097904f63b0c827fea034..851b1bdbab092210be21b5ceaecd53362c0209e1 100644 (file)
@@ -114,7 +114,7 @@ table#attachment_flags th, table#attachment_flags td {
 
 /* show_bug.cgi (start) */
 
-.bz_alias_short_desc_container {
+.bz_short_desc_container {
     margin: 8px 0;
     padding: 0.3em;
     background-color: rgb(208, 208, 208);
@@ -231,7 +231,7 @@ table#flags {
 .text_input, .bz_userfield, #keywords_container, #tag_container {
     width: 100%;
 }
-.bz_bug .bz_alias_short_desc_container {
+.bz_bug .bz_short_desc_container {
     width: inherit;
 }
 
index 8b55dedcbf74c596acac851fee9cc52cc56f9189..6917a89ecfec240664c194bf2ac4ddba9839fe8a 100644 (file)
         <table>
           [%# *** ID, product, component, status, resolution, Hardware, and  OS *** %]
           [% PROCESS section_status %]
-          
+
           [% PROCESS section_spacer %]
-          
+
+          [% PROCESS section_aliases %]
+
+          [% PROCESS section_spacer %]
+
           [% PROCESS section_details1 %]
           
           [% PROCESS section_spacer %]
 
 [% BLOCK section_title %]
   [%# 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"%]
      <a href="show_bug.cgi?id=[% bug.bug_id %]">
         [%-# %]<b>[% terms.Bug %]&nbsp;[% bug.bug_id FILTER html %]</b>
-     [%-# %]</a> <span id="summary_alias_container" class="bz_default_hidden"> 
-      [% IF bug.alias != "" %]
-        (<span id="alias_nonedit_display">[% bug.alias FILTER html %]</span>) 
+     [%-# %]</a> <span id="summary_container" class="bz_default_hidden">
+      [% IF bug.alias.size > 0 %]
+        (<span id="alias_nonedit_display">[% bug.alias.join(', ') FILTER html %]</span>)
       [% END %]
       - <span id="short_desc_nonedit_display">[% bug.short_desc FILTER quoteUrls(bug) %]</span>
-      [% IF bug.check_can_change_field('short_desc', 0, 1) || 
-            bug.check_can_change_field('alias', 0, 1)  %]
-        <small class="editme">(<a href="#" id="editme_action">edit</a>)</small>
+      [% IF bug.check_can_change_field('short_desc', 0, 1) %]
+        <small>(<a href="#" id="summary_edit_action">edit</a>)</small>
       [% END %]
      </span>
-  
-       
-    <div id="summary_alias_input">
-      <table id="summary"> 
-        <tr>
-          [% IF bug.check_can_change_field('alias', 0, 1) %]      
-            [% INCLUDE "bug/field-label.html.tmpl"
-               field = bug_fields.alias
-               editable = 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 id="summary_input">
+      [% INCLUDE "bug/field-label.html.tmpl"
+        field = bug_fields.short_desc
+        editable = 1
+        accesskey = "s"
+        tag_name = 'span'
+      %]
+      [% PROCESS input inputname => "short_desc" size => "80"
+                       maxlength => 255 spellcheck => "true" no_td => 1 %]
     </div>
   </div>
   <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>
 [% 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                                                          #%]
 [%############################################################################%]
index 6dfc19dfb8bd5ea517be12a33defed23d8bd0411..3b1f2725269a5c9ea76208bc92fa81976cb21b95 100644 (file)
@@ -13,7 +13,7 @@
   # 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_timestamp = bug.delta_ts FILTER time %]
 
@@ -34,7 +34,7 @@
   [% header_addl_info = "Last modified: $filtered_timestamp" %]
   [% unfiltered_title = "$bug.bug_id – " %]
   [% IF bug.alias != '' %]
-    [% unfiltered_title = unfiltered_title _ "($bug.alias) " %]
+    [% unfiltered_title = unfiltered_title _ "(" _ bug.alias.join(', ') _ ") " %]
   [% END %]
   [% unfiltered_title = unfiltered_title _ bug.short_desc %]
   [% javascript =  BLOCK %]