Bug 70605

git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@987 6955db30-a419-402b-8a0d-67ecbb4d7f56
custis
vfilippov 2010-10-14 10:31:30 +00:00
parent 2cfc068c4b
commit dd4075c58e
13 changed files with 138 additions and 93 deletions

View File

@ -106,7 +106,7 @@ use constant SHUTDOWNHTML_EXIT_SILENTLY => [
{ # Block taken directly from Encode::MIME::Header v2.11
my $especials =
join( '|' => map { quotemeta( chr($_) ) }
unpack( "C*", qq{()<>@,;:"'/[]?.=} ) );
unpack( "C*", qq{()<>@,;:\"\'/[]?.=} ) );
my $re_encoded_word = qr{
=\? # begin encoded word
@ -655,23 +655,63 @@ sub switch_to_main_db {
return $class->dbh_main;
}
sub get_fields {
sub cache_fields
{
my $class = shift;
my $criteria = shift;
# This function may be called during installation, and Field::match
# may fail at that time. so we want to return an empty list in that
# case.
my $fields = eval { Bugzilla::Field->match($criteria) } || [];
return @$fields;
my $cache = $class->request_cache;
if (!$cache->{fields})
{
my $r = {};
my $f;
eval { $f = [ Bugzilla::Field->get_all ]; };
return undef if $@;
for (@$f)
{
$r->{id}->{$_->id} = $_;
$r->{name}->{$_->name} = $_;
}
$cache->{fields} = $r;
}
return $cache->{fields};
}
sub active_custom_fields {
sub get_field
{
my $class = shift;
if (!exists $class->request_cache->{active_custom_fields}) {
$class->request_cache->{active_custom_fields} =
Bugzilla::Field->match({ custom => 1, obsolete => 0 });
my ($id_or_name, $throw_error) = @_;
my $c = $class->cache_fields;
$c = $id_or_name =~ /^\d+$/so ? $c->{id}->{$id_or_name} : $c->{name}->{$id_or_name};
if (!$c && $throw_error)
{
ThrowUserError('object_does_not_exist', {
($id_or_name =~ /^\d+$/so ? 'id' : 'name') => $id_or_name,
class => 'Bugzilla::Field',
});
}
return @{$class->request_cache->{active_custom_fields}};
return $c;
}
sub get_fields
{
my $class = shift;
my $criteria = shift || {};
my $cache = $class->cache_fields;
my @fields = values %{$cache->{id}};
for my $k (keys %$criteria)
{
my %v = map { $_ => 1 } (ref $criteria->{$k} ? @{$criteria->{$k}} : $criteria->{$k});
@fields = grep { $v{$_->$k} } @fields;
}
return @fields;
}
sub active_custom_fields
{
my $class = shift;
my $criteria = shift || {};
$criteria->{custom} = 1;
$criteria->{obsolete} = 0;
return $class->get_fields($criteria);
}
sub has_flags {

View File

@ -3147,7 +3147,7 @@ sub choices {
target_milestone => $self->product_obj->milestones,
);
my $resolution_field = new Bugzilla::Field({ name => 'resolution' });
my $resolution_field = Bugzilla->get_field('resolution');
# Don't include the empty resolution in drop-downs.
my @resolutions = grep($_->name, @{ $resolution_field->legal_values });
# And don't include MOVED in the list unless the bug is already MOVED.

View File

@ -284,7 +284,7 @@ sub _check_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 });
my $field = Bugzilla->get_field($name);
ThrowUserError('field_already_exists', {'field' => $field }) if $field;
return $name;
@ -325,7 +325,7 @@ 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 });
my $field = Bugzilla->get_field($field_id);
if (blessed($invocant) && $field->id == $invocant->id) {
ThrowUserError('field_cant_control_self', { field => $field });
}
@ -526,6 +526,12 @@ sub visibility_field {
return $self->{visibility_field};
}
sub visibility_field_id
{
my $self = shift;
return $self->{visibility_field_id};
}
sub visibility_values
{
my $self = shift;
@ -581,8 +587,7 @@ field controls the visibility of.
sub controls_visibility_of {
my $self = shift;
$self->{controls_visibility_of} ||=
Bugzilla::Field->match({ visibility_field_id => $self->id });
$self->{controls_visibility_of} ||= [ Bugzilla->get_fields({ visibility_field_id => $self->id }) ];
return $self->{controls_visibility_of};
}
@ -608,6 +613,12 @@ sub value_field {
return $self->{value_field};
}
sub value_field_id
{
my $self = shift;
return $self->{value_field_id};
}
=pod
=over
@ -623,8 +634,7 @@ field controls the values of.
sub controls_values_of {
my $self = shift;
$self->{controls_values_of} ||=
Bugzilla::Field->match({ value_field_id => $self->id });
$self->{controls_values_of} ||= [ Bugzilla->get_fields({ value_field_id => $self->id }) ];
return $self->{controls_values_of};
}
@ -1057,7 +1067,7 @@ sub check_field {
# 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;
$legalsRef = Bugzilla->get_field($name)->legal_values;
my @values = map($_->name, @$legalsRef);
$legalsRef = \@values;
@ -1070,7 +1080,7 @@ sub check_field {
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 = Bugzilla->get_field($name);
my $field_desc = $field ? $field->description : $name;
ThrowUserError('illegal_field', { field => $field_desc, value => $value, legals => $legalsRef, ($args ? %$args : ()) });
}

View File

@ -89,7 +89,7 @@ use constant DEFAULT_MAP => {
sub type {
my ($class, $field) = @_;
my $field_obj = blessed $field ? $field : Bugzilla::Field->check($field);
my $field_obj = blessed $field ? $field : Bugzilla->get_field($field, THROW_ERROR);
my $field_name = $field_obj->name;
if ($class->CLASS_MAP->{$field_name}) {
@ -246,8 +246,7 @@ sub field {
my $cache = Bugzilla->request_cache;
# This is just to make life easier for subclasses. Our auto-generated
# subclasses from type() already have this set.
$cache->{"field_$class"} ||=
new Bugzilla::Field({ name => $class->DB_TABLE });
$cache->{"field_$class"} ||= Bugzilla->get_field($class->DB_TABLE);
return $cache->{"field_$class"};
}
@ -285,7 +284,7 @@ sub controls_visibility_of_fields
" AND f.visibility_field_id=? AND c.visibility_value_id=? AND c.value_id=0",
undef, $self->field->id, $self->id
);
$f = Bugzilla::Field->match({ id => $f });
$_ = Bugzilla->get_field($_) for @$f;
$self->{controls_visibility_of_fields} = $f;
}
return $f;
@ -308,7 +307,7 @@ sub controlled_values
{
my $type = Bugzilla::Field::Choice->type($field);
$f = $type->match({ id => $f });
}
}
$controlled_values->{$field->name} = $f;
}
$self->{controlled_values} = $controlled_values;

View File

@ -13,7 +13,7 @@
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Everything Solved.
# Portions created by Everything Solved are Copyright (C) 2006
# Portions created by Everything Solved are Copyright (C) 2006
# Everything Solved. All Rights Reserved.
#
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
@ -88,7 +88,7 @@ sub _init {
$sql = "$id_field = ?";
@values = ($id);
} else {
unless (defined $param->{name} || (defined $param->{'condition'}
unless (defined $param->{name} || (defined $param->{'condition'}
&& defined $param->{'values'}))
{
ThrowCodeError('bad_arg', { argument => 'param',
@ -102,7 +102,7 @@ sub _init {
elsif (defined $param->{'condition'} && defined $param->{'values'}) {
caller->isa('Bugzilla::Object')
|| ThrowCodeError('protection_violation',
{ caller => caller,
{ caller => caller,
function => $class . '::new',
argument => 'condition/values' });
$sql = $param->{'condition'};
@ -191,20 +191,20 @@ sub match {
my (@terms, @values, $postamble);
foreach my $field (keys %$criteria) {
my $value = $criteria->{$field};
# allow for LIMIT and OFFSET expressions via the criteria.
next if $field eq 'OFFSET';
if ( $field eq 'LIMIT' ) {
next unless defined $value;
detaint_natural($value)
or ThrowCodeError('param_must_be_numeric',
{ param => 'LIMIT',
or ThrowCodeError('param_must_be_numeric',
{ param => 'LIMIT',
function => "${class}::match" });
my $offset;
if (defined $criteria->{OFFSET}) {
$offset = $criteria->{OFFSET};
detaint_signed($offset)
or ThrowCodeError('param_must_be_numeric',
or ThrowCodeError('param_must_be_numeric',
{ param => 'OFFSET',
function => "${class}::match" });
}
@ -217,13 +217,13 @@ sub match {
# value (either a scalar or an array of values).
foreach my $k (keys %$value) {
push(@terms, $k);
my @this_value = ref($value->{$k}) ? @{ $value->{$k} }
my @this_value = ref($value->{$k}) ? @{ $value->{$k} }
: ($value->{$k});
push(@values, @this_value);
}
}
next;
}
$class->_check_field($field, 'match');
if (ref $value eq 'ARRAY') {
@ -263,9 +263,9 @@ sub _do_list_select {
$sql .= " WHERE $where ";
}
$sql .= " ORDER BY $order";
$sql .= " $postamble" if $postamble;
my $dbh = Bugzilla->dbh;
# Sometimes the values are tainted, but we don't want to untaint them
# for the caller. So we copy the array. It's safe to untaint because
@ -293,7 +293,7 @@ sub set {
# This method is protected. It's used to help implement set_ functions.
caller->isa('Bugzilla::Object')
|| ThrowCodeError('protection_violation',
|| ThrowCodeError('protection_violation',
{ caller => caller,
superclass => __PACKAGE__,
function => 'Bugzilla::Object->set' });
@ -339,7 +339,7 @@ sub update {
$dbh->bz_start_transaction();
my $old_self = $self->new($self->id);
my %numeric = map { $_ => 1 } $self->NUMERIC_COLUMNS;
my %date = map { $_ => 1 } $self->DATE_COLUMNS;
my (@update_columns, @values, %changes);
@ -351,7 +351,7 @@ sub update {
if (!defined $new || !defined $old) {
next if !defined $new && !defined $old;
}
elsif ( ($numeric{$column} && $old == $new)
elsif ( ($numeric{$column} && $old == $new)
|| ($date{$column} && str2time($old) == str2time($new))
|| $old eq $new ) {
next;
@ -367,7 +367,7 @@ sub update {
my $columns = join(', ', map {"$_ = ?"} @update_columns);
$dbh->do("UPDATE $table SET $columns WHERE $id_field = ?", undef,
$dbh->do("UPDATE $table SET $columns WHERE $id_field = ?", undef,
@values, $self->id) if @values;
Bugzilla::Hook::process('object_end_of_update',
@ -555,8 +555,8 @@ and into this object. This should be an array.
The name of the column that should be considered to be the unique
"name" of this object. The 'name' is a B<string> that uniquely identifies
this Object in the database. Defaults to 'name'. When you specify
C<{name => $name}> to C<new()>, this is the column that will be
this Object in the database. Defaults to 'name'. When you specify
C<{name => $name}> to C<new()>, this is the column that will be
matched against in the DB.
=item C<ID_FIELD>
@ -578,7 +578,7 @@ C<create()>. This should be an array.
=item C<VALIDATORS>
A hashref that points to a function that will validate each param to
L</create>.
L</create>.
Validators are called both by L</create> and L</set>. When
they are called by L</create>, the first argument will be the name
@ -587,8 +587,8 @@ of the class (what we normally call C<$class>).
When they are called by L</set>, the first argument will be
a reference to the current object (what we normally call C<$self>).
The second argument will be the value passed to L</create> or
L</set>for that field.
The second argument will be the value passed to L</create> or
L</set>for that field.
The third argument will be the name of the field being validated.
This may be required by validators which validate several distinct fields.
@ -644,14 +644,14 @@ by id or by name.
=item B<Params>
If you pass an integer, the integer is the id of the object,
If you pass an integer, the integer is the id of the object,
from the database, that we want to read in. (id is defined
as the value in the L</ID_FIELD> column).
If you pass in a hashref, you can pass a C<name> key. The
value of the C<name> key is the case-insensitive name of the object
If you pass in a hashref, you can pass a C<name> key. The
value of the C<name> key is the case-insensitive name of the object
(from L</NAME_FIELD>) in the DB. You can also pass in an C<id> key
which will be interpreted as the id of the object you want (overriding the
which will be interpreted as the id of the object you want (overriding the
C<name> key).
B<Additional Parameters Available for Subclasses>
@ -714,7 +714,7 @@ template.
Params: \@id_list - A reference to an array of numbers, database ids.
If any of these are not numeric, the function
will throw an error. If any of these are not
valid ids in the database, they will simply
valid ids in the database, they will simply
be skipped.
Returns: A reference to an array of objects.
@ -735,26 +735,26 @@ a smaller set of results, not a larger set.
=item B<Params>
A hashref, where the keys are column names of the table, pointing to the
value that you want to match against for that column.
A hashref, where the keys are column names of the table, pointing to the
value that you want to match against for that column.
There are two special values, the constants C<NULL> and C<NOT_NULL>,
which means "give me objects where this field is NULL or NOT NULL,
respectively."
In addition to the column keys, there are a few special keys that
can be used to rig the underlying database queries. These are
can be used to rig the underlying database queries. These are
C<LIMIT>, C<OFFSET>, and C<WHERE>.
The value for the C<LIMIT> key is expected to be an integer defining
The value for the C<LIMIT> key is expected to be an integer defining
the number of objects to return, while the value for C<OFFSET> defines
the position, relative to the number of objects the query would normally
return, at which to begin the result set. If C<OFFSET> is defined without
the position, relative to the number of objects the query would normally
return, at which to begin the result set. If C<OFFSET> is defined without
a corresponding C<LIMIT> it is silently ignored.
The C<WHERE> key provides a mechanism for adding arbitrary WHERE
clauses to the underlying query. Its value is expected to a hash
reference whose keys are the columns, operators and placeholders, and the
clauses to the underlying query. Its value is expected to a hash
reference whose keys are the columns, operators and placeholders, and the
values are the placeholders' bind value. For example:
WHERE => { 'some_column >= ?' => $some_value }
@ -784,7 +784,7 @@ Description: Creates a new item in the database.
are invalid.
Params: C<$params> - hashref - A value to put in each database
field for this object. Certain values must be set (the
field for this object. Certain values must be set (the
ones specified in L</REQUIRED_CREATE_FIELDS>), and
the function will throw a Code Error if you don't set
them.
@ -843,7 +843,7 @@ Returns: A hash, in a similar format as C<$params>, except that
Part of L</create>.
Takes the return value from L</run_create_validators> and inserts the
data into the database. Returns a newly created object.
data into the database. Returns a newly created object.
=item C<update>
@ -984,8 +984,8 @@ C<0> otherwise.
Returns: A list of objects, or an empty list if there are none.
Notes: Note that you must call this as C<$class->get_all>. For
example, C<Bugzilla::Keyword->get_all>.
Notes: Note that you must call this as C<$class->get_all>. For
example, C<Bugzilla::Keyword->get_all>.
C<Bugzilla::Keyword::get_all> will not work.
=back

View File

@ -586,7 +586,7 @@ sub field {
my $invocant = shift;
my $class = ref $invocant || $invocant;
my $cache = Bugzilla->request_cache;
$cache->{"field_$class"} ||= new Bugzilla::Field({ name => 'product' });
$cache->{"field_$class"} ||= Bugzilla->get_field('product');
return $cache->{"field_$class"};
}

View File

@ -306,7 +306,7 @@ sub init {
my @bug_statuses = $params->param('bug_status');
# Also include inactive bug statuses, as you can query them.
my @legal_statuses =
map {$_->name} @{Bugzilla::Field->new({name => 'bug_status'})->legal_values};
map {$_->name} @{Bugzilla->get_field('bug_status')->legal_values};
# Filter out any statuses that have been removed completely that are still
# being used by the client
@ -336,7 +336,7 @@ sub init {
if ($params->param('resolution')) {
my @resolutions = $params->param('resolution');
# Also include inactive resolutions, as you can query them.
my $legal_resolutions = Bugzilla::Field->new({name => 'resolution'})->legal_values;
my $legal_resolutions = Bugzilla->get_field('resolution')->legal_values;
if (scalar(@resolutions) == scalar(@$legal_resolutions)) {
$params->delete('resolution');
}

View File

@ -70,7 +70,7 @@ sub fields {
if (defined $params->{ids}) {
my $ids = $params->{ids};
foreach my $id (@$ids) {
my $loop_field = Bugzilla::Field->check({ id => $id });
my $loop_field = Bugzilla->get_field($id, THROW_USER_ERROR);
push(@fields, $loop_field);
}
}
@ -78,7 +78,7 @@ sub fields {
if (defined $params->{names}) {
my $names = $params->{names};
foreach my $field_name (@$names) {
my $loop_field = Bugzilla::Field->check($field_name);
my $loop_field = Bugzilla->get_field($field_name, THROW_USER_ERROR);
# Don't push in duplicate fields if we also asked for this field
# in "ids".
if (!grep($_->id == $loop_field->id, @fields)) {

View File

@ -104,7 +104,7 @@ $vars->{'open_status'} = \@open_status;
$vars->{'closed_status'} = \@closed_status;
# Generate a list of fields that can be queried.
my @fields = @{Bugzilla::Field->match({obsolete => 0})};
my @fields = Bugzilla->get_fields({obsolete => 0});
# Exclude fields the user cannot query.
if (!Bugzilla->user->is_timetracker) {
@fields = grep { $_->name !~ /^(estimated_time|remaining_time|work_time|percentage_complete|deadline)$/ } @fields;

View File

@ -128,7 +128,7 @@ my $maxrows = formvalue("maxrows");
my $openonly = formvalue("openonly");
my $sortby = formvalue("sortby");
if (!grep(lc($_) eq lc($sortby), qw(count delta id))) {
Bugzilla::Field->check($sortby);
Bugzilla->get_field($sortby, THROW_ERROR);
}
my $reverse = formvalue("reverse");
# Reverse count and delta by default.

View File

@ -81,7 +81,7 @@ elsif ($action eq 'new') {
}
elsif ($action eq 'edit') {
my $name = $cgi->param('name') || ThrowUserError('field_missing_name');
my $field = new Bugzilla::Field({'name' => $name});
my $field = Bugzilla->get_field($name);
$field || ThrowUserError('customfield_nonexistent', {'name' => $name});
$vars->{'field'} = $field;
@ -96,7 +96,7 @@ elsif ($action eq 'update') {
# Validate fields.
$name || ThrowUserError('field_missing_name');
my $field = new Bugzilla::Field({'name' => $name});
my $field = Bugzilla->get_field($name);
$field || ThrowUserError('customfield_nonexistent', {'name' => $name});
$field->set_description($cgi->param('desc'));
@ -133,7 +133,7 @@ elsif ($action eq 'del') {
if ($name !~ /^cf_/) {
$name = 'cf_' . $name;
}
my $field = new Bugzilla::Field({'name' => $name});
my $field = Bugzilla->get_field($name);
$field || ThrowUserError('customfield_nonexistent', {'name' => $name});
$vars->{'field'} = $field;
@ -153,7 +153,7 @@ elsif ($action eq 'delete') {
if ($name !~ /^cf_/) {
$name = 'cf_' . $name;
}
my $field = new Bugzilla::Field({'name' => $name});
my $field = Bugzilla->get_field($name);
$field || ThrowUserError('customfield_nonexistent', {'name' => $name});
# Calling remove_from_db will check if field can be deleted.

View File

@ -257,12 +257,12 @@ $vars->{'chfield'} = [ sort grep { !$exclude{$_} } map { $_->name } @fields ];
unshift @{$vars->{fields}}, { name => "noop", description => "---" };
# Legal values for select fields
$vars->{'bug_status'} = Bugzilla::Field->new({name => 'bug_status'})->legal_values;
Bugzilla->params->{useplatform} and $vars->{'rep_platform'} = Bugzilla::Field->new({name => 'rep_platform'})->legal_values;
Bugzilla->params->{useopsys} and $vars->{'op_sys'} = Bugzilla::Field->new({name => 'op_sys'})->legal_values;
$vars->{'priority'} = Bugzilla::Field->new({name => 'priority'})->legal_values;
$vars->{'bug_severity'} = Bugzilla::Field->new({name => 'bug_severity'})->legal_values;
$vars->{'resolution'} = Bugzilla::Field->new({name => 'resolution'})->legal_values;
$vars->{'bug_status'} = Bugzilla->get_field('bug_status')->legal_values;
Bugzilla->params->{useplatform} and $vars->{'rep_platform'} = Bugzilla->get_field('rep_platform')->legal_values;
Bugzilla->params->{useopsys} and $vars->{'op_sys'} = Bugzilla->get_field('op_sys')->legal_values;
$vars->{'priority'} = Bugzilla->get_field('priority')->legal_values;
$vars->{'bug_severity'} = Bugzilla->get_field('bug_severity')->legal_values;
$vars->{'resolution'} = Bugzilla->get_field('resolution')->legal_values;
# If we're not in the time-tracking group, exclude time-tracking fields.
if (!Bugzilla->user->is_timetracker) {
@ -350,21 +350,19 @@ if (($cgi->param('query_format') || $cgi->param('format') || "")
# CustIS Bug 58300 - Add custom fields to search filters
# This logic is moved from search/form.html.tmpl
$vars->{freetext_fields} = [
Bugzilla::Field->new({ name => "longdesc" }),
Bugzilla::Field->new({ name => "bug_file_loc" }),
Bugzilla->get_field('longdesc'),
Bugzilla->get_field('bug_file_loc')
];
if (Bugzilla->params->{usestatuswhiteboard})
{
push @{$vars->{freetext_fields}}, Bugzilla::Field->new({ name => "status_whiteboard" });
push @{$vars->{freetext_fields}}, Bugzilla->get_field('status_whiteboard');
}
push @{$vars->{freetext_fields}},
grep { $_->type == FIELD_TYPE_TEXTAREA || $_->type == FIELD_TYPE_FREETEXT }
Bugzilla->active_custom_fields;
Bugzilla->active_custom_fields({ type => [ FIELD_TYPE_TEXTAREA, FIELD_TYPE_FREETEXT ] });
if ($cgi->param('format') && $cgi->param('format') =~ /^report-(table|graph)$/) {
# Get legal custom fields for tabular and graphical reports.
my @custom_fields_for_reports =
grep { $_->type == FIELD_TYPE_SINGLE_SELECT } Bugzilla->active_custom_fields;
my @custom_fields_for_reports = Bugzilla->active_custom_fields({ type => FIELD_TYPE_SINGLE_SELECT });
$vars->{'custom_fields'} = \@custom_fields_for_reports;
}

View File

@ -62,12 +62,10 @@ my $est = {};
if ($args->{id})
{
push @$bugs, split /,/, $args->{id}, -1;
my $bug_objects = { map { $_->bug_id => $_ } @{ Bugzilla::Bug->new_from_list([ grep { $_ } @$bugs ]) } };
for (@$bugs)
{
if ($_)
{
$_ = Bugzilla::Bug->new($_);
}
$_ = $bug_objects->{$_} if $_;
}
for (@$bugs)
{