diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 42 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/New.pm | 3 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Reports.pm | 27 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Bristol.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Oxfordshire.pm | 6 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/ResultSet/Nearby.pm | 3 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/ResultSet/Problem.pm | 37 | ||||
-rw-r--r-- | t/app/controller/report_inspect.t | 26 | ||||
-rw-r--r-- | t/app/controller/report_new.t | 16 | ||||
-rw-r--r-- | t/cobrand/oxfordshire.t | 51 | ||||
-rw-r--r-- | templates/web/base/report/_inspect.html | 6 | ||||
-rw-r--r-- | templates/web/base/report/new/form_user_loggedin.html | 7 | ||||
-rw-r--r-- | templates/web/bristol/maps/noscript_map.html | 32 | ||||
-rw-r--r-- | templates/web/oxfordshire/header.html | 10 | ||||
-rw-r--r-- | web/cobrands/angus/js.js | 4 | ||||
-rw-r--r-- | web/cobrands/bristol/js.js | 16 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/assets.js | 271 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/staff.js | 4 | ||||
-rw-r--r-- | web/vendor/OpenLayers.Projection.OrdnanceSurvey.js | 12 |
20 files changed, 366 insertions, 211 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 45267a57e..e05f8c4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ * Unreleased - Front end improvements: - Improve questionnaire process. #1939 #1998 + - Admin improvements: + - Inspectors can set non_public status of reports. #1992 * v2.3.1 (12th February 2018) - Front end improvements: diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 8708c6128..ec0e6f886 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -76,7 +76,7 @@ sub _display : Private { $c->forward( 'load_updates' ); $c->forward( 'format_problem_for_display' ); - my $permissions = $c->stash->{_permissions} = $c->forward( 'check_has_permission_to', + my $permissions = $c->stash->{_permissions} ||= $c->forward( 'check_has_permission_to', [ qw/report_inspect report_edit_category report_edit_priority/ ] ); if (any { $_ } values %$permissions) { $c->stash->{template} = 'report/inspect.html'; @@ -128,7 +128,11 @@ sub load_problem_or_display_error : Private { [ _('That report has been removed from FixMyStreet.') ] # ); } elsif ( $problem->non_public ) { - if ( !$c->user || $c->user->id != $problem->user->id ) { + # Creator, and inspection users can see non_public reports + $c->stash->{problem} = $problem; + my $permissions = $c->stash->{_permissions} = $c->forward( 'check_has_permission_to', + [ qw/report_inspect report_edit_category report_edit_priority/ ] ); + if ( !$c->user || ($c->user->id != $problem->user->id && !$permissions->{report_inspect}) ) { $c->detach( '/page_error_403_access_denied', [ sprintf(_('That report cannot be viewed on %s.'), $c->stash->{site_name}) ] @@ -348,6 +352,8 @@ sub inspect : Private { my %update_params = (); if ($permissions->{report_inspect}) { + $problem->non_public($c->get_param('non_public') ? 1 : 0); + $problem->set_extra_metadata( traffic_information => $c->get_param('traffic_information') ); if ( my $info = $c->get_param('detailed_information') ) { @@ -461,22 +467,24 @@ sub inspect : Private { } $problem->lastupdate( \'current_timestamp' ); $problem->update; - my $timestamp = \'current_timestamp'; - if (my $saved_at = $c->get_param('saved_at')) { - $timestamp = DateTime->from_epoch( epoch => $saved_at ); + if ($update_text || %update_params) { + my $timestamp = \'current_timestamp'; + if (my $saved_at = $c->get_param('saved_at')) { + $timestamp = DateTime->from_epoch( epoch => $saved_at ); + } + my $name = $c->user->from_body ? $c->user->from_body->name : $c->user->name; + $problem->add_to_comments( { + text => $update_text, + created => $timestamp, + confirmed => $timestamp, + user_id => $c->user->id, + name => $name, + state => 'confirmed', + mark_fixed => 0, + anonymous => 0, + %update_params, + } ); } - my $name = $c->user->from_body ? $c->user->from_body->name : $c->user->name; - $problem->add_to_comments( { - text => $update_text, - created => $timestamp, - confirmed => $timestamp, - user_id => $c->user->id, - name => $name, - state => 'confirmed', - mark_fixed => 0, - anonymous => 0, - %update_params, - } ); my $redirect_uri; $problem->discard_changes; diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index f9e07dd41..888110429 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -870,6 +870,7 @@ sub process_report : Private { 'subcategory', # 'partial', # 'service', # + 'non_public', ); # load the report @@ -897,6 +898,8 @@ sub process_report : Private { $report->anonymous( $params{may_show_name} ? 0 : 1 ); } + $report->non_public($params{non_public} ? 1 : 0); + # clean up text before setting $report->title( Utils::cleanup_text( $params{title} ) ); diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index 7c3796c42..15a220644 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -544,20 +544,27 @@ sub load_and_group_problems : Private { my $states = $c->stash->{filter_problem_states}; my $where = { - non_public => 0, state => [ keys %$states ] }; + + my $body = $c->stash->{body}; # Might be undef + + if ($c->user_exists && ($c->user->is_superuser || ($body && $c->user->has_permission_to('report_inspect', $body->id)))) { + # See all reports, no restriction + } else { + $where->{non_public} = 0; + } + my $filter = { order_by => $c->stash->{sort_order}, rows => $c->cobrand->reports_per_page, }; - if ($c->user_exists && $c->stash->{body}) { - my $bid = $c->stash->{body}->id; + if ($c->user_exists && $body) { my $prefetch = []; - if ($c->user->has_permission_to('planned_reports', $bid)) { + if ($c->user->has_permission_to('planned_reports', $body->id)) { push @$prefetch, 'user_planned_reports'; } - if ($c->user->has_permission_to('report_edit_priority', $bid) || $c->user->has_permission_to('report_inspect', $bid)) { + if ($c->user->has_permission_to('report_edit_priority', $body->id) || $c->user->has_permission_to('report_inspect', $body->id)) { push @$prefetch, 'response_priority'; } $prefetch = $prefetch->[0] if @$prefetch == 1; @@ -589,9 +596,9 @@ sub load_and_group_problems : Private { $where->{areas} = [ map { { 'like', '%,' . $_->{id} . ',%' } } @{$c->stash->{wards}} ]; - $problems = $problems->to_body($c->stash->{body}); - } elsif ($c->stash->{body}) { - $problems = $problems->to_body($c->stash->{body}); + $problems = $problems->to_body($body); + } elsif ($body) { + $problems = $problems->to_body($body); } if (my $bbox = $c->get_param('bbox')) { @@ -609,7 +616,7 @@ sub load_and_group_problems : Private { my ( %problems, @pins ); while ( my $problem = $problems->next ) { - if ( !$c->stash->{body} ) { + if ( !$body ) { add_row( $c, $problem, 0, \%problems, \@pins ); next; } @@ -623,7 +630,7 @@ sub load_and_group_problems : Private { # Add to bodies it was sent to my $bodies = $problem->bodies_str_ids; foreach ( @$bodies ) { - next if $_ != $c->stash->{body}->id; + next if $_ != $body->id; add_row( $c, $problem, $_, \%problems, \@pins ); } } diff --git a/perllib/FixMyStreet/Cobrand/Bristol.pm b/perllib/FixMyStreet/Cobrand/Bristol.pm index 4648802bd..b11a52643 100644 --- a/perllib/FixMyStreet/Cobrand/Bristol.pm +++ b/perllib/FixMyStreet/Cobrand/Bristol.pm @@ -20,7 +20,7 @@ sub example_places { } sub map_type { - 'OSM'; + 'Bristol'; } sub default_link_zoom { 6 } diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index 00f099278..4b1dbc32c 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -67,6 +67,11 @@ sub problem_response_days { my $self = shift; my $p = shift; + return 'emergency' if $p->category eq 'Street lighting'; + + # Temporary, see https://github.com/mysociety/fixmystreetforcouncils/issues/291 + return 0; + return 10 if $p->category eq 'Bridges'; return 10 if $p->category eq 'Carriageway Defect'; # phone if urgent return 10 if $p->category eq 'Debris/Spillage'; @@ -87,7 +92,6 @@ sub problem_response_days { return 10 if $p->category eq 'Road traffic signs'; return 10 if $p->category eq 'Roads/highways'; return 10 if $p->category eq 'Skips and scaffolding'; - return 'emergency' if $p->category eq 'Street lighting'; return 10 if $p->category eq 'Traffic lights'; # phone if urgent return 10 if $p->category eq 'Traffic'; return 10 if $p->category eq 'Trees'; diff --git a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm index 6e5e0220f..ab554eb9d 100644 --- a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm +++ b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm @@ -17,13 +17,14 @@ sub nearby { } my $params = { - non_public => 0, state => [ keys %$states ], }; $params->{id} = { -not_in => $ids } if $ids; $params->{category} = $categories if $categories && @$categories; + FixMyStreet::DB::ResultSet::Problem->non_public_if_possible($params, $c); + $rs = $c->cobrand->problems_restriction($rs); my $attrs = { diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm index 3f083c073..458efa179 100644 --- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm +++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm @@ -15,15 +15,41 @@ sub set_restriction { $site_key = $key; } -sub to_body { - my ($rs, $bodies, $join) = @_; - return $rs unless $bodies; +sub body_query { + my ($rs, $bodies) = @_; unless (ref $bodies eq 'ARRAY') { $bodies = [ map { ref $_ ? $_->id : $_ } $bodies ]; } + \[ "regexp_split_to_array(bodies_str, ',') && ?", [ {} => $bodies ] ] +} + +# Edits PARAMS in place to either hide non_public reports, or show them +# if user is superuser (all) or inspector (correct body) +sub non_public_if_possible { + my ($rs, $params, $c) = @_; + if ($c->user_exists) { + if ($c->user->is_superuser) { + # See all reports, no restriction + } elsif ($c->user->has_body_permission_to('report_inspect')) { + $params->{'-or'} = [ + non_public => 0, + $rs->body_query($c->user->from_body->id), + ]; + } else { + $params->{non_public} = 0; + } + } else { + $params->{non_public} = 0; + } +} + +sub to_body { + my ($rs, $bodies, $join) = @_; + return $rs unless $bodies; $join = { join => 'problem' } if $join; $rs = $rs->search( - \[ "regexp_split_to_array(bodies_str, ',') && ?", [ {} => $bodies ] ], + # This isn't using $rs->body_query because $rs might be Problem, Comment, or Nearby + FixMyStreet::DB::ResultSet::Problem->body_query($bodies), $join ); return $rs; @@ -151,13 +177,14 @@ sub around_map { } my $q = { - non_public => 0, state => [ keys %{$p{states}} ], latitude => { '>=', $p{min_lat}, '<', $p{max_lat} }, longitude => { '>=', $p{min_lon}, '<', $p{max_lon} }, }; $q->{category} = $p{categories} if $p{categories} && @{$p{categories}}; + $rs->non_public_if_possible($q, $c); + my $problems = mySociety::Locale::in_gb_locale { $rs->search( $q, $attr )->include_comment_counts->page($p{page}); }; diff --git a/t/app/controller/report_inspect.t b/t/app/controller/report_inspect.t index 239cc408b..39dd57444 100644 --- a/t/app/controller/report_inspect.t +++ b/t/app/controller/report_inspect.t @@ -559,6 +559,7 @@ FixMyStreet::override_config { my $expected_fields = { state => 'action scheduled', category => 'Cows', + non_public => undef, public_update => '', priority => $rp->id, include_update => '1', @@ -594,6 +595,31 @@ FixMyStreet::override_config { is $report->comments->count, 1, "Only leaves one update"; like $report->comments->first->text, qr/Category changed.*Badgers/, 'update text included category change'; }; + + subtest "test non-public changing" => sub { + $report->comments->delete; + is $report->non_public, 0, 'Not set to non-public'; + $mech->get_ok("/report/$report_id"); + $mech->submit_form(button => 'save', with_fields => { include_update => 0, non_public => 1 }); + is $report->comments->count, 0, "No updates left"; + $report->discard_changes; + is $report->non_public, 1, 'Now set to non-public'; + $mech->submit_form(button => 'save', with_fields => { include_update => 0, non_public => 0 }); + is $report->comments->count, 0, "No updates left"; + $report->discard_changes; + is $report->non_public, 0, 'Not set to non-public'; + }; + + subtest "test saved-at setting" => sub { + $report->comments->delete; + $mech->get_ok("/report/$report_id"); + my $now = DateTime->now->subtract(days => 1); + $mech->submit_form(button => 'save', form_id => 'report_inspect_form', + fields => { include_update => 1, public_update => 'An update', saved_at => $now->epoch }); + $report->discard_changes; + is $report->comments->count, 1, "One update"; + is $report->comments->first->confirmed, $now; + }; }; FixMyStreet::override_config { diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t index 3c120b0b0..32d86d803 100644 --- a/t/app/controller/report_new.t +++ b/t/app/controller/report_new.t @@ -1733,7 +1733,11 @@ subtest "extra google analytics code displayed on email confirmation problem cre }; }; -subtest "inspectors get redirected directly to the report page" => sub { +foreach my $test ( + { non_public => 0 }, + { non_public => 1 }, +) { + subtest "inspectors get redirected directly to the report page, non_public=$test->{non_public}" => sub { FixMyStreet::override_config { ALLOWED_COBRANDS => [ { fixmystreet => '.' } ], BASE_URL => 'https://www.fixmystreet.com', @@ -1746,10 +1750,14 @@ subtest "inspectors get redirected directly to the report page" => sub { body => $bodies[0], permission_type => 'planned_reports', }); + $user->user_body_permissions->find_or_create({ + body => $bodies[0], + permission_type => 'report_inspect', + }); $mech->log_in_ok('inspector@example.org'); $mech->get_ok('/'); - $mech->submit_form_ok( { with_fields => { pc => 'GL50 2PR' } }, + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, "submit location" ); $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, @@ -1766,6 +1774,7 @@ subtest "inspectors get redirected directly to the report page" => sub { may_show_name => '1', phone => '07903 123 456', category => 'Trees', + non_public => $test->{non_public}, } }, "submit good details" @@ -1773,6 +1782,7 @@ subtest "inspectors get redirected directly to the report page" => sub { like $mech->uri->path, qr/\/report\/[0-9]+/, 'Redirects directly to report'; } -}; + }; +} done_testing(); diff --git a/t/cobrand/oxfordshire.t b/t/cobrand/oxfordshire.t index ee30e7e0b..54c6e32ea 100644 --- a/t/cobrand/oxfordshire.t +++ b/t/cobrand/oxfordshire.t @@ -185,57 +185,6 @@ subtest 'Reports are marked as inspected correctly' => sub { }; }; -subtest 'response times messages displayed' => sub { - my $oxfordshire = $mech->create_body_ok( - 2237, 'Oxfordshire County Council' - ); - my $contact = $mech->create_contact_ok( - body_id => $oxfordshire->id, - category => 'Pothole', - email => 'pothole@example.com', - ); - - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'oxfordshire' ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->log_out_ok; - $mech->clear_emails_ok; - - $mech->get_ok('/around'); - $mech->submit_form_ok( { - with_fields => { pc => 'OX20 1SZ' } - }, - "submit_location" - ); - - $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, - "follow 'skip this step' link" ); - - $mech->submit_form_ok( - { - with_fields => { - title => 'Test Report', - detail => 'Test report details.', - photo1 => '', - username => 'test-2@example.com', - name => 'Test User', - category => 'Pothole', - } - }, - "submit details" - ); - - $mech->text_contains('Problems in the Pothole category are generally responded'); - my $email = $mech->get_email; - ok $email, 'got and email'; - like $mech->get_text_body_from_email, qr/Problems in the Pothole category/, 'emails contains response time message'; - my $url = $mech->get_link_from_email($email); - $mech->get_ok($url); - $mech->text_contains('Problems in the Pothole category are generally responded') - }; -}; - END { done_testing(); } diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html index 1893826de..eef85c06e 100644 --- a/templates/web/base/report/_inspect.html +++ b/templates/web/base/report/_inspect.html @@ -7,9 +7,12 @@ [% INCLUDE 'errors.html' %] <form name="report_inspect_form" id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate"> - <input type="hidden" name="js" value=""> <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> @@ -190,6 +193,7 @@ </p> </div> + <input type="hidden" name="js" value=""> </form> </div> [%- END %] diff --git a/templates/web/base/report/new/form_user_loggedin.html b/templates/web/base/report/new/form_user_loggedin.html index ad74a5654..6257a8346 100644 --- a/templates/web/base/report/new/form_user_loggedin.html +++ b/templates/web/base/report/new/form_user_loggedin.html @@ -72,6 +72,13 @@ <input class="form-control" type="text" value="[% report.user.email | html %]" name="email" id="form_email"> [% END %] +[% IF c.user.has_permission_to("report_inspect", bodies.keys) %] + <div class="checkbox-group"> + <input type="checkbox" name="non_public" id="form_non_public" value="1"[% ' checked' IF report.non_public %]> + <label class="inline" for="form_non_public">[% loc('Private') %] </label> + </div> +[% END %] + <div class="form-txt-submit-box"> <input class="green-btn js-submit_register" type="submit" name="submit_register" value="[% loc('Submit') %]"> </div> diff --git a/templates/web/bristol/maps/noscript_map.html b/templates/web/bristol/maps/noscript_map.html new file mode 100644 index 000000000..987aa76a6 --- /dev/null +++ b/templates/web/bristol/maps/noscript_map.html @@ -0,0 +1,32 @@ +<div class="noscript square-map__outer"> + <div class="square-map__inner"> + <div id="[% nsm_prefix %]drag"> + [%- FOR row IN map.tiles -%] + [%- FOR tile IN row -%] + [%- top_px = tile.row_offset * map.tile_size -%] + [%- left_px = tile.col_offset * map.tile_size %] + <[% map.img_type %] + class="square-map__tile" + alt="[% tile.alt %]" + id="[% nsm_prefix %]t[% tile.dotted_id %]" + name="tile_[% tile.dotted_id %]" + src="[% tile.src %]" + style="width: [% 100 / map.cols %]%; height: auto; float: left;"> + [%- END -%] + [% END %] + </div> + <div id="[% nsm_prefix %]pins">[% FOR pin IN map.pins %][% INCLUDE pin %][% END %]</div> + [% INCLUDE 'maps/_compass.html' %] + </div> +</div> + +[% BLOCK pin %] +[% + SET pin_top = pin.py / ( map.tile_size * map.rows ) * 100; + SET pin_left = pin.px / ( map.tile_size * map.cols ) * 100; + # -24px half of 48px wide image, -64px all of 64px tall image + INCLUDE 'maps/pin.html' + pin_style = 'top:' _ pin_top _ '%; left:' _ pin_left _ '%; position:absolute; margin-left:-24px; margin-top:-64px;' +%] +[% END %] + diff --git a/templates/web/oxfordshire/header.html b/templates/web/oxfordshire/header.html index a1d42a777..0d3476195 100644 --- a/templates/web/oxfordshire/header.html +++ b/templates/web/oxfordshire/header.html @@ -54,6 +54,16 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> </div> </header> +[% IF c.req.uri.path == '/' %] +<p class="oxfordshire-preamble"> +Winter weather over the past few weeks has caused widespread damage to +Oxfordshire’s roads. We are of course dealing with the most dangerous issues +first but please do carry on alerting us to new ones so that we can continue to +prioritise this work efficiently and so keep the whole county moving about its +business as quickly as possible. +</p> +[% END %] + [% pre_container_extra %] <div class="container"> diff --git a/web/cobrands/angus/js.js b/web/cobrands/angus/js.js index f3e7bf211..566b3a842 100644 --- a/web/cobrands/angus/js.js +++ b/web/cobrands/angus/js.js @@ -4,7 +4,7 @@ if (!fixmystreet.maps) { return; } -$(fixmystreet.add_assets({ +fixmystreet.assets.add({ wfs_url: "https://data.angus.gov.uk/geoserver/services/wfs", wfs_feature: "lighting_column_v", wfs_fault_feature: "lighting_faults_v", @@ -18,6 +18,6 @@ $(fixmystreet.add_assets({ column_id: 'n' }, geometryName: 'g' -})); +}); })(); diff --git a/web/cobrands/bristol/js.js b/web/cobrands/bristol/js.js index 1fc23d61a..9a4d1ec46 100644 --- a/web/cobrands/bristol/js.js +++ b/web/cobrands/bristol/js.js @@ -19,32 +19,32 @@ var options = { geometryName: 'SHAPE' }; -$(fixmystreet.add_assets($.extend({}, options, { +fixmystreet.assets.add($.extend({}, options, { wfs_feature: "COD_ASSETS_AREA", asset_type: 'area', asset_category: "Bridges/Subways", asset_item: 'bridge/subway' -}))); +})); -$(fixmystreet.add_assets($.extend({}, options, { +fixmystreet.assets.add($.extend({}, options, { asset_category: "Gully/Drainage", asset_item: 'gully', filter_key: 'COD_ASSET_TYPE', filter_value: 'GULLY' -}))); +})); -$(fixmystreet.add_assets($.extend({}, options, { +fixmystreet.assets.add($.extend({}, options, { asset_category: "Grit Bins", asset_item: 'grit bin', filter_key: 'COD_ASSET_TYPE', filter_value: 'GRITBIN' -}))); +})); -$(fixmystreet.add_assets($.extend({}, options, { +fixmystreet.assets.add($.extend({}, options, { asset_category: "Street Lighting", asset_item: 'street light', filter_key: 'COD_ASSET_TYPE', filter_value: 'SL' -}))); +})); })(); diff --git a/web/cobrands/fixmystreet/assets.js b/web/cobrands/fixmystreet/assets.js index e24e76495..a6ecbadb2 100644 --- a/web/cobrands/fixmystreet/assets.js +++ b/web/cobrands/fixmystreet/assets.js @@ -17,7 +17,7 @@ function asset_selected(e) { close_fault_popup(); var lonlat = e.feature.geometry.getBounds().getCenterLonLat(); - // Check if there is a known fault with the light that's been clicked, + // Check if there is a known fault with the asset that's been clicked, // and disallow selection if so. var fault_feature = find_matching_feature(e.feature, this.fixmystreet.fault_layer, this.fixmystreet.asset_id_field); if (!!fault_feature) { @@ -34,13 +34,18 @@ function asset_selected(e) { // Set the extra field to the value of the selected feature $.each(this.fixmystreet.attributes, function (field_name, attribute_name) { - var id = e.feature.attributes[attribute_name]; - $("#form_" + field_name).val(id); + var field_value; + if (typeof attribute_name === 'function') { + field_value = attribute_name.apply(e.feature); + } else { + field_value = e.feature.attributes[attribute_name]; + } + $("#form_" + field_name).val(field_value); }); // Hide the normal markers layer to keep things simple, but // move the green marker to the point of the click to stop - // it jumping around unexpectedly if the user deselects street light. + // it jumping around unexpectedly if the user deselects the asset. fixmystreet.markers.setVisibility(false); fixmystreet.markers.features[0].move(lonlat); @@ -108,7 +113,7 @@ function check_zoom_message_visibility() { function layer_visibilitychanged() { check_zoom_message_visibility.call(this); - var layers = fixmystreet.map.getLayersByName('WFS'); + var layers = fixmystreet.map.getLayersBy('assets', true); var visible = 0; for (var i = 0; i<layers.length; i++) { if (layers[i].getVisibility()) { @@ -121,7 +126,9 @@ function layer_visibilitychanged() { // to show the marker again. fixmystreet.markers.setVisibility(true); } - select_nearest_asset.call(this); + if (!this.fixmystreet.non_interactive) { + select_nearest_asset.call(this); + } } function zoom_to_assets(layer) { @@ -184,6 +191,10 @@ function layer_loadend() { } function get_asset_stylemap() { + // fixmystreet.pin_prefix isn't always available here (e.g. on /report/new), + // so get it from the DOM directly + var pin_prefix = fixmystreet.pin_prefix || document.getElementById('js-map-data').getAttribute('data-pin_prefix'); + return new OpenLayers.StyleMap({ 'default': new OpenLayers.Style({ fillColor: "#FFFF00", @@ -194,13 +205,13 @@ function get_asset_stylemap() { pointRadius: 6 }), 'select': new OpenLayers.Style({ - externalGraphic: fixmystreet.pin_prefix + "pin-spot.png", + externalGraphic: pin_prefix + "pin-spot.png", fillColor: "#55BB00", graphicWidth: 48, graphicHeight: 64, graphicXOffset: -24, graphicYOffset: -56, - backgroundGraphic: fixmystreet.pin_prefix + "pin-shadow.png", + backgroundGraphic: pin_prefix + "pin-shadow.png", backgroundWidth: 60, backgroundHeight: 30, backgroundXOffset: -7, @@ -208,7 +219,7 @@ function get_asset_stylemap() { popupYOffset: -40, graphicOpacity: 1.0 }), - 'temporary': new OpenLayers.Style({ + 'hover': new OpenLayers.Style({ fillColor: "#55BB00", fillOpacity: 0.8, strokeColor: "#000000", @@ -233,54 +244,57 @@ function get_fault_stylemap() { }); } -fixmystreet.add_assets = function(options) { - var asset_layer = null; - var asset_fault_layer = null; +fixmystreet.assets = { + layers: [], + controls: [], - function add_assets() { - if (asset_layer !== null) { - // Layer has already been added - return; - } - if (window.fixmystreet === undefined) { - // We're on a page without a map, yet somehow still got called... - // Nothing to do. - return; - } - if (fixmystreet.map === undefined) { - // Map's not loaded yet, let's try again soon... - setTimeout(add_assets, 250); - return; - } - if (fixmystreet.page != 'new' && fixmystreet.page != 'around') { - // We only want to show light markers when making a new report - return; - } + add: function(options) { + var asset_fault_layer = null; - // An interactive layer for selecting a street light - var protocol_options = { - version: "1.1.0", - url: options.wfs_url, - featureType: options.wfs_feature, - geometryName: options.geometryName - }; - if (fixmystreet.wmts_config) { - protocol_options.srsName = fixmystreet.wmts_config.map_projection; - } - if (options.propertyNames) { - protocol_options.propertyNames = options.propertyNames; + // An interactive layer for selecting an asset (e.g. street light) + var protocol_options; + var protocol; + if (options.http_options !== undefined) { + protocol_options = OpenLayers.Util.extend(options.http_options, {}); + if (protocol_options.format_class) { + protocol_options.format = new protocol_options.format_class(protocol_options.format_options); + } else { + protocol_options.format = new OpenLayers.Format.GML({ + geometryName: options.geometryName + }); + } + protocol = new OpenLayers.Protocol.HTTP(protocol_options); + } else { + protocol_options = { + version: "1.1.0", + url: options.wfs_url, + featureType: options.wfs_feature, + geometryName: options.geometryName + }; + if (options.srsName !== undefined) { + protocol_options.srsName = options.srsName; + } else if (fixmystreet.wmts_config) { + protocol_options.srsName = fixmystreet.wmts_config.map_projection; + } + if (options.propertyNames) { + protocol_options.propertyNames = options.propertyNames; + } + protocol = new OpenLayers.Protocol.WFS(protocol_options); } - var protocol = new OpenLayers.Protocol.WFS(protocol_options); + var StrategyClass = options.strategy_class || OpenLayers.Strategy.BBOX; var layer_options = { fixmystreet: options, - strategies: [new OpenLayers.Strategy.BBOX()], + strategies: [new StrategyClass()], protocol: protocol, visibility: false, maxResolution: options.max_resolution, minResolution: options.min_resolution, - styleMap: get_asset_stylemap() + styleMap: options.stylemap || get_asset_stylemap(), + assets: true }; - if (fixmystreet.wmts_config) { + if (options.srsName !== undefined) { + layer_options.projection = new OpenLayers.Projection(options.srsName); + } else if (fixmystreet.wmts_config) { layer_options.projection = new OpenLayers.Projection(fixmystreet.wmts_config.map_projection); } if (options.filter_key) { @@ -290,9 +304,10 @@ fixmystreet.add_assets = function(options) { value: options.filter_value }); } - asset_layer = new OpenLayers.Layer.Vector("WFS", layer_options); - // A non-interactive layer to display existing street light faults + var asset_layer = new OpenLayers.Layer.Vector(options.name || "WFS", layer_options); + + // A non-interactive layer to display existing asset faults if (options.wfs_fault_feature) { var po = { featureType: options.wfs_fault_feature @@ -302,7 +317,8 @@ fixmystreet.add_assets = function(options) { var lo = { strategies: [new OpenLayers.Strategy.BBOX()], protocol: fault_protocol, - styleMap: get_fault_stylemap() + styleMap: get_fault_stylemap(), + assets: true }; OpenLayers.Util.applyDefaults(lo, layer_options); asset_fault_layer = new OpenLayers.Layer.Vector("WFS", lo); @@ -311,81 +327,122 @@ fixmystreet.add_assets = function(options) { asset_layer.fixmystreet.fault_layer = asset_fault_layer; } - // Set up handlers for selecting/unselecting markers and panning/zooming the map - var select_feature_control = new OpenLayers.Control.SelectFeature( asset_layer ); - asset_layer.events.register( 'featureselected', asset_layer, asset_selected); - asset_layer.events.register( 'featureunselected', asset_layer, asset_unselected); - asset_layer.events.register( 'loadend', asset_layer, layer_loadend); - asset_layer.events.register( 'visibilitychanged', asset_layer, layer_visibilitychanged); - fixmystreet.map.events.register( 'zoomend', asset_layer, check_zoom_message_visibility); + var hover_feature_control, select_feature_control; + if (!options.non_interactive) { + // Set up handlers for selecting/unselecting markers + select_feature_control = new OpenLayers.Control.SelectFeature( asset_layer ); + asset_layer.events.register( 'featureselected', asset_layer, asset_selected); + asset_layer.events.register( 'featureunselected', asset_layer, asset_unselected); + // When panning/zooming the map check that this layer is still correctly shown + // and any selected marker is preserved + asset_layer.events.register( 'loadend', asset_layer, layer_loadend); + } + + // Even if an asset layer is marked as non-interactive it can still have + // a hover style which we'll need to set up. + if (!options.non_interactive || (options.stylemap && options.stylemap.styles.hover)) { + // Set up handlers for simply hovering over an asset marker + hover_feature_control = new OpenLayers.Control.SelectFeature( + asset_layer, + { + hover: true, + highlightOnly: true, + renderIntent: 'hover' + } + ); + hover_feature_control.events.register('beforefeaturehighlighted', null, function(e) { + // Don't let marker go from selected->hover state, + // as it causes some mad flickering effect. + if (e.feature.renderIntent == 'select') { + return false; + } + }); + } + if (!options.always_visible) { + asset_layer.events.register( 'visibilitychanged', asset_layer, layer_visibilitychanged); + } // Make sure the user knows something is happening (some asset layers can be sllooowwww) asset_layer.events.register( 'loadstart', null, fixmystreet.maps.loading_spinner.show); asset_layer.events.register( 'loadend', null, fixmystreet.maps.loading_spinner.hide); - // Set up handlers for simply hovering over a street light marker - var hover_feature_control = new OpenLayers.Control.SelectFeature( - asset_layer, - { - hover: true, - highlightOnly: true, - renderIntent: 'temporary' - } - ); - hover_feature_control.events.register('beforefeaturehighlighted', null, function(e) { - // Don't let marker go from selected->hover state, - // as it causes some mad flickering effect. - if (e.feature.renderIntent == 'select') { - return false; - } - }); - - fixmystreet.map.addLayer(asset_layer); + fixmystreet.assets.layers.push(asset_layer); + if (options.always_visible) { + asset_layer.setVisibility(true); + } if (asset_fault_layer) { - fixmystreet.map.addLayer(asset_fault_layer); + fixmystreet.assets.layers.push(asset_fault_layer); + } + if (hover_feature_control) { + fixmystreet.assets.controls.push(hover_feature_control); + } + if (select_feature_control) { + fixmystreet.assets.controls.push(select_feature_control); } - fixmystreet.map.addControl( hover_feature_control ); - hover_feature_control.activate(); - fixmystreet.map.addControl( select_feature_control ); - select_feature_control.activate(); - // Make sure the fault markers always appear beneath the street lights + // Make sure the fault markers always appear beneath the linked assets if (asset_fault_layer) { asset_fault_layer.setZIndex(asset_layer.getZIndex()-1); } - // Show/hide the asset layer when the category is chosen - $("#problem_form").on("change.category", "select#form_category", function(){ - var category = $(this).val(); - if (category == options.asset_category) { - asset_layer.setVisibility(true); - if (asset_fault_layer) { - asset_fault_layer.setVisibility(true); + if (!asset_layer.fixmystreet.always_visible) { + // Show/hide the asset layer when the category is chosen + $("#problem_form").on("change.category", "select#form_category", function(){ + var category = $(this).val(); + if (category == options.asset_category) { + asset_layer.setVisibility(true); + if (asset_fault_layer) { + asset_fault_layer.setVisibility(true); + } + zoom_to_assets(asset_layer); + } else { + asset_layer.setVisibility(false); + if (asset_fault_layer) { + asset_fault_layer.setVisibility(false); + } } - zoom_to_assets(asset_layer); - } else { - asset_layer.setVisibility(false); - if (asset_fault_layer) { - asset_fault_layer.setVisibility(false); + }); + } + }, + + init: function() { + if (fixmystreet.page != 'new' && fixmystreet.page != 'around') { + // We only want to show asset markers when making a new report + return; + } + + // Make sure the assets get hidden if the back button is pressed + fixmystreet.maps.display_around = (function(original) { + function hide_assets() { + for (var i = 0; i < fixmystreet.assets.layers.length; i++) { + var layer = fixmystreet.assets.layers[i]; + if (!layer.fixmystreet.always_visible) { + layer.setVisibility(false); + } } + fixmystreet.markers.setVisibility(true); + original.apply(fixmystreet.maps); } - }); - } - - // Make sure the assets get hidden if the back button is pressed - fixmystreet.maps.display_around = (function(original) { - function hide_assets() { - asset_layer.setVisibility(false); - if (asset_fault_layer) { - asset_fault_layer.setVisibility(false); + return hide_assets; + })(fixmystreet.maps.display_around); + + for (var i = 0; i < fixmystreet.assets.layers.length; i++) { + var layer = fixmystreet.assets.layers[i]; + fixmystreet.map.addLayer(layer); + if (layer.fixmystreet.asset_category) { + fixmystreet.map.events.register( 'zoomend', layer, check_zoom_message_visibility); } - fixmystreet.markers.setVisibility(true); - original.apply(fixmystreet.maps); } - return hide_assets; - })(fixmystreet.maps.display_around); - return add_assets; + for (i = 0; i < fixmystreet.assets.controls.length; i++) { + fixmystreet.map.addControl(fixmystreet.assets.controls[i]); + fixmystreet.assets.controls[i].activate(); + } + } }; +$(function() { + fixmystreet.assets.init(); +}); + })(); diff --git a/web/cobrands/fixmystreet/staff.js b/web/cobrands/fixmystreet/staff.js index f2b98744b..37bfeabaf 100644 --- a/web/cobrands/fixmystreet/staff.js +++ b/web/cobrands/fixmystreet/staff.js @@ -432,8 +432,8 @@ $.extend(fixmystreet.set_up, { $.extend(fixmystreet.hooks, { update_problem_fields: function(args) { if (args.prefill_reports && args.role == 'inspector') { - var title = args.category + ' problem has been scheduled for fixing'; - var description = args.category + ' problem found - scheduled for fixing by ' + args.body; + var title = 'A ' + args.category + ' problem has been found'; + var description = 'A ' + args.category + ' problem has been found by ' + args.body; var $title_field = $('#form_title'); var $description_field = $('#form_detail'); diff --git a/web/vendor/OpenLayers.Projection.OrdnanceSurvey.js b/web/vendor/OpenLayers.Projection.OrdnanceSurvey.js index 85574d8e0..339f57a93 100644 --- a/web/vendor/OpenLayers.Projection.OrdnanceSurvey.js +++ b/web/vendor/OpenLayers.Projection.OrdnanceSurvey.js @@ -107,11 +107,19 @@ OpenLayers.Projection.OS = { }, goog2osgb: function(point) { - return OpenLayers.Projection.OS.projectForwardBritish(OpenLayers.Layer.SphericalMercator.projectInverse(point)); + var p1 = OpenLayers.Layer.SphericalMercator.inverseMercator(point.x, point.y); + var p2 = OpenLayers.Projection.OS.projectForwardBritish({x: p1.lon, y: p1.lat}); + point.x = p2.x; + point.y = p2.y; + return point; }, osgb2goog: function(point) { - return OpenLayers.Layer.SphericalMercator.projectForward(OpenLayers.Projection.OS.projectInverseBritish(point)); + var p1 = OpenLayers.Projection.OS.projectInverseBritish(point); + var p2 = OpenLayers.Layer.SphericalMercator.forwardMercator(p1.x, p1.y); + point.x = p2.lon; + point.y = p2.lat; + return point; }, /***** |