summaryrefslogtreecommitdiffstats
path: root/Bugzilla/Field.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/Field.pm')
-rw-r--r--Bugzilla/Field.pm1414
1 files changed, 775 insertions, 639 deletions
diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm
index 837e1c0de..b0b7224dd 100644
--- a/Bugzilla/Field.pm
+++ b/Bugzilla/Field.pm
@@ -83,80 +83,79 @@ use constant DB_TABLE => 'fielddefs';
use constant LIST_ORDER => 'sortkey, name';
use constant DB_COLUMNS => qw(
- id
- name
- description
- type
- custom
- mailhead
- sortkey
- obsolete
- enter_bug
- buglist
- visibility_field_id
- value_field_id
- reverse_desc
- is_mandatory
- is_numeric
+ id
+ name
+ description
+ type
+ custom
+ mailhead
+ sortkey
+ obsolete
+ enter_bug
+ buglist
+ visibility_field_id
+ value_field_id
+ reverse_desc
+ is_mandatory
+ is_numeric
);
use constant VALIDATORS => {
- custom => \&_check_custom,
- description => \&_check_description,
- enter_bug => \&_check_enter_bug,
- buglist => \&Bugzilla::Object::check_boolean,
- mailhead => \&_check_mailhead,
- name => \&_check_name,
- obsolete => \&_check_obsolete,
- reverse_desc => \&_check_reverse_desc,
- sortkey => \&_check_sortkey,
- type => \&_check_type,
- value_field_id => \&_check_value_field_id,
- visibility_field_id => \&_check_visibility_field_id,
- visibility_values => \&_check_visibility_values,
- is_mandatory => \&Bugzilla::Object::check_boolean,
- is_numeric => \&_check_is_numeric,
+ custom => \&_check_custom,
+ description => \&_check_description,
+ enter_bug => \&_check_enter_bug,
+ buglist => \&Bugzilla::Object::check_boolean,
+ mailhead => \&_check_mailhead,
+ name => \&_check_name,
+ obsolete => \&_check_obsolete,
+ reverse_desc => \&_check_reverse_desc,
+ sortkey => \&_check_sortkey,
+ type => \&_check_type,
+ value_field_id => \&_check_value_field_id,
+ visibility_field_id => \&_check_visibility_field_id,
+ visibility_values => \&_check_visibility_values,
+ is_mandatory => \&Bugzilla::Object::check_boolean,
+ is_numeric => \&_check_is_numeric,
};
use constant VALIDATOR_DEPENDENCIES => {
- is_numeric => ['type'],
- name => ['custom'],
- type => ['custom'],
- reverse_desc => ['type'],
- value_field_id => ['type'],
- visibility_values => ['visibility_field_id'],
+ is_numeric => ['type'],
+ name => ['custom'],
+ type => ['custom'],
+ reverse_desc => ['type'],
+ value_field_id => ['type'],
+ visibility_values => ['visibility_field_id'],
};
use constant UPDATE_COLUMNS => qw(
- description
- mailhead
- sortkey
- obsolete
- enter_bug
- buglist
- visibility_field_id
- value_field_id
- reverse_desc
- is_mandatory
- is_numeric
- type
+ description
+ mailhead
+ sortkey
+ obsolete
+ enter_bug
+ buglist
+ visibility_field_id
+ value_field_id
+ reverse_desc
+ is_mandatory
+ is_numeric
+ type
);
# How various field types translate into SQL data definitions.
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)',
- NOTNULL => 1, DEFAULT => "''"},
- FIELD_TYPE_SINGLE_SELECT, { TYPE => 'varchar(64)', NOTNULL => 1,
- DEFAULT => "'---'" },
- FIELD_TYPE_TEXTAREA, { TYPE => 'MEDIUMTEXT',
- NOTNULL => 1, DEFAULT => "''"},
- FIELD_TYPE_DATETIME, { TYPE => 'DATETIME' },
- FIELD_TYPE_DATE, { TYPE => 'DATE' },
- FIELD_TYPE_BUG_ID, { TYPE => 'INT3' },
- # BMO : allow integer fields to be NULL
- FIELD_TYPE_INTEGER, { TYPE => 'INT4' },
+
+ # Using commas because these are constants and they shouldn't
+ # be auto-quoted by the "=>" operator.
+ FIELD_TYPE_FREETEXT, {TYPE => 'varchar(255)', NOTNULL => 1, DEFAULT => "''"},
+ FIELD_TYPE_SINGLE_SELECT,
+ {TYPE => 'varchar(64)', NOTNULL => 1, DEFAULT => "'---'"}, FIELD_TYPE_TEXTAREA,
+ {TYPE => 'MEDIUMTEXT', NOTNULL => 1, DEFAULT => "''"}, FIELD_TYPE_DATETIME,
+ {TYPE => 'DATETIME'}, FIELD_TYPE_DATE, {TYPE => 'DATE'}, FIELD_TYPE_BUG_ID,
+ {TYPE => 'INT3'},
+
+ # BMO : allow integer fields to be NULL
+ FIELD_TYPE_INTEGER, {TYPE => 'INT4'},
};
# Field definitions for the fields that ship with Bugzilla.
@@ -164,108 +163,217 @@ use constant SQL_DEFINITIONS => {
# the fielddefs table.
# 'days_elapsed' is set in populate_field_definitions() itself.
use constant DEFAULT_FIELDS => (
- {name => 'bug_id', desc => 'Bug #', in_new_bugmail => 1,
- buglist => 1, is_numeric => 1},
- {name => 'short_desc', desc => 'Summary', in_new_bugmail => 1,
- is_mandatory => 1, buglist => 1},
- {name => 'classification', desc => 'Classification', in_new_bugmail => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'product', desc => 'Product', in_new_bugmail => 1,
- is_mandatory => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'component', desc => 'Component', in_new_bugmail => 1,
- is_mandatory => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'version', desc => 'Version', in_new_bugmail => 1,
- is_mandatory => 1, buglist => 1},
- {name => 'rep_platform', desc => 'Platform', in_new_bugmail => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'bug_file_loc', desc => 'URL', in_new_bugmail => 1,
- buglist => 1},
- {name => 'op_sys', desc => 'OS/Version', in_new_bugmail => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'bug_status', desc => 'Status', in_new_bugmail => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'status_whiteboard', desc => 'Status Whiteboard',
- in_new_bugmail => 1, buglist => 1},
- {name => 'keywords', desc => 'Keywords', in_new_bugmail => 1,
- type => FIELD_TYPE_KEYWORDS, buglist => 1},
- {name => 'resolution', desc => 'Resolution',
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'bug_severity', desc => 'Severity', in_new_bugmail => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'priority', desc => 'Priority', in_new_bugmail => 1,
- type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
- {name => 'assigned_to', desc => 'AssignedTo', in_new_bugmail => 1,
- buglist => 1},
- {name => 'reporter', desc => 'ReportedBy', in_new_bugmail => 1,
- buglist => 1},
- {name => 'qa_contact', desc => 'QAContact', in_new_bugmail => 1,
- buglist => 1},
- {name => 'cc', desc => 'CC', in_new_bugmail => 1},
- {name => 'dependson', desc => 'Depends on', in_new_bugmail => 1,
- is_numeric => 1, buglist => 1},
- {name => 'blocked', desc => 'Blocks', in_new_bugmail => 1,
- is_numeric => 1, buglist => 1},
-
- {name => 'assignee_last_login', desc => 'Assignee Last Login Date', buglist => 1},
-
- {name => 'attachments.description', desc => 'Attachment description'},
- {name => 'attachments.filename', desc => 'Attachment filename'},
- {name => 'attachments.mimetype', desc => 'Attachment mime type'},
- {name => 'attachments.ispatch', desc => 'Attachment is patch',
- is_numeric => 1},
- {name => 'attachments.isobsolete', desc => 'Attachment is obsolete',
- is_numeric => 1},
- {name => 'attachments.isprivate', desc => 'Attachment is private',
- is_numeric => 1},
- {name => 'attachments.submitter', desc => 'Attachment creator'},
-
- {name => 'target_milestone', desc => 'Target Milestone',
- buglist => 1},
- {name => 'creation_ts', desc => 'Creation date',
- buglist => 1},
- {name => 'delta_ts', desc => 'Last changed date',
- buglist => 1},
- {name => 'longdesc', desc => 'Comment'},
- {name => 'longdescs.isprivate', desc => 'Comment is private',
- is_numeric => 1},
- {name => 'longdescs.count', desc => 'Number of Comments',
- buglist => 1, is_numeric => 1},
- {name => 'alias', desc => 'Alias', buglist => 1},
- {name => 'everconfirmed', desc => 'Ever Confirmed',
- is_numeric => 1},
- {name => 'reporter_accessible', desc => 'Reporter Accessible',
- is_numeric => 1},
- {name => 'cclist_accessible', desc => 'CC Accessible',
- is_numeric => 1},
- {name => 'bug_group', desc => 'Group', in_new_bugmail => 1},
- {name => 'estimated_time', desc => 'Estimated Hours',
- in_new_bugmail => 1, buglist => 1, is_numeric => 1},
- {name => 'remaining_time', desc => 'Remaining Hours', buglist => 1,
- is_numeric => 1},
- {name => 'deadline', desc => 'Deadline',
- type => FIELD_TYPE_DATETIME, in_new_bugmail => 1, buglist => 1},
- {name => 'commenter', desc => 'Commenter'},
- {name => 'flagtypes.name', desc => 'Flags', buglist => 1},
- {name => 'requestees.login_name', desc => 'Flag Requestee'},
- {name => 'setters.login_name', desc => 'Flag Setter'},
- {name => 'work_time', desc => 'Hours Worked', buglist => 1,
- is_numeric => 1},
- {name => 'percentage_complete', desc => 'Percentage Complete',
- buglist => 1, is_numeric => 1},
- {name => 'content', desc => 'Content'},
- {name => 'attach_data.thedata', desc => 'Attachment data'},
- {name => "owner_idle_time", desc => "Time Since Assignee Touched"},
- {name => 'see_also', desc => "See Also",
- type => FIELD_TYPE_BUG_URLS},
- {name => 'tag', desc => 'Tags'},
- {name => 'last_visit_ts', desc => 'Last Visit', buglist => 1,
- type => FIELD_TYPE_DATETIME},
- {name => 'bug_interest_ts', desc => 'Bug Interest', buglist => 1,
- type => FIELD_TYPE_DATETIME},
- {name => 'comment_tag', desc => 'Comment Tag'},
- {name => 'triage_owner', desc => 'Triage Owner', buglist => 1},
+ {
+ name => 'bug_id',
+ desc => 'Bug #',
+ in_new_bugmail => 1,
+ buglist => 1,
+ is_numeric => 1
+ },
+ {
+ name => 'short_desc',
+ desc => 'Summary',
+ in_new_bugmail => 1,
+ is_mandatory => 1,
+ buglist => 1
+ },
+ {
+ name => 'classification',
+ desc => 'Classification',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'product',
+ desc => 'Product',
+ in_new_bugmail => 1,
+ is_mandatory => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'component',
+ desc => 'Component',
+ in_new_bugmail => 1,
+ is_mandatory => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'version',
+ desc => 'Version',
+ in_new_bugmail => 1,
+ is_mandatory => 1,
+ buglist => 1
+ },
+ {
+ name => 'rep_platform',
+ desc => 'Platform',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {name => 'bug_file_loc', desc => 'URL', in_new_bugmail => 1, buglist => 1},
+ {
+ name => 'op_sys',
+ desc => 'OS/Version',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'bug_status',
+ desc => 'Status',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'status_whiteboard',
+ desc => 'Status Whiteboard',
+ in_new_bugmail => 1,
+ buglist => 1
+ },
+ {
+ name => 'keywords',
+ desc => 'Keywords',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_KEYWORDS,
+ buglist => 1
+ },
+ {
+ name => 'resolution',
+ desc => 'Resolution',
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'bug_severity',
+ desc => 'Severity',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'priority',
+ desc => 'Priority',
+ in_new_bugmail => 1,
+ type => FIELD_TYPE_SINGLE_SELECT,
+ buglist => 1
+ },
+ {
+ name => 'assigned_to',
+ desc => 'AssignedTo',
+ in_new_bugmail => 1,
+ buglist => 1
+ },
+ {name => 'reporter', desc => 'ReportedBy', in_new_bugmail => 1, buglist => 1},
+ {name => 'qa_contact', desc => 'QAContact', in_new_bugmail => 1, buglist => 1},
+ {name => 'cc', desc => 'CC', in_new_bugmail => 1},
+ {
+ name => 'dependson',
+ desc => 'Depends on',
+ in_new_bugmail => 1,
+ is_numeric => 1,
+ buglist => 1
+ },
+ {
+ name => 'blocked',
+ desc => 'Blocks',
+ in_new_bugmail => 1,
+ is_numeric => 1,
+ buglist => 1
+ },
+
+ {
+ name => 'assignee_last_login',
+ desc => 'Assignee Last Login Date',
+ buglist => 1
+ },
+
+ {name => 'attachments.description', desc => 'Attachment description'},
+ {name => 'attachments.filename', desc => 'Attachment filename'},
+ {name => 'attachments.mimetype', desc => 'Attachment mime type'},
+ {name => 'attachments.ispatch', desc => 'Attachment is patch', is_numeric => 1},
+ {
+ name => 'attachments.isobsolete',
+ desc => 'Attachment is obsolete',
+ is_numeric => 1
+ },
+ {
+ name => 'attachments.isprivate',
+ desc => 'Attachment is private',
+ is_numeric => 1
+ },
+ {name => 'attachments.submitter', desc => 'Attachment creator'},
+
+ {name => 'target_milestone', desc => 'Target Milestone', buglist => 1},
+ {name => 'creation_ts', desc => 'Creation date', buglist => 1},
+ {name => 'delta_ts', desc => 'Last changed date', buglist => 1},
+ {name => 'longdesc', desc => 'Comment'},
+ {name => 'longdescs.isprivate', desc => 'Comment is private', is_numeric => 1},
+ {
+ name => 'longdescs.count',
+ desc => 'Number of Comments',
+ buglist => 1,
+ is_numeric => 1
+ },
+ {name => 'alias', desc => 'Alias', buglist => 1},
+ {name => 'everconfirmed', desc => 'Ever Confirmed', is_numeric => 1},
+ {name => 'reporter_accessible', desc => 'Reporter Accessible', is_numeric => 1},
+ {name => 'cclist_accessible', desc => 'CC Accessible', is_numeric => 1},
+ {name => 'bug_group', desc => 'Group', in_new_bugmail => 1},
+ {
+ name => 'estimated_time',
+ desc => 'Estimated Hours',
+ in_new_bugmail => 1,
+ buglist => 1,
+ is_numeric => 1
+ },
+ {
+ name => 'remaining_time',
+ desc => 'Remaining Hours',
+ buglist => 1,
+ is_numeric => 1
+ },
+ {
+ name => 'deadline',
+ desc => 'Deadline',
+ type => FIELD_TYPE_DATETIME,
+ in_new_bugmail => 1,
+ buglist => 1
+ },
+ {name => 'commenter', desc => 'Commenter'},
+ {name => 'flagtypes.name', desc => 'Flags', buglist => 1},
+ {name => 'requestees.login_name', desc => 'Flag Requestee'},
+ {name => 'setters.login_name', desc => 'Flag Setter'},
+ {name => 'work_time', desc => 'Hours Worked', buglist => 1, is_numeric => 1},
+ {
+ name => 'percentage_complete',
+ desc => 'Percentage Complete',
+ buglist => 1,
+ is_numeric => 1
+ },
+ {name => 'content', desc => 'Content'},
+ {name => 'attach_data.thedata', desc => 'Attachment data'},
+ {name => "owner_idle_time", desc => "Time Since Assignee Touched"},
+ {name => 'see_also', desc => "See Also", type => FIELD_TYPE_BUG_URLS},
+ {name => 'tag', desc => 'Tags'},
+ {
+ name => 'last_visit_ts',
+ desc => 'Last Visit',
+ buglist => 1,
+ type => FIELD_TYPE_DATETIME
+ },
+ {
+ name => 'bug_interest_ts',
+ desc => 'Bug Interest',
+ buglist => 1,
+ type => FIELD_TYPE_DATETIME
+ },
+ {name => 'comment_tag', desc => 'Comment Tag'},
+ {name => 'triage_owner', desc => 'Triage Owner', buglist => 1},
);
################
@@ -274,15 +382,15 @@ use constant DEFAULT_FIELDS => (
# Override match to add is_select.
sub match {
- my $self = shift;
- my ($params) = @_;
- if (delete $params->{is_select}) {
- $params->{type} = [FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT];
- }
- if (delete $params->{skip_extensions}) {
- $params->{WHERE}{'type != ?'} = FIELD_TYPE_EXTENSION;
- }
- return $self->SUPER::match(@_);
+ my $self = shift;
+ my ($params) = @_;
+ if (delete $params->{is_select}) {
+ $params->{type} = [FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT];
+ }
+ if (delete $params->{skip_extensions}) {
+ $params->{WHERE}{'type != ?'} = FIELD_TYPE_EXTENSION;
+ }
+ return $self->SUPER::match(@_);
}
##############
@@ -292,142 +400,144 @@ sub match {
sub _check_custom { return $_[1] ? 1 : 0; }
sub _check_description {
- my ($invocant, $desc) = @_;
- $desc = clean_text($desc);
- $desc || ThrowUserError('field_missing_description');
- return $desc;
+ my ($invocant, $desc) = @_;
+ $desc = clean_text($desc);
+ $desc || ThrowUserError('field_missing_description');
+ return $desc;
}
sub _check_enter_bug { return $_[1] ? 1 : 0; }
sub _check_is_numeric {
- my ($invocant, $value, undef, $params) = @_;
- my $type = blessed($invocant) ? $invocant->type : $params->{type};
- return 1 if $type == FIELD_TYPE_BUG_ID;
- return $value ? 1 : 0;
+ my ($invocant, $value, undef, $params) = @_;
+ my $type = blessed($invocant) ? $invocant->type : $params->{type};
+ return 1 if $type == FIELD_TYPE_BUG_ID;
+ return $value ? 1 : 0;
}
sub _check_mailhead { return $_[1] ? 1 : 0; }
sub _check_name {
- my ($class, $name, undef, $params) = @_;
- $name = lc(clean_text($name));
- $name || ThrowUserError('field_missing_name');
-
- # Don't want to allow a name that might mess up SQL.
- my $name_regex = qr/^[\w\.]+$/;
- # Custom fields have more restrictive name requirements than
- # standard fields.
- $name_regex = qr/^[a-zA-Z0-9_]+$/ if $params->{custom};
- # Custom fields can't be named just "cf_", and there is no normal
- # field named just "cf_".
- ($name =~ $name_regex && $name ne "cf_")
- || ThrowUserError('field_invalid_name', { name => $name });
-
- # If it's custom, prepend cf_ to the custom field name to distinguish
- # it from standard fields.
- if ($name !~ /^cf_/ && $params->{custom}) {
- $name = 'cf_' . $name;
- }
+ my ($class, $name, undef, $params) = @_;
+ $name = lc(clean_text($name));
+ $name || ThrowUserError('field_missing_name');
+
+ # Don't want to allow a name that might mess up SQL.
+ my $name_regex = qr/^[\w\.]+$/;
+
+ # Custom fields have more restrictive name requirements than
+ # standard fields.
+ $name_regex = qr/^[a-zA-Z0-9_]+$/ if $params->{custom};
+
+ # Custom fields can't be named just "cf_", and there is no normal
+ # field named just "cf_".
+ ($name =~ $name_regex && $name ne "cf_")
+ || ThrowUserError('field_invalid_name', {name => $name});
+
+ # If it's custom, prepend cf_ to the custom field name to distinguish
+ # it from standard fields.
+ if ($name !~ /^cf_/ && $params->{custom}) {
+ $name = 'cf_' . $name;
+ }
- # Assure the name is unique. Names can't be changed, so we don't have
- # to worry about what to do on updates.
- my $field = new Bugzilla::Field({ name => $name });
- ThrowUserError('field_already_exists', {'field' => $field }) if $field;
+ # Assure the name is unique. Names can't be changed, so we don't have
+ # to worry about what to do on updates.
+ my $field = new Bugzilla::Field({name => $name});
+ ThrowUserError('field_already_exists', {'field' => $field}) if $field;
- return $name;
+ return $name;
}
sub _check_obsolete { return $_[1] ? 1 : 0; }
sub _check_sortkey {
- my ($invocant, $sortkey) = @_;
- my $skey = $sortkey;
- if (!defined $skey || $skey eq '') {
- ($sortkey) = Bugzilla->dbh->selectrow_array(
- 'SELECT MAX(sortkey) + 100 FROM fielddefs') || 100;
- }
- detaint_natural($sortkey)
- || ThrowUserError('field_invalid_sortkey', { sortkey => $skey });
- return $sortkey;
+ my ($invocant, $sortkey) = @_;
+ my $skey = $sortkey;
+ if (!defined $skey || $skey eq '') {
+ ($sortkey)
+ = Bugzilla->dbh->selectrow_array('SELECT MAX(sortkey) + 100 FROM fielddefs')
+ || 100;
+ }
+ detaint_natural($sortkey)
+ || ThrowUserError('field_invalid_sortkey', {sortkey => $skey});
+ return $sortkey;
}
sub _check_type {
- my ($invocant, $type, undef, $params) = @_;
- my $saved_type = $type;
- (detaint_natural($type) && $type < FIELD_TYPE_HIGHEST_PLUS_ONE)
- || ThrowCodeError('invalid_customfield_type', { type => $saved_type });
-
- my $custom = blessed($invocant) ? $invocant->custom : $params->{custom};
- if ($custom && !$type) {
- ThrowCodeError('field_type_not_specified');
- }
+ my ($invocant, $type, undef, $params) = @_;
+ my $saved_type = $type;
+ (detaint_natural($type) && $type < FIELD_TYPE_HIGHEST_PLUS_ONE)
+ || ThrowCodeError('invalid_customfield_type', {type => $saved_type});
+
+ my $custom = blessed($invocant) ? $invocant->custom : $params->{custom};
+ if ($custom && !$type) {
+ ThrowCodeError('field_type_not_specified');
+ }
- return $type;
+ return $type;
}
sub _check_value_field_id {
- my ($invocant, $field_id, undef, $params) = @_;
- my $is_select = $invocant->is_select($params);
- if ($field_id && !$is_select) {
- ThrowUserError('field_value_control_select_only');
- }
- return $invocant->_check_visibility_field_id($field_id);
+ my ($invocant, $field_id, undef, $params) = @_;
+ my $is_select = $invocant->is_select($params);
+ if ($field_id && !$is_select) {
+ ThrowUserError('field_value_control_select_only');
+ }
+ return $invocant->_check_visibility_field_id($field_id);
}
sub _check_visibility_field_id {
- my ($invocant, $field_id) = @_;
- $field_id = trim($field_id);
- return undef if !$field_id;
- my $field = Bugzilla::Field->check({ id => $field_id });
- if (blessed($invocant) && $field->id == $invocant->id) {
- ThrowUserError('field_cant_control_self', { field => $field });
- }
- if (!$field->is_select) {
- ThrowUserError('field_control_must_be_select',
- { field => $field });
- }
- return $field->id;
+ my ($invocant, $field_id) = @_;
+ $field_id = trim($field_id);
+ return undef if !$field_id;
+ my $field = Bugzilla::Field->check({id => $field_id});
+ if (blessed($invocant) && $field->id == $invocant->id) {
+ ThrowUserError('field_cant_control_self', {field => $field});
+ }
+ if (!$field->is_select) {
+ ThrowUserError('field_control_must_be_select', {field => $field});
+ }
+ return $field->id;
}
sub _check_visibility_values {
- my ($invocant, $values, undef, $params) = @_;
- my $field;
- if (blessed $invocant) {
- $field = $invocant->visibility_field;
- }
- elsif ($params->{visibility_field_id}) {
- $field = $invocant->new($params->{visibility_field_id});
- }
- # When no field is set, no values are set.
- return [] if !$field;
+ my ($invocant, $values, undef, $params) = @_;
+ my $field;
+ if (blessed $invocant) {
+ $field = $invocant->visibility_field;
+ }
+ elsif ($params->{visibility_field_id}) {
+ $field = $invocant->new($params->{visibility_field_id});
+ }
- if (!scalar @$values) {
- ThrowUserError('field_visibility_values_must_be_selected',
- { field => $field });
- }
+ # When no field is set, no values are set.
+ return [] if !$field;
+
+ if (!scalar @$values) {
+ ThrowUserError('field_visibility_values_must_be_selected', {field => $field});
+ }
- my @visibility_values;
- my $choice = Bugzilla::Field::Choice->type($field);
- foreach my $value (@$values) {
- if (!blessed $value) {
- $value = $choice->check({ id => $value });
- }
- push(@visibility_values, $value);
+ my @visibility_values;
+ my $choice = Bugzilla::Field::Choice->type($field);
+ foreach my $value (@$values) {
+ if (!blessed $value) {
+ $value = $choice->check({id => $value});
}
+ push(@visibility_values, $value);
+ }
- return \@visibility_values;
+ return \@visibility_values;
}
sub _check_reverse_desc {
- my ($invocant, $reverse_desc, undef, $params) = @_;
- my $type = blessed($invocant) ? $invocant->type : $params->{type};
- if ($type != FIELD_TYPE_BUG_ID) {
- return undef; # store NULL for non-reversible field types
- }
+ my ($invocant, $reverse_desc, undef, $params) = @_;
+ my $type = blessed($invocant) ? $invocant->type : $params->{type};
+ if ($type != FIELD_TYPE_BUG_ID) {
+ return undef; # store NULL for non-reversible field types
+ }
- $reverse_desc = clean_text($reverse_desc);
- return $reverse_desc;
+ $reverse_desc = clean_text($reverse_desc);
+ return $reverse_desc;
}
sub _check_is_mandatory { return $_[1] ? 1 : 0; }
@@ -563,11 +673,13 @@ objects.
=cut
sub is_select {
- my ($invocant, $params) = @_;
- # This allows this method to be called by create() validators.
- my $type = blessed($invocant) ? $invocant->type : $params->{type};
- return ($type == FIELD_TYPE_SINGLE_SELECT
- || $type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0
+ my ($invocant, $params) = @_;
+
+ # This allows this method to be called by create() validators.
+ my $type = blessed($invocant) ? $invocant->type : $params->{type};
+ return ($type == FIELD_TYPE_SINGLE_SELECT || $type == FIELD_TYPE_MULTI_SELECT)
+ ? 1
+ : 0;
}
=over
@@ -588,19 +700,19 @@ This method returns C<1> if the field is "abnormal", C<0> otherwise.
=cut
sub is_abnormal {
- my $self = shift;
- return ABNORMAL_SELECTS->{$self->name} ? 1 : 0;
+ my $self = shift;
+ return ABNORMAL_SELECTS->{$self->name} ? 1 : 0;
}
sub legal_values {
- my $self = shift;
+ my $self = shift;
- if (!defined $self->{'legal_values'}) {
- require Bugzilla::Field::Choice;
- my @values = Bugzilla::Field::Choice->type($self)->get_all();
- $self->{'legal_values'} = \@values;
- }
- return $self->{'legal_values'};
+ if (!defined $self->{'legal_values'}) {
+ require Bugzilla::Field::Choice;
+ my @values = Bugzilla::Field::Choice->type($self)->get_all();
+ $self->{'legal_values'} = \@values;
+ }
+ return $self->{'legal_values'};
}
=pod
@@ -617,8 +729,8 @@ in the C<timetrackinggroup>.
=cut
sub is_timetracking {
- my ($self) = @_;
- return grep($_ eq $self->name, TIMETRACKING_FIELDS) ? 1 : 0;
+ my ($self) = @_;
+ return grep($_ eq $self->name, TIMETRACKING_FIELDS) ? 1 : 0;
}
=pod
@@ -637,12 +749,12 @@ Returns undef if there is no field that controls this field's visibility.
=cut
sub visibility_field {
- my $self = shift;
- if ($self->{visibility_field_id}) {
- $self->{visibility_field} ||=
- $self->new({ id => $self->{visibility_field_id}, cache => 1 });
- }
- return $self->{visibility_field};
+ my $self = shift;
+ if ($self->{visibility_field_id}) {
+ $self->{visibility_field}
+ ||= $self->new({id => $self->{visibility_field_id}, cache => 1});
+ }
+ return $self->{visibility_field};
}
=pod
@@ -660,22 +772,23 @@ or undef if there is no C<visibility_field> set.
=cut
sub visibility_values {
- my $self = shift;
- my $dbh = Bugzilla->dbh;
+ my $self = shift;
+ my $dbh = Bugzilla->dbh;
- return [] if !$self->{visibility_field_id};
+ return [] if !$self->{visibility_field_id};
- if (!defined $self->{visibility_values}) {
- my $visibility_value_ids =
- $dbh->selectcol_arrayref("SELECT value_id FROM field_visibility
- WHERE field_id = ?", undef, $self->id);
+ if (!defined $self->{visibility_values}) {
+ my $visibility_value_ids = $dbh->selectcol_arrayref(
+ "SELECT value_id FROM field_visibility
+ WHERE field_id = ?", undef, $self->id
+ );
- $self->{visibility_values} =
- Bugzilla::Field::Choice->type($self->visibility_field)
- ->new_from_list($visibility_value_ids);
- }
+ $self->{visibility_values}
+ = Bugzilla::Field::Choice->type($self->visibility_field)
+ ->new_from_list($visibility_value_ids);
+ }
- return $self->{visibility_values};
+ return $self->{visibility_values};
}
=pod
@@ -692,10 +805,10 @@ field controls the visibility of.
=cut
sub controls_visibility_of {
- my $self = shift;
- $self->{controls_visibility_of} ||=
- Bugzilla::Field->match({ visibility_field_id => $self->id });
- return $self->{controls_visibility_of};
+ my $self = shift;
+ $self->{controls_visibility_of}
+ ||= Bugzilla::Field->match({visibility_field_id => $self->id});
+ return $self->{controls_visibility_of};
}
=pod
@@ -713,11 +826,11 @@ Returns undef if there is no field that controls this field's visibility.
=cut
sub value_field {
- my $self = shift;
- if ($self->{value_field_id}) {
- $self->{value_field} ||= $self->new($self->{value_field_id});
- }
- return $self->{value_field};
+ my $self = shift;
+ if ($self->{value_field_id}) {
+ $self->{value_field} ||= $self->new($self->{value_field_id});
+ }
+ return $self->{value_field};
}
=pod
@@ -734,10 +847,10 @@ field controls the values of.
=cut
sub controls_values_of {
- my $self = shift;
- $self->{controls_values_of} ||=
- Bugzilla::Field->match({ value_field_id => $self->id });
- return $self->{controls_values_of};
+ my $self = shift;
+ $self->{controls_values_of}
+ ||= Bugzilla::Field->match({value_field_id => $self->id});
+ return $self->{controls_values_of};
}
=over
@@ -751,15 +864,15 @@ See L<Bugzilla::Field::ChoiceInterface>.
=cut
sub is_visible_on_bug {
- my ($self, $bug) = @_;
+ my ($self, $bug) = @_;
- # Always return visible, if this field is not
- # visibility controlled.
- return 1 if !$self->{visibility_field_id};
+ # Always return visible, if this field is not
+ # visibility controlled.
+ return 1 if !$self->{visibility_field_id};
- my $visibility_values = $self->visibility_values;
+ my $visibility_values = $self->visibility_values;
- return (any { $_->is_set_on_bug($bug) } @$visibility_values) ? 1 : 0;
+ return (any { $_->is_set_on_bug($bug) } @$visibility_values) ? 1 : 0;
}
=over
@@ -775,13 +888,13 @@ dependency tree display, and similar functionality.
=cut
-sub is_relationship {
- my $self = shift;
- my $desc = $self->reverse_desc;
- if (defined $desc && $desc ne "") {
- return 1;
- }
- return 0;
+sub is_relationship {
+ my $self = shift;
+ my $desc = $self->reverse_desc;
+ if (defined $desc && $desc ne "") {
+ return 1;
+ }
+ return 0;
}
=over
@@ -866,28 +979,31 @@ They will throw an error if you try to set the values to something invalid.
=cut
-sub set_description { $_[0]->set('description', $_[1]); }
-sub set_enter_bug { $_[0]->set('enter_bug', $_[1]); }
-sub set_is_numeric { $_[0]->set('is_numeric', $_[1]); }
-sub set_obsolete { $_[0]->set('obsolete', $_[1]); }
-sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
-sub set_in_new_bugmail { $_[0]->set('mailhead', $_[1]); }
-sub set_buglist { $_[0]->set('buglist', $_[1]); }
-sub set_reverse_desc { $_[0]->set('reverse_desc', $_[1]); }
+sub set_description { $_[0]->set('description', $_[1]); }
+sub set_enter_bug { $_[0]->set('enter_bug', $_[1]); }
+sub set_is_numeric { $_[0]->set('is_numeric', $_[1]); }
+sub set_obsolete { $_[0]->set('obsolete', $_[1]); }
+sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
+sub set_in_new_bugmail { $_[0]->set('mailhead', $_[1]); }
+sub set_buglist { $_[0]->set('buglist', $_[1]); }
+sub set_reverse_desc { $_[0]->set('reverse_desc', $_[1]); }
+
sub set_visibility_field {
- my ($self, $value) = @_;
- $self->set('visibility_field_id', $value);
- delete $self->{visibility_field};
- delete $self->{visibility_values};
+ my ($self, $value) = @_;
+ $self->set('visibility_field_id', $value);
+ delete $self->{visibility_field};
+ delete $self->{visibility_values};
}
+
sub set_visibility_values {
- my ($self, $value_ids) = @_;
- $self->set('visibility_values', $value_ids);
+ my ($self, $value_ids) = @_;
+ $self->set('visibility_values', $value_ids);
}
+
sub set_value_field {
- my ($self, $value) = @_;
- $self->set('value_field_id', $value);
- delete $self->{value_field};
+ my ($self, $value) = @_;
+ $self->set('value_field_id', $value);
+ delete $self->{value_field};
}
sub set_is_mandatory { $_[0]->set('is_mandatory', $_[1]); }
@@ -911,83 +1027,87 @@ there are no values specified (or EVER specified) for the field.
=cut
sub remove_from_db {
- my $self = shift;
- my $dbh = Bugzilla->dbh;
+ my $self = shift;
+ my $dbh = Bugzilla->dbh;
+
+ my $name = $self->name;
+
+ if (!$self->custom) {
+ ThrowCodeError('field_not_custom', {'name' => $name});
+ }
+
+ if (!$self->obsolete) {
+ ThrowUserError('customfield_not_obsolete', {'name' => $self->name});
+ }
+
+ # BMO: disable bug updates during field creation
+ # using an eval as try/finally
+ eval {
+ SetParam('disable_bug_updates', 1);
+ write_params();
+
+ $dbh->bz_start_transaction();
+
+ # Check to see if bug activity table has records (should be fast with index)
+ my $has_activity = $dbh->selectrow_array(
+ "SELECT COUNT(*) FROM bugs_activity
+ WHERE fieldid = ?", undef, $self->id
+ );
+ if ($has_activity) {
+ ThrowUserError('customfield_has_activity', {'name' => $name});
+ }
- my $name = $self->name;
+ # Check to see if bugs table has records (slow)
+ my $bugs_query = "";
- if (!$self->custom) {
- ThrowCodeError('field_not_custom', {'name' => $name });
+ if ($self->type == FIELD_TYPE_MULTI_SELECT) {
+ $bugs_query = "SELECT COUNT(*) FROM bug_$name";
+ }
+ else {
+ $bugs_query = "SELECT COUNT(*) FROM bugs WHERE $name IS NOT NULL";
+ if ( $self->type != FIELD_TYPE_BUG_ID
+ && $self->type != FIELD_TYPE_DATE
+ && $self->type != FIELD_TYPE_DATETIME)
+ {
+ $bugs_query .= " AND $name != ''";
+ }
+
+ # Ignore the default single select value
+ if ($self->type == FIELD_TYPE_SINGLE_SELECT) {
+ $bugs_query .= " AND $name != '---'";
+ }
}
- if (!$self->obsolete) {
- ThrowUserError('customfield_not_obsolete', {'name' => $self->name });
+ my $has_bugs = $dbh->selectrow_array($bugs_query);
+ if ($has_bugs) {
+ ThrowUserError('customfield_has_contents', {'name' => $name});
}
- # BMO: disable bug updates during field creation
- # using an eval as try/finally
- eval {
- SetParam('disable_bug_updates', 1);
- write_params();
-
- $dbh->bz_start_transaction();
-
- # Check to see if bug activity table has records (should be fast with index)
- my $has_activity = $dbh->selectrow_array("SELECT COUNT(*) FROM bugs_activity
- WHERE fieldid = ?", undef, $self->id);
- if ($has_activity) {
- ThrowUserError('customfield_has_activity', {'name' => $name });
- }
-
- # Check to see if bugs table has records (slow)
- my $bugs_query = "";
-
- if ($self->type == FIELD_TYPE_MULTI_SELECT) {
- $bugs_query = "SELECT COUNT(*) FROM bug_$name";
- }
- else {
- $bugs_query = "SELECT COUNT(*) FROM bugs WHERE $name IS NOT NULL";
- if ($self->type != FIELD_TYPE_BUG_ID
- && $self->type != FIELD_TYPE_DATE
- && $self->type != FIELD_TYPE_DATETIME)
- {
- $bugs_query .= " AND $name != ''";
- }
- # Ignore the default single select value
- if ($self->type == FIELD_TYPE_SINGLE_SELECT) {
- $bugs_query .= " AND $name != '---'";
- }
- }
-
- my $has_bugs = $dbh->selectrow_array($bugs_query);
- if ($has_bugs) {
- ThrowUserError('customfield_has_contents', {'name' => $name });
- }
-
- # Once we reach here, we should be OK to delete.
- $dbh->do('DELETE FROM fielddefs WHERE id = ?', undef, $self->id);
-
- my $type = $self->type;
-
- # the values for multi-select are stored in a seperate table
- if ($type != FIELD_TYPE_MULTI_SELECT) {
- $dbh->bz_drop_column('bugs', $name);
- }
-
- if ($self->is_select) {
- # Delete the table that holds the legal values for this field.
- $dbh->bz_drop_field_tables($self);
- }
-
- Bugzilla->memcached->clear({ table => 'fielddefs', id => $self->id });
- Bugzilla->memcached->clear_config();
-
- $dbh->bz_commit_transaction();
- };
- my $error = "$@";
- SetParam('disable_bug_updates', 0);
- write_params();
- die $error if $error;
+ # Once we reach here, we should be OK to delete.
+ $dbh->do('DELETE FROM fielddefs WHERE id = ?', undef, $self->id);
+
+ my $type = $self->type;
+
+ # the values for multi-select are stored in a seperate table
+ if ($type != FIELD_TYPE_MULTI_SELECT) {
+ $dbh->bz_drop_column('bugs', $name);
+ }
+
+ if ($self->is_select) {
+
+ # Delete the table that holds the legal values for this field.
+ $dbh->bz_drop_field_tables($self);
+ }
+
+ Bugzilla->memcached->clear({table => 'fielddefs', id => $self->id});
+ Bugzilla->memcached->clear_config();
+
+ $dbh->bz_commit_transaction();
+ };
+ my $error = "$@";
+ SetParam('disable_bug_updates', 0);
+ write_params();
+ die $error if $error;
}
=pod
@@ -1031,109 +1151,114 @@ C<is_mandatory> - boolean - Whether this field is mandatory. Defaults to 0.
=cut
sub create {
- my $class = shift;
- my ($params) = @_;
- my $dbh = Bugzilla->dbh;
-
- # BMO: disable bug updates during field creation
- # using an eval as try/finally
- my $field;
- eval {
- if ($params->{'custom'}) {
- SetParam('disable_bug_updates', 1);
- write_params();
- }
-
- # This makes sure the "sortkey" validator runs, even if
- # the parameter isn't sent to create().
- $params->{sortkey} = undef if !exists $params->{sortkey};
- $params->{type} ||= 0;
- # We mark the custom field as obsolete till it has been fully created,
- # to avoid race conditions when viewing bugs at the same time.
- my $is_obsolete = $params->{obsolete};
- $params->{obsolete} = 1 if $params->{custom};
-
- $dbh->bz_start_transaction();
- $class->check_required_create_fields(@_);
- my $field_values = $class->run_create_validators($params);
- my $visibility_values = delete $field_values->{visibility_values};
- $field = $class->insert_create_data($field_values);
-
- $field->set_visibility_values($visibility_values);
- $field->_update_visibility_values();
-
- $dbh->bz_commit_transaction();
- Bugzilla->memcached->clear_config();
-
- if ($field->custom) {
- my $name = $field->name;
- my $type = $field->type;
- if (SQL_DEFINITIONS->{$type}) {
- # Create the database column that stores the data for this field.
- $dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type});
- }
-
- if ($field->is_select) {
- # Create the table that holds the legal values for this field.
- $dbh->bz_add_field_tables($field);
- }
-
- if ($type == FIELD_TYPE_SINGLE_SELECT) {
- # Insert a default value of "---" into the legal values table.
- $dbh->do("INSERT INTO $name (value) VALUES ('---')");
- }
-
- # Restore the original obsolete state of the custom field.
- $dbh->do('UPDATE fielddefs SET obsolete = 0 WHERE id = ?', undef, $field->id)
- unless $is_obsolete;
-
- Bugzilla->memcached->clear({ table => 'fielddefs', id => $field->id });
- Bugzilla->memcached->clear_config();
- }
- };
-
- my $error = "$@";
+ my $class = shift;
+ my ($params) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ # BMO: disable bug updates during field creation
+ # using an eval as try/finally
+ my $field;
+ eval {
if ($params->{'custom'}) {
- SetParam('disable_bug_updates', 0);
- write_params();
+ SetParam('disable_bug_updates', 1);
+ write_params();
}
- die $error if $error;
- Bugzilla::Hook::process("field_end_of_create", { field => $field });
+ # This makes sure the "sortkey" validator runs, even if
+ # the parameter isn't sent to create().
+ $params->{sortkey} = undef if !exists $params->{sortkey};
+ $params->{type} ||= 0;
- return $field;
+ # We mark the custom field as obsolete till it has been fully created,
+ # to avoid race conditions when viewing bugs at the same time.
+ my $is_obsolete = $params->{obsolete};
+ $params->{obsolete} = 1 if $params->{custom};
+
+ $dbh->bz_start_transaction();
+ $class->check_required_create_fields(@_);
+ my $field_values = $class->run_create_validators($params);
+ my $visibility_values = delete $field_values->{visibility_values};
+ $field = $class->insert_create_data($field_values);
+
+ $field->set_visibility_values($visibility_values);
+ $field->_update_visibility_values();
+
+ $dbh->bz_commit_transaction();
+ Bugzilla->memcached->clear_config();
+
+ if ($field->custom) {
+ my $name = $field->name;
+ my $type = $field->type;
+ if (SQL_DEFINITIONS->{$type}) {
+
+ # Create the database column that stores the data for this field.
+ $dbh->bz_add_column('bugs', $name, SQL_DEFINITIONS->{$type});
+ }
+
+ if ($field->is_select) {
+
+ # Create the table that holds the legal values for this field.
+ $dbh->bz_add_field_tables($field);
+ }
+
+ if ($type == FIELD_TYPE_SINGLE_SELECT) {
+
+ # Insert a default value of "---" into the legal values table.
+ $dbh->do("INSERT INTO $name (value) VALUES ('---')");
+ }
+
+ # Restore the original obsolete state of the custom field.
+ $dbh->do('UPDATE fielddefs SET obsolete = 0 WHERE id = ?', undef, $field->id)
+ unless $is_obsolete;
+
+ Bugzilla->memcached->clear({table => 'fielddefs', id => $field->id});
+ Bugzilla->memcached->clear_config();
+ }
+ };
+
+ my $error = "$@";
+ if ($params->{'custom'}) {
+ SetParam('disable_bug_updates', 0);
+ write_params();
+ }
+ die $error if $error;
+
+ Bugzilla::Hook::process("field_end_of_create", {field => $field});
+
+ return $field;
}
sub update {
- my $self = shift;
- my $changes = $self->SUPER::update(@_);
- my $dbh = Bugzilla->dbh;
- if ($changes->{value_field_id} && $self->is_select) {
- $dbh->do("UPDATE " . $self->name . " SET visibility_value_id = NULL");
- }
- $self->_update_visibility_values();
- Bugzilla->memcached->clear_config();
- return $changes;
+ my $self = shift;
+ my $changes = $self->SUPER::update(@_);
+ my $dbh = Bugzilla->dbh;
+ if ($changes->{value_field_id} && $self->is_select) {
+ $dbh->do("UPDATE " . $self->name . " SET visibility_value_id = NULL");
+ }
+ $self->_update_visibility_values();
+ Bugzilla->memcached->clear_config();
+ return $changes;
}
sub _update_visibility_values {
- my $self = shift;
- my $dbh = Bugzilla->dbh;
-
- my @visibility_value_ids = map($_->id, @{$self->visibility_values});
- $self->_delete_visibility_values();
- for my $value_id (@visibility_value_ids) {
- $dbh->do("INSERT INTO field_visibility (field_id, value_id)
- VALUES (?, ?)", undef, $self->id, $value_id);
- }
+ my $self = shift;
+ my $dbh = Bugzilla->dbh;
+
+ my @visibility_value_ids = map($_->id, @{$self->visibility_values});
+ $self->_delete_visibility_values();
+ for my $value_id (@visibility_value_ids) {
+ $dbh->do(
+ "INSERT INTO field_visibility (field_id, value_id)
+ VALUES (?, ?)", undef, $self->id, $value_id
+ );
+ }
}
sub _delete_visibility_values {
- my ($self) = @_;
- my $dbh = Bugzilla->dbh;
- $dbh->do("DELETE FROM field_visibility WHERE field_id = ?",
- undef, $self->id);
- delete $self->{visibility_values};
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
+ $dbh->do("DELETE FROM field_visibility WHERE field_id = ?", undef, $self->id);
+ delete $self->{visibility_values};
}
=pod
@@ -1156,13 +1281,14 @@ Returns: a reference to a list of valid values.
=cut
sub get_legal_field_values {
- my ($field) = @_;
- my $dbh = Bugzilla->dbh;
- my $result_ref = $dbh->selectcol_arrayref(
- "SELECT value FROM $field
+ my ($field) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $result_ref = $dbh->selectcol_arrayref(
+ "SELECT value FROM $field
WHERE isactive = ?
- ORDER BY sortkey, value", undef, (1));
- return $result_ref;
+ ORDER BY sortkey, value", undef, (1)
+ );
+ return $result_ref;
}
=over
@@ -1181,107 +1307,115 @@ Returns: nothing
=cut
sub populate_field_definitions {
- my $dbh = Bugzilla->dbh;
-
- # ADD and UPDATE field definitions
- foreach my $def (DEFAULT_FIELDS) {
- my $field = new Bugzilla::Field({ name => $def->{name} });
- if ($field) {
- $field->set_description($def->{desc});
- $field->set_in_new_bugmail($def->{in_new_bugmail});
- $field->set_buglist($def->{buglist});
- $field->_set_type($def->{type}) if $def->{type};
- $field->set_is_mandatory($def->{is_mandatory});
- $field->set_is_numeric($def->{is_numeric});
- $field->update();
- }
- else {
- if (exists $def->{in_new_bugmail}) {
- $def->{mailhead} = $def->{in_new_bugmail};
- delete $def->{in_new_bugmail};
- }
- $def->{description} = delete $def->{desc};
- Bugzilla::Field->create($def);
- }
+ my $dbh = Bugzilla->dbh;
+
+ # ADD and UPDATE field definitions
+ foreach my $def (DEFAULT_FIELDS) {
+ my $field = new Bugzilla::Field({name => $def->{name}});
+ if ($field) {
+ $field->set_description($def->{desc});
+ $field->set_in_new_bugmail($def->{in_new_bugmail});
+ $field->set_buglist($def->{buglist});
+ $field->_set_type($def->{type}) if $def->{type};
+ $field->set_is_mandatory($def->{is_mandatory});
+ $field->set_is_numeric($def->{is_numeric});
+ $field->update();
+ }
+ else {
+ if (exists $def->{in_new_bugmail}) {
+ $def->{mailhead} = $def->{in_new_bugmail};
+ delete $def->{in_new_bugmail};
+ }
+ $def->{description} = delete $def->{desc};
+ Bugzilla::Field->create($def);
}
+ }
- # DELETE fields which were added only accidentally, or which
- # were never tracked in bugs_activity. Note that you can never
- # delete fields which are used by bugs_activity.
-
- # Oops. Bug 163299
- $dbh->do("DELETE FROM fielddefs WHERE name='cc_accessible'");
- # Oops. Bug 215319
- $dbh->do("DELETE FROM fielddefs WHERE name='requesters.login_name'");
- # This field was never tracked in bugs_activity, so it's safe to delete.
- $dbh->do("DELETE FROM fielddefs WHERE name='attachments.thedata'");
-
- # MODIFY old field definitions
-
- # 2005-11-13 LpSolit@gmail.com - Bug 302599
- # One of the field names was a fragment of SQL code, which is DB dependent.
- # We have to rename it to a real name, which is DB independent.
- my $new_field_name = 'days_elapsed';
- my $field_description = 'Days since bug changed';
-
- my ($old_field_id, $old_field_name) =
- $dbh->selectrow_array('SELECT id, name FROM fielddefs
- WHERE description = ?',
- undef, $field_description);
-
- if ($old_field_id && ($old_field_name ne $new_field_name)) {
- print "SQL fragment found in the 'fielddefs' table...\n";
- print "Old field name: " . $old_field_name . "\n";
- # We have to fix saved searches first. Queries have been escaped
- # before being saved. We have to do the same here to find them.
- $old_field_name = url_quote($old_field_name);
- my $broken_named_queries =
- $dbh->selectall_arrayref('SELECT userid, name, query
- FROM namedqueries WHERE ' .
- $dbh->sql_istrcmp('query', '?', 'LIKE'),
- undef, "%=$old_field_name%");
-
- my $sth_UpdateQueries = $dbh->prepare('UPDATE namedqueries SET query = ?
- WHERE userid = ? AND name = ?');
-
- print "Fixing saved searches...\n" if scalar(@$broken_named_queries);
- foreach my $named_query (@$broken_named_queries) {
- my ($userid, $name, $query) = @$named_query;
- $query =~ s/=\Q$old_field_name\E(&|$)/=$new_field_name$1/gi;
- $sth_UpdateQueries->execute($query, $userid, $name);
- }
-
- # We now do the same with saved chart series.
- my $broken_series =
- $dbh->selectall_arrayref('SELECT series_id, query
- FROM series WHERE ' .
- $dbh->sql_istrcmp('query', '?', 'LIKE'),
- undef, "%=$old_field_name%");
-
- my $sth_UpdateSeries = $dbh->prepare('UPDATE series SET query = ?
- WHERE series_id = ?');
-
- print "Fixing saved chart series...\n" if scalar(@$broken_series);
- foreach my $series (@$broken_series) {
- my ($series_id, $query) = @$series;
- $query =~ s/=\Q$old_field_name\E(&|$)/=$new_field_name$1/gi;
- $sth_UpdateSeries->execute($query, $series_id);
- }
- # Now that saved searches have been fixed, we can fix the field name.
- print "Fixing the 'fielddefs' table...\n";
- print "New field name: " . $new_field_name . "\n";
- $dbh->do('UPDATE fielddefs SET name = ? WHERE id = ?',
- undef, ($new_field_name, $old_field_id));
+ # DELETE fields which were added only accidentally, or which
+ # were never tracked in bugs_activity. Note that you can never
+ # delete fields which are used by bugs_activity.
+
+ # Oops. Bug 163299
+ $dbh->do("DELETE FROM fielddefs WHERE name='cc_accessible'");
+
+ # Oops. Bug 215319
+ $dbh->do("DELETE FROM fielddefs WHERE name='requesters.login_name'");
+
+ # This field was never tracked in bugs_activity, so it's safe to delete.
+ $dbh->do("DELETE FROM fielddefs WHERE name='attachments.thedata'");
+
+ # MODIFY old field definitions
+
+ # 2005-11-13 LpSolit@gmail.com - Bug 302599
+ # One of the field names was a fragment of SQL code, which is DB dependent.
+ # We have to rename it to a real name, which is DB independent.
+ my $new_field_name = 'days_elapsed';
+ my $field_description = 'Days since bug changed';
+
+ my ($old_field_id, $old_field_name) = $dbh->selectrow_array(
+ 'SELECT id, name FROM fielddefs
+ WHERE description = ?', undef, $field_description
+ );
+
+ if ($old_field_id && ($old_field_name ne $new_field_name)) {
+ print "SQL fragment found in the 'fielddefs' table...\n";
+ print "Old field name: " . $old_field_name . "\n";
+
+ # We have to fix saved searches first. Queries have been escaped
+ # before being saved. We have to do the same here to find them.
+ $old_field_name = url_quote($old_field_name);
+ my $broken_named_queries = $dbh->selectall_arrayref(
+ 'SELECT userid, name, query
+ FROM namedqueries WHERE '
+ . $dbh->sql_istrcmp('query', '?', 'LIKE'), undef, "%=$old_field_name%"
+ );
+
+ my $sth_UpdateQueries = $dbh->prepare(
+ 'UPDATE namedqueries SET query = ?
+ WHERE userid = ? AND name = ?'
+ );
+
+ print "Fixing saved searches...\n" if scalar(@$broken_named_queries);
+ foreach my $named_query (@$broken_named_queries) {
+ my ($userid, $name, $query) = @$named_query;
+ $query =~ s/=\Q$old_field_name\E(&|$)/=$new_field_name$1/gi;
+ $sth_UpdateQueries->execute($query, $userid, $name);
}
- # This field has to be created separately, or the above upgrade code
- # might not run properly.
- Bugzilla::Field->create({ name => $new_field_name,
- description => $field_description })
- unless new Bugzilla::Field({ name => $new_field_name });
+ # We now do the same with saved chart series.
+ my $broken_series = $dbh->selectall_arrayref(
+ 'SELECT series_id, query
+ FROM series WHERE '
+ . $dbh->sql_istrcmp('query', '?', 'LIKE'), undef, "%=$old_field_name%"
+ );
+
+ my $sth_UpdateSeries = $dbh->prepare(
+ 'UPDATE series SET query = ?
+ WHERE series_id = ?'
+ );
+
+ print "Fixing saved chart series...\n" if scalar(@$broken_series);
+ foreach my $series (@$broken_series) {
+ my ($series_id, $query) = @$series;
+ $query =~ s/=\Q$old_field_name\E(&|$)/=$new_field_name$1/gi;
+ $sth_UpdateSeries->execute($query, $series_id);
+ }
-}
+ # Now that saved searches have been fixed, we can fix the field name.
+ print "Fixing the 'fielddefs' table...\n";
+ print "New field name: " . $new_field_name . "\n";
+ $dbh->do('UPDATE fielddefs SET name = ? WHERE id = ?',
+ undef, ($new_field_name, $old_field_id));
+ }
+ # This field has to be created separately, or the above upgrade code
+ # might not run properly.
+ Bugzilla::Field->create({
+ name => $new_field_name, description => $field_description
+ })
+ unless new Bugzilla::Field({name => $new_field_name});
+
+}
=head2 Data Validation
@@ -1313,32 +1447,32 @@ Returns: 1 on success; 0 on failure if $no_warn is true (else an
=cut
sub check_field {
- my ($name, $value, $legalsRef, $no_warn) = @_;
- my $dbh = Bugzilla->dbh;
-
- # If $legalsRef is undefined, we use the default valid values.
- # Valid values for this check are all possible values.
- # Using get_legal_values would only return active values, but since
- # some bugs may have inactive values set, we want to check them too.
- unless (defined $legalsRef) {
- $legalsRef = Bugzilla::Field->new({name => $name})->legal_values;
- my @values = map($_->name, @$legalsRef);
- $legalsRef = \@values;
+ my ($name, $value, $legalsRef, $no_warn) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ # If $legalsRef is undefined, we use the default valid values.
+ # Valid values for this check are all possible values.
+ # Using get_legal_values would only return active values, but since
+ # some bugs may have inactive values set, we want to check them too.
+ unless (defined $legalsRef) {
+ $legalsRef = Bugzilla::Field->new({name => $name})->legal_values;
+ my @values = map($_->name, @$legalsRef);
+ $legalsRef = \@values;
- }
+ }
- if (!defined($value)
- or trim($value) eq ""
- or !grep { $_ eq $value } @$legalsRef)
- {
- return 0 if $no_warn; # We don't want an error to be thrown; return.
- trick_taint($name);
+ if ( !defined($value)
+ or trim($value) eq ""
+ or !grep { $_ eq $value } @$legalsRef)
+ {
+ return 0 if $no_warn; # We don't want an error to be thrown; return.
+ trick_taint($name);
- my $field = new Bugzilla::Field({ name => $name });
- my $field_desc = $field ? $field->description : $name;
- ThrowCodeError('illegal_field', { field => $field_desc });
- }
- return 1;
+ my $field = new Bugzilla::Field({name => $name});
+ my $field_desc = $field ? $field->description : $name;
+ ThrowCodeError('illegal_field', {field => $field_desc});
+ }
+ return 1;
}
=pod
@@ -1360,15 +1494,17 @@ Returns: the corresponding field ID or an error if the field name
=cut
sub get_field_id {
- my ($name) = @_;
- my $dbh = Bugzilla->dbh;
+ my ($name) = @_;
+ my $dbh = Bugzilla->dbh;
- trick_taint($name);
- my $id = $dbh->selectrow_array('SELECT id FROM fielddefs
- WHERE name = ?', undef, $name);
+ trick_taint($name);
+ my $id = $dbh->selectrow_array(
+ 'SELECT id FROM fielddefs
+ WHERE name = ?', undef, $name
+ );
- ThrowCodeError('invalid_field_name', {field => $name}) unless $id;
- return $id
+ ThrowCodeError('invalid_field_name', {field => $name}) unless $id;
+ return $id;
}
1;