diff options
author | pezholio <pezholio@gmail.com> | 2017-05-24 11:27:19 +0100 |
---|---|---|
committer | Matthew Somerville <matthew-github@dracos.co.uk> | 2017-06-20 17:58:59 +0100 |
commit | bdd1e1627a1be6d9253ecc4e6904e68948227914 (patch) | |
tree | 8acbe51dd2419778eeacd7c8512b1b515da5a2a3 | |
parent | 6c4f3f78bfada011441411f308967298984e7ba5 (diff) |
Populate defect types dropdown on category change
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/New.pm | 6 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/ResultSet/DefectType.pm | 32 | ||||
-rw-r--r-- | perllib/FixMyStreet/Roles/ContactExtra.pm | 43 | ||||
-rw-r--r-- | t/app/model/defecttype.t | 70 | ||||
-rw-r--r-- | templates/web/base/report/_inspect.html | 4 | ||||
-rw-r--r-- | templates/web/oxfordshire/footer_extra_js.html | 3 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/staff.js | 23 | ||||
-rw-r--r-- | web/cobrands/oxfordshire/js.js | 7 |
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 + ')'; + } +}); |