From 8ec8da0491ad89604700b3e29a227966f6d84ba1 Mon Sep 17 00:00:00 2001 From: Perl Tidy Date: Wed, 5 Dec 2018 15:38:52 -0500 Subject: no bug - reformat all the code using the new perltidy rules --- Bugzilla/Field.pm | 1414 +++++++++++++++++++++++++++++------------------------ 1 file changed, 775 insertions(+), 639 deletions(-) (limited to 'Bugzilla/Field.pm') 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. =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 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. =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 - 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; -- cgit v1.2.3-24-g4f1b