diff options
author | Perl Tidy <perltidy@bugzilla.org> | 2018-12-05 21:38:52 +0100 |
---|---|---|
committer | Dylan William Hardison <dylan@hardison.net> | 2018-12-05 23:49:08 +0100 |
commit | 8ec8da0491ad89604700b3e29a227966f6d84ba1 (patch) | |
tree | 9d270f173330ca19700e0ba9f2ee931300646de1 /extensions/RequestNagger | |
parent | a7bb5a65b71644d9efce5fed783ed545b9336548 (diff) | |
download | bugzilla-8ec8da0491ad89604700b3e29a227966f6d84ba1.tar.gz bugzilla-8ec8da0491ad89604700b3e29a227966f6d84ba1.tar.xz |
no bug - reformat all the code using the new perltidy rules
Diffstat (limited to 'extensions/RequestNagger')
-rw-r--r-- | extensions/RequestNagger/Config.pm | 6 | ||||
-rw-r--r-- | extensions/RequestNagger/Extension.pm | 552 | ||||
-rwxr-xr-x | extensions/RequestNagger/bin/send-request-nags.pl | 481 | ||||
-rw-r--r-- | extensions/RequestNagger/lib/Bug.pm | 34 | ||||
-rw-r--r-- | extensions/RequestNagger/lib/Constants.pm | 69 | ||||
-rw-r--r-- | extensions/RequestNagger/lib/Settings.pm | 75 |
6 files changed, 582 insertions, 635 deletions
diff --git a/extensions/RequestNagger/Config.pm b/extensions/RequestNagger/Config.pm index a338cd441..7bcaf3013 100644 --- a/extensions/RequestNagger/Config.pm +++ b/extensions/RequestNagger/Config.pm @@ -11,8 +11,8 @@ use 5.10.1; use strict; use warnings; -use constant NAME => 'RequestNagger'; -use constant REQUIRED_MODULES => [ ]; -use constant OPTIONAL_MODULES => [ ]; +use constant NAME => 'RequestNagger'; +use constant REQUIRED_MODULES => []; +use constant OPTIONAL_MODULES => []; __PACKAGE__->NAME; diff --git a/extensions/RequestNagger/Extension.pm b/extensions/RequestNagger/Extension.pm index e0f97c9f7..54a11ff5b 100644 --- a/extensions/RequestNagger/Extension.pm +++ b/extensions/RequestNagger/Extension.pm @@ -25,241 +25,239 @@ use DateTime; our $VERSION = '1'; BEGIN { - *Bugzilla::Flag::age = \&_flag_age; - *Bugzilla::Flag::deferred = \&_flag_deferred; - *Bugzilla::Product::nag_interval = \&_product_nag_interval; + *Bugzilla::Flag::age = \&_flag_age; + *Bugzilla::Flag::deferred = \&_flag_deferred; + *Bugzilla::Product::nag_interval = \&_product_nag_interval; } sub _flag_age { - return time_ago(datetime_from($_[0]->modification_date)); + return time_ago(datetime_from($_[0]->modification_date)); } sub _flag_deferred { - my ($self) = @_; - if (!exists $self->{deferred}) { - my $dbh = Bugzilla->dbh; - my ($defer_until) = $dbh->selectrow_array( - "SELECT defer_until FROM nag_defer WHERE flag_id=?", - undef, - $self->id - ); - $self->{deferred} = $defer_until ? datetime_from($defer_until) : undef; - } - return $self->{deferred}; + my ($self) = @_; + if (!exists $self->{deferred}) { + my $dbh = Bugzilla->dbh; + my ($defer_until) + = $dbh->selectrow_array("SELECT defer_until FROM nag_defer WHERE flag_id=?", + undef, $self->id); + $self->{deferred} = $defer_until ? datetime_from($defer_until) : undef; + } + return $self->{deferred}; } sub _product_nag_interval { $_[0]->{nag_interval} } sub object_columns { - my ($self, $args) = @_; - my ($class, $columns) = @$args{qw(class columns)}; - if ($class->isa('Bugzilla::Product')) { - push @$columns, 'nag_interval'; - } + my ($self, $args) = @_; + my ($class, $columns) = @$args{qw(class columns)}; + if ($class->isa('Bugzilla::Product')) { + push @$columns, 'nag_interval'; + } } sub object_update_columns { - my ($self, $args) = @_; - my ($object, $columns) = @$args{qw(object columns)}; - if ($object->isa('Bugzilla::Product')) { - push @$columns, 'nag_interval'; - } + my ($self, $args) = @_; + my ($object, $columns) = @$args{qw(object columns)}; + if ($object->isa('Bugzilla::Product')) { + push @$columns, 'nag_interval'; + } } sub object_before_create { - my ($self, $args) = @_; - my ($class, $params) = @$args{qw(class params)}; - return unless $class->isa('Bugzilla::Product'); - my $input = Bugzilla->input_params; - if (exists $input->{nag_interval}) { - my $interval = _check_nag_interval($input->{nag_interval}); - $params->{nag_interval} = $interval; - } + my ($self, $args) = @_; + my ($class, $params) = @$args{qw(class params)}; + return unless $class->isa('Bugzilla::Product'); + my $input = Bugzilla->input_params; + if (exists $input->{nag_interval}) { + my $interval = _check_nag_interval($input->{nag_interval}); + $params->{nag_interval} = $interval; + } } sub object_end_of_set_all { - my ($self, $args) = @_; - my ($object, $params) = @$args{qw(object params)}; - return unless $object->isa('Bugzilla::Product'); - my $input = Bugzilla->input_params; - if (exists $input->{nag_interval}) { - my $interval = _check_nag_interval($input->{nag_interval}); - $object->set('nag_interval', $interval); - } + my ($self, $args) = @_; + my ($object, $params) = @$args{qw(object params)}; + return unless $object->isa('Bugzilla::Product'); + my $input = Bugzilla->input_params; + if (exists $input->{nag_interval}) { + my $interval = _check_nag_interval($input->{nag_interval}); + $object->set('nag_interval', $interval); + } } sub _check_nag_interval { - my ($value) = @_; - detaint_natural($value) - || ThrowUserError('invalid_parameter', { name => 'request reminding interval', err => 'must be numeric' }); - return $value < 0 ? 0 : $value * 24; + my ($value) = @_; + detaint_natural($value) + || ThrowUserError('invalid_parameter', + {name => 'request reminding interval', err => 'must be numeric'}); + return $value < 0 ? 0 : $value * 24; } sub page_before_template { - my ($self, $args) = @_; - my ($vars, $page) = @$args{qw(vars page_id)}; - return unless $page eq 'request_defer.html'; - - my $user = Bugzilla->login(LOGIN_REQUIRED); - my $input = Bugzilla->input_params; - - # load flag - my $flag_id = scalar($input->{flag}) - || ThrowUserError('request_nagging_flag_invalid'); - detaint_natural($flag_id) - || ThrowUserError('request_nagging_flag_invalid'); - my $flag = Bugzilla::Flag->new({ id => $flag_id, cache => 1 }) - || ThrowUserError('request_nagging_flag_invalid'); - - # you can only defer flags directed at you - $user->can_see_bug($flag->bug->id) - || ThrowUserError("bug_access_denied", { bug_id => $flag->bug->id }); - $flag->status eq '?' - || ThrowUserError('request_nagging_flag_set'); - $flag->requestee - || ThrowUserError('request_nagging_flag_wind'); - $flag->requestee->id == $user->id - || ThrowUserError('request_nagging_flag_not_owned'); - - my $date = DateTime->now()->truncate(to => 'day'); - my $defer_until; - if ($input->{'defer-until'} - && $input->{'defer-until'} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/) - { - $defer_until = DateTime->new(year => $1, month => $2, day => $3); - if ($defer_until > $date->clone->add(days => 7)) { - $defer_until = undef; - } + my ($self, $args) = @_; + my ($vars, $page) = @$args{qw(vars page_id)}; + return unless $page eq 'request_defer.html'; + + my $user = Bugzilla->login(LOGIN_REQUIRED); + my $input = Bugzilla->input_params; + + # load flag + my $flag_id + = scalar($input->{flag}) || ThrowUserError('request_nagging_flag_invalid'); + detaint_natural($flag_id) || ThrowUserError('request_nagging_flag_invalid'); + my $flag = Bugzilla::Flag->new({id => $flag_id, cache => 1}) + || ThrowUserError('request_nagging_flag_invalid'); + + # you can only defer flags directed at you + $user->can_see_bug($flag->bug->id) + || ThrowUserError("bug_access_denied", {bug_id => $flag->bug->id}); + $flag->status eq '?' || ThrowUserError('request_nagging_flag_set'); + $flag->requestee || ThrowUserError('request_nagging_flag_wind'); + $flag->requestee->id == $user->id + || ThrowUserError('request_nagging_flag_not_owned'); + + my $date = DateTime->now()->truncate(to => 'day'); + my $defer_until; + if ( $input->{'defer-until'} + && $input->{'defer-until'} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/) + { + $defer_until = DateTime->new(year => $1, month => $2, day => $3); + if ($defer_until > $date->clone->add(days => 7)) { + $defer_until = undef; } - - if ($input->{save} && $defer_until) { - $self->_defer_until($flag_id, $defer_until); - $vars->{saved} = "1"; - $vars->{defer_until} = $defer_until; - } - else { - my @dates; - foreach my $i (1..7) { - $date->add(days => 1); - unshift @dates, { days => $i, date => $date->clone }; - } - $vars->{defer_until} = \@dates; + } + + if ($input->{save} && $defer_until) { + $self->_defer_until($flag_id, $defer_until); + $vars->{saved} = "1"; + $vars->{defer_until} = $defer_until; + } + else { + my @dates; + foreach my $i (1 .. 7) { + $date->add(days => 1); + unshift @dates, {days => $i, date => $date->clone}; } + $vars->{defer_until} = \@dates; + } - $vars->{flag} = $flag; + $vars->{flag} = $flag; } sub _defer_until { - my ($self, $flag_id, $defer_until) = @_; - my $dbh = Bugzilla->dbh; - - $dbh->bz_start_transaction(); - - my ($defer_id) = $dbh->selectrow_array("SELECT id FROM nag_defer WHERE flag_id=?", undef, $flag_id); - if ($defer_id) { - $dbh->do("UPDATE nag_defer SET defer_until=? WHERE id=?", undef, $defer_until->ymd, $flag_id); - } else { - $dbh->do("INSERT INTO nag_defer(flag_id, defer_until) VALUES (?, ?)", undef, $flag_id, $defer_until->ymd); - } - - $dbh->bz_commit_transaction(); + my ($self, $flag_id, $defer_until) = @_; + my $dbh = Bugzilla->dbh; + + $dbh->bz_start_transaction(); + + my ($defer_id) + = $dbh->selectrow_array("SELECT id FROM nag_defer WHERE flag_id=?", + undef, $flag_id); + if ($defer_id) { + $dbh->do("UPDATE nag_defer SET defer_until=? WHERE id=?", + undef, $defer_until->ymd, $flag_id); + } + else { + $dbh->do("INSERT INTO nag_defer(flag_id, defer_until) VALUES (?, ?)", + undef, $flag_id, $defer_until->ymd); + } + + $dbh->bz_commit_transaction(); } sub object_end_of_update { - my ($self, $args) = @_; - if ($args->{object}->isa("Bugzilla::Flag") && exists $args->{changes}) { - # any change to the flag (setting, clearing, or retargetting) will clear the deferals - my $flag = $args->{object}; - Bugzilla->dbh->do("DELETE FROM nag_defer WHERE flag_id=?", undef, $flag->id); - } + my ($self, $args) = @_; + if ($args->{object}->isa("Bugzilla::Flag") && exists $args->{changes}) { + +# any change to the flag (setting, clearing, or retargetting) will clear the deferals + my $flag = $args->{object}; + Bugzilla->dbh->do("DELETE FROM nag_defer WHERE flag_id=?", undef, $flag->id); + } } sub user_preferences { - my ($self, $args) = @_; - my $tab = $args->{'current_tab'}; - return unless $tab eq 'request_nagging'; - - my $save = $args->{'save_changes'}; - my $vars = $args->{'vars'}; - my $user = Bugzilla->user; - my $dbh = Bugzilla->dbh; - - my %watching = - map { $_ => 1 } - @{ $dbh->selectcol_arrayref( - "SELECT profiles.login_name + my ($self, $args) = @_; + my $tab = $args->{'current_tab'}; + return unless $tab eq 'request_nagging'; + + my $save = $args->{'save_changes'}; + my $vars = $args->{'vars'}; + my $user = Bugzilla->user; + my $dbh = Bugzilla->dbh; + + my %watching = map { $_ => 1 } @{ + $dbh->selectcol_arrayref( + "SELECT profiles.login_name FROM nag_watch INNER JOIN profiles ON nag_watch.nagged_id = profiles.userid WHERE nag_watch.watcher_id = ? - ORDER BY profiles.login_name", - undef, - $user->id - ) }; - - my $nag_settings = Bugzilla::Extension::RequestNagger::Settings->new($user->id); - - if ($save) { - my $input = Bugzilla->input_params; - Bugzilla::User::match_field({ 'add_watching' => {'type' => 'multi'} }); - - $dbh->bz_start_transaction(); - - # user preference - if (my $value = $input->{request_nagging}) { - my $settings = $user->settings; - my $setting = new Bugzilla::User::Setting('request_nagging'); - if ($value eq 'default') { - $settings->{request_nagging}->reset_to_default; - } - else { - $setting->validate_value($value); - $settings->{request_nagging}->set($value); - } - } - - # watching - if ($input->{remove_watched_users}) { - my $del_watching = ref($input->{del_watching}) ? $input->{del_watching} : [ $input->{del_watching} ]; - foreach my $login (@$del_watching) { - my $u = Bugzilla::User->new({ name => $login, cache => 1 }) - || next; - next unless exists $watching{$u->login}; - $dbh->do( - "DELETE FROM nag_watch WHERE watcher_id=? AND nagged_id=?", - undef, - $user->id, $u->id - ); - delete $watching{$u->login}; - } - } - if ($input->{add_watching}) { - my $add_watching = ref($input->{add_watching}) ? $input->{add_watching} : [ $input->{add_watching} ]; - foreach my $login (@$add_watching) { - my $u = Bugzilla::User->new({ name => $login, cache => 1 }) - || next; - next if exists $watching{$u->login}; - $dbh->do( - "INSERT INTO nag_watch(watcher_id, nagged_id) VALUES(?, ?)", - undef, - $user->id, $u->id - ); - $watching{$u->login} = 1; - } - } - - # watching settings - foreach my $field (Bugzilla::Extension::RequestNagger::Settings::FIELDS()) { - $nag_settings->set($field, $input->{$field}); - } - - $dbh->bz_commit_transaction(); + ORDER BY profiles.login_name", undef, $user->id + ) + }; + + my $nag_settings = Bugzilla::Extension::RequestNagger::Settings->new($user->id); + + if ($save) { + my $input = Bugzilla->input_params; + Bugzilla::User::match_field({'add_watching' => {'type' => 'multi'}}); + + $dbh->bz_start_transaction(); + + # user preference + if (my $value = $input->{request_nagging}) { + my $settings = $user->settings; + my $setting = new Bugzilla::User::Setting('request_nagging'); + if ($value eq 'default') { + $settings->{request_nagging}->reset_to_default; + } + else { + $setting->validate_value($value); + $settings->{request_nagging}->set($value); + } } - $vars->{watching} = [ sort keys %watching ]; - $vars->{settings} = $nag_settings; + # watching + if ($input->{remove_watched_users}) { + my $del_watching + = ref($input->{del_watching}) + ? $input->{del_watching} + : [$input->{del_watching}]; + foreach my $login (@$del_watching) { + my $u = Bugzilla::User->new({name => $login, cache => 1}) || next; + next unless exists $watching{$u->login}; + $dbh->do("DELETE FROM nag_watch WHERE watcher_id=? AND nagged_id=?", + undef, $user->id, $u->id); + delete $watching{$u->login}; + } + } + if ($input->{add_watching}) { + my $add_watching + = ref($input->{add_watching}) + ? $input->{add_watching} + : [$input->{add_watching}]; + foreach my $login (@$add_watching) { + my $u = Bugzilla::User->new({name => $login, cache => 1}) || next; + next if exists $watching{$u->login}; + $dbh->do("INSERT INTO nag_watch(watcher_id, nagged_id) VALUES(?, ?)", + undef, $user->id, $u->id); + $watching{$u->login} = 1; + } + } + + # watching settings + foreach my $field (Bugzilla::Extension::RequestNagger::Settings::FIELDS()) { + $nag_settings->set($field, $input->{$field}); + } - my $handled = $args->{'handled'}; - $$handled = 1; + $dbh->bz_commit_transaction(); + } + + $vars->{watching} = [sort keys %watching]; + $vars->{settings} = $nag_settings; + + my $handled = $args->{'handled'}; + $$handled = 1; } # @@ -267,125 +265,77 @@ sub user_preferences { # sub db_schema_abstract_schema { - my ($self, $args) = @_; - $args->{'schema'}->{'nag_watch'} = { - FIELDS => [ - id => { - TYPE => 'MEDIUMSERIAL', - NOTNULL => 1, - PRIMARYKEY => 1, - }, - nagged_id => { - TYPE => 'INT3', - NOTNULL => 1, - REFERENCES => { - TABLE => 'profiles', - COLUMN => 'userid', - DELETE => 'CASCADE', - } - }, - watcher_id => { - TYPE => 'INT3', - NOTNULL => 1, - REFERENCES => { - TABLE => 'profiles', - COLUMN => 'userid', - DELETE => 'CASCADE', - } - }, - ], - INDEXES => [ - nag_watch_idx => { - FIELDS => [ 'nagged_id', 'watcher_id' ], - TYPE => 'UNIQUE', - }, - ], - }; - $args->{'schema'}->{'nag_defer'} = { - FIELDS => [ - id => { - TYPE => 'MEDIUMSERIAL', - NOTNULL => 1, - PRIMARYKEY => 1, - }, - flag_id => { - TYPE => 'INT3', - NOTNULL => 1, - REFERENCES => { - TABLE => 'flags', - COLUMN => 'id', - DELETE => 'CASCADE', - } - }, - defer_until => { - TYPE => 'DATETIME', - NOTNULL => 1, - }, - ], - INDEXES => [ - nag_defer_idx => { - FIELDS => [ 'flag_id' ], - TYPE => 'UNIQUE', - }, - ], - }; - $args->{'schema'}->{'nag_settings'} = { - FIELDS => [ - id => { - TYPE => 'MEDIUMSERIAL', - NOTNULL => 1, - PRIMARYKEY => 1, - }, - user_id => { - TYPE => 'INT3', - NOTNULL => 1, - REFERENCES => { - TABLE => 'profiles', - COLUMN => 'userid', - DELETE => 'CASCADE', - } - }, - setting_name => { - TYPE => 'VARCHAR(16)', - NOTNULL => 1, - }, - setting_value => { - TYPE => 'VARCHAR(16)', - NOTNULL => 1, - }, - ], - INDEXES => [ - nag_setting_idx => { - FIELDS => [ 'user_id', 'setting_name' ], - TYPE => 'UNIQUE', - }, - ], - }; + my ($self, $args) = @_; + $args->{'schema'}->{'nag_watch'} = { + FIELDS => [ + id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1,}, + nagged_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE',} + }, + watcher_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE',} + }, + ], + INDEXES => [ + nag_watch_idx => {FIELDS => ['nagged_id', 'watcher_id'], TYPE => 'UNIQUE',}, + ], + }; + $args->{'schema'}->{'nag_defer'} = { + FIELDS => [ + id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1,}, + flag_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => {TABLE => 'flags', COLUMN => 'id', DELETE => 'CASCADE',} + }, + defer_until => {TYPE => 'DATETIME', NOTNULL => 1,}, + ], + INDEXES => [nag_defer_idx => {FIELDS => ['flag_id'], TYPE => 'UNIQUE',},], + }; + $args->{'schema'}->{'nag_settings'} = { + FIELDS => [ + id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1,}, + user_id => { + TYPE => 'INT3', + NOTNULL => 1, + REFERENCES => {TABLE => 'profiles', COLUMN => 'userid', DELETE => 'CASCADE',} + }, + setting_name => {TYPE => 'VARCHAR(16)', NOTNULL => 1,}, + setting_value => {TYPE => 'VARCHAR(16)', NOTNULL => 1,}, + ], + INDEXES => [ + nag_setting_idx => {FIELDS => ['user_id', 'setting_name'], TYPE => 'UNIQUE',}, + ], + }; } sub install_update_db { - my $dbh = Bugzilla->dbh; - $dbh->bz_add_column('products', 'nag_interval', { TYPE => 'INT2', NOTNULL => 1, DEFAULT => 7 * 24 }); + my $dbh = Bugzilla->dbh; + $dbh->bz_add_column('products', 'nag_interval', + {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 7 * 24}); } sub install_filesystem { - my ($self, $args) = @_; - my $files = $args->{'files'}; - my $extensions_dir = bz_locations()->{'extensionsdir'}; - my $script_name = $extensions_dir . "/" . __PACKAGE__->NAME . "/bin/send-request-nags.pl"; - $files->{$script_name} = { - perms => Bugzilla::Install::Filesystem::WS_EXECUTE - }; + my ($self, $args) = @_; + my $files = $args->{'files'}; + my $extensions_dir = bz_locations()->{'extensionsdir'}; + my $script_name + = $extensions_dir . "/" . __PACKAGE__->NAME . "/bin/send-request-nags.pl"; + $files->{$script_name} = {perms => Bugzilla::Install::Filesystem::WS_EXECUTE}; } sub install_before_final_checks { - my ($self, $args) = @_; - add_setting({ - name => 'request_nagging', - options => ['on', 'off'], - default => 'on', - category => 'Reviews and Needinfo' - }); + my ($self, $args) = @_; + add_setting({ + name => 'request_nagging', + options => ['on', 'off'], + default => 'on', + category => 'Reviews and Needinfo' + }); } __PACKAGE__->NAME; diff --git a/extensions/RequestNagger/bin/send-request-nags.pl b/extensions/RequestNagger/bin/send-request-nags.pl index f823fc197..33c49d2b6 100755 --- a/extensions/RequestNagger/bin/send-request-nags.pl +++ b/extensions/RequestNagger/bin/send-request-nags.pl @@ -39,8 +39,8 @@ my $DO_NOT_NAG = grep { $_ eq '-d' } @ARGV; @ARGV = grep { !/^-/ } @ARGV; if (my $filename = shift @ARGV) { - _send_email(decode_json(scalar read_file($filename))); - exit; + _send_email(decode_json(scalar read_file($filename))); + exit; } my $dbh = Bugzilla->dbh; @@ -53,269 +53,272 @@ Bugzilla->switch_to_shadow_db(); # send nags to requestees send_nags( - reports => [ 'requestee' ], - requestee_sql => REQUESTEE_NAG_SQL, - setter_sql => SETTER_NAG_SQL, - template => 'user', - date => $date, + reports => ['requestee'], + requestee_sql => REQUESTEE_NAG_SQL, + setter_sql => SETTER_NAG_SQL, + template => 'user', + date => $date, ); # send nags to watchers send_nags( - reports => [ 'requestee', 'setter' ], - requestee_sql => WATCHING_REQUESTEE_NAG_SQL, - setter_sql => WATCHING_SETTER_NAG_SQL, - template => 'watching', - date => $date, + reports => ['requestee', 'setter'], + requestee_sql => WATCHING_REQUESTEE_NAG_SQL, + setter_sql => WATCHING_SETTER_NAG_SQL, + template => 'watching', + date => $date, ); sub send_nags { - my (%args) = @_; - my $requests = {}; - my $watching = $args{template} eq 'watching'; - - # get requests - - foreach my $report (@{ $args{reports} }) { - - # collate requests - my $rows = $dbh->selectall_arrayref($args{$report . '_sql'}, { Slice => {} }); - foreach my $request (@$rows) { - next unless _include_request($request, $report); - - my $target = Bugzilla::User->new({ id => $request->{target_id}, cache => 1 }); - push @{ - $requests - ->{$request->{recipient_id}} - ->{$target->login} - ->{$report} - ->{$request->{flag_type}} - }, $request; - push @{ - $requests - ->{$request->{recipient_id}} - ->{$target->login} - ->{bug_ids} - ->{$report} - }, $request->{bug_id}; - } + my (%args) = @_; + my $requests = {}; + my $watching = $args{template} eq 'watching'; - # process requests here to avoid doing it in the templates - foreach my $recipient_id (keys %$requests) { - foreach my $target_login (keys %{ $requests->{$recipient_id} }) { - my $rh = $requests->{$recipient_id}->{$target_login}; - - # build a list of valid types in the correct order - $rh->{types}->{$report} = []; - foreach my $type (map { $_->{type} } FLAG_TYPES) { - next unless exists $rh->{$report}->{$type}; - push @{ $rh->{types}->{$report} }, $type; - } - - # build a summary - $rh->{summary}->{$report} = join(', ', - map { scalar(@{ $rh->{$report}->{$_} }) . ' ' . $_ } - @{ $rh->{types}->{$report} } - ); - - if ($watching && $report eq 'setter') { - # remove links to reports with too many items to display - my $total = 0; - foreach my $type (@{ $rh->{types}->{$report} }) { - $total += scalar(@{ $rh->{$report}->{$type} }); - } - if ($total > MAX_SETTER_COUNT) { - $rh->{types}->{$report} = []; - } - } - } - } - } + # get requests - # send emails - - foreach my $recipient_id (sort keys %$requests) { - # send the email in a separate process to avoid excessive memory usage - my $params = { - recipient_id => $recipient_id, - template => $args{template}, - date => $args{date}, - reports => $args{reports}, - requests => $requests->{$recipient_id}, - }; - my ($fh, $filename) = tempfile(); - print $fh encode_json($params); - close($fh); - - my @command = ($0, $filename); - push @command, '-d' if $DO_NOT_NAG; - system(@command); - unlink($filename); - } -} - -sub _include_request { - my ($request, $report) = @_; - state $now = datetime_from($db_date, 'UTC')->truncate( to => 'day' ); - - my $recipient = Bugzilla::User->new({ id => $request->{recipient_id}, cache => 1 }); - - if ($report eq 'requestee') { - # check recipient group membership - my $group; - foreach my $type (FLAG_TYPES) { - next unless $type->{type} eq $request->{flag_type}; - $group = $type->{group}; - last; - } - return 0 unless $recipient->in_group($group); - } + foreach my $report (@{$args{reports}}) { - # check bug visibility - return 0 unless $recipient->can_see_bug($request->{bug_id}); + # collate requests + my $rows = $dbh->selectall_arrayref($args{$report . '_sql'}, {Slice => {}}); + foreach my $request (@$rows) { + next unless _include_request($request, $report); - # check attachment visibility - if ($request->{attach_id}) { - my $attachment = Bugzilla::Attachment->new({ id => $request->{attach_id}, cache => 1 }); - return 0 if $attachment->isprivate && !$recipient->is_insider; + my $target = Bugzilla::User->new({id => $request->{target_id}, cache => 1}); + push @{$requests->{$request->{recipient_id}}->{$target->login}->{$report} + ->{$request->{flag_type}}}, $request; + push @{$requests->{$request->{recipient_id}}->{$target->login}->{bug_ids} + ->{$report}}, $request->{bug_id}; } - # exclude weekends and re-check nag-interval - my $date = datetime_from($request->{modification_date}, 'UTC'); - my $hours = 0; - $hours += 24 - $date->hour if $date->day_of_week <= 5; - $date->add( days => 1 )->truncate( to => 'day' ); - while ($date < $now) { - $hours += 24 if $date->day_of_week <= 5; - $date->add( days => 1 ); - } - return 0 if $hours < ($request->{extended_period} ? $request->{nag_interval} + 24 : $request->{nag_interval}); + # process requests here to avoid doing it in the templates + foreach my $recipient_id (keys %$requests) { + foreach my $target_login (keys %{$requests->{$recipient_id}}) { + my $rh = $requests->{$recipient_id}->{$target_login}; - return 1; -} + # build a list of valid types in the correct order + $rh->{types}->{$report} = []; + foreach my $type (map { $_->{type} } FLAG_TYPES) { + next unless exists $rh->{$report}->{$type}; + push @{$rh->{types}->{$report}}, $type; + } -sub _send_email { - my ($params) = @_; - - my @reports = @{ $params->{reports} }; - my $recipient_id = $params->{recipient_id}; - my $requests = $params->{requests}; - my $watching = $params->{template} eq 'watching'; - my $recipient = Bugzilla::User->new({ id => $recipient_id, cache => 1 }); - my $securemail = Bugzilla::User->can('public_key'); - my $has_key = $securemail && $recipient->public_key; - my $has_private_bug = 0; - - my $settings = Bugzilla::Extension::RequestNagger::Settings->new($recipient_id); - if ($watching && $settings->no_encryption) { - $has_key = 0; - } + # build a summary + $rh->{summary}->{$report} = join(', ', + map { scalar(@{$rh->{$report}->{$_}}) . ' ' . $_ } @{$rh->{types}->{$report}}); + + if ($watching && $report eq 'setter') { - foreach my $target_login (keys %$requests) { - my $rh = $requests->{$target_login}; - $rh->{target} = Bugzilla::User->new({ name => $target_login, cache => 1 }); - foreach my $report (@reports) { - foreach my $type (keys %{ $rh->{$report} }) { - foreach my $request (@{ $rh->{$report}->{$type} }) { - - _create_objects($request); - - # we need to encrypt or censor emails which contain - # non-public bugs - if ($request->{bug}->is_private) { - $has_private_bug = 1; - $request->{bug}->{sanitise_bug} = !$securemail || !$has_key; - } - else { - $request->{bug}->{sanitise_bug} = 0; - } - } - } + # remove links to reports with too many items to display + my $total = 0; + foreach my $type (@{$rh->{types}->{$report}}) { + $total += scalar(@{$rh->{$report}->{$type}}); + } + if ($total > MAX_SETTER_COUNT) { + $rh->{types}->{$report} = []; + } } + } } - my $encrypt = $securemail && $has_private_bug && $has_key; - - # generate email - my $template = Bugzilla->template_inner($recipient->setting('lang')); - my $template_file = $params->{template}; - my $vars = { - recipient => $recipient, - requests => $requests, - date => $params->{date}, - }; + } - my ($header, $text); - $template->process("email/request_nagging-$template_file-header.txt.tmpl", $vars, \$header) - || ThrowTemplateError($template->error()); - $header .= "\n"; - $template->process("email/request_nagging-$template_file.txt.tmpl", $vars, \$text) - || ThrowTemplateError($template->error()); - - my @parts = ( - Email::MIME->create( - attributes => { - content_type => 'text/plain', - charset => 'UTF-8', - encoding => 'quoted-printable', - }, - body_str => $text, - ) - ); - if ($recipient->setting('email_format') eq 'html') { - my $html; - $template->process("email/request_nagging-$template_file.html.tmpl", $vars, \$html) - || ThrowTemplateError($template->error()); - push @parts, Email::MIME->create( - attributes => { - content_type => 'text/html', - charset => 'UTF-8', - encoding => 'quoted-printable', - }, - body_str => $html, - ); - } + # send emails - my $email = Email::MIME->new($header); - $email->header_set('X-Generated-By' => hostname()); - if (scalar(@parts) == 1) { - $email->content_type_set($parts[0]->content_type); - } - else { - $email->content_type_set('multipart/alternative'); - } - $email->parts_set(\@parts); - if ($encrypt) { - $email->header_set('X-Bugzilla-Encrypt' => '1'); - } + foreach my $recipient_id (sort keys %$requests) { - # send - if ($DO_NOT_NAG) { - # uncomment the following line to enable other extensions to - # process this email, including encryption - # Bugzilla::Hook::process('mailer_before_send', { email => $email }); - print $email->as_string, "\n"; - } - else { - MessageToMTA($email); - } + # send the email in a separate process to avoid excessive memory usage + my $params = { + recipient_id => $recipient_id, + template => $args{template}, + date => $args{date}, + reports => $args{reports}, + requests => $requests->{$recipient_id}, + }; + my ($fh, $filename) = tempfile(); + print $fh encode_json($params); + close($fh); + + my @command = ($0, $filename); + push @command, '-d' if $DO_NOT_NAG; + system(@command); + unlink($filename); + } } -sub _create_objects { - my ($request) = @_; +sub _include_request { + my ($request, $report) = @_; + state $now = datetime_from($db_date, 'UTC')->truncate(to => 'day'); - $request->{recipient} = Bugzilla::User->new({ id => $request->{recipient_id}, cache => 1 }); - $request->{setter} = Bugzilla::User->new({ id => $request->{setter_id}, cache => 1 }); + my $recipient + = Bugzilla::User->new({id => $request->{recipient_id}, cache => 1}); - if (defined $request->{requestee_id}) { - $request->{requestee} = Bugzilla::User->new({ id => $request->{requestee_id}, cache => 1 }); - } - if (exists $request->{watcher_id}) { - $request->{watcher} = Bugzilla::User->new({ id => $request->{watcher_id}, cache => 1 }); + if ($report eq 'requestee') { + + # check recipient group membership + my $group; + foreach my $type (FLAG_TYPES) { + next unless $type->{type} eq $request->{flag_type}; + $group = $type->{group}; + last; } + return 0 unless $recipient->in_group($group); + } + + # check bug visibility + return 0 unless $recipient->can_see_bug($request->{bug_id}); + + # check attachment visibility + if ($request->{attach_id}) { + my $attachment + = Bugzilla::Attachment->new({id => $request->{attach_id}, cache => 1}); + return 0 if $attachment->isprivate && !$recipient->is_insider; + } + + # exclude weekends and re-check nag-interval + my $date = datetime_from($request->{modification_date}, 'UTC'); + my $hours = 0; + $hours += 24 - $date->hour if $date->day_of_week <= 5; + $date->add(days => 1)->truncate(to => 'day'); + while ($date < $now) { + $hours += 24 if $date->day_of_week <= 5; + $date->add(days => 1); + } + return 0 + if $hours < ($request->{extended_period} + ? $request->{nag_interval} + 24 + : $request->{nag_interval}); + + return 1; +} - $request->{bug} = Bugzilla::Extension::RequestNagger::Bug->new({ id => $request->{bug_id}, cache => 1 }); - $request->{flag} = Bugzilla::Flag->new({ id => $request->{flag_id}, cache => 1 }); - if (defined $request->{attach_id}) { - $request->{attachment} = Bugzilla::Attachment->new({ id => $request->{attach_id}, cache => 1 }); +sub _send_email { + my ($params) = @_; + + my @reports = @{$params->{reports}}; + my $recipient_id = $params->{recipient_id}; + my $requests = $params->{requests}; + my $watching = $params->{template} eq 'watching'; + my $recipient = Bugzilla::User->new({id => $recipient_id, cache => 1}); + my $securemail = Bugzilla::User->can('public_key'); + my $has_key = $securemail && $recipient->public_key; + my $has_private_bug = 0; + + my $settings = Bugzilla::Extension::RequestNagger::Settings->new($recipient_id); + if ($watching && $settings->no_encryption) { + $has_key = 0; + } + + foreach my $target_login (keys %$requests) { + my $rh = $requests->{$target_login}; + $rh->{target} = Bugzilla::User->new({name => $target_login, cache => 1}); + foreach my $report (@reports) { + foreach my $type (keys %{$rh->{$report}}) { + foreach my $request (@{$rh->{$report}->{$type}}) { + + _create_objects($request); + + # we need to encrypt or censor emails which contain + # non-public bugs + if ($request->{bug}->is_private) { + $has_private_bug = 1; + $request->{bug}->{sanitise_bug} = !$securemail || !$has_key; + } + else { + $request->{bug}->{sanitise_bug} = 0; + } + } + } } + } + my $encrypt = $securemail && $has_private_bug && $has_key; + + # generate email + my $template = Bugzilla->template_inner($recipient->setting('lang')); + my $template_file = $params->{template}; + my $vars + = {recipient => $recipient, requests => $requests, date => $params->{date},}; + + my ($header, $text); + $template->process("email/request_nagging-$template_file-header.txt.tmpl", + $vars, \$header) + || ThrowTemplateError($template->error()); + $header .= "\n"; + $template->process("email/request_nagging-$template_file.txt.tmpl", + $vars, \$text) + || ThrowTemplateError($template->error()); + + my @parts = (Email::MIME->create( + attributes => { + content_type => 'text/plain', + charset => 'UTF-8', + encoding => 'quoted-printable', + }, + body_str => $text, + )); + + if ($recipient->setting('email_format') eq 'html') { + my $html; + $template->process("email/request_nagging-$template_file.html.tmpl", + $vars, \$html) + || ThrowTemplateError($template->error()); + push @parts, + Email::MIME->create( + attributes => { + content_type => 'text/html', + charset => 'UTF-8', + encoding => 'quoted-printable', + }, + body_str => $html, + ); + } + + my $email = Email::MIME->new($header); + $email->header_set('X-Generated-By' => hostname()); + if (scalar(@parts) == 1) { + $email->content_type_set($parts[0]->content_type); + } + else { + $email->content_type_set('multipart/alternative'); + } + $email->parts_set(\@parts); + if ($encrypt) { + $email->header_set('X-Bugzilla-Encrypt' => '1'); + } + + # send + if ($DO_NOT_NAG) { + + # uncomment the following line to enable other extensions to + # process this email, including encryption + # Bugzilla::Hook::process('mailer_before_send', { email => $email }); + print $email->as_string, "\n"; + } + else { + MessageToMTA($email); + } +} + +sub _create_objects { + my ($request) = @_; + + $request->{recipient} + = Bugzilla::User->new({id => $request->{recipient_id}, cache => 1}); + $request->{setter} + = Bugzilla::User->new({id => $request->{setter_id}, cache => 1}); + + if (defined $request->{requestee_id}) { + $request->{requestee} + = Bugzilla::User->new({id => $request->{requestee_id}, cache => 1}); + } + if (exists $request->{watcher_id}) { + $request->{watcher} + = Bugzilla::User->new({id => $request->{watcher_id}, cache => 1}); + } + + $request->{bug} = Bugzilla::Extension::RequestNagger::Bug->new( + {id => $request->{bug_id}, cache => 1}); + $request->{flag} = Bugzilla::Flag->new({id => $request->{flag_id}, cache => 1}); + if (defined $request->{attach_id}) { + $request->{attachment} + = Bugzilla::Attachment->new({id => $request->{attach_id}, cache => 1}); + } } diff --git a/extensions/RequestNagger/lib/Bug.pm b/extensions/RequestNagger/lib/Bug.pm index 974a688ea..dc510d486 100644 --- a/extensions/RequestNagger/lib/Bug.pm +++ b/extensions/RequestNagger/lib/Bug.pm @@ -17,29 +17,29 @@ use feature 'state'; use Bugzilla::User; sub short_desc { - my ($self) = @_; - return $self->{sanitise_bug} ? '(Secure bug)' : $self->SUPER::short_desc; + my ($self) = @_; + return $self->{sanitise_bug} ? '(Secure bug)' : $self->SUPER::short_desc; } sub is_private { - my ($self) = @_; - if (!exists $self->{is_private}) { - state $default_user //= Bugzilla::User->new(); - $self->{is_private} = !$default_user->can_see_bug($self); - } - return $self->{is_private}; + my ($self) = @_; + if (!exists $self->{is_private}) { + state $default_user //= Bugzilla::User->new(); + $self->{is_private} = !$default_user->can_see_bug($self); + } + return $self->{is_private}; } sub tooltip { - my ($self) = @_; - my $tooltip = $self->bug_status; - if ($self->bug_status eq 'RESOLVED') { - $tooltip .= '/' . $self->resolution; - } - if (!$self->{sanitise_bug}) { - $tooltip .= ' ' . $self->product . ' :: ' . $self->component; - } - return $tooltip; + my ($self) = @_; + my $tooltip = $self->bug_status; + if ($self->bug_status eq 'RESOLVED') { + $tooltip .= '/' . $self->resolution; + } + if (!$self->{sanitise_bug}) { + $tooltip .= ' ' . $self->product . ' :: ' . $self->component; + } + return $tooltip; } 1; diff --git a/extensions/RequestNagger/lib/Constants.pm b/extensions/RequestNagger/lib/Constants.pm index bc6cf3371..1309e06c9 100644 --- a/extensions/RequestNagger/lib/Constants.pm +++ b/extensions/RequestNagger/lib/Constants.pm @@ -14,13 +14,13 @@ use warnings; use base qw(Exporter); our @EXPORT = qw( - MAX_SETTER_COUNT - MAX_REQUEST_AGE - FLAG_TYPES - REQUESTEE_NAG_SQL - SETTER_NAG_SQL - WATCHING_REQUESTEE_NAG_SQL - WATCHING_SETTER_NAG_SQL + MAX_SETTER_COUNT + MAX_REQUEST_AGE + FLAG_TYPES + REQUESTEE_NAG_SQL + SETTER_NAG_SQL + WATCHING_REQUESTEE_NAG_SQL + WATCHING_SETTER_NAG_SQL ); # if there are more than this many requests that a user is waiting on, show a @@ -29,33 +29,24 @@ use constant MAX_SETTER_COUNT => 7; # ignore any request older than this many days in the requestee emails # massively overdue requests will still be included in the 'watching' emails -use constant MAX_REQUEST_AGE => 90; # about three months +use constant MAX_REQUEST_AGE => 90; # about three months # the order of this array determines the order used in email use constant FLAG_TYPES => ( - { - type => 'review', # flag_type.name - group => 'everyone', # the user must be a member of this group to receive reminders - }, - { - type => 'superview', - group => 'everyone', - }, - { - type => 'feedback', - group => 'everyone', - }, - { - type => 'needinfo', - group => 'editbugs', - }, + { + type => 'review', # flag_type.name + group => 'everyone', # the user must be a member of this group to receive reminders + }, + {type => 'superview', group => 'everyone',}, + {type => 'feedback', group => 'everyone',}, + {type => 'needinfo', group => 'editbugs',}, ); sub REQUESTEE_NAG_SQL { - my $dbh = Bugzilla->dbh; - my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; + my $dbh = Bugzilla->dbh; + my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; - return " + return " SELECT flagtypes.name AS flag_type, flags.id AS flag_id, @@ -84,7 +75,8 @@ sub REQUESTEE_NAG_SQL { AND flags.status = '?' AND products.nag_interval != 0 AND TIMESTAMPDIFF(HOUR, flags.modification_date, CURRENT_DATE()) >= products.nag_interval - AND TIMESTAMPDIFF(DAY, flags.modification_date, CURRENT_DATE()) <= " . MAX_REQUEST_AGE . " + AND TIMESTAMPDIFF(DAY, flags.modification_date, CURRENT_DATE()) <= " + . MAX_REQUEST_AGE . " AND (profile_setting.setting_value IS NULL OR profile_setting.setting_value = 'on') AND requestee.disable_mail = 0 AND nag_defer.id IS NULL @@ -96,10 +88,10 @@ sub REQUESTEE_NAG_SQL { } sub SETTER_NAG_SQL { - my $dbh = Bugzilla->dbh; - my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; + my $dbh = Bugzilla->dbh; + my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; - return " + return " SELECT flagtypes.name AS flag_type, flags.id AS flag_id, @@ -128,7 +120,8 @@ sub SETTER_NAG_SQL { AND flags.status = '?' AND products.nag_interval != 0 AND TIMESTAMPDIFF(HOUR, flags.modification_date, CURRENT_DATE()) >= products.nag_interval - AND TIMESTAMPDIFF(DAY, flags.modification_date, CURRENT_DATE()) <= " . MAX_REQUEST_AGE . " + AND TIMESTAMPDIFF(DAY, flags.modification_date, CURRENT_DATE()) <= " + . MAX_REQUEST_AGE . " AND (profile_setting.setting_value IS NULL OR profile_setting.setting_value = 'on') AND setter.disable_mail = 0 AND nag_defer.id IS NULL @@ -140,10 +133,10 @@ sub SETTER_NAG_SQL { } sub WATCHING_REQUESTEE_NAG_SQL { - my $dbh = Bugzilla->dbh; - my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; + my $dbh = Bugzilla->dbh; + my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; - return " + return " SELECT nag_watch.watcher_id, flagtypes.name AS flag_type, @@ -192,10 +185,10 @@ sub WATCHING_REQUESTEE_NAG_SQL { } sub WATCHING_SETTER_NAG_SQL { - my $dbh = Bugzilla->dbh; - my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; + my $dbh = Bugzilla->dbh; + my @flag_types_sql = map { $dbh->quote($_->{type}) } FLAG_TYPES; - return " + return " SELECT nag_watch.watcher_id, flagtypes.name AS flag_type, diff --git a/extensions/RequestNagger/lib/Settings.pm b/extensions/RequestNagger/lib/Settings.pm index 393d224ba..839c37485 100644 --- a/extensions/RequestNagger/lib/Settings.pm +++ b/extensions/RequestNagger/lib/Settings.pm @@ -17,47 +17,48 @@ use List::MoreUtils qw( any ); use constant FIELDS => qw( reviews_only extended_period no_encryption ); sub new { - my ($class, $user_id) = @_; - - my $dbh = Bugzilla->dbh; - my $self = { user_id => $user_id }; - foreach my $row (@{ $dbh->selectall_arrayref( - "SELECT setting_name,setting_value FROM nag_settings WHERE user_id = ?", - { Slice => {} }, - $user_id - ) }) { - $self->{$row->{setting_name}} = $row->{setting_value}; - } - - return bless($self, $class); + my ($class, $user_id) = @_; + + my $dbh = Bugzilla->dbh; + my $self = {user_id => $user_id}; + foreach my $row (@{ + $dbh->selectall_arrayref( + "SELECT setting_name,setting_value FROM nag_settings WHERE user_id = ?", + {Slice => {}}, $user_id) + }) + { + $self->{$row->{setting_name}} = $row->{setting_value}; + } + + return bless($self, $class); } -sub reviews_only { exists $_[0]->{reviews_only} ? $_[0]->{reviews_only} : 0 } -sub extended_period { exists $_[0]->{extended_period} ? $_[0]->{extended_period} : 0 } -sub no_encryption { exists $_[0]->{no_encryption} ? $_[0]->{no_encryption} : 0 } +sub reviews_only { exists $_[0]->{reviews_only} ? $_[0]->{reviews_only} : 0 } + +sub extended_period { + exists $_[0]->{extended_period} ? $_[0]->{extended_period} : 0; +} +sub no_encryption { exists $_[0]->{no_encryption} ? $_[0]->{no_encryption} : 0 } sub set { - my ($self, $field, $value) = @_; - return unless any { $_ eq $field } FIELDS; - $value = $value ? 1 : 0; - - my $dbh = Bugzilla->dbh; - if (exists $self->{$field}) { - $dbh->do( - "UPDATE nag_settings SET setting_value=? WHERE user_id=? AND setting_name=?", - undef, - $value, $self->{user_id}, $field - ); - } - else { - $dbh->do( - "INSERT INTO nag_settings(user_id, setting_name, setting_value) VALUES (?, ?, ?)", - undef, - $self->{user_id}, $field, $value - ); - } - - $self->{$field} = $value; + my ($self, $field, $value) = @_; + return unless any { $_ eq $field } FIELDS; + $value = $value ? 1 : 0; + + my $dbh = Bugzilla->dbh; + if (exists $self->{$field}) { + $dbh->do( + "UPDATE nag_settings SET setting_value=? WHERE user_id=? AND setting_name=?", + undef, $value, $self->{user_id}, $field); + } + else { + $dbh->do( + "INSERT INTO nag_settings(user_id, setting_name, setting_value) VALUES (?, ?, ?)", + undef, $self->{user_id}, $field, $value + ); + } + + $self->{$field} = $value; } 1; |