diff options
-rw-r--r-- | Bugzilla/Classification.pm | 193 | ||||
-rw-r--r-- | Bugzilla/Component.pm | 198 | ||||
-rw-r--r-- | Bugzilla/Constants.pm | 5 | ||||
-rw-r--r-- | Bugzilla/Group.pm | 72 | ||||
-rw-r--r-- | Bugzilla/Milestone.pm | 172 | ||||
-rw-r--r-- | Bugzilla/Product.pm | 336 | ||||
-rw-r--r-- | Bugzilla/Version.pm | 170 | ||||
-rw-r--r-- | template/en/default/global/code-error.html.tmpl | 5 |
8 files changed, 1137 insertions, 14 deletions
diff --git a/Bugzilla/Classification.pm b/Bugzilla/Classification.pm new file mode 100644 index 000000000..fd011e6fe --- /dev/null +++ b/Bugzilla/Classification.pm @@ -0,0 +1,193 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Tiago R. Mello <timello@async.com.br> +# + +use strict; + +package Bugzilla::Classification; + +use Bugzilla; +use Bugzilla::Util; + +############################### +#### Initialization #### +############################### + +use constant DB_COLUMNS => qw( + classifications.id + classifications.name + classifications.description +); + +our $columns = join(", ", DB_COLUMNS); + +############################### +#### Methods #### +############################### + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = {}; + bless($self, $class); + return $self->_init(@_); +} + +sub _init { + my $self = shift; + my ($param) = @_; + my $dbh = Bugzilla->dbh; + + my $id = $param unless (ref $param eq 'HASH'); + my $classification; + + if (defined $id && detaint_natural($id)) { + + $classification = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM classifications + WHERE id = ?}, undef, $id); + + } elsif (defined $param->{'name'}) { + + trick_taint($param->{'name'}); + $classification = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM classifications + WHERE name = ?}, undef, $param->{'name'}); + } else { + ThrowCodeError('bad_arg', + {argument => 'param', + function => 'Bugzilla::Classification::_init'}); + } + + return undef unless (defined $classification); + + foreach my $field (keys %$classification) { + $self->{$field} = $classification->{$field}; + } + return $self; +} + +sub product_count { + my $self = shift; + my $dbh = Bugzilla->dbh; + + if (!defined $self->{'product_count'}) { + $self->{'product_count'} = $dbh->selectrow_array(q{ + SELECT COUNT(*) FROM products + WHERE classification_id = ?}, undef, $self->id); + } + return $self->{'product_count'}; +} + +############################### +#### Accessors #### +############################### + +sub id { return $_[0]->{'id'}; } +sub name { return $_[0]->{'name'}; } +sub description { return $_[0]->{'description'}; } + +############################### +#### Subroutines #### +############################### + +sub get_all_classifications () { + my $dbh = Bugzilla->dbh; + + my $ids = $dbh->selectcol_arrayref(q{ + SELECT id FROM classifications}); + + my $classifications; + foreach my $id (@$ids) { + $classifications->{$id} = new Bugzilla::Classification($id); + } + return $classifications; +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Classification - Bugzilla classification class. + +=head1 SYNOPSIS + + use Bugzilla::Classification; + + my $classification = new Bugzilla::Classification(1); + my $classification = new Bugzilla::Classification({name => 'Acme'}); + + my $id = $classification->id; + my $name = $classification->name; + my $description = $classification->description; + my $product_count = $classification->product_count; + + my $hash_ref = Bugzilla::Classification::get_all_classifications(); + my $classification = $hash_ref->{1}; + +=head1 DESCRIPTION + +Classification.pm represents a Classification object. + +A Classification is a higher-level grouping of Bugzilla Products. + +=head1 METHODS + +=over + +=item C<new($param)> + + Description: The constructor is used to load an existing + classification by passing a classification + id or classification name using a hash. + + Params: $param - If you pass an integer, the integer is the + classification_id from the database that we + want to read in. If you pass in a hash with + 'name' key, then the value of the name key + is the name of a classification from the DB. + + Returns: A Bugzilla::Classification object. + +=item C<product_count()> + + Description: Returns the total number of products that belong to + the classification. + + Params: none. + + Returns: Integer - The total of products inside the classification. + +=back + +=head1 SUBROUTINES + +=over + +=item C<get_all_classifications()> + + Description: Returns all Bugzilla classifications. + + Params: none. + + Returns: A hash with classification id as key and + Bugzilla::Classification object as value. + +=back + +=cut diff --git a/Bugzilla/Component.pm b/Bugzilla/Component.pm new file mode 100644 index 000000000..216616d98 --- /dev/null +++ b/Bugzilla/Component.pm @@ -0,0 +1,198 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Tiago R. Mello <timello@async.com.br> +# + +use strict; + +package Bugzilla::Component; + +use Bugzilla; +use Bugzilla::Util; +use Bugzilla::Error; + +############################### +#### Initialization #### +############################### + +use constant DB_COLUMNS => qw( + components.id + components.name + components.product_id + components.initialowner + components.initialqacontact + components.description +); + +our $columns = join(", ", DB_COLUMNS); + +############################### +#### Methods #### +############################### + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = {}; + bless($self, $class); + return $self->_init(@_); +} + +sub _init { + my $self = shift; + my ($param) = (@_); + my $dbh = Bugzilla->dbh; + + my $id = $param unless (ref $param eq 'HASH'); + my $component; + + if (defined $id && detaint_natural($id)) { + + $component = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM components + WHERE id = ?}, undef, $id); + + } elsif (defined $param->{'product_id'} + && detaint_natural($param->{'product_id'}) + && defined $param->{'name'}) { + + trick_taint($param->{'name'}); + + $component = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM components + WHERE name = ? AND product_id = ?}, undef, + ($param->{'name'}, $param->{'product_id'})); + } else { + ThrowCodeError('bad_arg', + {argument => 'param', + function => 'Bugzilla::Component::_init'}); + } + + return undef unless (defined $component); + + foreach my $field (keys %$component) { + $self->{$field} = $component->{$field}; + } + return $self; +} + +############################### +#### Accessors #### +############################### + +sub id { return $_[0]->{'id'}; } +sub name { return $_[0]->{'name'}; } +sub description { return $_[0]->{'description'}; } +sub product_id { return $_[0]->{'product_id'}; } +sub default_assignee { return $_[0]->{'initialowner'}; } +sub default_qa_contact { return $_[0]->{'initialqacontact'}; } + +############################### +#### Subroutines #### +############################### + +sub get_components_by_product ($) { + my ($product_id) = @_; + my $dbh = Bugzilla->dbh; + + my $stored_product_id = $product_id; + unless (detaint_natural($product_id)) { + ThrowCodeError( + 'invalid_numeric_argument', + {argument => 'product_id', + value => $stored_product_id, + function => + 'Bugzilla::Component::get_components_by_product'} + ); + } + + my $ids = $dbh->selectcol_arrayref(q{ + SELECT id FROM components + WHERE product_id = ?}, undef, $product_id); + + my $components; + foreach my $id (@$ids) { + $components->{$id} = new Bugzilla::Component($id); + } + return $components; +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Component - Bugzilla product component class. + +=head1 SYNOPSIS + + use Bugzilla::Component; + + my $component = new Bugzilla::Component(1); + my $component = new Bugzilla::Component({product_id => 1, + name => 'AcmeComp'}); + + my $id = $component->id; + my $name = $component->name; + my $description = $component->description; + my $product_id = $component->product_id; + my $default_assignee = $component->default_assignee; + my $default_qa_contact = $component->default_qa_contact; + + my $hash_ref = Bugzilla::Component::get_components_by_product(1); + my $component = $hash_ref->{1}; + +=head1 DESCRIPTION + +Component.pm represents a Product Component object. + +=head1 METHODS + +=over + +=item C<new($param)> + + Description: The constructor is used to load an existing component + by passing a component id or a hash with the product + id and the component name. + + Params: $param - If you pass an integer, the integer is the + component id from the database that we want to + read in. If you pass in a hash with 'name' key, + then the value of the name key is the name of a + component from the DB. + + Returns: A Bugzilla::Component object. + +=back + +=head1 SUBROUTINES + +=over + +=item C<get_components_by_product($product_id)> + + Description: Returns all Bugzilla components that belong to the + supplied product. + + Params: $product_id - Integer with a Bugzilla product id. + + Returns: A hash with component id as key and Bugzilla::Component + object as value. + +=back + +=cut diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index a62629420..95b8af98c 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -87,6 +87,8 @@ use base qw(Exporter); EVT_FLAG_REQUESTED EVT_REQUESTED_FLAG FULLTEXT_BUGLIST_LIMIT + + ADMIN_GROUP_NAME ); @Bugzilla::Constants::EXPORT_OK = qw(contenttypes); @@ -233,4 +235,7 @@ use constant GLOBAL_EVENTS => EVT_FLAG_REQUESTED, EVT_REQUESTED_FLAG; # a fulltext search. use constant FULLTEXT_BUGLIST_LIMIT => 200; +# Default administration group name. +use constant ADMIN_GROUP_NAME => 'admin'; + 1; diff --git a/Bugzilla/Group.pm b/Bugzilla/Group.pm index 85e6de5b1..808860274 100644 --- a/Bugzilla/Group.pm +++ b/Bugzilla/Group.pm @@ -106,7 +106,7 @@ sub is_active { return $_[0]->{'isactive'}; } ##### Module Subroutines ### ################################ -sub ValidateGroupName { +sub ValidateGroupName ($$) { my ($name, @users) = (@_); my $dbh = Bugzilla->dbh; my $query = "SELECT id FROM groups " . @@ -125,13 +125,34 @@ sub ValidateGroupName { return $ret; } +sub get_group_controls_by_product ($) { + my ($product_id) = @_; + my $dbh = Bugzilla->dbh; + + my $query = qq{SELECT + $columns, + group_control_map.entry, + group_control_map.membercontrol, + group_control_map.othercontrol, + group_control_map.canedit + FROM groups + LEFT JOIN group_control_map + ON groups.id = group_control_map.group_id + WHERE group_control_map.product_id = ? + AND groups.isbuggroup != 0 + ORDER BY groups.name}; + my $groups = $dbh->selectall_hashref($query, 'id', undef, + ($product_id)); + return $groups; +} + 1; __END__ =head1 NAME -Bugzilla::Group - Object for a Bugzilla group. +Bugzilla::Group - Bugzilla group class. =head1 SYNOPSIS @@ -147,6 +168,10 @@ Bugzilla::Group - Object for a Bugzilla group. my $user_reg_exp = $group->user_reg_exp; my $is_active = $group->is_active; + my $group_id = Bugzilla::Group::ValidateGroupName('admin', @users); + + my $grops = Bugzilla::Group::get_group_controls_by_product(1); + =head1 DESCRIPTION Group.pm represents a Bugzilla Group object. @@ -157,8 +182,16 @@ Group.pm represents a Bugzilla Group object. =item C<new($param)> -The constructor is used to load an existing group by passing -a group id or a hash with the group name. + Description: The constructor is used to load an existing group + by passing a group id or a hash with the group name. + + Params: $param - If you pass an integer, the integer is the + group id from the database that we want to + read in. If you pass in a hash with 'name' + key, then the value of the name key is the + name of a product from the DB. + + Returns: A Bugzilla::Group object. =back @@ -166,18 +199,29 @@ a group id or a hash with the group name. =over -=item C<ValidateGroupName($group_name, @users)> +=item C<ValidateGroupName($name, @users)> -ValidateGroupName checks to see if ANY of the users in the provided list -of user objects can see the named group. It returns the group id if -successful and undef otherwise. + Description: ValidateGroupName checks to see if ANY of the users + in the provided list of user objects can see the + named group. -=back + Params: $name - String with the group name. + @users - An array with Bugzilla::User objects. + + Returns: It returns the group id if successful + and undef otherwise. + +=item C<get_group_controls_by_product($product_id)> + + Description: Returns all group controls of a specific product. + It is encouraged to use Bugzilla::Product object + instead of directly calling this routine. -=head1 AUTHOR - - Joel Peshkin <bugreport@peshkin.net> - Erik Stambaugh <erik@dasbistro.com> - Tiago R. Mello <timello@async.com.br> + Params: $product_id - Integer with a Bugzilla product id. + + Returns: A hash with group id as key and hash containing the + group data as value. + +=back =cut diff --git a/Bugzilla/Milestone.pm b/Bugzilla/Milestone.pm new file mode 100644 index 000000000..dad8b6c11 --- /dev/null +++ b/Bugzilla/Milestone.pm @@ -0,0 +1,172 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Tiago R. Mello <timello@async.com.br> + +use strict; + +package Bugzilla::Milestone; + +use Bugzilla; +use Bugzilla::Util; +use Bugzilla::Error; + +################################ +##### Initialization ##### +################################ + +use constant DEFAULT_SORTKEY => 0; + +use constant DB_COLUMNS => qw( + milestones.value + milestones.product_id + milestones.sortkey +); + +my $columns = join(", ", DB_COLUMNS); + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = {}; + bless($self, $class); + return $self->_init(@_); +} + +sub _init { + my $self = shift; + my ($product_id, $value) = (@_); + my $dbh = Bugzilla->dbh; + + my $milestone; + + if (defined $product_id + && detaint_natural($product_id) + && defined $value) { + + trick_taint($value); + $milestone = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM milestones + WHERE value = ? + AND product_id = ?}, undef, ($value, $product_id)); + } else { + ThrowCodeError('bad_arg', + {argument => 'product_id/value', + function => 'Bugzilla::Milestone::_init'}); + } + + return undef unless (defined $milestone); + + foreach my $field (keys %$milestone) { + $self->{$field} = $milestone->{$field}; + } + return $self; +} + +################################ +##### Accessors ###### +################################ + +sub value { return $_[0]->{'value'}; } +sub product_id { return $_[0]->{'product_id'}; } +sub sortkey { return $_[0]->{'sortkey'}; } + +################################ +##### Subroutines ##### +################################ + +sub get_milestones_by_product ($) { + my ($product_id) = @_; + my $dbh = Bugzilla->dbh; + + my $stored_product_id = $product_id; + unless (detaint_natural($product_id)) { + ThrowCodeError( + 'invalid_numeric_argument', + {argument => 'product_id', + value => $stored_product_id, + function => + 'Bugzilla::Milestone::get_milestones_by_product'} + ); + } + + my $values = $dbh->selectcol_arrayref(q{ + SELECT value FROM milestones + WHERE product_id = ?}, undef, $product_id); + + my $milestones; + foreach my $value (@$values) { + $milestones->{$value} = new Bugzilla::Milestone($product_id, + $value); + } + return $milestones; +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Milestone - Bugzilla product milestone class. + +=head1 SYNOPSIS + + use Bugzilla::Milestone; + + my $milestone = new Bugzilla::Milestone(1, 'milestone_value'); + + my $product_id = $milestone->product_id; + my $value = $milestone->value; + + my $hash_ref = Bugzilla::Milestone::get_milestones_by_product(1); + my $milestone = $hash_ref->{'milestone_value'}; + +=head1 DESCRIPTION + +Milestone.pm represents a Product Milestone object. + +=head1 METHODS + +=over + +=item C<new($product_id, $value)> + + Description: The constructor is used to load an existing milestone + by passing a product id and a milestone value. + + Params: $product_id - Integer with a Bugzilla product id. + $value - String with a milestone value. + + Returns: A Bugzilla::Milestone object. + +=back + +=head1 SUBROUTINES + +=over + +=item C<get_milestones_by_product($product_id)> + + Description: Returns all Bugzilla product milestones that belong + to the supplied product. + + Params: $product_id - Integer with a Bugzilla product id. + + Returns: A hash with milestone value as key and a + Bugzilla::Milestone object as hash value. + +=back + +=cut diff --git a/Bugzilla/Product.pm b/Bugzilla/Product.pm new file mode 100644 index 000000000..28f1e73c0 --- /dev/null +++ b/Bugzilla/Product.pm @@ -0,0 +1,336 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Tiago R. Mello <timello@async.com.br> + +use strict; + +package Bugzilla::Product; + +use Bugzilla; +use Bugzilla::Component; +use Bugzilla::Classification; +use Bugzilla::Version; +use Bugzilla::Milestone; + +use Bugzilla::Util; +use Bugzilla::Group; +use Bugzilla::Error; + +use constant DEFAULT_CLASSIFICATION_ID => 1; + +############################### +#### Initialization #### +############################### + +use constant DB_COLUMNS => qw( + products.id + products.name + products.classification_id + products.description + products.milestoneurl + products.disallownew + products.votesperuser + products.maxvotesperbug + products.votestoconfirm + products.defaultmilestone +); + +my $columns = join(", ", DB_COLUMNS); + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = {}; + bless($self, $class); + return $self->_init(@_); +} + +sub _init { + my $self = shift; + my ($param) = @_; + my $dbh = Bugzilla->dbh; + + my $id = $param unless (ref $param eq 'HASH'); + my $product; + + if (defined $id && detaint_natural($id)) { + + $product = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM products + WHERE id = ?}, undef, $id); + + } elsif (defined $param->{'name'}) { + + trick_taint($param->{'name'}); + $product = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM products + WHERE name = ?}, undef, $param->{'name'}); + } else { + ThrowCodeError('bad_arg', + {argument => 'param', + function => 'Bugzilla::Product::_init'}); + } + + return undef unless (defined $product); + + foreach my $field (keys %$product) { + $self->{$field} = $product->{$field}; + } + return $self; +} + +############################### +#### Methods #### +############################### + +sub components { + my $self = shift; + + if (!defined $self->{components}) { + $self->{components} = + Bugzilla::Component::get_components_by_product($self->id); + } + return $self->{components} +} + +sub classification { + my $self = shift; + + if (!defined $self->{'classification'}) { + $self->{'classification'} = + new Bugzilla::Classification($self->classification_id); + } + return $self->{'classification'}; +} + +sub group_controls { + my $self = shift; + + if (!defined $self->{group_controls}) { + $self->{group_controls} = + Bugzilla::Group::get_group_controls_by_product($self->id); + } + return $self->{group_controls}; +} + +sub versions { + my $self = shift; + + if (!defined $self->{versions}) { + $self->{versions} = + Bugzilla::Version::get_versions_by_product($self->id); + + } + return $self->{versions}; +} + +sub milestones { + my $self = shift; + + if (!defined $self->{milestones}) { + $self->{milestones} = + Bugzilla::Milestone::get_milestones_by_product($self->id); + } + return $self->{milestones}; +} + +sub bug_count { + my $self = shift; + my $dbh = Bugzilla->dbh; + + if (!defined $self->{'bug_count'}) { + $self->{'bug_count'} = $dbh->selectrow_array(qq{ + SELECT COUNT(bug_id) FROM bugs + WHERE product_id = ?}, undef, $self->id); + + } + return $self->{'bug_count'}; +} + +############################### +#### Accessors ###### +############################### + +sub id { return $_[0]->{'id'}; } +sub name { return $_[0]->{'name'}; } +sub description { return $_[0]->{'description'}; } +sub milestone_url { return $_[0]->{'milestoneurl'}; } +sub disallow_new { return $_[0]->{'disallownew'}; } +sub votes_per_user { return $_[0]->{'votesperuser'}; } +sub max_votes_per_bug { return $_[0]->{'maxvotesperbug'}; } +sub votes_to_confirm { return $_[0]->{'votestoconfirm'}; } +sub default_milestone { return $_[0]->{'defaultmilestone'}; } +sub classification_id { return $_[0]->{'classification_id'}; } + +############################### +#### Subroutines ###### +############################### + +sub get_products_by_classification ($) { + my ($class_id) = @_; + my $dbh = Bugzilla->dbh; + $class_id ||= DEFAULT_CLASSIFICATION_ID; + + my $stored_class_id = $class_id; + unless (detaint_natural($class_id)) { + ThrowCodeError( + 'invalid_numeric_argument', + {argument => 'product_id', + value => $stored_class_id, + function => + 'Bugzilla::Product::get_classification_products'} + ); + } + + my $ids = $dbh->selectcol_arrayref(q{ + SELECT id FROM products + WHERE classification_id = ?}, undef, $class_id); + + my $products; + foreach my $id (@$ids) { + $products->{$id} = new Bugzilla::Product($id); + } + return $products; +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Product - Bugzilla product class. + +=head1 SYNOPSIS + + use Bugzilla::Product; + + my $product = new Bugzilla::Product(1); + my $product = new Bugzilla::Product('AcmeProduct'); + + my $components = $product->components(); + my $classification = $product->classification(); + my $hash_ref = $product->group_controls(); + my $hash_ref = $product->milestones(); + my $hash_ref = $product->versions(); + my $bugcount = $product->bug_count(); + + my $id = $product->id; + my $name = $product->name; + my $description = $product->description; + my $milestoneurl = $product->milestone_url; + my disallownew = $product->disallow_new; + my votesperuser = $product->votes_per_user; + my maxvotesperbug = $product->max_votes_per_bug; + my votestoconfirm = $product->votes_to_confirm; + my $defaultmilestone = $product->default_milestone; + my $classificationid = $product->classification_id; + + my $hash_ref = Bugzilla::Product::get_products_by_classification(1); + my $product = $hash_ref->{1}; + +=head1 DESCRIPTION + +Product.pm represents a product object. + +=head1 METHODS + +=over + +=item C<new($param)> + + Description: The constructor is used to load an existing product + by passing a product id or a hash. + + Params: $param - If you pass an integer, the integer is the + product id from the database that we want to + read in. If you pass in a hash with 'name' key, + then the value of the name key is the name of a + product from the DB. + + Returns: A Bugzilla::Product object. + +=item C<components()> + + Description: Returns a hash with all product components. + + Params: none. + + Returns: A hash where component id is the hash key and + Bugzilla::Component object is the hash value. + +=item C<classification()> + + Description: Returns a Bugzilla::Classification object for + the product classification. + + Params: none. + + Returns: A Bugzilla::Classification object. + +=item C<group_controls()> + + Description: Returns a hash (group id as key) with all product + group controls. + + Params: none. + + Returns: A hash with group id as key and hash containing the + group data as value. + +=item C<versions()> + + Description: Returns a hash with of all product versions. + + Params: none. + + Returns: A hash with version id as key and a Bugzilla::Version + as value. + +=item C<milestones()> + + Description: Returns a hash with of all product milestones. + + Params: none. + + Returns: A hash with milestone id as key and a Bugzilla::Milestone + as value. + +=item C<bug_count()> + + Description: Returns the total of bugs that belong to the product. + + Params: none. + + Returns: Integer with the number of bugs. + +=back + +=head1 SUBROUTINES + +=over + +=item C<get_products_by_classification($class_id)> + + Description: Returns all products for a specific classification id. + + Params: none. + + Returns: A hash with product id as key and a Bugzilla::Product + object as value. + +=back + +=cut diff --git a/Bugzilla/Version.pm b/Bugzilla/Version.pm new file mode 100644 index 000000000..5cd5b2aeb --- /dev/null +++ b/Bugzilla/Version.pm @@ -0,0 +1,170 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): Tiago R. Mello <timello@async.com.br> + +use strict; + +package Bugzilla::Version; + +use Bugzilla; +use Bugzilla::Util; +use Bugzilla::Error; + +################################ +##### Initialization ##### +################################ + +use constant DEFAULT_VERSION => 'unspecified'; + +use constant DB_COLUMNS => qw( + versions.value + versions.product_id +); + +our $columns = join(", ", DB_COLUMNS); + +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my $self = {}; + bless($self, $class); + return $self->_init(@_); +} + +sub _init { + my $self = shift; + my ($product_id, $value) = (@_); + my $dbh = Bugzilla->dbh; + + my $version; + + if (defined $product_id + && detaint_natural($product_id) + && defined $value) { + + trick_taint($value); + $version = $dbh->selectrow_hashref(qq{ + SELECT $columns FROM versions + WHERE value = ? + AND product_id = ?}, undef, ($value, $product_id)); + } else { + ThrowCodeError('bad_arg', + {argument => 'product_id/value', + function => 'Bugzilla::Version::_init'}); + } + + return undef unless (defined $version); + + foreach my $field (keys %$version) { + $self->{$field} = $version->{$field}; + } + return $self; +} + +############################### +##### Accessors #### +############################### + +sub value { return $_[0]->{'value'}; } +sub product_id { return $_[0]->{'product_id'}; } + +############################### +##### Subroutines ### +############################### + +sub get_versions_by_product ($) { + my ($product_id) = @_; + my $dbh = Bugzilla->dbh; + + my $stored_product_id = $product_id; + unless (detaint_natural($product_id)) { + ThrowCodeError( + 'invalid_numeric_argument', + {argument => 'product_id', + value => $stored_product_id, + function => + 'Bugzilla::Version::get_versions_by_product'} + ); + } + + my $values = $dbh->selectcol_arrayref(q{ + SELECT value FROM versions + WHERE product_id = ?}, undef, $product_id); + + my $versions; + foreach my $value (@$values) { + $versions->{$value} = new Bugzilla::Version($product_id, + $value); + } + return $versions; +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Version - Bugzilla product version class. + +=head1 SYNOPSIS + + use Bugzilla::Version; + + my $version = new Bugzilla::Version(1, 'version_value'); + + my $product_id = $version->product_id; + my $value = $version->value; + + my $hash_ref = Bugzilla::Version::get_versions_by_product(1); + my $version = $hash_ref->{'version_value'}; + +=head1 DESCRIPTION + +Version.pm represents a Product Version object. + +=head1 METHODS + +=over + +=item C<new($product_id, $value)> + + Description: The constructor is used to load an existing version + by passing a product id and a version value. + + Params: $product_id - Integer with a Bugzilla product id. + $value - String with a version value. + + Returns: A Bugzilla::Version object. + +=back + +=head1 SUBROUTINES + +=over + +=item C<get_versions_by_product($product_id)> + + Description: Returns all Bugzilla product versions that belong + to the supplied product. + + Params: $product_id - Integer with a Bugzilla product id. + + Returns: A hash with version value as key and a Bugzilla::Version + objects as value. + +=back + +=cut diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl index 1b7af3fea..5ad057061 100644 --- a/template/en/default/global/code-error.html.tmpl +++ b/template/en/default/global/code-error.html.tmpl @@ -149,6 +149,11 @@ The active flag was improperly set. There may be a problem with [% terms.Bugzilla %] or [% terms.abug %] in your browser. + [% ELSIF error == "invalid_numeric_argument" %] + [% title = "Invalid number argument" %] + The argument <code>[% argument FILTER html %] = [% value FILTER html %]</code> + of <code>[% function FILTER html %]</code> is not a natural number. + [% ELSIF error == "invalid_series_id" %] [% title = "Invalid Series" %] The series_id [% series_id FILTER html %] is not valid. It may be that |