aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm75
-rw-r--r--perllib/FixMyStreet/Reporting.pm41
2 files changed, 114 insertions, 2 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
index 0d0a704bb..5400a6209 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -137,9 +137,24 @@ sub index : Path : Args(0) {
my $reporting = $c->forward('construct_rs_filter', [ $c->get_param('updates') ]);
- if ( $c->get_param('export') ) {
+ if ( my $export = $c->get_param('export') ) {
$reporting->csv_parameters;
- $reporting->generate_csv_http($c);
+ if ($export == 1) {
+ # Existing method, generate and serve
+ $reporting->generate_csv_http($c);
+ } elsif ($export == 2) {
+ # New offline method
+ $reporting->kick_off_process;
+ my ($redirect, $code) = ('/dashboard/status', 303);
+ if (Catalyst::Authentication::Credential::AccessToken->get_token($c)) {
+ # Client knows to re-request until ready
+ $redirect = '/dashboard/csv/' . $reporting->filename . '.csv';
+ $c->res->body('');
+ $code = 202;
+ }
+ $c->res->redirect($redirect, $code);
+ $c->detach;
+ }
} else {
$c->forward('generate_grouped_data');
$self->generate_summary_figures($c);
@@ -276,6 +291,62 @@ sub generate_summary_figures {
}
}
+sub status : Local : Args(0) {
+ my ($self, $c) = @_;
+
+ my $body = $c->stash->{body} = $c->forward('check_page_allowed');
+ $c->stash->{body_name} = $body->name if $body;
+
+ my $reporting = FixMyStreet::Reporting->new(
+ user => $c->user_exists ? $c->user->obj : undef,
+ );
+ my $dir = $reporting->cache_dir;
+ my @data;
+ foreach ($dir->children) {
+ my $stat = $_->stat;
+ my $name = $_->basename;
+ my $finished = $name =~ /part$/ ? 0 : 1;
+ $name =~ s/-part$//;
+ push @data, {
+ ctime => $stat->ctime,
+ size => $stat->size,
+ name => $name,
+ finished => $finished,
+ };
+ }
+ @data = sort { $b->{ctime} <=> $a->{ctime} } @data;
+ $c->stash->{rows} = \@data;
+}
+
+sub csv : Local : Args(1) {
+ my ($self, $c, $filename) = @_;
+
+ $c->authenticate(undef, "access_token");
+
+ my $body = $c->stash->{body} = $c->forward('check_page_allowed');
+
+ (my $basename = $filename) =~ s/\.csv$//;
+ my $reporting = FixMyStreet::Reporting->new(
+ user => $c->user_exists ? $c->user->obj : undef,
+ filename => $basename,
+ );
+ my $dir = $reporting->cache_dir;
+ my $csv = path($dir, $filename);
+
+ if (!$csv->exists) {
+ if (path($dir, "$filename-part")->exists && Catalyst::Authentication::Credential::AccessToken->get_token($c)) {
+ $c->res->body('');
+ $c->res->status(202);
+ $c->detach;
+ } else {
+ $c->detach( '/page_error_404_not_found', [] ) unless $csv->exists;
+ }
+ }
+
+ $reporting->http_setup($c);
+ $c->res->body($csv->openr_raw);
+}
+
sub generate_body_response_time : Private {
my ( $self, $c ) = @_;
diff --git a/perllib/FixMyStreet/Reporting.pm b/perllib/FixMyStreet/Reporting.pm
index 7ee9fc41a..08cdf1544 100644
--- a/perllib/FixMyStreet/Reporting.pm
+++ b/perllib/FixMyStreet/Reporting.pm
@@ -2,6 +2,7 @@ package FixMyStreet::Reporting;
use DateTime;
use Moo;
+use Path::Tiny;
use Text::CSV;
use Types::Standard qw(ArrayRef CodeRef Enum HashRef InstanceOf Int Maybe Str);
use FixMyStreet::DB;
@@ -305,6 +306,46 @@ sub generate_csv {
# Output code
+sub cache_dir {
+ my $self = shift;
+
+ my $cfg = FixMyStreet->config('PHOTO_STORAGE_OPTIONS');
+ my $dir = $cfg ? $cfg->{UPLOAD_DIR} : FixMyStreet->config('UPLOAD_DIR');
+ $dir = path($dir, "dashboard_csv")->absolute(FixMyStreet->path_to());
+ my $subdir = $self->user ? $self->user->id : 0;
+ $dir = $dir->child($subdir);
+ $dir->mkpath;
+ $dir;
+}
+
+sub kick_off_process {
+ my $self = shift;
+
+ return $self->_process if FixMyStreet->test_mode;
+
+ my $pid = fork;
+ unless ($pid) {
+ unless (fork) {
+ # eval so that it will definitely exit cleanly. Otherwise, an
+ # exception would turn this grandchild into a zombie app process
+ eval { $self->_process };
+ exit 0;
+ }
+ exit 0;
+ }
+ waitpid($pid, 0);
+}
+
+sub _process {
+ my $self = shift;
+ my $out = path($self->cache_dir, $self->filename . '.csv');
+ my $file = path($out . '-part');
+ if (!$file->exists) {
+ $self->generate_csv($file->openw_utf8);
+ $file->move($out);
+ }
+}
+
# Outputs relevant CSV HTTP headers, and then streams the CSV
sub generate_csv_http {
my ($self, $c) = @_;