aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Script/Reports.pm
blob: 3d5afe2168e37e74cc9d9ac115ece8f4b67b18d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package FixMyStreet::Script::Reports;

use Moo;
use CronFns;
use FixMyStreet;
use FixMyStreet::DB;
use FixMyStreet::Queue::Item::Report;

has verbose => ( is => 'ro' );

has unconfirmed_data => ( is => 'ro', default => sub { {} } );
has test_data => ( is => 'ro', default => sub { {} } );

# Static method, used by send-reports cron script and tests.
# Creates a manager object from provided data and processes it.
sub send {
    my ($verbose, $nomail, $debug) = @_;

    my $manager = __PACKAGE__->new(
        verbose => $verbose,
    );

    my $params = construct_query($debug);
    my $db = FixMyStreet::DB->schema->storage;

    $db->txn_do(sub {
        my $unsent = FixMyStreet::DB->resultset('Problem')->search($params, {
            for => \'UPDATE SKIP LOCKED',
        });

        $manager->log("starting to loop through unsent problem reports...");
        my $unsent_count = 0;
        while (my $row = $unsent->next) {
            $unsent_count++;
            my $item = FixMyStreet::Queue::Item::Report->new(
                report => $row,
                manager => $manager,
                verbose => $verbose,
                nomail => $nomail,
            );
            $item->process;
        }

        $manager->end_line($unsent_count);
        $manager->end_summary_unconfirmed;
    });

    return $manager->test_data;
}

sub construct_query {
    my ($debug) = @_;
    my $site = CronFns::site(FixMyStreet->config('BASE_URL'));
    my $states = [ FixMyStreet::DB::Result::Problem::open_states() ];
    $states = [ 'submitted', 'confirmed', 'in progress', 'feedback pending', 'external', 'wish' ] if $site eq 'zurich';

    # Devolved Noop categories (unlikely to be any, but still)
    my @noop_params;
    my $noop_cats = FixMyStreet::DB->resultset('Contact')->search({
        'body.can_be_devolved' => 1,
        'me.send_method' => 'Noop'
    }, { join => 'body' });
    while (my $cat = $noop_cats->next) {
        push @noop_params, [
            \[ "NOT regexp_split_to_array(bodies_str, ',') && ?", [ {} => [ $cat->body_id ] ] ],
            category => { '!=' => $cat->category } ];
    }

    # Noop bodies
    my @noop_bodies = FixMyStreet::DB->resultset('Body')->search({ send_method => 'Noop' })->all;
    @noop_bodies = map { $_->id } @noop_bodies;
    push @noop_params, \[ "NOT regexp_split_to_array(bodies_str, ',') && ?", [ {} => \@noop_bodies ] ];

    my $params = {
        state => $states,
        whensent => undef,
        bodies_str => { '!=', undef },
        -and => \@noop_params,
    };
    if (!$debug) {
        $params->{'-or'} = [
            send_fail_count => 0,
            { send_fail_count => 1, send_fail_timestamp => { '<', \"current_timestamp - '5 minutes'::interval" } },
            { send_fail_timestamp => { '<', \"current_timestamp - '30 minutes'::interval" } },
        ];
    }

    return $params;
}

sub end_line {
    my ($self, $unsent_count) = @_;
    return unless $self->verbose;

    if ($unsent_count) {
        $self->log("processed all unsent reports (total: $unsent_count)");
    } else {
        $self->log("no unsent reports were found (must have whensent=null and suitable bodies_str & state) -- nothing to send");
    }
}

sub end_summary_unconfirmed {
    my $self = shift;
    return unless $self->verbose;

    my %unconfirmed_data = %{$self->unconfirmed_data};
    print "Council email addresses that need checking:\n" if keys %unconfirmed_data;
    foreach my $e (keys %unconfirmed_data) {
        foreach my $c (keys %{$unconfirmed_data{$e}}) {
            my $data = $unconfirmed_data{$e}{$c};
            print "    " . $data->{count} . " problem, to $e category $c (" . $data->{note} . ")\n";
        }
    }
}

sub end_summary_failures {
    my $self = shift;

    my $sending_errors = '';
    my $unsent = FixMyStreet::DB->resultset('Problem')->search( {
        state => [ FixMyStreet::DB::Result::Problem::open_states() ],
        whensent => undef,
        bodies_str => { '!=', undef },
        send_fail_count => { '>', 0 }
    } );
    while (my $row = $unsent->next) {
        my $base_url = FixMyStreet->config('BASE_URL');
        $sending_errors .= "\n" . '=' x 80 . "\n\n" . "* " . $base_url . "/report/" . $row->id . ", failed "
            . $row->send_fail_count . " times, last at " . $row->send_fail_timestamp
            . ", reason " . $row->send_fail_reason . "\n";
    }
    if ($sending_errors) {
        print "The following reports had problems sending:\n$sending_errors";
    }
}

sub log {
    my ($self, $msg) = @_;
    return unless $self->verbose;
    STDERR->print("[fmsd] $msg\n");
}

1;