aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdmund von der Burg <evdb@mysociety.org>2011-03-24 12:16:51 +0000
committerEdmund von der Burg <evdb@mysociety.org>2011-03-24 12:28:38 +0000
commit237fff72cf2b574ae8d19e9e2596ea93e08fcfc6 (patch)
tree2feb6c0c0d704576b1b91c5dbe7552c4a3b963e4
parent8fbaaf5d937f1c6d2c42ec7db205a581144ff882 (diff)
Handle photo uploads - caching between requests if there are errors
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports/New.pm148
-rw-r--r--templates/web/default/reports/new/fill_in_details.html21
2 files changed, 123 insertions, 46 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Reports/New.pm b/perllib/FixMyStreet/App/Controller/Reports/New.pm
index 12f904e5e..20fb24a32 100644
--- a/perllib/FixMyStreet/App/Controller/Reports/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports/New.pm
@@ -10,6 +10,7 @@ use Sort::Key qw(keysort);
use List::MoreUtils qw(uniq);
use HTML::Entities;
use mySociety::MaPit;
+use Path::Class;
=head1 NAME
@@ -38,6 +39,10 @@ x, y, tile_xxx.yyy.x, tile_xxx.yyy.y: x and y are the tile locations. The
'tile_xxx.yyy' pair are the click locations on the tile. These can be converted
back into lat/lng by the map code.
+=head2 image related
+
+Parameters are 'photo' or 'upload_fileid'. The 'photo' is used when a user has selected a file. Once it has been uploaded it is cached on disk so that if there are errors on the form it need not be uploaded again. The cache location is stored in 'upload_fileid'.
+
=head2 optional
pc: location user searched for
@@ -61,8 +66,6 @@ email
phone
-council
-
partial
=head2 can be ignored
@@ -90,6 +93,7 @@ sub report_new : Path : Args(0) {
return
unless $c->forward('process_user')
&& $c->forward('process_report')
+ && $c->forward('process_photo')
&& $c->forward('check_form_submitted')
&& $c->forward('check_for_errors')
&& $c->forward('save_user_and_report')
@@ -497,12 +501,6 @@ sub process_report : Private {
$report->name( $params{name} );
$report->category( $params{category} );
- # my $fh = $q->upload('photo');
- # if ($fh) {
- # my $err = Page::check_photo( $q, $fh );
- # $field_errors{photo} = $err if $err;
- # }
-
my $mapit_query =
sprintf( "4326/%s,%s", $report->longitude, $report->latitude );
my $areas = mySociety::MaPit::call( 'point', $mapit_query );
@@ -555,7 +553,6 @@ sub process_report : Private {
# construct the council string:
# 'x,x' - x are councils_ids that have this category
# 'x,x|y,y' - x are councils_ids that have this category, y don't
- # '-1' - no councils have this category
my $council_string = join '|', grep { $_ } #
(
join( ',', @councils_with_category ),
@@ -566,30 +563,6 @@ sub process_report : Private {
# set defaults that make sense
$report->state('unconfirmed');
-# my $image;
-# if ($fh) {
-# try {
-# $image = Page::process_photo($fh);
-# }
-# catch Error::Simple with {
-# my $e = shift;
-# $field_errors{photo} = sprintf(
-# _(
-# "That image doesn't appear to have uploaded correctly (%s), please try again."
-# ),
-# $e
-# );
-# };
-# }
-#
-# if ( $input{upload_fileid} ) {
-# open FP,
-# mySociety::Config::get('UPLOAD_CACHE') . $input{upload_fileid};
-# $image = join( '', <FP> );
-# close FP;
-# }
-#
-
# save the cobrand and language related information
$report->cobrand( $c->cobrand->moniker );
$report->cobrand_data( $c->cobrand->extra_problem_data );
@@ -648,6 +621,89 @@ sub process_report : Private {
return 1;
}
+=head2 process_photo
+
+Handle the photo - either checking and storing it after an upload or retrieving
+it from the cache.
+
+Store any error message onto 'photo_error' in stash.
+=cut
+
+sub process_photo : Private {
+ my ( $self, $c ) = @_;
+
+ return
+ $c->forward('process_photo_upload')
+ || $c->forward('process_photo_cache')
+ || 1; # always return true
+}
+
+sub process_photo_upload : Private {
+ my ( $self, $c ) = @_;
+
+ # check for upload or return
+ my $upload = $c->req->upload('photo')
+ || return;
+
+ # check that the photo is a jpeg
+ my $ct = $upload->type;
+ unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' ) {
+ $c->stash->{photo_error} = _('Please upload a JPEG image only');
+ return;
+ }
+
+ # convert the photo into a blob (also resize etc)
+ my $photo_blob = eval { Page::process_photo( $upload->fh ) };
+ if ( my $error = $@ ) {
+ my $format = _(
+"That image doesn't appear to have uploaded correctly (%s), please try again."
+ );
+ $c->stash->{photo_error} = sprintf( $format, $error );
+ return;
+ }
+
+ # we have an image we can use - save it to the cache in case there is an
+ # error
+ my $cache_dir = dir( $c->config->{UPLOAD_CACHE} );
+ $cache_dir->mkpath;
+ unless ( -d $cache_dir && -w $cache_dir ) {
+ warn "Can't find/write to photo cache directory '$cache_dir'";
+ return;
+ }
+
+ # create a random name and store the file there
+ my $fileid = int rand 1_000_000_000;
+ my $file = $cache_dir->file("$fileid.jpg");
+ $file->openw->print($photo_blob);
+
+ # stick the random number on the stash
+ $c->stash->{upload_fileid} = $fileid;
+
+ return 1;
+}
+
+=head2 process_photo_cache
+
+Look for the upload_fileid parameter and check it matches a file on disk. If it
+does return true and put fileid on stash, otherwise false.
+
+=cut
+
+sub process_photo_cache : Private {
+ my ( $self, $c ) = @_;
+
+ # get the fileid and make sure it is just a number
+ my $fileid = $c->req->param('upload_fileid') || '';
+ $fileid =~ s{\D+}{}g;
+ return unless $fileid;
+
+ my $file = file( $c->config->{UPLOAD_CACHE}, "$fileid.jpg" );
+ return unless -e $file;
+
+ $c->stash->{upload_fileid} = $fileid;
+ return 1;
+}
+
=head2 check_form_submitted
$bool = $c->forward('check_form_submitted');
@@ -659,7 +715,7 @@ on the presence of the C<submit_problem> parameter.
sub check_form_submitted : Private {
my ( $self, $c ) = @_;
- return !!$c->req->param('submit_problem');
+ return $c->req->param('submit_problem') || '';
}
=head2 check_for_errors
@@ -675,18 +731,19 @@ sub check_for_errors : Private {
# let the model check for errors
my %field_errors = (
%{ $c->stash->{report_user}->check_for_errors },
- %{ $c->stash->{report}->check_for_errors }
+ %{ $c->stash->{report}->check_for_errors },
);
+ # add the photo error if there is one.
+ if ( my $photo_error = delete $c->stash->{photo_error} ) {
+ $field_errors{photo} = $photo_error;
+ }
+
# all good if no errors
return 1 unless scalar keys %field_errors;
$c->stash->{field_errors} = \%field_errors;
- use Data::Dumper;
- local $Data::Dumper::Sortkeys = 1;
- warn Dumper( \%field_errors );
-
return;
}
@@ -713,20 +770,29 @@ sub save_user_and_report : Private {
}
elsif ( $c->user && $report_user->id == $c->user->id ) {
$report_user->update();
- $report->confirmed(1); # as we know the user is genuine
+
+ # we can also confirm the report straight away
$report->state('confirmed');
$report->confirmed( \'ms_current_timestamp()' ); # FIXME - move to model
}
else {
# user exists and we are not logged in as them. Throw away changes to
- # the name and phone. FIXME - propagate changes using tokens.
+ # the name and phone. TODO - propagate changes using tokens.
$report_user->discard_changes();
}
# add the user to the report
$report->user($report_user);
+ # If there was a photo add that too
+ if ( my $fileid = $c->stash->{upload_fileid} ) {
+ my $file = file( $c->config->{UPLOAD_CACHE}, "$fileid.jpg" );
+ my $blob = $file->slurp;
+ $file->remove;
+ $report->photo($blob);
+ }
+
# Set a default if possible
$report->category( _('Other') ) unless $report->category;
diff --git a/templates/web/default/reports/new/fill_in_details.html b/templates/web/default/reports/new/fill_in_details.html
index b6ede7b4c..824609488 100644
--- a/templates/web/default/reports/new/fill_in_details.html
+++ b/templates/web/default/reports/new/fill_in_details.html
@@ -81,12 +81,23 @@
<!-- {{ $partial_field }} -->
-<!-- {{ if ( $field_errors{photo}) {
- "<div class='form-error'>$field_errors{photo}</div>";
-} }} -->
-<!-- $vars{photo_label} = _('Photo:'); -->
-<!-- {{ $photo_field }} -->
+
+[% IF field_errors.photo %]
+ <div class='form-error'>[% field_errors.photo %]</div>
+[% END %]
+
+[% IF upload_fileid %]
+ <p>[% loc('Please note that you have already uploaded a photo - only add another if you wish to replace it') %]</p>
+ <input type="hidden" name="upload_fileid" value="[% upload_fileid %]" />
+[% END %]
+
+<div class='form-field'>
+ <label for="form_name">[% loc('Photo:') %]</label>
+ <input type="file" value="" name="photo" id="form_photo" >
+</div>
+
+
[% IF field_errors.name %]
<div class='form-error'>[% field_errors.name %]</div>