diff options
Diffstat (limited to 'extensions/BugmailFilter')
-rw-r--r-- | extensions/BugmailFilter/Config.pm | 2 | ||||
-rw-r--r-- | extensions/BugmailFilter/Extension.pm | 807 | ||||
-rw-r--r-- | extensions/BugmailFilter/lib/Constants.pm | 120 | ||||
-rw-r--r-- | extensions/BugmailFilter/lib/FakeField.pm | 50 | ||||
-rw-r--r-- | extensions/BugmailFilter/lib/Filter.pm | 217 |
5 files changed, 551 insertions, 645 deletions
diff --git a/extensions/BugmailFilter/Config.pm b/extensions/BugmailFilter/Config.pm index 5948c3b64..5b9585cee 100644 --- a/extensions/BugmailFilter/Config.pm +++ b/extensions/BugmailFilter/Config.pm @@ -11,7 +11,7 @@ use 5.10.1; use strict; use warnings; -use constant NAME => 'BugmailFilter'; +use constant NAME => 'BugmailFilter'; use constant REQUIRED_MODULES => []; use constant OPTIONAL_MODULES => []; diff --git a/extensions/BugmailFilter/Extension.pm b/extensions/BugmailFilter/Extension.pm index d4d7bb790..063cb273d 100644 --- a/extensions/BugmailFilter/Extension.pm +++ b/extensions/BugmailFilter/Extension.pm @@ -34,185 +34,172 @@ use Sys::Syslog qw(:DEFAULT); # sub user_preferences { - my ($self, $args) = @_; - return unless $args->{current_tab} eq 'bugmail_filter'; - - if ($args->{save_changes}) { - my $input = Bugzilla->input_params; - - if ($input->{add_filter}) { - - # add a new filter - - my $params = { - user_id => Bugzilla->user->id, - }; - $params->{field_name} = $input->{field} || IS_NULL; - if ($params->{field_name} eq '~') { - $params->{field_name} = '~' . $input->{field_contains}; - } - $params->{relationship} = $input->{relationship} || IS_NULL; - if ($input->{changer}) { - Bugzilla::User::match_field({ changer => { type => 'single'} }); - $params->{changer_id} = Bugzilla::User->check({ - name => $input->{changer}, - cache => 1, - })->id; - } - else { - $params->{changer_id} = IS_NULL; - } - if (my $product_name = $input->{product}) { - my $product = Bugzilla::Product->check({ - name => $product_name, cache => 1 - }); - $params->{product_id} = $product->id; - - if (my $component_name = $input->{component}) { - $params->{component_id} = Bugzilla::Component->check({ - name => $component_name, product => $product, - cache => 1 - })->id; - } - else { - $params->{component_id} = IS_NULL; - } - } - else { - $params->{product_id} = IS_NULL; - $params->{component_id} = IS_NULL; - } - - if (@{ Bugzilla::Extension::BugmailFilter::Filter->match($params) }) { - ThrowUserError('bugmail_filter_exists'); - } - $params->{action} = $input->{action} eq 'Exclude' ? 1 : 0; - foreach my $name (keys %$params) { - $params->{$name} = undef - if $params->{$name} eq IS_NULL; - } - Bugzilla::Extension::BugmailFilter::Filter->create($params); + my ($self, $args) = @_; + return unless $args->{current_tab} eq 'bugmail_filter'; + + if ($args->{save_changes}) { + my $input = Bugzilla->input_params; + + if ($input->{add_filter}) { + + # add a new filter + + my $params = {user_id => Bugzilla->user->id,}; + $params->{field_name} = $input->{field} || IS_NULL; + if ($params->{field_name} eq '~') { + $params->{field_name} = '~' . $input->{field_contains}; + } + $params->{relationship} = $input->{relationship} || IS_NULL; + if ($input->{changer}) { + Bugzilla::User::match_field({changer => {type => 'single'}}); + $params->{changer_id} + = Bugzilla::User->check({name => $input->{changer}, cache => 1,})->id; + } + else { + $params->{changer_id} = IS_NULL; + } + if (my $product_name = $input->{product}) { + my $product = Bugzilla::Product->check({name => $product_name, cache => 1}); + $params->{product_id} = $product->id; + + if (my $component_name = $input->{component}) { + $params->{component_id} + = Bugzilla::Component->check({ + name => $component_name, product => $product, cache => 1 + })->id; } - - elsif ($input->{remove_filter}) { - - # remove filter(s) - - my $ids = ref($input->{remove}) ? $input->{remove} : [ $input->{remove} ]; - my $dbh = Bugzilla->dbh; - my $user = Bugzilla->user; - - my $filters = Bugzilla::Extension::BugmailFilter::Filter->match({ id => $ids, user_id => $user->id }); - $dbh->bz_start_transaction; - foreach my $filter (@$filters) { - $filter->remove_from_db(); - } - $dbh->bz_commit_transaction; + else { + $params->{component_id} = IS_NULL; } + } + else { + $params->{product_id} = IS_NULL; + $params->{component_id} = IS_NULL; + } + + if (@{Bugzilla::Extension::BugmailFilter::Filter->match($params)}) { + ThrowUserError('bugmail_filter_exists'); + } + $params->{action} = $input->{action} eq 'Exclude' ? 1 : 0; + foreach my $name (keys %$params) { + $params->{$name} = undef if $params->{$name} eq IS_NULL; + } + Bugzilla::Extension::BugmailFilter::Filter->create($params); } - my $vars = $args->{vars}; - my $field_descs = template_var('field_descs'); + elsif ($input->{remove_filter}) { - # load all fields into a hash for easy manipulation - my %fields = - map { $_->name => $field_descs->{$_->name} } - @{ Bugzilla->fields({ obsolete => 0 }) }; + # remove filter(s) - # remove time trackinger fields - if (!Bugzilla->user->is_timetracker) { - foreach my $field (TIMETRACKING_FIELDS) { - delete $fields{$field}; - } - } + my $ids = ref($input->{remove}) ? $input->{remove} : [$input->{remove}]; + my $dbh = Bugzilla->dbh; + my $user = Bugzilla->user; - # remove fields which don't make any sense to filter on - foreach my $field (IGNORE_FIELDS) { - delete $fields{$field}; + my $filters = Bugzilla::Extension::BugmailFilter::Filter->match( + {id => $ids, user_id => $user->id}); + $dbh->bz_start_transaction; + foreach my $filter (@$filters) { + $filter->remove_from_db(); + } + $dbh->bz_commit_transaction; } + } - # remove all tracking flag fields. these change too frequently to be of - # value, so they only add noise to the list. - foreach my $field (Bugzilla->tracking_flag_names) { - delete $fields{$field}; - } + my $vars = $args->{vars}; + my $field_descs = template_var('field_descs'); - # add tracking flag types instead - foreach my $field ( - @{ Bugzilla::Extension::BugmailFilter::FakeField->tracking_flag_fields() } - ) { - $fields{$field->name} = $field->description; - } + # load all fields into a hash for easy manipulation + my %fields = map { $_->name => $field_descs->{$_->name} } + @{Bugzilla->fields({obsolete => 0})}; - # adjust the description for selected fields - foreach my $field (keys %{ FIELD_DESCRIPTION_OVERRIDE() }) { - $fields{$field} = FIELD_DESCRIPTION_OVERRIDE->{$field}; + # remove time trackinger fields + if (!Bugzilla->user->is_timetracker) { + foreach my $field (TIMETRACKING_FIELDS) { + delete $fields{$field}; } - - # some fields are present in the changed-fields x-header but are not real - # bugzilla fields - foreach my $field ( - @{ Bugzilla::Extension::BugmailFilter::FakeField->fake_fields() } - ) { - $fields{$field->name} = $field->description; + } + + # remove fields which don't make any sense to filter on + foreach my $field (IGNORE_FIELDS) { + delete $fields{$field}; + } + + # remove all tracking flag fields. these change too frequently to be of + # value, so they only add noise to the list. + foreach my $field (Bugzilla->tracking_flag_names) { + delete $fields{$field}; + } + + # add tracking flag types instead + foreach my $field ( + @{Bugzilla::Extension::BugmailFilter::FakeField->tracking_flag_fields()}) + { + $fields{$field->name} = $field->description; + } + + # adjust the description for selected fields + foreach my $field (keys %{FIELD_DESCRIPTION_OVERRIDE()}) { + $fields{$field} = FIELD_DESCRIPTION_OVERRIDE->{$field}; + } + + # some fields are present in the changed-fields x-header but are not real + # bugzilla fields + foreach + my $field (@{Bugzilla::Extension::BugmailFilter::FakeField->fake_fields()}) + { + $fields{$field->name} = $field->description; + } + + $vars->{fields} = \%fields; + $vars->{field_list} = [sort { lc($a->{description}) cmp lc($b->{description}) } + map { {name => $_, description => $fields{$_}} } keys %fields]; + + $vars->{relationships} = FILTER_RELATIONSHIPS(); + + $vars->{filters} = [ + sort { + $a->product_name cmp $b->product_name + || $a->component_name cmp $b->component_name + || $a->field_name cmp $b->field_name + } @{Bugzilla::Extension::BugmailFilter::Filter->match({ + user_id => Bugzilla->user->id, + }) } + ]; - $vars->{fields} = \%fields; - $vars->{field_list} = [ - sort { lc($a->{description}) cmp lc($b->{description}) } - map { { name => $_, description => $fields{$_} } } - keys %fields - ]; - - $vars->{relationships} = FILTER_RELATIONSHIPS(); - - $vars->{filters} = [ - sort { - $a->product_name cmp $b->product_name - || $a->component_name cmp $b->component_name - || $a->field_name cmp $b->field_name - } - @{ Bugzilla::Extension::BugmailFilter::Filter->match({ - user_id => Bugzilla->user->id, - }) } - ]; - - # set field_description - foreach my $filter (@{ $vars->{filters} }) { - my $field_name = $filter->field_name; - if (!$field_name) { - $filter->field_description('Any'); - } - elsif (substr($field_name, 0, 1) eq '~') { - $filter->field_description('~ ' . substr($field_name, 1)); - } - else { - $filter->field_description($fields{$field_name} || $filter->field->description); - } + # set field_description + foreach my $filter (@{$vars->{filters}}) { + my $field_name = $filter->field_name; + if (!$field_name) { + $filter->field_description('Any'); } - - # build a list of tracking-flags, grouped by type - require Bugzilla::Extension::TrackingFlags::Constants; - require Bugzilla::Extension::TrackingFlags::Flag; - my %flag_types = - map { $_->{name} => $_->{description} } - @{ Bugzilla::Extension::TrackingFlags::Constants::FLAG_TYPES() }; - my %tracking_flags_by_type; - foreach my $flag (Bugzilla::Extension::TrackingFlags::Flag->get_all) { - my $type = $flag_types{$flag->flag_type}; - $tracking_flags_by_type{$type} //= []; - push @{ $tracking_flags_by_type{$type} }, $flag; + elsif (substr($field_name, 0, 1) eq '~') { + $filter->field_description('~ ' . substr($field_name, 1)); } - my @tracking_flags_by_type; - foreach my $type (sort keys %tracking_flags_by_type) { - push @tracking_flags_by_type, { - name => $type, - flags => $tracking_flags_by_type{$type}, - }; + else { + $filter->field_description($fields{$field_name} || $filter->field->description); } - $vars->{tracking_flags_by_type} = \@tracking_flags_by_type; - - ${ $args->{handled} } = 1; + } + + # build a list of tracking-flags, grouped by type + require Bugzilla::Extension::TrackingFlags::Constants; + require Bugzilla::Extension::TrackingFlags::Flag; + my %flag_types = map { $_->{name} => $_->{description} } + @{Bugzilla::Extension::TrackingFlags::Constants::FLAG_TYPES()}; + my %tracking_flags_by_type; + foreach my $flag (Bugzilla::Extension::TrackingFlags::Flag->get_all) { + my $type = $flag_types{$flag->flag_type}; + $tracking_flags_by_type{$type} //= []; + push @{$tracking_flags_by_type{$type}}, $flag; + } + my @tracking_flags_by_type; + foreach my $type (sort keys %tracking_flags_by_type) { + push @tracking_flags_by_type, + {name => $type, flags => $tracking_flags_by_type{$type},}; + } + $vars->{tracking_flags_by_type} = \@tracking_flags_by_type; + + ${$args->{handled}} = 1; } # @@ -220,219 +207,212 @@ sub user_preferences { # sub user_wants_mail { - my ($self, $args) = @_; - my ($user, $wants_mail, $diffs, $comments) - = @$args{qw( user wants_mail fieldDiffs comments )}; - - # already filtered by email prefs - return unless $$wants_mail; + my ($self, $args) = @_; + my ($user, $wants_mail, $diffs, $comments) + = @$args{qw( user wants_mail fieldDiffs comments )}; + + # already filtered by email prefs + return unless $$wants_mail; + + # avoid recursion + my $depth = 0; + for (my $stack = 1; my $sub = (caller($stack))[3]; $stack++) { + $depth++ if $sub eq 'Bugzilla::User::wants_bug_mail'; + } + return if $depth > 1; + + my $cache = Bugzilla->request_cache->{bugmail_filters} //= {}; + my $filters = $cache->{$user->id} + //= Bugzilla::Extension::BugmailFilter::Filter->match({user_id => $user->id}); + return unless @$filters; + + my $fields = [ + map { { + filter_field => $_->{field_name}, # filter's field_name + field_name => $_->{field_name}, # raw bugzilla field_name + } } grep { + + # flags are added later + $_->{field_name} ne 'flagtypes.name' + } @$diffs + ]; + + # if more than one field was changed we need to check if the normal email + # preferences would have excluded the field. + if (@$fields > 1) { + + # check each field individually and create filter objects if required + my @arg_list + = @$args{qw( bug relationship fieldDiffs comments dep_mail changer )}; + foreach my $field (@$fields) { - # avoid recursion - my $depth = 0; - for (my $stack = 1; my $sub = (caller($stack))[3]; $stack++) { - $depth++ if $sub eq 'Bugzilla::User::wants_bug_mail'; - } - return if $depth > 1; - - my $cache = Bugzilla->request_cache->{bugmail_filters} //= {}; - my $filters = $cache->{$user->id} //= - Bugzilla::Extension::BugmailFilter::Filter->match({ - user_id => $user->id - }); - return unless @$filters; - - my $fields = [ - map { { - filter_field => $_->{field_name}, # filter's field_name - field_name => $_->{field_name}, # raw bugzilla field_name - } } - grep { - # flags are added later - $_->{field_name} ne 'flagtypes.name' - } - @$diffs - ]; - - # if more than one field was changed we need to check if the normal email - # preferences would have excluded the field. - if (@$fields > 1) { - # check each field individually and create filter objects if required - my @arg_list = @$args{qw( bug relationship fieldDiffs comments dep_mail changer )}; - foreach my $field (@$fields) { - # just a single diff - foreach my $diff (@$diffs) { - next unless $diff->{field_name} eq $field->{field_name}; - $arg_list[2] = [ $diff ]; - last; - } - if (!$user->wants_bug_mail(@arg_list)) { - # changes to just this field would have been dropped by email - # preferences. build a corresponding filter object so we - # interact with email preferences correctly. - push @$filters, Bugzilla::Extension::BugmailFilter::Filter->new_from_hash({ - field_name => $field->{field_name}, - action => 1, - }); - } - } + # just a single diff + foreach my $diff (@$diffs) { + next unless $diff->{field_name} eq $field->{field_name}; + $arg_list[2] = [$diff]; + last; + } + if (!$user->wants_bug_mail(@arg_list)) { + + # changes to just this field would have been dropped by email + # preferences. build a corresponding filter object so we + # interact with email preferences correctly. + push @$filters, + Bugzilla::Extension::BugmailFilter::Filter->new_from_hash({ + field_name => $field->{field_name}, action => 1, + }); + } } + } - # insert fake fields for new attachments and comments - if (@$comments) { - if (grep { $_->type == CMT_ATTACHMENT_CREATED } @$comments) { - push @$fields, { field_name => 'attachment.created', - filter_field => 'attachment.created' }; - } - if (grep { $_->type != CMT_ATTACHMENT_CREATED } @$comments) { - push @$fields, { field_name => 'comment.created', - filter_field => 'comment.created' }; - } + # insert fake fields for new attachments and comments + if (@$comments) { + if (grep { $_->type == CMT_ATTACHMENT_CREATED } @$comments) { + push @$fields, + {field_name => 'attachment.created', filter_field => 'attachment.created'}; } - - # insert fake fields for flags - foreach my $diff (@$diffs) { - next unless $diff->{field_name} eq 'flagtypes.name'; - foreach my $change (split(/, /, join(', ', ($diff->{old}, $diff->{new})))) { - next unless $change =~ /^(.+)[\?\-+]/; - push @$fields, { - filter_field => $1, - field_name => 'flagtypes.name', - }; - } + if (grep { $_->type != CMT_ATTACHMENT_CREATED } @$comments) { + push @$fields, + {field_name => 'comment.created', filter_field => 'comment.created'}; } - - # set filter_field on tracking flags to tracking.$type - require Bugzilla::Extension::TrackingFlags::Flag; - my @tracking_flags = Bugzilla->tracking_flags; - foreach my $field (@$fields) { - next unless my $field_name = $field->{field_name}; - foreach my $tracking_flag (@tracking_flags) { - if ($field_name eq $tracking_flag->name) { - $field->{filter_field} = 'tracking.'. $tracking_flag->flag_type; - } - } + } + + # insert fake fields for flags + foreach my $diff (@$diffs) { + next unless $diff->{field_name} eq 'flagtypes.name'; + foreach my $change (split(/, /, join(', ', ($diff->{old}, $diff->{new})))) { + next unless $change =~ /^(.+)[\?\-+]/; + push @$fields, {filter_field => $1, field_name => 'flagtypes.name',}; } - - if (_should_drop($fields, $filters, $args)) { - $$wants_mail = 0; - openlog('apache', 'cons,pid', 'local4'); - syslog('notice', encode_utf8(sprintf( - '[bugmail] %s (filtered) bug-%s %s', - $args->{user}->login, - $args->{bug}->id, - $args->{bug}->short_desc, - ))); - closelog(); + } + + # set filter_field on tracking flags to tracking.$type + require Bugzilla::Extension::TrackingFlags::Flag; + my @tracking_flags = Bugzilla->tracking_flags; + foreach my $field (@$fields) { + next unless my $field_name = $field->{field_name}; + foreach my $tracking_flag (@tracking_flags) { + if ($field_name eq $tracking_flag->name) { + $field->{filter_field} = 'tracking.' . $tracking_flag->flag_type; + } } + } + + if (_should_drop($fields, $filters, $args)) { + $$wants_mail = 0; + openlog('apache', 'cons,pid', 'local4'); + syslog( + 'notice', + encode_utf8(sprintf( + '[bugmail] %s (filtered) bug-%s %s', + $args->{user}->login, + $args->{bug}->id, $args->{bug}->short_desc, + )) + ); + closelog(); + } } sub _should_drop { - my ($fields, $filters, $args) = @_; - - # calculate relationships - - my ($user, $bug, $relationship, $changer) = @$args{qw( user bug relationship changer )}; - my ($user_id, $login) = ($user->id, $user->login); - my $bit_direct = Bugzilla::BugMail::BIT_DIRECT; - my $bit_watching = Bugzilla::BugMail::BIT_WATCHING; - my $bit_compwatch = 15; # from Bugzilla::Extension::ComponentWatching - - # the index of $rel_map corresponds to the values in FILTER_RELATIONSHIPS - my @rel_map; - $rel_map[1] = $bug->assigned_to->id == $user_id; - $rel_map[2] = !$rel_map[1]; - $rel_map[3] = $bug->reporter->id == $user_id; - $rel_map[4] = !$rel_map[3]; - if ($bug->qa_contact) { - $rel_map[5] = $bug->qa_contact->id == $user_id; - $rel_map[6] = !$rel_map[6]; + my ($fields, $filters, $args) = @_; + + # calculate relationships + + my ($user, $bug, $relationship, $changer) + = @$args{qw( user bug relationship changer )}; + my ($user_id, $login) = ($user->id, $user->login); + my $bit_direct = Bugzilla::BugMail::BIT_DIRECT; + my $bit_watching = Bugzilla::BugMail::BIT_WATCHING; + my $bit_compwatch = 15; # from Bugzilla::Extension::ComponentWatching + + # the index of $rel_map corresponds to the values in FILTER_RELATIONSHIPS + my @rel_map; + $rel_map[1] = $bug->assigned_to->id == $user_id; + $rel_map[2] = !$rel_map[1]; + $rel_map[3] = $bug->reporter->id == $user_id; + $rel_map[4] = !$rel_map[3]; + if ($bug->qa_contact) { + $rel_map[5] = $bug->qa_contact->id == $user_id; + $rel_map[6] = !$rel_map[6]; + } + $rel_map[7] = $bug->cc ? grep { $_ eq $login } @{$bug->cc} : 0; + $rel_map[8] = !$rel_map[8]; + $rel_map[9] = ($relationship & $bit_watching or $relationship & $bit_compwatch); + $rel_map[10] = !$rel_map[9]; + $rel_map[11] = $bug->is_mentor($user); + $rel_map[12] = !$rel_map[11]; + foreach my $bool (@rel_map) { + $bool = $bool ? 1 : 0; + } + + # exclusions + # drop email where we are excluding all changed fields + + my $params = { + product_id => $bug->product_id, + component_id => $bug->component_id, + rel_map => \@rel_map, + changer_id => $changer->id, + }; + + foreach my $field (@$fields) { + $params->{field} = $field; + foreach my $filter (grep { $_->is_exclude } @$filters) { + if ($filter->matches($params)) { + $field->{exclude} = 1; + last; + } } - $rel_map[7] = $bug->cc - ? grep { $_ eq $login } @{ $bug->cc } - : 0; - $rel_map[8] = !$rel_map[8]; - $rel_map[9] = ( - $relationship & $bit_watching - or $relationship & $bit_compwatch - ); - $rel_map[10] = !$rel_map[9]; - $rel_map[11] = $bug->is_mentor($user); - $rel_map[12] = !$rel_map[11]; - foreach my $bool (@rel_map) { - $bool = $bool ? 1 : 0; - } - - # exclusions - # drop email where we are excluding all changed fields - - my $params = { - product_id => $bug->product_id, - component_id => $bug->component_id, - rel_map => \@rel_map, - changer_id => $changer->id, - }; - - foreach my $field (@$fields) { - $params->{field} = $field; - foreach my $filter (grep { $_->is_exclude } @$filters) { - if ($filter->matches($params)) { - $field->{exclude} = 1; - last; - } - } + } + + # no need to process includes if nothing was excluded + if (!grep { $_->{exclude} } @$fields) { + return 0; + } + + # inclusions + # flip the bit for fields that should be included + + foreach my $field (@$fields) { + $params->{field} = $field; + foreach my $filter (grep { $_->is_include } @$filters) { + if ($filter->matches($params)) { + $field->{exclude} = 0; + last; + } } + } - # no need to process includes if nothing was excluded - if (!grep { $_->{exclude} } @$fields) { - return 0; - } - - # inclusions - # flip the bit for fields that should be included - - foreach my $field (@$fields) { - $params->{field} = $field; - foreach my $filter (grep { $_->is_include } @$filters) { - if ($filter->matches($params)) { - $field->{exclude} = 0; - last; - } - } - } - - # drop if all fields are still excluded - return !(grep { !$_->{exclude} } @$fields); + # drop if all fields are still excluded + return !(grep { !$_->{exclude} } @$fields); } # catch when fields are renamed, and update the field_name entires sub object_end_of_update { - my ($self, $args) = @_; - my $object = $args->{object}; + my ($self, $args) = @_; + my $object = $args->{object}; - return unless $object->isa('Bugzilla::Field') - || $object->isa('Bugzilla::Extension::TrackingFlags::Flag'); + return + unless $object->isa('Bugzilla::Field') + || $object->isa('Bugzilla::Extension::TrackingFlags::Flag'); - return unless exists $args->{changes}->{name}; + return unless exists $args->{changes}->{name}; - my $old_name = $args->{changes}->{name}->[0]; - my $new_name = $args->{changes}->{name}->[1]; + my $old_name = $args->{changes}->{name}->[0]; + my $new_name = $args->{changes}->{name}->[1]; - Bugzilla->dbh->do( - "UPDATE bugmail_filters SET field_name=? WHERE field_name=?", - undef, - $new_name, $old_name); + Bugzilla->dbh->do("UPDATE bugmail_filters SET field_name=? WHERE field_name=?", + undef, $new_name, $old_name); } sub reorg_move_component { - my ($self, $args) = @_; - my $new_product = $args->{new_product}; - my $component = $args->{component}; - - Bugzilla->dbh->do( - "UPDATE bugmail_filters SET product_id=? WHERE component_id=?", - undef, - $new_product->id, $component->id, - ); + my ($self, $args) = @_; + my $new_product = $args->{new_product}; + my $component = $args->{component}; + + Bugzilla->dbh->do( + "UPDATE bugmail_filters SET product_id=? WHERE component_id=?", + undef, $new_product->id, $component->id,); } # @@ -440,92 +420,61 @@ sub reorg_move_component { # sub db_schema_abstract_schema { - my ($self, $args) = @_; - $args->{schema}->{bugmail_filters} = { + my ($self, $args) = @_; + $args->{schema}->{bugmail_filters} = { + FIELDS => [ + id => {TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1,}, + user_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE'}, + }, + field_name => { + + # due to fake fields, this can't be field_id + TYPE => 'VARCHAR(64)', + NOTNULL => 0, + }, + product_id => { + TYPE => 'INT2', + NOTNULL => 0, + REFERENCES => {TABLE => 'products', COLUMN => 'id', DELETE => 'CASCADE'}, + }, + component_id => { + TYPE => 'INT2', + NOTNULL => 0, + REFERENCES => {TABLE => 'components', COLUMN => 'id', DELETE => 'CASCADE'}, + }, + changer_id => { + TYPE => 'INT3', + NOTNULL => 0, + REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE'}, + }, + relationship => {TYPE => 'INT2', NOTNULL => 0,}, + action => {TYPE => 'INT1', NOTNULL => 1,}, + ], + INDEXES => [ + bugmail_filters_unique_idx => { FIELDS => [ - id => { - TYPE => 'INTSERIAL', - NOTNULL => 1, - PRIMARYKEY => 1, - }, - user_id => { - TYPE => 'INT3', - NOTNULL => 1, - REFERENCES => { - TABLE => 'profiles', - COLUMN => 'userid', - DELETE => 'CASCADE' - }, - }, - field_name => { - # due to fake fields, this can't be field_id - TYPE => 'VARCHAR(64)', - NOTNULL => 0, - }, - product_id => { - TYPE => 'INT2', - NOTNULL => 0, - REFERENCES => { - TABLE => 'products', - COLUMN => 'id', - DELETE => 'CASCADE' - }, - }, - component_id => { - TYPE => 'INT2', - NOTNULL => 0, - REFERENCES => { - TABLE => 'components', - COLUMN => 'id', - DELETE => 'CASCADE' - }, - }, - changer_id => { - TYPE => 'INT3', - NOTNULL => 0, - REFERENCES => { - TABLE => 'profiles', - COLUMN => 'userid', - DELETE => 'CASCADE' - }, - }, - relationship => { - TYPE => 'INT2', - NOTNULL => 0, - }, - action => { - TYPE => 'INT1', - NOTNULL => 1, - }, + qw( user_id field_name product_id component_id + relationship ) ], - INDEXES => [ - bugmail_filters_unique_idx => { - FIELDS => [ qw( user_id field_name product_id component_id - relationship ) ], - TYPE => 'UNIQUE', - }, - bugmail_filters_user_idx => [ - 'user_id', - ], - ], - }; + TYPE => 'UNIQUE', + }, + bugmail_filters_user_idx => ['user_id',], + ], + }; } sub install_update_db { - Bugzilla->dbh->bz_add_column( - 'bugmail_filters', - 'changer_id', - { - TYPE => 'INT3', - NOTNULL => 0, - } - ); + Bugzilla->dbh->bz_add_column('bugmail_filters', 'changer_id', + {TYPE => 'INT3', NOTNULL => 0,}); } sub db_sanitize { - my $dbh = Bugzilla->dbh; - print "Deleting bugmail filters...\n"; - $dbh->do("DELETE FROM bugmail_filters"); + my $dbh = Bugzilla->dbh; + print "Deleting bugmail filters...\n"; + $dbh->do("DELETE FROM bugmail_filters"); } __PACKAGE__->NAME; diff --git a/extensions/BugmailFilter/lib/Constants.pm b/extensions/BugmailFilter/lib/Constants.pm index a6636dda7..bed8a37d3 100644 --- a/extensions/BugmailFilter/lib/Constants.pm +++ b/extensions/BugmailFilter/lib/Constants.pm @@ -14,10 +14,10 @@ use warnings; use base qw(Exporter); our @EXPORT = qw( - FAKE_FIELD_NAMES - IGNORE_FIELDS - FIELD_DESCRIPTION_OVERRIDE - FILTER_RELATIONSHIPS + FAKE_FIELD_NAMES + IGNORE_FIELDS + FIELD_DESCRIPTION_OVERRIDE + FILTER_RELATIONSHIPS ); use Bugzilla::Constants; @@ -26,98 +26,54 @@ use Bugzilla::Constants; # header but are not real fields use constant FAKE_FIELD_NAMES => [ - { - name => 'comment.created', - description => 'Comment created', - }, - { - name => 'attachment.created', - description => 'Attachment created', - }, + {name => 'comment.created', description => 'Comment created',}, + {name => 'attachment.created', description => 'Attachment created',}, ]; # these fields don't make any sense to filter on use constant IGNORE_FIELDS => qw( - assignee_last_login - attach_data.thedata - attachments.submitter - cf_last_resolved - commenter - comment_tag - creation_ts - days_elapsed - delta_ts - everconfirmed - last_visit_ts - longdesc - longdescs.count - owner_idle_time - reporter - reporter_accessible - setters.login_name - tag - votes + assignee_last_login + attach_data.thedata + attachments.submitter + cf_last_resolved + commenter + comment_tag + creation_ts + days_elapsed + delta_ts + everconfirmed + last_visit_ts + longdesc + longdescs.count + owner_idle_time + reporter + reporter_accessible + setters.login_name + tag + votes ); # override the description of some fields -use constant FIELD_DESCRIPTION_OVERRIDE => { - bug_id => 'Bug Created', -}; +use constant FIELD_DESCRIPTION_OVERRIDE => {bug_id => 'Bug Created',}; # relationship / int mappings # _should_drop() also needs updating when this const is changed use constant FILTER_RELATIONSHIPS => [ - { - name => 'Assignee', - value => 1, - }, - { - name => 'Not Assignee', - value => 2, - }, - { - name => 'Reporter', - value => 3, - }, - { - name => 'Not Reporter', - value => 4, - }, - { - name => 'QA Contact', - value => 5, - }, - { - name => 'Not QA Contact', - value => 6, - }, - { - name => "CC'ed", - value => 7, - }, - { - name => "Not CC'ed", - value => 8, - }, - { - name => 'Watching', - value => 9, - }, - { - name => 'Not Watching', - value => 10, - }, - { - name => 'Mentoring', - value => 11, - }, - { - name => 'Not Mentoring', - value => 12, - }, + {name => 'Assignee', value => 1,}, + {name => 'Not Assignee', value => 2,}, + {name => 'Reporter', value => 3,}, + {name => 'Not Reporter', value => 4,}, + {name => 'QA Contact', value => 5,}, + {name => 'Not QA Contact', value => 6,}, + {name => "CC'ed", value => 7,}, + {name => "Not CC'ed", value => 8,}, + {name => 'Watching', value => 9,}, + {name => 'Not Watching', value => 10,}, + {name => 'Mentoring', value => 11,}, + {name => 'Not Mentoring', value => 12,}, ]; 1; diff --git a/extensions/BugmailFilter/lib/FakeField.pm b/extensions/BugmailFilter/lib/FakeField.pm index e9f8b1808..cf82aec85 100644 --- a/extensions/BugmailFilter/lib/FakeField.pm +++ b/extensions/BugmailFilter/lib/FakeField.pm @@ -16,8 +16,8 @@ use Bugzilla::Extension::BugmailFilter::Constants; # object sub new { - my ($class, $params) = @_; - return bless($params, $class); + my ($class, $params) = @_; + return bless($params, $class); } sub name { $_[0]->{name} } @@ -26,33 +26,35 @@ sub description { $_[0]->{description} } # static methods sub fake_fields { - my $cache = Bugzilla->request_cache->{bugmail_filter}; - if (!$cache->{fake_fields}) { - my @fields; - foreach my $rh (@{ FAKE_FIELD_NAMES() }) { - push @fields, Bugzilla::Extension::BugmailFilter::FakeField->new($rh); - } - $cache->{fake_fields} = \@fields; + my $cache = Bugzilla->request_cache->{bugmail_filter}; + if (!$cache->{fake_fields}) { + my @fields; + foreach my $rh (@{FAKE_FIELD_NAMES()}) { + push @fields, Bugzilla::Extension::BugmailFilter::FakeField->new($rh); } - return $cache->{fake_fields}; + $cache->{fake_fields} = \@fields; + } + return $cache->{fake_fields}; } sub tracking_flag_fields { - my $cache = Bugzilla->request_cache->{bugmail_filter}; - if (!$cache->{tracking_flag_fields}) { - require Bugzilla::Extension::TrackingFlags::Constants; - my @fields; - my $tracking_types = Bugzilla::Extension::TrackingFlags::Constants::FLAG_TYPES(); - foreach my $tracking_type (@$tracking_types) { - push @fields, Bugzilla::Extension::BugmailFilter::FakeField->new({ - name => 'tracking.' . $tracking_type->{name}, - description => $tracking_type->{description}, - sortkey => $tracking_type->{sortkey}, - }); - } - $cache->{tracking_flag_fields} = \@fields; + my $cache = Bugzilla->request_cache->{bugmail_filter}; + if (!$cache->{tracking_flag_fields}) { + require Bugzilla::Extension::TrackingFlags::Constants; + my @fields; + my $tracking_types + = Bugzilla::Extension::TrackingFlags::Constants::FLAG_TYPES(); + foreach my $tracking_type (@$tracking_types) { + push @fields, + Bugzilla::Extension::BugmailFilter::FakeField->new({ + name => 'tracking.' . $tracking_type->{name}, + description => $tracking_type->{description}, + sortkey => $tracking_type->{sortkey}, + }); } - return $cache->{tracking_flag_fields}; + $cache->{tracking_flag_fields} = \@fields; + } + return $cache->{tracking_flag_fields}; } 1; diff --git a/extensions/BugmailFilter/lib/Filter.pm b/extensions/BugmailFilter/lib/Filter.pm index 7f2f4cb87..fa2c708cd 100644 --- a/extensions/BugmailFilter/lib/Filter.pm +++ b/extensions/BugmailFilter/lib/Filter.pm @@ -25,14 +25,14 @@ use Bugzilla::Util qw(trim); use constant DB_TABLE => 'bugmail_filters'; use constant DB_COLUMNS => qw( - id - user_id - product_id - component_id - field_name - relationship - changer_id - action + id + user_id + product_id + component_id + field_name + relationship + changer_id + action ); use constant LIST_ORDER => 'id'; @@ -40,13 +40,11 @@ use constant LIST_ORDER => 'id'; use constant UPDATE_COLUMNS => (); use constant VALIDATORS => { - user_id => \&_check_user, - field_name => \&_check_field_name, - action => \&Bugzilla::Object::check_boolean, -}; -use constant VALIDATOR_DEPENDENCIES => { - component_id => [ 'product_id' ], + user_id => \&_check_user, + field_name => \&_check_field_name, + action => \&Bugzilla::Object::check_boolean, }; +use constant VALIDATOR_DEPENDENCIES => {component_id => ['product_id'],}; use constant AUDIT_CREATES => 0; use constant AUDIT_UPDATES => 0; @@ -56,163 +54,164 @@ use constant USE_MEMCACHED => 0; # getters sub user { - my ($self) = @_; - return Bugzilla::User->new({ id => $self->{user_id}, cache => 1 }); + my ($self) = @_; + return Bugzilla::User->new({id => $self->{user_id}, cache => 1}); } sub product { - my ($self) = @_; - return $self->{product_id} - ? Bugzilla::Product->new({ id => $self->{product_id}, cache => 1 }) - : undef; + my ($self) = @_; + return $self->{product_id} + ? Bugzilla::Product->new({id => $self->{product_id}, cache => 1}) + : undef; } sub product_name { - my ($self) = @_; - return $self->{product_name} //= $self->{product_id} ? $self->product->name : ''; + my ($self) = @_; + return $self->{product_name} + //= $self->{product_id} ? $self->product->name : ''; } sub component { - my ($self) = @_; - return $self->{component_id} - ? Bugzilla::Component->new({ id => $self->{component_id}, cache => 1 }) - : undef; + my ($self) = @_; + return $self->{component_id} + ? Bugzilla::Component->new({id => $self->{component_id}, cache => 1}) + : undef; } sub component_name { - my ($self) = @_; - return $self->{component_name} //= $self->{component_id} ? $self->component->name : ''; + my ($self) = @_; + return $self->{component_name} + //= $self->{component_id} ? $self->component->name : ''; } sub field_name { - return $_[0]->{field_name} //= ''; + return $_[0]->{field_name} //= ''; } sub field_description { - my ($self, $value) = @_; - $self->{field_description} = $value if defined($value); - return $self->{field_description}; + my ($self, $value) = @_; + $self->{field_description} = $value if defined($value); + return $self->{field_description}; } sub field { - my ($self) = @_; - return unless $self->{field_name}; - if (!$self->{field}) { - if (substr($self->{field_name}, 0, 1) eq '~') { - # this should never happen - die "not implemented"; - } - foreach my $field ( - @{ Bugzilla::Extension::BugmailFilter::FakeField->fake_fields() }, - @{ Bugzilla::Extension::BugmailFilter::FakeField->tracking_flag_fields() }, - ) { - if ($field->{name} eq $self->{field_name}) { - return $self->{field} = $field; - } - } - $self->{field} = Bugzilla::Field->new({ name => $self->{field_name}, cache => 1 }); + my ($self) = @_; + return unless $self->{field_name}; + if (!$self->{field}) { + if (substr($self->{field_name}, 0, 1) eq '~') { + + # this should never happen + die "not implemented"; } - return $self->{field}; + foreach my $field ( + @{Bugzilla::Extension::BugmailFilter::FakeField->fake_fields()}, + @{Bugzilla::Extension::BugmailFilter::FakeField->tracking_flag_fields()}, + ) + { + if ($field->{name} eq $self->{field_name}) { + return $self->{field} = $field; + } + } + $self->{field} + = Bugzilla::Field->new({name => $self->{field_name}, cache => 1}); + } + return $self->{field}; } sub relationship { - return $_[0]->{relationship}; + return $_[0]->{relationship}; } sub changer_id { - return $_[0]->{changer_id}; + return $_[0]->{changer_id}; } sub changer { - my ($self) = @_; - return $self->{changer_id} - ? Bugzilla::User->new({ id => $self->{changer_id}, cache => 1 }) - : undef; + my ($self) = @_; + return $self->{changer_id} + ? Bugzilla::User->new({id => $self->{changer_id}, cache => 1}) + : undef; } sub relationship_name { - my ($self) = @_; - foreach my $rel (@{ FILTER_RELATIONSHIPS() }) { - return $rel->{name} - if $rel->{value} == $self->{relationship}; - } - return '?'; + my ($self) = @_; + foreach my $rel (@{FILTER_RELATIONSHIPS()}) { + return $rel->{name} if $rel->{value} == $self->{relationship}; + } + return '?'; } sub is_exclude { - return $_[0]->{action} == 1; + return $_[0]->{action} == 1; } sub is_include { - return $_[0]->{action} == 0; + return $_[0]->{action} == 0; } # validators sub _check_user { - my ($class, $user) = @_; - $user || ThrowCodeError('param_required', { param => 'user' }); + my ($class, $user) = @_; + $user || ThrowCodeError('param_required', {param => 'user'}); } sub _check_field_name { - my ($class, $field_name) = @_; - return undef unless $field_name; - if (substr($field_name, 0, 1) eq '~') { - $field_name = lc(trim($field_name)); - $field_name =~ /^~[a-z0-9_\.\-]+$/ - || ThrowUserError('bugmail_filter_invalid'); - length($field_name) <= 64 - || ThrowUserError('bugmail_filter_too_long'); - return $field_name; - } - foreach my $rh (@{ FAKE_FIELD_NAMES() }) { - return $field_name if $rh->{name} eq $field_name; - } - return $field_name - if $field_name =~ /^tracking\./; - Bugzilla::Field->check({ name => $field_name, cache => 1}); + my ($class, $field_name) = @_; + return undef unless $field_name; + if (substr($field_name, 0, 1) eq '~') { + $field_name = lc(trim($field_name)); + $field_name =~ /^~[a-z0-9_\.\-]+$/ || ThrowUserError('bugmail_filter_invalid'); + length($field_name) <= 64 || ThrowUserError('bugmail_filter_too_long'); return $field_name; + } + foreach my $rh (@{FAKE_FIELD_NAMES()}) { + return $field_name if $rh->{name} eq $field_name; + } + return $field_name if $field_name =~ /^tracking\./; + Bugzilla::Field->check({name => $field_name, cache => 1}); + return $field_name; } # methods sub matches { - my ($self, $args) = @_; - - if (my $field_name = $self->{field_name}) { - if ($args->{field}->{field_name} && substr($field_name, 0, 1) eq '~') { - my $substring = quotemeta(substr($field_name, 1)); - if ($args->{field}->{filter_field} !~ /$substring/i) { - return 0; - } - } - elsif ($field_name eq 'flagtypes.name') { - if ($args->{field}->{field_name} ne $field_name) { - return 0; - } - } - elsif ($field_name ne $args->{field}->{filter_field}) { - return 0; - } - } + my ($self, $args) = @_; - if ($self->{product_id} && $self->{product_id} != $args->{product_id}) { + if (my $field_name = $self->{field_name}) { + if ($args->{field}->{field_name} && substr($field_name, 0, 1) eq '~') { + my $substring = quotemeta(substr($field_name, 1)); + if ($args->{field}->{filter_field} !~ /$substring/i) { return 0; + } } - - if ($self->{component_id} && $self->{component_id} != $args->{component_id}) { + elsif ($field_name eq 'flagtypes.name') { + if ($args->{field}->{field_name} ne $field_name) { return 0; + } } - - if ($self->{relationship} && !$args->{rel_map}->[$self->{relationship}]) { - return 0; + elsif ($field_name ne $args->{field}->{filter_field}) { + return 0; } + } - if ($self->{changer_id} && $self->{changer_id} != $args->{changer_id}) { - return 0; - } + if ($self->{product_id} && $self->{product_id} != $args->{product_id}) { + return 0; + } + + if ($self->{component_id} && $self->{component_id} != $args->{component_id}) { + return 0; + } + + if ($self->{relationship} && !$args->{rel_map}->[$self->{relationship}]) { + return 0; + } + + if ($self->{changer_id} && $self->{changer_id} != $args->{changer_id}) { + return 0; + } - return 1; + return 1; } 1; |