diff options
50 files changed, 1408 insertions, 13 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d866c13..9cfc0e5f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,15 @@ - Bugfixes: - Prevent creation of two templates with same title. - Fix bug going between report/new pages client side + - Don't include private reports when searching by ref from front page. - Development improvements: - Upgrade the underlying framework and a number of other packages. - Add feature cobrand helper function. + - Open311 improvements: + - Support use of 'private' service definition <keywords> to mark + reports made in that category private. + - Ensure any reports fetched in a category marked private are also + marked private on the site. * v2.6 (3rd May 2019) - New features: diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index a09161494..203296c4d 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -416,7 +416,7 @@ sub lookup_by_ref : Private { external_id => $ref ]; - my $problems = $c->cobrand->problems->search( $criteria ); + my $problems = $c->cobrand->problems->search({ non_public => 0, -or => $criteria }); my $count = try { $problems->count; diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 10c869aee..1c5aae647 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -201,6 +201,10 @@ sub report_form_ajax : Path('ajax') : Args(0) { my $extra_titles_list = $c->cobrand->title_list($c->stash->{all_areas}); 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; + ( $_->name ne $name ) ? ( $_->name => $name ) : (); + } values %{$c->stash->{bodies}}; my $contribute_as = {}; if ($c->user_exists) { my @bodies = keys %{$c->stash->{bodies}}; @@ -227,6 +231,7 @@ sub report_form_ajax : Path('ajax') : Args(0) { category => $category, extra_name_info => $extra_name_info, titles_list => $extra_titles_list, + %display_names ? (display_names => \%display_names) : (), %$contribute_as ? (contribute_as => $contribute_as) : (), $top_message ? (top_message => $top_message) : (), unresponsive => $c->stash->{unresponsive}->{ALL} || '', diff --git a/perllib/FixMyStreet/Cobrand/Hounslow.pm b/perllib/FixMyStreet/Cobrand/Hounslow.pm new file mode 100644 index 000000000..7ebd62a18 --- /dev/null +++ b/perllib/FixMyStreet/Cobrand/Hounslow.pm @@ -0,0 +1,149 @@ +package FixMyStreet::Cobrand::Hounslow; +use parent 'FixMyStreet::Cobrand::Whitelabel'; + +use strict; +use warnings; + +sub council_area_id { 2483 } +sub council_area { 'Hounslow' } +sub council_name { 'Hounslow Highways' } +sub council_url { 'hounslow' } +sub example_places { ( 'TW3 1SN', "Depot Road" ) } + +sub map_type { 'Hounslow' } + +sub base_url { + my $self = shift; + return $self->next::method() if FixMyStreet->config('STAGING_SITE'); + return 'https://fms.hounslowhighways.org'; +} + +sub enter_postcode_text { + my ($self) = @_; + return "Enter a Hounslow street name and area, or postcode"; +} + +sub admin_user_domain { 'hounslowhighways.org' } + +sub disambiguate_location { + my $self = shift; + my $string = shift; + + my $town = "Hounslow"; + + # Some specific Hounslow roads produce lots of geocoder results + # for the same road; this picks just one. + ( $string, $town ) = ( "TW3 4HR", "" ) if $string =~ /lampton\s+road/i; + ( $string, $town ) = ( "TW3 4AJ", "" ) if $string =~ /kingsley\s+road/i; + ( $string, $town ) = ( "TW3 1YQ", "" ) if $string =~ /stanborough\s+road/i; + + return { + %{ $self->SUPER::disambiguate_location() }, + string => $string, + centre => '51.468495,-0.366134', + town => $town, + bounds => [ 51.420739, -0.461502, 51.502850, -0.243443 ], + }; +} + +sub get_geocoder { + return 'OSM'; # default of Bing gives poor results, let's try overriding. +} + +sub on_map_default_status { 'open' } + +sub contact_email { + my $self = shift; + return join( '@', 'enquiries', $self->council_url . 'highways.org' ); +} + +sub send_questionnaires { 0 } + +sub enable_category_groups { 1 } + +sub categories_restriction { + my ($self, $rs) = @_; + # Categories covering the Hounslow area have a mixture of Open311 and Email + # send methods. Hounslow only want Open311 categories to be visible on their + # cobrand, not the email categories from FMS.com. We've set up the + # Email categories with a devolved send_method, so can identify Open311 + # categories as those which have a blank send_method. + return $rs->search( { 'me.send_method' => undef, 'body.name' => 'Hounslow Borough Council' } ); +} + +sub report_sent_confirmation_email { 'external_id' } + +# Used to change the "Sent to" line on report pages +sub link_to_council_cobrand { "Hounslow Highways" } + +# The "all reports" link will default to using council_name, which +# in our case doesn't correspond to a body and so causes an infinite redirect. +# Instead, force the borough council name to be used. +sub all_reports_single_body { { name => "Hounslow Borough Council" } } + +sub open311_post_send { + my ($self, $row, $h) = @_; + + # Check Open311 was successful + return unless $row->external_id; + + my $e = join( '@', 'enquiries', $self->council_url . 'highways.org' ); + my $sender = FixMyStreet::SendReport::Email->new( to => [ [ $e, 'Hounslow Highways' ] ] ); + $sender->send($row, $h); +} + +sub open311_config { + my ($self, $row, $h, $params) = @_; + + my $extra = $row->get_extra_fields; + push @$extra, + { name => 'report_url', + value => $h->{url} }, + { name => 'title', + value => $row->title }, + { name => 'description', + value => $row->detail }; + + # Reports made via FMS.com or the app probably won't have a site code + # value because we don't display the adopted highways layer on those + # frontends. Instead we'll look up the closest asset from the WFS + # service at the point we're sending the report over Open311. + if (!$row->get_extra_field_value('site_code')) { + if (my $site_code = $self->lookup_site_code($row)) { + push @$extra, + { name => 'site_code', + value => $site_code }; + } + } + + $row->set_extra_fields(@$extra); + + $params->{multi_photos} = 1; +} + +sub open311_munge_update_params { + my ($self, $params, $comment, $body) = @_; + + # Hounslow want to make it clear in Confirm when an update is left by + # someone who's not the original reporter. + unless ($comment->user eq $comment->problem->user) { + $params->{description} = "[This comment was not left by the original problem reporter] " . $params->{description}; + } +} + +sub open311_skip_report_fetch { + my ($self, $problem) = @_; + + return 1 if $problem->non_public; +} + +sub lookup_site_code_config { { + buffer => 50, # metres + url => "https://tilma.mysociety.org/mapserver/hounslow", + srsname => "urn:ogc:def:crs:EPSG::27700", + typename => "streets", + property => "SITE_CODE", + accept_feature => sub { 1 } +} } + +1; diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm index 09ca6c535..c21ed6401 100644 --- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm +++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm @@ -282,6 +282,8 @@ sub lookup_site_code { my $response = get($uri); + return '' unless $response; + my $j = JSON->new->utf8->allow_nonref; try { $j = $j->decode($response); diff --git a/perllib/FixMyStreet/Map/Hounslow.pm b/perllib/FixMyStreet/Map/Hounslow.pm new file mode 100644 index 000000000..ce0831196 --- /dev/null +++ b/perllib/FixMyStreet/Map/Hounslow.pm @@ -0,0 +1,68 @@ +# FixMyStreet:Map::Hounslow +# Hounslow use their own tiles on their cobrand + +package FixMyStreet::Map::Hounslow; +use base 'FixMyStreet::Map::UKCouncilWMTS'; + +use strict; + +sub default_zoom { 5; } + +sub urls { [ 'https://gis.ringway.co.uk/server/rest/services/Hosted/HounslowOSBasemap/MapServer/WMTS/tile' ] } + +sub layer_names { [ 'Hosted_HounslowOSBasemap' ] } + +sub scales { + my $self = shift; + my @scales = ( + # The first 5 levels don't load and are really zoomed-out, so + # they're not included here. + # '600000', + # '500000', + # '400000', + # '300000', + # '200000', + '100000', + '75000', + '50000', + '25000', + '10000', + '8000', + '6000', + '4000', + '2000', + '1000', + '400', + ); + return @scales; +} + +sub zoom_parameters { + my $self = shift; + my $params = { + zoom_levels => scalar $self->scales, + default_zoom => $self->default_zoom, + min_zoom_level => 0, + id_offset => 5, # see note above about zoom layers we've skipped + }; + return $params; +} + +sub copyright { + return 'Contains Ordnance Survey data © Crown copyright and database rights 2019 OS. Use of this data is subject to <a href="/about/mapterms">terms and conditions</a>.'; +} + + +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-hounslow.js', + '/cobrands/fixmystreet-uk-councils/roadworks.js', + '/cobrands/fixmystreet/assets.js', + '/cobrands/hounslow/js.js', + '/cobrands/hounslow/assets.js', +] } + +1; diff --git a/perllib/Open311/GetServiceRequests.pm b/perllib/Open311/GetServiceRequests.pm index 194d8d296..a9ec88a70 100644 --- a/perllib/Open311/GetServiceRequests.pm +++ b/perllib/Open311/GetServiceRequests.pm @@ -146,7 +146,8 @@ sub create_problems { next; } - if ( my $cobrand = $body->get_cobrand_handler ) { + my $cobrand = $body->get_cobrand_handler; + if ( $cobrand ) { my $filtered = $cobrand->call_hook('filter_report_description', $request->{description}); $request->{description} = $filtered if defined $filtered; } @@ -157,6 +158,7 @@ sub create_problems { my $state = $open311->map_state($request->{status}); my $non_public = $request->{non_public} ? 1 : 0; + $non_public ||= $contacts[0] ? $contacts[0]->non_public : 0; my $problem = $self->schema->resultset('Problem')->new( { @@ -184,6 +186,8 @@ sub create_problems { } ); + next if $cobrand && $cobrand->call_hook(open311_skip_report_fetch => $problem); + $open311->add_media($request->{media_url}, $problem) if $request->{media_url}; diff --git a/perllib/Open311/PopulateServiceList.pm b/perllib/Open311/PopulateServiceList.pm index ad7288c62..2da67e9cd 100644 --- a/perllib/Open311/PopulateServiceList.pm +++ b/perllib/Open311/PopulateServiceList.pm @@ -165,6 +165,7 @@ sub _handle_existing_contact { } $self->_set_contact_group($contact); + $self->_set_contact_non_public($contact); push @{ $self->found_contacts }, $self->_current_service->{service_code}; } @@ -201,6 +202,7 @@ sub _create_contact { } $self->_set_contact_group($contact); + $self->_set_contact_non_public($contact); if ( $contact ) { push @{ $self->found_contacts }, $self->_current_service->{service_code}; @@ -283,6 +285,21 @@ sub _set_contact_group { } } +sub _set_contact_non_public { + my ($self, $contact) = @_; + + # We never want to make a private category unprivate. + return if $contact->non_public; + + my %keywords = map { $_ => 1 } split /,/, ( $self->_current_service->{keywords} || '' ); + $contact->update({ + non_public => 1, + editor => $0, + whenedited => \'current_timestamp', + note => 'marked private automatically by script', + }) if $keywords{private}; +} + sub _delete_contacts_not_in_service_list { my $self = shift; diff --git a/t/Mock/MapIt.pm b/t/Mock/MapIt.pm index 7429d9731..c255c916a 100644 --- a/t/Mock/MapIt.pm +++ b/t/Mock/MapIt.pm @@ -39,6 +39,7 @@ my @PLACES = ( [ 'BR1 3UH', 51.402096, 0.015784, 2482, 'Bromley Council', 'LBO' ], [ 'NN1 1NS', 52.236251, 0.892052, 2234, 'Northamptonshire County Council', 'CTY', 2397, 'Northampton Borough Council', 'DIS' ], [ 'NN1 2NS', 52.238301, 0.889992, 2234, 'Northamptonshire County Council', 'CTY', 2397, 'Northampton Borough Council', 'DIS' ], + [ 'TW7 5JN', 51.482286, -0.328163, 2483, 'Hounslow Borough Council', 'LBO' ], [ '?', 50.78301, -0.646929 ], [ 'TA1 1QP', 51.023569, -3.099055, 2239, 'Somerset County Council', 'CTY', 2429, 'Taunton Deane Borough Council', 'DIS' ], [ 'GU51 4AE', 51.279456, -0.846216, 2333, 'Hart District Council', 'DIS', 2227, 'Hampshire County Council', 'CTY' ], diff --git a/t/app/controller/around.t b/t/app/controller/around.t index 5ef37f197..829d78ca3 100644 --- a/t/app/controller/around.t +++ b/t/app/controller/around.t @@ -100,6 +100,16 @@ subtest 'check lookup by reference' => sub { is $mech->uri->path, "/report/$id", "redirected to report page"; }; +subtest 'check lookup by reference does not show non_public reports' => sub { + $edinburgh_problems[0]->update({ + non_public => 1 + }); + my $id = $edinburgh_problems[0]->id; + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => "ref:$id" } }, 'non_public ref'); + $mech->content_contains('Searching found no reports'); +}; + subtest 'check non public reports are not displayed on around page' => sub { $mech->get_ok('/'); FixMyStreet::override_config { diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t index ae6f760d8..d13f9d9ea 100644 --- a/t/app/controller/report_new.t +++ b/t/app/controller/report_new.t @@ -52,6 +52,7 @@ for my $body ( { area_id => 2237, name => 'Oxfordshire County Council' }, { area_id => 2600, name => 'Rutland County Council' }, { area_id => 2234, name => 'Northamptonshire County Council' }, + { area_id => 2483, name => 'Hounslow Borough Council' }, ) { my $body_obj = $mech->create_body_ok($body->{area_id}, $body->{name}); push @bodies, $body_obj; @@ -139,6 +140,11 @@ my $contact16 = $mech->create_contact_ok( category => 'Trees', email => 'trees-2234@example.com', ); +my $contact17 = $mech->create_contact_ok( + body_id => $body_ids{2483}, # Hounslow + category => 'Trees', + email => 'trees-2483@example.com', +); # test that the various bit of form get filled in and errors correctly # generated. @@ -1387,6 +1393,14 @@ subtest "check map click ajax response" => sub { is $extra_details->{category}, '', 'category is empty for council with no contacts'; is_deeply $extra_details->{bodies}, [ "Sandwell Borough Council" ], 'correct bodies for council with no contacts'; ok !$extra_details->{extra_name_info}, 'no extra name info'; + + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'hounslow', + MAPIT_URL => 'http://mapit.uk/', + }, 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'; }; #### test uploading an image diff --git a/t/map/tests.t b/t/map/tests.t index 7cc8f6860..692cf6790 100644 --- a/t/map/tests.t +++ b/t/map/tests.t @@ -11,6 +11,7 @@ my $requires = { 'FMS' => 'map-fms.js', 'Google' => 'map-google.js', 'GoogleOL' => 'map-google-ol.js', + 'Hounslow' => 'hounslow/assets.js', 'OSM' => 'OpenStreetMap.js', 'CycleMap' => 'OpenStreetMap.js', 'MapQuest' => 'OpenStreetMap.js', diff --git a/t/open311.t b/t/open311.t index 85176ff0d..73bb488d5 100644 --- a/t/open311.t +++ b/t/open311.t @@ -302,14 +302,14 @@ subtest 'basic request update post parameters' => sub { my $c = CGI::Simple->new( $results->{ req }->content ); - is $c->param('description'), 'this is a comment', 'email correct'; + is $c->param('description'), 'this is a comment', 'description correct'; is $c->param('email'), 'test@example.com', 'email correct'; is $c->param('status'), 'OPEN', 'status correct'; is $c->param('service_request_id'), 81, 'request id correct'; is $c->param('updated_datetime'), DateTime::Format::W3CDTF->format_datetime($dt), 'correct date'; is $c->param('title'), 'Mr', 'correct title'; - is $c->param('last_name'), 'User', 'correct first name'; - is $c->param('first_name'), 'Test', 'correct second name'; + is $c->param('first_name'), 'Test', 'correct first name'; + is $c->param('last_name'), 'User', 'correct second name'; is $c->param('media_url'), undef, 'no media url'; }; @@ -326,7 +326,7 @@ subtest 'extended request update post parameters' => sub { my $c = CGI::Simple->new( $results->{ req }->content ); - is $c->param('description'), 'this is a comment', 'email correct'; + is $c->param('description'), 'this is a comment', 'description correct'; is $c->param('email'), 'test@example.com', 'email correct'; is $c->param('status'), 'OPEN', 'status correct'; is $c->param('service_request_id_ext'), 80, 'external request id correct'; @@ -334,12 +334,66 @@ subtest 'extended request update post parameters' => sub { is $c->param('public_anonymity_required'), 'FALSE', 'anon status correct'; is $c->param('updated_datetime'), DateTime::Format::W3CDTF->format_datetime($dt), 'correct date'; is $c->param('title'), 'Mr', 'correct title'; - is $c->param('last_name'), 'User', 'correct first name'; - is $c->param('first_name'), 'Test', 'correct second name'; + is $c->param('first_name'), 'Test', 'correct first name'; + is $c->param('last_name'), 'User', 'correct second name'; is $c->param('email_alerts_requested'), 'FALSE', 'email alerts flag correct'; is $c->param('media_url'), undef, 'no media url'; }; +subtest 'Hounslow update description is correct for same user' => sub { + my $comment = make_comment('hounslow'); + my $results; + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'hounslow', + }, sub { + $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>' ); + }; + + is $results->{ res }, 248, 'got update id'; + + my $c = CGI::Simple->new( $results->{ req }->content ); + + is $c->param('description'), 'this is a comment', 'description correct'; + is $c->param('email'), 'test@example.com', 'email correct'; + is $c->param('status'), 'OPEN', 'status correct'; + is $c->param('service_request_id'), 81, 'request id correct'; + is $c->param('updated_datetime'), DateTime::Format::W3CDTF->format_datetime($dt), 'correct date'; + is $c->param('title'), 'Mr', 'correct title'; + is $c->param('first_name'), 'Test', 'correct first name'; + is $c->param('last_name'), 'User', 'correct second name'; + is $c->param('media_url'), undef, 'no media url'; +}; + +subtest 'Hounslow update description is correct for a different user' => sub { + my $user2 = FixMyStreet::DB->resultset('User')->new( { + name => 'Another User', + email => 'another@example.org', + } ); + + my $comment = make_comment('hounslow'); + $comment->user($user2); + my $results; + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'hounslow', + }, sub { + $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>' ); + }; + + is $results->{ res }, 248, 'got update id'; + + my $c = CGI::Simple->new( $results->{ req }->content ); + + is $c->param('description'), "[This comment was not left by the original problem reporter] this is a comment", 'description correct'; + is $c->param('email'), 'another@example.org', 'email correct'; + is $c->param('status'), 'OPEN', 'status correct'; + is $c->param('service_request_id'), 81, 'request id correct'; + is $c->param('updated_datetime'), DateTime::Format::W3CDTF->format_datetime($dt), 'correct date'; + is $c->param('title'), 'Mr', 'correct title'; + is $c->param('first_name'), 'Another', 'correct first name'; + is $c->param('last_name'), 'User', 'correct second name'; + is $c->param('media_url'), undef, 'no media url'; +}; + subtest 'check media url set' => sub { my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); diff --git a/t/open311/getservicerequests.t b/t/open311/getservicerequests.t index 55bb9ba11..c44be5099 100644 --- a/t/open311/getservicerequests.t +++ b/t/open311/getservicerequests.t @@ -17,6 +17,9 @@ my $contact = $mech->create_contact_ok( body_id => $body->id, category => 'Sidew my $body2 = $mech->create_body_ok(2217, 'Buckinghamshire'); my $contact2 = $mech->create_contact_ok( body_id => $body2->id, category => 'Sidewalk and Curb Issues', email => 'sidewalks' ); +my $hounslow = $mech->create_body_ok(2483, 'Hounslow'); +my $hounslowcontact = $mech->create_contact_ok( body_id => $hounslow->id, category => 'Sidewalk and Curb Issues', email => 'sidewalks' ); + my $dtf = DateTime::Format::W3CDTF->new; my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?> @@ -469,6 +472,110 @@ for my $test ( }; } +my $hounslow_non_public_xml = qq[<?xml version="1.0" encoding="utf-8"?> +<service_requests> +<request> +<service_request_id>123456</service_request_id> +<status>open</status> +<status_notes></status_notes> +<service_name>Sidewalk and Curb Issues</service_name> +<service_code>sidewalks</service_code> +<description>this is a problem</description> +<agency_responsible></agency_responsible> +<service_notice></service_notice> +<requested_datetime>2010-04-14T06:37:38-08:00</requested_datetime> +<updated_datetime>2010-04-14T06:37:38-08:00</updated_datetime> +<expected_datetime>2010-04-15T06:37:38-08:00</expected_datetime> +<lat>51.482286</lat> +<long>-0.328163</long> +<non_public>1</non_public> +</request> +</service_requests> +]; + +for my $test ( + { + desc => 'Hounslow non_public reports not created', + non_public => 1, + count => 0, + }, + { + desc => 'Hounslow public reports are created', + non_public => 0, + count => 1, + }, +) { + subtest $test->{desc} => sub { + (my $xml = $hounslow_non_public_xml) =~ s/non_public>1/non_public>$test->{non_public}/; + + my $o = Open311->new( + jurisdiction => 'mysociety', + endpoint => 'http://example.com', + test_mode => 1, + test_get_returns => { 'requests.xml' => $xml} + ); + + my $update = Open311::GetServiceRequests->new( + system_user => $user, + start_date => $start_date, + end_date => $end_date + ); + + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => [ 'hounslow' ], + }, sub { + $update->create_problems( $o, $hounslow ); + }; + + my $q = FixMyStreet::DB->resultset('Problem')->search( + { external_id => 123456 } + ); + + is $q->count, $test->{count}, 'problem count is correct'; + + $q->first->delete if $test->{count}; + }; +} + +subtest "non_public contacts result in non_public reports" => sub { + + $contact->update({ + non_public => 1 + }); + my $o = Open311->new( + jurisdiction => 'mysociety', + endpoint => 'http://example.com', + test_mode => 1, + test_get_returns => { 'requests.xml' => prepare_xml( {} ) } + ); + + my $update = Open311::GetServiceRequests->new( + system_user => $user, + start_date => $start_date, + end_date => $end_date + ); + + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $update->create_problems( $o, $body ); + }; + + my $p = FixMyStreet::DB->resultset('Problem')->search( + { external_id => 123456 } + )->first; + + ok $p, 'problem created'; + is $p->non_public, 1, "report non_public is set correctly"; + + $p->delete; + $contact->update({ + non_public => 0 + }); + +}; + for my $test ( { test_desc => 'filters out phone numbers', diff --git a/t/open311/populate-service-list.t b/t/open311/populate-service-list.t index ff4c4cf9d..c67fae9bd 100644 --- a/t/open311/populate-service-list.t +++ b/t/open311/populate-service-list.t @@ -225,6 +225,107 @@ subtest 'check conflicting contacts not changed' => sub { is $contact_count, 4, 'correct number of contacts'; }; +subtest 'check new category marked non_public' => sub { + FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->delete(); + + my $services_xml = '<?xml version="1.0" encoding="utf-8"?> + <services> + <service> + <service_code>100</service_code> + <service_name>Cans left out 24x7</service_name> + <description>Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.</description> + <metadata>false</metadata> + <type>realtime</type> + <keywords>private</keywords> + <group>sanitation</group> + </service> + </services> + '; + + my $service_list = get_xml_simple_object( $services_xml ); + + my $processor = Open311::PopulateServiceList->new(); + $processor->_current_body( $body ); + $processor->process_services( $service_list ); + + my $contact_count = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->count(); + is $contact_count, 1, 'correct number of contacts'; + + my $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->first; + is $contact->email, '100', 'email correct'; + is $contact->category, 'Cans left out 24x7', 'category correct'; + is $contact->non_public, 1, 'contact marked as non_public'; +}; + +subtest 'check existing category marked non_public' => sub { + my $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->first; + $contact->update({ + non_public => 0 + }); + is $contact->non_public, 0, 'contact not marked as non_public'; + + my $services_xml = '<?xml version="1.0" encoding="utf-8"?> + <services> + <service> + <service_code>100</service_code> + <service_name>Cans left out 24x7</service_name> + <description>Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.</description> + <metadata>false</metadata> + <type>realtime</type> + <keywords>private</keywords> + <group>sanitation</group> + </service> + </services> + '; + + my $service_list = get_xml_simple_object( $services_xml ); + + my $processor = Open311::PopulateServiceList->new(); + $processor->_current_body( $body ); + $processor->process_services( $service_list ); + + my $contact_count = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->count(); + is $contact_count, 1, 'correct number of contacts'; + + $contact->discard_changes; + is $contact->email, '100', 'email correct'; + is $contact->category, 'Cans left out 24x7', 'category correct'; + is $contact->non_public, 1, 'contact changed to non_public'; +}; + +subtest 'check existing non_public category does not get marked public' => sub { + my $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->first; + is $contact->non_public, 1, 'contact marked as non_public'; + + my $services_xml = '<?xml version="1.0" encoding="utf-8"?> + <services> + <service> + <service_code>100</service_code> + <service_name>Cans left out 24x7</service_name> + <description>Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.</description> + <metadata>false</metadata> + <type>realtime</type> + <keywords></keywords> + <group>sanitation</group> + </service> + </services> + '; + + my $service_list = get_xml_simple_object( $services_xml ); + + my $processor = Open311::PopulateServiceList->new(); + $processor->_current_body( $body ); + $processor->process_services( $service_list ); + + my $contact_count = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->count(); + is $contact_count, 1, 'correct number of contacts'; + + $contact->discard_changes; + is $contact->email, '100', 'email correct'; + is $contact->category, 'Cans left out 24x7', 'category correct'; + is $contact->non_public, 1, 'contact remains non_public'; +}; + for my $test ( { desc => 'check meta data added to existing contact', diff --git a/templates/email/default/login.html b/templates/email/default/login.html index b22838d4e..86bda2464 100644 --- a/templates/email/default/login.html +++ b/templates/email/default/login.html @@ -1,6 +1,6 @@ [% -email_summary = "Click this link to confirm your email address and log into " _ site_name; +email_summary = "Click the link below to confirm your email address and log into " _ site_name; email_columns = 1; PROCESS '_email_settings.html'; diff --git a/templates/email/hounslow/_council_reference.html b/templates/email/hounslow/_council_reference.html new file mode 100644 index 000000000..56944f954 --- /dev/null +++ b/templates/email/hounslow/_council_reference.html @@ -0,0 +1,4 @@ +[% IF problem.external_id ~%] +<p style="[% p_style %]">The report's reference number is <strong>[% problem.external_id %]</strong>. + Please quote this if you need to contact the council about this report.</p> +[%~ END %] diff --git a/templates/email/hounslow/_council_reference.txt b/templates/email/hounslow/_council_reference.txt new file mode 100644 index 000000000..3dd3f1e9f --- /dev/null +++ b/templates/email/hounslow/_council_reference.txt @@ -0,0 +1,2 @@ +[% IF problem.external_id %]The report's reference number is [% problem.external_id %]. Please quote this if +you need to contact the council about this report.[% END %] diff --git a/templates/email/hounslow/_council_reference_alert_update.html b/templates/email/hounslow/_council_reference_alert_update.html new file mode 100644 index 000000000..56944f954 --- /dev/null +++ b/templates/email/hounslow/_council_reference_alert_update.html @@ -0,0 +1,4 @@ +[% IF problem.external_id ~%] +<p style="[% p_style %]">The report's reference number is <strong>[% problem.external_id %]</strong>. + Please quote this if you need to contact the council about this report.</p> +[%~ END %] diff --git a/templates/email/hounslow/_council_reference_alert_update.txt b/templates/email/hounslow/_council_reference_alert_update.txt new file mode 100644 index 000000000..3dd3f1e9f --- /dev/null +++ b/templates/email/hounslow/_council_reference_alert_update.txt @@ -0,0 +1,2 @@ +[% IF problem.external_id %]The report's reference number is [% problem.external_id %]. Please quote this if +you need to contact the council about this report.[% END %] diff --git a/templates/email/hounslow/_email_color_overrides.html b/templates/email/hounslow/_email_color_overrides.html new file mode 100644 index 000000000..b08a92d86 --- /dev/null +++ b/templates/email/hounslow/_email_color_overrides.html @@ -0,0 +1,19 @@ +[% + +color_purple = '#7D2B80' +color_green = '#8BC54F' +color_white = '#fff' + +header_background_color = color_white +header_text_color = color_purple + +secondary_column_background_color = color_white + +button_background_color = color_purple +button_text_color = color_white + +logo_width = "231" # pixel measurement, but without 'px' suffix +logo_height = "102" # pixel measurement, but without 'px' suffix +logo_file = "logo.gif" + +%] diff --git a/templates/email/hounslow/confirm_report_sent.html b/templates/email/hounslow/confirm_report_sent.html new file mode 100644 index 000000000..5a0c19f0d --- /dev/null +++ b/templates/email/hounslow/confirm_report_sent.html @@ -0,0 +1 @@ +[% INCLUDE 'other-reported.html' %]
\ No newline at end of file diff --git a/templates/email/hounslow/confirm_report_sent.txt b/templates/email/hounslow/confirm_report_sent.txt new file mode 100644 index 000000000..72fe01f6d --- /dev/null +++ b/templates/email/hounslow/confirm_report_sent.txt @@ -0,0 +1 @@ +[% INCLUDE 'other-reported.txt' %]
\ No newline at end of file diff --git a/templates/email/hounslow/other-reported.html b/templates/email/hounslow/other-reported.html new file mode 100644 index 000000000..f715a392c --- /dev/null +++ b/templates/email/hounslow/other-reported.html @@ -0,0 +1,31 @@ +[% + +email_summary = "Thanks for logging your report"; +email_columns = 2; + +PROCESS '_email_settings.html'; +INCLUDE '_email_top.html'; + +%] + +<th style="[% td_style %][% primary_column_style %]" id="primary_column"> + [% start_padded_box %] + <h1 style="[% h1_style %]">Your report has been logged</h1> + <p style="[% p_style %]">Your report to [% cobrand.council_name %] has been logged on [% site_name %].</p> +[% IF cobrand.is_council && !cobrand.owns_problem( report ) %] +<p style="[% p_style %]">Please note that [% cobrand.council_name %] is not responsible for this type +of report, so it will instead be sent to [% report.body %].</p> +[% ELSE %] +[% TRY %][% INCLUDE '_council_reference.html' problem=report %][% CATCH file %][% END %] +[% END %] + <p style="margin: 20px auto; text-align: center"> + <a style="[% button_style %]" href="[% cobrand.base_url_for_report(report) %][% report.url %]">View my report</a> + </p> + [% end_padded_box %] +</th> +[% WRAPPER '_email_sidebar.html' object = report %] + <h2 style="[% h2_style %]">[% report.title | html %]</h2> + <p style="[% secondary_p_style %]">[% report.detail | html %]</p> +[% END %] + +[% INCLUDE '_email_bottom.html' %] diff --git a/templates/email/hounslow/other-reported.txt b/templates/email/hounslow/other-reported.txt new file mode 100644 index 000000000..b976c4edc --- /dev/null +++ b/templates/email/hounslow/other-reported.txt @@ -0,0 +1,29 @@ +Subject: Your report has been logged: [% report.title %] + +Hello [% report.name %], + +Your report to [% cobrand.council_name %] has been logged on [% site_name %]. + +[% IF cobrand.is_council && !cobrand.owns_problem( report ) %] +Please note that [% cobrand.council_name %] is not responsible for this type +of report, so it will instead be sent to [% report.body %]. +[% ELSE %] +[% TRY %][% INCLUDE '_council_reference.txt' problem=report %][% CATCH file %][% END %] +[% END %] + +It is available to view at: + +[% cobrand.base_url_for_report(report) %][% report.url %] + +Your report has the title: + +[% report.title %] + +And details: + +[% report.detail %] + +[% signature %] + +This email was sent automatically, from an unmonitored email account - so +please do not reply to it. diff --git a/templates/email/hounslow/submit.html b/templates/email/hounslow/submit.html new file mode 100644 index 000000000..7bc5ce45d --- /dev/null +++ b/templates/email/hounslow/submit.html @@ -0,0 +1,70 @@ +[% + +PROCESS '_email_settings.html'; + +email_summary = "A new problem in your area has been reported by a " _ site_name _ " user."; +email_footer = ""; +email_columns = 2; + +INCLUDE '_email_top.html'; + +%] + +<th style="[% td_style %][% primary_column_style %]" id="primary_column"> + [% start_padded_box %] + <h1 style="[% h1_style %]">New problem in your area</h1> + <p style="[% p_style %]">[% multiple %]A user of [% site_name %] has submitted the following report +of a local problem that they believe might require your attention.</p> + + <p style="margin: 20px auto; text-align: center"> + <a style="[% button_style %]" href="[% url %]">Show full report</a> + </p> + <h2 style="[% h2_style %] margin: 30px 0 10px 0">Reported by:</h2> + <table [% table_reset %]> + <tr> + <th style="[% contact_th_style %]">Name</th> + <td style="[% contact_td_style %]">[% report.name | html %]</td> + </tr> + <tr> + <th style="[% contact_th_style %]">Email</th> + <td style="[% contact_td_style %]"> + [%~ IF report.user.email ~%] + <a href="mailto:[% report.user.email | html %]">[% report.user.email | html %]</a> + [%~ ELSE ~%] + <strong>No email address provided, only phone number</strong> + [%~ END ~%] + </td> + </tr> + [%~ IF report.user.phone %] + <tr> + <th style="[% contact_th_style %]">Phone</th> + <td style="[% contact_td_style %]"><a href="tel:[% report.user.phone | html %]">[% report.user.phone | html %]</a></td> + </tr> + [%~ END %] + </table> + <p style="[% p_style %] margin-top: 0.5em;">Replies to this message will go directly to [% report.name | html %], the user who reported the problem.</p> + [% end_padded_box %] +</th> +[% WRAPPER '_email_sidebar.html' object = report %] + <h2 style="[% h2_style %]">[% report.title | html %]</h2> + [% IF report.external_id %] + <p style="[% secondary_p_style %]"><strong>Enquiry ref:</strong> [% report.external_id | html %]</p> + [% END %] + <p style="[% secondary_p_style %]"><strong>Category:</strong> [% report.category | html %]</p> + <p style="[% secondary_p_style %]">[% report.detail | html %]</p> + [%~ IF additional_information %] + <p style="[% secondary_p_style %]">[% additional_information %]</p> + [%~ END %] + <p style="[% secondary_p_style %]"> + <strong>Location:</strong> + <br>Easting/Northing + [%~ " (IE)" IF coordsyst == "I" ~%] + : [% easting %]/[% northing %] + (<a href="[% osm_url %]" title="View OpenStreetMap of this location"> + [%~ report.latitude %], [% report.longitude ~%] + </a>) + [% IF closest_address %]<br>[% closest_address | trim | replace("\n\n", "<br>") %][% END %] + </p> +[% END %] + +[% INCLUDE '_email_bottom.html' %] diff --git a/templates/email/hounslow/submit.txt b/templates/email/hounslow/submit.txt new file mode 100644 index 000000000..3d9518e53 --- /dev/null +++ b/templates/email/hounslow/submit.txt @@ -0,0 +1,43 @@ +Subject: Problem Report: [% report.title %] + +[% multiple %]A user of +[% site_name %] has submitted the following report +of a local problem that they believe might require your attention. + +[% fuzzy %], or to provide an update on the problem, +please visit the following link: + + [% url %] + +[% has_photo %]---------- + +Name: [% report.name %] + +Email: [% report.user.email OR 'None provided' %] + +Phone: [% report.user.phone OR 'None provided' %] + +[% IF report.external_id %]Enquiry ref: [% report.external_id %][% END %] + +Category: [% report.category %] + +Subject: [% report.title %] + +Details: [% report.detail %] + +[% additional_information %] + +Easting/Northing +[%- " (IE)" IF coordsyst == "I" -%] +: [% easting %]/[% northing %] + +Latitude: [% report.latitude %] + +Longitude: [% report.longitude %] + +View OpenStreetMap of this location: [% osm_url %] + +[% closest_address %]---------- + +Replies to this email will go to the user who submitted the problem. + diff --git a/templates/web/base/report/new/form_user_loggedin.html b/templates/web/base/report/new/form_user_loggedin.html index 37f0c6f0b..1016c5c47 100644 --- a/templates/web/base/report/new/form_user_loggedin.html +++ b/templates/web/base/report/new/form_user_loggedin.html @@ -25,7 +25,7 @@ <option value="another_user">[% loc('Another user') %]</option> [% END %] [% IF js || can_contribute_as_body %] - <option value="body" [% c.user.from_body AND ( c.user.has_body_permission_to('planned_reports') || c.user.has_body_permission_to('default_to_body') ) ? 'selected' : '' %]>[% c.user.from_body.name %]</option> + <option value="body" [% c.user.from_body AND ( c.user.has_body_permission_to('planned_reports') || c.user.has_body_permission_to('default_to_body') ) ? 'selected' : '' %]>[% c.user.from_body.get_cobrand_handler ? c.user.from_body.get_cobrand_handler.council_name : c.user.from_body.name %]</option> [% END %] </select> [% END %] diff --git a/templates/web/fixmystreet.com/footer_extra_js.html b/templates/web/fixmystreet.com/footer_extra_js.html index 61f260fe8..7835e1eac 100644 --- a/templates/web/fixmystreet.com/footer_extra_js.html +++ b/templates/web/fixmystreet.com/footer_extra_js.html @@ -13,6 +13,7 @@ IF bodyclass.match('mappage'); scripts.push( version('/cobrands/lincolnshire/assets.js') ); scripts.push( version('/cobrands/northamptonshire/assets.js') ); scripts.push( version('/cobrands/oxfordshire/assets.js') ); + scripts.push( version('/cobrands/hounslow/assets.js') ); scripts.push( version('/cobrands/highways/assets.js') ); scripts.push( version('/cobrands/fixmystreet-uk-councils/council_validation_rules.js') ); scripts.push( diff --git a/templates/web/hounslow/about/mapterms.html b/templates/web/hounslow/about/mapterms.html new file mode 100644 index 000000000..04c0aeb09 --- /dev/null +++ b/templates/web/hounslow/about/mapterms.html @@ -0,0 +1,24 @@ +[% INCLUDE header.html + title = 'Map Terms and Conditions' +%] + +<h1>Map Terms and Conditions</h1> + +<ul> + <li> + I. You are granted a non-exclusive, royalty free revocable licence + solely to view the licensed data for non-commercial purposes for the + period during which mySociety Ltd. makes it available; + </li> + <li> + II. You are not permitted to copy, sub-license, distribute, sell or + otherwise make available the Licensed Data to third parties in any form; + and + </li> + <li> + III. Third party rights to enforce the terms of this licence shall be + reserved to OS. + </li> +</ul> +[% INCLUDE footer.html %] + diff --git a/templates/web/hounslow/footer_extra_js.html b/templates/web/hounslow/footer_extra_js.html new file mode 100644 index 000000000..ccec09313 --- /dev/null +++ b/templates/web/hounslow/footer_extra_js.html @@ -0,0 +1,11 @@ +[% +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/highways/assets.js'), + version('/cobrands/hounslow/js.js'), + ); +END +%] diff --git a/templates/web/hounslow/header_extra.html b/templates/web/hounslow/header_extra.html new file mode 100644 index 000000000..8a977495f --- /dev/null +++ b/templates/web/hounslow/header_extra.html @@ -0,0 +1 @@ +[% INCLUDE 'tracking_code.html' %] diff --git a/templates/web/hounslow/header_logo.html b/templates/web/hounslow/header_logo.html new file mode 100644 index 000000000..50d896496 --- /dev/null +++ b/templates/web/hounslow/header_logo.html @@ -0,0 +1,2 @@ + <a href="http://www.hounslowhighways.org" id="site-logo">Hounslow Highways</a> + <a href="/" id="report-cta" title="[%- loc('Report a problem') -%]">[%- loc('Report') -%]</a> diff --git a/templates/web/hounslow/report/new/_form_labels.html b/templates/web/hounslow/report/new/_form_labels.html new file mode 100644 index 000000000..971715fa8 --- /dev/null +++ b/templates/web/hounslow/report/new/_form_labels.html @@ -0,0 +1,3 @@ +[% +SET form_title = 'Summarise the problem and location'; +%]
\ No newline at end of file diff --git a/templates/web/hounslow/report/new/after_photo.html b/templates/web/hounslow/report/new/after_photo.html new file mode 100644 index 000000000..e8fac0d2a --- /dev/null +++ b/templates/web/hounslow/report/new/after_photo.html @@ -0,0 +1,8 @@ +<div class="description_tips" aria-label="Tips for perfect photos"> + <ul class="do"> + <li>To help us locate the problem, include both a close-up and a wide shot</li> + </ul> + <ul class="dont"> + <li>Avoid personal information</li> + </ul> +</div> diff --git a/templates/web/hounslow/report/new/councils_text_all.html b/templates/web/hounslow/report/new/councils_text_all.html new file mode 100644 index 000000000..ae2d9191c --- /dev/null +++ b/templates/web/hounslow/report/new/councils_text_all.html @@ -0,0 +1,5 @@ +<p> + These will be sent to <strong>Hounslow Highways</strong> and also published + online for others to see, in accordance with our + <a href="[% c.cobrand.privacy_policy_url %]">privacy policy</a>. +</p> diff --git a/templates/web/hounslow/report/new/top_message.html b/templates/web/hounslow/report/new/top_message.html new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/templates/web/hounslow/report/new/top_message.html diff --git a/templates/web/hounslow/report/update/form_state_checkbox.html b/templates/web/hounslow/report/update/form_state_checkbox.html new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/templates/web/hounslow/report/update/form_state_checkbox.html diff --git a/templates/web/hounslow/report/updates-sidebar-notes.html b/templates/web/hounslow/report/updates-sidebar-notes.html new file mode 100644 index 000000000..606595fc6 --- /dev/null +++ b/templates/web/hounslow/report/updates-sidebar-notes.html @@ -0,0 +1,10 @@ +<p class="box-warning"> +[% IF problem.is_open %] + <strong>Please note: If the problem has worsened, please open a new report instead of updating this one.</strong> +[% ELSE %] + If this problem is still ongoing, please open a new report instead of updating this one. +[% END %] +</p> +<p> + [% loc( 'Your information will only be used in accordance with our <a href="/privacy">privacy policy</a>.' ) %] +</p> diff --git a/templates/web/hounslow/tokens/_confirm_problem_council_id.html b/templates/web/hounslow/tokens/_confirm_problem_council_id.html new file mode 100644 index 000000000..703fbd1b6 --- /dev/null +++ b/templates/web/hounslow/tokens/_confirm_problem_council_id.html @@ -0,0 +1,2 @@ +<h2>Your issue has been sent.</h2> +<p>You will receive an email with a reference number for this report soon, please quote it in any enquiries.</p> diff --git a/templates/web/hounslow/tracking_code.html b/templates/web/hounslow/tracking_code.html new file mode 100644 index 000000000..d5d443560 --- /dev/null +++ b/templates/web/hounslow/tracking_code.html @@ -0,0 +1,15 @@ +[% IF c.config.BASE_URL == "https://www.fixmystreet.com" %] + +<!-- Global Site Tag (gtag.js) - Google Analytics --> +<script async src="https://www.googletagmanager.com/gtag/js?id=UA-136557400-1"></script> +<script> + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + + gtag('config', 'UA-136557400-1'); +</script> + +[% ELSE %] +<!-- Tracking code not inserted as "[% c.config.BASE_URL %]" not "https://www.fixmystreet.com" --> +[% END %] diff --git a/web/cobrands/fixmystreet-uk-councils/roadworks.js b/web/cobrands/fixmystreet-uk-councils/roadworks.js index 05417545d..083f669c8 100644 --- a/web/cobrands/fixmystreet-uk-councils/roadworks.js +++ b/web/cobrands/fixmystreet-uk-councils/roadworks.js @@ -34,11 +34,16 @@ OpenLayers.Format.RoadworksForwardPlanning = OpenLayers.Class(OpenLayers.Format. var results = null; var obj = null; if (typeof json == "string") { - obj = OpenLayers.Format.JSON.prototype.read.apply(this, [json, filter]); + try { + obj = OpenLayers.Format.JSON.prototype.read.apply(this, [json, filter]); + } catch (error) { + OpenLayers.Console.error("Bad JSON: " + error); + return; + } } else { obj = json; } - if(!obj) { + if(!obj || !obj.query) { OpenLayers.Console.error("Bad JSON: " + json); return; } diff --git a/web/cobrands/fixmystreet/staff.js b/web/cobrands/fixmystreet/staff.js index 7dccedcd9..0bbf65aae 100644 --- a/web/cobrands/fixmystreet/staff.js +++ b/web/cobrands/fixmystreet/staff.js @@ -390,7 +390,8 @@ $(fixmystreet).on('display:report', function() { $(fixmystreet).on('report_new:category_change', function(evt, $this) { var category = $this.val(); var prefill_reports = $this.data('prefill'); - var body = $this.data('body'); + var display_names = fixmystreet.reporting_data.display_names || {}; + var body = display_names[ $this.data('body') ] || $this.data('body'); if (prefill_reports) { var title = 'A ' + category + ' problem has been found'; diff --git a/web/cobrands/hounslow/_colours.scss b/web/cobrands/hounslow/_colours.scss new file mode 100644 index 000000000..0a4476720 --- /dev/null +++ b/web/cobrands/hounslow/_colours.scss @@ -0,0 +1,38 @@ +/* COLOURS */ + +$menu-image: 'menu-black'; + +$mappage-header-height: 134px; + +// Primary +$white: #fff; +$purple: rgb(125, 43, 128); +$green: rgb(139, 197, 79); + +// Secondary +$orange: rgb(245,132,35); +$red: rgb(211,17,69); +$blue: rgb(0, 85, 150); +$dark_green: rgb(0, 137, 82); +$magenta: rgb(236, 0, 140); +$cyan: rgb(0, 174, 239); + +$primary: $purple; +//$primary: #dce6f2; // From bexley.gov.uk/services +$primary_b: #222; +$primary_text: $white; + +$base_bg: $white; +$base_fg: #222; + +$nav_background_colour: $white; +$nav_colour: $purple; +$nav_hover_background_colour: darken($purple, 10%); + +$col_click_map: $green; + +$header-top-border: false; + +$heading-font: InfoText, Frutiger, Arial, sans-serif; +$body-font: Frutiger, Arial, sans-serif; +$meta-font: $body-font; diff --git a/web/cobrands/hounslow/assets.js b/web/cobrands/hounslow/assets.js new file mode 100644 index 000000000..e6d3383ff --- /dev/null +++ b/web/cobrands/hounslow/assets.js @@ -0,0 +1,241 @@ +(function(){ + +if (!fixmystreet.maps) { + return; +} + +var defaults = { + http_options: { + url: "https://tilma.mysociety.org/mapserver/hounslow", + params: { + SERVICE: "WFS", + VERSION: "1.1.0", + REQUEST: "GetFeature", + SRSNAME: "urn:ogc:def:crs:EPSG::27700" + } + }, + format_class: OpenLayers.Format.GML.v3.MultiCurveFix, + asset_type: 'spot', + max_resolution: { + 'hounslow': 0.5291677250021167, + 'fixmystreet': 1.194328566789627 + }, + min_resolution: 0.00001, + asset_id_field: 'CentralAssetId', + attributes: { + central_asset_id: 'CentralAssetId', + asset_details: 'FeatureId' + }, + geometryName: 'msGeometry', + srsName: "EPSG:27700", + strategy_class: OpenLayers.Strategy.FixMyStreet, + body: "Hounslow Borough Council" +}; + +fixmystreet.assets.add($.extend(true, {}, defaults, { + http_options: { + params: { + TYPENAME: "bins" + } + }, + asset_category: "Litter Bins", + asset_item: 'bin' +})); + +fixmystreet.assets.add($.extend(true, {}, defaults, { + http_options: { + params: { + TYPENAME: "trees" + } + }, + asset_id_field: 'central_asset_id', + attributes: { + central_asset_id: 'central_asset_id', + asset_details: 'asset_Id' + }, + asset_category: [ + "Tree Danger/Obstruction", + "Branches overhanging", + "Damage By Tree", + "Dead/Dying/Diseased", + "Dying or dangerous tree", + "Empty tree Pit", + "Fallen or leaning tree", + "General Maintenance and pruning", + "Illuminated Traffic signal obstructed by vegetation", + "Traffic signal obstructed by vegetation", + "Pest: Tree/Shrub", + "Pests in trees and shrubs", + "Tree Branches Overhanging", + "Tree Maintenance", + "Tree causing damage to property", + "Tree obstructing street light", + "Trees or shrubs blocking visibility", + "Trees or shrubs causing obstruction of highway", + "Trees" + ], + asset_item: 'tree' +})); + +fixmystreet.assets.add($.extend(true, {}, defaults, { + http_options: { + params: { + TYPENAME: "signs" + } + }, + asset_category: [ + "Sign Obstructed: Vegetation", + "Missing sign", + "Missing/ damaged traffic sign", + "Sign or road marking missing following works", + "Street nameplate damaged", + "Traffic Sign obstructed (vegetation)", + "Unlit sign knocked down" + ], + asset_item: 'sign' +})); + +// "We do not want to show gullies as an asset layer, until we are +// confident that the inventory is accurate." +// https://3.basecamp.com/4020879/buckets/10951425/todos/1780668464 +// fixmystreet.assets.add($.extend(true, {}, defaults, { +// http_options: { +// params: { +// TYPENAME: "gulleys" +// } +// }, +// asset_category: [ +// "Bad smell", +// "Flooding", +// "Blocked gully", +// "Damaged/ cracked drain or man hole cover", +// "Missing drain or man hole cover" +// ], +// asset_item: 'gulley' +// })); + +var pin_prefix = fixmystreet.pin_prefix || document.getElementById('js-map-data').getAttribute('data-pin_prefix'); + +var streetlight_default = { + fillColor: "#FFFF00", + fillOpacity: 0.6, + strokeColor: "#000000", + strokeOpacity: 0.8, + strokeWidth: 2, + pointRadius: 6 +}; + +var streetlight_select = { + externalGraphic: pin_prefix + "pin-spot.png", + fillColor: "#55BB00", + graphicWidth: 48, + graphicHeight: 64, + graphicXOffset: -24, + graphicYOffset: -56, + backgroundGraphic: pin_prefix + "pin-shadow.png", + backgroundWidth: 60, + backgroundHeight: 30, + backgroundXOffset: -7, + backgroundYOffset: -22, + popupYOffset: -40, + graphicOpacity: 1.0, + + label: "${FeatureId}", + labelOutlineColor: "white", + labelOutlineWidth: 3, + labelYOffset: 65, + fontSize: '15px', + fontWeight: 'bold' +}; + +// The label for street light markers should be everything after the final +// '/' in the feature's FeatureId attribute. +// This seems to be the easiest way to perform custom processing +// on style attributes in OpenLayers... +var select_style = new OpenLayers.Style(streetlight_select); +select_style.createLiterals = function() { + var literals = Object.getPrototypeOf(this).createLiterals.apply(this, arguments); + if (literals.label && literals.label.split) { + literals.label = literals.label.split("/").slice(-1)[0]; + } + return literals; +}; + +var streetlight_stylemap = new OpenLayers.StyleMap({ + 'default': new OpenLayers.Style(streetlight_default), + 'select': select_style +}); + +var labeled_defaults = $.extend(true, {}, defaults, { + select_action: true, + stylemap: streetlight_stylemap, + feature_code: 'FeatureId', + actions: { + asset_found: function(asset) { + var id = asset.attributes[this.fixmystreet.feature_code] || ''; + if (id !== '' && id.split) { + var code = id.split("/").slice(-1)[0]; + $('.category_meta_message').html('You have selected column <b>' + code + '</b>'); + } else { + $('.category_meta_message').html('You can pick a <b class="asset-spot">' + this.fixmystreet.asset_item + '</b> from the map »'); + } + }, + asset_not_found: function() { + $('.category_meta_message').html('You can pick a <b class="asset-spot">' + this.fixmystreet.asset_item + '</b> from the map »'); + } + } +}); + +fixmystreet.assets.add($.extend(true, {}, labeled_defaults, { + http_options: { + params: { + TYPENAME: "lighting" + } + }, + asset_category: [ + "Damage to paintwork", + "Damage to paintwork/ column", + "Door Missing/ open", + "Lights too bright/ dull", + "New LED lights not working", + "New LED lights too bright", + "New LED lights too dull", + "Not coming on/ faulty", + "Street light leaning", + "Street light not working", + "Street light on during the day", + "Street light wiring exposed", + "Street lights on during the day", + "Unauthorised sign", + "Veg Obstructed: Street Light", + "Zebra crossing beacon fault" + ], + asset_item: 'light' +})); + +fixmystreet.assets.add($.extend(true, {}, defaults, { + http_options: { + params: { + TYPENAME: "streets" + } + }, + max_resolution: { + 'hounslow': 6.614596562526458, + 'fixmystreet': 4.777314267158508 + }, + always_visible: true, + non_interactive: true, + usrn: { + attribute: 'SITE_CODE', + field: 'site_code' + }, + stylemap: new OpenLayers.StyleMap({ + 'default': new OpenLayers.Style({ + fill: false, + stroke: false + }) + }) +})); + + +})(); diff --git a/web/cobrands/hounslow/base.scss b/web/cobrands/hounslow/base.scss new file mode 100644 index 000000000..a7b14c245 --- /dev/null +++ b/web/cobrands/hounslow/base.scss @@ -0,0 +1,38 @@ +@import "../sass/h5bp"; +@import "./_colours"; +@import "../sass/mixins"; +@import "../sass/base"; + +#site-logo { + width: 115px; + height: 51px; + padding: 0.5em 0; + background: url(/cobrands/hounslow/images/logo.gif) 0 50% no-repeat; + background-size: 115px 51px; +} + +#postcodeForm .form-hint { + color: $white; +} + +#map_box #map { + background-color: white; +} + +.btn-primary, +.green-btn, +.btn--primary { + border: none; + background: $green; + + &:hover, + &:active { + background: lighten($green, 5%); + } +} + +.general-notes { + .box-warning { + font-size: 1.2em; + } +} diff --git a/web/cobrands/hounslow/images/logo.gif b/web/cobrands/hounslow/images/logo.gif Binary files differnew file mode 100644 index 000000000..3bc1019ac --- /dev/null +++ b/web/cobrands/hounslow/images/logo.gif diff --git a/web/cobrands/hounslow/js.js b/web/cobrands/hounslow/js.js new file mode 100644 index 000000000..e8772b691 --- /dev/null +++ b/web/cobrands/hounslow/js.js @@ -0,0 +1,30 @@ +(function(){ + +if (!fixmystreet.maps) { + return; +} + +var org_id = '5540'; +var body = "Hounslow Borough Council"; +fixmystreet.assets.add($.extend(true, {}, fixmystreet.roadworks.layer_future, { + http_options: { params: { organisation_id: org_id } }, + body: body +})); +fixmystreet.assets.add($.extend(true, {}, fixmystreet.roadworks.layer_planned, { + http_options: { params: { organisation_id: org_id } }, + body: body +})); + +if (fixmystreet.cobrand == 'hounslow') { + // We want the cobranded site to always display "Hounslow Highways" + // as the destination for reports in the "Public details" section. + // This is OK because the cobranded site only shows categories which + // Hounslow Highways actually handle. + // Replacing this function with a no-op stops the changes made + // to the cobranded councils_text_all.html from being clobbered and + // the 'correct' (according to bodies set up within FMS) body names + // being shown. + fixmystreet.update_public_councils_text = function() {}; +} + +})(); diff --git a/web/cobrands/hounslow/layout.scss b/web/cobrands/hounslow/layout.scss new file mode 100644 index 000000000..6917305de --- /dev/null +++ b/web/cobrands/hounslow/layout.scss @@ -0,0 +1,21 @@ +@import "_colours"; + +@import "../sass/layout"; + +body.twothirdswidthpage .content .sticky-sidebar aside { + top: 10em; +} + +#site-logo { + width: 231px; + height: 102px; + padding: 1em 0; + background-size: 231px 102px; +} + +// Stop visited nav links being purple when hovering over them +.nav-menu--main { + a:hover { + color: $primary_text; + } +} diff --git a/web/js/map-wmts-hounslow.js b/web/js/map-wmts-hounslow.js new file mode 100644 index 000000000..ea414a3d8 --- /dev/null +++ b/web/js/map-wmts-hounslow.js @@ -0,0 +1,194 @@ +/* + * Maps for FMS using Hounslow Highways' WMTS tile server + */ + +fixmystreet.maps.layer_bounds = new OpenLayers.Bounds( + 500968.38879189314, + 164348.14012837573, + 528802.2803971764, + 185779.43299096148); + +fixmystreet.maps.matrix_ids = [ + // The first 5 levels don't load and are really zoomed-out, so + // they're not included here. + // { + // "identifier": 0, + // "scaleDenominator": 566965.4196450538, + // "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + // "tileWidth": 256, + // "tileHeight": 256, + // "matrixWidth": 142, + // "matrixHeight": 106, + // }, + // { + // "identifier": 1, + // "scaleDenominator": 472471.18303754483, + // "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + // "tileWidth": 256, + // "tileHeight": 256, + // "matrixWidth": 170, + // "matrixHeight": 128, + // }, + // { + // "identifier": 2, + // "scaleDenominator": 377976.9464300358, + // "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + // "tileWidth": 256, + // "tileHeight": 256, + // "matrixWidth": 213, + // "matrixHeight": 159, + // }, + // { + // "identifier": 3, + // "scaleDenominator": 283482.7098225269, + // "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + // "tileWidth": 256, + // "tileHeight": 256, + // "matrixWidth": 283, + // "matrixHeight": 212, + // }, + // { + // "identifier": 4, + // "scaleDenominator": 188988.4732150179, + // "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + // "tileWidth": 256, + // "tileHeight": 256, + // "matrixWidth": 425, + // "matrixHeight": 318, + // }, + { + "identifier": 5, + "scaleDenominator": 94494.23660750895, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 849, + "matrixHeight": 636, + }, + { + "identifier": 6, + "scaleDenominator": 70870.67745563173, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 1132, + "matrixHeight": 848, + }, + { + "identifier": 7, + "scaleDenominator": 47247.118303754476, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 1698, + "matrixHeight": 1272, + }, + { + "identifier": 8, + "scaleDenominator": 23623.559151877238, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 3396, + "matrixHeight": 2543, + }, + { + "identifier": 9, + "scaleDenominator": 9449.423660750896, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 8488, + "matrixHeight": 6358, + }, + { + "identifier": 10, + "scaleDenominator": 7559.538928600717, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 10610, + "matrixHeight": 7947, + }, + { + "identifier": 11, + "scaleDenominator": 5669.654196450538, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 14147, + "matrixHeight": 10596, + }, + { + "identifier": 12, + "scaleDenominator": 3779.7694643003583, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 21220, + "matrixHeight": 15893, + }, + { + "identifier": 13, + "scaleDenominator": 1889.8847321501792, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 42440, + "matrixHeight": 31786, + }, + { + "identifier": 14, + "scaleDenominator": 944.9423660750896, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 84880, + "matrixHeight": 63571, + }, + { + "identifier": 15, + "scaleDenominator": 377.9769464300358, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 212200, + "matrixHeight": 158927, + } +]; + +/* + * maps.config() is called on dom ready in map-OpenLayers.js + * to setup the way the map should operate. + */ +fixmystreet.maps.config = function() { + var permalink_id; + if ($('#map_permalink').length) { + permalink_id = 'map_permalink'; + } + + fixmystreet.controls = [ + new OpenLayers.Control.ArgParserFMS(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PermalinkFMS(permalink_id), + new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' }) + ]; + + /* Linking back to around from report page, keeping track of map moves */ + if ( fixmystreet.page == 'report' ) { + fixmystreet.controls.push( new OpenLayers.Control.PermalinkFMS('key-tool-problems-nearby', '/around') ); + } + + this.setup_wmts_base_map(); +}; + +fixmystreet.maps.marker_size = function() { + var zoom = fixmystreet.map.getZoom() + fixmystreet.zoomOffset; + if (zoom >= 8) { + return 'normal'; + } else if (zoom >= 4) { + return 'small'; + } else { + return 'mini'; + } +}; |