aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perllib/FixMyStreet/App/Controller/Waste.pm92
-rw-r--r--t/cobrand/bromley.t62
2 files changed, 154 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Waste.pm b/perllib/FixMyStreet/App/Controller/Waste.pm
new file mode 100644
index 000000000..3cdd9fd42
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Waste.pm
@@ -0,0 +1,92 @@
+package FixMyStreet::App::Controller::Waste;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller' }
+
+use utf8;
+use Open311::GetServiceRequestUpdates;
+
+sub receive_echo_event_notification : Path('/waste/echo') : Args(0) {
+ my ($self, $c) = @_;
+ $c->stash->{format} = 'xml';
+ $c->response->header(Content_Type => 'application/soap+xml');
+
+ require SOAP::Lite;
+
+ $c->detach('soap_error', [ 'Invalid method', 405 ]) unless $c->req->method eq 'POST';
+
+ my $echo = $c->cobrand->feature('echo');
+ $c->detach('soap_error', [ 'Missing config', 500 ]) unless $echo;
+
+ # Make sure we log entire request for debugging
+ $c->detach('soap_error', [ 'Missing body' ]) unless $c->req->body;
+ my $soap = join('', $c->req->body->getlines);
+ $c->log->info($soap);
+
+ my $body = $c->cobrand->body;
+ $c->detach('soap_error', [ 'Bad jurisdiction' ]) unless $body;
+
+ my $env = SOAP::Deserializer->deserialize($soap);
+
+ my $header = $env->header;
+ $c->detach('soap_error', [ 'Missing SOAP header' ]) unless $header;
+ my $action = $header->{Action};
+ $c->detach('soap_error', [ 'Incorrect Action' ]) unless $action && $action eq $echo->{receive_action};
+ $header = $header->{Security};
+ $c->detach('soap_error', [ 'Missing Security header' ]) unless $header;
+ my $token = $header->{UsernameToken};
+ $c->detach('soap_error', [ 'Authentication failed' ])
+ unless $token && $token->{Username} eq $echo->{receive_username} && $token->{Password} eq $echo->{receive_password};
+
+ # Still want to say it is okay, even if we did nothing with it
+ $c->forward('soap_ok');
+}
+
+sub soap_error : Private {
+ my ($self, $c, $comment, $code) = @_;
+ $code ||= 400;
+ $c->response->status($code);
+ my $type = $code == 500 ? 'Server' : 'Client';
+ $c->response->body(SOAP::Serializer->fault($type, "Bad request: $comment", soap_header()));
+}
+
+sub soap_ok : Private {
+ my ($self, $c) = @_;
+ $c->response->status(200);
+ my $method = SOAP::Data->name("NotifyEventUpdatedResponse")->attr({
+ xmlns => "http://www.twistedfish.com/xmlns/echo/api/v1"
+ });
+ $c->response->body(SOAP::Serializer->envelope(method => $method, soap_header()));
+}
+
+sub soap_header {
+ my $attr = "http://www.twistedfish.com/xmlns/echo/api/v1";
+ my $action = "NotifyEventUpdatedResponse";
+ my $header = SOAP::Header->name("Action")->attr({
+ xmlns => 'http://www.w3.org/2005/08/addressing',
+ 'soap:mustUnderstand' => 1,
+ })->value("$attr/ReceiverService/$action");
+
+ my $dt = DateTime->now();
+ my $dt2 = $dt->clone->add(minutes => 5);
+ my $w3c = DateTime::Format::W3CDTF->new;
+ my $header2 = SOAP::Header->name("Security")->attr({
+ 'soap:mustUnderstand' => 'true',
+ 'xmlns' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
+ })->value(
+ \SOAP::Header->name(
+ "Timestamp" => \SOAP::Header->value(
+ SOAP::Header->name('Created', $w3c->format_datetime($dt)),
+ SOAP::Header->name('Expires', $w3c->format_datetime($dt2)),
+ )
+ )->attr({
+ xmlns => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
+ })
+ );
+ return ($header, $header2);
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/t/cobrand/bromley.t b/t/cobrand/bromley.t
index d26b10709..e6fa8e115 100644
--- a/t/cobrand/bromley.t
+++ b/t/cobrand/bromley.t
@@ -242,4 +242,66 @@ subtest 'check heatmap page' => sub {
};
};
+package SOAP::Result;
+sub result { return $_[0]->{result}; }
+sub new { my $c = shift; bless { @_ }, $c; }
+
+package main;
+
+subtest 'updating of waste reports' => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => 'bromley',
+ COBRAND_FEATURES => {
+ echo => { bromley => {
+ receive_action => 'action',
+ receive_username => 'un',
+ receive_password => 'password',
+ } },
+ waste => { bromley => 1 }
+ },
+ }, sub {
+ FixMyStreet::App->log->disable('info');
+
+ $mech->get('/waste/echo');
+ is $mech->res->code, 405, 'Cannot GET';
+
+ $mech->post('/waste/echo', Content_Type => 'text/xml');
+ is $mech->res->code, 400, 'No body';
+
+ my $in = '<Envelope><Header><Action>bad-action</Action></Header><Body></Body></Envelope>';
+ $mech->post('/waste/echo', Content_Type => 'text/xml', Content => $in);
+ is $mech->res->code, 400, 'Bad action';
+
+ $in = '<Envelope><Header><Action>action</Action><Security><UsernameToken><Username></Username><Password></Password></UsernameToken></Security></Header><Body></Body></Envelope>';
+ $mech->post('/waste/echo', Content_Type => 'text/xml', Content => $in);
+ is $mech->res->code, 400, 'Bad auth';
+
+ $in = <<EOF;
+<?xml version="1.0" encoding="UTF-8"?>
+<Envelope>
+ <Header>
+ <Action>action</Action>
+ <Security><UsernameToken><Username>un</Username><Password>password</Password></UsernameToken></Security>
+ </Header>
+ <Body>
+ <NotifyEventUpdated>
+ <event>
+ <Guid>waste-15005-XXX</Guid>
+ <EventTypeId>2104</EventTypeId>
+ <EventStateId>15006</EventStateId>
+ <ResolutionCodeId>207</ResolutionCodeId>
+ </event>
+ </NotifyEventUpdated>
+ </Body>
+</Envelope>
+EOF
+
+ $mech->post('/waste/echo', Content_Type => 'text/xml', Content => $in);
+ is $mech->res->code, 200, 'OK response, even though event does not exist';
+ is $report->comments->count, 2, 'No new update';
+
+ FixMyStreet::App->log->enable('info');
+ };
+};
+
done_testing();