From d73a83506def7c6b43e5ad720777ec700f6af2e8 Mon Sep 17 00:00:00 2001 From: Jesse Clark Date: Sun, 7 Feb 2010 16:10:03 -0800 Subject: Bug 251556: Allow "Bug ID" fields to have one-way mutual relationships (like blocks/dependson) r=mkanat, a=mkanat --- Bugzilla/Bug.pm | 47 ++++++++++++++++++++++++++++++++++- Bugzilla/DB/Schema.pm | 1 + Bugzilla/Field.pm | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ Bugzilla/Install/DB.pm | 3 +++ 4 files changed, 116 insertions(+), 1 deletion(-) (limited to 'Bugzilla') diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index fd28b5b82..1e418aa18 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -25,6 +25,7 @@ # Max Kanat-Alexander # Frédéric Buclin # Lance Larsh +# Elliotte Martin package Bugzilla::Bug; @@ -1761,7 +1762,42 @@ sub _check_select_field { sub _check_bugid_field { my ($invocant, $value, $field) = @_; return undef if !$value; - return $invocant->check($value, $field)->id; + + # check that the value is a valid, visible bug id + my $checked_id = $invocant->check($value, $field)->id; + + # check for loop (can't have a loop if this is a new bug) + if (ref $invocant) { + _check_relationship_loop($field, $invocant->bug_id, $checked_id); + } + + return $checked_id; +} + +sub _check_relationship_loop { + # Generates a dependency tree for a given bug. Calls itself recursively + # to generate sub-trees for the bug's dependencies. + my ($field, $bug_id, $dep_id, $ids) = @_; + + # Don't do anything if this bug doesn't have any dependencies. + return unless defined($dep_id); + + # Check whether we have seen this bug yet + $ids = {} unless defined $ids; + $ids->{$bug_id} = 1; + if ($ids->{$dep_id}) { + ThrowUserError("relationship_loop_single", { + 'bug_id' => $bug_id, + 'dep_id' => $dep_id, + 'field_name' => $field}); + } + + # Get this dependency's record from the database + my $dbh = Bugzilla->dbh; + my $next_dep_id = $dbh->selectrow_array( + "SELECT $field FROM bugs WHERE bug_id = ?", undef, $dep_id); + + _check_relationship_loop($field, $dep_id, $next_dep_id, $ids); } ##################################################################### @@ -2553,6 +2589,15 @@ sub blocked { # Even bugs in an error state always have a bug_id. sub bug_id { $_[0]->{'bug_id'}; } +sub related_bugs { + my ($self, $relationship) = @_; + return [] if $self->{'error'}; + + my $field_name = $relationship->name; + $self->{'related_bugs'}->{$field_name} ||= $self->match({$field_name => $self->id}); + return $self->{'related_bugs'}->{$field_name}; +} + sub cc { my ($self) = @_; return $self->{'cc'} if exists $self->{'cc'}; diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 8bee5dfe1..44d224d57 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -693,6 +693,7 @@ use constant ABSTRACT_SCHEMA => { value_field_id => {TYPE => 'INT3', REFERENCES => {TABLE => 'fielddefs', COLUMN => 'id'}}, + reverse_desc => {TYPE => 'TINYTEXT'}, ], INDEXES => [ fielddefs_name_idx => {FIELDS => ['name'], diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 2f14037ab..17e4194c2 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -101,6 +101,7 @@ use constant DB_COLUMNS => qw( visibility_field_id visibility_value_id value_field_id + reverse_desc ); use constant REQUIRED_CREATE_FIELDS => qw(name description); @@ -120,6 +121,7 @@ use constant VALIDATORS => { use constant UPDATE_VALIDATORS => { value_field_id => \&_check_value_field_id, visibility_value_id => \&_check_control_value, + reverse_desc => \&_check_reverse_desc, }; use constant UPDATE_COLUMNS => qw( @@ -132,6 +134,7 @@ use constant UPDATE_COLUMNS => qw( visibility_field_id visibility_value_id value_field_id + reverse_desc type ); @@ -357,6 +360,22 @@ sub _check_control_value { return $value_obj->id; } +sub _check_reverse_desc { + my ($invocant, $reverse_desc, $type) = @_; + + if (blessed $invocant) { + $type = $invocant->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; +} + + =pod =head2 Instance Properties @@ -637,6 +656,44 @@ sub controls_values_of { return $self->{controls_values_of}; } +=over + +=item C + +Applies only to fields of type FIELD_TYPE_BUG_ID. +Checks to see if a reverse relationship description has been set. +This is the canonical condition to enable reverse link display, +dependency tree display, and similar functionality. + +=back + +=cut + +sub is_relationship { + my $self = shift; + my $desc = $self->reverse_desc; + if (defined $desc && $desc ne "") { + return 1; + } + return 0; +} + +=over + +=item C + +Applies only to fields of type FIELD_TYPE_BUG_ID. +Describes the reverse relationship of this field. +For example, if a BUG_ID field is called "Is a duplicate of", +the reverse description would be "Duplicates of this bug". + +=back + +=cut + +sub reverse_desc { return $_[0]->{reverse_desc} } + + =pod =head2 Instance Mutators @@ -661,6 +718,8 @@ They will throw an error if you try to set the values to something invalid. =item C +=item C + =item C =item C @@ -677,6 +736,7 @@ 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); @@ -868,6 +928,12 @@ sub run_create_validators { $class->_check_value_field_id($params->{value_field_id}, ($type == FIELD_TYPE_SINGLE_SELECT || $type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0); + + $params->{reverse_desc} = $class->_check_reverse_desc( + $params->{reverse_desc}, $type); + + + return $params; } diff --git a/Bugzilla/Install/DB.pm b/Bugzilla/Install/DB.pm index f6d6edcb1..d150a4e9b 100644 --- a/Bugzilla/Install/DB.pm +++ b/Bugzilla/Install/DB.pm @@ -102,6 +102,9 @@ sub update_fielddefs_definition { $dbh->do('UPDATE fielddefs SET buglist = 1 WHERE custom = 1 AND type != ' . FIELD_TYPE_MULTI_SELECT); } + #2008-08-26 elliotte_martin@yahoo.com - Bug 251556 + $dbh->bz_add_column('fielddefs', 'reverse_desc', {TYPE => 'TINYTEXT'}); + # Remember, this is not the function for adding general table changes. # That is below. Add new changes to the fielddefs table above this -- cgit v1.2.3-24-g4f1b