diff options
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&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=Whole_Street&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 Binary files differnew file mode 100644 index 000000000..9ac5be44b --- /dev/null +++ b/t/app/controller/sample.pdf 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 _ '&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 _ '&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 +%] |