aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Somerville <matthew-github@dracos.co.uk>2016-08-23 15:43:22 +0100
committerMatthew Somerville <matthew-github@dracos.co.uk>2016-08-23 16:15:58 +0100
commiteaa2480195d27ff3f1efd325b149da0668c63708 (patch)
tree7d548537eff1bb2a831129c71ad2e2b621066f72
parentec5e2c47f736c075e6dafd1ed63860287f596077 (diff)
Remove Open311 endpoint to separate repo.
-rwxr-xr-xbin/install_perl_modules2
-rw-r--r--cpanfile9
-rw-r--r--cpanfile.snapshot164
-rw-r--r--perllib/Open311/Endpoint.pm817
-rw-r--r--perllib/Open311/Endpoint/Integration/Exor.pm458
-rw-r--r--perllib/Open311/Endpoint/Integration/Warwick.pm47
-rw-r--r--perllib/Open311/Endpoint/Result.pm38
-rw-r--r--perllib/Open311/Endpoint/Role/ConfigFile.pm30
-rw-r--r--perllib/Open311/Endpoint/Role/mySociety.pm159
-rw-r--r--perllib/Open311/Endpoint/Schema.pm177
-rw-r--r--perllib/Open311/Endpoint/Schema/Comma.pm53
-rw-r--r--perllib/Open311/Endpoint/Schema/Regex.pm43
-rw-r--r--perllib/Open311/Endpoint/Service.pm55
-rw-r--r--perllib/Open311/Endpoint/Service/Attribute.pm82
-rw-r--r--perllib/Open311/Endpoint/Service/Exor.pm44
-rw-r--r--perllib/Open311/Endpoint/Service/Request.pm110
-rw-r--r--perllib/Open311/Endpoint/Service/Request/Update.pm57
-rw-r--r--perllib/Open311/Endpoint/Service/Request/mySociety.pm51
-rw-r--r--perllib/Open311/Endpoint/Spark.pm117
-rw-r--r--t/open311/endpoint.t351
-rw-r--r--t/open311/endpoint/Endpoint1.pm114
-rw-r--r--t/open311/endpoint/Endpoint2.pm25
-rw-r--r--t/open311/endpoint/Endpoint_Warwick.pm31
-rw-r--r--t/open311/endpoint/ServiceType1.pm10
-rw-r--r--t/open311/endpoint/config1.yml1
-rw-r--r--t/open311/endpoint/configfile.t23
-rw-r--r--t/open311/endpoint/exor/DBD/Oracle.pm8
-rw-r--r--t/open311/endpoint/mysociety.t160
-rw-r--r--t/open311/endpoint/schema.t82
-rw-r--r--t/open311/endpoint/spark.t62
-rw-r--r--t/open311/endpoint/warwick.t443
-rw-r--r--t/open311/endpoint/warwick_dbd.t17
32 files changed, 1 insertions, 3839 deletions
diff --git a/bin/install_perl_modules b/bin/install_perl_modules
index d757facb6..74b30fbdd 100755
--- a/bin/install_perl_modules
+++ b/bin/install_perl_modules
@@ -4,7 +4,7 @@ set -e
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd | sed -e 's/\/bin$//' )"
-$DIR/vendor/bin/carton install --deployment --without uk --without zurich --without open311-endpoint
+$DIR/vendor/bin/carton install --deployment --without uk --without zurich
if ! perl -MImage::Magick -e 'exit()' >/dev/null 2>&1
then
diff --git a/cpanfile b/cpanfile
index 890cac380..e1beab08e 100644
--- a/cpanfile
+++ b/cpanfile
@@ -100,15 +100,6 @@ feature 'uk', 'FixMyStreet.com specific requirements' => sub {
requires 'SOAP::Lite';
};
-feature 'open311-endpoint', 'Open311::Endpoint specific requirements' => sub {
- requires 'Web::Simple';
- requires 'Data::Rx';
- requires 'MooX::HandlesVia';
- requires 'Types::Standard';
- requires 'DateTime::Format::Oracle'; # for EXOR
- requires 'Convert::NLS_DATE_FORMAT', '0.06'; # Perl 5.22 upgrade
-};
-
feature 'zurich', 'Zueri wie neu specific requirements' => sub {
# Geocoder
requires 'SOAP::Lite';
diff --git a/cpanfile.snapshot b/cpanfile.snapshot
index c391e67ce..9fe2f566f 100644
--- a/cpanfile.snapshot
+++ b/cpanfile.snapshot
@@ -925,13 +925,6 @@ DISTRIBUTIONS
Test::Exception 0
Test::More 0
ok 0
- Convert-NLS_DATE_FORMAT-0.06
- pathname: K/KO/KOLIBRIE/Convert-NLS_DATE_FORMAT-0.06.tar.gz
- provides:
- Convert::NLS_DATE_FORMAT 0.06
- requirements:
- Module::Build::Tiny 0.035
- perl 5.006001
Cpanel-JSON-XS-3.0210
pathname: R/RU/RURBAN/Cpanel-JSON-XS-3.0210.tar.gz
provides:
@@ -1379,74 +1372,6 @@ DISTRIBUTIONS
Module::Build 0.35
Test::Exception 0
Test::More 0
- Data-Perl-0.002007
- pathname: M/MA/MATTP/Data-Perl-0.002007.tar.gz
- provides:
- Data::Perl 0.002007
- Data::Perl::Bool 0.002007
- Data::Perl::Code 0.002007
- Data::Perl::Collection::Array 0.002007
- Data::Perl::Collection::Hash 0.002007
- Data::Perl::Counter 0.002007
- Data::Perl::Number 0.002007
- Data::Perl::Role::Bool 0.002007
- Data::Perl::Role::Code 0.002007
- Data::Perl::Role::Collection::Array 0.002007
- Data::Perl::Role::Collection::Hash 0.002007
- Data::Perl::Role::Counter 0.002007
- Data::Perl::Role::Number 0.002007
- Data::Perl::Role::String 0.002007
- Data::Perl::String 0.002007
- requirements:
- Class::Method::Modifiers 0
- ExtUtils::MakeMaker 6.30
- List::MoreUtils 0
- List::Util 0
- Module::Runtime 0
- Role::Tiny 0
- Scalar::Util 0
- parent 0
- strictures 0
- Data-Rx-0.200005
- pathname: R/RJ/RJBS/Data-Rx-0.200005.tar.gz
- provides:
- Data::Rx 0.200005
- Data::Rx::CommonType 0.200005
- Data::Rx::CommonType::EasyNew 0.200005
- Data::Rx::CoreType 0.200005
- Data::Rx::CoreType::all 0.200005
- Data::Rx::CoreType::any 0.200005
- Data::Rx::CoreType::arr 0.200005
- Data::Rx::CoreType::bool 0.200005
- Data::Rx::CoreType::def 0.200005
- Data::Rx::CoreType::fail 0.200005
- Data::Rx::CoreType::int 0.200005
- Data::Rx::CoreType::map 0.200005
- Data::Rx::CoreType::nil 0.200005
- Data::Rx::CoreType::num 0.200005
- Data::Rx::CoreType::one 0.200005
- Data::Rx::CoreType::rec 0.200005
- Data::Rx::CoreType::seq 0.200005
- Data::Rx::CoreType::str 0.200005
- Data::Rx::Failure 0.200005
- Data::Rx::FailureSet 0.200005
- Data::Rx::TypeBundle 0.200005
- Data::Rx::TypeBundle::Core 0.200005
- Data::Rx::Util 0.200005
- requirements:
- Carp 0
- ExtUtils::MakeMaker 6.30
- File::Find::Rule 0
- JSON 2
- List::Util 0
- Number::Tolerant 0
- Scalar::Util 0
- Test::More 0.96
- autodie 0
- overload 0
- parent 0
- strict 0
- warnings 0
Data-Visitor-0.28
pathname: D/DO/DOY/Data-Visitor-0.28.tar.gz
provides:
@@ -1536,16 +1461,6 @@ DISTRIBUTIONS
Module::Build 0
Params::Validate 0.67
Test::More 0.47
- DateTime-Format-Oracle-0.06
- pathname: K/KO/KOLIBRIE/DateTime-Format-Oracle-0.06.tar.gz
- provides:
- DateTime::Format::Oracle 0.06
- requirements:
- Convert::NLS_DATE_FORMAT 0.03
- DateTime 0
- DateTime::Format::Builder 0
- ExtUtils::MakeMaker 0
- Test::More 0
DateTime-Format-Pg-0.16008
pathname: D/DM/DMAKI/DateTime-Format-Pg-0.16008.tar.gz
provides:
@@ -3960,22 +3875,6 @@ DISTRIBUTIONS
Module::Runtime 0.012
Role::Tiny 1.003
strictures 1.004003
- MooX-HandlesVia-0.001005
- pathname: M/MA/MATTP/MooX-HandlesVia-0.001005.tar.gz
- provides:
- Data::Perl::Bool::MooseLike 0.001005
- Data::Perl::Collection::Array::MooseLike 0.001005
- Data::Perl::Collection::Hash::MooseLike 0.001005
- Data::Perl::Number::MooseLike 0.001005
- Data::Perl::String::MooseLike 0.001005
- MooX::HandlesVia 0.001005
- requirements:
- Class::Method::Modifiers 0
- Data::Perl 0.002006
- ExtUtils::MakeMaker 6.30
- Module::Runtime 0
- Moo 1.003000
- Role::Tiny 0
MooX-Types-MooseLike-0.29
pathname: M/MA/MATEU/MooX-Types-MooseLike-0.29.tar.gz
provides:
@@ -4584,27 +4483,6 @@ DISTRIBUTIONS
Carp 0
ExtUtils::MakeMaker 0
POSIX 0
- Number-Tolerant-1.703
- pathname: R/RJ/RJBS/Number-Tolerant-1.703.tar.gz
- provides:
- Number::Tolerant 1.703
- Number::Tolerant::Constant 1.703
- Number::Tolerant::Type 1.703
- Number::Tolerant::Union 1.703
- Test::Tolerant 1.703
- requirements:
- Carp 0
- ExtUtils::MakeMaker 6.30
- Math::BigFloat 0
- Math::BigRat 0
- Scalar::Util 0
- Sub::Exporter 0.950
- Sub::Exporter::Util 0
- Test::Builder 0
- overload 0
- parent 0
- strict 0
- warnings 0
Object-Signature-1.07
pathname: A/AD/ADAMK/Object-Signature-1.07.tar.gz
provides:
@@ -6068,48 +5946,6 @@ DISTRIBUTIONS
constant 0
strict 0
warnings 0
- Type-Tiny-0.040
- pathname: T/TO/TOBYINK/Type-Tiny-0.040.tar.gz
- provides:
- Devel::TypeTiny::Perl56Compat 0.040
- Devel::TypeTiny::Perl58Compat 0.040
- Error::TypeTiny 0.040
- Error::TypeTiny::Assertion 0.040
- Error::TypeTiny::Compilation 0.040
- Error::TypeTiny::WrongNumberOfParameters 0.040
- Eval::TypeTiny 0.040
- Reply::Plugin::TypeTiny 0.040
- Test::TypeTiny 0.040
- Type::Coercion 0.040
- Type::Coercion::FromMoose 0.040
- Type::Coercion::Union 0.040
- Type::Library 0.040
- Type::Params 0.040
- Type::Parser 0.040
- Type::Registry 0.040
- Type::Tiny 0.040
- Type::Tiny::Class 0.040
- Type::Tiny::Duck 0.040
- Type::Tiny::Enum 0.040
- Type::Tiny::Intersection 0.040
- Type::Tiny::Role 0.040
- Type::Tiny::Union 0.040
- Type::Utils 0.040
- Types::Common::Numeric 0.040
- Types::Common::String 0.040
- Types::Standard 0.040
- Types::Standard::ArrayRef 0.040
- Types::Standard::Dict 0.040
- Types::Standard::HashRef 0.040
- Types::Standard::Map 0.040
- Types::Standard::ScalarRef 0.040
- Types::Standard::Tuple 0.040
- Types::TypeTiny 0.040
- requirements:
- CPAN::Meta::Requirements 2.000
- Exporter::Tiny 0.026
- ExtUtils::MakeMaker 6.17
- perl 5.006001
UNIVERSAL-can-1.20140328
pathname: C/CH/CHROMATIC/UNIVERSAL-can-1.20140328.tar.gz
provides:
diff --git a/perllib/Open311/Endpoint.pm b/perllib/Open311/Endpoint.pm
deleted file mode 100644
index 425a708ef..000000000
--- a/perllib/Open311/Endpoint.pm
+++ /dev/null
@@ -1,817 +0,0 @@
-package Open311::Endpoint;
-
-=head1 NAME
-
-Open311::Endpoint - a generic Open311 endpoint implementation
-
-=cut
-
-use Web::Simple;
-
-use JSON::MaybeXS;
-use XML::Simple;
-
-use Open311::Endpoint::Result;
-use Open311::Endpoint::Service;
-use Open311::Endpoint::Service::Request;
-use Open311::Endpoint::Spark;
-use Open311::Endpoint::Schema;
-
-use MooX::HandlesVia;
-
-use Data::Dumper;
-use Scalar::Util 'blessed';
-use List::Util 'first';
-use Types::Standard ':all';
-
-use DateTime::Format::W3CDTF;
-
-=head1 DESCRIPTION
-
-An implementation of L<http://wiki.open311.org/GeoReport_v2> with a
-dispatcher written as a L<Plack> application, designed to be easily
-deployed.
-
-This is a generic wrapper, designed to be a conformant Open311 server.
-However, it knows nothing about your business logic! You should subclass it
-and provide the necessary methods.
-
-=head1 SUBCLASSING
-
- package My::Open311::Endpoint;
- use Web::Simple;
- extends 'Open311::Endpoint';
-
-See also t/open311/endpoint/Endpoint1.pm and Endpoint2.pm as examples.
-
-=head2 methods to override
-
-These are the important methods to override. They are passed a list of
-simple arguments, and should generally return objects like
-L<Open311::Endpoint::Request>.
-
- services
- service
- post_service_request
- get_service_requests
- get_service_request
- requires_jurisdiction_ids
- check_jurisdiction_id
-
-The dispatch framework will take care of actually formatting the output
-into conformant XML or JSON.
-
-TODO document better
-
-=cut
-
-sub services {
- # this should be overridden in your subclass!
- ();
-}
-sub service {
- # this stub implementation is a simple lookup on $self->services, and
- # should *probably* be overridden in your subclass!
- # (for example, to look up in App DB, with $args->{jurisdiction_id})
-
- my ($self, $service_code, $args) = @_;
-
- return first { $_->service_code eq $service_code } $self->services;
-}
-
-sub post_service_request {
- my ($self, $service, $args) = @_;
-
- die "abstract method post_service_request not overridden";
-}
-
-sub get_service_requests {
- my ($self, $args) = @_;
- die "abstract method get_service_requests not overridden";
-}
-
-sub get_service_request {
- my ($self, $service_request_id, $args) = @_;
-
- die "abstract method get_service_request not overridden";
-}
-
-sub requires_jurisdiction_ids {
- # you may wish to subclass this
- return shift->has_multiple_jurisdiction_ids;
-}
-
-sub check_jurisdiction_id {
- my ($self, $jurisdiction_id) = @_;
-
- # you may wish to override this stub implementation which:
- # - always succeeds if no jurisdiction_id is set
- # - accepts no jurisdiction_id if there is only one set
- # - otherwise checks that the id passed is one of those set
- #
- return 1 unless $self->has_jurisdiction_ids;
-
- if (! defined $jurisdiction_id) {
- return $self->requires_jurisdiction_ids ? 1 : undef;
- }
-
- return first { $jurisdiction_id eq $_ } $self->get_jurisdiction_ids;
-}
-
-=head2 Configurable arguments
-
- * default_service_notice - default for <service_notice> if not
- set by the service or an individual request
- * jurisdictions - an array of jurisdiction_ids
- you may want to subclass the methods:
- - requires_jurisdiction_ids
- - check_jurisdiction_id
- * default_identifier_type
- Open311 doesn't mandate what these types look like, but a backend
- server may! The module provides an example identifier type which allows
- ascii "word" characters .e.g [a-zA-Z0-9_] as an example default.
- You can also override these individually using:
-
- identifier_types => {
- api_key => '//str', #
- jurisdiction_id => ...
- service_code => ...
- service_request_id => ...
- # etc.
- }
- * request_class - class to instantiate for requests via new_request
-
-=cut
-
-has default_identifier_type => (
- is => 'ro',
- isa => Str,
- default => '/open311/example/identifier',
-);
-
-has identifier_types => (
- is => 'ro',
- isa => HashRef[Str],
- default => sub { {} },
- handles_via => 'Hash',
- handles => {
- get_identifier_type => 'get',
- },
-);
-
-around get_identifier_type => sub {
- my ($orig, $self, $type) = @_;
- return $self->$orig($type) // $self->default_identifier_type;
-};
-
-has default_service_notice => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has jurisdiction_ids => (
- is => 'ro',
- isa => Maybe[ArrayRef],
- default => sub { [] },
- handles_via => 'Array',
- handles => {
- has_jurisdiction_ids => 'count',
- get_jurisdiction_ids => 'elements',
- }
-);
-
-has request_class => (
- is => 'ro',
- isa => Str,
- default => 'Open311::Endpoint::Service::Request',
-);
-
-sub new_request {
- my ($self, %args) = @_;
- return $self->request_class->new( %args );
-}
-
-=head2 Other accessors
-
-You may additionally wish to replace the following objects.
-
- * schema - Data::Rx schema for validating Open311 protocol inputs and
- outputs
- * spark - methods for munging base data-structure for output
- * json - JSON output object
- * xml - XML::Simple output object
-
-=cut
-
-has schema => (
- is => 'lazy',
- default => sub {
- my $self = shift;
- Open311::Endpoint::Schema->new( endpoint => $self ),
- },
- handles => {
- rx => 'schema',
- format_boolean => 'format_boolean',
- },
-);
-
-sub learn_additional_types {
- # my ($self, $rx) = @_;
- ## no-op, but override in ::Role or implementation!
-}
-
-has spark => (
- is => 'lazy',
- default => sub {
- Open311::Endpoint::Spark->new();
- },
-);
-
-has json => (
- is => 'lazy',
- default => sub {
- JSON->new->pretty->allow_blessed->convert_blessed;
- },
-);
-
-has xml => (
- is => 'lazy',
- default => sub {
- XML::Simple->new(
- NoAttr=> 1,
- KeepRoot => 1,
- SuppressEmpty => 0,
- );
- },
-);
-
-has w3_dt => (
- is => 'lazy',
- default => sub { DateTime::Format::W3CDTF->new },
-);
-
-has time_zone => (
- is => 'ro',
- default => 'Europe/London',
-);
-
-sub maybe_inflate_datetime {
- my ($self, $dt) = @_;
- return unless $dt;
- return $self->w3_dt->parse_datetime($dt);
-}
-
-=head2 Dispatching
-
-The method dispatch_request returns a list of all the dispatcher routines
-that will be checked in turn by L<Web::Simple>.
-
-You may extend this in a subclass, or with a role.
-
-=cut
-
-sub dispatch_request {
- my $self = shift;
-
- sub (.*) {
- my ($self, $ext) = @_;
- $self->format_response($ext);
- },
-
- sub (GET + /services + ?*) {
- my ($self, $args) = @_;
- $self->call_api( GET_Service_List => $args );
- },
-
- sub (GET + /services/* + ?*) {
- my ($self, $service_id, $args) = @_;
- $self->call_api( GET_Service_Definition => $service_id, $args );
- },
-
- sub (POST + /requests + %*) {
- my ($self, $args) = @_;
- $self->call_api( POST_Service_Request => $args );
- },
-
- sub (GET + /tokens/*) {
- return Open311::Endpoint::Result->error( 400, 'not implemented' );
- },
-
- sub (GET + /requests + ?*) {
- my ($self, $args) = @_;
- $self->call_api( GET_Service_Requests => $args );
- },
-
- sub (GET + /requests/* + ?*) {
- my ($self, $service_request_id, $args) = @_;
- $self->call_api( GET_Service_Request => $service_request_id, $args );
- },
-}
-
-sub GET_Service_List_input_schema {
- return shift->get_jurisdiction_id_validation;
-}
-
-sub GET_Service_List_output_schema {
- return {
- type => '//rec',
- required => {
- services => {
- type => '//arr',
- contents => '/open311/service',
- },
- }
- };
-}
-
-sub GET_Service_List {
- my ($self, @args) = @_;
-
- my @services = map {
- my $service = $_;
- {
- keywords => (join ',' => @{ $service->keywords } ),
- metadata => $self->format_boolean( $service->has_attributes ),
- map { $_ => $service->$_ }
- qw/ service_name service_code description type group /,
- }
- } $self->services;
- return {
- services => \@services,
- };
-}
-
-sub GET_Service_Definition_input_schema {
- my $self = shift;
- return {
- type => '//seq',
- contents => [
- $self->get_identifier_type('service_code'),
- $self->get_jurisdiction_id_validation,
- ],
- };
-}
-
-sub GET_Service_Definition_output_schema {
- return {
- type => '//rec',
- required => {
- service_definition => {
- type => '/open311/service_definition',
- },
- }
- };
-}
-
-sub GET_Service_Definition {
- my ($self, $service_id, $args) = @_;
-
- my $service = $self->service($service_id, $args) or return;
- my $order = 0;
- my $service_definition = {
- service_definition => {
- service_code => $service_id,
- attributes => [
- map {
- my $attribute = $_;
- {
- order => ++$order,
- variable => $self->format_boolean( $attribute->variable ),
- required => $self->format_boolean( $attribute->required ),
- $attribute->has_values ? (
- values => [
- map {
- my ($key, $name) = @$_;
- +{
- key => $key,
- name => $name,
- }
- } sort { $a->[0] cmp $b->[0] } $attribute->values_kv
- ]) : (),
- map { $_ => $attribute->$_ }
- qw/ code datatype datatype_description description /,
- }
- } $service->get_attributes,
- ],
- },
- };
- return $service_definition;
-}
-
-sub POST_Service_Request_input_schema {
- my ($self, $args) = @_;
-
- my $service_code = $args->{service_code};
- unless ($service_code && $args->{api_key}) {
- # return a simple validator
- # to give a nice error message
- return {
- type => '//rec',
- required => {
- service_code => $self->get_identifier_type('service_code'),
- api_key => $self->get_identifier_type('api_key') },
- rest => '//any',
- };
- }
-
- my $service = $self->service($service_code)
- or return; # we can't fetch service, so signal error TODO
-
- my %attributes = ( required => {}, optional => {} );
- for my $attribute ($service->get_attributes) {
- my $section = $attribute->required ? 'required' : 'optional';
- my $key = sprintf 'attribute[%s]', $attribute->code;
- my $def = $attribute->schema_definition;
-
- $attributes{ $section }{ $key } = $def;
- }
-
- # we have to supply at least one of these, but can supply more
- my @address_options = (
- { lat => '//num', long => '//num' },
- { address_string => '//str' },
- { address_id => '//str' },
- );
-
- my @address_schemas;
- while (my $address_required = shift @address_options) {
- push @address_schemas,
- {
- type => '//rec',
- required => {
- service_code => $self->get_identifier_type('service_code'),
- api_key => $self->get_identifier_type('api_key'),
- %{ $attributes{required} },
- %{ $address_required },
- $self->get_jurisdiction_id_required_clause,
- },
- optional => {
- email => '//str',
- device_id => '//str',
- account_id => '//str',
- first_name => '//str',
- last_name => '//str',
- phone => '//str',
- description => '//str',
- media_url => '//str',
- %{ $attributes{optional} || {}},
- (map %$_, @address_options),
- $self->get_jurisdiction_id_optional_clause,
- },
- };
- }
-
- return {
- type => '//any',
- of => \@address_schemas,
- };
-}
-
-sub POST_Service_Request_output_schema {
- my ($self, $args) = @_;
-
- my $service_code = $args->{service_code};
- my $service = $self->service($service_code);
-
- my %return_schema = (
- ($service->type eq 'realtime') ? ( service_request_id => $self->get_identifier_type('service_request_id') ) : (),
- ($service->type eq 'batch') ? ( token => '//str' ) : (),
- );
-
- return {
- type => '//rec',
- required => {
- service_requests => {
- type => '//arr',
- contents => {
- type => '//rec',
- required => {
- %return_schema,
- },
- optional => {
- service_notice => '//str',
- account_id => '//str',
-
- },
- },
- },
- },
- };
-}
-
-sub POST_Service_Request {
- my ($self, $args) = @_;
-
- # TODO pass this through instead of calculating again?
- my $service_code = $args->{service_code};
- my $service = $self->service($service_code);
-
- for my $k (keys %$args) {
- if ($k =~ /^attribute\[(\w+)\]$/) {
- my $value = delete $args->{$k};
- $args->{attributes}{$1} = $value;
- }
- }
-
- my @service_requests = $self->post_service_request( $service, $args );
-
- return {
- service_requests => [
- map {
- my $service_notice =
- $_->service_notice
- || $service->default_service_notice
- || $self->default_service_notice;
- +{
- ($service->type eq 'realtime') ? ( service_request_id => $_->service_request_id ) : (),
- ($service->type eq 'batch') ? ( token => $_->token ) : (),
- $service_notice ? ( service_notice => $service_notice ) : (),
- $_->has_account_id ? ( account_id => $_->account_id ) : (),
- }
- } @service_requests,
- ],
- };
-}
-
-sub GET_Service_Requests_input_schema {
- my $self = shift;
- return {
- type => '//rec',
- required => {
- $self->get_jurisdiction_id_required_clause,
- },
- optional => {
- $self->get_jurisdiction_id_optional_clause,,
- service_request_id => {
- type => '/open311/comma',
- contents => $self->get_identifier_type('service_request_id'),
- },
- service_code => {
- type => '/open311/comma',
- contents => $self->get_identifier_type('service_code'),
- },
- start_date => '/open311/datetime',
- end_date => '/open311/datetime',
- status => {
- type => '/open311/comma',
- contents => '/open311/status',
- },
- },
- };
-}
-
-sub GET_Service_Requests_output_schema {
- my $self = shift;
- return {
- type => '//rec',
- required => {
- service_requests => {
- type => '//arr',
- contents => '/open311/service_request',
- },
- },
- };
-}
-
-sub GET_Service_Requests {
- my ($self, $args) = @_;
-
- my @service_requests = $self->get_service_requests({
-
- jurisdiction_id => $args->{jurisdiction_id},
- start_date => $args->{start_date},
- end_date => $args->{end_date},
-
- map {
- $args->{$_} ?
- ( $_ => [ split ',' => $args->{$_} ] )
- : ()
- } qw/ service_request_id service_code status /,
- });
-
- $self->format_service_requests(@service_requests);
-}
-
-sub GET_Service_Request_input_schema {
- my $self = shift;
- return {
- type => '//seq',
- contents => [
- $self->get_identifier_type('service_request_id'),
- {
- type => '//rec',
- required => {
- $self->get_jurisdiction_id_required_clause,
- },
- optional => {
- $self->get_jurisdiction_id_optional_clause,
- }
- }
- ],
- };
-}
-
-sub GET_Service_Request_output_schema {
- my $self = shift;
- return {
- type => '//rec',
- required => {
- service_requests => {
- type => '//seq', # e.g. a single service_request
- contents => [
- '/open311/service_request',
- ]
- },
- },
- };
-}
-
-sub GET_Service_Request {
- my ($self, $service_request_id, $args) = @_;
-
- my $service_request = $self->get_service_request($service_request_id, $args);
-
- $self->format_service_requests($service_request);
-}
-
-sub format_service_requests {
- my ($self, @service_requests) = @_;
- return {
- service_requests => [
- map {
- my $request = $_;
- +{
- (
- map {
- $_ => $request->$_,
- }
- qw/
- service_request_id
- status
- service_name
- service_code
- address
- address_id
- zipcode
- lat
- long
- media_url
- /
- ),
- (
- map {
- if (my $dt = $request->$_) {
- $_ => $self->w3_dt->format_datetime( $dt )
- }
- else {
- ()
- }
- }
- qw/
- requested_datetime
- updated_datetime
- /
- ),
- (
- map {
- my $value = $request->$_;
- $value ? ( $_ => $value ) : (),
- }
- qw/
- description
- agency_responsible
- service_notice
- /
- ),
- }
- } @service_requests,
- ],
- };
-}
-
-sub has_multiple_jurisdiction_ids {
- return shift->has_jurisdiction_ids > 1;
-}
-
-sub get_jurisdiction_id_validation {
- my $self = shift;
-
- # jurisdiction_id is documented as "Required", but with the note
- # 'This is only required if the endpoint serves multiple jurisdictions'
- # i.e. it is optional as regards the schema, but the server may choose
- # to error if it is not provided.
- return {
- type => '//rec',
- ($self->requires_jurisdiction_ids ? 'required' : 'optional') => {
- jurisdiction_id => $self->get_identifier_type('jurisdiction_id'),
- },
- };
-}
-
-sub get_jurisdiction_id_required_clause {
- my $self = shift;
- $self->requires_jurisdiction_ids ? (jurisdiction_id => $self->get_identifier_type('jurisdiction_id')) : ();
-}
-
-sub get_jurisdiction_id_optional_clause {
- my $self = shift;
- $self->requires_jurisdiction_ids ? () : (jurisdiction_id => $self->get_identifier_type('jurisdiction_id'));
-}
-
-sub call_api {
- my ($self, $api_name, @args) = @_;
-
- my $api_method = $self->can($api_name)
- or die "No such API $api_name!";
-
- if (my $input_schema_method = $self->can("${api_name}_input_schema")) {
- my $input_schema = $self->$input_schema_method(@args)
- or return Open311::Endpoint::Result->error( 400,
- 'Bad request' );
-
- my $schema = $self->rx->make_schema( $input_schema );
- my $input = (scalar @args == 1) ? $args[0] : [@args];
- eval {
- $schema->assert_valid( $input );
- };
- if ($@) {
- return Open311::Endpoint::Result->error( 400,
- "Error in input for $api_name",
- split /\n/, $@,
- # map $_->struct, @{ $@->failures }, # bit cheeky, spec suggests it wants strings only
- );
- }
- }
-
- my $data = eval { $self->$api_method(@args) }
- or return Open311::Endpoint::Result->error(
- $@ ? (500 => $@) : (404 => 'Resource not found')
- );
-
- if (my $output_schema_method = $self->can("${api_name}_output_schema")) {
- my $definition = $self->$output_schema_method(@args);
- my $schema = $self->rx->make_schema( $definition );
- eval {
- $schema->assert_valid( $data );
- };
- if ($@) {
- use Data::Dumper;
- return Open311::Endpoint::Result->error( 500,
- "Error in output for $api_name",
- Dumper($data),
- split /\n/, $@,
- # map $_->struct, @{ $@->failures },
- );
- }
- }
-
- return Open311::Endpoint::Result->success( $data );
-}
-
-sub format_response {
- my ($self, $ext) = @_;
- response_filter {
- my $response = shift;
- return $response unless blessed $response;
- my $status = $response->status;
- my $data = $response->data;
- if ($ext eq 'json') {
- return [
- $status,
- [ 'Content-Type' => 'application/json' ],
- [ $self->json->encode(
- $self->spark->process_for_json( $data )
- )]
- ];
- }
- elsif ($ext eq 'xml') {
- return [
- $status,
- [ 'Content-Type' => 'text/xml' ],
- [ qq(<?xml version="1.0" encoding="utf-8"?>\n),
- $self->xml->XMLout(
- $self->spark->process_for_xml( $data )
- )],
- ];
- }
- else {
- return [
- 404,
- [ 'Content-Type' => 'text/plain' ],
- [ 'Bad extension. We support .xml and .json' ],
- ]
- }
- }
-}
-
-=head1 AUTHOR and LICENSE
-
- hakim@mysociety.org 2014
-
-This is released under the same license as FixMyStreet.
-see https://github.com/mysociety/fixmystreet/blob/master/LICENSE.txt
-
-=cut
-
-__PACKAGE__->run_if_script;
diff --git a/perllib/Open311/Endpoint/Integration/Exor.pm b/perllib/Open311/Endpoint/Integration/Exor.pm
deleted file mode 100644
index 0d5264115..000000000
--- a/perllib/Open311/Endpoint/Integration/Exor.pm
+++ /dev/null
@@ -1,458 +0,0 @@
-package Open311::Endpoint::Integration::Exor;
-use Web::Simple;
-extends 'Open311::Endpoint';
-with 'Open311::Endpoint::Role::mySociety';
-with 'Open311::Endpoint::Role::ConfigFile';
-use DBI;
-use MooX::HandlesVia;
-use DateTime::Format::Oracle; # default format 'YYYY-MM-DD HH24:MI:SS' # NB: hh24 (not hh)
-use Encode qw(from_to);
-
-# declare our constants, as we may not be able to easily install DBD::Oracle
-# on a development system!
-# t/open311/endpoint/warwick.t disables DBD::Oracle from loading, so the default
-# stubbed values will be used instead:
-sub ORA_DATE ();
-sub ORA_NUMBER ();
-sub ORA_VARCHAR2 ();
-no warnings 'redefine';
-use DBD::Oracle qw(:ora_types);
-
-BEGIN {
-*ORA_DATE = *ORA_NUMBER = *ORA_VARCHAR2 = sub () { 1 }
- unless $DBD::Oracle::VERSION;
-}
-
-has ora_dt => (
- is => 'lazy',
- default => sub {
- $ENV{NLS_DATE_FORMAT} = 'YYYY-MM-DD HH24:MI';
- return 'DateTime::Format::Oracle'
- },
- # NB: we just return the class name. This is to smooth over odd API,
- # for consistency with w3_dt
-);
-
-sub parse_ora_date {
- my ($self, $date_string) = @_;
-
- my $date = $self->ora_dt->parse_datetime( $date_string );
-
- # will be in floating time_zone so set
- $date->set_time_zone( $self->time_zone );
-
- return $date;
-}
-
-has max_limit => (
- is => 'ro',
- default => 1000,
-);
-
-has encode_to_win1252 => (
- is => 'ro',
- default => 1,
-);
-
-has _connection_details => (
- is => 'lazy',
- default => sub {
- my $self = shift;
- my $DB_HOST = $self->db_host;
- my $ORACLE_SID = $self->oracle_sid;
- my $DB_PORT = $self->db_port;
- my $USERNAME = $self->db_username;
- my $PASSWORD = $self->db_password;
- return [ "dbi:Oracle:host=$DB_HOST;sid=$ORACLE_SID;port=$DB_PORT", $USERNAME, $PASSWORD ]
- },
- handles_via => 'Array',
- handles => {
- connection_details => 'elements',
- dsn => [ get => 0 ],
- },
-);
-
-has dbh => (
- is => 'lazy',
- default => sub {
- my $self = shift;
- return DBI->connect( $self->connection_details );
- }
-);
-
-has db_host => (
- is => 'ro',
- default => 'localhost',
-);
-
-has oracle_sid => (
- is => 'ro',
- default => '1000', # DUMMY
-);
-
-has db_port => (
- is => 'ro',
- default => 1531,
-);
-
-has db_username => (
- is => 'ro',
- default => 'FIXMYSTREET',
-);
-
-has db_password => (
- is => 'ro',
- default => 'SUPERSEEKRIT', # DUMMY
-);
-
-has strip_control_characters => (
- is => 'ro',
- default => 'ruthless',
-);
-
-has testing => (
- is => 'ro',
- default => 0,
-);
-
-has ce_cat => (
- is => 'ro',
- default => 'DEF',
-);
-
-has ce_class => (
- is => 'ro',
- default => 'N/A',
-);
-
-has ce_cpr_id => (
- is => 'ro',
- default => 5,
-);
-
-has ce_contact_type => (
- is => 'ro',
- default => 'PU',
-);
-
-has ce_status_code => (
- is => 'ro',
- default => 'RE',
-);
-
-has ce_compl_user_type => (
- is => 'ro',
- default => 'USER',
-);
-
-#------------------------------------------------------------------
-# pem_field_types
-# return hash of types by field name: any not explicitly set here
-# can be defaulted to VARCHAR2
-#------------------------------------------------------------------
-has get_pem_field_types => (
- is => 'ro',
- handles_via => 'Hash',
- default => sub {
- {
- ':ce_incident_datetime' => ORA_DATE,
- ':ce_x' => ORA_NUMBER,
- ':ce_y' => ORA_NUMBER,
- ':ce_date_expires' => ORA_DATE,
- ':ce_issue_number' => ORA_NUMBER,
- ':ce_status_date' => ORA_DATE,
- ':ce_compl_ack_date' => ORA_DATE,
- ':ce_compl_peo_date' => ORA_DATE,
- ':ce_compl_target' => ORA_DATE,
- ':ce_compl_complete' => ORA_DATE,
- ':ce_compl_from' => ORA_DATE,
- ':ce_compl_to' => ORA_DATE,
- ':ce_compl_corresp_date' => ORA_DATE,
- ':ce_compl_corresp_deliv_date' => ORA_DATE,
- ':ce_compl_no_of_petitioners' => ORA_NUMBER,
- ':ce_compl_est_cost' => ORA_NUMBER,
- ':ce_compl_adv_cost' => ORA_NUMBER,
- ':ce_compl_act_cost' => ORA_NUMBER,
- ':ce_compl_follow_up1' => ORA_DATE,
- ':ce_compl_follow_up2' => ORA_DATE,
- ':ce_compl_follow_uo3' => ORA_DATE,
- ':ce_date_time_arrived' => ORA_DATE,
- ':error_value' => ORA_NUMBER,
- ':ce_doc_id' => ORA_NUMBER,
- }
- },
- handles => {
- get_pem_field_type => 'get',
-
- },
-);
-
-sub pem_field_type {
- my ($self, $field) = @_;
- return $self->get_pem_field_type($field) || ORA_VARCHAR2;
-}
-
-
-sub services {
- # not currently used as Warwick.pm uses a hardcoded list.
- die "TODO";
-}
-
-sub _strip_ruthless {
- my $text = shift or return '';
- $text =~ s/[[:cntrl:]]/ /g; # strip all control chars, simples
- return $text;
-}
-
-sub _strip_non_ruthless {
- my $text = shift or return '';
- # slightly odd doubly negated character class
- $text =~ s/[^\t\n[:^cntrl:]]/ /g; # leave tabs and newlines
- return $text;
-}
-sub strip {
- my ($self, $text, $max_len, $prefer_non_ruthless) = @_;
- use Carp 'confess';
- confess 'EEEK' unless $self;
- if (my $scc = $self->strip_control_characters) {
- if ($scc eq 'ruthless') {
- $text = _strip_ruthless($text);
- }
- elsif ($prefer_non_ruthless) {
- $text = _strip_non_ruthless($text);
- }
- else {
- $text = _strip_ruthless($text);
- }
- }
- return $max_len ? substr($text, 0, $max_len) : $text;
-}
-
-sub post_service_request {
- my ($self, $service, $args) = @_;
- die "No such service" unless $service;
-
- if ($args->{media_url}) {
- # don't put URL for full images into the database (because they're too big to see on a Blackberry)
- $args->{media_url} =~ s/\.full(\.jpe?g)$/$1/;
- $args->{description} .= $self->strip( "\n\n") . 'Photo: ' . $args->{media_url};
- }
- my $attributes = $args->{attributes};
- my $location = $attributes->{closest_address};
-
- if ($location) {
- # strip out everything apart from "Nearest" preamble
- $location=~s/(Nearest road)[^:]+:/$1:/;
- $location=~s/(Nearest postcode)[^:]+:(.*?)(\(\w+ away\))?\s*(\n|$)/$1: $2/;
- }
-
- my %bindings;
- # comments here are suggested values
- # field lengths are from OCC's Java portlet
- # fixed values (configurable via config)
- $bindings{":ce_cat"} = $self->ce_cat;
- $bindings{":ce_class"} = $self->ce_class;
- $bindings{":ce_contact_type"} = $self->ce_contact_type;
- $bindings{":ce_status_code"} = $self->ce_status_code;
- $bindings{":ce_compl_user_type"}= $self->ce_compl_user_type;
- $bindings{":ce_cpr_id"} = $self->ce_cpr_id;
-
- # ce_incident_datetime is *not* an optional param, but FMS isn't sending it at the moment
- $bindings{":ce_incident_datetime"}=$args->{requested_datetime}
- || $self->ora_dt->format_datetime( DateTime->now );
-
- # especially FMS-specific:
- $bindings{":ce_source"} = "FMS"; # important, and specific to this script!
- $bindings{":ce_doc_reference"} = $attributes->{external_id}; # FMS ID
- $bindings{":ce_enquiry_type"} = $args->{service_code};
-
- # incoming data
- $bindings{":ce_x"} = $attributes->{easting};
- $bindings{":ce_y"} = $attributes->{northing};
- $bindings{":ce_forename"} = uc $self->strip($args->{first_name}, 30); # 'CLIFF'
- $bindings{":ce_surname"} = uc $self->strip($args->{last_name}, 30); # 'STEWART'
- $bindings{":ce_work_phone"} = $self->strip($args->{phone}, 25); # '0117 600 4200'
- $bindings{":ce_email"} = uc $self->strip($args->{email}, 50); # 'info@exor.co.uk'
- $bindings{":ce_description"} = $self->strip($args->{description}, 1970, 1); # 'Large Pothole'
-
- # nearest address guesstimate
- $bindings{":ce_location"} = $self->strip($location, 254);
-
- if ($self->testing) {
- warn Dumper(\%bindings); use Data::Dumper;
- }
-
- my ($pem_id, $error_value, $error_product) = $self->insert_into_db(\%bindings);
-
- # if error, maybe need to look it up:
- # error_value is the index HER_NO in table HIG_ERRORS, which has messages
- # actually err_product not helpful (will always be "DOC")
- die "$error_value $error_product" if $error_value || $error_product;
-
- my $request = $self->new_request(
-
- # NB: possible race condition between next_request_id and _add_request
- # (this is fine for synchronous test-cases)
-
- service => $service,
- service_request_id => $pem_id,
- status => 'open',
- description => $args->{description},
- agency_responsible => '',
- requested_datetime => DateTime->now(),
- updated_datetime => DateTime->now(),
- address => $args->{address_string} // '',
- address_id => $args->{address_id} // '',
- media_url => $args->{media_url} // '',
- zipcode => $args->{zipcode} // '',
- attributes => $attributes,
-
- );
-
- return $request;
-}
-
-sub insert_into_db {
- my ($self, $bindings) = @_;
- my %bindings = %$bindings;
-
- my ($pem_id, $error_value, $error_product);
-
- my $dbh = $self->dbh;
-
- my $sth = $dbh->prepare(q#
- BEGIN
- PEM.create_enquiry(
- ce_cat => :ce_cat,
- ce_class => :ce_class,
- ce_cpr_id => :ce_cpr_id,
- ce_forename => :ce_forename,
- ce_surname => :ce_surname,
- ce_contact_type => :ce_contact_type,
- ce_location => :ce_location,
- ce_work_phone => :ce_work_phone,
- ce_email => :ce_email,
- ce_description => :ce_description,
- ce_enquiry_type => :ce_enquiry_type,
- ce_source => :ce_source,
- ce_incident_datetime => to_Date(:ce_incident_datetime,'YYYY-MM-DD HH24:MI'),
- ce_x => :ce_x,
- ce_y => :ce_y,
- ce_doc_reference => :ce_doc_reference,
- ce_status_code => :ce_status_code,
- ce_compl_user_type => :ce_compl_user_type,
- error_value => :error_value,
- error_product => :error_product,
- ce_doc_id => :ce_doc_id);
- END;
- #);
-
- foreach my $name (sort keys %bindings) {
- next if grep {$name eq $_} (':error_value', ':error_product', ':ce_doc_id'); # return values (see below)
- $sth->bind_param(
- $name,
- $bindings{$name},
- $self->pem_field_type( $name ),
- );
- }
- # return values are bound explicitly here:
- $sth->bind_param_inout(":error_value", \$error_value, 12); #> l_ERROR_VALUE # number
- $sth->bind_param_inout(":error_product", \$error_product, 10); #> l_ERROR_PRODUCT (will always be 'DOC')
- $sth->bind_param_inout(":ce_doc_id", \$pem_id, 12); #> l_ce_doc_id # number
-
- # not used, but from the example docs, for reference
- # $sth->bind_param(":ce_contact_title", $undef); # 'MR'
- # $sth->bind_param(":ce_postcode", $undef); # 'BS11EJ' NB no spaces, upper case
- # $sth->bind_param(":ce_building_no", $undef); # '1'
- # $sth->bind_param(":ce_building_name", $undef); # 'CLIFTON HEIGHTS'
- # $sth->bind_param(":ce_street", $undef); # 'HIGH STREET'
- # $sth->bind_param(":ce_town", $undef); # 'BRSITOL'
- # $sth->bind_param(":ce_rse_he_id", $undef); #> nm3net.get_ne_id('1200D90970/09001','L')
- # $sth->bind_param(":ce_compl_target", $undef); # '08-JAN-2004'
- # $sth->bind_param(":ce_compl_corresp_date",$undef); # '02-JAN-2004'
- # $sth->bind_param(":ce_compl_corresp_deliv_date", $undef); # '02-JAN-2004'
- # $sth->bind_param(":ce_resp_of", $undef); # 'GBOWLER'
- # $sth->bind_param(":ce_hct_vip", $undef); # 'CO'
- # $sth->bind_param(":ce_hct_home_phone", $undef); # '0117 900 6201'
- # $sth->bind_param(":ce_hct_mobile_phone", $undef); # '07111 1111111'
- # $sth->bind_param(":ce_compl_remarks", $undef); # remarks (notes) max 254 char
-
- $sth->execute();
- $dbh->disconnect;
-
- return ($pem_id, $error_value, $error_product);
-}
-
-sub get_service_request_updates {
- my ($self, $args) = @_;
-
- # ignore jurisdiction_id for now
- #
- my $start_date = $self->maybe_inflate_datetime( $args->{start_date} );
- my $end_date = $self->maybe_inflate_datetime( $args->{end_date} );
-
- unless ($self->testing) {
- $start_date = DateTime->now->subtract( days => 1 )
- unless ($start_date or $end_date);
- }
-
- my $w3_dt = $self->w3_dt;
- my $ora_dt = $self->ora_dt;
- my $ORA_DT_FORMAT = $ora_dt->nls_date_format;
-
- my @where;
-
- push @where, sprintf
- 'updated_timedate >= to_date(%s, %s)',
- $ora_dt->format_datetime($start_date), $ORA_DT_FORMAT
- if $start_date;
-
- push @where, sprintf
- 'updated_timedate <= to_date(%s, %s)',
- $ora_dt->format_datetime($end_date), $ORA_DT_FORMAT
- if $end_date;
-
- push @where, "(status='OPEN' OR status='CLOSED')"
- unless $self->testing;
-
- my $WHERE_CLAUSE = @where ?
- 'WHERE ' . join(' AND ', grep {$_} @where)
- : '';
-
- my $sql = qq(
- SELECT
- row_id,
- service_request_id,
- to_char(updated_timedate, '$ORA_DT_FORMAT'),
- status,
- description
- FROM higatlas.fms_update
- $WHERE_CLAUSE
- ORDER BY updated_timedate DESC);
-
- my $limit = $self->max_limit; # also allow testing to modify this?
- $sql = "SELECT * FROM ($sql) WHERE ROWNUM <= $limit" if $limit;
-
- my @data = $self->get_updates_from_sql( $sql );
-
- my @updates = map {
- Open311::Endpoint::Service::Request::Update->new(
- update_id => $_->{row_id},
- service_request_id => $_->{service_request_id},
- updated_datetime => $self->parse_ora_date( $_->{updated_datetime} ),
- status => $_->{status},
- description => $_->{description}
- )
- } @data;
-
- return @updates;
-}
-
-sub get_updates_from_sql {
- my ($self, $sql) = @_;
- my $dbh = $self->dbh;
- my $ary_ref = $dbh->selectall_arrayref($sql, { Slice => {} } );
- return @$ary_ref;
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Integration/Warwick.pm b/perllib/Open311/Endpoint/Integration/Warwick.pm
deleted file mode 100644
index bc57a8e8c..000000000
--- a/perllib/Open311/Endpoint/Integration/Warwick.pm
+++ /dev/null
@@ -1,47 +0,0 @@
-package Open311::Endpoint::Integration::Warwick;
-use Web::Simple;
-extends 'Open311::Endpoint::Integration::Exor';
-use Open311::Endpoint::Service::Exor;
-
-has '+default_service_notice' => (
- default => 'Warwickshire Open311 Endpoint',
-);
-
-sub services {
- # TODO, get this from ::Exor
- my @services = (
- # [ BR => 'Bridges' ],
- # [ CD => 'Carriageway Defect' ],
- # [ CD => 'Roads/Highways' ],
- # [ DR => 'Drainage' ],
- # [ DS => 'Debris/Spillage' ],
- # [ FE => 'Fences' ],
- # [ 'F D' => 'Pavements' ],
- # [ GC => 'Gully & Catchpits' ],
- # [ IS => 'Ice/Snow' ],
- # [ MD => 'Mud & Debris' ],
- # [ MH => 'Manhole' ],
- # [ OS => 'Oil Spillage' ],
- # [ OT => 'Other' ],
- [ PO => 'Pothole' ],
- # [ PD => 'Property Damage' ],
- # [ RM => 'Road Marking' ],
- # [ SN => 'Road traffic signs' ],
- # [ SP => 'Traffic' ],
- # [ UT => 'Utilities' ],
- # [ VG => 'Vegetation' ],
- );
- return map {
- my ($code, $name) = @$_;
- Open311::Endpoint::Service::Exor->new(
- service_code => $code,
- service_name => $name,
- description => $name,
- type => 'realtime',
- keywords => [qw/ /],
- group => 'highways',
- ),
- } @services;
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Result.pm b/perllib/Open311/Endpoint/Result.pm
deleted file mode 100644
index 61454e749..000000000
--- a/perllib/Open311/Endpoint/Result.pm
+++ /dev/null
@@ -1,38 +0,0 @@
-package Open311::Endpoint::Result;
-use Moo;
-
-has status => (
- is => 'ro',
-);
-has data => (
- is => 'ro',
-);
-
-sub success {
- my ($class, $data) = @_;
- return $class->new({
- status => 200,
- data => $data,
- });
-}
-
-sub error {
- my ($class, $code, @errors) = @_;
- $code ||= 400;
- return $class->new({
- status => $code,
- data => {
- errors => [
- map {
- ref $_ eq 'HASH' ? $_ :
- {
- code => $code,
- description => "$_",
- }
- } @errors,
- ],
- },
- });
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Role/ConfigFile.pm b/perllib/Open311/Endpoint/Role/ConfigFile.pm
deleted file mode 100644
index 1c4b83355..000000000
--- a/perllib/Open311/Endpoint/Role/ConfigFile.pm
+++ /dev/null
@@ -1,30 +0,0 @@
-package Open311::Endpoint::Role::ConfigFile;
-use Moo::Role;
-use Path::Tiny 'path';
-use Carp 'croak';
-use YAML ();
-use Types::Standard qw( Maybe Str );
-
-has config_file => (
- is => 'ro',
- isa => Maybe[Str],
-);
-
-around BUILDARGS => sub {
- my $next = shift;
- my $class = shift;
-
- my %args = @_;
- if (my $config_file = $args{config_file}) {
- my $cfg = path($config_file);
- croak "$config_file is not a file" unless $cfg->is_file;
-
- my $config = YAML::LoadFile($cfg) or croak "Couldn't load config from $config_file";
- return $class->$next(%$config, %args);
- }
- else {
- return $class->$next(%args);
- }
-};
-
-1;
diff --git a/perllib/Open311/Endpoint/Role/mySociety.pm b/perllib/Open311/Endpoint/Role/mySociety.pm
deleted file mode 100644
index de65baab6..000000000
--- a/perllib/Open311/Endpoint/Role/mySociety.pm
+++ /dev/null
@@ -1,159 +0,0 @@
-package Open311::Endpoint::Role::mySociety;
-
-=head1 NAME
-
-Open311::Endpoint::Role::mySociety - mySociety's proposed Open311 extensions
-
-=head1 SYNOPSIS
-
-See mySociety's
-L<blog post|https://www.mysociety.org/2013/02/20/open311-extended/>
-and
-L<proposal|https://github.com/mysociety/FixMyStreet/wiki/Open311-FMS---Proposed-differences-to-Open311>
-for a full explanation of the spec extension.
-
-You can use the extensions as follows:
-
- package My::Open311::Endpoint;
- use Web::Simple;
- extends 'Open311::Endpoint';
- with 'Open311::Endpoint::Role::mySociety';
-
-You will have to provide implementations of
-
- get_service_request_updates
- post_service_request_update
-
-You will need to return L<Open311::Endpoint::Service::Request::Update>
-objects. However, the root L<Open311::Endpoint::Service::Request> is not
-aware of updates, so you may may find it easier to ensure that the ::Service
-objects you create (with get_service_request etc.) return
-L<Open311::Endpoint::Service::Request::mySociety> objects.
-
-=cut
-
-use Moo::Role;
-no warnings 'illegalproto';
-
-use Open311::Endpoint::Service::Request::mySociety;
-has '+request_class' => (
- is => 'ro',
- default => 'Open311::Endpoint::Service::Request::mySociety',
-);
-
-around dispatch_request => sub {
- my ($orig, $self, @args) = @_;
- my @dispatch = $self->$orig(@args);
- return (
- @dispatch,
-
- sub (GET + /servicerequestupdates + ?*) {
- my ($self, $args) = @_;
- $self->call_api( GET_Service_Request_Updates => $args );
- },
-
- sub (POST + /servicerequestupdates + ?*) {
- my ($self, $args) = @_;
- $self->call_api( POST_Service_Request_Update => $args );
- },
-
- );
-};
-
-sub GET_Service_Request_Updates_input_schema {
- my $self = shift;
- return {
- type => '//rec',
- required => {
- $self->get_jurisdiction_id_required_clause,
- },
- optional => {
- $self->get_jurisdiction_id_optional_clause,
- api_key => $self->get_identifier_type('api_key'),
- start_date => '/open311/datetime',
- end_date => '/open311/datetime',
- }
- };
-}
-
-sub GET_Service_Request_Updates_output_schema {
- my $self = shift;
- return {
- type => '//rec',
- required => {
- service_request_updates => {
- type => '//arr',
- contents => '/open311/service_request_update',
- },
- },
- };
-}
-
-sub GET_Service_Request_Updates {
- my ($self, $args) = @_;
-
- my @updates = $self->get_service_request_updates({
- jurisdiction_id => $args->{jurisdiction_id},
- start_date => $args->{start_date},
- end_date => $args->{end_date},
- });
-
- $self->format_updates(@updates);
-}
-
-sub format_updates {
- my ($self, @updates) = @_;
- return {
- service_request_updates => [
- map {
- my $update = $_;
- +{
- (
- map {
- $_ => $update->$_,
- }
- qw/
- update_id
- service_request_id
- status
- description
- media_url
- /
- ),
- (
- map {
- $_ => $self->w3_dt->format_datetime( $update->$_ ),
- }
- qw/
- updated_datetime
- /
- ),
- }
- } @updates
- ]
- };
-}
-
-sub get_service_request_updates {
- my ($self, $args) = @_;
- die "abstract method get_service_request_updates not overridden";
-}
-
-sub learn_additional_types {
- my ($self, $schema) = @_;
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/service_request_update',
- {
- type => '//rec',
- required => {
- service_request_id => $self->get_identifier_type('service_request_id'),
- update_id => $self->get_identifier_type('update_id'),
- status => '/open311/status',
- updated_datetime => '/open311/datetime',
- description => '//str',
- media_url => '//str',
- },
- }
- );
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Schema.pm b/perllib/Open311/Endpoint/Schema.pm
deleted file mode 100644
index 9a2ad81e5..000000000
--- a/perllib/Open311/Endpoint/Schema.pm
+++ /dev/null
@@ -1,177 +0,0 @@
-package Open311::Endpoint::Schema;
-use Moo;
-use Data::Rx;
-
-use Open311::Endpoint::Schema::Comma;
-use Open311::Endpoint::Schema::Regex;
-
-use Carp 'confess';
-has endpoint => (
- is => 'ro',
- handles => [qw/
- get_jurisdiction_id_required_clause
- get_jurisdiction_id_optional_clause
- get_identifier_type
- learn_additional_types
- /],
-);
-
-sub enum {
- my ($self, $type, @values) = @_;
- return {
- type => '//any',
- of => [ map {
- {
- type => $type,
- value => $_,
- }
- } @values ],
- };
-}
-
-sub format_boolean {
- my ($self, $value) = @_;
- return $value ? 'true' : 'false';
-}
-
-has schema => (
- is => 'lazy',
- default => sub {
- my $self = shift;
-
- my $schema = Data::Rx->new({
- sort_keys => 1,
- prefix => {
- open311 => 'tag:wiki.open311.org,GeoReport_v2:rx/',
- },
- type_plugins => [qw(
- Open311::Endpoint::Schema::Comma
- Open311::Endpoint::Schema::Regex
- )],
- });
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/bool',
- $self->enum( '//str', qw[ true false ] ));
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/datetime',
- {
- type => '/open311/regex',
- pattern => qr{
- ^
- \d{4} - \d{2} - \d{2} # yyyy-mm-dd
- T
- \d{2} : \d{2} : \d{2} # hh:mm:ss
- (?:
- Z # "Zulu" time, e.g. UTC
- | [+-] \d{2} : \d{2} # +/- hh:mm offset
- )
- $
- }ax, # use ascii semantics so /d means [0-9], and allow formatting
- message => "found value isn't a datetime",
- });
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/example/identifier',
- {
- type => '/open311/regex',
- pattern => qr{^ \w+ $}ax,
- message => "found value isn't a valid identifier",
- });
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/status',
- $self->enum( '//str', qw[ open closed ] ));
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/post_type',
- $self->enum( '//str', qw[ realtime batch blackbox ] ));
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/service',
- {
- type => '//rec',
- required => {
- service_name => '//str',
- type => '/open311/post_type',
- metadata => '/open311/bool',
- description => '//str',
- service_code => '//str',
- },
- optional => {
- keywords => '//str',
- group => '//str',
- }
- }
- );
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/value',
- {
- type => '//rec',
- required => {
- key => '//str',
- name => '//str',
- }
- }
- );
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/attribute',
- {
- type => '//rec',
- required => {
- code => '//str',
- datatype => $self->enum( '//str', qw[ string number datetime text singlevaluelist multivaluelist ] ),
- datatype_description => '//str',
- description => '//str',
- order => '//int',
- required => '/open311/bool',
- variable => '/open311/bool',
- },
- optional => {
- values => {
- type => '//arr',
- contents => '/open311/value',
- },
- },
- }
- );
-
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/service_definition',
- {
- type => '//rec',
- required => {
- service_code => '//str',
- attributes => {
- type => '//arr',
- contents => '/open311/attribute',
- }
- },
- }
- );
- $schema->learn_type( 'tag:wiki.open311.org,GeoReport_v2:rx/service_request',
- {
- type => '//rec',
- required => {
- service_request_id => $self->get_identifier_type('service_request_id'),
- status => '/open311/status',
- service_name => '//str',
- service_code => $self->get_identifier_type('service_code'),
- requested_datetime => '/open311/datetime',
- updated_datetime => '/open311/datetime',
- address => '//str',
- address_id => '//str',
- zipcode => '//str',
- lat => '//num',
- long => '//num',
- media_url => '//str',
- },
- optional => {
- request => '//str',
- description => '//str',
- agency_responsible => '//str',
- service_notice => '//str',
- },
- }
- );
-
- $self->learn_additional_types($schema);
-
- return $schema;
- },
-);
-
-1;
diff --git a/perllib/Open311/Endpoint/Schema/Comma.pm b/perllib/Open311/Endpoint/Schema/Comma.pm
deleted file mode 100644
index f6ac1bcc7..000000000
--- a/perllib/Open311/Endpoint/Schema/Comma.pm
+++ /dev/null
@@ -1,53 +0,0 @@
-use strict; use warnings;
-package Open311::Endpoint::Schema::Comma;
-use parent 'Data::Rx::CommonType::EasyNew';
-
-use Carp ();
-
-sub type_uri {
- 'tag:wiki.open311.org,GeoReport_v2:rx/comma',
-}
-
-sub guts_from_arg {
- my ($class, $arg, $rx) = @_;
- $arg ||= {};
-
- my $contents = delete $arg->{contents}
- or Carp::croak "No contents for comma-separated list";
- my $trim = delete $arg->{trim};
- if (my @unexpected = keys %$arg) {
- Carp::croak sprintf "Unknown arguments %s in constructing %s",
- (join ',' => @unexpected), $class->type_uri;
- }
-
- return {
- trim => $trim,
- str_schema => $rx->make_schema('//str'),
- subschema => $rx->make_schema( $contents ),
- };
-}
-
-sub assert_valid {
- my ($self, $value) = @_;
-
- $self->{str_schema}->assert_valid( $value );
-
- my @values = split ',' => $value;
-
- my $subschema = $self->{subschema};
- my $trim = $self->{trim};
-
- for my $subvalue (@values) {
-
- if ($self->{trim}) {
- $subvalue =~s/^\s*//;
- $subvalue =~s/\s*$//;
- }
-
- $subschema->assert_valid( $subvalue );
- }
-
- return 1;
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Schema/Regex.pm b/perllib/Open311/Endpoint/Schema/Regex.pm
deleted file mode 100644
index a79542198..000000000
--- a/perllib/Open311/Endpoint/Schema/Regex.pm
+++ /dev/null
@@ -1,43 +0,0 @@
-use strict; use warnings;
-package Open311::Endpoint::Schema::Regex;
-use parent 'Data::Rx::CommonType::EasyNew';
-
-use Carp ();
-
-sub type_uri {
- 'tag:wiki.open311.org,GeoReport_v2:rx/regex',
-}
-
-sub guts_from_arg {
- my ($class, $arg, $rx) = @_;
- $arg ||= {};
-
- my $pattern = delete $arg->{pattern};
- my $message = delete $arg->{message};
- if (my @unexpected = keys %$arg) {
- Carp::croak sprintf "Unknown arguments %s in constructing %s",
- (join ',' => @unexpected), $class->type_uri;
- }
-
- return {
- str_schema => $rx->make_schema('//str'),
- pattern => qr/$pattern/,
- message => $message,
- };
-}
-
-sub assert_valid {
- my ($self, $value) = @_;
-
- $self->{str_schema}->assert_valid( $value );
-
- return 1 if $value =~ $self->{pattern};
-
- $self->fail({
- error => [ qw(type) ],
- message => $self->{message} || "found value doesn't match regex",
- value => $value,
- })
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Service.pm b/perllib/Open311/Endpoint/Service.pm
deleted file mode 100644
index 2c28c6d79..000000000
--- a/perllib/Open311/Endpoint/Service.pm
+++ /dev/null
@@ -1,55 +0,0 @@
-package Open311::Endpoint::Service;
-use Moo;
-use MooX::HandlesVia;
-use Types::Standard ':all';
-use namespace::clean;
-
-has service_name => (
- is => 'ro',
- isa => Str,
-);
-
-has service_code => (
- is => 'ro',
- isa => Str,
-);
-
-has default_service_notice => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has description => (
- is => 'ro',
- isa => Str,
-);
-
-has keywords => (
- is => 'ro',
- isa => ArrayRef[Str],
- default => sub { [] },
-);
-
-has group => (
- is => 'ro',
- isa => Str,
-);
-
-has type => (
- is => 'ro',
- isa => Enum[qw/ realtime batch blackbox /],
-);
-
-has attributes => (
- is => 'ro',
- isa => ArrayRef[ InstanceOf['Open311::Endpoint::Service::Attribute'] ],
- default => sub { [] },
- handles_via => 'Array',
- handles => {
- has_attributes => 'count',
- get_attributes => 'elements',
- }
-);
-
-1;
diff --git a/perllib/Open311/Endpoint/Service/Attribute.pm b/perllib/Open311/Endpoint/Service/Attribute.pm
deleted file mode 100644
index f88919408..000000000
--- a/perllib/Open311/Endpoint/Service/Attribute.pm
+++ /dev/null
@@ -1,82 +0,0 @@
-package Open311::Endpoint::Service::Attribute;
-use Moo;
-use MooX::HandlesVia;
-use Types::Standard ':all';
-use namespace::clean;
-
-# from http://wiki.open311.org/GeoReport_v2#GET_Service_Definition
-
-# A unique identifier for the attribute
-has code => (
- is => 'ro',
- isa => Str,
-);
-
-# true denotes that user input is needed
-# false means the attribute is only used to present information to the user within the description field
-#
-# NB: unsure what false means for the rest of the options here, e.g. should remainder of fields by Maybe[] ?
-has variable => (
- is => 'ro',
- isa => Bool,
- default => sub { 1 },
-);
-
-# Denotes the type of field used for user input.
-has datatype => (
- is => 'ro',
- isa => Enum[qw/ string number datetime text singlevaluelist multivaluelist /],
-);
-
-has required => (
- is => 'ro',
- isa => Bool,
-);
-
-# A description of the datatype which helps the user provide their input
-has datatype_description => (
- is => 'ro',
- isa => Str,
-);
-
-# A description of the attribute field with instructions for the user to find
-# and identify the requested information
-has description => (
- is => 'ro',
- isa => Str,
-);
-
-# NB: we don't model the "Order" field here, as that's really for the Service
-# object to return
-
-# only relevant for singlevaluelist or multivaluelist
-has values => (
- is => 'ro',
- isa => HashRef,
- default => sub { {} },
- handles_via => 'Hash',
- handles => {
- get_value => 'get',
- get_values => 'keys',
- has_values => 'count',
- values_kv => 'kv',
- }
-);
-
-sub schema_definition {
- my $self = shift;
-
- my @values = map +{ type => '//str', value => $_ }, $self->get_values;
- my %schema_types = (
- string => '//str',
- number => '//num',
- datetime => '//str', # TODO
- text => '//str',
- singlevaluelist => { type => '//any', of => [@values] },
- multivaluelist => { type => '//arr', of => [@values] },
- );
-
- return $schema_types{ $self->datatype };
-}
-
-1;
diff --git a/perllib/Open311/Endpoint/Service/Exor.pm b/perllib/Open311/Endpoint/Service/Exor.pm
deleted file mode 100644
index 6261875c1..000000000
--- a/perllib/Open311/Endpoint/Service/Exor.pm
+++ /dev/null
@@ -1,44 +0,0 @@
-package Open311::Endpoint::Service::Exor;
-use Moo;
-extends 'Open311::Endpoint::Service';
-use Open311::Endpoint::Service::Attribute;
-
-has '+attributes' => (
- is => 'ro',
- default => sub { [
- Open311::Endpoint::Service::Attribute->new(
- code => 'easting',
- variable => 0, # set by server
- datatype => 'number',
- required => 1,
- datatype_description => 'a number',
- description => 'easting',
- ),
- Open311::Endpoint::Service::Attribute->new(
- code => 'northing',
- variable => 0, # set by server
- datatype => 'number',
- required => 1,
- datatype_description => 'a number',
- description => 'northing',
- ),
- Open311::Endpoint::Service::Attribute->new(
- code => 'closest_address',
- variable => 0, # set by server
- datatype => 'string',
- required => 1,
- datatype_description => 'an address',
- description => 'closest address',
- ),
- Open311::Endpoint::Service::Attribute->new(
- code => 'external_id',
- variable => 0, # set by server
- datatype => 'string',
- required => 1,
- datatype_description => 'an id',
- description => 'external system ID',
- ),
- ] },
-);
-
-1;
diff --git a/perllib/Open311/Endpoint/Service/Request.pm b/perllib/Open311/Endpoint/Service/Request.pm
deleted file mode 100644
index 8dfa5df3a..000000000
--- a/perllib/Open311/Endpoint/Service/Request.pm
+++ /dev/null
@@ -1,110 +0,0 @@
-package Open311::Endpoint::Service::Request;
-use Moo;
-use MooX::HandlesVia;
-use Types::Standard ':all';
-use namespace::clean;
-
-has service => (
- is => 'ro',
- isa => InstanceOf['Open311::Endpoint::Service'],
- handles => [
- qw/ service_code service_name /
- ],
-);
-
-has service_request_id => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has token => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has service_notice => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has account_id => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has status => (
- is => 'rw',
- isa => Enum[qw/ open closed /],
- default => sub { 'open' },
-);
-
-has description => (
- is => 'ro',
- isa => Maybe[Str],
-);
-
-has agency_responsible => (
- is => 'ro',
- isa => Maybe[Str],
-);
-
-has requested_datetime => (
- is => 'ro',
- isa => Maybe[ InstanceOf['DateTime'] ],
- default => sub { DateTime->now() },
-);
-
-has updated_datetime => (
- is => 'rw',
- isa => Maybe[ InstanceOf['DateTime'] ],
- default => sub { DateTime->now() },
-);
-
-has expected_datetime => (
- is => 'ro',
- isa => Maybe[ InstanceOf['DateTime'] ],
-);
-
-has address => (
- is => 'ro',
- isa => Str,
- default => sub { '' },
-);
-
-has address_id => (
- is => 'ro',
- isa => Str,
- default => sub { '' },
-);
-
-has zipcode => (
- is => 'ro',
- isa => Str,
- default => sub { '' },
-);
-
-has latlong => (
- is => 'ro',
- isa => Tuple[ Num, Num ],
- default => sub { [0,0] },
- handles_via => 'Array',
- handles => {
- #lat => [ get => 0 ],
- #long => [ get => 1 ],
- }
-);
-
-sub lat { shift->latlong->[0] }
-sub long { shift->latlong->[1] }
-
-has media_url => (
- is => 'ro',
- isa => Str,
- default => sub { '' },
-);
-
-1;
diff --git a/perllib/Open311/Endpoint/Service/Request/Update.pm b/perllib/Open311/Endpoint/Service/Request/Update.pm
deleted file mode 100644
index b881af9ce..000000000
--- a/perllib/Open311/Endpoint/Service/Request/Update.pm
+++ /dev/null
@@ -1,57 +0,0 @@
-package Open311::Endpoint::Service::Request::Update;
-use Moo;
-use Types::Standard ':all';
-use namespace::clean;
-
-sub BUILDARGS {
- my ($class, %args) = @_;
- my $service_request = delete $args{service_request};
-
- if (! $args{status}) {
- $args{status} = $service_request->status;
- }
-
- return \%args;
-}
-
-has update_id => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has service_request_id => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has token => (
- is => 'ro',
- isa => Maybe[Str],
- predicate => 1,
-);
-
-has status => (
- is => 'ro',
- isa => Enum[qw/ open closed /],
-);
-
-has description => (
- is => 'ro',
- isa => Maybe[Str],
-);
-
-has media_url => (
- is => 'ro',
- isa => Str,
- default => sub { '' },
-);
-
-has updated_datetime => (
- is => 'ro',
- isa => InstanceOf['DateTime'],
- default => sub { DateTime->now() },
-);
-
-1;
diff --git a/perllib/Open311/Endpoint/Service/Request/mySociety.pm b/perllib/Open311/Endpoint/Service/Request/mySociety.pm
deleted file mode 100644
index 85e31b26f..000000000
--- a/perllib/Open311/Endpoint/Service/Request/mySociety.pm
+++ /dev/null
@@ -1,51 +0,0 @@
-package Open311::Endpoint::Service::Request::mySociety;
-use Moo;
-use MooX::HandlesVia;
-extends 'Open311::Endpoint::Service::Request';
-
-use DateTime;
-use Open311::Endpoint::Service::Request::Update;
-use Types::Standard ':all';
-
-has updates => (
- is => 'rw',
- isa => ArrayRef[InstanceOf['Open311::Endpoint::Service::Request::Update']],
- default => sub { [] },
- handles_via => 'Array',
- handles => {
- _add_update => 'push',
- get_updates => 'elements',
- get_update => 'get',
- has_updates => 'count',
- filter_updates => 'grep',
- }
-);
-
-sub add_update {
- my ($self, %args) = @_;
- my $update = Open311::Endpoint::Service::Request::Update->new(
- %args,
- service_request => $self,
- service_request_id => $self->service_request_id,
- );
- $self->_add_update($update);
-}
-
-sub last_update {
- my $self = shift;
- return $self->has_updates ? $self->get_update(-1) : undef;
-}
-
-around updated_datetime => sub {
- my ($orig, $self) = @_;
- my $last_update = $self->last_update or return;
- return $last_update->updated_datetime;
-};
-
-around status => sub {
- my ($orig, $self) = @_;
- my $last_update = $self->last_update or return 'open';
- return $last_update->status;
-};
-
-1;
diff --git a/perllib/Open311/Endpoint/Spark.pm b/perllib/Open311/Endpoint/Spark.pm
deleted file mode 100644
index 292a66996..000000000
--- a/perllib/Open311/Endpoint/Spark.pm
+++ /dev/null
@@ -1,117 +0,0 @@
-package Open311::Endpoint::Spark;
-use Moo;
-
-=head1 NAME
-
-Open311::Endpoint::Spark - transform from canonical data-structure to XML or JSON
-
-=head1 SUMMARY
-
-The Open311 docs discuss the Spark convention, to transform between XML and JSON.
-
- http://wiki.open311.org/JSON_and_XML_Conversion#The_Spark_Convention
-
-These options seem fragile, and require starting with the verbose XML form,
-which isn't really natural in Perl. Instead, we'll start with a standard
-Perl data structure, with a single extra hash wrapper, and will:
-
- * for JSON, remove the outside hash wrapper
-
- * for XML, for arrays, insert an extra layer with the singular name:
- (this is the way XML::Simple knows how to do this nesting)
-
-So:
-
- # FROM
- {
- foo => {
- bars => [ 1, 2, 3 ]
- }
- }
-
- # JSON (note the 'foo' has been removed
- {
- bars: [
- 1,
- 2,
- 3
- ]
- }
-
- # XML intermediate
- {
- foo => {
- bars => {
- bar => [ 1, 2, 3 ]
- }
- }
- }
-
- # XML result
- <foo>
- <bars>
- <bar>1</bar>
- <bar>2</bar>
- <bar>3</bar>
- </bars>
- </foo>
-
-=cut
-
-sub process_for_json {
- my ($self, $data) = @_;
- if (ref $data eq 'HASH' and scalar keys %$data == 1) {
- my $inner = $data->{ (keys %$data)[0] };
- $data = $inner if ref $inner;
- }
- return $data;
-}
-
-sub process_for_xml {
- my ($self, $data) = @_;
-
- # NB: in place mutation
- _process_for_xml($data);
- return $data;
-}
-
-# NB: in place mutation
-sub _process_for_xml {
- my $data = shift;
- return unless ref $data;
-
- if (ref $data eq 'HASH') {
- while ( my ($k, $v) = each %$data) {
- if (ref $v eq 'ARRAY') {
- my $singular = _singularize($k);
- # add extra layer
- $data->{$k} = {
- $singular => $v,
- };
- }
- _process_for_xml($v);
- }
- }
- elsif (ref $data eq 'ARRAY') {
- for my $item (@$data) {
- _process_for_xml($item);
- }
- }
-}
-
-my %singular_map = (
- service_requests => 'request',
- service_request_updates => 'request_update',
-);
-
-sub _singularize {
- my $name = shift;
- return $singular_map{ $name }
- || do {
- # strip final 's' if present
- $name =~ s/s$//;
- return $name;
- };
-}
-
-1;
diff --git a/t/open311/endpoint.t b/t/open311/endpoint.t
deleted file mode 100644
index a2a4ea83e..000000000
--- a/t/open311/endpoint.t
+++ /dev/null
@@ -1,351 +0,0 @@
-use strict; use warnings;
-
-use Test::More;
-use Test::LongString;
-use Test::MockTime ':all';
-
-use Open311::Endpoint;
-use Data::Dumper;
-use JSON::MaybeXS;
-
-use t::open311::endpoint::Endpoint1;
-
-my $endpoint = t::open311::endpoint::Endpoint1->new;
-
-subtest "GET Service List" => sub {
- my $res = $endpoint->run_test_request( GET => '/services.xml' );
- ok $res->is_success, 'xml success'
- or diag $res->content;
- is_string $res->content, <<CONTENT, 'xml string ok';
-<?xml version="1.0" encoding="utf-8"?>
-<services>
- <service>
- <description>Pothole Repairs Service</description>
- <group>highways</group>
- <keywords>deep,hole,wow</keywords>
- <metadata>true</metadata>
- <service_code>POT</service_code>
- <service_name>Pothole Repairs</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Bin Enforcement Service</description>
- <group>sanitation</group>
- <keywords>bin</keywords>
- <metadata>false</metadata>
- <service_code>BIN</service_code>
- <service_name>Bin Enforcement</service_name>
- <type>realtime</type>
- </service>
-</services>
-CONTENT
-
- $res = $endpoint->run_test_request( GET => '/services.json' );
- ok $res->is_success, 'json success';
- is_deeply decode_json($res->content),
- [ {
- "keywords" => "deep,hole,wow",
- "group" => "highways",
- "service_name" => "Pothole Repairs",
- "type" => "realtime",
- "metadata" => "true",
- "description" => "Pothole Repairs Service",
- "service_code" => "POT"
- }, {
- "keywords" => "bin",
- "group" => "sanitation",
- "service_name" => "Bin Enforcement",
- "type" => "realtime",
- "metadata" => "false",
- "description" => "Bin Enforcement Service",
- "service_code" => "BIN"
- } ], 'json structure ok';
-
-};
-
-subtest "GET Service Definition" => sub {
- my $res = $endpoint->run_test_request( GET => '/services/POT.xml' );
- ok $res->is_success, 'xml success',
- or diag $res->content;
- is_string $res->content, <<CONTENT, 'xml string ok';
-<?xml version="1.0" encoding="utf-8"?>
-<service_definition>
- <attributes>
- <attribute>
- <code>depth</code>
- <datatype>number</datatype>
- <datatype_description>an integer</datatype_description>
- <description>depth of pothole, in centimetres</description>
- <order>1</order>
- <required>true</required>
- <variable>true</variable>
- </attribute>
- <attribute>
- <code>shape</code>
- <datatype>singlevaluelist</datatype>
- <datatype_description>square | circle | triangle</datatype_description>
- <description>shape of the pothole</description>
- <order>2</order>
- <required>false</required>
- <values>
- <value>
- <name>Circle</name>
- <key>circle</key>
- </value>
- <value>
- <name>Square</name>
- <key>square</key>
- </value>
- <value>
- <name>Triangle</name>
- <key>triangle</key>
- </value>
- </values>
- <variable>true</variable>
- </attribute>
- </attributes>
- <service_code>POT</service_code>
-</service_definition>
-CONTENT
-
- $res = $endpoint->run_test_request( GET => '/services/POT.json' );
- ok $res->is_success, 'json success';
- is_deeply decode_json($res->content),
- {
- "service_code" => "POT",
- "attributes" => [
- {
- "order" => 1,
- "code" => "depth",
- "required" => "true",
- "variable" => "true",
- "datatype_description" => "an integer",
- "description" => "depth of pothole, in centimetres",
- "datatype" => "number",
- },
- {
- "order" => 2,
- "code" => "shape",
- "variable" => "true",
- "datatype_description" => "square | circle | triangle",
- "description" => "shape of the pothole",
- "required" => "false",
- "datatype" => "singlevaluelist",
- "values" => [
- {
- "name" => "Circle",
- "key" => "circle"
- },
- {
- "name" => "Square",
- "key" => "square"
- },
- {
- "name" => "Triangle",
- "key" => "triangle"
- },
- ],
- }
- ],
- }, 'json structure ok';
-};
-
-subtest "POST Service Request validation" => sub {
- my $res = $endpoint->run_test_request(
- POST => '/requests.json',
- );
- ok ! $res->is_success, 'no service_code';
-
- $res = $endpoint->run_test_request(
- POST => '/requests.json',
- service_code => 'BIN',
- );
- ok ! $res->is_success, 'no api_key';
-
- $res = $endpoint->run_test_request(
- POST => '/requests.json',
- api_key => 'test',
- service_code => 'BADGER', # has moved the goalposts
- );
- ok ! $res->is_success, 'bad service_code';
-
- $res = $endpoint->run_test_request(
- POST => '/requests.json',
- api_key => 'test',
- service_code => 'POT',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- );
- ok ! $res->is_success, 'no required attributes';
-
- $res = $endpoint->run_test_request(
- POST => '/requests.json',
- api_key => 'test',
- service_code => 'POT',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- 'attribute[depth]' => 100,
- 'attribute[shape]' => 'starfish',
- );
- ok ! $res->is_success, 'bad attribute';
-};
-
-subtest "POST Service Request valid test" => sub {
-
- set_fixed_time('2014-01-01T12:00:00Z');
- my $res = $endpoint->run_test_request(
- POST => '/requests.json',
- api_key => 'test',
- service_code => 'POT',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- 'attribute[depth]' => 100,
- 'attribute[shape]' => 'triangle',
- );
- ok $res->is_success, 'valid request'
- or diag $res->content;
-
- is_deeply decode_json($res->content),
- [ {
- "service_notice" => "This is a test service",
- "service_request_id" => 0
- } ], 'correct json returned';
-
- set_fixed_time('2014-02-01T12:00:00Z');
- $res = $endpoint->run_test_request(
- POST => '/requests.xml',
- api_key => 'test',
- service_code => 'POT',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- 'attribute[depth]' => 100,
- 'attribute[shape]' => 'triangle',
- );
-
- ok $res->is_success, 'valid request'
- or diag $res->content;
-
- is_string $res->content, <<CONTENT, 'xml string ok';
-<?xml version="1.0" encoding="utf-8"?>
-<service_requests>
- <request>
- <service_notice>This is a test service</service_notice>
- <service_request_id>1</service_request_id>
- </request>
-</service_requests>
-CONTENT
-};
-
-subtest "GET Service Requests" => sub {
-
- my $res = $endpoint->run_test_request( GET => '/requests.xml', );
- ok $res->is_success, 'valid request'
- or die $res->content;
- my $xml = <<CONTENT;
-<?xml version="1.0" encoding="utf-8"?>
-<service_requests>
- <request>
- <address>22 Acacia Avenue</address>
- <address_id></address_id>
- <lat>0</lat>
- <long>0</long>
- <media_url></media_url>
- <requested_datetime>2014-01-01T12:00:00Z</requested_datetime>
- <service_code>POT</service_code>
- <service_name>Pothole Repairs</service_name>
- <service_request_id>0</service_request_id>
- <status>open</status>
- <updated_datetime>2014-01-01T12:00:00Z</updated_datetime>
- <zipcode></zipcode>
- </request>
- <request>
- <address>22 Acacia Avenue</address>
- <address_id></address_id>
- <lat>0</lat>
- <long>0</long>
- <media_url></media_url>
- <requested_datetime>2014-02-01T12:00:00Z</requested_datetime>
- <service_code>POT</service_code>
- <service_name>Pothole Repairs</service_name>
- <service_request_id>1</service_request_id>
- <status>open</status>
- <updated_datetime>2014-02-01T12:00:00Z</updated_datetime>
- <zipcode></zipcode>
- </request>
-</service_requests>
-CONTENT
-
- is_string $res->content, $xml, 'xml string ok';
-
- $res = $endpoint->run_test_request( GET => '/requests.xml?service_code=POT', );
- ok $res->is_success, 'valid request';
-
- is_string $res->content, $xml, 'xml string ok POT'
- or diag $res->content;
-
- $res = $endpoint->run_test_request( GET => '/requests.xml?service_code=BIN', );
- ok $res->is_success, 'valid request';
- is_string $res->content, <<CONTENT, 'xml string ok BIN (no requests)';
-<?xml version="1.0" encoding="utf-8"?>
-<service_requests>
-</service_requests>
-CONTENT
-};
-
-subtest "GET Service Request" => sub {
- my @req=(<<REQ0,<<REQ1);
-<?xml version="1.0" encoding="utf-8"?>
-<service_requests>
- <request>
- <address>22 Acacia Avenue</address>
- <address_id></address_id>
- <lat>0</lat>
- <long>0</long>
- <media_url></media_url>
- <requested_datetime>2014-01-01T12:00:00Z</requested_datetime>
- <service_code>POT</service_code>
- <service_name>Pothole Repairs</service_name>
- <service_request_id>0</service_request_id>
- <status>open</status>
- <updated_datetime>2014-01-01T12:00:00Z</updated_datetime>
- <zipcode></zipcode>
- </request>
-</service_requests>
-REQ0
-<?xml version="1.0" encoding="utf-8"?>
-<service_requests>
- <request>
- <address>22 Acacia Avenue</address>
- <address_id></address_id>
- <lat>0</lat>
- <long>0</long>
- <media_url></media_url>
- <requested_datetime>2014-02-01T12:00:00Z</requested_datetime>
- <service_code>POT</service_code>
- <service_name>Pothole Repairs</service_name>
- <service_request_id>1</service_request_id>
- <status>open</status>
- <updated_datetime>2014-02-01T12:00:00Z</updated_datetime>
- <zipcode></zipcode>
- </request>
-</service_requests>
-REQ1
-
- my $res = $endpoint->run_test_request( GET => '/requests/0.xml', );
- ok $res->is_success, 'valid request';
-
- is_string $res->content, $req[0], 'Request 0 ok'
- or diag $res->content;;
-
- $res = $endpoint->run_test_request( GET => '/requests/1.xml', );
- ok $res->is_success, 'valid request';
-
- is_string $res->content, $req[1], 'Request 1 ok';
-};
-
-restore_time();
-done_testing;
diff --git a/t/open311/endpoint/Endpoint1.pm b/t/open311/endpoint/Endpoint1.pm
deleted file mode 100644
index ae12172b8..000000000
--- a/t/open311/endpoint/Endpoint1.pm
+++ /dev/null
@@ -1,114 +0,0 @@
-package t::open311::endpoint::Endpoint1;
-use Web::Simple;
-extends 'Open311::Endpoint';
-use Types::Standard ':all';
-use MooX::HandlesVia;
-
-use Open311::Endpoint::Service;
-use t::open311::endpoint::ServiceType1;
-use Open311::Endpoint::Service::Attribute;
-use Open311::Endpoint::Service::Request;
-
-sub services {
- return (
- t::open311::endpoint::ServiceType1->new(
- service_code => 'POT',
- service_name => 'Pothole Repairs',
- description => 'Pothole Repairs Service',
- attributes => [
- Open311::Endpoint::Service::Attribute->new(
- code => 'depth',
- required => 1,
- datatype => 'number',
- datatype_description => 'an integer',
- description => 'depth of pothole, in centimetres',
- ),
- Open311::Endpoint::Service::Attribute->new(
- code => 'shape',
- required => 0,
- datatype => 'singlevaluelist',
- datatype_description => 'square | circle | triangle',
- description => 'shape of the pothole',
- values => {
- square => 'Square',
- circle => 'Circle',
- triangle => 'Triangle',
- },
- ),
- ],
- type => 'realtime',
- keywords => [qw/ deep hole wow/],
- group => 'highways',
- ),
- t::open311::endpoint::ServiceType1->new(
- service_code => 'BIN',
- service_name => 'Bin Enforcement',
- description => 'Bin Enforcement Service',
- attributes => [],
- type => 'realtime',
- keywords => [qw/ bin /],
- group => 'sanitation',
- )
- );
-}
-
-# FOR TESTING, we'll just maintain requests in a *global* array...
-# obviously a real Service driver will use a DB or API call!
-{
- our @SERVICE_REQUESTS;
- has _requests => (
- is => 'ro',
- isa => ArrayRef[ InstanceOf[ 'Open311::Endpoint::Service::Request' ] ],
- default => sub { \@SERVICE_REQUESTS },
- handles_via => 'Array',
- handles => {
- next_request_id => 'count',
- _add_request => 'push',
- get_request => 'get',
- get_requests => 'elements',
- filter_requests => 'grep',
- }
- );
-}
-
-sub post_service_request {
- my ($self, $service, $args) = @_;
-
- my $request = $self->new_request(
-
- # NB: possible race condition between next_request_id and _add_request
- # (this is fine for synchronous test-cases)
-
- service => $service,
- service_request_id => $self->next_request_id,
- status => 'open',
- description => $args->{description},
- agency_responsible => '',
- requested_datetime => DateTime->now(),
- updated_datetime => DateTime->now(),
- address => $args->{address_string} // '',
- address_id => $args->{address_id} // '',
- media_url => $args->{media_url} // '',
- zipcode => $args->{zipcode} // '',
- # NB: other info is passed in that would be stored by an Open311
- # endpoint, see Open311::Endpoint::Service::Request for full list,
- # but we don't need to handle all of those in this test
- );
- $self->_add_request( $request );
-
- return ( $request );
-}
-
-sub get_service_requests {
- my ($self, $args) = @_;
-
- my $service_code = $args->{service_code} or return $self->get_requests;
- return $self->filter_requests( sub { my $c = shift->service->service_code; grep { $_ eq $c } @$service_code });
-}
-
-sub get_service_request {
- my ($self, $service_request_id, $args) = @_;
- return $self->get_request( $service_request_id );
-}
-
-1;
diff --git a/t/open311/endpoint/Endpoint2.pm b/t/open311/endpoint/Endpoint2.pm
deleted file mode 100644
index 664a7f3d6..000000000
--- a/t/open311/endpoint/Endpoint2.pm
+++ /dev/null
@@ -1,25 +0,0 @@
-package t::open311::endpoint::Endpoint2;
-use Web::Simple;
-extends 't::open311::endpoint::Endpoint1';
-with 'Open311::Endpoint::Role::mySociety';
-
-sub get_service_request_updates {
- my ($self, $args) = @_;
-
- my $start_date = $self->maybe_inflate_datetime($args->{start_date});
- my $end_date = $self->maybe_inflate_datetime($args->{end_date});
-
- my @requests = $self->filter_requests( sub { $_[0]->has_updates } );
-
- return map {
- $_->filter_updates( sub {
- my $update = shift;
- my $updated_datetime = $update->updated_datetime or return;
- if ($start_date) { return unless $updated_datetime >= $start_date }
- if ($end_date) { return unless $updated_datetime <= $end_date }
- return 1;
- });
- } @requests;
-}
-
-1;
diff --git a/t/open311/endpoint/Endpoint_Warwick.pm b/t/open311/endpoint/Endpoint_Warwick.pm
deleted file mode 100644
index c097f177e..000000000
--- a/t/open311/endpoint/Endpoint_Warwick.pm
+++ /dev/null
@@ -1,31 +0,0 @@
-package t::open311::endpoint::Endpoint_Warwick;
-use Web::Simple;
-
-our %BINDINGS;
-our $UPDATES_SQL;
-
-extends 'Open311::Endpoint::Integration::Warwick';
-
-sub insert_into_db {
- my ($self, $bindings) = @_;
-
- %BINDINGS = %$bindings;
- # return ($pem_id, $error_value, $error_product);
- return (1001);
-}
-
-sub get_updates_from_sql {
- my ($self, $sql) = @_;
- $UPDATES_SQL = $sql;
- return (
- {
- row_id => 999,
- service_request_id => 1001,
- updated_datetime => '2014-07-23 11:07:00',
- status => 'closed',
- description => 'Closed the ticket',
- }
- );
-}
-
-1;
diff --git a/t/open311/endpoint/ServiceType1.pm b/t/open311/endpoint/ServiceType1.pm
deleted file mode 100644
index e35e44fda..000000000
--- a/t/open311/endpoint/ServiceType1.pm
+++ /dev/null
@@ -1,10 +0,0 @@
-package t::open311::endpoint::ServiceType1;
-use Moo;
-extends 'Open311::Endpoint::Service';
-use DateTime;
-
-has '+default_service_notice' => (
- default => 'This is a test service',
-);
-
-1;
diff --git a/t/open311/endpoint/config1.yml b/t/open311/endpoint/config1.yml
deleted file mode 100644
index c444f32c5..000000000
--- a/t/open311/endpoint/config1.yml
+++ /dev/null
@@ -1 +0,0 @@
-foo: baz
diff --git a/t/open311/endpoint/configfile.t b/t/open311/endpoint/configfile.t
deleted file mode 100644
index 7f41468ba..000000000
--- a/t/open311/endpoint/configfile.t
+++ /dev/null
@@ -1,23 +0,0 @@
-use strict; use warnings;
-
-BEGIN {
- package Foo;
- use Moo;
- with 'Open311::Endpoint::Role::ConfigFile';
-
- has foo => ( is => 'ro', default => 'foo' );
-}
-
-package main;
-use Test::More;
-
-is +Foo->new->foo,
- 'foo', 'sanity';
-is +Foo->new( foo => 'bar')->foo,
- 'bar', 'override';
-is +Foo->new( config_file => 't/open311/endpoint/config1.yml' )->foo,
- 'baz', 'with config';
-is +Foo->new( config_file => 't/open311/endpoint/config1.yml', foo => 'qux' )->foo,
- 'qux', 'with config, overridden';
-
-done_testing;
diff --git a/t/open311/endpoint/exor/DBD/Oracle.pm b/t/open311/endpoint/exor/DBD/Oracle.pm
deleted file mode 100644
index d84580d10..000000000
--- a/t/open311/endpoint/exor/DBD/Oracle.pm
+++ /dev/null
@@ -1,8 +0,0 @@
-package DBD::Oracle; # test
-use strict; use warnings;
-
-sub ORA_DATE () { 2 };
-sub ORA_NUMBER () { 3 } ;
-sub ORA_VARCHAR2 () { 5 };
-
-1;
diff --git a/t/open311/endpoint/mysociety.t b/t/open311/endpoint/mysociety.t
deleted file mode 100644
index d0ad60602..000000000
--- a/t/open311/endpoint/mysociety.t
+++ /dev/null
@@ -1,160 +0,0 @@
-use strict; use warnings;
-
-use Test::More;
-use Test::LongString;
-use Test::MockTime ':all';
-
-use Open311::Endpoint;
-use Data::Dumper;
-use JSON::MaybeXS;
-
-use t::open311::endpoint::Endpoint2;
-
-my $endpoint = t::open311::endpoint::Endpoint2->new;
-
-subtest "POST OK" => sub {
- diag "Serves as sanity test of subclassing, as well as preparing our data";
- # TODO, refactor repeated code lifted from t/open311/endpoint.t
-
- set_fixed_time('2014-01-01T12:00:00Z');
- my $res = $endpoint->run_test_request(
- POST => '/requests.json',
- api_key => 'test',
- service_code => 'POT',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- 'attribute[depth]' => 100,
- 'attribute[shape]' => 'triangle',
- );
- ok $res->is_success, 'valid request'
- or diag $res->content;
-
- is_deeply decode_json($res->content),
- [ {
- "service_notice" => "This is a test service",
- "service_request_id" => 0
- } ], 'correct json returned';
-
- set_fixed_time('2014-02-01T12:00:00Z');
- $res = $endpoint->run_test_request(
- POST => '/requests.xml',
- api_key => 'test',
- service_code => 'POT',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- 'attribute[depth]' => 100,
- 'attribute[shape]' => 'triangle',
- );
-
- ok $res->is_success, 'valid request'
- or diag $res->content;
-};
-
-subtest "GET Service Request Updates" => sub {
-
- my $empty_xml = <<CONTENT;
-<?xml version="1.0" encoding="utf-8"?>
-<service_request_updates>
-</service_request_updates>
-CONTENT
-
- my $update_0_xml = <<CONTENT;
-<?xml version="1.0" encoding="utf-8"?>
-<service_request_updates>
- <request_update>
- <description>Fixed</description>
- <media_url></media_url>
- <service_request_id>0</service_request_id>
- <status>closed</status>
- <update_id>1</update_id>
- <updated_datetime>2014-01-01T13:00:00Z</updated_datetime>
- </request_update>
-</service_request_updates>
-CONTENT
-
-my $updates_xml = <<CONTENT;
-<?xml version="1.0" encoding="utf-8"?>
-<service_request_updates>
- <request_update>
- <description>Fixed</description>
- <media_url></media_url>
- <service_request_id>0</service_request_id>
- <status>closed</status>
- <update_id>1</update_id>
- <updated_datetime>2014-01-01T13:00:00Z</updated_datetime>
- </request_update>
- <request_update>
- <description>Have investigated. Looks tricky!</description>
- <media_url></media_url>
- <service_request_id>1</service_request_id>
- <status>open</status>
- <update_id>2</update_id>
- <updated_datetime>2014-03-01T13:00:00Z</updated_datetime>
- </request_update>
-</service_request_updates>
-CONTENT
-
- subtest 'No updates' => sub {
- my $res = $endpoint->run_test_request( GET => '/servicerequestupdates.xml', );
- ok $res->is_success, 'valid request' or diag $res->content;
-
- is_string $res->content, $empty_xml, 'xml string ok'
- or diag $res->content;
- };
-
- subtest 'Updated 1 ticket' => sub {
- # an agent updates the first ticket
- set_fixed_time('2014-01-01T13:00:00Z');
- my $request = $endpoint->get_request(0);
- $request->add_update(
- update_id => 1,
- status => 'closed',
- description => 'Fixed',
- );
-
- is $request->status, 'closed', 'Status updated';
-
- my $before='2014-01-01T12:00:00Z';
- my $after ='2014-01-01T14:00:00Z';
-
- for my $scenario (
- [ '', $update_0_xml, 'Basic test', ],
- [ "?start_date=$before", $update_0_xml, 'start date' ],
- [ "?end_date=$after", $update_0_xml, 'end_date' ],
- [ "?start_date=$before&end_date=$after", $update_0_xml, 'both dates' ],
- [ "?start_date=$after", $empty_xml, 'Not found if start date after update' ],
- [ "?end_date=$before", $empty_xml, 'Not found if end date before update' ]
- ) {
- my ($query, $xml, $description) = @$scenario;
-
- my $res = $endpoint->run_test_request( GET => '/servicerequestupdates.xml' . $query, );
- ok $res->is_success, 'valid request' or diag $res->content;
- is_string $res->content, $xml, $description;
- }
- };
-
- subtest 'Updated another ticket' => sub {
- set_fixed_time('2014-03-01T13:00:00Z');
- my $request = $endpoint->get_request(1);
- $request->add_update(
- update_id => 2,
- description => 'Have investigated. Looks tricky!',
- );
-
- for my $scenario (
- [ '', $updates_xml, 'Both reports', ],
- [ "?end_date=2014-01-01T14:00:00Z", $update_0_xml, 'end_date before second update' ],
- ) {
- my ($query, $xml, $description) = @$scenario;
-
- my $res = $endpoint->run_test_request( GET => '/servicerequestupdates.xml' . $query, );
- ok $res->is_success, 'valid request' or diag $res->content;
- is_string $res->content, $xml, $description or diag $res->content;
- }
- };
-};
-
-restore_time();
-done_testing;
diff --git a/t/open311/endpoint/schema.t b/t/open311/endpoint/schema.t
deleted file mode 100644
index b669ca4a5..000000000
--- a/t/open311/endpoint/schema.t
+++ /dev/null
@@ -1,82 +0,0 @@
-use strict; use warnings;
-
-use Test::More;
-use Test::Exception;
-
-use Data::Rx;
-use Open311::Endpoint;
-
-my $endpoint = Open311::Endpoint->new;
-my $schema = $endpoint->rx;
-
-subtest 'comma tests' => sub {
-
- dies_ok {
- my $comma = $schema->make_schema({
- type => '/open311/comma',
- });
- } 'Construction dies on no contents';
-
- dies_ok {
- my $comma = $schema->make_schema({
- type => '/open311/comma',
- contents => '/open311/status',
- zirble => 'fleem',
- });
- } 'Construction dies on extra arguments';
-
- my $comma = $schema->make_schema({
- type => '/open311/comma',
- contents => '/open311/status',
- trim => 1,
- });
-
- ok ! $comma->check( undef ), 'Undef is not a valid string';
- ok ! $comma->check( [] ), 'Reference is not a valid string';
-
- ok ! $comma->check( 'zibble' ), 'invalid string';
- ok ! $comma->check( 'open,zibble' ), 'an invalid element';
-
- ok $comma->check( 'open' ), 'single value';
- ok $comma->check( 'open,closed' ), 'multiple values ok';
- ok $comma->check( 'open, closed ' ), 'spaces trimmed ok';
-};
-
-subtest 'datetime tests' => sub {
-
- dies_ok {
- my $comma = $schema->make_schema({
- type => '/open311/datetime',
- zirble => 'fleem',
- });
- } 'Construction dies on extra keys';
-
- my $dt = $schema->make_schema({
- type => '/open311/datetime',
- });
-
- ok ! $dt->check( undef ), 'Undef is not a valid string';
- ok ! $dt->check( [] ), 'Reference is not a valid string';
-
- ok ! $dt->check( '9th Feb 2012' ), 'invalid datetime format';
-
- ok $dt->check( '1994-11-05T08:15:30-05:00' ), 'datetime format with offset';
- ok $dt->check( '1994-11-05T08:15:30+05:00' ), 'datetime format with positive';
- ok $dt->check( '1994-11-05T13:15:30Z' ), 'datetime format zulu';
-};
-
-subtest 'identifier tests' => sub {
- my $id = $schema->make_schema( '/open311/example/identifier' );
-
- ok ! $id->check( undef ), 'Undef is not a valid string';
- ok ! $id->check( '' ), 'Empty string is not a valid identifier';
- ok ! $id->check( 'foo bar' ), 'String with spaces is not a valid identifier';
-
- ok $id->check( 'foo' ), 'Ascii word string is a valid identifier';
- ok $id->check( 'foo_bar' ), 'Ascii word string is a valid identifier';
- ok $id->check( 'foo_123' ), 'Ascii word/num string is a valid identifier';
-};
-
-done_testing;
-
-1;
diff --git a/t/open311/endpoint/spark.t b/t/open311/endpoint/spark.t
deleted file mode 100644
index 015876c94..000000000
--- a/t/open311/endpoint/spark.t
+++ /dev/null
@@ -1,62 +0,0 @@
-use strict; use warnings;
-
-use Test::More;
-
-use Open311::Endpoint;
-use Data::Dumper;
-
-my $endpoint = Open311::Endpoint->new;
-
-subtest "Spark test" => sub {
- my $spark = $endpoint->spark;
- my $struct = {
- foo => {
- service_requests => [ 1,2,3 ],
- quxes => [
- {
- values => [1,2],
- },
- {
- values => [3,4],
- },
- ],
- },
- };
- is_deeply $spark->process_for_json($struct),
- {
- service_requests => [ 1,2,3 ],
- quxes => [
- {
- values => [1,2],
- },
- {
- values => [3,4],
- },
- ],
- };
-
- my $xml_struct = $spark->process_for_xml($struct);
- is_deeply $xml_struct,
- {
- foo => {
- service_requests => { request => [ 1,2,3 ] },
- quxes => {
- quxe => [
- {
- values => {
- value => [1,2],
- },
- },
- {
- values => {
- value => [3,4],
- },
- },
- ]
- },
- }
- }
- or warn Dumper($xml_struct);
-};
-
-done_testing;
diff --git a/t/open311/endpoint/warwick.t b/t/open311/endpoint/warwick.t
deleted file mode 100644
index e5f124c8d..000000000
--- a/t/open311/endpoint/warwick.t
+++ /dev/null
@@ -1,443 +0,0 @@
-use strict; use warnings;
-
-use Test::More;
-use Test::LongString;
-use Test::MockTime ':all';
-
-use Data::Dumper;
-use JSON::MaybeXS;
-
-use FixMyStreet::DB;
-
-use Module::Loaded;
-BEGIN { mark_as_loaded('DBD::Oracle') }
-
-use t::open311::endpoint::Endpoint_Warwick;
-
-use LWP::Protocol::PSGI;
-use Open311::PopulateServiceList;
-use Open311::GetServiceRequestUpdates;
-
-my $endpoint = t::open311::endpoint::Endpoint_Warwick->new;
-
-subtest "GET Service List" => sub {
- my $res = $endpoint->run_test_request( GET => '/services.xml' );
- ok $res->is_success, 'xml success';
- my $expected = <<XML;
-<?xml version="1.0" encoding="utf-8"?>
-<services>
- <service>
- <description>Pothole</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>PO</service_code>
- <service_name>Pothole</service_name>
- <type>realtime</type>
- </service>
-</services>
-XML
- is $res->content, $expected
- or diag $res->content;
-};
-
-subtest "POST OK" => sub {
- set_fixed_time('2014-01-01T12:00:00Z');
- my $res = $endpoint->run_test_request(
- POST => '/requests.json',
- api_key => 'test',
- service_code => 'PO',
- address_string => '22 Acacia Avenue',
- first_name => 'Bob',
- last_name => 'Mould',
- 'attribute[easting]' => 100,
- 'attribute[northing]' => 100,
- 'attribute[external_id]' => 1001,
- 'attribute[closest_address]' => '22 Acacia Avenue',
- );
- ok $res->is_success, 'valid request'
- or diag $res->content;
-
- is_deeply decode_json($res->content),
- [ {
- "service_notice" => "Warwickshire Open311 Endpoint",
- "service_request_id" => 1001
- } ], 'correct json returned';
-
- is_deeply \%t::open311::endpoint::Endpoint_Warwick::BINDINGS,
- {
- ':ce_surname' => 'MOULD',
- ':ce_y' => '100',
- ':ce_x' => '100',
- ':ce_work_phone' => '',
- ':ce_contact_type' => 'PU',
- ':ce_source' => 'FMS',
- ':ce_doc_reference' => '1001',
- ':ce_enquiry_type' => 'PO',
- ':ce_email' => '',
- ':ce_description' => '',
- ':ce_location' => '22 Acacia Avenue',
- ':ce_incident_datetime' => '2014-01-01 12:00',
- ':ce_class' => 'N/A',
- ':ce_cpr_id' => 5,
- ':ce_compl_user_type' => 'USER',
- ':ce_status_code' => 'RE',
- ':ce_cat' => 'DEF',
- ':ce_forename' => 'BOB'
- },
- 'bindings as expected';
-};
-
-subtest 'updates' => sub {
- my $res = $endpoint->run_test_request( GET => '/servicerequestupdates.xml', );
- ok $res->is_success, 'valid request' or diag $res->content;
-
-my $expected = <<XML;
-<?xml version="1.0" encoding="utf-8"?>
-<service_request_updates>
- <request_update>
- <description>Closed the ticket</description>
- <media_url></media_url>
- <service_request_id>1001</service_request_id>
- <status>closed</status>
- <update_id>999</update_id>
- <updated_datetime>2014-07-23T11:07:00+01:00</updated_datetime>
- </request_update>
-</service_request_updates>
-XML
-
- is_string $res->content, $expected, 'xml string ok'
- or diag $res->content;
-
- chomp (my $expected_sql = <<SQL);
-SELECT * FROM (
- SELECT
- row_id,
- service_request_id,
- to_char(updated_timedate, 'YYYY-MM-DD HH24:MI'),
- status,
- description
- FROM higatlas.fms_update
- WHERE updated_timedate >= to_date(2013-12-31 12:00, YYYY-MM-DD HH24:MI) AND (status='OPEN' OR status='CLOSED')
- ORDER BY updated_timedate DESC) WHERE ROWNUM <= 1000
-SQL
-
- is_string $t::open311::endpoint::Endpoint_Warwick::UPDATES_SQL, $expected_sql, 'SQL as expected';
-};
-
-subtest "End to end" => sub {
-
- # We create and instance of the endpoint as a PSGI app
- # And then bind it to the dummy URL. This mocks that whole hostname, so that FMS's
- # calls via Open311.pm are rerouted to our PSGI app.
- # (This saves us all the faff of having to launch and manage a new server process
- # for this test)
-
- my $endpoint_psgi = t::open311::endpoint::Endpoint_Warwick->run_if_script;
-
- my $ENDPOINT = 'open311.warwickshire.gov.uk';
- LWP::Protocol::PSGI->register($endpoint_psgi, host => $ENDPOINT);
-
- my $WARWICKSHIRE_MAPIT_ID = 2243;
-
- my $db = FixMyStreet::DB->connect;
-
- $db->txn_begin;
-
- my $body = FixMyStreet::DB->resultset('Body')->find_or_create( {
- id => $WARWICKSHIRE_MAPIT_ID,
- name => 'Warwickshire County Council',
- });
-
- my $user = FixMyStreet::DB->resultset('User')
- ->find_or_create( { email => 'test@example.com', name => 'Test User' } );
-
- $body->update({
- jurisdiction => 'wcc',
- endpoint => "http://$ENDPOINT",
- api_key => 'SEEKRIT',
- send_method => 'Open311',
- send_comments => 1,
- comment_user_id => $user->id,
- });
-
- $body->body_areas->find_or_create({
- area_id => $WARWICKSHIRE_MAPIT_ID
- } );
-
- subtest "Populate service list" => sub {
- # as per bin/open311-populate-service-list
-
- $body->contacts->delete;
-
- is $body->contacts->count, 0, 'sanity check';
-
- my $bodies = self_rs($body);
-
- my $p = Open311::PopulateServiceList->new( bodies => $bodies, verbose => 0, schema => $db );
- $p->process_bodies;
-
- is $body->contacts->count, 1, 'Categories imported from Open311';
- };
-
- set_fixed_time('2014-07-20T15:05:00Z');
-
- my $problem = FixMyStreet::DB->resultset('Problem')->create({
- postcode => 'WC1 1AA',
- bodies_str => $WARWICKSHIRE_MAPIT_ID,
- areas => ",$WARWICKSHIRE_MAPIT_ID,",
- category => 'Pothole',
- title => 'Testing',
- detail => 'Testing Detail',
- used_map => 1,
- name => 'Joe Bloggs',
- anonymous => 0,
- state => 'confirmed',
- confirmed => '2014-07-20 15:00:00',
- lastupdate => '2014-07-20 15:00:00',
- lang => 'en-gb',
- service => '',
- cobrand => 'fixmystreet', # e.g. UK
- cobrand_data => '',
- send_questionnaire => 0,
- latitude => '52.2804',
- longitude => '-1.5897',
- user_id => $user->id,
- });
-
- subtest "Send report" => sub {
- # as per bin/send-reports
-
- FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'fixmystreet' ],
- SEND_REPORTS_ON_STAGING => 1,
- MAPIT_URL => 'http://mapit.mysociety.org/',
- }, sub {
- ## we can't (yet) just do following due to
- ## https://github.com/mysociety/fixmystreet/issues/893
- # self_rs($problem)->send_reports;
-
- ## instead, as we are in a transaction, we'll just delete everything else.
- my $rs = FixMyStreet::DB->resultset('Problem');
- $rs->search({ id => { '!=', $problem->id } })->delete;
- $rs->send_reports;
- };
- $problem->discard_changes;
-
- # Our test endpoint returns a hardcoded external ID.
- ok $problem->whensent, 'whensent has been set';
- is $problem->external_id, 1001, 'External ID set correctly'
- or die;
- };
-
- subtest "Send update" => sub {
- # as per bin/send-reports
-
- $problem->update({ lastupdate => '2014-07-20 15:05:00' }); # override
-
- set_fixed_time('2014-07-23T11:07:00Z');
-
- is $problem->comments->count, 0, 'sanity check update count';
- is $problem->state, 'confirmed', 'sanity check status';
-
-
- my $updates = Open311::GetServiceRequestUpdates->new( verbose => 1, schema => $db );
- $updates->fetch;
-
- $problem->discard_changes;
- is $problem->comments->count, 1, 'comment has been added';
-
-
- my $update = $problem->comments->single;
- is $update->user_id, $user->id, 'update user correct';
- is $update->state, 'confirmed', 'update itself is confirmed';
-
- is $update->problem_state, 'fixed - council', 'update marked problem as closed';
- is $problem->state, 'fixed - council', 'has been closed';
- };
-
- $db->txn_rollback;
-};
-
-restore_time();
-done_testing;
-
-sub self_rs {
- my ($row) = @_;
- # create a result-set with just this body (see also DBIx::Class::Helper::Row::SelfResultSet)
- return $row->result_source->resultset->search( $row->ident_condition );
-}
-
-__END__
- <service>
- <description>Bridges</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>BR</service_code>
- <service_name>Bridges</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Carriageway Defect</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>CD</service_code>
- <service_name>Carriageway Defect</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Roads/Highways</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>CD</service_code>
- <service_name>Roads/Highways</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Drainage</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>DR</service_code>
- <service_name>Drainage</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Debris/Spillage</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>DS</service_code>
- <service_name>Debris/Spillage</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Fences</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>FE</service_code>
- <service_name>Fences</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Pavements</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>F D</service_code>
- <service_name>Pavements</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Gully &amp; Catchpits</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>GC</service_code>
- <service_name>Gully &amp; Catchpits</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Ice/Snow</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>IS</service_code>
- <service_name>Ice/Snow</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Mud &amp; Debris</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>MD</service_code>
- <service_name>Mud &amp; Debris</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Manhole</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>MH</service_code>
- <service_name>Manhole</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Oil Spillage</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>OS</service_code>
- <service_name>Oil Spillage</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Other</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>OT</service_code>
- <service_name>Other</service_name>
- <type>realtime</type>
- </service>
-
- <service>
- <description>Property Damage</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>PD</service_code>
- <service_name>Property Damage</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Road Marking</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>RM</service_code>
- <service_name>Road Marking</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Road traffic signs</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>SN</service_code>
- <service_name>Road traffic signs</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Traffic</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>SP</service_code>
- <service_name>Traffic</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Utilities</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>UT</service_code>
- <service_name>Utilities</service_name>
- <type>realtime</type>
- </service>
- <service>
- <description>Vegetation</description>
- <group>highways</group>
- <keywords></keywords>
- <metadata>true</metadata>
- <service_code>VG</service_code>
- <service_name>Vegetation</service_name>
- <type>realtime</type>
- </service>
diff --git a/t/open311/endpoint/warwick_dbd.t b/t/open311/endpoint/warwick_dbd.t
deleted file mode 100644
index 9120c6467..000000000
--- a/t/open311/endpoint/warwick_dbd.t
+++ /dev/null
@@ -1,17 +0,0 @@
-use strict; use warnings;
-
-=head1 NAME
-
-warwick_dbd.t - test that Oracle constants can be imported if present
-
-=cut
-
-use Test::More;
-
-use lib 't/open311/endpoint/exor/';
-
-use DBD::Oracle; # fake from above test lib (or real if installed)
-use t::open311::endpoint::Endpoint_Warwick;
-
-ok 1;
-done_testing;