aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/Open311.pm
diff options
context:
space:
mode:
authorDave Arter <davea@mysociety.org>2019-06-06 11:59:49 +0100
committerDave Arter <davea@mysociety.org>2019-06-06 12:05:38 +0100
commit1ccd6bb35cce43c88610ad6ed93d18b3fc342d72 (patch)
tree338208feee61997a1b76c2946a14c18442fc8cd5 /perllib/Open311.pm
parentff3b747698f577876bff25512ac137c6677ccab7 (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.
Diffstat (limited to 'perllib/Open311.pm')
-rw-r--r--perllib/Open311.pm70
1 files changed, 68 insertions, 2 deletions
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;
+ }
}
};