diff options
author | Dave Arter <davea@mysociety.org> | 2019-06-06 11:59:49 +0100 |
---|---|---|
committer | Dave Arter <davea@mysociety.org> | 2019-06-06 12:05:38 +0100 |
commit | 1ccd6bb35cce43c88610ad6ed93d18b3fc342d72 (patch) | |
tree | 338208feee61997a1b76c2946a14c18442fc8cd5 | |
parent | ff3b747698f577876bff25512ac137c6677ccab7 (diff) |
Allow file uploading when sending Open311 service requests
This adds a new upload_files flag (which cobrands can set in their
open311_config method) to Open311 which means any general enquiry files
are POSTed to the Open311 endpoint in a multipart/form-data request.
Photos on hidden reports are also sent if this flag is set, because they
wouldn't be accessible to the Open311 endpoint via media_url as the
reports are non_public.
This feature is not part of the Open311 specification.
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/SendReport/Open311.pm | 1 | ||||
-rw-r--r-- | perllib/Open311.pm | 70 |
3 files changed, 71 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cfc0e5f9..eb6e86381 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ reports made in that category private. - Ensure any reports fetched in a category marked private are also marked private on the site. + - Add new upload_files flag which sends files/photos as part of the + POST service request. * v2.6 (3rd May 2019) - New features: diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm index a661ff206..8a6b992fd 100644 --- a/perllib/FixMyStreet/SendReport/Open311.pm +++ b/perllib/FixMyStreet/SendReport/Open311.pm @@ -29,6 +29,7 @@ sub send { use_service_as_deviceid => 0, extended_description => 1, multi_photos => 0, + upload_files => 0, fixmystreet_body => $body, ); diff --git a/perllib/Open311.pm b/perllib/Open311.pm index ec3390ee7..a902a7213 100644 --- a/perllib/Open311.pm +++ b/perllib/Open311.pm @@ -12,6 +12,7 @@ use HTTP::Request::Common qw(GET POST); use FixMyStreet::Cobrand; use FixMyStreet::DB; use Utils; +use Path::Tiny 'path'; has jurisdiction => ( is => 'ro', isa => Str );; has api_key => ( is => 'ro', isa => Str ); @@ -32,6 +33,7 @@ has use_service_as_deviceid => ( is => 'ro', isa => Bool, default => 0 ); has extended_statuses => ( is => 'ro', isa => Bool, default => 0 ); has always_send_email => ( is => 'ro', isa => Bool, default => 0 ); has multi_photos => ( is => 'ro', isa => Bool, default => 0 ); +has upload_files => ( is => 'ro', isa => Bool, default => 0 ); has use_customer_reference => ( is => 'ro', isa => Bool, default => 0 ); has mark_reopen => ( is => 'ro', isa => Bool, default => 0 ); has fixmystreet_body => ( is => 'ro', isa => InstanceOf['FixMyStreet::DB::Result::Body'] ); @@ -90,8 +92,9 @@ sub send_service_request { my $params = $self->_populate_service_request_params( $problem, $extra, $service_code ); + my $uploads = $self->_populate_service_request_uploads($problem, $params); - my $response = $self->_post( $self->endpoints->{requests}, $params ); + my $response = $self->_post( $self->endpoints->{requests}, $params, $uploads ); if ( $response ) { my $obj = $self->_get_xml_object( $response ); @@ -191,6 +194,43 @@ sub _populate_service_request_params { return $params; } +sub _populate_service_request_uploads { + my $self = shift; + my $problem = shift; + my $params = shift; + + return unless $self->upload_files; + + my $uploads = {}; + + if ( $problem->get_extra_metadata('enquiry_files') ) { + my $cfg = FixMyStreet->config('PHOTO_STORAGE_OPTIONS'); + my $dir = $cfg ? $cfg->{UPLOAD_DIR} : FixMyStreet->config('UPLOAD_DIR'); + $dir = path($dir, "enquiry_files")->absolute(FixMyStreet->path_to()); + + my $files = $problem->get_extra_metadata('enquiry_files') || {}; + for my $key (keys %$files) { + my $name = $files->{$key}; + $uploads->{"file_$key"} = [ path($dir, $key)->canonpath, $name ]; + } + } + + if ( $problem->photo && $problem->non_public ) { + # open311-adapter won't be able to download any photos if they're on + # a private report, so instead of sending the media_url parameter + # send the actual photo content with the POST request. + my $i = 0; + my $photoset = $problem->get_photoset; + for ( $photoset->all_ids ) { + my $photo = $photoset->get_image_data( num => $i++, size => 'full' ); + $uploads->{"photo$i"} = [ undef, $_, Content_Type => $photo->{content_type}, Content => $photo->{data} ]; + } + delete $params->{media_url}; + } + + return $uploads; +} + sub _generate_service_request_description { my $self = shift; my $problem = shift; @@ -442,6 +482,7 @@ sub _request { my $method = shift; my $path = shift; my $params = shift || {}; + my $uploads = shift; my $uri = URI->new( $self->endpoint ); $uri->path( $uri->path . $path ); @@ -458,7 +499,32 @@ sub _request { $uri->query_form( $params ); GET $uri->as_string; } elsif ($method eq 'POST') { - POST $uri->as_string, $params; + if ($uploads) { + # HTTP::Request::Common needs to be constructed slightly + # differently if there are files to upload. + + my @media_urls = (); + # HTTP::Request::Common treats an arrayref as a filespec, + # so we need to rejig the media_url parameter so it doesn't + # get confused... + # https://stackoverflow.com/questions/50705344/perl-httprequestcommon-post-file-and-array + if ($self->multi_photos) { + my $media_urls = $params->{media_url}; + @media_urls = map { ( media_url => $_ ) } @$media_urls; + delete $params->{media_url}; + } + $params = { + Content_Type => 'form-data', + Content => [ + %$params, + @media_urls, + %$uploads + ] + }; + POST $uri->as_string, %$params; + } else { + POST $uri->as_string, $params; + } } }; |