summaryrefslogtreecommitdiffstats
path: root/extensions/RequestNagger/bin/send-request-nags.pl
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/RequestNagger/bin/send-request-nags.pl')
-rw-r--r--extensions/RequestNagger/bin/send-request-nags.pl183
1 files changed, 183 insertions, 0 deletions
diff --git a/extensions/RequestNagger/bin/send-request-nags.pl b/extensions/RequestNagger/bin/send-request-nags.pl
new file mode 100644
index 000000000..c62d91f03
--- /dev/null
+++ b/extensions/RequestNagger/bin/send-request-nags.pl
@@ -0,0 +1,183 @@
+#!/usr/bin/perl
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+use strict;
+use warnings;
+
+use FindBin qw($RealBin);
+use lib "$RealBin/../../..";
+
+use Bugzilla;
+BEGIN { Bugzilla->extensions() }
+
+use Bugzilla::Attachment;
+use Bugzilla::Bug;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Extension::RequestNagger::Constants;
+use Bugzilla::Mailer;
+use Bugzilla::User;
+use Bugzilla::Util qw(format_time);
+use Email::MIME;
+use Sys::Hostname;
+
+Bugzilla->usage_mode(USAGE_MODE_CMDLINE);
+
+my $DO_NOT_NAG = grep { $_ eq '-d' } @ARGV;
+
+my $dbh = Bugzilla->dbh;
+my $date = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+$date = format_time($date, '%a, %d %b %Y %T %z', 'UTC');
+
+# delete expired defers
+$dbh->do("DELETE FROM nag_defer WHERE defer_until <= CURRENT_DATE()");
+Bugzilla->switch_to_shadow_db();
+
+# send nags to requestees
+send_nags(
+ sql => REQUESTEE_NAG_SQL,
+ template => 'requestee',
+ recipient_field => 'requestee_id',
+ date => $date,
+);
+
+# send nags to watchers
+send_nags(
+ sql => WATCHING_NAG_SQL,
+ template => 'watching',
+ recipient_field => 'watcher_id',
+ date => $date,
+);
+
+sub send_nags {
+ my (%args) = @_;
+ my $rows = $dbh->selectall_arrayref($args{sql}, { Slice => {} });
+
+ # iterate over rows, sending email when the current recipient changes
+ my $requests = [];
+ my $current_recipient;
+ foreach my $request (@$rows) {
+ # send previous user's requests
+ if (!$current_recipient || $request->{$args{recipient_field}} != $current_recipient->id) {
+ send_email(%args, recipient => $current_recipient, requests => $requests);
+ $current_recipient = Bugzilla::User->new({ id => $request->{$args{recipient_field}}, cache => 1 });
+ $requests = [];
+ }
+
+ # check group membership
+ $request->{requestee} = Bugzilla::User->new({ id => $request->{requestee_id}, cache => 1 });
+ my $group;
+ foreach my $type (FLAG_TYPES) {
+ next unless $type->{type} eq $request->{flag_type};
+ $group = $type->{group};
+ last;
+ }
+ next unless $request->{requestee}->in_group($group);
+
+ # check bug visibility
+ next unless $current_recipient->can_see_bug($request->{bug_id});
+
+ # create objects
+ $request->{bug} = Bugzilla::Bug->new({ id => $request->{bug_id}, cache => 1 });
+ $request->{requester} = Bugzilla::User->new({ id => $request->{requester_id}, cache => 1 });
+ $request->{flag} = Bugzilla::Flag->new({ id => $request->{flag_id}, cache => 1 });
+ if ($request->{attach_id}) {
+ $request->{attachment} = Bugzilla::Attachment->new({ id => $request->{attach_id}, cache => 1 });
+ # check attachment visibility
+ next if $request->{attachment}->isprivate && !$current_recipient->is_insider;
+ }
+ if (exists $request->{watcher_id}) {
+ $request->{watcher} = Bugzilla::User->new({ id => $request->{watcher_id}, cache => 1 });
+ }
+
+ # add this request to the current user's list
+ push(@$requests, $request);
+ }
+ send_email(%args, recipient => $current_recipient, requests => $requests);
+}
+
+sub send_email {
+ my (%vars) = @_;
+ my $vars = \%vars;
+ return unless $vars->{recipient} && @{ $vars->{requests} };
+
+ # restructure the list to group by requestee then flag type
+ my $request_list = delete $vars->{requests};
+ my $requests = {};
+ my %seen_types;
+ foreach my $request (@{ $request_list }) {
+ # by requestee
+ my $requestee_login = $request->{requestee}->login;
+ $requests->{$requestee_login} ||= {
+ requestee => $request->{requestee},
+ types => {},
+ typelist => [],
+ };
+
+ # by flag type
+ my $types = $requests->{$requestee_login}->{types};
+ my $flag_type = $request->{flag_type};
+ $types->{$flag_type} ||= [];
+
+ push @{ $types->{$flag_type} }, $request;
+ $seen_types{$requestee_login}{$flag_type} = 1;
+ }
+ foreach my $requestee_login (keys %seen_types) {
+ my @flag_types;
+ foreach my $flag_type (map { $_->{type} } FLAG_TYPES) {
+ push @flag_types, $flag_type if $seen_types{$requestee_login}{$flag_type};
+ }
+ $requests->{$requestee_login}->{typelist} = \@flag_types;
+ }
+ $vars->{requests} = $requests;
+
+ # generate email
+ my $template = Bugzilla->template_inner($vars->{recipient}->setting('lang'));
+ my $template_file = $vars->{template};
+
+ 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" },
+ body => $text,
+ )
+ );
+ if ($vars->{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" },
+ body => $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);
+
+ # send
+ if ($DO_NOT_NAG) {
+ print $email->as_string, "\n";
+ } else {
+ MessageToMTA($email);
+ }
+}
+