diff options
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Dashboard.pm | 75 | ||||
-rw-r--r-- | perllib/FixMyStreet/Reporting.pm | 41 |
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) = @_; |