diff options
98 files changed, 3745 insertions, 899 deletions
diff --git a/.cypress/cypress/fixtures/iow_roadworks.json b/.cypress/cypress/fixtures/iow_roadworks.json new file mode 100644 index 000000000..b20dd8514 --- /dev/null +++ b/.cypress/cypress/fixtures/iow_roadworks.json @@ -0,0 +1,97 @@ +{ + "query": { + "recordcount": 38, + "columnlist": "se_id,phase_id,u_se_id,longitude,latitude,gsymbol_id,tooltip,swtype,org_name_disp,promoter,source,promoter_works_ref,originator_ref,swa_org_ref,promoter_org_ref,publisher_orgref,publisher_organisation_id,promoter_organisation_id,organisation_id,lha_id,start_date,end_date,works_state,impact,works_desc,geom_type,geojson_wgs84,tm_cat", + "data": { + "se_id": [ + 114013162 + ], + "phase_id": [ + 1 + ], + "u_se_id": [ + "114013162:1" + ], + "longitude": [ + -1.29574 + ], + "latitude": [ + 50.71086 + ], + "gsymbol_id": [ + "gcln01y" + ], + "tooltip": [ + "B3401 Whitepit Lane, Newport, Isle of Wight\\n18 Jun 2019 - 23 Jul 2019\\ndelays unlikely" + ], + "swtype": [ + "cw" + ], + "org_name_disp": [ + "Island Roads on behalf of the Isle of Wight Council" + ], + "promoter": [ + "Island Roads on behalf of the Isle of Wight Council" + ], + "source": [ + "SW" + ], + "promoter_works_ref": [ + "RF101BT0103000021728" + ], + "originator_ref": [ + "RF101BT0103000021728" + ], + "swa_org_ref": [ + 2114 + ], + "promoter_org_ref": [ + 2114 + ], + "publisher_orgref": [ + 2114 + ], + "publisher_organisation_id": [ + 1062 + ], + "promoter_organisation_id": [ + 1062 + ], + "organisation_id": [ + 1062 + ], + "lha_id": [ + 62 + ], + "start_date": [ + "{ts '2019-06-18 00:00:00'}" + ], + "end_date": [ + "{ts '2030-07-23 23:59:59'}" + ], + "works_state": [ + 4 + ], + "impact": [ + 1 + ], + "works_desc": [ + "Parapet improvement NEWPORT" + ], + "geom_type": [ + 1 + ], + "geojson_wgs84": [ + "{\"type\":\"Point\",\"coordinates\":[-1.295784,50.71086]}" + ], + "tm_cat": [ + "" + ] + } + }, + "reqtoken": "", + "filterimpact": "1,2,3,4", + "filterenddate": "16/10/2019", + "filterstartdate": "16/07/2019", + "timeperiod": "cw" +} diff --git a/.cypress/cypress/integration/isleofwight.js b/.cypress/cypress/integration/isleofwight.js new file mode 100644 index 000000000..daa69f36a --- /dev/null +++ b/.cypress/cypress/integration/isleofwight.js @@ -0,0 +1,35 @@ +describe('When you look at the Island Roads site', function() { + + beforeEach(function() { + cy.server(); + cy.fixture('roads.xml'); + cy.route('/report/new/ajax*').as('report-ajax'); + cy.visit('http://isleofwight.localhost:3001/'); + cy.contains('Island Roads'); + cy.get('[name=pc]').type('PO30 5XJ'); + cy.get('[name=pc]').parents('form').submit(); + }); + + it('uses the correct name', function() { + cy.get('#map_box').click(); + cy.wait('@report-ajax'); + cy.get('select:eq(4)').select('Potholes'); + cy.contains('sent to Island Roads'); + cy.get('select:eq(4)').select('Private'); + cy.contains('sent to Island Roads'); + cy.get('select:eq(4)').select('Extra'); + cy.contains('Help Island Roads'); + }); + + it('displays nearby roadworks', function() { + cy.fixture('iow_roadworks.json'); + cy.route('/data/**', 'fixture:iow_roadworks.json').as('roadworks'); + cy.visit('http://isleofwight.localhost:3001/'); + cy.get('[name=pc]').type('PO30 5XJ'); + cy.get('[name=pc]').parents('form').submit(); + cy.get('#map_box').click(); + cy.wait('@report-ajax'); + cy.wait('@roadworks'); + cy.contains('Roadworks are scheduled near this location'); + }); +}); diff --git a/bin/browser-tests b/bin/browser-tests index 013c0d8d3..0180db0b5 100755 --- a/bin/browser-tests +++ b/bin/browser-tests @@ -11,7 +11,7 @@ my ($cobrand, $coords, $area_id, $name, $mapit_url); BEGIN { $config_file = 'conf/general.yml-example'; - $cobrand = [ 'borsetshire', 'fixmystreet', 'northamptonshire', 'bathnes', 'buckinghamshire', 'hounslow' ]; + $cobrand = [ 'borsetshire', 'fixmystreet', 'northamptonshire', 'bathnes', 'buckinghamshire', 'hounslow', 'isleofwight' ]; $coords = '51.532851,-2.284277'; $area_id = 2608; $name = 'Borsetshire'; @@ -150,7 +150,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,buckinghamshire + --cobrand Cobrand(s) to use, default is fixmystreet,northamptonshire,bathnes,buckinghamshire,isleofwight --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 760c76414..1f6063a47 100755 --- a/bin/fixmystreet.com/fixture +++ b/bin/fixmystreet.com/fixture @@ -99,6 +99,7 @@ if ($opt->test_fixtures) { { area_id => 2257, categories => ['Flytipping', 'Graffiti'], name => 'Chiltern District Council' }, { area_id => 2397, categories => [ 'Graffiti' ], name => 'Northampton Borough Council' }, { area_id => 2483, categories => [ 'Potholes', 'Other' ], name => 'Hounslow Borough Council' }, + { area_id => 2636, categories => [ 'Potholes', 'Private', 'Extra' ], name => 'Isle of Wight Council' }, ) { $bodies->{$_->{area_id}} = FixMyStreet::DB::Factory::Body->find_or_create($_); my $cats = join(', ', @{$_->{categories}}); @@ -144,6 +145,36 @@ if ($opt->test_fixtures) { $child_cat->update({ non_public => 1 }); + + $child_cat = FixMyStreet::DB->resultset("Contact")->find({ + body => $bodies->{2636}, + category => 'Potholes', + }); + $child_cat->update({ + send_method => 'Triage' + }); + $child_cat = FixMyStreet::DB->resultset("Contact")->find({ + body => $bodies->{2636}, + category => 'Private', + }); + $child_cat->update({ + non_public => 1, + send_method => 'Triage' + }); + $child_cat = FixMyStreet::DB->resultset("Contact")->find({ + body => $bodies->{2636}, + category => 'Extra', + }); + $child_cat->update({ + send_method => 'Triage' + }); + $child_cat->set_extra_fields({ + code => 'extra', + datatype => 'string', + order => 1, + variable => 'true', + }); + $child_cat->update; } FixMyStreet::DB::Factory::ResponseTemplate->create({ diff --git a/bin/fixmystreet.com/island_roads_setup_messages b/bin/fixmystreet.com/island_roads_setup_messages new file mode 100644 index 000000000..4969f18ba --- /dev/null +++ b/bin/fixmystreet.com/island_roads_setup_messages @@ -0,0 +1,73 @@ +#!/usr/bin/env perl +# +# One off script to transfer the hardcoded JS messages to the database + +use strict; +use warnings; +use v5.14; + +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../../setenv.pl"; +} + +use FixMyStreet::DB; + +use Getopt::Long; + +my $commit; +GetOptions( + 'commit' => \$commit, +); + +if (!$commit) { + say "*** DRY RUN ***"; +} + +my $urgent = { + order => 0, + required => 'true', + protected => 'true', + code => 'urgent', + description => 'To ensure your report is dealt with effectively, please tell us the severity of the issue:-', + datatype_description => 'You have indicated that the issue requires an urgent response, please phone Island Roads on 01983 822440 so that we can respond to the issue appropriately.', + datatype => 'singlevaluelist', + variable => 'true', + values => [ + { + key => 'urgent', + name => 'The issue requires an urgent response/action', + disable => 1, + }, + { + key => 'not_urgent', + name => 'The issue requires a routine/non-urgent response/action', + } + ], +}; + +my $iow = FixMyStreet::DB->resultset("Body")->find({ name => 'Isle of Wight Council' }); +if ($iow) { + my @iow_contacts = $iow->contacts->search({ send_method => 'Triage' })->all; + foreach my $category (@iow_contacts) { + my $extra_fields = $category->get_extra_fields; + my $found = 0; + foreach (@$extra_fields) { + next unless $_->{code} eq 'urgent'; + $_ = $urgent; + $found = 1; + } + if (!$found) { + push @$extra_fields, $urgent; + } + $category->set_extra_fields(@$extra_fields); + say "Making emergency message disable form on " . $category->category . ", Isle of Wight"; + if ($commit) { + $category->update; + } + } +} else { + say STDERR "Could not find IoW"; +} diff --git a/bin/fixmystreet.com/setup_island_roads_triage_cats b/bin/fixmystreet.com/setup_island_roads_triage_cats new file mode 100755 index 000000000..b747fb99b --- /dev/null +++ b/bin/fixmystreet.com/setup_island_roads_triage_cats @@ -0,0 +1,133 @@ +#!/usr/bin/env perl + +=head1 NAME + +setup_island_roads_triage_cats - create/update triage contacts for Island Roads cobrand + +=head1 DESCRIPTION + +This script creates a set of contacts for Island Road to be used as part of their triage +system. The contacts created all have the `Triage` send_method and so will be displayed +to non staff users. + +It also adds the relevant extra fields to the contacts to enable asset details to be +added to a report created in the category. + +If a contact with the same category already exists that does not have a send_method of +`Triage` then the script will emit a warning. Any existing contacts with the `Triage` +send_method will have their state reset to `confirmed`. + +=cut + +use v5.14; +use warnings; + +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../../setenv.pl"; +} + + +my @cat_list = ( + "Dog Fouling", + "Manholes", + "Trees & Hedges", + "Pavements/footpaths", + "Drainage", + "Car Parking", + "Street Lighting", + "Bus Stops", + "Flyposting", + "Potholes", + "Street Cleaning", + "Bridges & Walls", + "Traffic Lights", + "Street Furniture", + "Roads/Highways", + "Road Traffic Signs & Markings", + "Grass Verges & Weeds", + "Flytipping", + "Graffiti", + "Street Nameplates", + "Abandoned Vehicles" +); + +use FixMyStreet::DB; +use FixMyStreet::Cobrand::IsleOfWight; + +my $iow = FixMyStreet::DB->resultset("Body")->search({ + name => "Isle of Wight Council" +}); + +my $cobrand = FixMyStreet::Cobrand::IsleOfWight->new; + +if ($iow->count != 1) { + die "Could not find IoW body\n"; +} + +$iow = $iow->first; + +for my $cat (@cat_list) { + + my $existing = FixMyStreet::DB->resultset("Contact")->search({ + category => $cat, body_id => $iow->id + })->first; + + if ( $existing ) { + if (!$existing->send_method || $existing->send_method ne 'Triage') { + warn "$cat is not a Triage category\n"; + next; + } + # make sure category is not deleted + $existing->state('confirmed'); + } else { + $existing = FixMyStreet::DB->resultset('Contact')->create({ + name => $cat, + body => $iow, + send_method => 'Triage', + state => 'confirmed', + editor => $0, + note => 'created automatically by script', + }); + } + + my $extra_fields = $existing->get_extra_fields; + my @meta = grep { $_->{code} ne 'central_asset_id' && $_->{code} ne 'site_code'} @$extra_fields; + + push @meta, + { + code => 'central_asset_id', + datatype => 'string', + description => 'central asset id', + order => 100, + required => 'false', + variable => 'true', + automated => 'hidden_field', + }, + { + code => 'asset_details', + datatype => 'string', + description => 'asset details', + order => 100, + required => 'false', + variable => 'true', + automated => 'hidden_field', + }, + { + code => 'site_code', + datatype => 'string', + description => 'site code', + order => 100, + required => 'false', + variable => 'true', + automated => 'hidden_field', + }; + + $cobrand->call_hook( + open311_contact_meta_override => {}, $existing, \@meta); + + $existing->set_extra_fields(@meta); + $existing->update; +} diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 5373220a7..c2c4e7588 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -678,6 +678,9 @@ sub categories_for_point : Private { shift @{$c->stash->{category_options}} if @{$c->stash->{category_options}}; $c->stash->{categories_hash} = { map { $_->category => 1 } @{$c->stash->{category_options}} }; + + $c->forward('/admin/triage/setup_categories'); + } sub alerts_for_report : Private { diff --git a/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm b/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm index 3d5f1084d..fa5a55213 100644 --- a/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm +++ b/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm @@ -396,9 +396,13 @@ sub body_params : Private { ); my %params = map { $_ => $c->get_param($_) || $defaults{$_} } keys %defaults; $c->forward('check_body_params', [ \%params ]); + my @extras = qw/fetch_all_problems/; + my $cobrand_extras = $c->cobrand->call_hook('body_extra_fields'); + push @extras, @$cobrand_extras if $cobrand_extras; + %defaults = map { $_ => '' } @extras; - my %extras = map { $_ => $c->get_param($_) || $defaults{$_} } @extras; + my %extras = map { $_ => $c->get_param("extra[$_]") || $defaults{$_} } @extras; return { params => \%params, extras => \%extras }; } diff --git a/perllib/FixMyStreet/App/Controller/Admin/Triage.pm b/perllib/FixMyStreet/App/Controller/Admin/Triage.pm new file mode 100644 index 000000000..385248cd1 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Admin/Triage.pm @@ -0,0 +1,163 @@ +package FixMyStreet::App::Controller::Admin::Triage; +use Moose; +use namespace::autoclean; + +BEGIN { extends 'Catalyst::Controller'; } + +=head1 NAME + +FixMyStreet::App::Controller::Admin::Triage - Catalyst Controller + +=head1 DESCRIPTION + +Admin pages for triaging reports. + +This allows reports to be triaged before being sent to the council. It works +by having a set of categories with a send_method of Triage which sets the report +state to 'for_triage'. Any reports with the state are then show on '/admin/triage' +which is available to users with the 'triage' permission. + +Clicking on reports on this list will then allow a user to change the category of +the report to one that has an alternative send method, which will trigger the report +to be resent. + +In order for this to work additional work needs to be done to the cobrand to only +display triageable categories to the user. + +=head1 METHODS + +=cut + +sub auto : Private { + my ( $self, $c ) = @_; + + unless ( $c->user->has_body_permission_to('triage') ) { + $c->detach('/page_error_403_access_denied', []); + } +} + +sub index : Path : Args(0) { + my ( $self, $c ) = @_; + + # default sort to oldest + unless ( $c->get_param('sort') ) { + $c->set_param('sort', 'created-asc'); + } + $c->stash->{body} = $c->forward('/reports/body_find', [ $c->cobrand->council_area ]); + $c->forward( 'stash_report_filter_status' ); + $c->forward( '/reports/load_and_group_problems' ); + $c->stash->{page} = 'reports'; # So the map knows to make clickable pins + + if ($c->get_param('ajax')) { + my $ajax_template = $c->stash->{ajax_template} || 'reports/_problem-list.html'; + $c->detach('/reports/ajax', [ $ajax_template ]); + } + + my @categories = $c->stash->{body}->contacts->not_deleted->search( undef, { + columns => [ 'id', 'category', 'extra' ], + distinct => 1, + order_by => [ 'category' ], + } )->all; + $c->stash->{filter_categories} = \@categories; + $c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) }; + my $pins = $c->stash->{pins} || []; + + my %map_params = ( + latitude => @$pins ? $pins->[0]{latitude} : 0, + longitude => @$pins ? $pins->[0]{longitude} : 0, + area => [ $c->stash->{wards} ? map { $_->{id} } @{$c->stash->{wards}} : keys %{$c->stash->{body}->areas} ], + any_zoom => 1, + ); + FixMyStreet::Map::display_map( + $c, %map_params, pins => $pins, + ); +} + +sub stash_report_filter_status : Private { + my ( $self, $c ) = @_; + $c->stash->{filter_problem_states} = { 'for triage' => 1 }; + return 1; +} + +sub setup_categories : Private { + my ( $self, $c ) = @_; + + if ( $c->stash->{problem}->state eq 'for triage' ) { + $c->stash->{holding_options} = [ grep { $_->send_method && $_->send_method eq 'Triage' } @{$c->stash->{category_options}} ]; + $c->stash->{holding_categories} = { map { $_->category => 1 } @{$c->stash->{holding_options}} }; + $c->stash->{end_options} = [ grep { !$_->send_method || $_->send_method ne 'Triage' } @{$c->stash->{category_options}} ]; + $c->stash->{end_categories} = { map { $_->category => 1 } @{$c->stash->{end_options}} }; + delete $c->stash->{categories_hash}; + my %category_groups = (); + for my $category (@{$c->stash->{end_options}}) { + my $group = $category->{group} // $category->get_extra_metadata('group') // ['']; + # this could be an array ref or a string + my @groups = ref $group eq 'ARRAY' ? @$group : ($group); + push( @{$category_groups{$_}}, $category ) for @groups; + } + my @category_groups = (); + for my $group ( grep { $_ ne _('Other') } sort keys %category_groups ) { + push @category_groups, { name => $group, categories => $category_groups{$group} }; + } + $c->stash->{end_groups} = \@category_groups; + } + + return 1; +} + +sub update : Private { + my ($self, $c) = @_; + + my $problem = $c->stash->{problem}; + + my $current_category = $problem->category; + my $new_category = $c->get_param('category'); + + my $changed = $c->forward('/admin/report_edit_category', [ $problem, 1 ] ); + + if ( $changed ) { + $c->stash->{problem}->update( { state => 'confirmed' } ); + $c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'triage' ] ); + + my $name = $c->user->moderating_user_name; + my $extra = { is_superuser => 1 }; + if ($c->user->from_body) { + delete $extra->{is_superuser}; + $extra->{is_body_user} = $c->user->from_body->id; + } + + $extra->{triage_report} = 1; + $extra->{holding_category} = $current_category; + $extra->{new_category} = $new_category; + + my $timestamp = \'current_timestamp'; + my $comment = $problem->add_to_comments( { + text => "Report triaged from $current_category to $new_category", + created => $timestamp, + confirmed => $timestamp, + user_id => $c->user->id, + name => $name, + mark_fixed => 0, + anonymous => 0, + state => 'confirmed', + problem_state => $problem->state, + extra => $extra, + whensent => \'current_timestamp', + } ); + + my @alerts = FixMyStreet::DB->resultset('Alert')->search( { + alert_type => 'new_updates', + parameter => $problem->id, + confirmed => 1, + } ); + + for my $alert (@alerts) { + my $alerts_sent = FixMyStreet::DB->resultset('AlertSent')->find_or_create( { + alert_id => $alert->id, + parameter => $comment->id, + } ); + } + } +} + +1; diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index 203296c4d..ebb3d4839 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -234,12 +234,18 @@ sub check_and_stash_category : Private { my @list_of_names = map { $_->name } values %bodies; my $csv = Text::CSV->new(); $csv->combine(@list_of_names); + $c->stash->{bodies} = \@bodies; $c->{stash}->{list_of_names_as_string} = $csv->string; + my $where = { body_id => [ keys %bodies ], }; + + my $cobrand_where = $c->cobrand->call_hook('munge_around_category_where', $where ); + if ( $cobrand_where ) { + $where = $cobrand_where; + } + my @categories = $c->model('DB::Contact')->not_deleted->search( - { - body_id => [ keys %bodies ], - }, + $where, { columns => [ 'category', 'extra' ], order_by => [ 'category' ], @@ -252,6 +258,7 @@ sub check_and_stash_category : Private { my $categories = [ $c->get_param_list('filter_category', 1) ]; my %valid_categories = map { $_ => 1 } grep { $_ && $categories_mapped{$_} } @$categories; $c->stash->{filter_category} = \%valid_categories; + $c->cobrand->call_hook('munge_around_filter_category_list'); } sub map_features : Private { @@ -312,6 +319,7 @@ sub ajax : Path('/ajax') { my %valid_categories = map { $_ => 1 } $c->get_param_list('filter_category', 1); $c->stash->{filter_category} = \%valid_categories; + $c->cobrand->call_hook('munge_around_filter_category_list'); $c->forward('map_features', [ { bbox => $c->stash->{bbox} } ]); $c->forward('/reports/ajax', [ 'around/on_map_list_items.html' ]); diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 9b90da161..eb6050fde 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -86,7 +86,7 @@ sub display :PathPart('') :Chained('id') :Args(0) { $c->forward( 'format_problem_for_display' ); my $permissions = $c->stash->{_permissions} ||= $c->forward( 'check_has_permission_to', - [ qw/report_inspect report_edit_category report_edit_priority report_mark_private/ ] ); + [ qw/report_inspect report_edit_category report_edit_priority report_mark_private triage/ ] ); if (any { $_ } values %$permissions) { $c->stash->{template} = 'report/inspect.html'; $c->forward('inspect'); @@ -396,7 +396,14 @@ sub inspect : Private { $c->stash->{max_detailed_info_length} = $c->cobrand->max_detailed_info_length; - if ( $c->get_param('save') ) { + if ( $c->get_param('triage') ) { + $c->forward('/auth/check_csrf_token'); + $c->forward('/admin/triage/update'); + my $redirect_uri = $c->uri_for( '/admin/triage' ); + $c->log->debug( "Redirecting to: " . $redirect_uri ); + $c->res->redirect( $redirect_uri ); + } + elsif ( $c->get_param('save') ) { $c->forward('/auth/check_csrf_token'); my $valid = 1; diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 554fbc3b7..9b7a925b8 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -261,15 +261,20 @@ sub category_extras_ajax : Path('category_extras') : Args(0) { sub by_category_ajax_data : Private { my ($self, $c, $type, $category) = @_; - my $bodies = $c->forward('contacts_to_bodies', [ $category ]); - my $list_of_names = [ map { $_->name } ($category ? @$bodies : values %{$c->stash->{bodies_to_list}}) ]; - my $vars = { - $category ? (list_of_names => $list_of_names) : (), - }; + my @bodies; + my $bodies = []; + my $vars = {}; + if ($category) { + $bodies = $c->forward('contacts_to_bodies', [ $category ]); + @bodies = @$bodies; + $vars->{list_of_names} = [ map { $_->cobrand_name } @bodies ]; + } else { + @bodies = values %{$c->stash->{bodies_to_list}}; + } my $non_public = $c->stash->{non_public_categories}->{$category}; my $body = { - bodies => $list_of_names, + bodies => [ map { $_->name } @bodies ], $non_public ? ( non_public => JSON->true ) : (), }; @@ -743,7 +748,7 @@ sub setup_categories_and_bodies : Private { push @category_options, $seen{_('Other')} if $seen{_('Other')}; } - $c->cobrand->call_hook(munge_category_list => \@category_options, \@contacts, \%category_extras); + $c->cobrand->call_hook(munge_report_new_category_list => \@category_options, \@contacts, \%category_extras); # put results onto stash for display $c->stash->{bodies} = \%bodies; diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index 9b33b42b4..741cbb60f 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -165,10 +165,13 @@ sub ward : Path : Args(2) { $c->stash->{stats} = $c->cobrand->get_report_stats(); my @categories = $c->stash->{body}->contacts->not_deleted->search( undef, { - columns => [ 'id', 'category', 'extra' ], + columns => [ 'id', 'category', 'extra', 'body_id', 'send_method' ], distinct => 1, order_by => [ 'category' ], } )->all; + + $c->cobrand->call_hook('munge_reports_category_list', \@categories); + $c->stash->{filter_categories} = \@categories; $c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) }; @@ -702,8 +705,9 @@ sub stash_report_filter_status : Private { my @status = $c->get_param_list('status', 1); @status = ($c->stash->{page} eq 'my' ? 'all' : $c->cobrand->on_map_default_status) unless @status; - my %status = map { $_ => 1 } @status; + $c->cobrand->call_hook(hook_report_filter_status => \@status); + my %status = map { $_ => 1 } @status; my %filter_problem_states; my %filter_status; diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm index e5327b084..38e9e09a0 100644 --- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm +++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm @@ -7,6 +7,7 @@ use warnings; use mySociety::Random; use constant COUNCIL_ID_BROMLEY => 2482; +use constant COUNCIL_ID_ISLEOFWIGHT => 2636; sub on_map_default_status { return 'open'; } @@ -37,13 +38,116 @@ sub restriction { return {}; } -sub munge_category_list { +sub munge_around_category_where { + my ($self, $where) = @_; + + my $user = $self->{c}->user; + my @iow = grep { $_->name eq 'Isle of Wight Council' } @{ $self->{c}->stash->{bodies} }; + return unless @iow; + + # display all the categories on Isle of Wight at the moment as there's no way to + # do the expand bit later as we fetch it using ajax which uses a bounding box so + # can't determine the body + $where->{send_method} = [ { '!=' => 'Triage' }, undef ]; + return $where; +} + +sub munge_reports_categories_list { + my ($self, $categories) = @_; + + my %bodies = map { $_->body->name => $_->body } @$categories; + if ( $bodies{'Isle of Wight Council'} ) { + my $user = $self->{c}->user; + my $b = $bodies{'Isle of Wight Council'}; + + if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) { + @$categories = grep { !$_->send_method || $_->send_method ne 'Triage' } @$categories; + return @$categories; + } + + @$categories = grep { $_->send_method && $_->send_method eq 'Triage' } @$categories; + return @$categories; + } +} + +sub munge_report_new_category_list { my ($self, $options, $contacts, $extras) = @_; # No TfL Traffic Lights category in Hounslow - my %bodies = map { $_->body->name => 1 } @$contacts; - return unless $bodies{'Hounslow Borough Council'}; - @$options = grep { ($_->{category} || $_->category) !~ /^Traffic lights$/i } @$options; + my %bodies = map { $_->body->name => $_->body } @$contacts; + if ( $bodies{'Hounslow Borough Council'} ) { + @$options = grep { ($_->{category} || $_->category) !~ /^Traffic lights$/i } @$options; + } + + if ( $bodies{'Isle of Wight Council'} ) { + my $user = $self->{c}->user; + if ( $user && ( $user->is_superuser || $user->belongs_to_body( $bodies{'Isle of Wight Council'}->id ) ) ) { + @$contacts = grep { !$_->send_method || $_->send_method ne 'Triage' } @$contacts; + my $seen = { map { $_->category => 1 } @$contacts }; + @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options; + return; + } + + @$contacts = grep { $_->send_method && $_->send_method eq 'Triage' } @$contacts; + my $seen = { map { $_->category => 1 } @$contacts }; + @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options; + } +} + +sub munge_load_and_group_problems { + my ($self, $where, $filter) = @_; + + return unless $where->{category} && $self->{c}->stash->{body}->name eq 'Isle of Wight Council'; + + my $cat_names = $self->expand_triage_cat_list($where->{category}); + + $where->{category} = $cat_names; + my $problems = $self->problems->search($where, $filter); + return $problems; +} + +sub expand_triage_cat_list { + my ($self, $categories) = @_; + + my $b = $self->{c}->stash->{body}; + + my $all_cats = $self->{c}->model('DB::Contact')->not_deleted->search( + { + body_id => $b->id, + send_method => [{ '!=', 'Triage'}, undef] + } + ); + + my %group_to_category; + while ( my $cat = $all_cats->next ) { + next unless $cat->get_extra_metadata('group'); + my $groups = $cat->get_extra_metadata('group'); + $groups = ref $groups eq 'ARRAY' ? $groups : [ $groups ]; + for my $group ( @$groups ) { + $group_to_category{$group} //= []; + push @{ $group_to_category{$group} }, $cat->category; + } + } + + my $cats = $self->{c}->model('DB::Contact')->not_deleted->search( + { + body_id => $b->id, + category => $categories + } + ); + + my @cat_names; + while ( my $cat = $cats->next ) { + if ( $cat->send_method && $cat->send_method eq 'Triage' ) { + # include the category itself + push @cat_names, $cat->category; + push @cat_names, @{ $group_to_category{$cat->category} } if $group_to_category{$cat->category}; + } else { + push @cat_names, $cat->category; + } + } + + return \@cat_names; } sub title_list { diff --git a/perllib/FixMyStreet/Cobrand/IsleOfWight.pm b/perllib/FixMyStreet/Cobrand/IsleOfWight.pm new file mode 100644 index 000000000..49356e3ae --- /dev/null +++ b/perllib/FixMyStreet/Cobrand/IsleOfWight.pm @@ -0,0 +1,236 @@ +package FixMyStreet::Cobrand::IsleOfWight; +use parent 'FixMyStreet::Cobrand::Whitelabel'; + +use strict; +use warnings; + +sub council_area_id { 2636 } +sub council_area { 'Isle of Wight' } +sub council_name { 'Island Roads' } +sub council_url { 'isleofwight' } +sub all_reports_single_body { { name => "Isle of Wight Council" } } +sub link_to_council_cobrand { "Island Roads" } + +sub enter_postcode_text { + my ($self) = @_; + return 'Enter an ' . $self->council_area . ' postcode, or street name and area'; +} + +sub admin_user_domain { ('islandroads.com') } + +sub on_map_default_status { 'open' } + +sub send_questionnaires { 0 } + +sub report_sent_confirmation_email { 'external_id' } + +sub map_type { 'IsleOfWight' } + +sub disambiguate_location { + my $self = shift; + my $string = shift; + + return { + %{ $self->SUPER::disambiguate_location() }, + centre => '50.675761,-1.296571', + bounds => [ 50.574653, -1.591732, 50.767567, -1.062957 ], + }; +} + +sub updates_disallowed { + my ($self, $problem) = @_; + + my $c = $self->{c}; + return 0 if $c->user_exists && $c->user->id eq $problem->user->id; + return 1; +} + +sub get_geocoder { 'OSM' } + +sub open311_pre_send { + my ($self, $row, $open311) = @_; + + return unless $row->extra; + my $extra = $row->get_extra_fields; + if (@$extra) { + @$extra = grep { $_->{name} ne 'urgent' } @$extra; + $row->set_extra_fields(@$extra); + } +} + +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 }; + + $row->set_extra_fields(@$extra); +} + +# Make sure fetched report description isn't shown. +sub filter_report_description { "" } + +sub open311_munge_update_params { + my ($self, $params, $comment, $body) = @_; + + if ($comment->mark_fixed) { + $params->{description} = "[The customer indicated that this issue had been fixed]\n\n" . $params->{description}; + } + + if ( $comment->get_extra_metadata('triage_report') ) { + $params->{description} = "Triaged by " . $comment->user->name . ' (' . $comment->user->email . "). " . $params->{description}; + } + + $params->{description} = "FMS-Update: " . $params->{description}; +} + +# this handles making sure the user sees the right categories on the new report page +sub munge_reports_category_list { + my ($self, $categories) = @_; + + my $user = $self->{c}->user; + my %bodies = map { $_->body->name => $_->body } @$categories; + my $b = $bodies{'Isle of Wight Council'}; + + if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) { + @$categories = grep { !$_->send_method || $_->send_method ne 'Triage' } @$categories; + return @$categories; + } + + @$categories = grep { $_->send_method && $_->send_method eq 'Triage' } @$categories; + return @$categories; +} + +sub munge_report_new_category_list { + my ($self, $options, $contacts, $extras) = @_; + + my $user = $self->{c}->user; + my %bodies = map { $_->body->name => $_->body } @$contacts; + my $b = $bodies{'Isle of Wight Council'}; + + if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) { + @$contacts = grep { !$_->send_method || $_->send_method ne 'Triage' } @$contacts; + my $seen = { map { $_->category => 1 } @$contacts }; + @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options; + return; + } + + @$contacts = grep { $_->send_method && $_->send_method eq 'Triage' } @$contacts; + my $seen = { map { $_->category => 1 } @$contacts }; + @$options = grep { my $c = ($_->{category} || $_->category); $c =~ 'Pick a category' || $seen->{ $c } } @$options; +} + +sub munge_around_category_where { + my ($self, $where) = @_; + + my $user = $self->{c}->user; + my $b = $self->{c}->model('DB::Body')->for_areas( $self->council_area_id )->first; + if ( $user && ( $user->is_superuser || $user->belongs_to_body( $b->id ) ) ) { + $where->{send_method} = [ { '!=' => 'Triage' }, undef ]; + return $where; + } + + $where->{'send_method'} = 'Triage'; + return $where; +} + +sub munge_load_and_group_problems { + my ($self, $where, $filter) = @_; + + return unless $where->{category}; + + my $cat_names = $self->expand_triage_cat_list($where->{category}); + + $where->{category} = $cat_names; + my $problems = $self->problems->search($where, $filter); + return $problems; +} + +sub munge_around_filter_category_list { + my $self = shift; + + my $c = $self->{c}; + return unless $c->stash->{filter_category}; + + my $cat_names = $self->expand_triage_cat_list([ keys %{$c->stash->{filter_category}} ]); + $c->stash->{filter_category} = { map { $_ => 1 } @$cat_names }; +} + +# this assumes that each Triage category has the same name as a group +# and uses this to generate a list of categories that a triage category +# could be triaged to +sub expand_triage_cat_list { + my ($self, $categories) = @_; + + my $b = $self->{c}->model('DB::Body')->for_areas( $self->council_area_id )->first; + + my $all_cats = $self->{c}->model('DB::Contact')->not_deleted->search( + { + body_id => $b->id, + send_method => [{ '!=', 'Triage'}, undef] + } + ); + + my %group_to_category; + while ( my $cat = $all_cats->next ) { + next unless $cat->get_extra_metadata('group'); + my $groups = $cat->get_extra_metadata('group'); + $groups = ref $groups eq 'ARRAY' ? $groups : [ $groups ]; + for my $group ( @$groups ) { + $group_to_category{$group} //= []; + push @{ $group_to_category{$group} }, $cat->category; + } + } + + my $cats = $self->{c}->model('DB::Contact')->not_deleted->search( + { + body_id => $b->id, + category => $categories + } + ); + + my @cat_names; + while ( my $cat = $cats->next ) { + if ( $cat->send_method eq 'Triage' ) { + # include the category itself + push @cat_names, $cat->category; + push @cat_names, @{ $group_to_category{$cat->category} } if $group_to_category{$cat->category}; + } else { + push @cat_names, $cat->category; + } + } + + return \@cat_names; +} + +sub open311_get_update_munging { + my ($self, $comment) = @_; + + # If we've received an update via Open311 that's closed + # or fixed the report, also close it to updates. + $comment->problem->set_extra_metadata(closed_updates => 1) + if !$comment->problem->is_open; +} + +sub admin_pages { + my $self = shift; + my $pages = $self->next::method(); + $pages->{triage} = [ undef, undef ]; + return $pages; +} + +sub available_permissions { + my $self = shift; + + my $perms = $self->next::method(); + $perms->{Problems}->{triage} = "Triage reports"; + + return $perms; +} +1; diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm index 9f4610143..5f45609bb 100644 --- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm +++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm @@ -179,7 +179,11 @@ sub reports_body_check { } # We want to make sure we're only on our page. - unless ( $self->council_name =~ /^\Q$code\E/ ) { + my $council_name = $self->council_name; + if (my $override = $self->all_reports_single_body) { + $council_name = $override->{name}; + } + unless ( $council_name =~ /^\Q$code\E/ ) { $c->res->redirect( 'https://www.fixmystreet.com' . $c->req->uri->path_query, 301 ); $c->detach(); } diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 5fea9a03f..9cf1030f0 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -9,6 +9,8 @@ use Scalar::Util 'blessed'; use DateTime::Format::Pg; use Try::Tiny; +use FixMyStreet::Geocode::Zurich; + use strict; use warnings; use utf8; @@ -141,7 +143,7 @@ sub problem_as_hashref { $hashref->{title} = _('This report is awaiting moderation.'); $hashref->{banner_id} = 'closed'; } else { - if ( $problem->state eq 'confirmed' || $problem->state eq 'external' ) { + if ( $problem->state eq 'confirmed' ) { $hashref->{banner_id} = 'closed'; } elsif ( $problem->is_fixed || $problem->is_closed ) { $hashref->{banner_id} = 'fixed'; @@ -152,7 +154,7 @@ sub problem_as_hashref { if ( $problem->state eq 'confirmed' ) { $hashref->{state} = 'open'; $hashref->{state_t} = _('Open'); - } elsif ( $problem->state eq 'wish' ) { + } elsif ( $problem->state eq 'wish' || $problem->state eq 'external' ) { $hashref->{state_t} = _('Closed'); } elsif ( $problem->is_fixed ) { $hashref->{state} = 'closed'; @@ -329,6 +331,14 @@ sub report_page_data { $c->detach('ajax', [ 'reports/_problem-list.html' ]); } + my @categories = $c->model('DB::Contact')->not_deleted->search(undef, { + columns => [ 'category', 'extra' ], + order_by => [ 'category' ], + distinct => 1 + })->all; + $c->stash->{filter_categories} = \@categories; + $c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) }; + my $pins = $c->stash->{pins}; FixMyStreet::Map::display_map( $c, @@ -522,12 +532,16 @@ sub admin { } sub category_options { - my ($self, $c) = @_; + my $self = shift; + my $c = $self->{c}; my @categories = $c->model('DB::Contact')->not_deleted->all; - $c->stash->{category_options} = [ map { { - category => $_->category, category_display => $_->category, + @categories = map { { + category => $_->category, + category_display => $_->get_extra_metadata('admin_label') || $_->category, abbreviation => $_->get_extra_metadata('abbreviation'), - } } @categories ]; + } } @categories; + @categories = sort { $a->{category_display} cmp $b->{category_display} } @categories; + $c->stash->{category_options} = \@categories; } sub admin_report_edit { @@ -553,21 +567,39 @@ sub admin_report_edit { $c->stash->{bodies} = \@bodies; # Can change category to any other - $self->category_options($c); + $self->category_options; } elsif ($type eq 'dm') { # Can assign to: my @bodies = $c->model('DB::Body')->search( [ - { 'me.parent' => $body->parent->id }, # Other DMs on the same level { 'me.parent' => $body->id }, # Their subdivisions { 'me.parent' => undef, 'bodies.id' => undef }, # External bodies - ], { join => 'bodies', distinct => 1 } ); - @bodies = sort { strcoll($a->name, $b->name) } @bodies; + ], { join => 'bodies', distinct => 1 } )->all; + @bodies = grep { + my $cat = $_->get_extra_metadata('category'); + if ($cat) { + $cat = $c->model('DB::Contact')->not_deleted->search({ category => $cat })->first; + } + !$cat || $cat->body_id == $body->id; + } @bodies; + @bodies = sort { + my $a_cat = $a->get_extra_metadata('category'); + my $b_cat = $b->get_extra_metadata('category'); + if ($a_cat && $b_cat) { + strcoll($a->name, $b->name) + } elsif ($a_cat) { + -1; + } elsif ($b_cat) { + 1; + } else { + strcoll($a->name, $b->name) + } + } @bodies; $c->stash->{bodies} = \@bodies; # Can change category to any other - $self->category_options($c); + $self->category_options; } @@ -927,6 +959,11 @@ sub admin_report_edit { } +sub admin_district_lookup { + my ($self, $row) = @_; + FixMyStreet::Geocode::Zurich::admin_district($row->local_coords); +} + sub stash_states { my ($self, $problem) = @_; my $c = $self->{c}; @@ -1135,7 +1172,7 @@ sub admin_stats { } # Can change category to any other - $self->category_options($c); + $self->category_options; # Total reports (non-hidden) my $total = $c->model('DB::Problem')->search( \%params )->count; @@ -1305,7 +1342,9 @@ sub reports_per_page { return 20; } sub singleton_bodies_str { 1 } -sub contact_extra_fields { [ 'abbreviation' ] }; +sub body_extra_fields { [ 'category' ] }; + +sub contact_extra_fields { [ 'abbreviation', 'admin_label' ] }; sub default_problem_state { 'submitted' } @@ -1343,4 +1382,11 @@ sub db_state_migration { } } +sub hook_report_filter_status { + my ($self, $status) = @_; + @$status = map { + $_ eq 'closed' ? ('closed', 'fixed') : $_ + } @$status; +} + 1; diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm index 39f446549..1ffcc7b40 100644 --- a/perllib/FixMyStreet/DB/Result/Comment.pm +++ b/perllib/FixMyStreet/DB/Result/Comment.pm @@ -231,6 +231,8 @@ sub meta_line { $body = "$body <img src='/cobrands/greenwich/favicon.png' alt=''>"; } elsif ($body eq 'Hounslow Borough Council') { $body = 'Hounslow Highways'; + } elsif ($body eq 'Isle of Wight Council') { + $body = 'Island Roads'; } } my $cobrand_always_view_body_user = $c->cobrand->call_hook("always_view_body_contribute_details"); diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 8159d7251..08b768719 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -751,7 +751,7 @@ sub defect_types { # Note: this only makes sense when called on a problem that has been sent! sub can_display_external_id { my $self = shift; - if ($self->external_id && $self->to_body_named('Oxfordshire|Lincolnshire')) { + if ($self->external_id && $self->to_body_named('Oxfordshire|Lincolnshire|Isle of Wight')) { return 1; } return 0; diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm index 51f959e0e..85fdc790b 100644 --- a/perllib/FixMyStreet/DB/Result/User.pm +++ b/perllib/FixMyStreet/DB/Result/User.pm @@ -317,7 +317,11 @@ sub body { sub moderating_user_name { my $self = shift; - return $self->body || _('an administrator'); + my $body = $self->body; + if ( $body && $body eq 'Isle of Wight Council' ) { + $body = 'Island Roads'; + } + return $body || _('an administrator'); } =head2 belongs_to_body diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm index 38df431c9..0b85ab7b2 100644 --- a/perllib/FixMyStreet/Geocode/Zurich.pm +++ b/perllib/FixMyStreet/Geocode/Zurich.pm @@ -24,6 +24,8 @@ sub setup_soap { # Variables for the SOAP web service my $geocoder = FixMyStreet->config('GEOCODER'); + return unless ref $geocoder eq 'HASH'; + my $url = $geocoder->{url}; my $username = $geocoder->{username}; my $password = $geocoder->{password}; @@ -49,6 +51,34 @@ sub setup_soap { $method = SOAP::Data->name('getLocation95')->attr({ xmlns => $attr }); } +sub admin_district { + my ($e, $n) = @_; + + setup_soap(); + return unless $soap; + + my $attr = 'http://ch/geoz/fixmyzuerich/service'; + my $bo = 'http://ch/geoz/fixmyzuerich/bo'; + my $method = SOAP::Data->name('getInfoByLocation')->attr({ xmlns => $attr }); + my $location = SOAP::Data->name( + 'location' => \SOAP::Data->value( + SOAP::Data->name('bo:easting', $e), + SOAP::Data->name('bo:northing', $n), + ) + )->attr({ 'xmlns:bo' => $bo }); + my $search = SOAP::Data->value($location); + my $result; + eval { + $result = $soap->call($method, $security, $search); + }; + if ($@) { + warn $@ if FixMyStreet->config('STAGING_SITE'); + return 'The geocoder appears to be down.'; + } + $result = $result->result; + return $result; +} + # string STRING CONTEXT # Looks up on Zurich web service a user-inputted location. # Returns array of (LAT, LON, ERROR), where ERROR is either undef, a string, or diff --git a/perllib/FixMyStreet/Map/IsleOfWight.pm b/perllib/FixMyStreet/Map/IsleOfWight.pm new file mode 100644 index 000000000..2316e2939 --- /dev/null +++ b/perllib/FixMyStreet/Map/IsleOfWight.pm @@ -0,0 +1,63 @@ +# FixMyStreet:Map::IsleOfWight +# IsleOfWight use their own tiles on their cobrand + +package FixMyStreet::Map::IsleOfWight; +use base 'FixMyStreet::Map::UKCouncilWMTS'; + +use strict; + +sub default_zoom { 7; } + +sub urls { [ 'https://gis.ringway.co.uk/server/rest/services/Hosted/IOW_OS/MapServer/WMTS/tile' ] } + +sub layer_names { [ 'Hosted_IOW_OS' ] } + +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 100019229. Use of this data is subject to <a href="/about/mapterms">terms and conditions</a>.'; +} + + +sub map_javascript { [ + '/vendor/OpenLayers/OpenLayers.wmts.js', + '/js/map-OpenLayers.js', + '/js/map-wmts-base.js', + '/js/map-wmts-isleofwight.js', +] } + +1; diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm index 6cd9afccd..09847cf5f 100644 --- a/perllib/FixMyStreet/SendReport/Email.pm +++ b/perllib/FixMyStreet/SendReport/Email.pm @@ -53,6 +53,15 @@ sub send_from { return [ $row->user->email, $row->name ]; } +sub envelope_sender { + my ($self, $row) = @_; + + if ($row->user->email && $row->user->email_verified) { + return FixMyStreet::Email::unique_verp_id('report', $row->id); + } + return FixMyStreet->config('DO_NOT_REPLY_EMAIL'); +} + sub send { my $self = shift; my ( $row, $h ) = @_; @@ -82,12 +91,10 @@ sub send { $params->{Bcc} = $self->bcc if @{$self->bcc}; - my $sender; + my $sender = $self->envelope_sender($row); if ($row->user->email && $row->user->email_verified) { - $sender = FixMyStreet::Email::unique_verp_id('report', $row->id); $params->{From} = $self->send_from( $row ); } else { - $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL'); my $name = sprintf(_("On behalf of %s"), @{ $self->send_from($row) }[1]); $params->{From} = [ $sender, $name ]; } diff --git a/perllib/FixMyStreet/SendReport/Triage.pm b/perllib/FixMyStreet/SendReport/Triage.pm new file mode 100644 index 000000000..38341f3ff --- /dev/null +++ b/perllib/FixMyStreet/SendReport/Triage.pm @@ -0,0 +1,20 @@ +package FixMyStreet::SendReport::Triage; + +use Moo; + +BEGIN { extends 'FixMyStreet::SendReport'; } + +sub send { + my $self = shift; + my ( $row, $h ) = @_; + + $row->update({ + state => 'for triage' + }); + + $self->success(1); + + return 0; +} + +1; diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index 16871d0f2..927e4556c 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -229,6 +229,17 @@ sub get_email { return $emails[0]; } +sub get_email_envelope { + my $mech = shift; + my @emails = FixMyStreet::Email::Sender->default_transport->deliveries; + @emails = map { $_->{envelope} } @emails; + + return @emails if wantarray; + + $mech->email_count_is(1) || return undef; + return $emails[0]; +} + sub get_text_body_from_email { my ($mech, $email, $obj) = @_; unless ($email) { diff --git a/perllib/Open311/PostServiceRequestUpdates.pm b/perllib/Open311/PostServiceRequestUpdates.pm index 1f080b168..14bebfcb7 100755 --- a/perllib/Open311/PostServiceRequestUpdates.pm +++ b/perllib/Open311/PostServiceRequestUpdates.pm @@ -14,6 +14,7 @@ use Open311; use constant SEND_METHOD_OPEN311 => 'Open311'; has verbose => ( is => 'ro', default => 0 ); +has current_open311 => ( is => 'rw' ); sub send { my $self = shift; @@ -26,6 +27,7 @@ sub send { while ( my $body = $bodies->next ) { my $cobrand = $body->get_cobrand_handler; next if $cobrand && $cobrand->call_hook('open311_post_update_skip'); + $self->current_open311(Open311->new($self->open311_params($body))); $self->process_body($body); } } @@ -51,8 +53,6 @@ sub open311_params { sub process_body { my ($self, $body) = @_; - my $o = Open311->new( $self->open311_params($body) ); - my $comments = FixMyStreet::DB->resultset('Comment')->to_body($body)->search( { 'me.whensent' => undef, 'me.external_id' => undef, @@ -82,12 +82,14 @@ sub process_body { next if !$self->verbose && $comment->send_fail_count && retry_timeout($comment); - $self->process_update($body, $o, $comment, $cobrand); + $self->process_update($body, $comment, $cobrand); } } sub process_update { - my ($self, $body, $o, $comment, $cobrand) = @_; + my ($self, $body, $comment, $cobrand) = @_; + + my $o = $self->current_open311; $cobrand->call_hook(open311_pre_send => $comment, $o); diff --git a/t/Mock/MapIt.pm b/t/Mock/MapIt.pm index b5cc694df..8b8bb5978 100644 --- a/t/Mock/MapIt.pm +++ b/t/Mock/MapIt.pm @@ -49,6 +49,7 @@ my @PLACES = ( [ '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' ], [ 'WS1 4NH', 52.563074, -1.991032, 2535, 'Sandwell Borough Council', 'MTD' ], + [ 'PO30 5XJ', 50.71086, -1.29573, 2636, 'Isle of Wight Council', 'UTA' ], [ 'OX28 4DS', 51.784721, -1.494453 ], [ 'E14 2DN', 51.508536, '0.000001' ], # Norway diff --git a/t/app/controller/admin/bodies.t b/t/app/controller/admin/bodies.t index c1072eb15..75f0f606f 100644 --- a/t/app/controller/admin/bodies.t +++ b/t/app/controller/admin/bodies.t @@ -162,7 +162,7 @@ subtest 'check open311 configuring' => sub { jurisdiction => 'open311', send_comments => 0, send_method => 'Open311', - fetch_all_problems => 1, + 'extra[fetch_all_problems]' => 1, } } ); @@ -181,7 +181,7 @@ subtest 'check open311 configuring' => sub { jurisdiction => 'open311', send_comments => 0, send_method => 'Open311', - fetch_all_problems => 0, + 'extra[fetch_all_problems]' => 0, can_be_devolved => 1, # for next test } } diff --git a/t/app/controller/admin/triage.t b/t/app/controller/admin/triage.t new file mode 100644 index 000000000..6c84d1ff4 --- /dev/null +++ b/t/app/controller/admin/triage.t @@ -0,0 +1,126 @@ +use FixMyStreet::TestMech; +use FixMyStreet::Script::Alerts; + +my $mech = FixMyStreet::TestMech->new; + +my $user = $mech->create_user_ok('test@example.com', name => 'Test User'); +my $user2 = $mech->create_user_ok('test2@example.com', name => 'Test User 2'); +my $superuser = $mech->create_user_ok( + 'superuser@example.com', + name => 'Super User', + is_superuser => 1 +); + +my $iow = $mech->create_body_ok(2636, 'Isle of Wight Council', { can_be_devolved => 1 } ); +my $iow_contact = $mech->create_contact_ok( + body_id => $iow->id, + category => 'Potholes', + email => 'potholes@example.com', + send_method => 'Triage' +); +$mech->create_contact_ok( + body_id => $iow->id, + category => 'Traffic lights', + email => 'lights@example.com' +); + +my $dt = DateTime->now(); + +my ($report) = $mech->create_problems_for_body( + 1, + $iow->id, + 'TITLE', + { + areas => 2636, + category => 'Potholes', + whensent => $dt, + latitude => 50.71086, + longitude => -1.29573, + send_method_used => 'Triage', + } +); + +FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1, skip_checks => 0 }, + ALLOWED_COBRANDS => [ 'isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', +}, sub { + subtest "user can access triage page with triage permission" => sub { + $user->update({ from_body => $iow }); + $mech->log_out_ok; + $mech->get_ok('/admin/triage'); + + $mech->log_in_ok($user->email); + $mech->get('/admin/triage'); + is $mech->res->code, 403, 'permission denied'; + + $user->user_body_permissions->create( { body => $iow, permission_type => 'triage' } ); + $mech->get_ok('/admin/triage'); + }; + + subtest "reports marked for triage show triage interface" => sub { + $mech->log_out_ok; + $mech->log_in_ok( $user->email ); + + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('CONFIRM Subject'); + + $report->update( { state => 'for triage' } ); + + $mech->get_ok('/report/' . $report->id); + $mech->content_contains('CONFIRM Subject'); + }; + + subtest "changing report category marks report as confirmed" => sub { + my $report_url = '/report/' . $report->id; + $mech->get_ok($report_url); + + my $alert = FixMyStreet::App->model('DB::Alert')->create( + { + user => $user2, + alert_type => 'new_updates', + parameter => $report->id, + parameter2 => '', + confirmed => 1, + } + ); + + $mech->content_contains('Traffic lights'); + + $mech->submit_form_ok( { + with_fields => { + category => 'Traffic lights', + include_update => 0, + } + }, + 'triage form submitted' + ); + + $mech->content_contains('Potholes'); + + $report->discard_changes; + is $report->state, 'confirmed', 'report marked as confirmed'; + ok !$report->whensent, 'report marked to resend'; + + my @comments = $report->comments; + my $comment = $comments[0]; + my $extra = $comment->get_extra_metadata(); + is $extra->{triage_report}, 1, 'comment indicates it is for triage in extra'; + is $extra->{holding_category}, 'Potholes', 'comment extra has previous category'; + is $extra->{new_category}, 'Traffic lights', 'comment extra has new category'; + ok $comment->whensent, 'comment is marked as sent'; + + $mech->get_ok($report_url); + $mech->content_contains('Report triaged from Potholes to Traffic lights'); + + $mech->log_out_ok; + $mech->get_ok($report_url); + $mech->content_lacks('Report triaged from Potholes to Traffic lights'); + + $mech->clear_emails_ok; + FixMyStreet::Script::Alerts::send(); + $mech->email_count_is(0); + }; +}; + +done_testing(); diff --git a/t/app/controller/report_new_open311.t b/t/app/controller/report_new_open311.t index 52f1ddc6e..a0d122a7b 100644 --- a/t/app/controller/report_new_open311.t +++ b/t/app/controller/report_new_open311.t @@ -203,6 +203,8 @@ foreach my $test ( # check that we got the errors expected is_deeply $mech->page_errors, $test->{errors}, "check errors"; + $mech->content_contains('Help <strong>Borsetshire Council</strong> resolve your problem quicker'); + # check that fields have changed as expected my $new_values = { %{ $test->{fields} }, # values added to form diff --git a/t/cobrand/isleofwight.t b/t/cobrand/isleofwight.t new file mode 100644 index 000000000..67088bc54 --- /dev/null +++ b/t/cobrand/isleofwight.t @@ -0,0 +1,567 @@ +use CGI::Simple; +use DateTime; +use FixMyStreet::TestMech; +use Open311; +use Open311::GetServiceRequests; +use Open311::GetServiceRequestUpdates; +use Open311::PostServiceRequestUpdates; +use FixMyStreet::Script::Alerts; +use FixMyStreet::Script::Reports; + +ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' ); + +my $params = { + send_method => 'Open311', + send_comments => 1, + api_key => 'KEY', + endpoint => 'endpoint', + jurisdiction => 'home', + can_be_devolved => 1, +}; +my $isleofwight = $mech->create_body_ok(2636, 'Isle of Wight Council', $params); +my $contact = $mech->create_contact_ok( + body_id => $isleofwight->id, + category => 'Potholes', + email => 'pothole@example.org', +); +$contact->set_extra_fields( ( { + code => 'urgent', + datatype => 'string', + description => 'question', + variable => 'true', + required => 'false', + order => 1, + datatype_description => 'datatype', +} ) ); +$contact->update; + +my $user = $mech->create_user_ok('user@example.org', name => 'Test User'); +my $iow_user = $mech->create_user_ok('iow_user@example.org', name => 'IoW User', from_body => $isleofwight); +$iow_user->user_body_permissions->create({ + body => $isleofwight, + permission_type => 'moderate', +}); + +my $contact2 = $mech->create_contact_ok( + body_id => $isleofwight->id, + category => 'Roads', + email => 'roads@example.org', + send_method => 'Triage', +); + +my $admin_user = $mech->create_user_ok('admin-user@example.org', name => 'Admin User', from_body => $isleofwight); + +$admin_user->user_body_permissions->create({ + body => $isleofwight, + permission_type => 'triage' +}); + +my @reports = $mech->create_problems_for_body(1, $isleofwight->id, 'An Isle of wight report', { + confirmed => '2019-05-25 09:00', + lastupdate => '2019-05-25 09:00', + latitude => 50.7108, + longitude => -1.29573, + user => $user, + external_id => 101202303 +}); + +subtest "check clicking all reports link" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $mech->get_ok('/'); + $mech->follow_link_ok({ text => 'All reports' }); + }; + + $mech->content_contains("An Isle of wight report", "Isle of Wight report there"); + $mech->content_contains("Island Roads", "is still on cobrand"); +}; + +subtest "use external id for reference number" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $mech->get_ok('/report/' . $reports[0]->id); + }; + + $mech->content_contains("101202303", "Display external id as reference number"); +}; + +subtest "only original reporter can comment" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $mech->get_ok('/report/' . $reports[0]->id); + $mech->content_contains('Only the original reporter may leave updates'); + + $mech->log_in_ok('user@example.org'); + $mech->get_ok('/report/' . $reports[0]->id); + $mech->content_lacks('Only the original reporter may leave updates'); + }; +}; + +subtest "check moderation label uses correct name" => sub { + my $REPORT_URL = '/report/' . $reports[0]->id; + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight'], + }, sub { + $mech->log_out_ok; + $mech->log_in_ok( $iow_user->email ); + $mech->get_ok($REPORT_URL); + $mech->content_lacks('show-moderation'); + $mech->follow_link_ok({ text_regex => qr/^Moderate$/ }); + $mech->content_contains('show-moderation'); + $mech->submit_form_ok({ with_fields => { + problem_title => 'Good good', + problem_detail => 'Good good improved', + }}); + $mech->base_like( qr{\Q$REPORT_URL\E} ); + $mech->content_like(qr/Moderated by Island Roads/); + }; +}; + +$_->delete for @reports; + +my $system_user = $mech->create_user_ok('system_user@example.org'); + +for my $status ( qw/ CLOSED FIXED DUPLICATE NOT_COUNCILS_RESPONSIBILITY NO_FURTHER_ACTION / ) { + subtest "updates which mark report as $status close it to comments" => sub { + my $dt = DateTime->now(formatter => DateTime::Format::W3CDTF->new)->add( minutes => -5 ); + my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, '', { lastupdate => $dt }); + $p->update({ external_id => $p->id }); + + my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?> + <service_requests_updates> + <request_update> + <update_id>UPDATE_ID</update_id> + <service_request_id>SERVICE_ID</service_request_id> + <service_request_id_ext>ID_EXTERNAL</service_request_id_ext> + <status>STATUS</status> + <description>This is a note</description> + <updated_datetime>UPDATED_DATETIME</updated_datetime> + </request_update> + </service_requests_updates> + }; + + my $update_dt = DateTime->now(formatter => DateTime::Format::W3CDTF->new); + + $requests_xml =~ s/STATUS/$status/; + $requests_xml =~ s/UPDATE_ID/@{[$p->id]}/; + $requests_xml =~ s/SERVICE_ID/@{[$p->id]}/; + $requests_xml =~ s/ID_EXTERNAL/@{[$p->id]}/; + $requests_xml =~ s/UPDATED_DATETIME/$update_dt/; + + my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'servicerequestupdates.xml' => $requests_xml } ); + + my $update = Open311::GetServiceRequestUpdates->new( + system_user => $system_user, + current_open311 => $o, + current_body => $isleofwight, + ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $update->process_body; + }; + + $mech->log_in_ok('user@example.org'); + $mech->get_ok('/report/' . $p->id); + $mech->content_lacks('Provide an update', "No update form on report"); + + $p->discard_changes; + is $p->get_extra_metadata('closed_updates'), 1, "report closed to updates"; + $p->comments->delete; + $p->delete; + }; +} + +subtest "fetched requests do not use the description text" => sub { + my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?> + <service_requests> + <request> + <service_request_id>638344</service_request_id> + <status>open</status> + <status_notes>This is a note.</status_notes> + <service_name>Potholes</service_name> + <service_code>potholes\@example.org</service_code> + <description>This the description of a pothole problem</description> + <agency_responsible></agency_responsible> + <service_notice></service_notice> + <requested_datetime>DATETIME</requested_datetime> + <updated_datetime>DATETIME</updated_datetime> + <expected_datetime>DATETIME</expected_datetime> + <lat>50.71086</lat> + <long>-1.29573</long> + </request> + </service_requests> + }; + + my $dt = DateTime->now(formatter => DateTime::Format::W3CDTF->new)->add( minutes => -5 ); + $requests_xml =~ s/DATETIME/$dt/gm; + + my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'requests.xml' => $requests_xml } ); + + my $update = Open311::GetServiceRequests->new( + system_user => $iow_user, + ); + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $update->create_problems( $o, $isleofwight ); + }; + + my $p = FixMyStreet::DB->resultset('Problem')->search( + { external_id => 638344 } + )->first; + + ok $p, 'Found problem'; + is $p->title, 'Potholes problem', 'correct problem title'; + is $p->detail, 'Potholes problem', 'correct problem description'; + $p->delete; +}; + +subtest "fixing passes along the correct message" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + my $test_res = HTTP::Response->new(); + $test_res->code(200); + $test_res->message('OK'); + $test_res->content('<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>'); + + my $o = Open311->new( + fixmystreet_body => $isleofwight, + test_mode => 1, + test_get_returns => { 'servicerequestupdates.xml' => $test_res }, + ); + + my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, 'Title', { external_id => 1 }); + + my $c = FixMyStreet::App->model('DB::Comment')->create({ + problem => $p, user => $p->user, anonymous => 't', text => 'Update text', + problem_state => 'fixed - council', state => 'confirmed', mark_fixed => 0, + confirmed => DateTime->now(), + }); + + my $id = $o->post_service_request_update($c); + is $id, 248, 'correct update ID returned'; + my $cgi = CGI::Simple->new($o->test_req_used->content); + like $cgi->param('description'), qr/^FMS-Update:/, 'FMS update prefix included'; + unlike $cgi->param('description'), qr/The customer indicated that this issue had been fixed/, 'No fixed message included'; + + $c = $mech->create_comment_for_problem($p, $p->user, 'Name', 'Update text', 'f', 'confirmed', 'fixed - user', { confirmed => \'current_timestamp' }); + $c->discard_changes; # Otherwise cannot set_nanosecond + + $id = $o->post_service_request_update($c); + is $id, 248, 'correct update ID returned'; + $cgi = CGI::Simple->new($o->test_req_used->content); + like $cgi->param('description'), qr/^FMS-Update: \[The customer indicated that this issue had been fixed/, 'Fixed message included'; + $p->comments->delete; + $p->delete; + }; +}; + +subtest 'Check special Open311 request handling', sub { + $mech->clear_emails_ok; + my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, 'Title', { category => 'Potholes', latitude => 50.7108, longitude => -1.29573, cobrand => 'isleofwight' }); + $p->set_extra_fields({ name => 'urgent', value => 'no'}); + $p->update; + + my $test_data; + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => ['isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $test_data = FixMyStreet::Script::Reports::send(); + }; + + $p->discard_changes; + ok $p->whensent, 'Report marked as sent'; + is $p->send_method_used, 'Open311', 'Report sent via Open311'; + is $p->external_id, 248, 'Report has right external ID'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('attribute[urgent]'), undef, 'no urgent param sent'; + + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), + qr/your enquiry has been received by Island Roads/, "correct report send email text"; +}; + +subtest "comment recording triage details is not sent" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => [ 'isleofwight' ], + }, sub { + my $test_res = HTTP::Response->new(); + $test_res->code(200); + $test_res->message('OK'); + $test_res->content('<?xml version="1.0" encoding="utf-8"?><service_request_updates></service_request_updates>'); + + my $o = Open311->new( + fixmystreet_body => $isleofwight, + test_mode => 1, + test_get_returns => { 'servicerequestupdates.xml' => $test_res }, + ); + + my ($p) = $mech->create_problems_for_body( + 1, $isleofwight->id, 'Title', + { + category => 'Roads', + areas => 2636, + latitude => 50.71086, + longitude => -1.29573, + whensent => DateTime->now->add( minutes => -5 ), + send_method_used => 'Triage', + state => 'for triage', + external_id => 1, + }); + + $mech->log_out_ok; + $mech->log_in_ok($admin_user->email); + my $report_url = '/report/' . $p->id; + $mech->get_ok($report_url); + $mech->submit_form_ok( { + with_fields => { + category => 'Potholes', + include_update => 0, + } + }, + 'triage form submitted' + ); + + ok $p->comments->first, 'comment created for problem'; + + $p->update({ + send_method_used => 'Open311', + whensent => DateTime->now->add( minutes => -5 ), + }); + + my $updates = Open311::PostServiceRequestUpdates->new( + current_open311 => $o, + ); + my $id = $updates->process_body($isleofwight); + ok !$o->test_req_used, 'no open311 update sent'; + + $p->comments->delete; + $p->delete; + }; +}; + +my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, '', { cobrand => 'isleofwight' }); +my $alert = FixMyStreet::App->model('DB::Alert')->create( { + parameter => $p->id, + alert_type => 'new_updates', + user => $user, + cobrand => 'isleofwight', +} )->confirm; + +subtest "sends branded alert emails" => sub { + $mech->create_comment_for_problem($p, $system_user, 'Other User', 'This is some update text', 'f', 'confirmed', undef, { confirmed => DateTime->now->add( minutes => 5 ) }); + $mech->clear_emails_ok; + + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight','fixmystreet'], + }, sub { + FixMyStreet::Script::Alerts::send(); + }; + + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), qr/Island Roads/, "emails are branded"; +}; + +$p->comments->delete; +$p->delete; + +subtest "sends branded confirmation emails" => sub { + $mech->log_out_ok; + $mech->clear_emails_ok; + $mech->get_ok('/around'); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + $mech->submit_form_ok( + { + button => 'submit_register', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo1 => '', + name => 'Joe Bloggs', + username => 'test-1@example.com', + category => 'Roads', + } + }, + "submit good details" + ); + + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), qr/Island Roads/, "emails are branded"; + + my $url = $mech->get_link_from_email($email); + $mech->get_ok($url); + $mech->clear_emails_ok; + }; +}; + +subtest "sends branded report sent emails" => sub { + $mech->clear_emails_ok; + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight','fixmystreet'], + }, sub { + FixMyStreet::Script::Reports::send(); + }; + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), qr/Island Roads/, "emails are branded"; +}; + +subtest "check category extra uses correct name" => sub { + my @extras = ( { + code => 'test', + datatype => 'string', + description => 'question', + variable => 'true', + required => 'false', + order => 1, + datatype_description => 'datatype', + } ); + $contact2->set_extra_fields( @extras ); + $contact2->update; + + my $extra_details; + + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight','fixmystreet'], + }, sub { + $extra_details = $mech->get_ok_json('/report/new/category_extras?category=Roads&latitude=50.71086&longitude=-1.29573'); + }; + + like $extra_details->{category_extra}, qr/Island Roads/, 'correct name in category extras'; +}; + +subtest "reports are marked for triage upon submission" => sub { + $mech->log_out_ok; + $mech->clear_emails_ok; + $mech->log_in_ok($user->email); + $mech->get_ok('/around'); + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1, skip_checks => 0 }, + ALLOWED_COBRANDS => [ 'isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + $mech->submit_form_ok( + { + button => 'submit_register', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo1 => '', + category => 'Roads', + } + }, + "submit good details" + ); + + my $report = $user->problems->first; + ok $report, "Found the report"; + is $report->state, 'confirmed', 'report confirmed'; + + $mech->clear_emails_ok; + + FixMyStreet::Script::Reports::send(); + $report->discard_changes; + is $report->state, 'for triage', 'report marked as for triage'; + ok $report->whensent, 'report marked as sent'; + + $mech->email_count_is(1); + my $email = $mech->get_email; + like $mech->get_text_body_from_email($email), + qr/submitted to Island Roads for review/, 'correct text for email sent for Triage'; + }; +}; + +for my $cobrand ( 'fixmystreet', 'isleofwight' ) { + subtest "only categories for Triage are displayed on " . $cobrand => sub { + $mech->log_out_ok; + $mech->get_ok('/around'); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ $cobrand ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + my $f = $mech->form_name('mapSkippedForm'); + ok $f, 'found form'; + my $cats = $f->find_input('category'); + ok $cats, 'found category element'; + my @values = $cats->possible_values; + is_deeply \@values, [ '-- Pick a category --', 'Roads' ], 'correct category list'; + }; + }; + + subtest "staff user can see non Triage categories on " . $cobrand => sub { + $mech->log_out_ok; + $mech->log_in_ok($admin_user->email); + $mech->get_ok('/around'); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ $cobrand ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + my $f = $mech->form_name('mapSkippedForm'); + ok $f, 'found form'; + my $cats = $f->find_input('category'); + ok $cats, 'found category element'; + my @values = $cats->possible_values; + is_deeply \@values, [ '-- Pick a category --', 'Potholes' ], 'correct category list'; + }; + }; +} + +done_testing(); diff --git a/t/cobrand/zurich.t b/t/cobrand/zurich.t index 0bfdd8351..a08eb431e 100644 --- a/t/cobrand/zurich.t +++ b/t/cobrand/zurich.t @@ -6,6 +6,7 @@ use Email::MIME; use File::Temp; use LWP::Protocol::PSGI; use Test::LongString; +use Test::MockModule; use Path::Tiny; use t::Mock::MapItZurich; use FixMyStreet::Script::Reports; @@ -28,18 +29,8 @@ $cobrand->db_state_migration; my $sample_file = path(__FILE__)->parent->parent->child("app/controller/sample.jpg"); ok $sample_file->exists, "sample file $sample_file exists"; -# This is a helper method that will send the reports but with the config -# correctly set - notably STAGING_FLAGS send_reports needs to be true, and -# zurich must be allowed cobrand if we want to be able to call cobrand -# methods on it. sub send_reports_for_zurich { - FixMyStreet::override_config { - STAGING_FLAGS => { send_reports => 1 }, - ALLOWED_COBRANDS => ['zurich'] - }, sub { - # Actually send the report - FixMyStreet::Script::Reports::send('zurich'); - }; + FixMyStreet::Script::Reports::send('zurich'); } sub reset_report_state { my ($report, $created) = @_; @@ -51,45 +42,45 @@ sub reset_report_state { $report->whensent(undef); $report->state('submitted'); $report->created($created) if $created; + $report->category('Other'); $report->update; } -# Front page test -ok $mech->host("zurich.example.com"), "change host to Zurich"; +my $UPLOAD_DIR = File::Temp->newdir(); FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => 'zurich', + MAPIT_URL => 'http://mapit.zurich/', + MAPIT_TYPES => [ 'O08' ], + MAPIT_ID_WHITELIST => [ 423017 ], + MAP_TYPE => 'Zurich,OSM', + PHOTO_STORAGE_BACKEND => 'FileSystem', + PHOTO_STORAGE_OPTIONS => { + UPLOAD_DIR => $UPLOAD_DIR, + }, }, sub { - $mech->get_ok('/'); -}; + +# Front page test +ok $mech->host("zurich.example.com"), "change host to Zurich"; +$mech->get_ok('/'); $mech->content_like( qr/zurich/i ); # Set up bodies my $zurich = $mech->create_body_ok( 1, 'Zurich' ); -$zurich->parent( undef ); -$zurich->update; -my $division = $mech->create_body_ok( 2, 'Division 1' ); -$division->parent( $zurich->id ); -$division->send_method( 'Zurich' ); -$division->endpoint( 'division@example.org' ); -$division->update; -$division->body_areas->find_or_create({ area_id => 423017 }); -my $subdivision = $mech->create_body_ok( 3, 'Subdivision A' ); -$subdivision->parent( $division->id ); -$subdivision->send_method( 'Zurich' ); -$subdivision->endpoint( 'subdivision@example.org' ); -$subdivision->update; -my $external_body = $mech->create_body_ok( 4, 'External Body' ); -$external_body->send_method( 'Zurich' ); -$external_body->endpoint( 'external_body@example.net' ); -$external_body->update; +my $division = $mech->create_body_ok( 423017, 'Division 1', { + parent => $zurich->id, send_method => 'Zurich', endpoint => 'division@example.org' } ); +my $division2 = $mech->create_body_ok( 423017, 'Division 2', { + parent => $zurich->id, send_method => 'Zurich', endpoint => 'division2@example.org' } ); +my $subdivision = $mech->create_body_ok( 3, 'Subdivision A', + { parent => $division->id, send_method => 'Zurich', endpoint => 'subdivision@example.org' } ); +my $external_body = $mech->create_body_ok( 4, 'External Body', + { send_method => 'Zurich', endpoint => 'external_body@example.net' } ); +my $external_body2 = $mech->create_body_ok( 4, 'Another Body External', + { send_method => 'Zurich', endpoint => 'external_body2@example.net' } ); sub get_export_rows_count { my $mech = shift; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get_ok( '/admin/stats?export=1' ); - }; + $mech->get_ok( '/admin/stats?export=1' ); is $mech->res->code, 200, 'csv retrieved ok'; is $mech->content_type, 'text/csv', 'content_type correct' and do { my @lines = split /\n/, $mech->content; @@ -117,29 +108,15 @@ my @reports = $mech->create_problems_for_body( 1, $division->id, 'Test', { }); my $report = $reports[0]; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { - $mech->get_ok( '/report/' . $report->id ); -}; +$mech->get_ok( '/report/' . $report->id ); $mech->content_contains('Überprüfung ausstehend') or die $mech->content; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { - my $json = $mech->get_ok_json( '/report/ajax/' . $report->id ); - is $json->{report}->{title}, "Überprüfung ausstehend", "correct title"; - is $json->{report}->{state}, "submitted", "correct state"; -}; +my $json = $mech->get_ok_json( '/report/ajax/' . $report->id ); +is $json->{report}->{title}, "Überprüfung ausstehend", "correct title"; +is $json->{report}->{state}, "submitted", "correct state"; subtest "Banners are displayed correctly" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { for my $test ( { description => 'new report', @@ -162,8 +139,8 @@ subtest "Banners are displayed correctly" => sub { { description => 'closed report', state => 'external', - banner_id => 'closed', - banner_text => 'Extern', + banner_id => 'fixed', + banner_text => 'Beantwortet', }, { description => 'in progress report', @@ -211,17 +188,14 @@ subtest "Banners are displayed correctly" => sub { }; } $report->update({ state => 'submitted' }); - }; }; -# Check logging in to deal with this report -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], -}, sub { +my $user; +subtest 'check logging in to deal with this report' => sub { $mech->get_ok( '/admin' ); is $mech->uri->path, '/auth', "got sent to the sign in page"; - my $user = $mech->log_in_ok( 'dm1@example.org') ; + $user = $mech->log_in_ok( 'dm1@example.org') ; $user->from_body( undef ); $user->update; ok $mech->get( '/admin' ); @@ -230,12 +204,12 @@ FixMyStreet::override_config { $user->update; $mech->get_ok( '/admin' ); -}; -is $mech->uri->path, '/admin', "am logged in"; + is $mech->uri->path, '/admin', "am logged in"; -$mech->content_contains( 'report_edit/' . $report->id ); -$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); -$mech->content_contains( 'Erfasst' ); + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); + $mech->content_contains( 'Erfasst' ); +}; subtest "changing of categories" => sub { # create a few categories (which are actually contacts) @@ -260,13 +234,8 @@ subtest "changing of categories" => sub { ok ( !$comments_rs->first, "There are no comments yet" ); # change the category via the web interface - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { category => 'Cat2' } } ); - }; + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { category => 'Cat2' } } ); # check changes correctly saved $report->discard_changes(); @@ -280,6 +249,38 @@ subtest "changing of categories" => sub { $report->update({category => $original_category }); }; +subtest "private categories" => sub { + $mech->log_in_ok( 'super@example.org' ); + $mech->get_ok('/admin/bodies'); + $mech->follow_link_ok({ text => 'Division 1' }); + $mech->submit_form_ok({ with_fields => { + category => 'Allgemein', + state => 'inactive', + email => 'allgemein@example.org', + 'extra[admin_label]' => 'StadtPeople', + 'extra[abbreviation]' => 'STA', + note => 'New', + }}); + $mech->follow_link_ok({ text => 'Allgemein' }); + $mech->content_contains('<option value="inactive" selected>'); + $mech->content_like(qr/admin_label.*?StadtPeople/); + + $mech->get_ok( '/around?lat=47.381817&lon=8.529156' ); + $mech->content_lacks('StadtPeople'); + $mech->content_contains('Allgemein'); + $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); + $mech->content_lacks('StadtPeople'); + $mech->content_lacks('Allgemein'); + + $report->update({ category => 'Allgemein' }); + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('StadtPeople'); + $mech->content_contains('Allgemein'); + + $mech->get_ok('/admin/report_edit/' . $report->id); + $mech->content_contains('<option value="Allgemein">StadtPeople (STA)</option>'); +}; + sub get_moderated_count { # my %date_params = ( ); # my $moderated = FixMyStreet::DB->resultset('Problem')->search({ @@ -288,17 +289,12 @@ sub get_moderated_count { # use a separate mech to avoid stomping on test state my $mech = FixMyStreet::TestMech->new; - my $user = $mech->log_in_ok( 'super@example.org' ); + $mech->log_in_ok( 'super@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get( '/admin/stats' ); - }; + $mech->get( '/admin/stats' ); if ($mech->content =~/Innerhalb eines Arbeitstages moderiert: (\d+)/) { return $1; - } - else { + } else { fail sprintf "Could not get moderation results (%d)", $mech->status; return undef; } @@ -306,127 +302,112 @@ sub get_moderated_count { subtest "report_edit" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { + reset_report_state($report); + ok ( ! $report->get_extra_metadata('moderated_overdue'), 'Report currently unmoderated' ); + is get_moderated_count(), 0; - reset_report_state($report); - ok ( ! $report->get_extra_metadata('moderated_overdue'), 'Report currently unmoderated' ); - is get_moderated_count(), 0; - - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains( 'Unbestätigt' ); # Unconfirmed email - $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); - $mech->get_ok( '/report/' . $report->id ); + $mech->log_in_ok( 'dm1@example.org') ; + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Unbestätigt' ); # Unconfirmed email + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); - $report->discard_changes(); + $report->discard_changes(); - $mech->content_contains('Aufgenommen'); - $mech->content_contains('Test Test'); - $mech->content_lacks('photo/' . $report->id . '.0.jpeg'); - $mech->email_count_is(0); + $mech->content_contains('Aufgenommen'); + $mech->content_contains('Test Test'); + $mech->content_lacks('photo/' . $report->id . '.0.jpeg'); + $mech->email_count_is(0); - $report->discard_changes; + $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Report now marked moderated' ); - is get_moderated_count(), 1; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Report now marked moderated' ); + is get_moderated_count(), 1; - # Set state back to 10 days ago so that report is overdue - my $created = $report->created; - reset_report_state($report, $created->clone->subtract(days => 10)); + # Set state back to 10 days ago so that report is overdue + my $created = $report->created; + reset_report_state($report, $created->clone->subtract(days => 10)); - is get_moderated_count(), 0; + is get_moderated_count(), 0; - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); - $mech->get_ok( '/report/' . $report->id ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 1, 'moderated_overdue set correctly when overdue' ); - is get_moderated_count(), 0, 'Moderated count not increased when overdue'; + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 1, 'moderated_overdue set correctly when overdue' ); + is get_moderated_count(), 0, 'Moderated count not increased when overdue'; - reset_report_state($report, $created); + reset_report_state($report, $created); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); - $mech->get_ok( '/report/' . $report->id ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking confirmed sets moderated_overdue' ); - is ( $report->get_extra_metadata('closed_overdue'), undef, 'Marking confirmed does NOT set closed_overdue' ); - is get_moderated_count(), 1; + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking confirmed sets moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), undef, 'Marking confirmed does NOT set closed_overdue' ); + is get_moderated_count(), 1; - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); - $mech->get_ok( '/report/' . $report->id, 'still visible as response not published yet' ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); + $mech->get_ok( '/report/' . $report->id, 'still visible as response not published yet' ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Still marked moderated_overdue' ); - is ( $report->get_extra_metadata('closed_overdue'), undef, "Marking hidden doesn't set closed_overdue..." ); - is ( $report->state, 'feedback pending', 'Marking hidden actually sets state to feedback pending'); - is ( $report->get_extra_metadata('closure_status'), 'hidden', 'Marking hidden sets closure_status to hidden'); - is get_moderated_count(), 1, 'Check still counted moderated' - or diag $report->get_column('extra'); - - # publishing actually sets hidden - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'status_update' ); - $mech->submit_form_ok( { button => 'publish_response' } ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $report->discard_changes; + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Still marked moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), undef, "Marking hidden doesn't set closed_overdue..." ); + is ( $report->state, 'feedback pending', 'Marking hidden actually sets state to feedback pending'); + is ( $report->get_extra_metadata('closure_status'), 'hidden', 'Marking hidden sets closure_status to hidden'); + is get_moderated_count(), 1, 'Check still counted moderated' + or diag $report->get_column('extra'); + + # publishing actually sets hidden + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $report->discard_changes; - is ( $report->get_extra_metadata('closed_overdue'), 0, "Closing as hidden sets closed_overdue..." ); - is ( $report->state, 'hidden', 'Closing as hidden sets state to hidden'); - is ( $report->get_extra_metadata('closure_status'), undef, 'Closing as hidden unsets closure_status'); + is ( $report->get_extra_metadata('closed_overdue'), 0, "Closing as hidden sets closed_overdue..." ); + is ( $report->state, 'hidden', 'Closing as hidden sets state to hidden'); + is ( $report->get_extra_metadata('closure_status'), undef, 'Closing as hidden unsets closure_status'); - $mech->submit_form_ok( { with_fields => { new_internal_note => 'Initial internal note.' } } ); - $report->discard_changes; - is ( $report->state, 'hidden', 'Another internal note does not reopen'); + $mech->submit_form_ok( { with_fields => { new_internal_note => 'Initial internal note.' } } ); + $report->discard_changes; + is ( $report->state, 'hidden', 'Another internal note does not reopen'); - $mech->get( '/report/' . $report->id); - is $mech->res->code, 410; + $mech->get( '/report/' . $report->id); + is $mech->res->code, 410; - reset_report_state($report); - is ( $report->get_extra_metadata('moderated_overdue'), undef, 'Sanity check' ); - is get_moderated_count(), 0; + reset_report_state($report); + is ( $report->get_extra_metadata('moderated_overdue'), undef, 'Sanity check' ); + is get_moderated_count(), 0; - # Check that setting to 'hidden' also triggers moderation - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'status_update' ); - $mech->submit_form_ok( { button => 'publish_response' } ); + # Check that setting to 'hidden' also triggers moderation + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking hidden from scratch sets moderated_overdue' ); - is ( $report->get_extra_metadata('closed_overdue'), 0, 'Marking hidden from scratch also set closed_overdue' ); - is get_moderated_count(), 1; + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking hidden from scratch sets moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), 0, 'Marking hidden from scratch also set closed_overdue' ); + is get_moderated_count(), 1; - is ($cobrand->get_or_check_overdue($report), 0, 'sanity check'); - $report->update({ created => $created->clone->subtract(days => 10) }); - is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased'); + is ($cobrand->get_or_check_overdue($report), 0, 'sanity check'); + $report->update({ created => $created->clone->subtract(days => 10) }); + is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased'); - reset_report_state($report, $created); - } + reset_report_state($report, $created); }; # Give the report three photos -my $UPLOAD_DIR = File::Temp->newdir(); my @files = map { $_ x 40 . ".jpeg" } (1..3); $sample_file->copy(path($UPLOAD_DIR, $_)) for @files; $report->photo(join(',', @files)); $report->update; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAP_TYPE => 'Zurich,OSM', - PHOTO_STORAGE_BACKEND => 'FileSystem', - PHOTO_STORAGE_OPTIONS => { - UPLOAD_DIR => $UPLOAD_DIR, - }, -}, sub { - # Photo publishing +subtest 'Photo publishing' => sub { $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->submit_form_ok( { with_fields => { state => 'confirmed', publish_photo_1 => 1 } } ); $mech->get_ok( '/around?lat=' . $report->latitude . ';lon=' . $report->longitude); @@ -469,50 +450,37 @@ $mech->log_out_ok; subtest 'SDM' => sub { my $user = $mech->log_in_ok( 'sdm1@example.org') ; $user->update({ from_body => undef }); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - ok $mech->get( '/admin' ); - }; + ok $mech->get( '/admin' ); is $mech->res->code, 403, 'Got 403'; $user->from_body( $subdivision->id ); $user->update; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get_ok( '/admin' ); - }; + $mech->get_ok( '/admin' ); is $mech->uri->path, '/admin', "am logged in"; $mech->content_contains( 'report_edit/' . $report->id ); $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); $mech->content_contains( 'In Bearbeitung' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains( 'Initial internal note' ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Initial internal note' ); - $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } ); - is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page"; - $mech->content_contains('This is an update'); - ok $mech->form_with_fields( 'status_update' ); - $mech->submit_form_ok( { button => 'no_more_updates' } ); - is $mech->uri->path, '/admin/summary', "redirected now finished with report."; + $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } ); + is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page"; + $mech->content_contains('This is an update'); + ok $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'no_more_updates' } ); + is $mech->uri->path, '/admin/summary', "redirected now finished with report."; - # Can still view the edit page but can't change anything - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains('<input disabled'); - $mech->submit_form_ok( { with_fields => { status_update => 'This is a disallowed update.' } } ); - $mech->content_lacks('This is a disallowed update'); + # Can still view the edit page but can't change anything + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains('<input disabled'); + $mech->submit_form_ok( { with_fields => { status_update => 'This is a disallowed update.' } } ); + $mech->content_lacks('This is a disallowed update'); - $mech->get_ok( '/report/' . $report->id ); - $mech->content_contains('In Bearbeitung'); - $mech->content_contains('Test Test'); - }; + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('In Bearbeitung'); + $mech->content_contains('Test Test'); send_reports_for_zurich(); $email = $mech->get_email; @@ -524,106 +492,86 @@ subtest 'SDM' => sub { is $report->state, 'feedback pending', 'Report now in feedback pending state'; subtest 'send_back' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { form_number => 2, button => 'send_back' } ); - $report->discard_changes; - is $report->state, 'confirmed', 'Report sent back to confirmed state'; - is $report->bodies_str, $division->id, 'Report sent back to division'; - }; + $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { form_number => 2, button => 'send_back' } ); + $report->discard_changes; + is $report->state, 'confirmed', 'Report sent back to confirmed state'; + is $report->bodies_str, $division->id, 'Report sent back to division'; }; subtest 'not contactable' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { button => 'not_contactable', form_number => 2 } ); - $report->discard_changes; - is $report->state, 'feedback pending', 'Report sent back to Rueckmeldung ausstehend state'; - is $report->get_extra_metadata('closure_status'), 'not contactable', 'Report sent back to not_contactable state'; - is $report->bodies_str, $division->id, 'Report sent back to division'; - }; + $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { button => 'not_contactable', form_number => 2 } ); + $report->discard_changes; + is $report->state, 'feedback pending', 'Report sent back to Rueckmeldung ausstehend state'; + is $report->get_extra_metadata('closure_status'), 'not contactable', 'Report sent back to not_contactable state'; + is $report->bodies_str, $division->id, 'Report sent back to division'; }; $mech->log_out_ok; }; -my $user = $mech->log_in_ok( 'dm1@example.org') ; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], -}, sub { +subtest 'Test publishing of final update by DM' => sub { + $user = $mech->log_in_ok( 'dm1@example.org'); $mech->get_ok( '/admin' ); -}; -reset_report_state($report); -$report->update({ state => 'feedback pending' }); + reset_report_state($report); + $report->update({ state => 'feedback pending' }); -$mech->content_contains( 'report_edit/' . $report->id ); -$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); -# User confirms their email address -$report->set_extra_metadata(email_confirmed => 1); -$report->confirmed(DateTime->now); -$report->update; + # User confirms their email address + $report->set_extra_metadata(email_confirmed => 1); + $report->confirmed(DateTime->now); + $report->update; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { # Quick RSS check here, while we have a report $mech->get_ok('/rss/problems'); + my $module = Test::MockModule->new('FixMyStreet::Geocode::Zurich'); + $module->mock(admin_district => sub { 'Admin district' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->content_contains('Admin district'); + $mech->content_lacks( 'Unbestätigt' ); # Confirmed email $mech->submit_form_ok( { with_fields => { status_update => 'FINAL UPDATE' } } ); $mech->form_with_fields( 'status_update' ); $mech->submit_form_ok( { button => 'publish_response' } ); $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Beantwortet'); + $mech->content_contains('Test Test'); + $mech->content_contains('FINAL UPDATE'); + + $email = $mech->get_email; + like $email->header('To'), qr/test\@example.com/, 'to line looks correct'; + like $email->header('From'), qr/do-not-reply\@example.org/, 'from line looks correct'; + like $email->body, qr/FINAL UPDATE/, 'body looks correct'; + $mech->clear_emails_ok; }; -$mech->content_contains('Beantwortet'); -$mech->content_contains('Test Test'); -$mech->content_contains('FINAL UPDATE'); - -$email = $mech->get_email; -like $email->header('To'), qr/test\@example.com/, 'to line looks correct'; -like $email->header('From'), qr/do-not-reply\@example.org/, 'from line looks correct'; -like $email->body, qr/FINAL UPDATE/, 'body looks correct'; -$mech->clear_emails_ok; -# Assign feedback pending (via confirmed), don't confirm email -@reports = $mech->create_problems_for_body( 1, $division->id, 'Second', { - state => 'submitted', - confirmed => undef, - cobrand => 'zurich', - areas => ',423017,', -}); -$report = $reports[0]; +subtest "Assign feedback pending (via confirmed), don't confirm email, no email sent" => sub { + @reports = $mech->create_problems_for_body( 1, $division->id, 'Second', { + state => 'submitted', + confirmed => undef, + cobrand => 'zurich', + areas => ',423017,', + }); + $report = $reports[0]; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->submit_form_ok( { with_fields => { state => 'feedback pending' } } ); $mech->get_ok( '/report/' . $report->id ); -}; -$mech->content_contains('In Bearbeitung'); -$mech->content_contains('Second Test'); + $mech->content_contains('In Bearbeitung'); + $mech->content_contains('Second Test'); -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->content_contains( 'Unbestätigt' ); $report->discard_changes; @@ -631,12 +579,12 @@ FixMyStreet::override_config { $mech->submit_form_ok( { button => 'publish_response', with_fields => { status_update => 'FINAL UPDATE' } } ); $mech->get_ok( '/report/' . $report->id ); -}; -$mech->content_contains('Beantwortet'); -$mech->content_contains('Second Test'); -$mech->content_contains('FINAL UPDATE'); + $mech->content_contains('Beantwortet'); + $mech->content_contains('Second Test'); + $mech->content_contains('FINAL UPDATE'); -$mech->email_count_is(0); + $mech->email_count_is(0); +}; # Report assigned to third party @@ -650,31 +598,27 @@ $report = $reports[0]; subtest "external report triggers email" => sub { my $EXTERNAL_MESSAGE = 'Look Ma, no hands!'; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # required to see body_external field - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'external'); - # Set the public_response manually here because the default one will have line breaks that get escaped as HTML, causing the comparison to fail. - $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); - $report->update; + # required to see body_external field + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + # Set the public_response manually here because the default one will have line breaks that get escaped as HTML, causing the comparison to fail. + $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); + $report->update; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + } }); + $report->discard_changes; + $mech->get_ok( '/report/' . $report->id ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - external_message => $EXTERNAL_MESSAGE, - } }); - $report->discard_changes; - $mech->get_ok( '/report/' . $report->id ); - }; is ($report->state, 'external', 'Report was closed correctly'); - $mech->content_contains('Extern') + $mech->content_contains('Beantwortet') or die $mech->content; $mech->content_contains('Third Test'); $mech->content_contains($report->get_extra_metadata('public_response')) or die $mech->content; @@ -688,30 +632,25 @@ subtest "external report triggers email" => sub { $mech->clear_emails_ok; subtest "Test third_personal boolean setting" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin' ); - # required to see body_external field - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'external'); - $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); - $report->update; + $mech->get_ok( '/admin' ); + # required to see body_external field + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); + $report->update; - is $mech->uri->path, '/admin', "am logged in"; - $mech->content_contains( 'report_edit/' . $report->id ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - third_personal => 1, - } }); - $mech->get_ok( '/report/' . $report->id ); - }; - $mech->content_contains('Extern'); + is $mech->uri->path, '/admin', "am logged in"; + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + third_personal => 1, + } }); + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Beantwortet'); $mech->content_contains('Third Test'); $mech->content_contains($report->get_extra_metadata('public_response')); send_reports_for_zurich(); @@ -724,30 +663,25 @@ subtest "external report triggers email" => sub { }; subtest "Test external wish sending" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # set as wish - $report->discard_changes; - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'wish'); - $report->update; - is ($report->state, 'feedback pending', 'Sanity check') or die; - - $mech->get_ok( '/admin/report_edit/' . $report->id ); - - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - external_message => $EXTERNAL_MESSAGE, - } }); - # Wishes publicly viewable - $mech->get_ok( '/report/' . $report->id ); - $mech->content_contains('Freundliche Gruesse Ihre Stadt Zuerich'); - }; + # set as wish + $report->discard_changes; + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'wish'); + $report->update; + is ($report->state, 'feedback pending', 'Sanity check') or die; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + } }); + # Wishes publicly viewable + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Freundliche Gruesse Ihre Stadt Zuerich'); send_reports_for_zurich(); $email = $mech->get_email; like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay'; @@ -760,30 +694,26 @@ subtest "external report triggers email" => sub { subtest "Closure email includes public response" => sub { my $PUBLIC_RESPONSE = "This is the public response to your report. Freundliche Gruesse."; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # set as extern - reset_report_state($report); - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'external'); - $report->set_extra_metadata('email_confirmed' => 1); - $report->unset_extra_metadata('public_response'); - $report->update; - is ($report->state, 'feedback pending', 'Sanity check') or die; - - $mech->get_ok( '/admin/report_edit/' . $report->id ); - - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - external_message => $EXTERNAL_MESSAGE, - status_update => $PUBLIC_RESPONSE, - } }); - }; + # set as extern + reset_report_state($report); + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + $report->set_extra_metadata('email_confirmed' => 1); + $report->unset_extra_metadata('public_response'); + $report->update; + is ($report->state, 'feedback pending', 'Sanity check') or die; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + status_update => $PUBLIC_RESPONSE, + } }); + $email = $mech->get_email; my $report_id = $report->id; like Encode::decode('MIME-Header', $email->header('Subject')), qr/Meldung #$report_id/, 'subject looks okay'; @@ -798,91 +728,89 @@ subtest "superuser and dm can see stats" => sub { $mech->log_out_ok; $user = $mech->log_in_ok( 'super@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get( '/admin/stats' ); - }; + $mech->get( '/admin/stats' ); is $mech->res->code, 200, "superuser should be able to see stats page"; $mech->log_out_ok; $user = $mech->log_in_ok( 'dm1@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get( '/admin/stats' ); - }; + $mech->get( '/admin/stats' ); is $mech->res->code, 200, "dm can now also see stats page"; $mech->log_out_ok; }; subtest "only superuser can edit bodies" => sub { $user = $mech->log_in_ok( 'dm1@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - }, sub { - $mech->get( '/admin/body/' . $zurich->id ); - }; + $mech->get( '/admin/body/' . $zurich->id ); is $mech->res->code, 403, "only superuser should be able to edit bodies"; $mech->log_out_ok; }; subtest "only superuser can see 'Add body' form" => sub { $user = $mech->log_in_ok( 'dm1@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAPIT_TYPES => [ 'O08' ], - MAPIT_ID_WHITELIST => [ 423017 ], - }, sub { - $mech->get_ok( '/admin/bodies' ); - }; + $mech->get_ok( '/admin/bodies' ); $mech->content_contains('External Body'); $mech->content_lacks( '<form method="post" action="bodies"' ); $mech->log_out_ok; }; subtest "phone number is mandatory" => sub { - FixMyStreet::override_config { - MAPIT_TYPES => [ 'O08' ], - MAPIT_URL => 'http://mapit.zurich/', - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $user = $mech->log_in_ok( 'dm1@example.org' ); - $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); - $mech->submit_form( with_fields => { phone => "" } ); - $mech->content_contains( 'Diese Information wird benötigt' ); - $mech->log_out_ok; - }; + $user = $mech->log_in_ok( 'dm1@example.org' ); + $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); + $mech->submit_form( with_fields => { phone => "" } ); + $mech->content_contains( 'Diese Information wird benötigt' ); + $mech->log_out_ok; }; subtest "phone number is not mandatory for reports from mobile apps" => sub { - FixMyStreet::override_config { - MAPIT_TYPES => [ 'O08' ], - MAPIT_URL => 'http://mapit.zurich/', - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->post_ok( '/report/new/mobile?lat=47.381817&lon=8.529156' , { - service => 'iPhone', - detail => 'Problem-Bericht', - lat => 47.381817, - lon => 8.529156, - email => 'user@example.org', - pc => '', - name => '', - category => 'bad category', - }); - my $res = $mech->response; - ok $res->header('Content-Type') =~ m{^application/json\b}, 'response should be json'; - unlike $res->content, qr/Diese Information wird benötigt/, 'response should not contain phone error'; - # Clear out the mailq - $mech->clear_emails_ok; - }; + $mech->post_ok( '/report/new/mobile?lat=47.381817&lon=8.529156' , { + service => 'iPhone', + detail => 'Problem-Bericht', + lat => 47.381817, + lon => 8.529156, + email => 'user@example.org', + pc => '', + name => '', + category => 'bad category', + }); + my $res = $mech->response; + ok $res->header('Content-Type') =~ m{^application/json\b}, 'response should be json'; + unlike $res->content, qr/Diese Information wird benötigt/, 'response should not contain phone error'; + # Clear out the mailq + $mech->clear_emails_ok; +}; + +subtest "link external body to category" => sub { + $mech->log_in_ok( 'super@example.org' ); + $mech->get_ok( '/admin/body/' . $zurich->id ); + $mech->content_lacks('extra[category]'); + $mech->get_ok( '/admin/body/' . $division->id ); + $mech->content_lacks('extra[category]'); + $mech->get_ok( '/admin/body/' . $subdivision->id ); + $mech->content_lacks('extra[category]'); + $mech->get_ok( '/admin/body/' . $external_body->id ); + $mech->content_contains('extra[category]'); + $mech->submit_form_ok({ with_fields => { 'extra[category]' => 'Cat1' } }); + $mech->content_contains('<option value="Cat1" selected>'); + $external_body->discard_changes; + is $external_body->get_extra_metadata('category'), 'Cat1'; +}; + +subtest "shows correct external bodies" => sub { + $report->discard_changes; + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + $report->update; + $user = $mech->log_in_ok( 'dm1@example.org' ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_like(qr/<option[^>]*>External Body<\/option>\s*<option[^>]*>Another Body External<\/option>/); # Test order + + $user = $mech->log_in_ok( 'dm2@example.org' ); + $user->update({ from_body => $division2->id }); + $report->update({ bodies_str => $division2->id }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains('Another Body External'); + $mech->content_lacks('External Body'); + $report->update({ bodies_str => $division->id }); }; subtest "problems can't be assigned to deleted bodies" => sub { @@ -891,23 +819,15 @@ subtest "problems can't be assigned to deleted bodies" => sub { $user->update; $report->state( 'confirmed' ); $report->update; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAPIT_TYPES => [ 'O08' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin/body/' . $external_body->id ); - $mech->submit_form_ok( { with_fields => { deleted => 1 } } ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_lacks( $external_body->name ) - or do { - diag $mech->content; - diag $external_body->name; - die; - }; - }; + $mech->get_ok( '/admin/body/' . $external_body->id ); + $mech->submit_form_ok( { with_fields => { deleted => 1 } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_lacks( $external_body->name ) + or do { + diag $mech->content; + diag $external_body->name; + die; + }; $user->from_body( $division->id ); $user->update; $mech->log_out_ok; @@ -924,44 +844,32 @@ subtest "photo must be supplied for categories that require it" => sub { note => "note for graffiti", extra => { photo_required => 1 } }); - FixMyStreet::override_config { - MAPIT_TYPES => [ 'O08' ], - MAPIT_URL => 'http://mapit.zurich/', - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok('/report/new?lat=47.381817&lon=8.529156'); - $mech->submit_form_ok({ with_fields => { - detail => 'Problem-Bericht', - username => 'user@example.org', - category => 'Graffiti - photo required', - }}); - is $mech->res->code, 200, "missing photo shouldn't return anything but 200"; - $mech->content_contains(_("Photo is required."), 'response should contain photo error message'); - }; + $mech->get_ok('/report/new?lat=47.381817&lon=8.529156'); + $mech->submit_form_ok({ with_fields => { + detail => 'Problem-Bericht', + username => 'user@example.org', + category => 'Graffiti - photo required', + }}); + is $mech->res->code, 200, "missing photo shouldn't return anything but 200"; + $mech->content_contains(_("Photo is required."), 'response should contain photo error message'); }; subtest "test stats" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $user = $mech->log_in_ok( 'super@example.org' ); - - $mech->get_ok( '/admin/stats' ); - is $mech->res->code, 200, "superuser should be able to see stats page"; - - $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 3'); - $mech->content_contains('Innerhalb von fünf Arbeitstagen abgeschlossen: 3'); - # my @data = $mech->content =~ /(?:moderiert|abgeschlossen): \d+/g; - # diag Dumper(\@data); use Data::Dumper; - - my $export_count = get_export_rows_count($mech); - if (defined $export_count) { - is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports'; - $mech->content_contains('fixed - council'); - } - }; + $user = $mech->log_in_ok( 'super@example.org' ); + + $mech->get_ok( '/admin/stats' ); + is $mech->res->code, 200, "superuser should be able to see stats page"; + + $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 3'); + $mech->content_contains('Innerhalb von fünf Arbeitstagen abgeschlossen: 3'); + # my @data = $mech->content =~ /(?:moderiert|abgeschlossen): \d+/g; + # diag Dumper(\@data); use Data::Dumper; + + my $export_count = get_export_rows_count($mech); + if (defined $export_count) { + is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports'; + $mech->content_contains('fixed - council'); + } }; subtest "test admin_log" => sub { @@ -977,136 +885,108 @@ subtest "test admin_log" => sub { }; subtest 'email images to external partners' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - reset_report_state($report); + reset_report_state($report); - my $photo = path(__FILE__)->parent->child('zurich-logo_portal.x.jpg')->slurp_raw; - my $photoset = FixMyStreet::App::Model::PhotoSet->new({ - data_items => [ $photo ], - }); - my $fileid = $photoset->data; - - $report->set_extra_metadata('publish_photo' => { 0 => 1 }); - # The below email comparison must not have an external message. - $report->unset_extra_metadata('external_message'); - $report->update({ - state => 'external', - photo => $fileid, - external_body => $external_body->id, - }); + my $photo = path(__FILE__)->parent->child('zurich-logo_portal.x.jpg')->slurp_raw; + my $photoset = FixMyStreet::App::Model::PhotoSet->new({ + data_items => [ $photo ], + }); + my $fileid = $photoset->data; + + $report->set_extra_metadata('publish_photo' => { 0 => 1 }); + # The below email comparison must not have an external message. + $report->unset_extra_metadata('external_message'); + $report->update({ + state => 'external', + photo => $fileid, + external_body => $external_body->id, + }); - $mech->clear_emails_ok; - send_reports_for_zurich(); + $mech->clear_emails_ok; + send_reports_for_zurich(); - my @emails = $mech->get_email; - my $email_as_string = $mech->get_first_email(@emails); - my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms; - my $email = Email::MIME->new($email_as_string); - - my $expected_email_content = path(__FILE__)->parent->child('zurich_attachments.txt')->slurp; - - my $REPORT_ID = $report->id; - $expected_email_content =~ s{Subject: (.*?)\r?\n}{ - my $subj = Encode::decode('MIME-Header', $1); - $subj =~ s{REPORT_ID}{$REPORT_ID}g; - 'Subject: ' . Email::MIME::Encode::mime_encode($subj, "utf-8", 9) . "\n"; - }eg; - $expected_email_content =~ s{REPORT_ID}{$REPORT_ID}g; - $expected_email_content =~ s{BOUNDARY}{$boundary}g; - my $expected_email = Email::MIME->new($expected_email_content); - - my @email_parts; - $email->walk_parts(sub { - my ($part) = @_; - push @email_parts, [ { $part->header_pairs }, $part->body ]; - }); - my @expected_email_parts; - $expected_email->walk_parts(sub { - my ($part) = @_; - push @expected_email_parts, [ { $part->header_pairs }, $part->body ]; - }); - is_deeply \@email_parts, \@expected_email_parts, 'MIME email text ok' - or do { - (my $test_name = $0) =~ s{/}{_}g; - my $path = path("test-output-$test_name.tmp"); - $path->spew($email_as_string); - diag "Saved output in $path"; - }; + my @emails = $mech->get_email; + my $email_as_string = $mech->get_first_email(@emails); + my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms; + my $email = Email::MIME->new($email_as_string); + + my $expected_email_content = path(__FILE__)->parent->child('zurich_attachments.txt')->slurp; + + my $REPORT_ID = $report->id; + $expected_email_content =~ s{Subject: (.*?)\r?\n}{ + my $subj = Encode::decode('MIME-Header', $1); + $subj =~ s{REPORT_ID}{$REPORT_ID}g; + 'Subject: ' . Email::MIME::Encode::mime_encode($subj, "utf-8", 9) . "\n"; + }eg; + $expected_email_content =~ s{REPORT_ID}{$REPORT_ID}g; + $expected_email_content =~ s{BOUNDARY}{$boundary}g; + my $expected_email = Email::MIME->new($expected_email_content); + + my @email_parts; + $email->walk_parts(sub { + my ($part) = @_; + push @email_parts, [ { $part->header_pairs }, $part->body ]; + }); + my @expected_email_parts; + $expected_email->walk_parts(sub { + my ($part) = @_; + push @expected_email_parts, [ { $part->header_pairs }, $part->body ]; + }); + is_deeply \@email_parts, \@expected_email_parts, 'MIME email text ok' + or do { + (my $test_name = $0) =~ s{/}{_}g; + my $path = path("test-output-$test_name.tmp"); + $path->spew($email_as_string); + diag "Saved output in $path"; }; }; subtest 'Status update shown as appropriate' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # ALL closed states must hide the public_response edit, and public ones - # must show the answer in blue. - for (['feedback pending', 1, 0, 0], - ['fixed - council', 0, 1, 0], - ['external', 0, 1, 0], - ['hidden', 0, 0, 1]) - { - my ($state, $update, $public, $user_response) = @$_; - $report->update({ state => $state }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->contains_or_lacks($update, "name='status_update'"); - $mech->contains_or_lacks($public || $user_response, '<div class="admin-official-answer">'); - - if ($public) { - $mech->get_ok( '/report/' . $report->id ); - $mech->content_contains('Antwort</h4>'); - } - } - }; + # ALL closed states must hide the public_response edit, and public ones + # must show the answer in blue. + for (['feedback pending', 1, 0, 0], + ['fixed - council', 0, 1, 0], + ['external', 0, 1, 0], + ['hidden', 0, 0, 1]) + { + my ($state, $update, $public, $user_response) = @$_; + $report->update({ state => $state }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->contains_or_lacks($update, "name='status_update'"); + $mech->contains_or_lacks($public || $user_response, '<div class="admin-official-answer">'); + + if ($public) { + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Antwort</h4>'); + } + } }; subtest 'time_spent' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - my $report = $reports[0]; - - is $report->get_time_spent, 0, '0 minutes spent'; - $report->update({ state => 'in progress' }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'time_spent' ); - $mech->submit_form_ok( { - with_fields => { - time_spent => 10, - } }); - is $report->get_time_spent, 10, '10 minutes spent'; - }; + my $report = $reports[0]; + + is $report->get_time_spent, 0, '0 minutes spent'; + $report->update({ state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'time_spent' ); + $mech->submit_form_ok( { + with_fields => { + time_spent => 10, + } }); + is $report->get_time_spent, 10, '10 minutes spent'; }; $mech->log_out_ok; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAPIT_TYPES => [ 'ZZZ' ], -}, sub { - subtest 'users at the top level can be edited' => sub { - $mech->log_in_ok( $superuser->email ); - $mech->get_ok('/admin/users/' . $superuser->id ); - }; +subtest 'users at the top level can be edited' => sub { + $mech->log_in_ok( $superuser->email ); + $mech->get_ok('/admin/users/' . $superuser->id ); }; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], -}, sub { - subtest 'A visit to /reports is okay' => sub { - $mech->get_ok('/reports'); - }; +subtest 'A visit to /reports is okay' => sub { + $mech->get_ok('/reports'); }; -END { - ok $mech->host("www.fixmystreet.com"), "change host back"; - done_testing(); -} +}; -1; +done_testing(); diff --git a/t/map/tests.t b/t/map/tests.t index 1b152620e..f1f29dc06 100644 --- a/t/map/tests.t +++ b/t/map/tests.t @@ -12,6 +12,7 @@ my $requires = { 'Google' => 'map-google.js', 'GoogleOL' => 'map-google-ol.js', 'Hounslow' => 'map-wmts-hounslow.js', + 'IsleOfWight' => 'map-wmts-isleofwight.js', 'OSM' => 'OpenStreetMap.js', 'CycleMap' => 'OpenStreetMap.js', 'MapQuest' => 'OpenStreetMap.js', diff --git a/t/open311/getservicerequestupdates.t b/t/open311/getservicerequestupdates.t index 809fd3a19..6ed1d44fd 100644 --- a/t/open311/getservicerequestupdates.t +++ b/t/open311/getservicerequestupdates.t @@ -24,6 +24,7 @@ my $user = FixMyStreet::DB->resultset('User')->find_or_create( my %bodies = ( 2237 => FixMyStreet::DB->resultset("Body")->create({ name => 'Oxfordshire' }), 2494 => FixMyStreet::DB->resultset("Body")->create({ name => 'Bexley' }), + 2636 => FixMyStreet::DB->resultset("Body")->create({ name => 'Isle of Wight' }), 2482 => FixMyStreet::DB->resultset("Body")->create({ name => 'Bromley', send_method => 'Open311', @@ -36,6 +37,7 @@ my %bodies = ( ); $bodies{2237}->body_areas->create({ area_id => 2237 }); $bodies{2494}->body_areas->create({ area_id => 2494 }); +$bodies{2636}->body_areas->create({ area_id => 2636 }); my $response_template = $bodies{2482}->response_templates->create({ title => "investigating template", @@ -529,29 +531,33 @@ for my $test ( }; } -subtest 'Marking report as fixed closes it for updates (Bexley)' => sub { - my $local_requests_xml = setup_xml($problemB->external_id, $problemB->id, 'CLOSED'); - my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'servicerequestupdates.xml' => $local_requests_xml } ); +for ( + { id => 2494, cobrand => 'bexley' }, + { id => 2636, cobrand => 'isleofwight' } +) { + subtest "Marking report as fixed closes it for updates ($_->{cobrand})" => sub { + my $local_requests_xml = setup_xml($problemB->external_id, $problemB->id, 'CLOSED'); + my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'servicerequestupdates.xml' => $local_requests_xml } ); - $problemB->update( { bodies_str => $bodies{2494}->id } ); + $problemB->update( { bodies_str => $bodies{$_->{id}}->id } ); - my $update = Open311::GetServiceRequestUpdates->new( - system_user => $user, - current_open311 => $o, - current_body => $bodies{2494}, - current_cobrand => $bodies{2494}->get_cobrand_handler, - ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => 'bexley', - }, sub { - $update->process_body; - }; + my $update = Open311::GetServiceRequestUpdates->new( + system_user => $user, + current_open311 => $o, + current_body => $bodies{$_->{id}}, + ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => $_->{cobrand}, + }, sub { + $update->process_body; + }; - $problemB->discard_changes; - is $problemB->comments->count, 1, 'comment count'; - is $problemB->get_extra_metadata('closed_updates'), 1; - $problemB->comments->delete; -}; + $problemB->discard_changes; + is $problemB->comments->count, 1, 'comment count'; + is $problemB->get_extra_metadata('closed_updates'), 1; + $problemB->comments->delete; + }; +} subtest 'Update with media_url includes image in update' => sub { my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); diff --git a/templates/email/isleofwight/_council_reference.html b/templates/email/isleofwight/_council_reference.html new file mode 100644 index 000000000..5b73ee7e7 --- /dev/null +++ b/templates/email/isleofwight/_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 Island Roads about this report.</p> +[%~ END %] diff --git a/templates/email/isleofwight/_council_reference.txt b/templates/email/isleofwight/_council_reference.txt new file mode 100644 index 000000000..d6922217d --- /dev/null +++ b/templates/email/isleofwight/_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 Island Roads about this report.[% END %] diff --git a/templates/email/isleofwight/_council_reference_alert_update.html b/templates/email/isleofwight/_council_reference_alert_update.html new file mode 100644 index 000000000..5b73ee7e7 --- /dev/null +++ b/templates/email/isleofwight/_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 Island Roads about this report.</p> +[%~ END %] diff --git a/templates/email/isleofwight/_council_reference_alert_update.txt b/templates/email/isleofwight/_council_reference_alert_update.txt new file mode 100644 index 000000000..d6922217d --- /dev/null +++ b/templates/email/isleofwight/_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 Island Roads about this report.[% END %] diff --git a/templates/email/isleofwight/_email_color_overrides.html b/templates/email/isleofwight/_email_color_overrides.html new file mode 100644 index 000000000..3d6218ca4 --- /dev/null +++ b/templates/email/isleofwight/_email_color_overrides.html @@ -0,0 +1,19 @@ +[% + +color_cyan = '#00aeef' +color_blue = '#00478c' +color_green = '#75c044' +color_white = '#fff' + +header_background_color = color_white +header_text_color = color_blue + +secondary_column_background_color = color_white + +button_background_color = color_green +button_text_color = color_white + +logo_width = "282" # pixel measurement, but without 'px' suffix +logo_height = "76" # pixel measurement, but without 'px' suffix + +%] diff --git a/templates/email/isleofwight/confirm_report_sent.html b/templates/email/isleofwight/confirm_report_sent.html new file mode 100644 index 000000000..8e85c5729 --- /dev/null +++ b/templates/email/isleofwight/confirm_report_sent.html @@ -0,0 +1,42 @@ +[% + +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> + [% IF report.state == 'for triage' %] + <p style="[% p_style %]">Thank you for submitting your report to FixMyStreet, it will be submitted to Island Roads for review.</p> + [% ELSE %] + <p style="[% p_style %]">Thank you, your enquiry has been received by Island Roads and appropriate action will be taken.</p> + + <p style="[% p_style %]">We don't routinely contact customers regarding their enquiries, unless we have a specific query about + the issue. Any status updates for the issue can be tracked via FixMyStreet, if you contact us again about this issue, + please quote your 8-digit reference number.</p> + + <p style="[% p_style %]">Thank you for submitting your enquiry to us via FixMyStreet.</p> + [% END %] + +[% 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/isleofwight/confirm_report_sent.txt b/templates/email/isleofwight/confirm_report_sent.txt new file mode 100644 index 000000000..a368bd95e --- /dev/null +++ b/templates/email/isleofwight/confirm_report_sent.txt @@ -0,0 +1,43 @@ +Subject: Your report has been logged: [% report.title %] + +Hello [% report.name %], + +[% IF report.state == 'for triage' %] +Thank you for submitting your report to FixMyStreet, it will be +submitted to Island Roads for review. +[% ELSE %] +Thank you, your enquiry has been received by Island Roads and +appropriate action will be taken. + +We don't routinely contact customers regarding their enquiries, +unless we have a specific query about the issue. Any status +updates for the issue can be tracked via FixMyStreet, if you +contact us again about this issue, please quote your 8-digit +reference number. + +Thank you for submitting your enquiry to us via FixMyStreet. +[% END %] + +[% 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/isleofwight/problem-confirm.html b/templates/email/isleofwight/problem-confirm.html new file mode 100644 index 000000000..ccdefc7aa --- /dev/null +++ b/templates/email/isleofwight/problem-confirm.html @@ -0,0 +1,31 @@ +[% + +email_summary = "You need to confirm your " _ site_name _ " report before it can be sent to Island Roads."; +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 %]">Please confirm your report</h1> + <p style="[% p_style %]">Please click on the link below to confirm that you want to send your report to Island Roads. + +[% TRY %][% INCLUDE '_problem-confirm_extra.html' %][% CATCH file %][% END %] + </p> + [% UNLESS report.non_public %]<p style="[% p_style %]">Your report will also appear on the [% site_name %] website.</p>[% END %] + <p style="margin: 20px auto; text-align: center"> + <a style="[% button_style %]" href="[% token_url %]">Yes, send my report</a> + </p> + <p style="[% p_style %]">If you no longer wish to send this report, please take no further action.</p> + [% end_padded_box %] +</th> +[% WRAPPER '_email_sidebar.html' object = report, url = token_url %] + <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/isleofwight/problem-confirm.txt b/templates/email/isleofwight/problem-confirm.txt new file mode 100644 index 000000000..20a871453 --- /dev/null +++ b/templates/email/isleofwight/problem-confirm.txt @@ -0,0 +1,31 @@ +Subject: Confirm your report on [% site_name %] + +Hello [% report.name %], + +Please click on the link below to confirm that you want to send your report to +Island Roads.[% UNLESS report.non_public %] Note that your report will also +appear on the [% site_name %] website.[% END %] + +[% token_url %] + +If your email program does not let you click on this link, copy and paste it +into your web browser and press return. +[% TRY %][% INCLUDE '_problem-confirm_extra.txt' %][% CATCH file %][% END %] +Your problem had the title: + +[% report.title %] + +And details: + +[% report.detail %] + +If you no longer wish to send this report, please take no further action. + +Thank you for submitting a report through [% site_name %]. + + + +[% signature %] + +This email was sent automatically, from an unmonitored email account - so +please do not reply to it. diff --git a/templates/email/isleofwight/signature.txt b/templates/email/isleofwight/signature.txt new file mode 100644 index 000000000..e375a0402 --- /dev/null +++ b/templates/email/isleofwight/signature.txt @@ -0,0 +1,2 @@ + +Island Roads diff --git a/templates/web/base/admin/bodies/open311-form-fields.html b/templates/web/base/admin/bodies/open311-form-fields.html index bdd4ad935..be2f13af0 100644 --- a/templates/web/base/admin/bodies/open311-form-fields.html +++ b/templates/web/base/admin/bodies/open311-form-fields.html @@ -161,7 +161,7 @@ </p> </div> <p> - <input type="checkbox" id="fetch_all_problems" name="fetch_all_problems"[% ' checked' IF object.get_extra_metadata('fetch_all_problems') %]> + <input type="checkbox" id="fetch_all_problems" name="extra[fetch_all_problems]"[% ' checked' IF object.get_extra_metadata('fetch_all_problems') %]> <label for="fetch_all_problems" class="inline">[% loc('Always fetch all problems') %]</label> </p> </div> diff --git a/templates/web/base/admin/report-category.html b/templates/web/base/admin/report-category.html index 0416d71c0..64aa474b9 100644 --- a/templates/web/base/admin/report-category.html +++ b/templates/web/base/admin/report-category.html @@ -1,4 +1,7 @@ -<select class="form-control" name="category" id="category"> +[%~ IF NOT select_name %] + [%~ select_name = 'category' %] +[%~ END %] +<select class="form-control" name="[% select_name %]" id="[% select_name %]"> [% IF NOT problem.category OR NOT categories_hash.${problem.category} %] <optgroup label="[% loc('Existing category') %]"> <option selected value="[% problem.category | html %]">[% (problem.category_display OR '-') | html %]</option> diff --git a/templates/web/base/admin/triage/_inspect.html b/templates/web/base/admin/triage/_inspect.html new file mode 100644 index 000000000..926197ceb --- /dev/null +++ b/templates/web/base/admin/triage/_inspect.html @@ -0,0 +1,77 @@ +[% BLOCK category_list %] +<select class="form-control" name="[% field_name %]" id="[% field_name %]"> + [% IF category_options.size %] + [%~ IF category_groups.size ~%] + [%~ FOREACH group IN category_groups ~%] + [% IF group.name %]<optgroup label="[% group.name %]">[% END %] + [% group_select = 0 %] + [% selected = 0 %] + [%~ FOREACH cat_op IN group.categories ~%] + [% IF group_select == 0 AND problem.category == group.name %] + [% selected = 1; group_select = 1 %] + [% END %] + <option value="[% cat_op.category | html %]"[% ' selected' IF selected OR problem.category == cat_op.category %]>[% cat_op.category_display | html %] ([% cat_op.email | html %])</option> + [% selected = 0 %] + [%~ END ~%] + [% IF group.name %]</optgroup>[% END %] + [%~ END =%] + [% ELSE %] + [% FOREACH cat IN category_options %] + <option value="[% cat.category | html %]"[% ' selected' IF problem.category == cat.category %]>[% cat.category_display | html %]</option> + [% END %] + [% END %] + [% END %] +</select> +[% END %] + +[% permissions = c.user.permissions(problem) %] +[% second_column = BLOCK -%] + <div id="side-inspect"> + + <h2 class="inspect-form-heading">[% loc('Inspect report') %]</h2> + + [% INCLUDE 'errors.html' %] + + <form name="report_inspect_form" id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate"> + + [% INCLUDE 'report/inspect/information.html' no_relocate=1 %] + + [% IF permissions.report_edit_category OR permissions.report_inspect OR permissions.triage %] + <div class="inspect-section"> + <p> + <strong>Holding category:</strong> [% problem.category %] + </p> + + <p> + <label for="category">CONFIRM Subject</label> + [% PROCESS category_list category_groups=end_groups field_name="category" categories_hash=end_categories category_options=end_options %] + </p> + + </div> + [% END %] + + <div class="inspect-section"> + [%- extra_fields = problem.get_extra_fields -%] + [% FOR field IN extra_fields %] + [% NEXT IF field.name == 'urgent' %] + <p> + <label for="[% field.name %]">[% field.description %]</label> + <input class="form-control" name="[% field.name %]" type="text" value="[% field.value | html %]" disabled> + </p> + [% END %] + + [% IF permissions.report_inspect OR permissions.triage %] + [% INCLUDE 'report/inspect/public_update.html' public_update_defaulted=0 %] + [% END %] + + <p> + <input type="hidden" name="token" value="[% csrf_token %]" /> + <input class="btn btn-primary" type="submit" value="[% loc('Save changes') %]" data-value-original="[% loc('Save changes') %]" data-value-duplicate="[% loc('Save + close as duplicate') %]" name="save" /> + </p> + </div> + + <input type="hidden" name="js" value=""> + <input type="hidden" name="triage" value="1"> + </form> + </div> +[%- END %] diff --git a/templates/web/base/admin/triage/_list-filters.html b/templates/web/base/admin/triage/_list-filters.html new file mode 100644 index 000000000..f6bedcb80 --- /dev/null +++ b/templates/web/base/admin/triage/_list-filters.html @@ -0,0 +1,53 @@ +[% select_category = BLOCK %] + [% IF filter_categories.size %] + <select class="form-control js-multiple" name="filter_category" id="filter_categories" multiple data-all="[% loc('Everything') %]"> + [% FOR cat IN filter_categories %] + <option value="[% cat.category | html %]"[% ' selected' IF filter_category.${cat.category} %]> + [% cat.category_display | html %] + [%~ IF cat.get_extra_metadata('help_text') %] ([% cat.get_extra_metadata('help_text') %])[% END ~%] + </option> + [% END %] + </select> + [% ELSE %] + [% loc('Everything') %] + [% END %] +[% END %] + +<div class="report-list-filters-wrapper"> + +[% IF use_form_wrapper %] + <form method="get" action=""> +[% END %] + + <p class="report-list-filters"> + [% tprintf(loc('<label for="statuses">Show</label> %s reports <label for="filter_categories">about</label> %s', "The first %s is a dropdown of all/fixed/etc, the second is a dropdown of categories"), 'untriaged', select_category) %] + <input type="submit" name="filter_update" value="[% loc('Go') %]"> + </p> + + <p class="report-list-filters"> + <label for="sort">[% loc('Sort by') %]</label> + <select class="form-control" name="sort" id="sort"> + [% IF shortlist %] + <option value="shortlist"[% ' selected' IF sort_key == 'shortlist' %]>[% loc('Manual order') %]</option> + [% END %] + <option value="created-desc"[% ' selected' IF sort_key == 'created-desc' %]>[% loc('Newest') %]</option> + <option value="created-asc"[% ' selected' IF sort_key == 'created-asc' %]>[% loc('Oldest') %]</option> + <option value="updated-desc"[% ' selected' IF sort_key == 'updated-desc' %]>[% loc('Recently updated') %]</option> + <option value="updated-asc"[% ' selected' IF sort_key == 'updated-asc' %]>[% loc('Least recently updated') %]</option> + <option value="comments-desc"[% ' selected' IF sort_key == 'comments-desc' %]>[% loc('Most commented') %]</option> + </select> + <input type="submit" name="filter_update" value="[% loc('Go') %]"> + </p> + [% IF page == 'around' %] + <p id="show_old_reports_wrapper" class="report-list-filters[% ' hidden' UNLESS num_old_reports > 0 %]"> + <label for="show_old_reports">[% loc('Show older reports') %]</label> + <input type="checkbox" name="show_old_reports" id="show_old_reports" value="1"[% ' checked' IF show_old_reports %]> + <input type="submit" name="filter_update" value="[% loc('Go') %]"> + </p> + [% END %] + +[% IF use_form_wrapper %] + </form> +[% END %] + +</div> diff --git a/templates/web/base/admin/triage/index.html b/templates/web/base/admin/triage/index.html new file mode 100644 index 000000000..f00bbc1fa --- /dev/null +++ b/templates/web/base/admin/triage/index.html @@ -0,0 +1,42 @@ +[% SET body_name = body.name %] +[% IF c.cobrand.moniker == 'hounslow' %] + [% SET body_name = 'Hounslow Highways' %] +[% ELSIF c.cobrand.moniker == 'isleofwight' %] + [% SET body_name = 'Island Roads' %] +[% END %] + +[% + PROCESS "report/photo-js.html"; + PROCESS "maps/${map.type}.html"; + SET bodyclass = 'mappage'; + INCLUDE 'header.html', + title = 'Awaiting triage' + rss = [ tprintf(loc('Problems within %s, %s', "First %s is the body name, second %s the site name"), name, site_name), rss_url ] +%] + +[% map_html %] + +</div> +<div id="map_sidebar"> + <div id="side"> + + <h1 id="reports_heading"> + Awaiting triage + </h1> + +<section class="full-width"> +[% INCLUDE "admin/triage/_list-filters.html", use_form_wrapper = 1 %] +<div class="js-pagination"> +[% INCLUDE 'pagination.html', param = 'p' %] +</div> +<div id="js-reports-list"> + [% INCLUDE 'reports/_problem-list.html' %] +</div> +<div class="js-pagination"> +[% INCLUDE 'pagination.html', param = 'p' %] +</div> +</section> + + </div> +</div> +[% INCLUDE 'footer.html' %] diff --git a/templates/web/base/common_header_tags.html b/templates/web/base/common_header_tags.html index e29d96655..728b81363 100644 --- a/templates/web/base/common_header_tags.html +++ b/templates/web/base/common_header_tags.html @@ -23,10 +23,7 @@ [% INCLUDE 'header_rss.html' %] -<title> - [% "$title :: " | html IF title %] - [% site_name -%] -</title> +[% INCLUDE 'header/title.html' %] [% IF bodyclass.match('frontpage') %] <link rel="prefetch" href="[% version('/js/validation_rules.js') %]"> diff --git a/templates/web/base/header/title.html b/templates/web/base/header/title.html new file mode 100644 index 000000000..835c87790 --- /dev/null +++ b/templates/web/base/header/title.html @@ -0,0 +1,4 @@ +<title> + [% "$title :: " | html IF title %] + [% site_name -%] +</title> diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html index fa79d9912..10f3b6b84 100644 --- a/templates/web/base/report/_inspect.html +++ b/templates/web/base/report/_inspect.html @@ -11,60 +11,7 @@ <form name="report_inspect_form" id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate"> - <div class="inspect-section"> - <p style="float: right"> - <label for="non_public">[% loc('Private') %]</label> - <input type="checkbox" id="non_public" name="non_public" value="1"[% ' checked' IF problem.non_public %]> - </p> - <p> - <strong>[% loc('Report ID:') %]</strong> - <span class="js-report-id">[% problem.id %]</span> - [% IF c.user_exists AND c.cobrand.admin_allow_user(c.user) AND c.user.has_permission_to('report_edit', problem.bodies_str_ids) %] - (<a href="[% c.uri_for_action( "admin/report_edit", problem.id ) %]">[% loc('admin') %]</a>) - [% END %] - </p> - [% IF permissions.report_inspect AND problem.user.phone %] - <p> - <strong>[% loc('Phone Reporter:') %]</strong> - <a href="tel:[% problem.user.phone | html %]">[% problem.user.phone_display | html %]</a> - </p> - [% END %] - <p> - [% SET local_coords = problem.local_coords; %] - [% IF local_coords %] - <strong>[% loc('Easting/Northing:') %]</strong> - <span id="problem_easting">[% local_coords.0 %]</span>, - <span id="problem_northing">[% local_coords.1 %]</span> - [% ELSE %] - <strong>[% loc('Latitude/Longitude:') %]</strong> - <span id="problem_latitude">[% problem.latitude %]</span>, - <span id="problem_longitude">[% problem.longitude %]</span> - [% END %] - <input type="hidden" name="longitude" value="[% problem.longitude %]"> - <input type="hidden" name="latitude" value="[% problem.latitude %]"> - </p> - [% IF problem.nearest_address() %] - <p> - <strong>[% loc('Nearest calculated address:') %]</strong> - [% problem.nearest_address() %] - </p> - [% END %] - <p> - <a target="_blank" href="https://www.google.com/maps/dir/?api=1&destination=[% problem.latitude %],[% problem.longitude %]" class="btn btn--block btn--navigate">[% loc('Navigate to this problem') %]</a> - </p> - <p> - <a href="#" class="btn btn--block btn--geolocate">[% loc('Set to my current location') %]</a> - </p> - [% IF permissions.report_reject %] - [% TRY %] - [% INCLUDE 'report/_inspect_reject_button.html' %] - [% CATCH file %] - <p> - <a href="[% c.uri_for( '/contact', { id => problem.id, reject => 1 } ) %]" class="btn btn--block">[% loc('Reject report') %]</a> - </p> - [% END %] - [% END %] - </div> + [% INCLUDE 'report/inspect/information.html' %] [% IF permissions.report_edit_category OR permissions.report_inspect %] <div class="inspect-section"> @@ -182,17 +129,7 @@ <div class="inspect-section"> [% IF permissions.report_inspect %] - <p> - <label class="label-containing-checkbox"> - <input type="checkbox" name="include_update" value="1" class="js-toggle-public-update" checked> - [% loc('Save with a public update') %] - </label> - </p> - <p> - <label for="public_update">[% loc('Public update:') %]</label> - [% INCLUDE 'admin/response_templates_select.html' for='public_update' %] - <textarea rows="2" name="public_update" id="public_update" class="form-control">[% public_update | html %]</textarea> - </p> + [% INCLUDE 'report/inspect/public_update.html' %] [% END %] [% IF problem.get_extra_metadata('inspected') %] diff --git a/templates/web/base/report/inspect/information.html b/templates/web/base/report/inspect/information.html new file mode 100644 index 000000000..cc8989522 --- /dev/null +++ b/templates/web/base/report/inspect/information.html @@ -0,0 +1,56 @@ + <div class="inspect-section"> + <p style="float: right"> + <label for="non_public">[% loc('Private') %]</label> + <input type="checkbox" id="non_public" name="non_public" value="1"[% ' checked' IF problem.non_public %]> + </p> + <p> + <strong>[% loc('Report ID:') %]</strong> + <span class="js-report-id">[% problem.id %]</span> + [% IF c.user_exists AND c.cobrand.admin_allow_user(c.user) AND c.user.has_permission_to('report_edit', problem.bodies_str_ids) %] + (<a href="[% c.uri_for_action( "admin/report_edit", problem.id ) %]">[% loc('admin') %]</a>) + [% END %] + </p> + [% IF permissions.report_inspect AND problem.user.phone %] + <p> + <strong>[% loc('Phone Reporter:') %]</strong> + <a href="tel:[% problem.user.phone | html %]">[% problem.user.phone_display | html %]</a> + </p> + [% END %] + <p> + [% SET local_coords = problem.local_coords; %] + [% IF local_coords %] + <strong>[% loc('Easting/Northing:') %]</strong> + <span id="problem_easting">[% local_coords.0 %]</span>, + <span id="problem_northing">[% local_coords.1 %]</span> + [% ELSE %] + <strong>[% loc('Latitude/Longitude:') %]</strong> + <span id="problem_latitude">[% problem.latitude %]</span>, + <span id="problem_longitude">[% problem.longitude %]</span> + [% END %] + <input type="hidden" name="longitude" value="[% problem.longitude %]"> + <input type="hidden" name="latitude" value="[% problem.latitude %]"> + </p> + [% IF problem.nearest_address() %] + <p> + <strong>[% loc('Nearest calculated address:') %]</strong> + [% problem.nearest_address() %] + </p> + [% END %] + <p> + <a target="_blank" href="https://www.google.com/maps/dir/?api=1&destination=[% problem.latitude %],[% problem.longitude %]" class="btn btn--block btn--navigate">[% loc('Navigate to this problem') %]</a> + </p> + [% UNLESS no_relocate %] + <p> + <a href="#" class="btn btn--block btn--geolocate">[% loc('Set to my current location') %]</a> + </p> + [% END %] + [% IF permissions.report_reject %] + [% TRY %] + [% INCLUDE 'report/_inspect_reject_button.html' %] + [% CATCH file %] + <p> + <a href="[% c.uri_for( '/contact', { id => problem.id, reject => 1 } ) %]" class="btn btn--block">[% loc('Reject report') %]</a> + </p> + [% END %] + [% END %] + </div> diff --git a/templates/web/base/report/inspect/public_update.html b/templates/web/base/report/inspect/public_update.html new file mode 100644 index 000000000..be07d7b89 --- /dev/null +++ b/templates/web/base/report/inspect/public_update.html @@ -0,0 +1,14 @@ +[% IF NOT public_update_defaulted.defined %] + [% public_update_defaulted = 1 %] +[% END %] + <p> + <label class="label-containing-checkbox"> + <input type="checkbox" name="include_update" value="1" class="js-toggle-public-update"[% ' checked' IF public_update_defaulted %]> + [% loc('Save with a public update') %] + </label> + </p> + <p> + <label for="public_update">[% loc('Public update:') %]</label> + [% INCLUDE 'admin/response_templates_select.html' for='public_update' %] + <textarea rows="2" name="public_update" id="public_update" class="form-control">[% public_update | html %]</textarea> + </p> diff --git a/templates/web/base/report/new/category_extras.html b/templates/web/base/report/new/category_extras.html index c7bdad94d..8e5b02952 100644 --- a/templates/web/base/report/new/category_extras.html +++ b/templates/web/base/report/new/category_extras.html @@ -1,4 +1,4 @@ -[% SET default_list = [] %][% FOR b IN bodies_to_list.values %][% default_list.push(b.name) %][% END %] +[% SET default_list = [] %][% FOR b IN bodies_to_list.values %][% default_list.push(b.cobrand_name) %][% END %] [% DEFAULT list_of_names = default_list %] <div id="category_meta"> diff --git a/templates/web/base/report/new/councils_text_all.html b/templates/web/base/report/new/councils_text_all.html index 8b9abf1f3..63f4125f4 100644 --- a/templates/web/base/report/new/councils_text_all.html +++ b/templates/web/base/report/new/councils_text_all.html @@ -1,4 +1,4 @@ -[% SET default_list = [] %][% FOR b IN bodies_to_list.values %][% default_list.push(b.name) %][% END %] +[% SET default_list = [] %][% FOR b IN bodies_to_list.values %][% default_list.push(b.cobrand_name) %][% END %] [% DEFAULT list_of_names = default_list %] <p> diff --git a/templates/web/base/report/updates.html b/templates/web/base/report/updates.html index 817cc7eb4..93bae4d64 100644 --- a/templates/web/base/report/updates.html +++ b/templates/web/base/report/updates.html @@ -6,6 +6,9 @@ [%- END %] [%- NEXT %] [%- END %] +[%- IF update.get_extra_metadata('triage_report') == 1 AND ( NOT c.user OR ( NOT c.user.from_body AND NOT c.user.is_superuser ) ) %] + [%- NEXT %] +[%- END %] [% INCLUDE 'report/update.html' %] [% END %] diff --git a/templates/web/base/reports/_list-filter-status.html b/templates/web/base/reports/_list-filter-status.html new file mode 100644 index 000000000..6923a7929 --- /dev/null +++ b/templates/web/base/reports/_list-filter-status.html @@ -0,0 +1,45 @@ +[% SET show_all_states = c.cobrand.filter_show_all_states OR (c.user_exists AND (c.user.is_superuser OR c.user.belongs_to_body(body.id))) %] + +<select class="form-control js-multiple" name="status" id="statuses" multiple + data-all="[% loc('All') %]" + [% IF show_all_states %] + [% options = []; + FOR group IN filter_states; FOR state IN group.1; + NEXT IF state == 'hidden'; + SET state = 'fixed' IF state == 'fixed - council'; + options.push(state); + END; END + %] + data-all-options='["[% options.join('", "') %]"]' + [%~ ELSE ~%] + [%~ IF has_fixed_state ~%] + data-all-options='["open","closed","fixed"]' + [%~ ELSE ~%] + data-all-options='["open","closed"]' + [%~ END ~%] + [%~ END ~%] + [% INCLUDE 'reports/_status_filter_options.html' %] + > + [% IF c.user_exists AND c.user.has_body_permission_to('planned_reports') AND !shortlist %] + <option value="shortlisted"[% ' selected' IF filter_status.shortlisted %]>[% loc('Shortlisted') %]</option> + <option value="unshortlisted"[% ' selected' IF filter_status.unshortlisted %]>[% loc('Unshortlisted') %]</option> + [% END %] + [% IF c.user_exists AND ( c.user.has_body_permission_to('report_inspect') OR c.user.has_body_permission_to('report_mark_private') ) %] + <option value="non_public"[% ' selected' IF filter_status.non_public %]>[% loc('Private only') %]</option> + [% END %] + [% IF show_all_states %] + [% FOR group IN filter_states %] + [% FOR state IN group.1 %] + [% NEXT IF state == 'hidden' %] + [% SET state = 'fixed' IF state == 'fixed - council' ~%] + <option value="[% state %]"[% ' selected' IF filter_status.$state %]>[% prettify_state(state, 1) %]</option> + [% END %] + [% END %] + [% ELSE %] + <option value="open"[% ' selected' IF filter_status.open %]>[% prettify_state('confirmed') %]</option> + <option value="closed"[% ' selected' IF filter_status.closed %]>[% prettify_state('closed') %]</option> + [% IF has_fixed_state %] + <option value="fixed"[% ' selected' IF filter_status.fixed %]>[% prettify_state('fixed') %]</option> + [% END %] + [% END %] +</select> diff --git a/templates/web/base/reports/_list-filters.html b/templates/web/base/reports/_list-filters.html index 6acb5936c..77c257e01 100644 --- a/templates/web/base/reports/_list-filters.html +++ b/templates/web/base/reports/_list-filters.html @@ -1,49 +1,4 @@ -[% SET show_all_states = c.cobrand.filter_show_all_states OR (c.user_exists AND (c.user.is_superuser OR c.user.belongs_to_body(body.id))) %] -[% select_status = BLOCK %] - <select class="form-control js-multiple" name="status" id="statuses" multiple - data-all="[% loc('All') %]" - [% IF show_all_states %] - [% options = []; - FOR group IN filter_states; FOR state IN group.1; - NEXT IF state == 'hidden'; - SET state = 'fixed' IF state == 'fixed - council'; - options.push(state); - END; END - %] - data-all-options='["[% options.join('", "') %]"]' - [%~ ELSE ~%] - [%~ IF has_fixed_state ~%] - data-all-options='["open","closed","fixed"]' - [%~ ELSE ~%] - data-all-options='["open","closed"]' - [%~ END ~%] - [%~ END ~%] - [% INCLUDE 'reports/_status_filter_options.html' %] - > - [% IF c.user_exists AND c.user.has_body_permission_to('planned_reports') AND !shortlist %] - <option value="shortlisted"[% ' selected' IF filter_status.shortlisted %]>[% loc('Shortlisted') %]</option> - <option value="unshortlisted"[% ' selected' IF filter_status.unshortlisted %]>[% loc('Unshortlisted') %]</option> - [% END %] - [% IF c.user_exists AND ( c.user.has_body_permission_to('report_inspect') OR c.user.has_body_permission_to('report_mark_private') ) %] - <option value="non_public"[% ' selected' IF filter_status.non_public %]>[% loc('Private only') %]</option> - [% END %] - [% IF show_all_states %] - [% FOR group IN filter_states %] - [% FOR state IN group.1 %] - [% NEXT IF state == 'hidden' %] - [% SET state = 'fixed' IF state == 'fixed - council' ~%] - <option value="[% state %]"[% ' selected' IF filter_status.$state %]>[% prettify_state(state, 1) %]</option> - [% END %] - [% END %] - [% ELSE %] - <option value="open"[% ' selected' IF filter_status.open %]>[% prettify_state('confirmed') %]</option> - <option value="closed"[% ' selected' IF filter_status.closed %]>[% prettify_state('closed') %]</option> - [% IF has_fixed_state %] - <option value="fixed"[% ' selected' IF filter_status.fixed %]>[% prettify_state('fixed') %]</option> - [% END %] - [% END %] - </select> -[% END %] +[% select_status = PROCESS 'reports/_list-filter-status.html' %] [% select_category = BLOCK %] [% IF filter_categories.size %] diff --git a/templates/web/base/reports/body.html b/templates/web/base/reports/body.html index 02791ba3b..23540104b 100755 --- a/templates/web/base/reports/body.html +++ b/templates/web/base/reports/body.html @@ -1,6 +1,8 @@ [% SET body_name = body.name %] [% IF c.cobrand.moniker == 'hounslow' %] [% SET body_name = 'Hounslow Highways' %] +[% ELSIF c.cobrand.moniker == 'isleofwight' %] + [% SET body_name = 'Island Roads' %] [% END %] [% IF ward %] diff --git a/templates/web/fixmystreet.com/footer_extra_js.html b/templates/web/fixmystreet.com/footer_extra_js.html index 3f3e61c52..6fcb5d59c 100644 --- a/templates/web/fixmystreet.com/footer_extra_js.html +++ b/templates/web/fixmystreet.com/footer_extra_js.html @@ -10,6 +10,7 @@ IF bodyclass.match('mappage'); scripts.push( version('/cobrands/bristol/assets.js') ); scripts.push( version('/cobrands/bromley/assets.js') ); scripts.push( version('/cobrands/buckinghamshire/assets.js') ); + scripts.push( version('/cobrands/isleofwight/assets.js') ); scripts.push( version('/cobrands/lincolnshire/assets.js') ); scripts.push( version('/cobrands/northamptonshire/assets.js') ); scripts.push( version('/cobrands/hounslow/assets.js') ); diff --git a/templates/web/hounslow/report/new/councils_text_all.html b/templates/web/hounslow/report/new/councils_text_all.html deleted file mode 100644 index c434813f8..000000000 --- a/templates/web/hounslow/report/new/councils_text_all.html +++ /dev/null @@ -1,8 +0,0 @@ -<p> - [% UNLESS non_public_categories.$category %] - 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>. - [% ELSE %] - These will be sent to <strong>Hounslow Highways</strong> but not published online. - [% END %] -</p> diff --git a/templates/web/isleofwight/about/mapterms.html b/templates/web/isleofwight/about/mapterms.html new file mode 100644 index 000000000..04c0aeb09 --- /dev/null +++ b/templates/web/isleofwight/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/isleofwight/footer_extra_js.html b/templates/web/isleofwight/footer_extra_js.html new file mode 100644 index 000000000..0ad3525e6 --- /dev/null +++ b/templates/web/isleofwight/footer_extra_js.html @@ -0,0 +1,10 @@ +[% 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/fixmystreet-uk-councils/js.js'), + version('/cobrands/isleofwight/js.js'), + version('/cobrands/isleofwight/assets.js'), + ); +END %] diff --git a/templates/web/isleofwight/header_extra.html b/templates/web/isleofwight/header_extra.html new file mode 100644 index 000000000..8a977495f --- /dev/null +++ b/templates/web/isleofwight/header_extra.html @@ -0,0 +1 @@ +[% INCLUDE 'tracking_code.html' %] diff --git a/templates/web/isleofwight/header_logo.html b/templates/web/isleofwight/header_logo.html new file mode 100644 index 000000000..e563007a7 --- /dev/null +++ b/templates/web/isleofwight/header_logo.html @@ -0,0 +1,2 @@ +<a href="http://www.islandroads.com" id="site-logo">Island Roads</a> +<a href="/" id="report-cta" title="[%- loc('Report a problem') -%]">[%- loc('Report') -%]</a> diff --git a/templates/web/isleofwight/main_nav_items.html b/templates/web/isleofwight/main_nav_items.html new file mode 100644 index 000000000..5b794a99d --- /dev/null +++ b/templates/web/isleofwight/main_nav_items.html @@ -0,0 +1,59 @@ +[%~ 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 ~%] + +[%~ IF c.user_exists AND c.user.has_body_permission_to('triage') ~%] + [%~ INCLUDE navitem always_url=1 uri='/admin/triage' label=loc('Awaiting triage') ~%] +[%~ 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 c.cobrand.council_area; + body_name = c.cobrand.council_area | 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='/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/isleofwight/report/_updates_disallowed_message.html b/templates/web/isleofwight/report/_updates_disallowed_message.html new file mode 100644 index 000000000..af56f73b1 --- /dev/null +++ b/templates/web/isleofwight/report/_updates_disallowed_message.html @@ -0,0 +1,8 @@ +<p> + Only the original reporter may leave updates. + [% IF NOT c.user_exists %] + If you made the original report please + <a href="/auth?r=report/[% problem.id %]">log in</a> + to leave an update. + [% END %] +</p> diff --git a/templates/web/isleofwight/report/inspect.html b/templates/web/isleofwight/report/inspect.html new file mode 100644 index 000000000..6cecff926 --- /dev/null +++ b/templates/web/isleofwight/report/inspect.html @@ -0,0 +1,10 @@ +[% + SET bodyclass = 'mappage with-actions'; + SET two_column_sidebar = 1; + IF problem.state == 'for triage'; + PROCESS 'admin/triage/_inspect.html'; + ELSE; + PROCESS 'report/_inspect.html'; + END; + INCLUDE 'report/display.html' +%] diff --git a/templates/web/isleofwight/report/new/_form_labels.html b/templates/web/isleofwight/report/new/_form_labels.html new file mode 100644 index 000000000..a666ab0a3 --- /dev/null +++ b/templates/web/isleofwight/report/new/_form_labels.html @@ -0,0 +1,3 @@ +[% +SET form_title = 'Summarise the problem and location'; +%] diff --git a/templates/web/isleofwight/tokens/_confirm_problem_council_id.html b/templates/web/isleofwight/tokens/_confirm_problem_council_id.html new file mode 100644 index 000000000..703fbd1b6 --- /dev/null +++ b/templates/web/isleofwight/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/isleofwight/tracking_code.html b/templates/web/isleofwight/tracking_code.html new file mode 100644 index 000000000..26358b589 --- /dev/null +++ b/templates/web/isleofwight/tracking_code.html @@ -0,0 +1,16 @@ +[% IF c.config.BASE_URL == "https://www.fixmystreet.com" %] + +<script> + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-136557400-2', 'auto'); + ga('send', 'pageview'); + +</script> + +[% ELSE %] +<!-- Tracking code not inserted as "[% c.config.BASE_URL %]" not "https://www.fixmystreet.com" --> +[% END %] diff --git a/templates/web/westminster/footer_extra_js.html b/templates/web/westminster/footer_extra_js.html index ec25926c5..f89cee3d4 100644 --- a/templates/web/westminster/footer_extra_js.html +++ b/templates/web/westminster/footer_extra_js.html @@ -3,6 +3,8 @@ 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/westminster/roadworks.js'), version('/cobrands/westminster/assets.js'), ); END diff --git a/templates/web/zurich/admin/bodies/contact-form.html b/templates/web/zurich/admin/bodies/contact-form.html index 7b59124fb..8449f2d39 100644 --- a/templates/web/zurich/admin/bodies/contact-form.html +++ b/templates/web/zurich/admin/bodies/contact-form.html @@ -15,6 +15,11 @@ <input type="text" class="form-control" name="extra[abbreviation]" id="abbreviation" size="30" value="[% contact.get_extra_metadata('abbreviation') | html %]"> </p> + <p> + <label for="admin_label">Admin-label</label> + <input type="text" class="form-control" name="extra[admin_label]" id="admin_label" size="30" value="[% contact.get_extra_metadata('admin_label') | html %]"> + </p> + <p><strong>[% loc('Email:') %] </strong> <input type="text" class="form-control" name="email" value="[% contact.email | html %]" size="30"> @@ -29,15 +34,12 @@ </div> <p> - [% IF contact.in_storage %] <label for="state">[% loc('State') %]</label> <select name="state" id="state"> <option value="confirmed"[% ' selected' IF contact.state == 'confirmed' %]>[% loc('Confirmed') %] + <option value="inactive"[% ' selected' IF contact.state == 'inactive' %]>[% loc('Inactive') %] <option value="deleted"[% ' selected' IF contact.state == 'deleted' %]>[% loc('Deleted') %] </select> - [% ELSE %] - <input type="hidden" name="state" value="confirmed" id="confirmed"> - [% END %] <input type="checkbox" name="photo_required" value="1" id="photo_required"[% ' checked' IF contact.get_extra_metadata('photo_required') %]> <label class="inline" for="photo_required">[% loc('Photo required') %]</label> </p> diff --git a/templates/web/zurich/admin/bodies/form.html b/templates/web/zurich/admin/bodies/form.html index b625efc44..f9cd4f812 100644 --- a/templates/web/zurich/admin/bodies/form.html +++ b/templates/web/zurich/admin/bodies/form.html @@ -20,6 +20,18 @@ </select> </p> + [% IF body AND NOT body.parent AND NOT body.bodies %] + <p> + <label for="category">[% loc('Category') %]</label> + <select class="form-control" name="extra[category]" id="category"> + <option value="">[% loc('-- Pick a category --') %]</option> + [% FOR cat IN c.cobrand.category_options %] + <option value="[% cat.category %]"[% ' selected' IF cat.category == body.get_extra_metadata('category') %]>[% cat.category_display | html %]</option> + [% END %] + </select> + </p> + [% END %] + <p> <label for="area_ids">[% loc('Area covered') %]</label> <select class="form-control js-multiple" name="area_ids" id="area_ids" multiple data-none="-- [% loc('Select an area') %] --"> diff --git a/templates/web/zurich/admin/index-dm.html b/templates/web/zurich/admin/index-dm.html index c93adbfb3..92df5b415 100644 --- a/templates/web/zurich/admin/index-dm.html +++ b/templates/web/zurich/admin/index-dm.html @@ -1,7 +1,9 @@ [% PROCESS 'admin/header.html' title=loc('Summary') -%] [% PROCESS 'admin/report_blocks.html' %] -[% INCLUDE status_message %] +<div class="index-status"> +[% status_message %] +</div> <h2 id="submitted">[% loc('Submitted') %]</h2> [% INCLUDE list, problems = submitted.all, hash = 'submitted' %] diff --git a/templates/web/zurich/admin/report_edit-sdm.html b/templates/web/zurich/admin/report_edit-sdm.html index b9fb6ff4d..d8e6c2625 100644 --- a/templates/web/zurich/admin/report_edit-sdm.html +++ b/templates/web/zurich/admin/report_edit-sdm.html @@ -39,23 +39,11 @@ <dd class="screen-no-space-after"> <strong>[% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</strong> </dd> - <dt class="print-only">[% loc('Coordinates:') %] <!-- Koordinaten --></dt> - <dd class="screen-no-space-after print-no-space-after"> - [% problem.local_coords.join(',') %] - <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]"> - <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]"> - </dd> - <dd class="screen-no-space-after print-no-space-after"> - [% IF problem.used_map %] - [% loc('Used map') %] - [% ELSE %] - [% loc("Didn't use map") %] - [% END %] - </dd> - <dd>[% - safe = problem.postcode | html; - tprintf( loc('originally entered: “%s”'), safe ) - %]</dd> + + <dd>[% c.cobrand.admin_district_lookup(problem) %]</dd> + + <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]"> + <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]"> <dt class="print-only">[% loc('Reported by:') %] <!-- Meldende Person --></dt> <dd> @@ -78,10 +66,6 @@ <dt>[% loc('Time spent (in minutes):') %]</dt> <dd>[% problem.get_time_spent %]</dd> - <dd> - [% INCLUDE status_message %] - </dd> - [% IF problem.photo %] <dd> [% FOR photo IN problem.photos %] @@ -102,6 +86,9 @@ <div class="admin-report-edit admin-report-edit--interact"> <p align="right" class="screen-only"><input [% sdm_disabled %] type="submit" class="btn" name="send_back" value="[% loc('Not for my subdivision') %]"></p> + +[% status_message %] + <p align="right" class="screen-only"><input [% sdm_disabled %] type="submit" class="btn" name="not_contactable" value="[% loc('Customer not contactable') %]"></p> <ul class="no-bullets screen-only"> diff --git a/templates/web/zurich/admin/report_edit.html b/templates/web/zurich/admin/report_edit.html index 0186a6286..6f69161fe 100644 --- a/templates/web/zurich/admin/report_edit.html +++ b/templates/web/zurich/admin/report_edit.html @@ -58,23 +58,11 @@ <dd class="screen-no-space-after"> <strong>[% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</strong> </dd> - <dt class="print-only">[% loc('Coordinates:') %] <!-- Koordinaten --></dt> - <dd class="screen-no-space-after print-no-space-after"> - [% problem.local_coords.join(',') %] - <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]"> - <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]"> - </dd> - <dd class="screen-no-space-after print-no-space-after"> - [% IF problem.used_map %] - [% loc('Used map') %] - [% ELSE %] - [% loc("Didn't use map") %] - [% END %] - </dd> - <dd>[% - safe = problem.postcode | html; - tprintf( loc('originally entered: “%s”'), safe ) - %]</dd> + + <dd>[% c.cobrand.admin_district_lookup(problem) %]</dd> + + <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]"> + <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]"> [% SET fields = problem.get_extra_fields; IF fields.size %] <dd> @@ -129,7 +117,7 @@ <div class="admin-report-edit admin-report-edit--interact"> -[% INCLUDE status_message %] +[% status_message %] <dl [% IF status_message %]class="with-message"[% END %]> @@ -280,6 +268,7 @@ [% ELSE %] [% loc('Message to competent body:') %] [% END %] + [% problem.body(c).endpoint %] </h2> <div class="admin-external-message"> [% problem.extra.external_message | html_para %] diff --git a/templates/web/zurich/header.html b/templates/web/zurich/header.html index b453465f7..cd08e9503 100644 --- a/templates/web/zurich/header.html +++ b/templates/web/zurich/header.html @@ -9,6 +9,7 @@ <meta name="HandHeldFriendly" content="true"> <meta name="mobileoptimized" content="0"> + [% INCLUDE 'header_opengraph.html' %] [% INCLUDE 'header/css.html' %] <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/redmond/jquery-ui.css"> diff --git a/templates/web/zurich/header/title.html b/templates/web/zurich/header/title.html new file mode 100644 index 000000000..118817e48 --- /dev/null +++ b/templates/web/zurich/header/title.html @@ -0,0 +1,4 @@ +<title> + [% "$title :: " | html IF title %] + Züri wie neu – Infrastrukturschäden melden – Stadt Zürich +</title> diff --git a/templates/web/zurich/header_opengraph.html b/templates/web/zurich/header_opengraph.html new file mode 100644 index 000000000..0a7dc42d7 --- /dev/null +++ b/templates/web/zurich/header_opengraph.html @@ -0,0 +1,8 @@ + <meta property="og:url" content="[% c.cobrand.base_url %][% c.req.uri.path %]"> + <meta property="og:title" content="[% title || site_name | html %]"> + <meta property="og:site_name" content="[% site_name %]"> + [% IF c.req.uri.path == '/' %] + <meta name="description" property="og:description" content="Melden Sie Schäden an der Infrastruktur der Stadt Zürich wie Schlaglöcher, defekte Beleuchtung/Signalisation, Graffitis, Schädlinge oder Abfall auf öffentlichem Grund."> + [% END %] + <meta property="og:type" content="website"> + [% INCLUDE 'header_opengraph_image.html' %] diff --git a/templates/web/zurich/reports/_list-filter-status.html b/templates/web/zurich/reports/_list-filter-status.html new file mode 100644 index 000000000..bf56821f6 --- /dev/null +++ b/templates/web/zurich/reports/_list-filter-status.html @@ -0,0 +1,7 @@ +<select class="form-control js-multiple" name="status" id="statuses" multiple + data-all="[% loc('All') %]" data-all-options='["open","closed"]' + [% INCLUDE 'reports/_status_filter_options.html' %] +> + <option value="open"[% ' selected' IF filter_status.open %]>[% prettify_state('confirmed') %]</option> + <option value="closed"[% ' selected' IF filter_status.closed %]>[% prettify_state('closed') %]</option> +</select> diff --git a/web/cobrands/fixmystreet-uk-councils/roadworks.js b/web/cobrands/fixmystreet-uk-councils/roadworks.js index f4da4c310..2b0de306a 100644 --- a/web/cobrands/fixmystreet-uk-councils/roadworks.js +++ b/web/cobrands/fixmystreet-uk-councils/roadworks.js @@ -222,16 +222,4 @@ fixmystreet.roadworks.display_message = function(feature) { $msg.prependTo('#js-post-category-messages'); }; -/* Stop sending a needless header so that no preflight CORS request */ -OpenLayers.Request.XMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { - if (sName.toLowerCase() == 'x-requested-with') { - return; - } - if (!this._headers) { - this._headers = {}; - } - this._headers[sName] = sValue; - return this._object.setRequestHeader(sName, sValue); -}; - })(); diff --git a/web/cobrands/fixmystreet/assets.js b/web/cobrands/fixmystreet/assets.js index c30fa2b5e..0b2205076 100644 --- a/web/cobrands/fixmystreet/assets.js +++ b/web/cobrands/fixmystreet/assets.js @@ -71,7 +71,7 @@ OpenLayers.Layer.VectorAsset = OpenLayers.Class(OpenLayers.Layer.Vector, { if (!fixmystreet.markers.getVisibility() || !(this.getVisibility() && this.inRange)) { return; } - var threshold = 50; // metres + var threshold = this.fixmystreet.snap_threshold || 50; // metres var marker = fixmystreet.markers.features[0]; if (marker === undefined) { // No marker to be found so bail out @@ -375,7 +375,7 @@ function clear_fields_for_attributes(attributes) { } function check_zoom_message_visibility() { - if (this.fixmystreet.non_interactive) { + if (this.fixmystreet.non_interactive && !this.fixmystreet.display_zoom_message) { return; } var select = this.fixmystreet.asset_group ? 'category_group' : 'form_category'; @@ -419,6 +419,9 @@ function layer_visibilitychanged() { if (!this.getVisibility()) { this.road_not_found(); } + if (this.fixmystreet.display_zoom_message) { + check_zoom_message_visibility.call(this); + } return; } else if (!this.getVisibility()) { asset_unselected.call(this); @@ -944,16 +947,6 @@ OpenLayers.Format.GML.v3.MultiCurveFix = OpenLayers.Class(OpenLayers.Format.GML. CLASS_NAME: "OpenLayers.Format.GML.v3.MultiCurveFix" }); -OpenLayers.Request.XMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { - if (sName.toLowerCase() == 'x-requested-with') { - return; - } - if (!this._headers) { - this._headers = {}; - } - this._headers[sName] = sValue; - return this._object.setRequestHeader(sName, sValue); -}; })(); /* Handling of body override functionality */ @@ -1031,6 +1024,7 @@ fixmystreet.message_controller = (function() { var stopperId = 'js-category-stopper', stoppers = [], ignored_bodies = []; + msg_after_bodies = []; // This shows an error message because e.g. an asset isn't selected or a road hasn't been clicked function show_responsibility_error(id, asset_item, asset_type) { @@ -1129,6 +1123,14 @@ fixmystreet.message_controller = (function() { } } + function stopper_after(stopper) { + var body = fixmystreet.bodies[0]; + if (OpenLayers.Util.indexOf( msg_after_bodies, body) > -1 ) { + return true; + } + return false; + } + function check_for_stopper() { var only_send = fixmystreet.body_overrides.get_only_send(); if (only_send == 'Highways England') { @@ -1160,7 +1162,11 @@ fixmystreet.message_controller = (function() { if ($id.length) { $id.replaceWith($msg); } else { - $msg.insertBefore('#js-post-category-messages'); + if (stopper_after(stopper)) { + $msg.insertAfter('#js-post-category-messages'); + } else { + $msg.insertBefore('#js-post-category-messages'); + } } disable_report_form(stopper.keep_category_extras); } @@ -1235,6 +1241,10 @@ fixmystreet.message_controller = (function() { add_ignored_body: function(body) { ignored_bodies.push(body); + }, + + add_msg_after_bodies: function(body) { + msg_after_bodies.push(body); } }; diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js index 8d6b2091b..c7749c729 100644 --- a/web/cobrands/fixmystreet/fixmystreet.js +++ b/web/cobrands/fixmystreet/fixmystreet.js @@ -1522,7 +1522,12 @@ fixmystreet.display = { window.selected_problem_id = reportId; var marker = fixmystreet.maps.get_marker_by_id(reportId); - if (fixmystreet.map.panTo && ($('html').hasClass('mobile') || !marker.onScreen())) { + var el = document.querySelector('input[name=triage]'); + if (el) { + fixmystreet.map.setCenter( + marker.geometry.getBounds().getCenterLonLat(), + fixmystreet.map.getNumZoomLevels() - 1 ); + } else if (fixmystreet.map.panTo && ($('html').hasClass('mobile') || !marker.onScreen())) { fixmystreet.map.panTo( marker.geometry.getBounds().getCenterLonLat() ); @@ -1538,8 +1543,10 @@ fixmystreet.display = { if (fixmystreet.maps.setup_inspector) { fixmystreet.maps.setup_inspector(); + fixmystreet.map.updateSize(); } + if (typeof callback === 'function') { callback(); } diff --git a/web/cobrands/fixmystreet/staff.js b/web/cobrands/fixmystreet/staff.js index b074a49f3..17bd54b8b 100644 --- a/web/cobrands/fixmystreet/staff.js +++ b/web/cobrands/fixmystreet/staff.js @@ -261,19 +261,22 @@ fixmystreet.staff_set_up = { if ('geolocation' in navigator) { var el = document.querySelector('.btn--geolocate'); - fixmystreet.geolocate(el, function(pos) { - var latlon = new OpenLayers.LonLat(pos.coords.longitude, pos.coords.latitude); - var bng = latlon.clone().transform( - new OpenLayers.Projection("EPSG:4326"), - new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections - ); - $("#problem_northing").text(bng.lat.toFixed(1)); - $("#problem_easting").text(bng.lon.toFixed(1)); - $("#problem_latitude").text(latlon.lat.toFixed(6)); - $("#problem_longitude").text(latlon.lon.toFixed(6)); - $inspect_form.find("input[name=latitude]").val(latlon.lat); - $inspect_form.find("input[name=longitude]").val(latlon.lon); - }); + // triage pages may not show geolocation button + if (el) { + fixmystreet.geolocate(el, function(pos) { + var latlon = new OpenLayers.LonLat(pos.coords.longitude, pos.coords.latitude); + var bng = latlon.clone().transform( + new OpenLayers.Projection("EPSG:4326"), + new OpenLayers.Projection("EPSG:27700") // TODO: Handle other projections + ); + $("#problem_northing").text(bng.lat.toFixed(1)); + $("#problem_easting").text(bng.lon.toFixed(1)); + $("#problem_latitude").text(latlon.lat.toFixed(6)); + $("#problem_longitude").text(latlon.lon.toFixed(6)); + $inspect_form.find("input[name=latitude]").val(latlon.lat); + $inspect_form.find("input[name=longitude]").val(latlon.lon); + }); + } } // Make the "Provide an update" form toggleable, hidden by default. diff --git a/web/cobrands/isleofwight/_colours.scss b/web/cobrands/isleofwight/_colours.scss new file mode 100644 index 000000000..688eb66e0 --- /dev/null +++ b/web/cobrands/isleofwight/_colours.scss @@ -0,0 +1,31 @@ +/* COLOURS */ + +$menu-image: 'menu-black'; + +$mappage-header-height: 124px; + +$blue: #00478c; +$cyan: #00aeef; // + 60 25 +$orange: #fcaf17; +$green: #75c044; + +//Any 20% tint of the above + +$primary_text: #fff; +$primary: $cyan; +$primary_b: #222; + +$base_bg: #fff; +$base_fg: #222; + +$nav_background_colour: #fff; +$nav_colour: $blue; +$nav_hover_background_colour: $cyan; + +$col_click_map: $green; + +$header-top-border: false; + +$body-font: Helvetica, Arial, sans-serif; +$heading-font: $body-font; +$meta-font: $body-font; diff --git a/web/cobrands/isleofwight/assets.js b/web/cobrands/isleofwight/assets.js new file mode 100644 index 000000000..a68b0418b --- /dev/null +++ b/web/cobrands/isleofwight/assets.js @@ -0,0 +1,311 @@ +(function(){ + +if (!fixmystreet.maps) { + return; +} + +var defaults = { + http_options: { + url: "https://tilma.staging.mysociety.org/mapserver/iow", + params: { + SERVICE: "WFS", + VERSION: "1.1.0", + REQUEST: "GetFeature", + SRSNAME: "urn:ogc:def:crs:EPSG::27700" + } + }, + format_class: OpenLayers.Format.GML.v3.MultiCurveFix, + max_resolution: { + 'isleofwight': 0.5291677250021167, + 'fixmystreet': 1.194328566789627 + }, + attributes: { + central_asset_id: 'central_asset_id', + site_code: 'site_code' + }, + min_resolution: 0.00001, + asset_id_field: 'asset_id', + geometryName: 'msGeometry', + srsName: "EPSG:27700", + strategy_class: OpenLayers.Strategy.FixMyStreet, + body: "Isle of Wight Council" +}; + +var pin_prefix = fixmystreet.pin_prefix || document.getElementById('js-map-data').getAttribute('data-pin_prefix'); + +var labeled_default = { + fillColor: "#FFFF00", + fillOpacity: 0.6, + strokeColor: "#000000", + strokeOpacity: 0.8, + strokeWidth: 2, + pointRadius: 6 +}; + +var labeled_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: "${asset_id}", + labelOutlineColor: "white", + labelOutlineWidth: 3, + labelYOffset: 65, + fontSize: '15px', + fontWeight: 'bold' +}; + +var labeled_stylemap = new OpenLayers.StyleMap({ + 'default': new OpenLayers.Style(labeled_default), + 'select': new OpenLayers.Style(labeled_select) +}); + +fixmystreet.assets.add($.extend(true, {}, defaults, { + http_options: { + params: { + TYPENAME: "streets" + } + }, + always_visible: true, + non_interactive: true, + asset_type: 'area', + max_resolution: { + 'isleofwight': 6.614596562526458, + 'fixmystreet': 4.777314267158508 + }, + usrn: { + attribute: 'SITE_CODE', + field: 'site_code' + }, + stylemap: new OpenLayers.StyleMap({ + 'default': new OpenLayers.Style({ + fill: false, + strokeColor: "#5555FF", + strokeOpacity: 0.1, + strokeWidth: 7 + }) + }) +})); + +function not_found_msg_update() { + $('.category_meta_message').html('Please select an item or a road/pavement/path on the map »'); + $('.category_meta_message').removeClass('meta-highlight'); + $("input[name=asset_details]").val(''); +} + +function found_item(layer, asset) { + var id = asset.attributes.central_asset_id || ''; + if (id !== '') { + var attrib = asset.attributes; + var asset_name = attrib.feature_type_name + '; ' + attrib.site_name + '; ' + attrib.feature_location; + $('.category_meta_message').html('You have selected ' + asset_name); + $('.category_meta_message').addClass('meta-highlight'); + $("input[name=asset_details]").val(asset_name); + } else { + not_found_msg_update(); + } +} + + +var point_asset_defaults = $.extend(true, {}, defaults, { + snap_threshold: 5, + select_action: true, + asset_type: 'spot', + asset_item: "item", + actions: { + asset_found: function(asset) { + found_item(this, asset); + }, + asset_not_found: function() { + not_found_msg_update(); + } + } + +}); + +var line_asset_defaults = $.extend(true, {}, defaults, { + display_zoom_message: true, + non_interactive: true, + road: true, + stylemap: fixmystreet.assets.stylemap_invisible, + usrn: { + attribute: 'site_code', + field: 'site_code' + }, + asset_item: 'road', + actions: { + found: function(layer, feature) { + if ( fixmystreet.assets.selectedFeature() ) { + return; + } + found_item(layer, feature); + }, + not_found: function(layer) { + if ( fixmystreet.assets.selectedFeature() ) { + return; + } + not_found_msg_update(); + } + } +}); + + +var point_category_list = [ + //"Dog Fouling", + "Manholes", + "Trees & Hedges", + //"Pavements/footpaths", + //"Drainage", + //"Car Parking", + "Street Lighting", + "Bus Stops", + //"Flyposting", + //"Potholes", + //"Street Cleaning", + "Bridges & Walls", + "Traffic Lights", + "Street Furniture", + //"Roads/Highways", + "Road Traffic Signs & Markings", + "Grass Verges & Weeds", + //"Flytipping", + //"Graffiti", + "Street Nameplates", + //"Abandoned Vehicles" +]; + +var line_category_list = [ + "Dog Fouling", + "Drainage", + "Car Parking", + "Pavements/footpaths", + "Potholes", + "Street Cleaning", + "Roads/Highways", + "Flytipping", + "Abandoned Vehicles" +]; + +var layer_map = { + "Dog Fouling": "Dog_Fouling", + "Drainage": "Drainage_line", + "Car Parking": "Car_Parks", + "Trees & Hedges": "Trees_Hedges", + "Pavements/footpaths": "Pavements_footpaths", + "Street Lighting": "Street_Lighting", + "Bus Stops": "Bus_Stops", + "Street Cleaning": "Street_Cleaning", + "Bridges & Walls": "Bridges_Walls", + "Traffic Lights": "Traffic_Lights", + "Street Furniture": "Street_Furniture", + "Roads/Highways": "Roads_Highways", + "Road Traffic Signs & Markings": "Road_Traffic_Signs_Markings", + "Grass Verges & Weeds": "Grass_Verges_Weeds", + "Street Nameplates": "Street_Nameplates", + "Abandoned Vehicles": "Abandoned_Vehicles" +}; + +for (i = 0; i < point_category_list.length; i++) { + cat = point_category_list[i]; + layer = layer_map[cat] || cat; + + fixmystreet.assets.add($.extend(true, {}, point_asset_defaults, { + asset_group: cat, + http_options: { + params: { + TYPENAME: layer + } + } + })); +} + +for (i = 0; i < line_category_list.length; i++) { + cat = line_category_list[i]; + layer = layer_map[cat] || cat; + + fixmystreet.assets.add($.extend(true, {}, line_asset_defaults, { + asset_group: cat, + asset_category: [ + cat + ], + http_options: { + params: { + TYPENAME: layer + } + } + })); +} + +// non union layers +fixmystreet.assets.add($.extend(true, {}, point_asset_defaults, { + asset_group: "Roads/Highways", + http_options: { + params: { + TYPENAME: "Fords" + } + } +})); + +fixmystreet.assets.add($.extend(true, {}, point_asset_defaults, { + asset_group: "Roads/Highways", + http_options: { + params: { + TYPENAME: "Furn-Grid_and_Stones" + } + } +})); + + +fixmystreet.assets.add($.extend(true, {}, point_asset_defaults, { + asset_group: "Drainage", + http_options: { + params: { + TYPENAME: "Drainage_spot" + } + } +})); + +fixmystreet.assets.add($.extend(true, {}, point_asset_defaults, { + asset_group: "Car Parking", + http_options: { + params: { + TYPENAME: "Car_Parking" + } + } +})); + +fixmystreet.assets.add($.extend(true, {}, line_asset_defaults, { + asset_group: "Grass Verges & Weeds", + asset_category: [ + "Grass Verges & Weeds" + ], + http_options: { + params: { + TYPENAME: "Verges-Natural" + } + } +})); + +fixmystreet.assets.add($.extend(true, {}, point_asset_defaults, { + asset_group: "Dog Fouling", + http_options: { + params: { + TYPENAME: "Furn-Bins" + } + } +})); + +fixmystreet.message_controller.add_msg_after_bodies(defaults.body); + + +})(); diff --git a/web/cobrands/isleofwight/base.scss b/web/cobrands/isleofwight/base.scss new file mode 100644 index 000000000..aae8e9f7c --- /dev/null +++ b/web/cobrands/isleofwight/base.scss @@ -0,0 +1,18 @@ +@import "../sass/h5bp"; +@import "./_colours"; +@import "../sass/mixins"; +@import "../sass/base"; + +/* Header */ + +#site-logo { + width: 141px; + height: 38px; + padding: 1em 0; + background: url(/cobrands/isleofwight/images/logo.gif) 0 50% no-repeat; + background-size: 141px 38px; +} + +#map_box #map { + background-color: white; +} diff --git a/web/cobrands/isleofwight/images/email-logo.gif b/web/cobrands/isleofwight/images/email-logo.gif new file mode 120000 index 000000000..94a12010e --- /dev/null +++ b/web/cobrands/isleofwight/images/email-logo.gif @@ -0,0 +1 @@ +logo.gif
\ No newline at end of file diff --git a/web/cobrands/isleofwight/images/logo.gif b/web/cobrands/isleofwight/images/logo.gif Binary files differnew file mode 100644 index 000000000..7238ca8a3 --- /dev/null +++ b/web/cobrands/isleofwight/images/logo.gif diff --git a/web/cobrands/isleofwight/js.js b/web/cobrands/isleofwight/js.js new file mode 100644 index 000000000..d43006fd5 --- /dev/null +++ b/web/cobrands/isleofwight/js.js @@ -0,0 +1,33 @@ +(function(){ + +if (!fixmystreet.maps) { + return; +} + +if (fixmystreet.cobrand == 'isleofwight') { + // We want the cobranded site to always display "Island Roads" + // as the destination for reports in the "Public details" section. + // This is OK because the cobranded site only shows categories which + // Island Roads actually handle. + // To achieve this we ignore the passed list of bodies and always + // use "Island Roads" when calling the original function. + // NB calling the original function is required so that private categories + // cause the correct text to be shown in the UI. + var original_update_public_councils_text = fixmystreet.update_public_councils_text; + fixmystreet.update_public_councils_text = function(text, bodies) { + original_update_public_councils_text.call(this, text, ['Island Roads']); + }; +} + +var org_id = '1062'; +var body = "Isle of Wight Council"; +fixmystreet.assets.add(fixmystreet.roadworks.layer_future, { + http_options: { params: { organisation_id: org_id } }, + body: body +}); +fixmystreet.assets.add(fixmystreet.roadworks.layer_planned, { + http_options: { params: { organisation_id: org_id } }, + body: body +}); + +})(); diff --git a/web/cobrands/isleofwight/layout.scss b/web/cobrands/isleofwight/layout.scss new file mode 100644 index 000000000..924092a86 --- /dev/null +++ b/web/cobrands/isleofwight/layout.scss @@ -0,0 +1,26 @@ +@import "_colours"; + +@import "../sass/layout"; + +body.twothirdswidthpage .content .sticky-sidebar aside { + top: 10em; +} + +#site-logo { + width: 282px; + height: 76px; + padding: 24px 0; + background-position: 0px 50%; + background-size: 282px 76px; +} + +.mappage #site-header { + box-sizing: border-box; + border-bottom: solid 5px $cyan; +} + +.meta-highlight { + margin: 1em -1em; + padding: 2em 2em; + background-color: mix(#fff, $primary, 70%); +} diff --git a/web/cobrands/westminster/roadworks.js b/web/cobrands/westminster/roadworks.js new file mode 100644 index 000000000..d7a30b63d --- /dev/null +++ b/web/cobrands/westminster/roadworks.js @@ -0,0 +1,32 @@ +(function(){ + +if (!fixmystreet.maps) { + return; +} + +var org_id = '1160'; +var body = "Westminster City Council"; +fixmystreet.assets.add(fixmystreet.roadworks.layer_future, { + http_options: { params: { organisation_id: org_id } }, + body: body +}); +fixmystreet.assets.add(fixmystreet.roadworks.layer_planned, { + http_options: { params: { organisation_id: org_id } }, + body: body +}); + +// Westminster want to also display the responsible party in roadworks messages +var original_display_message = fixmystreet.roadworks.display_message; +fixmystreet.roadworks.display_message = function(feature) { + var retval = original_display_message.apply(this, arguments); + + if (feature.attributes.promoter) { + var $dl = $(".js-roadworks-message-" + feature.layer.id + " dl"); + $dl.append("<dt>Responsibility</dt>"); + $dl.append($("<dd></dd>").text(feature.attributes.promoter)); + } + + return retval; +}; + +})(); diff --git a/web/cobrands/zurich/layout.scss b/web/cobrands/zurich/layout.scss index 97ae8fc4a..d98afba5d 100644 --- a/web/cobrands/zurich/layout.scss +++ b/web/cobrands/zurich/layout.scss @@ -315,6 +315,9 @@ body.mappage.admin { font-weight: bold; position: absolute; } + .index-status .message-updated { + margin-top: -1.5em; + } } .admin-nav-wrapper { diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index cd2283491..1588bda2e 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -562,6 +562,9 @@ $.extend(fixmystreet.utils, { } else { $.extend(style.defaultStyle, { fillColor: 'black', strokeColor: 'black' }); } + if (!this.features.length) { + return; + } var geometry = this.features[0].geometry; if (geometry.CLASS_NAME == 'OpenLayers.Geometry.Collection' || geometry.CLASS_NAME == 'OpenLayers.Geometry.MultiPolygon') { @@ -673,7 +676,7 @@ $.extend(fixmystreet.utils, { styleMap: pin_layer_style_map }; if (fixmystreet.page == 'around') { - fixmystreet.bbox_strategy = fixmystreet.bbox_strategy || new OpenLayers.Strategy.FixMyStreet(); + fixmystreet.bbox_strategy = fixmystreet.map_bbox_strategy || new OpenLayers.Strategy.FixMyStreet(); pin_layer_options.strategies = [ fixmystreet.bbox_strategy ]; } if (fixmystreet.page == 'reports') { @@ -1185,3 +1188,15 @@ OpenLayers.Renderer.SVGBig = OpenLayers.Class(OpenLayers.Renderer.SVG, { CLASS_NAME: "OpenLayers.Renderer.SVGBig" }); + +/* Stop sending a needless header so that no preflight CORS request */ +OpenLayers.Request.XMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { + if (sName.toLowerCase() == 'x-requested-with') { + return; + } + if (!this._headers) { + this._headers = {}; + } + this._headers[sName] = sValue; + return this._object.setRequestHeader(sName, sValue); +}; diff --git a/web/js/map-wmts-base.js b/web/js/map-wmts-base.js index fe8d8015e..43f829ab5 100644 --- a/web/js/map-wmts-base.js +++ b/web/js/map-wmts-base.js @@ -28,27 +28,4 @@ fixmystreet.maps.setup_wmts_base_map = function() { tileOrigin: new OpenLayers.LonLat(fixmystreet.wmts_config.origin_x, fixmystreet.wmts_config.origin_y) }); }); - - // Give main code a new bbox_strategy that translates between - // lat/lon and our WMTS layer's coordinates - fixmystreet.bbox_strategy = new OpenLayers.Strategy.ReprojectBBOX({ - ratio: 1 - }); }; - -OpenLayers.Strategy.ReprojectBBOX = OpenLayers.Class(OpenLayers.Strategy.BBOX, { - getMapBounds: function() { - // Get the map bounds but return them in lat/lon, not - // local coordinates - if (this.layer.map === null) { - return null; - } - - var localBounds = this.layer.map.getExtent(); - // Transform bound corners into WGS84 - localBounds.transform( new OpenLayers.Projection(fixmystreet.wmts_config.map_projection), new OpenLayers.Projection("EPSG:4326") ); - return localBounds; - }, - - CLASS_NAME: "OpenLayers.Strategy.ReprojectBBOX" -}); diff --git a/web/js/map-wmts-isleofwight.js b/web/js/map-wmts-isleofwight.js new file mode 100644 index 000000000..464bee913 --- /dev/null +++ b/web/js/map-wmts-isleofwight.js @@ -0,0 +1,206 @@ +/* + * Maps for FMS using Island Roads' WMTS tile server + */ + +fixmystreet.maps.layer_bounds = new OpenLayers.Bounds( + 428576.1131782566, + 70608.46901095579, + 468137.51522498735, + 101069.6062942903 +); + +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": 140, + //"matrixHeight": 109 + //}, + //{ + //"identifier": 1, + //"scaleDenominator": 472471.18303754483, + //"supportedCRS": "urn:ogc:def:crs:EPSG:27700", + //"tileWidth": 256, + //"tileHeight": 256, + //"matrixWidth": 168, + //"matrixHeight": 130 + //}, + //{ + //"identifier": 2, + //"scaleDenominator": 377976.9464300358, + //"supportedCRS": "urn:ogc:def:crs:EPSG:27700", + //"tileWidth": 256, + //"tileHeight": 256, + //"matrixWidth": 210, + //"matrixHeight": 163 + //}, + //{ + //"identifier": 3, + //"scaleDenominator": 283482.7098225269, + //"supportedCRS": "urn:ogc:def:crs:EPSG:27700", + //"tileWidth": 256, + //"tileHeight": 256, + //"matrixWidth": 280, + //"matrixHeight": 217 + //}, + //{ + //"identifier": 4, + //"scaleDenominator": 188988.4732150179, + //"supportedCRS": "urn:ogc:def:crs:EPSG:27700", + //"tileWidth": 256, + //"tileHeight": 256, + //"matrixWidth": 420, + //"matrixHeight": 325 + //}, + { + "identifier": 5, + "scaleDenominator": 94494.23660750895, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 840, + "matrixHeight": 650 + }, + { + "identifier": 6, + "scaleDenominator": 70870.67745563173, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 1120, + "matrixHeight": 867 + }, + { + "identifier": 7, + "scaleDenominator": 47247.118303754476, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 1680, + "matrixHeight": 1300 + }, + { + "identifier": 8, + "scaleDenominator": 23623.559151877238, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 3360, + "matrixHeight": 2599 + }, + { + "identifier": 9, + "scaleDenominator": 9449.423660750896, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 8399, + "matrixHeight": 6496 + }, + { + "identifier": 10, + "scaleDenominator": 7559.538928600717, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 10499, + "matrixHeight": 8120 + }, + { + "identifier": 11, + "scaleDenominator": 5669.654196450538, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 13998, + "matrixHeight": 10826 + }, + { + "identifier": 12, + "scaleDenominator": 3779.7694643003583, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 20997, + "matrixHeight": 16239 + }, + { + "identifier": 13, + "scaleDenominator": 1889.8847321501792, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 41993, + "matrixHeight": 32478 + }, + { + "identifier": 14, + "scaleDenominator": 944.9423660750896, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 83985, + "matrixHeight": 64955 + }, + { + "identifier": 15, + "scaleDenominator": 377.9769464300358, + "supportedCRS": "urn:ogc:def:crs:EPSG:27700", + "tileWidth": 256, + "tileHeight": 256, + "matrixWidth": 209961, + "matrixHeight": 162387 + } +]; + +/* + * 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 >= 7) { + return 'normal'; + } else if (zoom >= 4) { + return 'small'; + } else { + return 'mini'; + } +}; + +fixmystreet.maps.selected_marker_size = function() { + var zoom = fixmystreet.map.getZoom() + fixmystreet.zoomOffset; + if (zoom >= 7) { + return 'big'; + } else if (zoom >= 4) { + return 'normal'; + } else { + return 'small'; + } +}; |