aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cypress/cypress.json2
-rw-r--r--.cypress/cypress/fixtures/roads.xml47
-rw-r--r--.cypress/cypress/integration/buckinghamshire.js33
-rw-r--r--.cypress/cypress/integration/northamptonshire.js13
-rw-r--r--CHANGELOG.md2
-rwxr-xr-xbin/browser-tests4
-rwxr-xr-xbin/fixmystreet.com/fixture50
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm16
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact/Enquiry.pm119
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm4
-rw-r--r--perllib/FixMyStreet/App/Model/PhotoSet.pm19
-rw-r--r--perllib/FixMyStreet/Cobrand/Hounslow.pm52
-rw-r--r--perllib/FixMyStreet/Cobrand/Lincolnshire.pm2
-rw-r--r--perllib/FixMyStreet/Map/Buckinghamshire.pm5
-rw-r--r--perllib/FixMyStreet/Map/Lincolnshire.pm21
-rw-r--r--perllib/FixMyStreet/PhotoStorage.pm28
-rw-r--r--perllib/FixMyStreet/SendReport/Open311.pm1
-rw-r--r--perllib/Open311.pm70
-rw-r--r--t/Mock/MapIt.pm2
-rw-r--r--t/app/controller/contact.t31
-rw-r--r--t/app/controller/contact_enquiry.t226
-rw-r--r--t/app/controller/report_new.t15
-rw-r--r--t/app/controller/sample.pdfbin0 -> 12501 bytes
-rw-r--r--t/cobrand/hounslow.t44
-rw-r--r--t/map/tests.t2
-rw-r--r--templates/email/hounslow/archive.html55
-rw-r--r--templates/email/hounslow/archive.txt27
-rw-r--r--templates/web/base/contact/enquiry/index.html79
-rw-r--r--templates/web/base/contact/enquiry/submit.html1
-rw-r--r--templates/web/buckinghamshire/footer_extra_js.html11
-rw-r--r--templates/web/hounslow/main_nav_items.html58
-rw-r--r--templates/web/lincolnshire/footer_extra_js.html11
32 files changed, 986 insertions, 64 deletions
diff --git a/.cypress/cypress.json b/.cypress/cypress.json
index d7d2ec3d7..8d25b96b6 100644
--- a/.cypress/cypress.json
+++ b/.cypress/cypress.json
@@ -1,7 +1,7 @@
{
"baseUrl": "http://fixmystreet.localhost:3001",
"projectId": "y8vvs1",
- "blacklistHosts": ["gaze.mysociety.org", "*.openstreetmap.org", "tilma.mysociety.org"],
+ "blacklistHosts": ["gaze.mysociety.org", "*.openstreetmap.org", "portal.roadworks.org", "tilma.mysociety.org"],
"env": {
"postcode": "BS10 5EE"
},
diff --git a/.cypress/cypress/fixtures/roads.xml b/.cypress/cypress/fixtures/roads.xml
new file mode 100644
index 000000000..fc3bce1bf
--- /dev/null
+++ b/.cypress/cypress/fixtures/roads.xml
@@ -0,0 +1,47 @@
+<?xml version='1.0' encoding="UTF-8" ?>
+<wfs:FeatureCollection
+ xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
+ xmlns:gml="http://www.opengis.net/gml"
+ xmlns:wfs="http://www.opengis.net/wfs"
+ xmlns:ogc="http://www.opengis.net/ogc"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver https://tilma.mysociety.org:80/mapserver/bucks?SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=Whole_Street&amp;OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
+ <gml:boundedBy>
+ <gml:Envelope srsName="EPSG:27700">
+ <gml:lowerCorner>499000.030000 189992.860000</gml:lowerCorner>
+ <gml:upperCorner>501833.770000 193639.230000</gml:upperCorner>
+ </gml:Envelope>
+ </gml:boundedBy>
+ <gml:featureMember>
+ <ms:Whole_Street gml:id="Whole_Street.HWSA7300268">
+ <gml:boundedBy>
+ <gml:Envelope srsName="EPSG:27700">
+ <gml:lowerCorner>499991.980000 191715.960000</gml:lowerCorner>
+ <gml:upperCorner>500040.010000 191858.080000</gml:upperCorner>
+ </gml:Envelope>
+ </gml:boundedBy>
+ <ms:msGeometry>
+ <gml:MultiCurve srsName="EPSG:27700">
+ <gml:curveMember>
+ <gml:LineString>
+ <gml:posList srsDimension="2">499991.980000 191715.960000 500000.000000 191720.020000 500004.960000 191721.000000 500008.960000 191721.970000 500019.990000 191724.970000 500028.010000 191729.030000 500032.990000 191733.020000 500035.030000 191734.950000 500039.020000 191743.030000 500039.990000 191746.950000 500040.000000 191749.950000 500040.010000 191755.960000 500035.180000 191772.660000 </gml:posList>
+ </gml:LineString>
+ </gml:curveMember>
+ <gml:curveMember>
+ <gml:LineString>
+ <gml:posList srsDimension="2">500035.180000 191772.660000 500025.070000 191769.020000 </gml:posList>
+ </gml:LineString>
+ </gml:curveMember>
+ <gml:curveMember>
+ <gml:LineString>
+ <gml:posList srsDimension="2">500035.180000 191772.660000 500027.000000 191800.990000 500019.980000 191819.980000 500008.590000 191849.680000 500005.380000 191858.080000 </gml:posList>
+ </gml:LineString>
+ </gml:curveMember>
+ </gml:MultiCurve>
+ </ms:msGeometry>
+ <ms:site_code>7300268</ms:site_code>
+ <ms:feature_ty>4B</ms:feature_ty>
+ </ms:Whole_Street>
+ </gml:featureMember>
+</wfs:FeatureCollection>
+
diff --git a/.cypress/cypress/integration/buckinghamshire.js b/.cypress/cypress/integration/buckinghamshire.js
new file mode 100644
index 000000000..92426e0d4
--- /dev/null
+++ b/.cypress/cypress/integration/buckinghamshire.js
@@ -0,0 +1,33 @@
+describe('flytipping', function() {
+
+ beforeEach(function() {
+ cy.server();
+ cy.fixture('roads.xml');
+ cy.route('**mapserver/bucks*Whole_Street*', 'fixture:roads.xml').as('roads-layer');
+ cy.route('/report/new/ajax*').as('report-ajax');
+ cy.visit('http://buckinghamshire.localhost:3001/');
+ cy.contains('Buckinghamshire');
+ cy.get('[name=pc]').type('SL9 0NX');
+ cy.get('[name=pc]').parents('form').submit();
+ });
+
+ it('handles flytipping on a road correctly', function() {
+ cy.get('.olMapViewport #fms_pan_zoom_zoomin').click();
+ cy.wait('@roads-layer');
+ cy.get('#map_box').click(290, 307);
+ cy.wait('@report-ajax');
+ cy.get('select:eq(4)').select('Flytipping');
+ cy.get('#form_road-placement').select('off-road');
+ cy.contains('sent to Chiltern District Council and also');
+ cy.get('#form_road-placement').select('road');
+ cy.contains('sent to Buckinghamshire County Council and also');
+ });
+
+ it('handles flytipping off a road correctly', function() {
+ cy.get('#map_box').click(200, 307);
+ cy.wait('@report-ajax');
+ cy.get('select:eq(4)').select('Flytipping');
+ cy.contains('sent to Chiltern District Council and also');
+ });
+
+});
diff --git a/.cypress/cypress/integration/northamptonshire.js b/.cypress/cypress/integration/northamptonshire.js
index c3a548843..dc683e4e6 100644
--- a/.cypress/cypress/integration/northamptonshire.js
+++ b/.cypress/cypress/integration/northamptonshire.js
@@ -70,3 +70,16 @@ it('detects multiple assets at same location', function() {
cy.contains('more than one tree at this location');
});
+
+it('shows the emergency message', function() {
+ cy.server();
+ cy.route('/report/new/ajax*').as('report-ajax');
+ cy.visit('http://northamptonshire.localhost:3001/');
+ cy.get('[name=pc]').type('NN1 2NS');
+ cy.get('[name=pc]').parents('form').submit();
+ cy.get('#map_box').click();
+ cy.wait('@report-ajax');
+ cy.get('[id=category_group]').select('Very Urgent');
+ cy.contains('Please call us instead, it is very urgent.');
+ cy.get('#form_title').should('not.be.visible');
+});
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7052ebc36..b18762648 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@
reports made in that category private.
- Ensure any reports fetched in a category marked private are also
marked private on the site.
+ - Add new upload_files flag which sends files/photos as part of the
+ POST service request.
* v2.6 (3rd May 2019)
- New features:
diff --git a/bin/browser-tests b/bin/browser-tests
index 6950c651d..37f542c92 100755
--- a/bin/browser-tests
+++ b/bin/browser-tests
@@ -14,7 +14,7 @@ use Getopt::Long ':config' => qw(pass_through auto_help);
my ($run_server, $run_cypress, $vagrant);
my $config_file = 'conf/general.yml-example';
-my $cobrand = [ 'fixmystreet', 'northamptonshire', 'bathnes' ];
+my $cobrand = [ 'fixmystreet', 'northamptonshire', 'bathnes', 'buckinghamshire' ];
my $coords = '51.532851,-2.284277';
my $area_id = 2608;
my $name = 'Borsetshire';
@@ -129,7 +129,7 @@ browser-tests [running options] [fixture options] [cypress options]
--help this help message
Fixture option:
- --cobrand Cobrand(s) to use, default is fixmystreet,northamptonshire,bathnes
+ --cobrand Cobrand(s) to use, default is fixmystreet,northamptonshire,bathnes,buckinghamshire
--coords Default co-ordinates for created reports
--area_id Area ID to use for created body
--name Name to use for created body
diff --git a/bin/fixmystreet.com/fixture b/bin/fixmystreet.com/fixture
index 35e4e819c..3c3336811 100755
--- a/bin/fixmystreet.com/fixture
+++ b/bin/fixmystreet.com/fixture
@@ -92,18 +92,48 @@ for my $cat ('Dropped Kerbs', 'Skips') {
}
if ($opt->test_fixtures) {
- my $ncc = FixMyStreet::DB::Factory::Body->find_or_create({
- area_id => 2234,
- categories => [ 'Fallen Tree' ],
- name => 'Northamptonshire County Council',
+ my $bodies;
+ foreach (
+ { area_id => 2234, categories => ['Fallen Tree', 'Very Urgent'], name => 'Northamptonshire County Council' },
+ { area_id => 2217, categories => ['Flytipping', 'Roads'], name => 'Buckinghamshire County Council' },
+ { area_id => 2257, categories => ['Flytipping', 'Graffiti'], name => 'Chiltern District Council' },
+ { area_id => 2397, categories => [ 'Graffiti' ], name => 'Northampton Borough Council' },
+ ) {
+ $bodies->{$_->{area_id}} = FixMyStreet::DB::Factory::Body->find_or_create($_);
+ my $cats = join(', ', @{$_->{categories}});
+ say "Created body $_->{name} for MapIt area ID $_->{area_id}, categories $cats";
+ }
+
+ my $child_cat = FixMyStreet::DB->resultset("Contact")->find({
+ body => $bodies->{2234},
+ category => 'Very Urgent',
});
- say "Created body " . $ncc->name . " for MapIt area ID 2234, categories Fallen Tree";
- $ncc = FixMyStreet::DB::Factory::Body->find_or_create({
- area_id => 2397,
- categories => [ 'Graffiti' ],
- name => 'Northampton Borough Council',
+ $child_cat->set_extra_fields({
+ code => 'emergency',
+ datatype => 'string',
+ description => 'Please call us instead, it is very urgent.',
+ order => 1,
+ variable => 'false',
});
- say "Created body " . $ncc->name . " for MapIt area ID 2397, categories Graffiti";
+ $child_cat->update;
+
+ $child_cat = FixMyStreet::DB->resultset("Contact")->find({
+ body => $bodies->{2217},
+ category => 'Flytipping',
+ });
+ $child_cat->set_extra_fields({
+ code => 'road-placement',
+ datatype => 'singlevaluelist',
+ description => 'Is the fly-tip located on',
+ order => 100,
+ required => 'true',
+ variable => 'true',
+ values => [
+ { key => 'road', name => 'The road' },
+ { key => 'off-road', name => 'Off the road/on a verge' },
+ ],
+ });
+ $child_cat->update;
}
FixMyStreet::DB::Factory::ResponseTemplate->create({
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index fb525fc1f..e2b76ca60 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -26,9 +26,14 @@ Functions to run on both GET and POST contact requests.
sub auto : Private {
my ($self, $c) = @_;
+ $c->forward('/auth/get_csrf_token');
+}
+
+sub begin : Private {
+ my ($self, $c) = @_;
+ $c->forward('/begin');
$c->forward('setup_request');
$c->forward('determine_contact_type');
- $c->forward('/auth/get_csrf_token');
}
=head2 index
@@ -106,7 +111,14 @@ sub determine_contact_type : Private {
$c->stash->{rejecting_report} = 1;
}
} elsif ( $c->cobrand->abuse_reports_only ) {
- $c->detach( '/page_error_404_not_found' );
+ # General enquiries replaces contact form if enabled
+ if ( $c->cobrand->can('setup_general_enquiries_stash') ) {
+ $c->res->redirect( '/contact/enquiry' );
+ $c->detach;
+ return 1;
+ } else {
+ $c->detach( '/page_error_404_not_found' );
+ }
}
return 1;
diff --git a/perllib/FixMyStreet/App/Controller/Contact/Enquiry.pm b/perllib/FixMyStreet/App/Controller/Contact/Enquiry.pm
new file mode 100644
index 000000000..5b1c4980f
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Contact/Enquiry.pm
@@ -0,0 +1,119 @@
+package FixMyStreet::App::Controller::Contact::Enquiry;
+
+use Moose;
+use namespace::autoclean;
+use Path::Tiny;
+use File::Copy;
+use Digest::SHA qw(sha1_hex);
+use File::Basename;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+sub auto : Private {
+ my ($self, $c) = @_;
+
+ unless ( $c->cobrand->call_hook('setup_general_enquiries_stash') ) {
+ $c->res->redirect( '/' );
+ $c->detach;
+ }
+}
+
+# This needs to be defined here so /contact/begin doesn't get run instead.
+sub begin : Private {
+ my ($self, $c) = @_;
+
+ $c->forward('/begin');
+}
+
+sub index : Path : Args(0) {
+ my ( $self, $c, $preserve_session ) = @_;
+
+ # Make sure existing files aren't lost if we're rendering this
+ # page as a result of validation error.
+ delete $c->session->{enquiry_files} unless $preserve_session;
+
+ $c->stash->{field_errors}->{name} = _("Please enter your full name.") if $c->stash->{field_errors}->{name};
+}
+
+sub submit : Path('submit') : Args(0) {
+ my ( $self, $c ) = @_;
+
+ unless ($c->req->method eq 'POST' && $c->forward("/report/new/check_form_submitted") ) {
+ $c->res->redirect( '/contact/enquiry' );
+ return;
+ }
+
+ # General enquiries are always private reports, and aren't
+ # located by the user on the map
+ $c->set_param('non_public', 1);
+ $c->set_param('pc', '');
+ $c->set_param('skipped', 1);
+
+ $c->forward('/report/new/initialize_report');
+ $c->forward('/report/new/check_for_category');
+ $c->forward('/auth/check_csrf_token');
+ $c->forward('/report/new/process_report');
+ $c->forward('/report/new/process_user');
+ $c->forward('handle_uploads');
+ $c->forward('/photo/process_photo');
+ $c->go('index', [ 1 ]) unless $c->forward('/report/new/check_for_errors');
+ $c->forward('/report/new/save_user_and_report');
+ $c->forward('confirm_report');
+ $c->stash->{success} = 1;
+
+ # Don't want these lingering around for the next time.
+ delete $c->session->{enquiry_files};
+}
+
+sub confirm_report : Private {
+ my ( $self, $c ) = @_;
+
+ my $report = $c->stash->{report};
+
+ # We don't ever want to modify an existing user, as general enquiries don't
+ # require any kind of email confirmation.
+ $report->user->insert unless $report->user->in_storage;
+ $report->confirm();
+ $report->update;
+}
+
+sub handle_uploads : Private {
+ my ( $self, $c ) = @_;
+
+ # NB. For simplicity's sake this relies on the UPLOAD_DIR config key provided
+ # when using the FileSystem PHOTO_STORAGE_BACKEND. Should your FMS site not
+ # be using this storage backend, you must ensure that UPLOAD_DIR is set
+ # in order for general enquiries uploads to work.
+ my $cfg = FixMyStreet->config('PHOTO_STORAGE_OPTIONS');
+ my $dir = $cfg ? $cfg->{UPLOAD_DIR} : FixMyStreet->config('UPLOAD_DIR');
+ $dir = path($dir, "enquiry_files")->absolute(FixMyStreet->path_to());
+ $dir->mkpath;
+
+ my $files = $c->session->{enquiry_files} || {};
+ foreach ($c->req->upload) {
+ my $upload = $c->req->upload($_);
+ if ($upload->type !~ /^image/) {
+ # It's not a photo so remove it before /photo/process_photo rejects it
+ delete $c->req->uploads->{$_};
+
+ # For each file, copy it into place in a subdir of PHOTO_STORAGE_OPTIONS.UPLOAD_DIR
+ FixMyStreet::PhotoStorage::base64_decode_upload($c, $upload);
+ # Hash each file to get its filename, but preserve the file extension
+ # so content-type is correct when POSTing to Open311.
+ my ($p, $n, $ext) = fileparse($upload->filename, qr/\.[^.]*/);
+ my $key = sha1_hex($upload->slurp) . $ext;
+ my $out = path($dir, $key);
+ unless (copy($upload->tempname, $out)) {
+ $c->log->info('Couldn\'t copy temp file to destination: ' . $!);
+ $c->stash->{photo_error} = _("Sorry, we couldn't save your file(s), please try again.");
+ return;
+ }
+ # Then store the file hashes in report->extra along with the original filenames
+ $files->{$key} = $upload->raw_basename;
+ }
+ }
+ $c->session->{enquiry_files} = $files;
+ $c->stash->{report}->set_extra_metadata(enquiry_files => $files);
+}
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 1c5aae647..156c81065 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -202,7 +202,9 @@ sub report_form_ajax : Path('ajax') : Args(0) {
my @list_of_names = map { $_->name } values %{$c->stash->{bodies}};
my %display_names = map {
- my $name = $_->get_cobrand_handler ? $_->get_cobrand_handler->council_name : $_->name;
+ my $name = $_->get_cobrand_handler && $_->get_cobrand_handler->can('council_name')
+ ? $_->get_cobrand_handler->council_name
+ : $_->name;
( $_->name ne $name ) ? ( $_->name => $name ) : ();
} values %{$c->stash->{bodies}};
my $contribute_as = {};
diff --git a/perllib/FixMyStreet/App/Model/PhotoSet.pm b/perllib/FixMyStreet/App/Model/PhotoSet.pm
index 8621286b0..1d9ccd7cd 100644
--- a/perllib/FixMyStreet/App/Model/PhotoSet.pm
+++ b/perllib/FixMyStreet/App/Model/PhotoSet.pm
@@ -121,23 +121,8 @@ has ids => ( # Arrayref of $fileid tuples (always, so post upload/raw data proc
return ();
}
- # base64 decode the file if it's encoded that way
- # Catalyst::Request::Upload doesn't do this automatically
- # unfortunately.
- my $transfer_encoding = $upload->headers->header('Content-Transfer-Encoding');
- if (defined $transfer_encoding && $transfer_encoding eq 'base64') {
- my $decoded = decode_base64($upload->slurp);
- if (open my $fh, '>', $upload->tempname) {
- binmode $fh;
- print $fh $decoded;
- close $fh
- } else {
- my $c = $self->c;
- $c->log->info('Couldn\'t open temp file to save base64 decoded image: ' . $!);
- $c->stash->{photo_error} = _("Sorry, we couldn't save your image(s), please try again.");
- return ();
- }
- }
+ # Make sure any base64 encoding is handled.
+ FixMyStreet::PhotoStorage::base64_decode_upload($self->c, $upload);
# get the photo into a variable
my $photo_blob = eval {
diff --git a/perllib/FixMyStreet/Cobrand/Hounslow.pm b/perllib/FixMyStreet/Cobrand/Hounslow.pm
index 7ebd62a18..491384847 100644
--- a/perllib/FixMyStreet/Cobrand/Hounslow.pm
+++ b/perllib/FixMyStreet/Cobrand/Hounslow.pm
@@ -119,6 +119,7 @@ sub open311_config {
$row->set_extra_fields(@$extra);
$params->{multi_photos} = 1;
+ $params->{upload_files} = 1;
}
sub open311_munge_update_params {
@@ -137,6 +138,48 @@ sub open311_skip_report_fetch {
return 1 if $problem->non_public;
}
+# Make sure fetched report description isn't shown.
+sub filter_report_description { "" }
+
+sub setup_general_enquiries_stash {
+ my $self = shift;
+
+ my @bodies = $self->{c}->model('DB::Body')->active->for_areas(( $self->council_area_id ))->all;
+ my %bodies = map { $_->id => $_ } @bodies;
+ my @contacts #
+ = $self->{c} #
+ ->model('DB::Contact') #
+ ->active
+ ->search(
+ {
+ 'me.body_id' => [ keys %bodies ]
+ },
+ {
+ prefetch => 'body',
+ order_by => 'me.category',
+ }
+ )->all;
+ @contacts = grep {
+ my $group = $_->get_extra_metadata('group') || '';
+ $group eq 'Other' || $group eq 'General Enquiries';
+ } @contacts;
+ $self->{c}->stash->{bodies} = \%bodies;
+ $self->{c}->stash->{bodies_to_list} = \%bodies;
+ $self->{c}->stash->{contacts} = \@contacts;
+ $self->{c}->stash->{missing_details_bodies} = [];
+ $self->{c}->stash->{missing_details_body_names} = [];
+
+ $self->{c}->set_param('title', "General Enquiry");
+ # Can't use (0, 0) for lat lon so default to the rough location
+ # of Hounslow Highways HQ.
+ $self->{c}->stash->{latitude} = 51.469;
+ $self->{c}->stash->{longitude} = -0.35;
+
+ return 1;
+}
+
+sub abuse_reports_only { 1 }
+
sub lookup_site_code_config { {
buffer => 50, # metres
url => "https://tilma.mysociety.org/mapserver/hounslow",
@@ -146,4 +189,13 @@ sub lookup_site_code_config { {
accept_feature => sub { 1 }
} }
+# Hounslow don't want any reports made before their go-live date visible on
+# their cobrand at all.
+sub problems_restriction {
+ my ($self, $rs) = @_;
+ return $rs->to_body($self->body)->search({
+ 'me.confirmed' => { '>=', '2019-05-06' }
+ });
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/Lincolnshire.pm b/perllib/FixMyStreet/Cobrand/Lincolnshire.pm
index 8d8ba3268..2506772b3 100644
--- a/perllib/FixMyStreet/Cobrand/Lincolnshire.pm
+++ b/perllib/FixMyStreet/Cobrand/Lincolnshire.pm
@@ -111,8 +111,6 @@ sub categories_restriction {
] } );
}
-sub map_type { 'Lincolnshire' }
-
sub pin_colour {
my ( $self, $p, $context ) = @_;
my $ext_status = $p->get_extra_metadata('external_status_code');
diff --git a/perllib/FixMyStreet/Map/Buckinghamshire.pm b/perllib/FixMyStreet/Map/Buckinghamshire.pm
index d24077f70..e811eac50 100644
--- a/perllib/FixMyStreet/Map/Buckinghamshire.pm
+++ b/perllib/FixMyStreet/Map/Buckinghamshire.pm
@@ -37,14 +37,9 @@ sub copyright {
sub map_javascript { [
'/vendor/OpenLayers/OpenLayers.wmts.js',
- '/vendor/OpenLayers.Projection.OrdnanceSurvey.js',
'/js/map-OpenLayers.js',
'/js/map-wmts-base.js',
'/js/map-wmts-buckinghamshire.js',
- '/cobrands/fixmystreet/assets.js',
- '/cobrands/fixmystreet-uk-councils/roadworks.js',
- '/cobrands/buckinghamshire/js.js',
- '/cobrands/buckinghamshire/assets.js',
] }
1;
diff --git a/perllib/FixMyStreet/Map/Lincolnshire.pm b/perllib/FixMyStreet/Map/Lincolnshire.pm
deleted file mode 100644
index 7dbfe5d8e..000000000
--- a/perllib/FixMyStreet/Map/Lincolnshire.pm
+++ /dev/null
@@ -1,21 +0,0 @@
-# FixMyStreet:Map::Lincolnshire
-# More JavaScript, for street assets
-
-package FixMyStreet::Map::Lincolnshire;
-use base 'FixMyStreet::Map::FMS';
-
-use strict;
-
-sub map_javascript { [
- '/vendor/OpenLayers/OpenLayers.wfs.js',
- '/vendor/OpenLayers.Projection.OrdnanceSurvey.js',
- '/js/map-OpenLayers.js',
- '/js/map-bing-ol.js',
- '/js/map-fms.js',
- '/cobrands/fixmystreet-uk-councils/roadworks.js',
- '/cobrands/fixmystreet/assets.js',
- '/cobrands/lincolnshire/roadworks.js',
- '/cobrands/lincolnshire/assets.js',
-] }
-
-1;
diff --git a/perllib/FixMyStreet/PhotoStorage.pm b/perllib/FixMyStreet/PhotoStorage.pm
index a441fb718..558c93749 100644
--- a/perllib/FixMyStreet/PhotoStorage.pm
+++ b/perllib/FixMyStreet/PhotoStorage.pm
@@ -37,5 +37,33 @@ sub get_fileid {
}
+=head2 base64_decode_upload
+
+base64 decode the temporary on-disk uploaded file if
+it's encoded that way. Modifies the file in-place.
+Catalyst::Request::Upload doesn't do this automatically
+unfortunately.
+
+=cut
+
+sub base64_decode_upload {
+ my ( $c, $upload ) = @_;
+
+ my $transfer_encoding = $upload->headers->header('Content-Transfer-Encoding');
+ if (defined $transfer_encoding && $transfer_encoding eq 'base64') {
+ my $decoded = decode_base64($upload->slurp);
+ if (open my $fh, '>', $upload->tempname) {
+ binmode $fh;
+ print $fh $decoded;
+ close $fh
+ } else {
+ $c->log->info('Couldn\'t open temp file to save base64 decoded image: ' . $!);
+ $c->stash->{photo_error} = _("Sorry, we couldn't save your file(s), please try again.");
+ return ();
+ }
+ }
+
+}
+
1;
diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm
index a661ff206..8a6b992fd 100644
--- a/perllib/FixMyStreet/SendReport/Open311.pm
+++ b/perllib/FixMyStreet/SendReport/Open311.pm
@@ -29,6 +29,7 @@ sub send {
use_service_as_deviceid => 0,
extended_description => 1,
multi_photos => 0,
+ upload_files => 0,
fixmystreet_body => $body,
);
diff --git a/perllib/Open311.pm b/perllib/Open311.pm
index ec3390ee7..a902a7213 100644
--- a/perllib/Open311.pm
+++ b/perllib/Open311.pm
@@ -12,6 +12,7 @@ use HTTP::Request::Common qw(GET POST);
use FixMyStreet::Cobrand;
use FixMyStreet::DB;
use Utils;
+use Path::Tiny 'path';
has jurisdiction => ( is => 'ro', isa => Str );;
has api_key => ( is => 'ro', isa => Str );
@@ -32,6 +33,7 @@ has use_service_as_deviceid => ( is => 'ro', isa => Bool, default => 0 );
has extended_statuses => ( is => 'ro', isa => Bool, default => 0 );
has always_send_email => ( is => 'ro', isa => Bool, default => 0 );
has multi_photos => ( is => 'ro', isa => Bool, default => 0 );
+has upload_files => ( is => 'ro', isa => Bool, default => 0 );
has use_customer_reference => ( is => 'ro', isa => Bool, default => 0 );
has mark_reopen => ( is => 'ro', isa => Bool, default => 0 );
has fixmystreet_body => ( is => 'ro', isa => InstanceOf['FixMyStreet::DB::Result::Body'] );
@@ -90,8 +92,9 @@ sub send_service_request {
my $params = $self->_populate_service_request_params(
$problem, $extra, $service_code
);
+ my $uploads = $self->_populate_service_request_uploads($problem, $params);
- my $response = $self->_post( $self->endpoints->{requests}, $params );
+ my $response = $self->_post( $self->endpoints->{requests}, $params, $uploads );
if ( $response ) {
my $obj = $self->_get_xml_object( $response );
@@ -191,6 +194,43 @@ sub _populate_service_request_params {
return $params;
}
+sub _populate_service_request_uploads {
+ my $self = shift;
+ my $problem = shift;
+ my $params = shift;
+
+ return unless $self->upload_files;
+
+ my $uploads = {};
+
+ if ( $problem->get_extra_metadata('enquiry_files') ) {
+ my $cfg = FixMyStreet->config('PHOTO_STORAGE_OPTIONS');
+ my $dir = $cfg ? $cfg->{UPLOAD_DIR} : FixMyStreet->config('UPLOAD_DIR');
+ $dir = path($dir, "enquiry_files")->absolute(FixMyStreet->path_to());
+
+ my $files = $problem->get_extra_metadata('enquiry_files') || {};
+ for my $key (keys %$files) {
+ my $name = $files->{$key};
+ $uploads->{"file_$key"} = [ path($dir, $key)->canonpath, $name ];
+ }
+ }
+
+ if ( $problem->photo && $problem->non_public ) {
+ # open311-adapter won't be able to download any photos if they're on
+ # a private report, so instead of sending the media_url parameter
+ # send the actual photo content with the POST request.
+ my $i = 0;
+ my $photoset = $problem->get_photoset;
+ for ( $photoset->all_ids ) {
+ my $photo = $photoset->get_image_data( num => $i++, size => 'full' );
+ $uploads->{"photo$i"} = [ undef, $_, Content_Type => $photo->{content_type}, Content => $photo->{data} ];
+ }
+ delete $params->{media_url};
+ }
+
+ return $uploads;
+}
+
sub _generate_service_request_description {
my $self = shift;
my $problem = shift;
@@ -442,6 +482,7 @@ sub _request {
my $method = shift;
my $path = shift;
my $params = shift || {};
+ my $uploads = shift;
my $uri = URI->new( $self->endpoint );
$uri->path( $uri->path . $path );
@@ -458,7 +499,32 @@ sub _request {
$uri->query_form( $params );
GET $uri->as_string;
} elsif ($method eq 'POST') {
- POST $uri->as_string, $params;
+ if ($uploads) {
+ # HTTP::Request::Common needs to be constructed slightly
+ # differently if there are files to upload.
+
+ my @media_urls = ();
+ # HTTP::Request::Common treats an arrayref as a filespec,
+ # so we need to rejig the media_url parameter so it doesn't
+ # get confused...
+ # https://stackoverflow.com/questions/50705344/perl-httprequestcommon-post-file-and-array
+ if ($self->multi_photos) {
+ my $media_urls = $params->{media_url};
+ @media_urls = map { ( media_url => $_ ) } @$media_urls;
+ delete $params->{media_url};
+ }
+ $params = {
+ Content_Type => 'form-data',
+ Content => [
+ %$params,
+ @media_urls,
+ %$uploads
+ ]
+ };
+ POST $uri->as_string, %$params;
+ } else {
+ POST $uri->as_string, $params;
+ }
}
};
diff --git a/t/Mock/MapIt.pm b/t/Mock/MapIt.pm
index 1cc3fb23c..60ba30fe3 100644
--- a/t/Mock/MapIt.pm
+++ b/t/Mock/MapIt.pm
@@ -28,6 +28,8 @@ my @PLACES = (
[ 'BS10 5EE', 51.494885, -2.602237, 2561, 'Bristol City Council', 'UTA', 148646, 'Bedminster', 'UTW' ],
[ 'BS20 5EE', 51.496194, -2.603439, 2608, 'Borsetshire County Council', 'CTY', 148646, 'Bedminster', 'UTW' ],
[ 'SL9 0NX', 51.615559, -0.556903, 2217, 'Buckinghamshire County Council', 'CTY', 2257, 'Chiltern District Council', 'DIS' ],
+ [ '?', 51.615499, -0.556667, 2217, 'Buckinghamshire County Council', 'CTY', 2257, 'Chiltern District Council', 'DIS' ],
+ [ '?', 51.615439, -0.558362, 2217, 'Buckinghamshire County Council', 'CTY', 2257, 'Chiltern District Council', 'DIS' ],
[ 'SW1A 1AA', 51.501009, -0.141588, 2504, 'Westminster City Council', 'LBO' ],
[ 'GL50 2PR', 51.896268, -2.093063, 2226, 'Gloucestershire County Council', 'CTY', 2326, 'Cheltenham Borough Council', 'DIS', 4544, 'Lansdown', 'DIW', 143641, 'Lansdown and Park', 'CED' ],
[ 'OX20 1SZ', 51.754926, -1.256179, 2237, 'Oxfordshire County Council', 'CTY', 2421, 'Oxford City Council', 'DIS' ],
diff --git a/t/app/controller/contact.t b/t/app/controller/contact.t
index 842f27dd5..c74aaa5ff 100644
--- a/t/app/controller/contact.t
+++ b/t/app/controller/contact.t
@@ -6,6 +6,16 @@ sub abuse_reports_only { 1; }
1;
+package FixMyStreet::Cobrand::GeneralEnquiries;
+
+use base 'FixMyStreet::Cobrand::Default';
+
+sub abuse_reports_only { 1 }
+
+sub setup_general_enquiries_stash { 1 }
+
+1;
+
package main;
use FixMyStreet::TestMech;
@@ -492,6 +502,27 @@ subtest 'check can limit contact to abuse reports' => sub {
}
};
+subtest 'check redirected to correct form for general enquiries cobrand' => sub {
+ FixMyStreet::override_config {
+ 'ALLOWED_COBRANDS' => [ 'generalenquiries' ],
+ }, sub {
+ $mech->get( '/contact' );
+ is $mech->res->code, 200, "got 200 for final destination";
+ is $mech->res->previous->code, 302, "got 302 for redirect";
+ is $mech->uri->path, '/contact/enquiry';
+
+ $mech->get_ok( '/contact?id=' . $problem_main->id, 'can visit for abuse report' );
+
+ my $token = FixMyStreet::App->model("DB::Token")->create({
+ scope => 'moderation',
+ data => { id => $problem_main->id }
+ });
+
+ $mech->get_ok( '/contact?m=' . $token->token, 'can visit for moderation complaint' );
+
+ }
+};
+
$problem_main->delete;
done_testing();
diff --git a/t/app/controller/contact_enquiry.t b/t/app/controller/contact_enquiry.t
new file mode 100644
index 000000000..fe3962c8e
--- /dev/null
+++ b/t/app/controller/contact_enquiry.t
@@ -0,0 +1,226 @@
+use FixMyStreet::TestMech;
+use Path::Tiny;
+use File::Temp 'tempdir';
+
+# disable info logs for this test run
+FixMyStreet::App->log->disable('info');
+END { FixMyStreet::App->log->enable('info'); }
+
+my $mech = FixMyStreet::TestMech->new;
+
+my $body = $mech->create_body_ok( 2483, 'Hounslow Borough Council' );
+my $contact = $mech->create_contact_ok(
+ body_id => $body->id,
+ category => 'General Enquiry',
+ email => 'genenq@example.com',
+ non_public => 1,
+);
+my $contact2 = $mech->create_contact_ok(
+ body_id => $body->id,
+ category => 'FOI Request',
+ email => 'foi@example.com',
+ non_public => 1,
+);
+my $contact3 = $mech->create_contact_ok(
+ body_id => $body->id,
+ category => 'Other',
+ email => 'other@example.com',
+);
+my $contact4 = $mech->create_contact_ok(
+ body_id => $body->id,
+ category => 'Carriageway Defect',
+ email => 'potholes@example.com',
+);
+$contact->update( { extra => { group => 'General Enquiries' } } );
+$contact2->update( { extra => { group => 'General Enquiries' } } );
+$contact3->update( { extra => { group => 'Other' } } );
+
+FixMyStreet::override_config { ALLOWED_COBRANDS => ['bromley'], }, sub {
+ subtest 'redirected to / if general enquiries not enabled' => sub {
+ $mech->get( '/contact/enquiry' );
+ is $mech->res->code, 200, "got 200 for final destination";
+ is $mech->res->previous->code, 302, "got 302 for redirect";
+ is $mech->uri->path, '/';
+ };
+};
+
+FixMyStreet::override_config {
+ ALLOWED_COBRANDS => ['hounslow'],
+ MAPIT_URL => 'http://mapit.uk/',
+}, sub {
+ subtest 'Non-general enquiries category not shown' => sub {
+ $mech->get_ok( '/contact/enquiry' );
+ $mech->content_lacks('Carriageway Defect');
+ $mech->content_contains('FOI Request');
+ };
+
+ subtest 'Enquiry can be submitted when logged out' => sub {
+ my $problems = FixMyStreet::App->model('DB::Problem')->to_body( $body->id );
+
+ $mech->get_ok( '/contact/enquiry' );
+ $mech->submit_form_ok( {
+ with_fields => {
+ name => 'Test User',
+ username => 'testuser@example.org',
+ category => 'Other',
+ detail => 'This is a general enquiry',
+ }
+ } );
+ is $mech->uri->path, '/contact/enquiry/submit';
+ $mech->content_contains("Thank you for your enquiry");
+
+ is $problems->count, 1, 'problem created';
+ my $problem = $problems->first;
+ is $problem->category, 'Other', 'problem has correct category';
+ is $problem->detail, 'This is a general enquiry', 'problem has correct detail';
+ is $problem->non_public, 1, 'problem created non_public';
+ is $problem->postcode, '';
+ is $problem->used_map, 0;
+ is $problem->latitude, 51.469, 'Problem has correct latitude';
+ is $problem->longitude, -0.35, 'Problem has correct longitude';
+ ok $problem->confirmed, 'problem confirmed';
+ is $problem->user->name, undef, 'User created without name';
+ is $problem->name, 'Test User', 'Report created with correct name';
+ is $problem->user->email, 'testuser@example.org', 'User created with correct email';
+ };
+
+ subtest 'Enquiry can be submitted when logged in' => sub {
+ my $problems = FixMyStreet::App->model('DB::Problem')->to_body( $body->id );
+ my $user = $problems->first->user;
+ $problems->delete_all;
+
+ $mech->log_in_ok( $user->email );
+
+ $mech->get_ok( '/contact/enquiry' );
+ $mech->submit_form_ok( {
+ with_fields => {
+ name => 'Test User',
+ category => 'FOI Request',
+ detail => 'This is a general enquiry',
+ }
+ } );
+ is $mech->uri->path, '/contact/enquiry/submit';
+ $mech->content_contains("Thank you for your enquiry");
+
+ is $problems->count, 1, 'problem created';
+ my $problem = $problems->first;
+ is $problem->category, 'FOI Request', 'problem has correct category';
+ is $problem->detail, 'This is a general enquiry', 'problem has correct detail';
+ is $problem->non_public, 1, 'problem created non_public';
+ is $problem->postcode, '';
+ is $problem->used_map, 0;
+ is $problem->latitude, 51.469, 'Problem has correct latitude';
+ is $problem->longitude, -0.35, 'Problem has correct longitude';
+ ok $problem->confirmed, 'problem confirmed';
+ is $problem->name, 'Test User', 'Report created with correct name';
+ is $problem->user->name, 'Test User', 'User name updated in DB';
+ is $problem->user->email, 'testuser@example.org', 'Report user has correct email';
+
+ $mech->log_out_ok;
+ };
+
+ subtest 'User name not changed if logged out when making report' => sub {
+ my $problems = FixMyStreet::App->model('DB::Problem')->to_body( $body->id );
+ my $user = $problems->first->user;
+ $problems->delete_all;
+
+ is $user->name, 'Test User', 'User has correct name';
+
+ $mech->get_ok( '/contact/enquiry' );
+ $mech->submit_form_ok( {
+ with_fields => {
+ name => 'Simon Neil',
+ username => 'testuser@example.org',
+ category => 'General Enquiry',
+ detail => 'This is a general enquiry',
+ }
+ } );
+ is $mech->uri->path, '/contact/enquiry/submit';
+ $mech->content_contains("Thank you for your enquiry");
+
+ is $problems->count, 1, 'problem created';
+ my $problem = $problems->first;
+ is $problem->category, 'General Enquiry', 'problem has correct category';
+ is $problem->detail, 'This is a general enquiry', 'problem has correct detail';
+ is $problem->non_public, 1, 'problem created non_public';
+ is $problem->postcode, '';
+ is $problem->used_map, 0;
+ is $problem->latitude, 51.469, 'Problem has correct latitude';
+ is $problem->longitude, -0.35, 'Problem has correct longitude';
+ ok $problem->confirmed, 'problem confirmed';
+ is $problem->name, 'Simon Neil', 'Report created with correct name';
+ is $problem->user->email, 'testuser@example.org', 'Report user has correct email';
+ $user->discard_changes;
+ is $user->name, 'Test User', 'User name in DB not changed';
+
+ $mech->log_out_ok;
+ };
+
+};
+
+my $sample_jpeg = path(__FILE__)->parent->child("sample.jpg");
+ok $sample_jpeg->exists, "sample image $sample_jpeg exists";
+my $sample_pdf = path(__FILE__)->parent->child("sample.pdf");
+ok $sample_pdf->exists, "sample PDF $sample_pdf exists";
+
+subtest "Check photo & file upload works" => sub {
+ my $UPLOAD_DIR = tempdir( CLEANUP => 1 );
+
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'hounslow' ],
+ MAPIT_URL => 'http://mapit.uk/',
+ PHOTO_STORAGE_BACKEND => 'FileSystem',
+ PHOTO_STORAGE_OPTIONS => {
+ UPLOAD_DIR => $UPLOAD_DIR,
+ },
+ }, sub {
+ my $problems = FixMyStreet::App->model('DB::Problem')->to_body( $body->id );
+ $problems->delete_all;
+
+
+ $mech->get_ok('/contact/enquiry');
+ my ($csrf) = $mech->content =~ /name="token" value="([^"]*)"/;
+
+ $mech->post( '/contact/enquiry/submit',
+ Content_Type => 'form-data',
+ Content =>
+ {
+ submit_problem => 1,
+ token => $csrf,
+ name => 'Test User',
+ username => 'testuser@example.org',
+ category => 'Other',
+ detail => 'This is a general enquiry',
+ photo1 => [ $sample_jpeg, undef, Content_Type => 'image/jpeg' ],
+ photo2 => [ $sample_pdf, undef, Content_Type => 'application/pdf' ],
+ }
+ );
+ ok $mech->success, 'Made request with two files uploaded';
+
+ is $problems->count, 1, 'problem created';
+ my $problem = $problems->first;
+ is $problem->detail, 'This is a general enquiry', 'problem has correct detail';
+ is $problem->non_public, 1, 'problem created non_public';
+ is $problem->postcode, '';
+ is $problem->used_map, 0;
+ is $problem->latitude, 51.469, 'Problem has correct latitude';
+ is $problem->longitude, -0.35, 'Problem has correct longitude';
+ ok $problem->confirmed, 'problem confirmed';
+
+ my $image_file = path($UPLOAD_DIR, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg');
+ ok $image_file->exists, 'Photo uploaded to temp';
+
+ my $photoset = $problem->get_photoset();
+ is $photoset->num_images, 1, 'Found just 1 image';
+ is $photoset->data, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg';
+
+ my $pdf_file = path($UPLOAD_DIR, 'enquiry_files', '90f7a64043fb458d58de1a0703a6355e2856b15e.pdf');
+ ok $pdf_file->exists, 'PDF uploaded to temp';
+
+ is_deeply $problem->get_extra_metadata('enquiry_files'), {
+ '90f7a64043fb458d58de1a0703a6355e2856b15e.pdf' => 'sample.pdf'
+ }, 'enquiry file info stored OK';
+
+ };
+};
+done_testing();
diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t
index d13f9d9ea..848529686 100644
--- a/t/app/controller/report_new.t
+++ b/t/app/controller/report_new.t
@@ -1,3 +1,10 @@
+package FixMyStreet::Cobrand::HounslowNoName;
+use base 'FixMyStreet::Cobrand::UK';
+
+sub council_area_id { 2483 };
+
+package main;
+
use Test::MockModule;
use FixMyStreet::TestMech;
use FixMyStreet::App;
@@ -1401,6 +1408,14 @@ subtest "check map click ajax response" => sub {
$extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=51.482286&longitude=-0.328163' );
};
is_deeply $extra_details->{display_names}, { 'Hounslow Borough Council' => 'Hounslow Highways' }, 'council display name mapping correct';
+
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => 'hounslownoname',
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=51.482286&longitude=-0.328163' );
+ };
+ isnt defined $extra_details->{display_names}, 'no council display names if none defined';
};
#### test uploading an image
diff --git a/t/app/controller/sample.pdf b/t/app/controller/sample.pdf
new file mode 100644
index 000000000..9ac5be44b
--- /dev/null
+++ b/t/app/controller/sample.pdf
Binary files differ
diff --git a/t/cobrand/hounslow.t b/t/cobrand/hounslow.t
new file mode 100644
index 000000000..5d9f022e7
--- /dev/null
+++ b/t/cobrand/hounslow.t
@@ -0,0 +1,44 @@
+use FixMyStreet::TestMech;
+
+ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' );
+
+my $hounslow_id = $mech->create_body_ok(2483, 'Hounslow Borough Council')->id;
+
+$mech->create_problems_for_body(1, $hounslow_id, 'An old problem made before Hounslow FMS launched', {
+ confirmed => '2018-12-25 09:00',
+ lastupdate => '2018-12-25 09:00',
+});
+$mech->create_problems_for_body(1, $hounslow_id, 'A brand new problem made on the Hounslow site', {
+ cobrand => 'hounslow'
+});
+$mech->create_problems_for_body(1, $hounslow_id, 'A brand new problem made on fixmystreet.com', {
+ cobrand => 'fixmystreet'
+});
+
+subtest "it still shows old reports on fixmystreet.com" => sub {
+ FixMyStreet::override_config {
+ MAPIT_URL => 'http://mapit.uk/',
+ ALLOWED_COBRANDS => 'fixmystreet',
+ }, sub {
+ $mech->get_ok('/reports/Hounslow');
+
+ $mech->content_contains('An old problem made before Hounslow FMS launched');
+ $mech->content_contains('A brand new problem made on the Hounslow site');
+ $mech->content_contains('A brand new problem made on fixmystreet.com');
+ };
+};
+
+subtest "it does not show old reports on Hounslow" => sub {
+ FixMyStreet::override_config {
+ MAPIT_URL => 'http://mapit.uk/',
+ ALLOWED_COBRANDS => 'hounslow',
+ }, sub {
+ $mech->get_ok('/reports/Hounslow');
+
+ $mech->content_lacks('An old problem made before Hounslow FMS launched');
+ $mech->content_contains('A brand new problem made on the Hounslow site') or diag $mech->content;
+ $mech->content_contains('A brand new problem made on fixmystreet.com');
+ };
+};
+
+done_testing();
diff --git a/t/map/tests.t b/t/map/tests.t
index 692cf6790..7e3b6f6bd 100644
--- a/t/map/tests.t
+++ b/t/map/tests.t
@@ -6,7 +6,7 @@ my $requires = {
'Bing' => 'map-bing-ol.js',
'Bristol' => 'bristol/assets.js',
'Bromley' => 'bromley/assets.js',
- 'Buckinghamshire' => 'buckinghamshire/assets.js',
+ 'Buckinghamshire' => 'map-wmts-buckinghamshire.js',
'Lincolnshire' => 'lincolnshire/assets.js',
'FMS' => 'map-fms.js',
'Google' => 'map-google.js',
diff --git a/templates/email/hounslow/archive.html b/templates/email/hounslow/archive.html
new file mode 100644
index 000000000..45089caa6
--- /dev/null
+++ b/templates/email/hounslow/archive.html
@@ -0,0 +1,55 @@
+[%
+
+email_summary = "Your reports on " _ site_name;
+
+PROCESS '_email_settings.html';
+
+INCLUDE '_email_top.html';
+
+%]
+
+<th style="[% td_style %][% only_column_style %]">
+ <h1 style="[% h1_style %]">Your reports on [% site_name %]</h1>
+ <p style="[% p_style %]">
+ Hello [% user.name %],
+ </p>
+ <p style="[% p_style %]">
+ FixMyStreet is being updated in Hounslow to
+ improve how problems get reported.
+ </p>
+ <p style="[% p_style %]">
+ As part of this process we are closing all reports
+ made before the update.
+ </p>
+ <p style="[% p_style %]">
+ We noticed that you have [% report_count %] old [% nget('report', 'reports', report_count) %] on the system,
+ which we've listed below.
+ </p>
+ <p style="[% p_style %]">
+ All of your reports will have been received and reviewed by Hounslow, so if
+ your report is no longer an issue, you don't need to do anything.
+ </p>
+ <p style="[% p_style %]">
+ If you believe that the issue has not been resolved you can <a href="https://fms.hounslowhighways.org/">report it again here.</a>
+ </p>
+
+ [% FOR report IN reports %]
+ <div style="[% list_item_style %]">
+ [% IF report.photo %]
+ <a href="[% cobrand.base_url_for_report( report ) %]/report/[% report.id %]">
+ <img style="[% list_item_photo_style %]" src="[% inline_image(report.get_first_image_fp) %]" alt="">
+ </a>
+ [% END %]
+ <h2 style="[% list_item_h2_style %]"><a href="[% cobrand.base_url_for_report( report ) %]/report/[% report.id %]">
+ [%~ report.title | html ~%]
+ </a></h2>
+ <p style="[% list_item_p_style %]">[% report.detail | html %]</p>
+ <p style="[% list_item_date_style %]">
+ Reported [% report.time_ago %] ago.
+ </p>
+ </div>
+ [% END %]
+
+</th>
+
+[% INCLUDE '_email_bottom.html' %]
diff --git a/templates/email/hounslow/archive.txt b/templates/email/hounslow/archive.txt
new file mode 100644
index 000000000..3573eb288
--- /dev/null
+++ b/templates/email/hounslow/archive.txt
@@ -0,0 +1,27 @@
+Subject: Your reports on [% site_name %]
+
+Hello [% user.name %],
+
+FixMyStreet is being updated in Hounslow to improve how problems get reported.
+
+As part of this process we are closing all reports made before the update.
+
+We noticed that you have [% report_count %] old [% nget('report', 'reports', report_count) %] on the system, which we've listed below.
+
+All of your reports will have been received and reviewed by Hounslow, so if your report is no longer an issue, you don't need to do anything.
+
+If you believe that the issue has not been resolved you can report it again here: https://fms.hounslowhighways.org/
+
+[% FOR report IN reports %]
+
+[% report.title %]
+
+Reported [% report.time_ago %] ago.
+
+View report: [% cobrand.base_url_for_report( report ) %]/report/[% report.id %]
+
+----
+
+[% END %]
+
+The FixMyStreet team and Hounslow Highways
diff --git a/templates/web/base/contact/enquiry/index.html b/templates/web/base/contact/enquiry/index.html
new file mode 100644
index 000000000..8b8bba1b7
--- /dev/null
+++ b/templates/web/base/contact/enquiry/index.html
@@ -0,0 +1,79 @@
+[% INCLUDE 'header.html',
+ bodyclass = 'twothirdswidthpage',
+ title = loc('General Enquiry')
+%]
+
+<form method="post" action="/contact/enquiry/submit" class="validate" enctype="multipart/form-data">
+ <input type="hidden" name="token" value="[% csrf_token %]">
+ <input type="hidden" name="submit_problem" value="1">
+ <fieldset>
+ [% INCLUDE 'errors.html' %]
+
+ <label for="form_name">[% loc('Your name') %]</label>
+ [% IF field_errors.name %]
+ <div class="form-error">[% field_errors.name %]</div>
+ [% END %]
+ <input type="text" class="form-control required" name="name" id="form_name" value="[% ( form_name OR c.user.name ) | html %]" size="30">
+
+ <label for="form_email">[% loc('Your email') %]</label>
+ [% IF field_errors.username %]
+ <div class="form-error">[% field_errors.username %]</div>
+ [% END %]
+ <input type="text" class="form-control required email" name="username" id="form_email" [% "disabled" IF c.user.email %] value="[% ( email OR c.user.email ) | html %]" size="30">
+
+ <div class="form-group">
+ <label for="form_phone">[% loc('Your phone number') %]</label>
+ <span class="required-text required-text--optional">optional</span>
+ <input type="text" class="form-control extra.phone" name="extra.phone" id="form_phone" value="[% report.user.phone | html %]" size="30">
+ </div>
+
+ <label for="form_category">[% loc('Subject') %]</label>
+ [% IF field_errors.category %]
+ <div class="form-error">[% field_errors.category %]</div>
+ [% END %]
+ <select class="form-control required" name="category" id="category">
+ <option value="">[% loc('-- Please select --') %]</option>
+ [% FOREACH contact IN contacts %]
+ <option value="[% contact.category | html %]" [% "selected" IF report.category == contact.category %]>[% contact.category | html %]</option>
+ [% END %]
+ </select>
+
+ <label for="form_detail">[% loc('Message') %]</label>
+ [% IF field_errors.detail %]
+ <div class="form-error">[% field_errors.detail %]</div>
+ [% END %]
+ <textarea class="form-control required" name="detail" id="form_detail" rows="7" cols="50">[% report.detail | html %]</textarea>
+
+ <input type="hidden" name="upload_fileid" value="[% upload_fileid %]">
+ <label for="form_photo">
+ [% loc('Photos/Documents') %]
+ </label>
+
+ [% IF field_errors.photo %]
+ <p class='form-error'>[% field_errors.photo %]</p>
+ [% END %]
+
+ <div id="form_photos">
+ [% IF upload_fileid OR report.get_extra_metadata('enquiry_files').keys.count %]
+ <p>[% loc('You have already attached files to this report. Note that you can attach a maximum of 3 to this report (if you try to upload more, the oldest will be removed).') %]</p>
+ [% FOREACH id IN upload_fileid.split(',') %]
+ <img align="right" src="/photo/temp.[% id %]" alt="">
+ [% END %]
+
+ [% IF report.get_extra_metadata('enquiry_files') %]
+ [% FOREACH id IN report.get_extra_metadata('enquiry_files').values %]
+ [% id %]<br />
+ [% END %]
+ <input type="hidden" name="enquiry_files" value="[% enquiry_files | html %]" />
+ [% END %]
+ [% END %]
+ <p><input type="file" name="photo1" id="form_photo"></p>
+ <p><input type="file" name="photo2" id="form_photo2"></p>
+ <p><input type="file" name="photo3" id="form_photo3"></p>
+ </div>
+
+ <input class="final-submit green-btn" type="submit" value="[% loc('Send') %]">
+
+ </fieldset></form>
+
+[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/base/contact/enquiry/submit.html b/templates/web/base/contact/enquiry/submit.html
new file mode 100644
index 000000000..050fd31a9
--- /dev/null
+++ b/templates/web/base/contact/enquiry/submit.html
@@ -0,0 +1 @@
+[% INCLUDE 'contact/submit.html' %]
diff --git a/templates/web/buckinghamshire/footer_extra_js.html b/templates/web/buckinghamshire/footer_extra_js.html
index 8113befc9..6080f5e4f 100644
--- a/templates/web/buckinghamshire/footer_extra_js.html
+++ b/templates/web/buckinghamshire/footer_extra_js.html
@@ -1,3 +1,14 @@
[% scripts.push(
version('/cobrands/fixmystreet-uk-councils/council_validation_rules.js'),
) %]
+[%~
+IF bodyclass.match('mappage');
+ scripts.push(
+ version('/vendor/OpenLayers.Projection.OrdnanceSurvey.js'),
+ version('/cobrands/fixmystreet/assets.js'),
+ version('/cobrands/fixmystreet-uk-councils/roadworks.js'),
+ version('/cobrands/buckinghamshire/js.js'),
+ version('/cobrands/buckinghamshire/assets.js'),
+ );
+END
+%]
diff --git a/templates/web/hounslow/main_nav_items.html b/templates/web/hounslow/main_nav_items.html
new file mode 100644
index 000000000..f333e08f3
--- /dev/null
+++ b/templates/web/hounslow/main_nav_items.html
@@ -0,0 +1,58 @@
+[%~ IF problem ~%]
+ [%~ INCLUDE navitem uri='/report/new?longitude=' _ problem.longitude _ '&amp;latitude=' _ problem.latitude label=loc('Report another problem here') attrs='class="report-a-problem-btn"' ~%]
+[%~ ELSIF latitude AND longitude ~%]
+ [%~ INCLUDE navitem uri='/report/new?longitude=' _ longitude _ '&amp;latitude=' _ latitude label=loc('Report a problem here') attrs='class="report-a-problem-btn"' ~%]
+[%~ ELSIF homepage_template ~%]
+ [%~ INCLUDE navitem uri='/report' label=loc('Report a problem') attrs='class="report-a-problem-btn"' ~%]
+[%~ ELSE ~%]
+ [%~ INCLUDE navitem uri='/' label=loc('Report a problem') attrs='class="report-a-problem-btn"' ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists ~%]
+ [%~ INCLUDE navitem uri='/my' label=loc('Your account') ~%]
+[%~ ELSE ~%]
+ [%~ INCLUDE navitem uri='/auth' label=loc('Sign in') ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists AND c.user.has_body_permission_to('planned_reports') ~%]
+ [%~ INCLUDE navitem always_url=1 uri='/my/planned' label=loc('Shortlist') ~%]
+[%~ END ~%]
+
+
+[%~ UNLESS hide_all_reports_link ~%]
+ [%~
+ IF c.user_exists AND c.user.categories.size;
+ categories = c.user.categories_string | uri;
+ cat_suffix = "?filter_category=" _ categories;
+ END;
+
+ reports_uri = '/reports';
+ IF body_name;
+ body_name = body_name | uri;
+ reports_uri = "${reports_uri}/${body_name}";
+ END;
+
+ INCLUDE navitem uri=reports_uri label=loc('All reports') suffix=cat_suffix;
+ ~%]
+[%~ END ~%]
+
+[%~
+ IF pc;
+ pc_uri = pc | uri;
+ pc_suffix = "/list?pc=" _ pc_uri;
+ END;
+
+ INCLUDE navitem uri='/alert' label=loc('Local alerts') suffix=pc_suffix;
+~%]
+
+[%~ INCLUDE navitem uri='/contact/enquiry' label=loc('Contact') ~%]
+
+[%~ INCLUDE navitem uri='/faq' label=loc('Help') ~%]
+
+[%~ UNLESS hide_privacy_link ~%]
+ [%~ INCLUDE navitem uri=c.cobrand.privacy_policy_url label=loc('Privacy') liattrs='class="nav-menu__item--privacy"' ~%]
+[%~ END ~%]
+
+[%~ IF c.user_exists AND c.cobrand.admin_allow_user(c.user) ~%]
+ [%~ INCLUDE navitem uri='/admin' label=loc('Admin') ~%]
+[%~ END ~%]
diff --git a/templates/web/lincolnshire/footer_extra_js.html b/templates/web/lincolnshire/footer_extra_js.html
index 8113befc9..946bddfdc 100644
--- a/templates/web/lincolnshire/footer_extra_js.html
+++ b/templates/web/lincolnshire/footer_extra_js.html
@@ -1,3 +1,14 @@
[% scripts.push(
version('/cobrands/fixmystreet-uk-councils/council_validation_rules.js'),
) %]
+[%~
+IF bodyclass.match('mappage');
+ scripts.push(
+ version('/vendor/OpenLayers.Projection.OrdnanceSurvey.js'),
+ version('/cobrands/fixmystreet-uk-councils/roadworks.js'),
+ version('/cobrands/fixmystreet/assets.js'),
+ version('/cobrands/lincolnshire/roadworks.js'),
+ version('/cobrands/lincolnshire/assets.js'),
+ );
+END
+%]