aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm5
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm14
-rw-r--r--t/app/controller/report_new.t149
-rw-r--r--templates/web/base/maps/openlayers.html3
-rw-r--r--web/cobrands/fixmystreet/assets.js96
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js3
-rw-r--r--web/cobrands/fixmystreet/map.js5
-rw-r--r--web/js/map-OpenLayers.js42
8 files changed, 260 insertions, 57 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index a2d7ed025..db2eceda3 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -9,6 +9,7 @@ use Encode;
use JSON::MaybeXS;
use Utils;
use Try::Tiny;
+use Text::CSV;
=head1 NAME
@@ -230,6 +231,10 @@ sub check_and_stash_category : Private {
my $all_areas = $c->stash->{all_areas};
my @bodies = $c->model('DB::Body')->active->for_areas(keys %$all_areas)->all;
my %bodies = map { $_->id => $_ } @bodies;
+ my @list_of_names = map { $_->name } values %bodies;
+ my $csv = Text::CSV->new();
+ $csv->combine(@list_of_names);
+ $c->{stash}->{list_of_names_as_string} = $csv->string;
my @categories = $c->model('DB::Contact')->not_deleted->search(
{
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 9172de5b6..5d24bc980 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -208,6 +208,7 @@ sub report_form_ajax : Path('ajax') : Args(0) {
my $extra_titles_list = $c->cobrand->title_list($c->stash->{all_areas});
+ my @list_of_names = map { $_->name } values %{$c->stash->{bodies}};
my $contribute_as = {};
if ($c->user_exists) {
my @bodies = keys %{$c->stash->{bodies}};
@@ -221,6 +222,7 @@ sub report_form_ajax : Path('ajax') : Args(0) {
my $body = encode_json(
{
+ bodies => \@list_of_names,
councils_text => $councils_text,
councils_text_private => $councils_text_private,
category => $category,
@@ -254,8 +256,10 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
$category = '' if $category eq _('-- Pick a 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 => [ map { $_->name } @$bodies ]) : (),
+ $category ? (list_of_names => $list_of_names) : (),
};
my $category_extra = '';
@@ -281,12 +285,14 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
my $councils_text_private = $c->render_fragment( 'report/new/councils_text_private.html');
$unresponsive = $c->stash->{unresponsive}->{$category} || $c->stash->{unresponsive}->{ALL} || '';
+
my $body = encode_json({
category_extra => $category_extra,
councils_text => $councils_text,
councils_text_private => $councils_text_private,
category_extra_json => $category_extra_json,
unresponsive => $unresponsive,
+ bodies => $list_of_names,
});
$c->res->content_type('application/json; charset=utf-8');
@@ -707,6 +713,12 @@ sub setup_categories_and_bodies : Private {
$c->stash->{non_public_categories} = \%non_public_categories;
$c->stash->{extra_name_info} = $first_area->{id} == COUNCIL_ID_BROMLEY ? 1 : 0;
+ # escape these so we can then split on , cleanly in the template.
+ my @list_of_names = map { $_->name } values %bodies_to_list;
+ my $csv = Text::CSV->new();
+ $csv->combine(@list_of_names);
+ $c->stash->{list_of_names_as_string} = $csv->string;
+
my @missing_details_bodies = grep { !$bodies_to_list{$_->id} } values %bodies;
my @missing_details_body_names = map { $_->name } @missing_details_bodies;
diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t
index 4f229dc8c..8c4deec56 100644
--- a/t/app/controller/report_new.t
+++ b/t/app/controller/report_new.t
@@ -40,6 +40,7 @@ for my $body (
{ area_id => 2482, name => 'Bromley Council' },
{ area_id => 2227, name => 'Hampshire County Council' },
{ area_id => 2333, name => 'Hart Council' },
+ { area_id => 2535, name => 'Sandwell Borough Council' },
) {
my $body_obj = $mech->create_body_ok($body->{area_id}, $body->{name});
push @bodies, $body_obj;
@@ -1177,24 +1178,48 @@ subtest "test report creation for a category that is non public" => sub {
$contact2->category( "Pothol\xc3\xa9s" );
$contact2->update;
-my $extra_details;
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
- MAPIT_URL => 'http://mapit.uk/',
-}, sub {
- $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=' . $saved_lat . '&longitude=' . $saved_lon );
-};
-$mech->content_contains( "Pothol\xc3\xa9s" );
-like $extra_details->{councils_text}, qr/<strong>Cheltenham/;
-ok !$extra_details->{titles_list}, 'Non Bromley does not send back list of titles';
-
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
- MAPIT_URL => 'http://mapit.uk/',
-}, sub {
- $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=51.4021&longitude=0.01578');
+subtest "check map click ajax response" => sub {
+ my $extra_details;
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => 'fixmystreet',
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=' . $saved_lat . '&longitude=' . $saved_lon );
+ };
+ # this order seems to be random so check individually/sort
+ like $extra_details->{councils_text}, qr/Cheltenham Borough Council/, 'correct council text for two tier';
+ like $extra_details->{councils_text}, qr/Gloucestershire County Council/, 'correct council text for two tier';
+ like $extra_details->{category}, qr/Pothol\x{00E9}s.*Street lighting/, 'category looks correct for two tier council';
+ my @sorted_bodies = sort @{ $extra_details->{bodies} };
+ is_deeply \@sorted_bodies, [ "Cheltenham Borough Council", "Gloucestershire County Council" ], 'correct bodies for two tier';
+ ok !$extra_details->{titles_list}, 'Non Bromley does not send back list of titles';
+
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => 'fixmystreet',
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=51.4021&longitude=0.01578');
+ };
+ ok $extra_details->{titles_list}, 'Bromley sends back list of titles';
+ like $extra_details->{councils_text}, qr/Bromley Council/, 'correct council text';
+ like $extra_details->{councils_text_private}, qr/^These will be sent to the council, but will never be shown online/, 'correct private council text';
+ like $extra_details->{category}, qr/Trees/, 'category looks correct';
+ is_deeply $extra_details->{bodies}, [ "Bromley Council" ], 'correct bodies';
+ ok !$extra_details->{contribute_as}, 'no contribute as section';
+ ok !$extra_details->{top_message}, 'no top message';
+ ok $extra_details->{extra_name_info}, 'extra name info';
+
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => 'fixmystreet',
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=52.563074&longitude=-1.991032' );
+ };
+ like $extra_details->{councils_text}, qr/^These will be published online for others to see/, 'correct council text for council with no contacts';
+ is $extra_details->{category}, '', 'category is empty for council with no contacts';
+ is_deeply $extra_details->{bodies}, [ "Sandwell Borough Council" ], 'correct bodies for council with no contacts';
+ ok !$extra_details->{extra_name_info}, 'no extra name info';
};
-ok $extra_details->{titles_list}, 'Bromley sends back list of titles';
#### test uploading an image
@@ -1885,6 +1910,7 @@ subtest "extra google analytics code displayed on email confirmation problem cre
};
};
+my $inspector = $mech->create_user_ok('inspector@example.org', name => 'inspector', from_body => $bodies[0]);
foreach my $test (
{ non_public => 0 },
{ non_public => 1 },
@@ -1897,12 +1923,11 @@ foreach my $test (
}, sub {
$mech->log_out_ok;
- my $user = $mech->create_user_ok('inspector@example.org', name => 'inspector', from_body => $bodies[0]);
- $user->user_body_permissions->find_or_create({
+ $inspector->user_body_permissions->find_or_create({
body => $bodies[0],
permission_type => 'planned_reports',
});
- $user->user_body_permissions->find_or_create({
+ $inspector->user_body_permissions->find_or_create({
body => $bodies[0],
permission_type => 'report_inspect',
});
@@ -1937,4 +1962,88 @@ foreach my $test (
};
}
+subtest "check map click ajax response for inspector" => sub {
+ $mech->log_out_ok;
+
+ my $extra_details;
+ $inspector->user_body_permissions->find_or_create({
+ body => $bodies[0],
+ permission_type => 'planned_reports',
+ });
+ $inspector->user_body_permissions->find_or_create({
+ body => $bodies[0],
+ permission_type => 'report_inspect',
+ });
+
+ $mech->log_in_ok('inspector@example.org');
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=55.952055&longitude=-3.189579' );
+ };
+ like $extra_details->{category}, qr/data-role="inspector/, 'category has correct data-role';
+ ok !$extra_details->{contribute_as}, 'no contribute as section';
+};
+
+for my $test (
+ {
+ desc => 'map click ajax for contribute_as_another_user',
+ permissions => {
+ contribute_as_another_user => 1,
+ contribute_as_anonymous_user => undef,
+ contribute_as_body => undef,
+ }
+ },
+ {
+ desc => 'map click ajax for contribute_as_anonymous_user',
+ permissions => {
+ contribute_as_another_user => undef,
+ contribute_as_anonymous_user => 1,
+ contribute_as_body => undef,
+ }
+ },
+ {
+ desc => 'map click ajax for contribute_as_body',
+ permissions => {
+ contribute_as_another_user => undef,
+ contribute_as_anonymous_user => undef,
+ contribute_as_body => 1,
+ }
+ },
+) {
+ subtest $test->{desc} => sub {
+ $mech->log_out_ok;
+ my $extra_details;
+ (my $name = $test->{desc}) =~ s/.*(contri.*)/$1/;
+ my $user = $mech->create_user_ok("$name\@example.org", name => 'test user', from_body => $bodies[0]);
+ for my $p ( keys %{$test->{permissions}} ) {
+ next unless $test->{permissions}->{$p};
+ $user->user_body_permissions->find_or_create({
+ body => $bodies[0],
+ permission_type => $p,
+ });
+ }
+ $mech->log_in_ok("$name\@example.org");
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=55.952055&longitude=-3.189579' );
+ };
+ for my $p ( keys %{$test->{permissions}} ) {
+ (my $key = $p) =~ s/contribute_as_//;
+ is $extra_details->{contribute_as}->{$key}, $test->{permissions}->{$p}, "$key correctly set";
+ }
+
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ $extra_details = $mech->get_ok_json( '/report/new/ajax?latitude=51.754926&longitude=-1.256179' );
+ };
+ ok !$extra_details->{contribute_as}, 'no contribute as section for other council';
+ };
+}
+
done_testing();
diff --git a/templates/web/base/maps/openlayers.html b/templates/web/base/maps/openlayers.html
index 12ae88c05..524075371 100644
--- a/templates/web/base/maps/openlayers.html
+++ b/templates/web/base/maps/openlayers.html
@@ -25,6 +25,9 @@
[% IF include_key -%]
data-key='[% c.config.BING_MAPS_API_KEY %]'
[%- END -%]
+[% IF list_of_names_as_string -%]
+ data-bodies='[% list_of_names_as_string | html %]'
+[%- END -%]
>
</div>
<div id="map_box" aria-hidden="true">
diff --git a/web/cobrands/fixmystreet/assets.js b/web/cobrands/fixmystreet/assets.js
index 7ce12cbe3..11ea1c80e 100644
--- a/web/cobrands/fixmystreet/assets.js
+++ b/web/cobrands/fixmystreet/assets.js
@@ -16,12 +16,59 @@ var fixmystreet = fixmystreet || {};
};
})();
+OpenLayers.Layer.VectorAsset = OpenLayers.Class(OpenLayers.Layer.Vector, {
+ initialize: function(name, options) {
+ OpenLayers.Layer.Vector.prototype.initialize.apply(this, arguments);
+ $(fixmystreet).on('report_new:category_change', this.update_layer_visibility.bind(this));
+ },
+
+ update_layer_visibility: function() {
+ if (!fixmystreet.map) {
+ return;
+ }
+
+ if (!this.fixmystreet.always_visible) {
+ // Show/hide the asset layer when the category is chosen
+ var category = $('#problem_form select#form_category').val();
+ if (fixmystreet.assets.check_layer_relevant(this.fixmystreet, category)) {
+ this.setVisibility(true);
+ if (this.fixmystreet.fault_layer) {
+ this.fixmystreet.fault_layer.setVisibility(true);
+ }
+ this.zoom_to_assets();
+ } else {
+ this.setVisibility(false);
+ if (this.fixmystreet.fault_layer) {
+ this.fixmystreet.fault_layer.setVisibility(false);
+ }
+ }
+ } else {
+ if (this.fixmystreet.body) {
+ this.setVisibility(OpenLayers.Util.indexOf(fixmystreet.bodies, this.fixmystreet.body) != -1 );
+ }
+ }
+ },
+
+ zoom_to_assets: function() {
+ // This function is called when the asset category is
+ // selected, and will zoom the map in to the first level that
+ // makes the asset layer visible if it's not already shown.
+ if (!this.inRange) {
+ var firstVisibleResolution = this.resolutions[0];
+ var zoomLevel = fixmystreet.map.getZoomForResolution(firstVisibleResolution);
+ fixmystreet.map.zoomTo(zoomLevel);
+ }
+ },
+
+ CLASS_NAME: 'OpenLayers.Layer.VectorAsset'
+});
+
// Handles layers such as USRN, TfL roads, and the like
-OpenLayers.Layer.VectorNearest = OpenLayers.Class(OpenLayers.Layer.Vector, {
+OpenLayers.Layer.VectorNearest = OpenLayers.Class(OpenLayers.Layer.VectorAsset, {
selected_feature: null,
initialize: function(name, options) {
- OpenLayers.Layer.Vector.prototype.initialize.apply(this, arguments);
+ OpenLayers.Layer.VectorAsset.prototype.initialize.apply(this, arguments);
$(fixmystreet).on('maps:update_pin', this.checkFeature.bind(this));
$(fixmystreet).on('assets:selected', this.checkFeature.bind(this));
// Might only be able to fill in fields once they've been returned from the server
@@ -31,10 +78,13 @@ OpenLayers.Layer.VectorNearest = OpenLayers.Class(OpenLayers.Layer.Vector, {
},
checkFeature: function(evt, lonlat) {
+ if (!this.getVisibility()) {
+ return;
+ }
this.getNearest(lonlat);
this.updateUSRNField();
if (this.fixmystreet.road) {
- var valid_category = this.fixmystreet.all_categories || (this.fixmystreet.asset_category && this.fixmystreet.asset_category.indexOf($('select#form_category').val()) != -1);
+ var valid_category = this.fixmystreet.all_categories || (this.fixmystreet.asset_category && fixmystreet.assets.check_layer_relevant( this.fixmystreet, $('select#form_category').val() ) );
if (!valid_category || !this.selected_feature) {
this.road_not_found();
} else {
@@ -111,6 +161,7 @@ var fault_popup = null;
* Called as part of fixmystreet.assets.init for each asset layer on the map.
*/
function init_asset_layer(layer, pins_layer) {
+ layer.update_layer_visibility();
fixmystreet.map.addLayer(layer);
if (layer.fixmystreet.asset_category) {
fixmystreet.map.events.register( 'zoomend', layer, check_zoom_message_visibility);
@@ -140,28 +191,8 @@ function init_asset_layer(layer, pins_layer) {
layer.events.register( 'loadend', layer, layer.one_time_select );
}
- if (!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 (layer.fixmystreet.asset_category.indexOf(category) != -1) {
- layer.setVisibility(true);
- if (layer.fixmystreet.fault_layer) {
- layer.fixmystreet.fault_layer.setVisibility(true);
- }
- zoom_to_assets(layer);
- } else {
- layer.setVisibility(false);
- if (layer.fixmystreet.fault_layer) {
- layer.fixmystreet.fault_layer.setVisibility(false);
- }
- }
- });
- }
-
}
-
function close_fault_popup() {
if (!!fault_popup) {
fixmystreet.map.removePopup(fault_popup);
@@ -267,7 +298,7 @@ function check_zoom_message_visibility() {
prefix = category.replace(/[^a-z]/gi, ''),
id = "category_meta_message_" + prefix,
$p = $('#' + id);
- if (this.fixmystreet.asset_category.indexOf(category) != -1) {
+ if (fixmystreet.assets.check_layer_relevant(this.fixmystreet, category)) {
if ($p.length === 0) {
$p = $("<p>").prop("id", id).prop('class', 'category_meta_message');
$p.insertAfter('#form_category_row');
@@ -313,16 +344,6 @@ function layer_visibilitychanged() {
}
}
-function zoom_to_assets(layer) {
- // This function is called when the asset category is
- // selected, and will zoom the map in to the first level that
- // makes the asset layer visible if it's not already shown.
- if (!layer.inRange) {
- var firstVisibleResolution = layer.resolutions[0];
- var zoomLevel = fixmystreet.map.getZoomForResolution(firstVisibleResolution);
- fixmystreet.map.zoomTo(zoomLevel);
- }
-}
function get_select_control(layer) {
var controls = fixmystreet.map.getControlsByClass('OpenLayers.Control.SelectFeature');
@@ -503,7 +524,7 @@ fixmystreet.assets = {
}
}
- var layer_class = OpenLayers.Layer.Vector;
+ var layer_class = OpenLayers.Layer.VectorAsset;
if (options.usrn || options.road) {
layer_class = OpenLayers.Layer.VectorNearest;
}
@@ -631,6 +652,11 @@ fixmystreet.assets = {
fixmystreet.map.addControl(fixmystreet.assets.controls[i]);
fixmystreet.assets.controls[i].activate();
}
+ },
+
+ check_layer_relevant: function(layer, category) {
+ return OpenLayers.Util.indexOf(layer.asset_category, category) != -1 &&
+ ( !layer.body || OpenLayers.Util.indexOf(fixmystreet.bodies, layer.body) != -1 );
}
};
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index 26b0b293a..5f9dd9699 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -409,6 +409,7 @@ $.extend(fixmystreet.set_up, {
} else {
$category_meta.empty();
}
+ fixmystreet.bodies = data.bodies || [];
$(fixmystreet).trigger('report_new:category_change:extras_received');
});
@@ -940,6 +941,8 @@ fixmystreet.update_pin = function(lonlat, savePushState) {
lb.before(data.extra_name_info);
}
+ fixmystreet.bodies = data.bodies || [];
+
// If the category filter appears on the map and the user has selected
// something from it, then pre-fill the category field in the report,
// if it's a value already present in the drop-down.
diff --git a/web/cobrands/fixmystreet/map.js b/web/cobrands/fixmystreet/map.js
index 9303c22b7..7c3aeb55e 100644
--- a/web/cobrands/fixmystreet/map.js
+++ b/web/cobrands/fixmystreet/map.js
@@ -3,7 +3,7 @@ var fixmystreet = fixmystreet || {};
(function(){
var map_data = document.getElementById('js-map-data'),
- map_keys = [ 'area', 'latitude', 'longitude', 'zoomToBounds', 'zoom', 'pin_prefix', 'pin_new_report_colour', 'numZoomLevels', 'zoomOffset', 'map_type', 'key' ],
+ map_keys = [ 'area', 'latitude', 'longitude', 'zoomToBounds', 'zoom', 'pin_prefix', 'pin_new_report_colour', 'numZoomLevels', 'zoomOffset', 'map_type', 'key', 'bodies' ],
numeric = { zoom: 1, numZoomLevels: 1, zoomOffset: 1, id: 1 },
pin_keys = [ 'lat', 'lon', 'colour', 'id', 'title', 'type' ];
@@ -18,6 +18,9 @@ var fixmystreet = fixmystreet || {};
}
});
+
+ fixmystreet.bodies = fixmystreet.bodies ? fixmystreet.utils.csv_to_array(fixmystreet.bodies)[0] : [];
+
fixmystreet.area = fixmystreet.area ? fixmystreet.area.split(',') : [];
if (fixmystreet.map_type) {
var s = fixmystreet.map_type.split('.');
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index 3c9e3fb91..07acf248c 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -27,6 +27,48 @@ $.extend(fixmystreet.utils, {
return out.join(',');
},
+ // https://stackoverflow.com/questions/1293147/javascript-code-to-parse-csv-data/1293163#1293163
+ csv_to_array: function( strData, strDelimiter ) {
+ strDelimiter = (strDelimiter || ",");
+
+ var objPattern = new RegExp(
+ (
+ "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
+ "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
+ "([^\"\\" + strDelimiter + "\\r\\n]*))"
+ ),
+ "gi"
+ );
+
+ var arrData = [[]];
+
+ var arrMatches = objPattern.exec( strData );
+ while (arrMatches) {
+
+ var strMatchedDelimiter = arrMatches[ 1 ];
+
+ if ( strMatchedDelimiter.length &&
+ strMatchedDelimiter !== strDelimiter) {
+ arrData.push( [] );
+ }
+
+ var strMatchedValue;
+ if (arrMatches[ 2 ]) {
+ strMatchedValue = arrMatches[ 2 ].replace(
+ new RegExp( "\"\"", "g" ),
+ "\""
+ );
+ } else {
+ strMatchedValue = arrMatches[ 3 ];
+ }
+
+ arrData[ arrData.length - 1 ].push( strMatchedValue );
+ arrMatches = objPattern.exec( strData );
+ }
+
+ return( arrData );
+ },
+
parse_query_string: function() {
var qs = {};
if (!location.search) {