aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/Open311.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/Open311.pm')
-rw-r--r--perllib/Open311.pm257
1 files changed, 225 insertions, 32 deletions
diff --git a/perllib/Open311.pm b/perllib/Open311.pm
index e26e3e4c6..fd6a67706 100644
--- a/perllib/Open311.pm
+++ b/perllib/Open311.pm
@@ -5,6 +5,7 @@ use Moose;
use XML::Simple;
use LWP::Simple;
use LWP::UserAgent;
+use DateTime::Format::W3CDTF;
use HTTP::Request::Common qw(POST);
has jurisdiction => ( is => 'ro', isa => 'Str' );;
@@ -12,10 +13,23 @@ has api_key => ( is => 'ro', isa => 'Str' );
has endpoint => ( is => 'ro', isa => 'Str' );
has test_mode => ( is => 'ro', isa => 'Bool' );
has test_uri_used => ( is => 'rw', 'isa' => 'Str' );
+has test_req_used => ( is => 'rw' );
has test_get_returns => ( is => 'rw' );
-has endpoints => ( is => 'rw', default => sub { { services => 'services.xml', requests => 'requests.xml' } } );
+has endpoints => ( is => 'rw', default => sub { { services => 'services.xml', requests => 'requests.xml', service_request_updates => 'update.xml', update => 'update.xml' } } );
has debug => ( is => 'ro', isa => 'Bool', default => 0 );
has debug_details => ( is => 'rw', 'isa' => 'Str', default => '' );
+has success => ( is => 'rw', 'isa' => 'Bool', default => 0 );
+has error => ( is => 'rw', 'isa' => 'Str', default => '' );
+has always_send_latlong => ( is => 'ro', isa => 'Bool', default => 1 );
+has send_notpinpointed => ( is => 'ro', isa => 'Bool', default => 0 );
+has basic_description => ( is => 'ro', isa => 'Bool', default => 0 );
+
+before [
+ qw/get_service_list get_service_meta_info get_service_requests get_service_request_updates
+ send_service_request post_service_request_update/
+ ] => sub {
+ shift->debug_details('');
+ };
sub get_service_list {
my $self = shift;
@@ -39,22 +53,49 @@ sub send_service_request {
my $extra = shift;
my $service_code = shift;
- my $description = <<EOT;
-title: @{[$problem->title()]}
+ my $params = $self->_populate_service_request_params(
+ $problem, $extra, $service_code
+ );
-detail: @{[$problem->detail()]}
+ my $response = $self->_post( $self->endpoints->{requests}, $params );
-url: $extra->{url}
+ if ( $response ) {
+ my $obj = $self->_get_xml_object( $response );
-Submitted via FixMyStreet
-EOT
-;
+ if ( $obj ) {
+ if ( $obj->{ request }->{ service_request_id } ) {
+ return $obj->{ request }->{ service_request_id };
+ } else {
+ my $token = $obj->{ request }->{ token };
+ if ( $token ) {
+ return $self->get_service_request_id_from_token( $token );
+ }
+ }
+ }
+
+ warn sprintf( "Failed to submit problem %s over Open311, response\n: %s\n%s", $problem->id, $response, $self->debug_details );
+ return 0;
+ }
+}
+
+sub _populate_service_request_params {
+ my $self = shift;
+ my $problem = shift;
+ my $extra = shift;
+ my $service_code = shift;
+
+ my $description;
+ if ( $self->basic_description ) {
+ $description = $problem->detail;
+ } else {
+ $description = $self->_generate_service_request_description(
+ $problem, $extra
+ );
+ }
my ( $firstname, $lastname ) = ( $problem->user->name =~ /(\w+)\s+(.+)/ );
my $params = {
- lat => $problem->latitude,
- long => $problem->longitude,
email => $problem->user->email,
description => $description,
service_code => $service_code,
@@ -62,6 +103,25 @@ EOT
last_name => $lastname || '',
};
+ # if you click nearby reports > skip map then it's possible
+ # to end up with used_map = f and nothing in postcode
+ if ( $problem->used_map || $self->always_send_latlong
+ || ( !$self->send_notpinpointed && !$problem->used_map
+ && !$problem->postcode ) )
+ {
+ $params->{lat} = $problem->latitude;
+ $params->{long} = $problem->longitude;
+ # this is a special case for sending to Bromley so they can
+ # report accuracy levels correctly. We include easting and
+ # northing as attributes elsewhere.
+ } elsif ( $self->send_notpinpointed && !$problem->used_map
+ && !$problem->postcode )
+ {
+ $params->{address_id} = '#NOTPINPOINTED#';
+ } else {
+ $params->{address_string} = $problem->postcode;
+ }
+
if ( $problem->user->phone ) {
$params->{ phone } = $problem->user->phone;
}
@@ -74,30 +134,37 @@ EOT
my $extras = $problem->extra;
for my $attr ( @$extras ) {
- my $name = sprintf( 'attribute[%s]', $attr->{name} );
+ my $attr_name = $attr->{name};
+ if ( $attr_name eq 'first_name' || $attr_name eq 'last_name' ) {
+ $params->{$attr_name} = $attr->{value} if $attr->{value};
+ next if $attr_name eq 'first_name';
+ }
+ $attr_name =~ s/fms_extra_//;
+ my $name = sprintf( 'attribute[%s]', $attr_name );
$params->{ $name } = $attr->{value};
}
}
- my $response = $self->_post( $self->endpoints->{requests}, $params );
+ return $params;
+}
- if ( $response ) {
- my $obj = $self->_get_xml_object( $response );
+sub _generate_service_request_description {
+ my $self = shift;
+ my $problem = shift;
+ my $extra = shift;
- if ( $obj ) {
- if ( $obj->{ request }->{ service_request_id } ) {
- return $obj->{ request }->{ service_request_id };
- } else {
- my $token = $obj->{ request }->{ token };
- if ( $token ) {
- return $self->get_service_request_id_from_token( $token );
- }
- }
- }
+ my $description = <<EOT;
+title: @{[$problem->title()]}
- warn sprintf( "Failed to submit problem %s over Open311, response\n: %s\n%s", $problem->id, $response, $self->debug_details );
- return 0;
- }
+detail: @{[$problem->detail()]}
+
+url: $extra->{url}
+
+Submitted via FixMyStreet
+EOT
+;
+
+ return $description;
}
sub get_service_requests {
@@ -129,6 +196,107 @@ sub get_service_request_id_from_token {
}
}
+sub get_service_request_updates {
+ my $self = shift;
+ my $start_date = shift;
+ my $end_date = shift;
+
+ my $params = {
+ api_key => $self->api_key,
+ jurisdiction => $self->jurisdiction,
+ };
+
+ if ( $start_date || $end_date ) {
+ return 0 unless $start_date && $end_date;
+
+ $params->{start_date} = $start_date;
+ $params->{end_date} = $end_date;
+ }
+
+ my $xml = $self->_get( $self->endpoints->{service_request_updates}, $params || undef );
+ my $service_requests = $self->_get_xml_object( $xml );
+ my $requests;
+ if ( ref $service_requests->{request_update } eq 'ARRAY' ) {
+ $requests = $service_requests->{request_update};
+ }
+ else {
+ $requests = [ $service_requests->{request_update} ];
+ }
+
+ return $requests;
+}
+
+sub post_service_request_update {
+ my $self = shift;
+ my $comment = shift;
+
+ my $params = $self->_populate_service_request_update_params( $comment );
+
+ my $response = $self->_post( $self->endpoints->{update}, $params );
+
+ if ( $response ) {
+ my $obj = $self->_get_xml_object( $response );
+
+ if ( $obj ) {
+ if ( $obj->{ request_update }->{ update_id } ) {
+ my $update_id = $obj->{request_update}->{update_id};
+
+ # if there's nothing in the update_id element we get a HASHREF back
+ unless ( ref $update_id ) {
+ return $obj->{ request_update }->{ update_id };
+ }
+ } else {
+ my $token = $obj->{ request_update }->{ token };
+ if ( $token ) {
+ return $self->get_service_request_id_from_token( $token );
+ }
+ }
+ }
+
+ warn sprintf( "Failed to submit comment %s over Open311, response - %s\n%s\n", $comment->id, $response, $self->debug_details );
+ return 0;
+ }
+}
+
+sub _populate_service_request_update_params {
+ my $self = shift;
+ my $comment = shift;
+
+ my $name = $comment->name || $comment->user->name;
+ my ( $firstname, $lastname ) = ( $name =~ /(\w+)\s+(.+)/ );
+
+ my $params = {
+ update_id_ext => $comment->id,
+ updated_datetime => DateTime::Format::W3CDTF->format_datetime($comment->confirmed_local->set_nanosecond(0)),
+ service_request_id => $comment->problem->external_id,
+ service_request_id_ext => $comment->problem->id,
+ status => $comment->problem->is_open ? 'OPEN' : 'CLOSED',
+ email => $comment->user->email,
+ description => $comment->text,
+ public_anonymity_required => $comment->anonymous ? 'TRUE' : 'FALSE',
+ last_name => $lastname,
+ first_name => $firstname,
+ };
+
+ if ( $comment->photo ) {
+ my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($comment->cobrand)->new();
+ my $email_base_url = $cobrand->base_url_for_emails($comment->cobrand_data);
+ my $url = $email_base_url . '/photo/c/' . $comment->id . '.full.jpeg';
+ $params->{media_url} = $url;
+ }
+
+ if ( $comment->extra ) {
+ $params->{'email_alerts_requested'}
+ = $comment->extra->{email_alerts_requested} ? 'TRUE' : 'FALSE';
+ $params->{'title'} = $comment->extra->{title};
+
+ $params->{first_name} = $comment->extra->{first_name} if $comment->extra->{first_name};
+ $params->{last_name} = $comment->extra->{last_name} if $comment->extra->{last_name};
+ }
+
+ return $params;
+}
+
sub _get {
my $self = shift;
my $path = shift;
@@ -144,10 +312,25 @@ sub _get {
my $content;
if ( $self->test_mode ) {
+ $self->success(1);
$content = $self->test_get_returns->{ $path };
$self->test_uri_used( $uri->as_string );
} else {
- $content = get( $uri->as_string );
+ my $ua = LWP::UserAgent->new;
+
+ my $req = HTTP::Request->new(
+ GET => $uri->as_string
+ );
+
+ my $res = $ua->request( $req );
+
+ if ( $res->is_success ) {
+ $content = $res->decoded_content;
+ $self->success(1);
+ } else {
+ $self->success(0);
+ $self->error( $res->status_line );
+ }
}
return $content;
@@ -171,17 +354,27 @@ sub _post {
$self->debug_details( $self->debug_details . "\nrequest:" . $req->as_string );
my $ua = LWP::UserAgent->new();
- my $res = $ua->request( $req );
+ my $res;
+
+ if ( $self->test_mode ) {
+ $res = $self->test_get_returns->{ $path };
+ $self->test_req_used( $req );
+ } else {
+ $res = $ua->request( $req );
+ }
if ( $res->is_success ) {
+ $self->success(1);
return $res->decoded_content;
} else {
- warn sprintf(
- "request failed: %s\nerror: %s\n%s",
+ $self->success(0);
+ $self->error( sprintf(
+ "request failed: %s\nerror: %s\n%s\n",
$res->status_line,
$self->_process_error( $res->decoded_content ),
$self->debug_details
- );
+ ) );
+ warn $self->error;
return 0;
}
}