aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm6
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/DefectType.pm32
-rw-r--r--perllib/FixMyStreet/Roles/ContactExtra.pm43
-rw-r--r--t/app/model/defecttype.t70
-rw-r--r--templates/web/base/report/_inspect.html4
-rw-r--r--templates/web/oxfordshire/footer_extra_js.html3
-rw-r--r--web/cobrands/fixmystreet/staff.js23
-rw-r--r--web/cobrands/oxfordshire/js.js7
8 files changed, 169 insertions, 19 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 823f4d08f..1d322e88c 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -633,6 +633,12 @@ sub setup_categories_and_bodies : Private {
# keysort does not appear to obey locale so use strcoll (see i18n.t)
@contacts = sort { strcoll( $a->category, $b->category ) } @contacts;
+ # Get defect types for inspectors
+ if ($c->cobrand->can('council_area_id')) {
+ my $category_defect_types = FixMyStreet::App->model('DB::DefectType')->by_categories($c->cobrand->council_area_id, @contacts);
+ $c->stash->{category_defect_types} = $category_defect_types;
+ }
+
my %seen;
foreach my $contact (@contacts) {
diff --git a/perllib/FixMyStreet/DB/ResultSet/DefectType.pm b/perllib/FixMyStreet/DB/ResultSet/DefectType.pm
index a873ef252..b2ef77f7c 100644
--- a/perllib/FixMyStreet/DB/ResultSet/DefectType.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/DefectType.pm
@@ -3,20 +3,26 @@ use base 'DBIx::Class::ResultSet';
use strict;
use warnings;
+use Moo;
+use HTML::Entities;
-sub for_bodies {
- my ($rs, $bodies, $category) = @_;
- my $attrs = {
- 'me.body_id' => $bodies,
- };
- if ($category) {
- $attrs->{'contact.category'} = [ $category, undef ];
- }
- $rs->search($attrs, {
- order_by => 'name',
- join => { 'contact_defect_types' => 'contact' },
- distinct => 1,
- });
+with('FixMyStreet::Roles::ContactExtra');
+
+sub join_table {
+ return 'contact_defect_types';
+}
+
+sub map_extras {
+ my ($rs, @ts) = @_;
+ return map {
+ my $meta = $_->get_extra_metadata();
+ my %extra = map { $_ => encode_entities($meta->{$_}) } keys %$meta;
+ {
+ id => $_->id,
+ name => encode_entities($_->name),
+ extra => \%extra
+ }
+ } @ts;
}
1;
diff --git a/perllib/FixMyStreet/Roles/ContactExtra.pm b/perllib/FixMyStreet/Roles/ContactExtra.pm
new file mode 100644
index 000000000..d23a094f3
--- /dev/null
+++ b/perllib/FixMyStreet/Roles/ContactExtra.pm
@@ -0,0 +1,43 @@
+package FixMyStreet::Roles::ContactExtra;
+
+use Moo::Role;
+use JSON::MaybeXS;
+
+requires 'join_table', 'map_extras';
+
+sub for_bodies {
+ my ($rs, $bodies, $category) = @_;
+ my $join_table = $rs->join_table();
+ my $attrs = {
+ 'me.body_id' => $bodies,
+ };
+ my $filters = {
+ order_by => 'name',
+ join => { $join_table => 'contact' },
+ distinct => 1,
+ };
+ if ($category) {
+ $attrs->{'contact.category'} = [ $category, undef ];
+ }
+ $rs->search($attrs, $filters);
+}
+
+sub by_categories {
+ my ($rs, $area_id, @contacts) = @_;
+ my %body_ids = map { $_->body_id => 1 } FixMyStreet::DB->resultset('BodyArea')->search({ area_id => $area_id });
+ my @body_ids = keys %body_ids;
+ my %extras = ();
+ my @results = $rs->for_bodies(\@body_ids, undef);
+ @contacts = grep { $body_ids{$_->body_id} } @contacts;
+
+ foreach my $contact (@contacts) {
+ my $join_table = $rs->join_table();
+ my @ts = grep { !defined($_->$join_table->first) || $_->$join_table->find({contact_id => $contact->get_column('id')}) } @results;
+ @ts = $rs->map_extras(@ts);
+ $extras{$contact->category} = encode_json(\@ts);
+ }
+
+ return \%extras;
+}
+
+1;
diff --git a/t/app/model/defecttype.t b/t/app/model/defecttype.t
index ec79c1c8e..4f380db59 100644
--- a/t/app/model/defecttype.t
+++ b/t/app/model/defecttype.t
@@ -1,21 +1,31 @@
use FixMyStreet::App;
use FixMyStreet::TestMech;
+use JSON::MaybeXS;
+
my $mech = FixMyStreet::TestMech->new;
+my $area_id = 2237;
-my $oxfordshire = $mech->create_body_ok(2237, 'Oxfordshire County Council');
+my $oxfordshire = $mech->create_body_ok($area_id, 'Oxfordshire County Council');
+my $other_body = $mech->create_body_ok($area_id, 'Some Other Council');
my $potholes_contact = $mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Potholes', email => 'potholes@example.com' );
my $traffic_lights_contact =$mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Traffic lights', email => 'lights@example.com' );
+my $pavements_contact =$mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Pavements', email => 'pavements@example.com' );
my $potholes_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create(
{
body_id => $oxfordshire->id,
- name => 'Potholes',
- description => 'This defect type is to do with potholes'
+ name => 'Potholes and Pavements',
+ description => 'This defect type is to do with potholes and Pavements'
}
);
+$potholes_defect_type->set_extra_metadata('defect_code' => 123);
$potholes_defect_type->contact_defect_types->find_or_create({
contact_id => $potholes_contact->id,
});
+$potholes_defect_type->contact_defect_types->find_or_create({
+ contact_id => $pavements_contact->id,
+});
+$potholes_defect_type->update();
my $general_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create(
{
@@ -55,6 +65,60 @@ subtest 'Problem->defect_types behaves correctly' => sub {
is $problem->defect_types->first->name, $general_defect_type->name, 'Correct defect type is returned for Traffic lights category';
};
+subtest 'by_categories returns all defect types grouped by category' => sub {
+ my @contacts = FixMyStreet::DB->resultset('Contact')->not_deleted->search( { body_id => [ $oxfordshire->id ] } )->all;
+ my $defect_types = FixMyStreet::App->model('DB::DefectType')->by_categories($area_id, @contacts);
+ my $potholes = decode_json($defect_types->{Potholes});
+ my $traffic_lights = decode_json($defect_types->{'Traffic lights'});
+ my $pavements = decode_json($defect_types->{Pavements});
+
+ is scalar @$potholes, 2, 'Potholes have 2 defect types';
+ is scalar @$traffic_lights, 1, 'Traffic lights have 1 defect type';
+ is scalar @$pavements, 2, 'Pavements have 2 defect types';
+
+ is @$potholes[1]->{extra}->{defect_code}, 123, 'Defect code is present';
+};
+
+subtest 'by_categories returns defect types for an area with multiple bodies' => sub {
+ FixMyStreet::App->model('DB::DefectType')->find_or_create(
+ {
+ body_id => $other_body->id,
+ name => 'All categories',
+ description => 'This defect type is for all categories'
+ }
+ );
+
+ my @contacts = FixMyStreet::DB->resultset('Contact')->not_deleted->search( { body_id => [ $oxfordshire->id ] } )->all;
+ my $defect_types = FixMyStreet::App->model('DB::DefectType')->by_categories($area_id, @contacts);
+ my $potholes = decode_json($defect_types->{Potholes});
+ my $traffic_lights = decode_json($defect_types->{'Traffic lights'});
+ my $pavements = decode_json($defect_types->{Pavements});
+
+ is scalar @$potholes, 3, 'Potholes have 3 defect types';
+ is scalar @$traffic_lights, 2, 'Traffic lights have 2 defect type';
+ is scalar @$pavements, 3, 'Pavements have 3 defect types';
+};
+
+subtest 'by_categories encodes HTML entities' => sub {
+ my $apostrophe_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create(
+ {
+ body_id => $oxfordshire->id,
+ name => 'This defect type\'s name has an apostrophe',
+ description => 'This defect type is for all categories'
+ }
+ );
+ $apostrophe_defect_type->set_extra_metadata('defect_code' => 'Here\'s an apostrophe');
+ $apostrophe_defect_type->update();
+
+ my @contacts = FixMyStreet::DB->resultset('Contact')->not_deleted->search( { body_id => [ $oxfordshire->id ] } )->all;
+ my $defect_types = FixMyStreet::App->model('DB::DefectType')->by_categories($area_id, @contacts);
+ my $traffic_lights = decode_json($defect_types->{'Traffic lights'});
+ my $defect_type = @$traffic_lights[2];
+ is $defect_type->{name}, 'This defect type's name has an apostrophe';
+ is $defect_type->{extra}->{defect_code}, 'Here's an apostrophe';
+
+};
+
END {
done_testing();
diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html
index a0c310ba4..79f48743a 100644
--- a/templates/web/base/report/_inspect.html
+++ b/templates/web/base/report/_inspect.html
@@ -46,11 +46,11 @@
[% cat_prefix = category | lower | replace('[^a-z]', '') %]
[% cat_prefix = "category_" _ cat_prefix _ "_" %]
[% IF category == problem.category %]
- <p data-category="[% category | html %]" data-priorities="[% priorities_by_category.$category %]">
+ <p data-category="[% category | html %]" data-priorities="[% priorities_by_category.$category %]" data-defect-types='[% category_defect_types.$category %]'>
[% INCLUDE 'report/new/category_extras_fields.html' %]
</p>
[% ELSE %]
- <p data-category="[% category | html %]" class="hidden" data-priorities="[% priorities_by_category.$category %]">
+ <p data-category="[% category | html %]" class="hidden" data-priorities="[% priorities_by_category.$category %]" data-defect-types='[% category_defect_types.$category %]'>
[% INCLUDE 'report/new/category_extras_fields.html' report_meta='' %]
</p>
[% END %]
diff --git a/templates/web/oxfordshire/footer_extra_js.html b/templates/web/oxfordshire/footer_extra_js.html
new file mode 100644
index 000000000..abef0d40f
--- /dev/null
+++ b/templates/web/oxfordshire/footer_extra_js.html
@@ -0,0 +1,3 @@
+[% scripts.push(
+ version('/cobrands/oxfordshire/js.js'),
+) %]
diff --git a/web/cobrands/fixmystreet/staff.js b/web/cobrands/fixmystreet/staff.js
index b1bd9ee54..ac665b591 100644
--- a/web/cobrands/fixmystreet/staff.js
+++ b/web/cobrands/fixmystreet/staff.js
@@ -195,7 +195,19 @@ $.extend(fixmystreet.set_up, {
// in the DOM, we just need to hide/show them as appropriate.
$('form#report_inspect_form [name=category]').change(function() {
var category = $(this).val(),
- selector = "[data-category='" + category + "']";
+ selector = "[data-category='" + category + "']",
+ $defect_types = $('#defect_type'),
+ defect_types_data = $("form#report_inspect_form " + selector).data('defect-types') || [];
+
+ function populateSelect($select, data, label_formatter) {
+ $select.find('option:gt(0)').remove();
+ $.each(data, function(k,v) {
+ label = window.fixmystreet.utils[label_formatter](v);
+ $select.append($('<option></option>')
+ .attr('value', v.id).text(label));
+ });
+ }
+
$("form#report_inspect_form [data-category]:not(" + selector + ")").addClass("hidden");
$("form#report_inspect_form " + selector).removeClass("hidden");
// And update the associated priority list
@@ -211,6 +223,7 @@ $.extend(fixmystreet.set_up, {
$select.append($('<option>', { value: kv[0], text: decodeURIComponent(kv[1]) }));
});
$select.val(curr_pri);
+ populateSelect($defect_types, defect_types_data, 'defect_type_format');
});
// The inspect form submit button can change depending on the selected state
@@ -447,3 +460,11 @@ $.extend(fixmystreet.maps, {
}
}
});
+
+fixmystreet.utils = fixmystreet.utils || {};
+
+$.extend(fixmystreet.utils, {
+ defect_type_format: function(data) {
+ return data.name;
+ }
+});
diff --git a/web/cobrands/oxfordshire/js.js b/web/cobrands/oxfordshire/js.js
new file mode 100644
index 000000000..17cb0dd8f
--- /dev/null
+++ b/web/cobrands/oxfordshire/js.js
@@ -0,0 +1,7 @@
+fixmystreet.utils = fixmystreet.utils || {};
+
+$.extend(fixmystreet.utils, {
+ defect_type_format: function(data) {
+ return data.extra.defect_code + ' - ' + data.extra.activity_code + ' (' + data.name + ')';
+ }
+});