summaryrefslogtreecommitdiffstats
path: root/Bugzilla
diff options
context:
space:
mode:
authorlpsolit%gmail.com <>2006-09-09 08:11:40 +0200
committerlpsolit%gmail.com <>2006-09-09 08:11:40 +0200
commita806b298f5bfe5914f27a1419d27366fe59da449 (patch)
tree25d737aeb60f17360de9a67f2017369a4d5d8349 /Bugzilla
parent27c1be36a3cbc57e01c8d51af85be76b0748ece6 (diff)
downloadbugzilla-a806b298f5bfe5914f27a1419d27366fe59da449.tar.gz
bugzilla-a806b298f5bfe5914f27a1419d27366fe59da449.tar.xz
Bug 287326: Ability to add custom single-select fields to a bug - Patch by Frédéric Buclin <LpSolit@gmail.com> and Max Kanat-Alexander <mkanat@bugzilla.org> r=mkanat a=myk
Diffstat (limited to 'Bugzilla')
-rwxr-xr-xBugzilla/Bug.pm46
-rw-r--r--Bugzilla/Constants.pm2
-rw-r--r--Bugzilla/DB.pm17
-rw-r--r--Bugzilla/DB/Schema.pm17
-rw-r--r--Bugzilla/Field.pm84
-rw-r--r--Bugzilla/Object.pm8
-rw-r--r--Bugzilla/Search.pm38
7 files changed, 169 insertions, 43 deletions
diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm
index 03a28bf5d..6e8079d27 100755
--- a/Bugzilla/Bug.pm
+++ b/Bugzilla/Bug.pm
@@ -110,20 +110,30 @@ use constant REQUIRED_CREATE_FIELDS => qw(
# There are also other, more complex validators that are called
# from run_create_validators.
-use constant VALIDATORS => {
- alias => \&_check_alias,
- bug_file_loc => \&_check_bug_file_loc,
- bug_severity => \&_check_bug_severity,
- cc => \&_check_cc,
- deadline => \&_check_deadline,
- estimated_time => \&_check_estimated_time,
- op_sys => \&_check_op_sys,
- priority => \&_check_priority,
- product => \&_check_product,
- remaining_time => \&_check_remaining_time,
- rep_platform => \&_check_rep_platform,
- short_desc => \&_check_short_desc,
- status_whiteboard => \&_check_status_whiteboard,
+sub VALIDATORS {
+ my $validators = {
+ alias => \&_check_alias,
+ bug_file_loc => \&_check_bug_file_loc,
+ bug_severity => \&_check_bug_severity,
+ cc => \&_check_cc,
+ deadline => \&_check_deadline,
+ estimated_time => \&_check_estimated_time,
+ op_sys => \&_check_op_sys,
+ priority => \&_check_priority,
+ product => \&_check_product,
+ remaining_time => \&_check_remaining_time,
+ rep_platform => \&_check_rep_platform,
+ short_desc => \&_check_short_desc,
+ status_whiteboard => \&_check_status_whiteboard,
+ };
+
+ my @select_fields = Bugzilla->get_fields({custom => 1, obsolete => 0,
+ type => FIELD_TYPE_SINGLE_SELECT});
+
+ foreach my $field (@select_fields) {
+ $validators->{$field->name} = \&_check_select_field;
+ }
+ return $validators;
};
# Used in LogActivityEntry(). Gives the max length of lines in the
@@ -279,7 +289,7 @@ sub run_create_validators {
$params->{remaining_time} = $params->{estimated_time};
$class->_check_strict_isolation($product, $params->{cc},
- $params->{assigned_to}, $params->{qa_contact});
+ $params->{assigned_to}, $params->{qa_contact});
return $params;
}
@@ -657,6 +667,12 @@ sub _check_version {
return $version;
}
+sub _check_select_field {
+ my ($invocant, $value, $field) = @_;
+ $value = trim($value);
+ check_field($field, $value);
+ return $value;
+}
#####################################################################
# Class Accessors
diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm
index a0e869c33..9559dcae3 100644
--- a/Bugzilla/Constants.pm
+++ b/Bugzilla/Constants.pm
@@ -106,6 +106,7 @@ use File::Basename;
FIELD_TYPE_UNKNOWN
FIELD_TYPE_FREETEXT
+ FIELD_TYPE_SINGLE_SELECT
BUG_STATE_OPEN
@@ -296,6 +297,7 @@ use constant SENDMAIL_EXE => '/usr/lib/sendmail.exe';
use constant FIELD_TYPE_UNKNOWN => 0;
use constant FIELD_TYPE_FREETEXT => 1;
+use constant FIELD_TYPE_SINGLE_SELECT => 2;
# The maximum number of days a token will remain valid.
use constant MAX_TOKEN_AGE => 3;
diff --git a/Bugzilla/DB.pm b/Bugzilla/DB.pm
index 077f93cf7..5fceb961d 100644
--- a/Bugzilla/DB.pm
+++ b/Bugzilla/DB.pm
@@ -577,10 +577,25 @@ sub bz_add_table {
sub _bz_add_table_raw {
my ($self, $name) = @_;
my @statements = $self->_bz_schema->get_table_ddl($name);
- print "Adding new table $name ...\n";
+ print "Adding new table $name ...\n" unless i_am_cgi();
$self->do($_) foreach (@statements);
}
+sub bz_add_field_table {
+ my ($self, $name) = @_;
+ my $table_schema = $self->_bz_schema->FIELD_TABLE_SCHEMA;
+ my $indexes = $table_schema->{INDEXES};
+ # $indexes is an arrayref, not a hash. In order to fix the keys,
+ # we have to fix every other item.
+ for (my $i = 0; $i < scalar @$indexes; $i++) {
+ next if ($i % 2 && $i != 0); # We skip 1, 3, 5, 7, etc.
+ $indexes->[$i] = $name . "_" . $indexes->[$i];
+ }
+ # We add this to the abstract schema so that bz_add_table can find it.
+ $self->_bz_schema->add_table($name, $table_schema);
+ $self->bz_add_table($name);
+}
+
sub bz_drop_column {
my ($self, $table, $column) = @_;
diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm
index 4c270e68c..384fb478b 100644
--- a/Bugzilla/DB/Schema.pm
+++ b/Bugzilla/DB/Schema.pm
@@ -1090,6 +1090,23 @@ use constant ABSTRACT_SCHEMA => {
},
};
+
+use constant FIELD_TABLE_SCHEMA => {
+ FIELDS => [
+ id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
+ PRIMARYKEY => 1},
+ value => {TYPE => 'varchar(64)', NOTNULL => 1},
+ sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
+ isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
+ DEFAULT => 'TRUE'},
+ ],
+ # Note that bz_add_field_table should prepend the table name
+ # to these index names.
+ INDEXES => [
+ value_idx => {FIELDS => ['value'], TYPE => 'UNIQUE'},
+ sortkey_idx => ['sortkey', 'value'],
+ ],
+};
#--------------------------------------------------------------------------
=head1 METHODS
diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm
index 870e93221..2dfd8aa6e 100644
--- a/Bugzilla/Field.pm
+++ b/Bugzilla/Field.pm
@@ -103,7 +103,9 @@ use constant DB_COLUMNS => (
use constant SQL_DEFINITIONS => {
# Using commas because these are constants and they shouldn't
# be auto-quoted by the "=>" operator.
- FIELD_TYPE_FREETEXT, { TYPE => 'varchar(255)' },
+ FIELD_TYPE_FREETEXT, { TYPE => 'varchar(255)' },
+ FIELD_TYPE_SINGLE_SELECT, { TYPE => 'varchar(64)', NOTNULL => 1,
+ DEFAULT => "'---'" },
};
# Field definitions for the fields that ship with Bugzilla.
@@ -266,6 +268,24 @@ enter_bug.cgi
sub enter_bug { return $_[0]->{enter_bug} }
+=over
+
+=item C<legal_values>
+
+A reference to an array with valid active values for this field.
+
+=back
+
+=cut
+
+sub legal_values {
+ my $self = shift;
+
+ if (!defined $self->{'legal_values'}) {
+ $self->{'legal_values'} = get_legal_field_values($self->name);
+ }
+ return $self->{'legal_values'};
+}
=pod
@@ -305,9 +325,7 @@ sub create_or_update {
my $name = $params->{name};
my $custom = $params->{custom} ? 1 : 0;
my $in_new_bugmail = $params->{in_new_bugmail} ? 1 : 0;
- # Some day we'll allow invocants to specify the field type.
- # We don't care about $params->{type} yet.
- my $type = $custom ? FIELD_TYPE_FREETEXT : FIELD_TYPE_UNKNOWN;
+ my $type = $params->{type} || FIELD_TYPE_UNKNOWN;
my $field = new Bugzilla::Field({name => $name});
if ($field) {
@@ -353,6 +371,15 @@ sub create_or_update {
$dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type});
}
+ if ($custom && !$dbh->bz_table_info($name)
+ && $type eq FIELD_TYPE_SINGLE_SELECT)
+ {
+ # Create the table that holds the legal values for this field.
+ $dbh->bz_add_field_table($name);
+ # And insert a default value of "---" into it.
+ $dbh->do("INSERT INTO $name (value) VALUES ('---')");
+ }
+
return new Bugzilla::Field({name => $name});
}
@@ -361,19 +388,45 @@ sub create_or_update {
=over
-=item C<match($criteria)>
+=item C<match>
+
+=over
+
+=item B<Description>
-Description: returns a list of fields that match the specified criteria.
+Returns a list of fields that match the specified criteria.
-Params: C<$criteria> - hash reference - the criteria to match against.
- Hash keys represent field properties; hash values represent
- their values. All criteria are optional. Valid criteria are
- "custom" and "obsolete", and both take boolean values.
+You should be using L<Bugzilla/get_fields> and
+L<Bugzilla/get_custom_field_names> instead of this function.
- Note: Bugzilla->get_fields() and Bugzilla->custom_field_names
- wrap this method for most callers.
+=item B<Params>
-Returns: A reference to an array of C<Bugzilla::Field> objects.
+Takes named parameters in a hashref:
+
+=over
+
+=item C<name> - The name of the field.
+
+=item C<custom> - Boolean. True to only return custom fields. False
+to only return non-custom fields.
+
+=item C<obsolete> - Boolean. True to only return obsolete fields.
+False to not return obsolete fields.
+
+=item C<type> - The type of the field. A C<FIELD_TYPE> constant from
+L<Bugzilla::Constants>.
+
+=item C<enter_bug> - Boolean. True to only return fields that appear
+on F<enter_bug.cgi>. False to only return fields that I<don't> appear
+on F<enter_bug.cgi>.
+
+=back
+
+=item B<Returns>
+
+A reference to an array of C<Bugzilla::Field> objects.
+
+=back
=back
@@ -395,8 +448,11 @@ sub match {
if (defined $criteria->{enter_bug}) {
push(@terms, "enter_bug=" . ($criteria->{enter_bug} ? '1' : '0'));
}
+ if (defined $criteria->{type}) {
+ push(@terms, "type = " . $criteria->{type});
+ }
my $where = (scalar(@terms) > 0) ? "WHERE " . join(" AND ", @terms) : "";
-
+
my $ids = Bugzilla->dbh->selectcol_arrayref(
"SELECT id FROM fielddefs $where", {Slice => {}});
diff --git a/Bugzilla/Object.pm b/Bugzilla/Object.pm
index 8de20d5f3..5d80a9d0f 100644
--- a/Bugzilla/Object.pm
+++ b/Bugzilla/Object.pm
@@ -17,6 +17,7 @@
# Everything Solved. All Rights Reserved.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
+# Frédéric Buclin <LpSolit@gmail.com>
use strict;
@@ -136,7 +137,7 @@ sub set {
my $validators = $self->VALIDATORS;
if (exists $validators->{$field}) {
my $validator = $validators->{$field};
- $value = $self->$validator($value);
+ $value = $self->$validator($value, $field);
}
$self->{$field} = $value;
@@ -196,7 +197,7 @@ sub run_create_validators {
my $value;
if (exists $validators->{$field}) {
my $validator = $validators->{$field};
- $value = $class->$validator($params->{$field});
+ $value = $class->$validator($params->{$field}, $field);
}
else {
$value = $params->{$field};
@@ -328,6 +329,9 @@ a reference to the current object (what we normally call C<$self>).
The second argument will be the value passed to L</create> or
L</set>for that field.
+The third argument will be the name of the field being validated.
+This may be required by validators which validate several distinct fields.
+
These functions should call L<Bugzilla::Error/ThrowUserError> if they fail.
The validator must return the validated value.
diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm
index d2d3b4978..0d72b5873 100644
--- a/Bugzilla/Search.pm
+++ b/Bugzilla/Search.pm
@@ -55,7 +55,7 @@ use constant SUMMARY_RELEVANCE_FACTOR => 7;
# We need to have a list of these fields and what they map to.
# Each field points to an array that contains the fields mapped
# to, in order.
-our %specialorder = (
+use constant SPECIAL_ORDER => {
'bugs.target_milestone' => [ 'ms_order.sortkey','ms_order.value' ],
'bugs.bug_status' => [ 'bug_status.sortkey','bug_status.value' ],
'bugs.rep_platform' => [ 'rep_platform.sortkey','rep_platform.value' ],
@@ -63,12 +63,12 @@ our %specialorder = (
'bugs.op_sys' => [ 'op_sys.sortkey','op_sys.value' ],
'bugs.resolution' => [ 'resolution.sortkey', 'resolution.value' ],
'bugs.bug_severity' => [ 'bug_severity.sortkey','bug_severity.value' ]
-);
+};
# When we add certain fields to the ORDER BY, we need to then add a
# table join to the FROM statement. This hash maps input fields to
# the join statements that need to be added.
-our %specialorderjoin = (
+use constant SPECIAL_ORDER_JOIN => {
'bugs.target_milestone' => 'LEFT JOIN milestones AS ms_order ON ms_order.value = bugs.target_milestone AND ms_order.product_id = bugs.product_id',
'bugs.bug_status' => 'LEFT JOIN bug_status ON bug_status.value = bugs.bug_status',
'bugs.rep_platform' => 'LEFT JOIN rep_platform ON rep_platform.value = bugs.rep_platform',
@@ -76,7 +76,7 @@ our %specialorderjoin = (
'bugs.op_sys' => 'LEFT JOIN op_sys ON op_sys.value = bugs.op_sys',
'bugs.resolution' => 'LEFT JOIN resolution ON resolution.value = bugs.resolution',
'bugs.bug_severity' => 'LEFT JOIN bug_severity ON bug_severity.value = bugs.bug_severity'
-);
+};
# Create a new Search
# Note that the param argument may be modified by Bugzilla::Search
@@ -117,6 +117,18 @@ sub init {
my @andlist;
my %chartfields;
+ my %special_order = %{SPECIAL_ORDER()};
+ my %special_order_join = %{SPECIAL_ORDER_JOIN()};
+
+ my @select_fields = Bugzilla->get_fields({ type => FIELD_TYPE_SINGLE_SELECT,
+ obsolete => 0 });
+ foreach my $field (@select_fields) {
+ my $name = $field->name;
+ $special_order{"bugs.$name"} = [ "$name.sortkey", "$name.value" ],
+ $special_order_join{"bugs.$name"} =
+ "LEFT JOIN $name ON $name.value = bugs.$name";
+ }
+
my $dbh = Bugzilla->dbh;
# First, deal with all the old hard-coded non-chart-based poop.
@@ -213,6 +225,9 @@ sub init {
"assigned_to", "reporter", "component", "classification",
"target_milestone", "bug_group");
+ # Include custom select fields.
+ push(@legal_fields, map { $_->name } @select_fields);
+
foreach my $field ($params->param()) {
if (lsearch(\@legal_fields, $field) != -1) {
push(@specialchart, [$field, "anyexact",
@@ -1368,7 +1383,7 @@ sub init {
if ($orderitem =~ /\s+AS\s+(.+)$/i) {
$orderitem = $1;
}
- BuildOrderBy($orderitem, \@orderby);
+ BuildOrderBy(\%special_order, $orderitem, \@orderby);
}
# Now JOIN the correct tables in the FROM clause.
# This is done separately from the above because it's
@@ -1376,8 +1391,8 @@ sub init {
foreach my $orderitem (@inputorder) {
# Grab the part without ASC or DESC.
my @splitfield = split(/\s+/, $orderitem);
- if ($specialorderjoin{$splitfield[0]}) {
- push(@supptables, $specialorderjoin{$splitfield[0]});
+ if ($special_order_join{$splitfield[0]}) {
+ push(@supptables, $special_order_join{$splitfield[0]});
}
}
@@ -1677,7 +1692,7 @@ sub IsValidQueryType
# BuildOrderBy recursively, to let it know that we're "reversing" the
# order. That is, that we wanted "A DESC", not "A".
sub BuildOrderBy {
- my ($orderitem, $stringlist, $reverseorder) = (@_);
+ my ($special_order, $orderitem, $stringlist, $reverseorder) = (@_);
my @twopart = split(/\s+/, $orderitem);
my $orderfield = $twopart[0];
@@ -1695,11 +1710,12 @@ sub BuildOrderBy {
}
# Handle fields that have non-standard sort orders, from $specialorder.
- if ($specialorder{$orderfield}) {
- foreach my $subitem (@{$specialorder{$orderfield}}) {
+ if ($special_order->{$orderfield}) {
+ foreach my $subitem (@{$special_order->{$orderfield}}) {
# DESC on a field with non-standard sort order means
# "reverse the normal order for each field that we map to."
- BuildOrderBy($subitem, $stringlist, $orderdirection =~ m/desc/i);
+ BuildOrderBy($special_order, $subitem, $stringlist,
+ $orderdirection =~ m/desc/i);
}
return;
}