diff options
Diffstat (limited to 'Bugzilla/Component.pm')
-rw-r--r-- | Bugzilla/Component.pm | 540 |
1 files changed, 279 insertions, 261 deletions
diff --git a/Bugzilla/Component.pm b/Bugzilla/Component.pm index d5a6ece5d..ef8180eb0 100644 --- a/Bugzilla/Component.pm +++ b/Bugzilla/Component.pm @@ -27,150 +27,147 @@ use Scalar::Util qw(blessed); ############################### use constant DB_TABLE => 'components'; + # This is mostly for the editfields.cgi case where ->get_all is called. use constant LIST_ORDER => 'product_id, name'; use constant DB_COLUMNS => qw( - id - name - product_id - initialowner - initialqacontact - description - isactive + id + name + product_id + initialowner + initialqacontact + description + isactive ); use constant UPDATE_COLUMNS => qw( - name - initialowner - initialqacontact - description - isactive + name + initialowner + initialqacontact + description + isactive ); -use constant REQUIRED_FIELD_MAP => { - product_id => 'product', -}; +use constant REQUIRED_FIELD_MAP => {product_id => 'product',}; use constant VALIDATORS => { - create_series => \&Bugzilla::Object::check_boolean, - product => \&_check_product, - initialowner => \&_check_initialowner, - initialqacontact => \&_check_initialqacontact, - description => \&_check_description, - initial_cc => \&_check_cc_list, - name => \&_check_name, - isactive => \&Bugzilla::Object::check_boolean, + create_series => \&Bugzilla::Object::check_boolean, + product => \&_check_product, + initialowner => \&_check_initialowner, + initialqacontact => \&_check_initialqacontact, + description => \&_check_description, + initial_cc => \&_check_cc_list, + name => \&_check_name, + isactive => \&Bugzilla::Object::check_boolean, }; -use constant VALIDATOR_DEPENDENCIES => { - name => ['product'], -}; +use constant VALIDATOR_DEPENDENCIES => {name => ['product'],}; ############################### sub new { - my $class = shift; - my $param = shift; - my $dbh = Bugzilla->dbh; - - my $product; - if (ref $param and !defined $param->{id}) { - $product = $param->{product}; - my $name = $param->{name}; - if (!defined $product) { - ThrowCodeError('bad_arg', - {argument => 'product', - function => "${class}::new"}); - } - if (!defined $name) { - ThrowCodeError('bad_arg', - {argument => 'name', - function => "${class}::new"}); - } - - my $condition = 'product_id = ? AND name = ?'; - my @values = ($product->id, $name); - $param = { condition => $condition, values => \@values }; + my $class = shift; + my $param = shift; + my $dbh = Bugzilla->dbh; + + my $product; + if (ref $param and !defined $param->{id}) { + $product = $param->{product}; + my $name = $param->{name}; + if (!defined $product) { + ThrowCodeError('bad_arg', {argument => 'product', function => "${class}::new"}); } + if (!defined $name) { + ThrowCodeError('bad_arg', {argument => 'name', function => "${class}::new"}); + } + + my $condition = 'product_id = ? AND name = ?'; + my @values = ($product->id, $name); + $param = {condition => $condition, values => \@values}; + } - unshift @_, $param; - my $component = $class->SUPER::new(@_); - # Add the product object as attribute only if the component exists. - $component->{product} = $product if ($component && $product); - return $component; + unshift @_, $param; + my $component = $class->SUPER::new(@_); + + # Add the product object as attribute only if the component exists. + $component->{product} = $product if ($component && $product); + return $component; } sub create { - my $class = shift; - my $dbh = Bugzilla->dbh; + my $class = shift; + my $dbh = Bugzilla->dbh; - $dbh->bz_start_transaction(); + $dbh->bz_start_transaction(); - $class->check_required_create_fields(@_); - my $params = $class->run_create_validators(@_); - my $cc_list = delete $params->{initial_cc}; - my $create_series = delete $params->{create_series}; - my $product = delete $params->{product}; - $params->{product_id} = $product->id; + $class->check_required_create_fields(@_); + my $params = $class->run_create_validators(@_); + my $cc_list = delete $params->{initial_cc}; + my $create_series = delete $params->{create_series}; + my $product = delete $params->{product}; + $params->{product_id} = $product->id; - my $component = $class->insert_create_data($params); - $component->{product} = $product; + my $component = $class->insert_create_data($params); + $component->{product} = $product; - # We still have to fill the component_cc table. - $component->_update_cc_list($cc_list) if $cc_list; + # We still have to fill the component_cc table. + $component->_update_cc_list($cc_list) if $cc_list; - # Create series for the new component. - $component->_create_series() if $create_series; + # Create series for the new component. + $component->_create_series() if $create_series; - $dbh->bz_commit_transaction(); - return $component; + $dbh->bz_commit_transaction(); + return $component; } sub update { - my $self = shift; - my $changes = $self->SUPER::update(@_); - - # Update the component_cc table if necessary. - if (defined $self->{cc_ids}) { - my $diff = $self->_update_cc_list($self->{cc_ids}); - $changes->{cc_list} = $diff if defined $diff; - } - return $changes; + my $self = shift; + my $changes = $self->SUPER::update(@_); + + # Update the component_cc table if necessary. + if (defined $self->{cc_ids}) { + my $diff = $self->_update_cc_list($self->{cc_ids}); + $changes->{cc_list} = $diff if defined $diff; + } + return $changes; } sub remove_from_db { - my $self = shift; - my $dbh = Bugzilla->dbh; + my $self = shift; + my $dbh = Bugzilla->dbh; - $self->_check_if_controller(); # From ChoiceInterface + $self->_check_if_controller(); # From ChoiceInterface - $dbh->bz_start_transaction(); + $dbh->bz_start_transaction(); - # Products must have at least one component. - my @components = @{ $self->product->components }; - if (scalar(@components) == 1) { - ThrowUserError('component_is_last', { comp => $self }); - } + # Products must have at least one component. + my @components = @{$self->product->components}; + if (scalar(@components) == 1) { + ThrowUserError('component_is_last', {comp => $self}); + } + + if ($self->bug_count) { + if (Bugzilla->params->{'allowbugdeletion'}) { + require Bugzilla::Bug; + foreach my $bug_id (@{$self->bug_ids}) { - if ($self->bug_count) { - if (Bugzilla->params->{'allowbugdeletion'}) { - require Bugzilla::Bug; - foreach my $bug_id (@{$self->bug_ids}) { - # Note: We allow admins to delete bugs even if they can't - # see them, as long as they can see the product. - my $bug = new Bugzilla::Bug($bug_id); - $bug->remove_from_db(); - } - } else { - ThrowUserError('component_has_bugs', {nb => $self->bug_count}); - } + # Note: We allow admins to delete bugs even if they can't + # see them, as long as they can see the product. + my $bug = new Bugzilla::Bug($bug_id); + $bug->remove_from_db(); + } } - # Update the list of components in the product object. - $self->product->{components} = [grep { $_->id != $self->id } @components]; - $self->SUPER::remove_from_db(); + else { + ThrowUserError('component_has_bugs', {nb => $self->bug_count}); + } + } + + # Update the list of components in the product object. + $self->product->{components} = [grep { $_->id != $self->id } @components]; + $self->SUPER::remove_from_db(); - $dbh->bz_commit_transaction(); + $dbh->bz_commit_transaction(); } ################################ @@ -178,69 +175,70 @@ sub remove_from_db { ################################ sub _check_name { - my ($invocant, $name, undef, $params) = @_; - my $product = blessed($invocant) ? $invocant->product : $params->{product}; - - $name = trim($name); - $name || ThrowUserError('component_blank_name'); - - if (length($name) > MAX_COMPONENT_SIZE) { - ThrowUserError('component_name_too_long', {'name' => $name}); - } - - my $component = new Bugzilla::Component({product => $product, name => $name}); - if ($component && (!ref $invocant || $component->id != $invocant->id)) { - ThrowUserError('component_already_exists', { name => $component->name, - product => $product }); - } - return $name; + my ($invocant, $name, undef, $params) = @_; + my $product = blessed($invocant) ? $invocant->product : $params->{product}; + + $name = trim($name); + $name || ThrowUserError('component_blank_name'); + + if (length($name) > MAX_COMPONENT_SIZE) { + ThrowUserError('component_name_too_long', {'name' => $name}); + } + + my $component = new Bugzilla::Component({product => $product, name => $name}); + if ($component && (!ref $invocant || $component->id != $invocant->id)) { + ThrowUserError('component_already_exists', + {name => $component->name, product => $product}); + } + return $name; } sub _check_description { - my ($invocant, $description) = @_; + my ($invocant, $description) = @_; - $description = trim($description); - $description || ThrowUserError('component_blank_description'); - return $description; + $description = trim($description); + $description || ThrowUserError('component_blank_description'); + return $description; } sub _check_initialowner { - my ($invocant, $owner) = @_; + my ($invocant, $owner) = @_; - $owner || ThrowUserError('component_need_initialowner'); - my $owner_id = Bugzilla::User->check($owner)->id; - return $owner_id; + $owner || ThrowUserError('component_need_initialowner'); + my $owner_id = Bugzilla::User->check($owner)->id; + return $owner_id; } sub _check_initialqacontact { - my ($invocant, $qa_contact) = @_; - - my $qa_contact_id; - if (Bugzilla->params->{'useqacontact'}) { - $qa_contact_id = Bugzilla::User->check($qa_contact)->id if $qa_contact; - } - elsif (ref $invocant) { - $qa_contact_id = $invocant->{initialqacontact}; - } - return $qa_contact_id; + my ($invocant, $qa_contact) = @_; + + my $qa_contact_id; + if (Bugzilla->params->{'useqacontact'}) { + $qa_contact_id = Bugzilla::User->check($qa_contact)->id if $qa_contact; + } + elsif (ref $invocant) { + $qa_contact_id = $invocant->{initialqacontact}; + } + return $qa_contact_id; } sub _check_product { - my ($invocant, $product) = @_; - $product || ThrowCodeError('param_required', - { function => "$invocant->create", param => 'product' }); - return Bugzilla->user->check_can_admin_product($product->name); + my ($invocant, $product) = @_; + $product + || ThrowCodeError('param_required', + {function => "$invocant->create", param => 'product'}); + return Bugzilla->user->check_can_admin_product($product->name); } sub _check_cc_list { - my ($invocant, $cc_list) = @_; - - my %cc_ids; - foreach my $cc (@$cc_list) { - my $id = login_to_id($cc, THROW_ERROR); - $cc_ids{$id} = 1; - } - return [keys %cc_ids]; + my ($invocant, $cc_list) = @_; + + my %cc_ids; + foreach my $cc (@$cc_list) { + my $id = login_to_id($cc, THROW_ERROR); + $cc_ids{$id} = 1; + } + return [keys %cc_ids]; } ############################### @@ -248,156 +246,176 @@ sub _check_cc_list { ############################### sub _update_cc_list { - my ($self, $cc_list) = @_; - my $dbh = Bugzilla->dbh; + my ($self, $cc_list) = @_; + my $dbh = Bugzilla->dbh; - my $old_cc_list = - $dbh->selectcol_arrayref('SELECT user_id FROM component_cc - WHERE component_id = ?', undef, $self->id); + my $old_cc_list = $dbh->selectcol_arrayref( + 'SELECT user_id FROM component_cc + WHERE component_id = ?', undef, $self->id + ); - my ($removed, $added) = diff_arrays($old_cc_list, $cc_list); - my $diff; - if (scalar @$removed || scalar @$added) { - $diff = [join(', ', @$removed), join(', ', @$added)]; - } + my ($removed, $added) = diff_arrays($old_cc_list, $cc_list); + my $diff; + if (scalar @$removed || scalar @$added) { + $diff = [join(', ', @$removed), join(', ', @$added)]; + } - $dbh->do('DELETE FROM component_cc WHERE component_id = ?', undef, $self->id); + $dbh->do('DELETE FROM component_cc WHERE component_id = ?', undef, $self->id); - my $sth = $dbh->prepare('INSERT INTO component_cc - (user_id, component_id) VALUES (?, ?)'); - $sth->execute($_, $self->id) foreach (@$cc_list); + my $sth = $dbh->prepare( + 'INSERT INTO component_cc + (user_id, component_id) VALUES (?, ?)' + ); + $sth->execute($_, $self->id) foreach (@$cc_list); - return $diff; + return $diff; } sub _create_series { - my $self = shift; - - # Insert default charting queries for this product. - # If they aren't using charting, this won't do any harm. - my $prodcomp = "&product=" . url_quote($self->product->name) . - "&component=" . url_quote($self->name); - - my $open_query = 'field0-0-0=resolution&type0-0-0=notregexp&value0-0-0=.' . - $prodcomp; - my $nonopen_query = 'field0-0-0=resolution&type0-0-0=regexp&value0-0-0=.' . - $prodcomp; - - my @series = ([get_text('series_all_open'), $open_query], - [get_text('series_all_closed'), $nonopen_query]); - - foreach my $sdata (@series) { - my $series = new Bugzilla::Series(undef, $self->product->name, - $self->name, $sdata->[0], - Bugzilla->user->id, 1, $sdata->[1], 1); - $series->writeToDatabase(); - } + my $self = shift; + + # Insert default charting queries for this product. + # If they aren't using charting, this won't do any harm. + my $prodcomp + = "&product=" + . url_quote($self->product->name) + . "&component=" + . url_quote($self->name); + + my $open_query + = 'field0-0-0=resolution&type0-0-0=notregexp&value0-0-0=.' . $prodcomp; + my $nonopen_query + = 'field0-0-0=resolution&type0-0-0=regexp&value0-0-0=.' . $prodcomp; + + my @series = ( + [get_text('series_all_open'), $open_query], + [get_text('series_all_closed'), $nonopen_query] + ); + + foreach my $sdata (@series) { + my $series + = new Bugzilla::Series(undef, $self->product->name, $self->name, $sdata->[0], + Bugzilla->user->id, 1, $sdata->[1], 1); + $series->writeToDatabase(); + } } -sub set_name { $_[0]->set('name', $_[1]); } +sub set_name { $_[0]->set('name', $_[1]); } sub set_description { $_[0]->set('description', $_[1]); } -sub set_is_active { $_[0]->set('isactive', $_[1]); } +sub set_is_active { $_[0]->set('isactive', $_[1]); } + sub set_default_assignee { - my ($self, $owner) = @_; + my ($self, $owner) = @_; + + $self->set('initialowner', $owner); - $self->set('initialowner', $owner); - # Reset the default owner object. - delete $self->{default_assignee}; + # Reset the default owner object. + delete $self->{default_assignee}; } + sub set_default_qa_contact { - my ($self, $qa_contact) = @_; + my ($self, $qa_contact) = @_; + + $self->set('initialqacontact', $qa_contact); - $self->set('initialqacontact', $qa_contact); - # Reset the default QA contact object. - delete $self->{default_qa_contact}; + # Reset the default QA contact object. + delete $self->{default_qa_contact}; } + sub set_cc_list { - my ($self, $cc_list) = @_; + my ($self, $cc_list) = @_; + + $self->{cc_ids} = $self->_check_cc_list($cc_list); - $self->{cc_ids} = $self->_check_cc_list($cc_list); - # Reset the list of CC user objects. - delete $self->{initial_cc}; + # Reset the list of CC user objects. + delete $self->{initial_cc}; } sub bug_count { - my $self = shift; - my $dbh = Bugzilla->dbh; + my $self = shift; + my $dbh = Bugzilla->dbh; - if (!defined $self->{'bug_count'}) { - $self->{'bug_count'} = $dbh->selectrow_array(q{ + if (!defined $self->{'bug_count'}) { + $self->{'bug_count'} = $dbh->selectrow_array( + q{ SELECT COUNT(*) FROM bugs - WHERE component_id = ?}, undef, $self->id) || 0; - } - return $self->{'bug_count'}; + WHERE component_id = ?}, undef, $self->id + ) || 0; + } + return $self->{'bug_count'}; } sub bug_ids { - my $self = shift; - my $dbh = Bugzilla->dbh; + my $self = shift; + my $dbh = Bugzilla->dbh; - if (!defined $self->{'bugs_ids'}) { - $self->{'bugs_ids'} = $dbh->selectcol_arrayref(q{ + if (!defined $self->{'bugs_ids'}) { + $self->{'bugs_ids'} = $dbh->selectcol_arrayref( + q{ SELECT bug_id FROM bugs - WHERE component_id = ?}, undef, $self->id); - } - return $self->{'bugs_ids'}; + WHERE component_id = ?}, undef, $self->id + ); + } + return $self->{'bugs_ids'}; } sub default_assignee { - my $self = shift; + my $self = shift; - return $self->{'default_assignee'} - ||= new Bugzilla::User({ id => $self->{'initialowner'}, cache => 1 }); + return $self->{'default_assignee'} + ||= new Bugzilla::User({id => $self->{'initialowner'}, cache => 1}); } sub default_qa_contact { - my $self = shift; + my $self = shift; - return unless $self->{'initialqacontact'}; - return $self->{'default_qa_contact'} - ||= new Bugzilla::User({id => $self->{'initialqacontact'}, cache => 1 }); + return unless $self->{'initialqacontact'}; + return $self->{'default_qa_contact'} + ||= new Bugzilla::User({id => $self->{'initialqacontact'}, cache => 1}); } sub flag_types { - my $self = shift; - - if (!defined $self->{'flag_types'}) { - my $flagtypes = Bugzilla::FlagType::match({ product_id => $self->product_id, - component_id => $self->id }); - - $self->{'flag_types'} = {}; - $self->{'flag_types'}->{'bug'} = - [grep { $_->target_type eq 'bug' } @$flagtypes]; - $self->{'flag_types'}->{'attachment'} = - [grep { $_->target_type eq 'attachment' } @$flagtypes]; - } - return $self->{'flag_types'}; + my $self = shift; + + if (!defined $self->{'flag_types'}) { + my $flagtypes = Bugzilla::FlagType::match( + {product_id => $self->product_id, component_id => $self->id}); + + $self->{'flag_types'} = {}; + $self->{'flag_types'}->{'bug'} + = [grep { $_->target_type eq 'bug' } @$flagtypes]; + $self->{'flag_types'}->{'attachment'} + = [grep { $_->target_type eq 'attachment' } @$flagtypes]; + } + return $self->{'flag_types'}; } sub initial_cc { - my $self = shift; - my $dbh = Bugzilla->dbh; - - if (!defined $self->{'initial_cc'}) { - # If set_cc_list() has been called but data are not yet written - # into the DB, we want the new values defined by it. - my $cc_ids = $self->{cc_ids} - || $dbh->selectcol_arrayref('SELECT user_id FROM component_cc - WHERE component_id = ?', - undef, $self->id); - - $self->{'initial_cc'} = Bugzilla::User->new_from_list($cc_ids); - } - return $self->{'initial_cc'}; + my $self = shift; + my $dbh = Bugzilla->dbh; + + if (!defined $self->{'initial_cc'}) { + + # If set_cc_list() has been called but data are not yet written + # into the DB, we want the new values defined by it. + my $cc_ids = $self->{cc_ids} || $dbh->selectcol_arrayref( + 'SELECT user_id FROM component_cc + WHERE component_id = ?', undef, + $self->id + ); + + $self->{'initial_cc'} = Bugzilla::User->new_from_list($cc_ids); + } + return $self->{'initial_cc'}; } sub product { - my $self = shift; - if (!defined $self->{'product'}) { - require Bugzilla::Product; # We cannot |use| it. - $self->{'product'} = new Bugzilla::Product($self->product_id); - } - return $self->{'product'}; + my $self = shift; + if (!defined $self->{'product'}) { + require Bugzilla::Product; # We cannot |use| it. + $self->{'product'} = new Bugzilla::Product($self->product_id); + } + return $self->{'product'}; } ############################### @@ -405,8 +423,8 @@ sub product { ############################### sub description { return $_[0]->{'description'}; } -sub product_id { return $_[0]->{'product_id'}; } -sub is_active { return $_[0]->{'isactive'}; } +sub product_id { return $_[0]->{'product_id'}; } +sub is_active { return $_[0]->{'isactive'}; } ############################################## # Implement Bugzilla::Field::ChoiceInterface # @@ -416,11 +434,11 @@ use constant FIELD_NAME => 'component'; use constant is_default => 0; sub is_set_on_bug { - my ($self, $bug) = @_; - my $value = blessed($bug) ? $bug->component_id : $bug->{component}; - $value = $value->id if blessed($value); - return 0 unless $value; - return $value == $self->id ? 1 : 0; + my ($self, $bug) = @_; + my $value = blessed($bug) ? $bug->component_id : $bug->{component}; + $value = $value->id if blessed($value); + return 0 unless $value; + return $value == $self->id ? 1 : 0; } ############################### |