diff options
25 files changed, 593 insertions, 40 deletions
diff --git a/bin/update-schema b/bin/update-schema index 94c42d8ae..171b87576 100755 --- a/bin/update-schema +++ b/bin/update-schema @@ -194,6 +194,7 @@ else { # By querying the database schema, we can see where we're currently at # (assuming schema change files are never half-applied, which should be the case) sub get_db_version { + return '0050' if table_exists('defect_types'); return '0049' if column_exists('response_priorities', 'external_id'); return '0048' if column_exists('response_templates', 'state'); return '0047' if column_exists('response_priorities', 'description'); diff --git a/db/schema.sql b/db/schema.sql index 23db82b65..18c1533d9 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -502,3 +502,21 @@ CREATE TABLE contact_response_priorities ( contact_id int REFERENCES contacts(id) NOT NULL, response_priority_id int REFERENCES response_priorities(id) NOT NULL ); + +CREATE TABLE defect_types ( + id serial not null primary key, + body_id int references body(id) not null, + name text not null, + description text not null, + extra text, + unique(body_id, name) +); + +CREATE TABLE contact_defect_types ( + id serial NOT NULL PRIMARY KEY, + contact_id int REFERENCES contacts(id) NOT NULL, + defect_type_id int REFERENCES defect_types(id) NOT NULL +); + +ALTER TABLE problem + ADD COLUMN defect_type_id int REFERENCES defect_types(id); diff --git a/db/schema_0050-add-defect-type-table.sql b/db/schema_0050-add-defect-type-table.sql new file mode 100644 index 000000000..d65e17940 --- /dev/null +++ b/db/schema_0050-add-defect-type-table.sql @@ -0,0 +1,21 @@ +BEGIN; + +CREATE TABLE defect_types ( + id serial not null primary key, + body_id int references body(id) not null, + name text not null, + description text not null, + extra text, + unique(body_id, name) +); + +CREATE TABLE contact_defect_types ( + id serial NOT NULL PRIMARY KEY, + contact_id int REFERENCES contacts(id) NOT NULL, + defect_type_id int REFERENCES defect_types(id) NOT NULL +); + +ALTER TABLE problem + ADD COLUMN defect_type_id int REFERENCES defect_types(id); + +COMMIT; diff --git a/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm b/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm new file mode 100644 index 000000000..bcfeb3dd8 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Admin/DefectTypes.pm @@ -0,0 +1,113 @@ +package FixMyStreet::App::Controller::Admin::DefectTypes; +use Moose; +use namespace::autoclean; +use mySociety::ArrayUtils; + +BEGIN { extends 'Catalyst::Controller'; } + + +sub begin : Private { + my ( $self, $c ) = @_; + + $c->forward('/admin/begin'); +} + +sub index : Path : Args(0) { + my ( $self, $c ) = @_; + + my $user = $c->user; + + if ($user->is_superuser) { + $c->forward('/admin/fetch_all_bodies'); + } elsif ( $user->from_body ) { + $c->forward('load_user_body', [ $user->from_body->id ]); + $c->res->redirect( $c->uri_for( '', $c->stash->{body}->id ) ); + } else { + $c->detach( '/page_error_404_not_found' ); + } +} + +sub list : Path : Args(1) { + my ($self, $c, $body_id) = @_; + + $c->forward('load_user_body', [ $body_id ]); + + my @defect_types = $c->stash->{body}->defect_types->search( + undef, + { + order_by => 'name' + } + ); + + $c->stash->{defect_types} = \@defect_types; +} + +sub edit : Path : Args(2) { + my ( $self, $c, $body_id, $defect_type_id ) = @_; + + $c->forward('load_user_body', [ $body_id ]); + + my $defect_type; + if ($defect_type_id eq 'new') { + $defect_type = $c->stash->{body}->defect_types->new({}); + } + else { + $defect_type = $c->stash->{body}->defect_types->find( $defect_type_id ) + or $c->detach( '/page_error_404_not_found' ); + } + + $c->forward('/admin/fetch_contacts'); + my @contacts = $defect_type->contacts->all; + my @live_contacts = $c->stash->{live_contacts}->all; + my %active_contacts = map { $_->id => 1 } @contacts; + my @all_contacts = map { { + id => $_->id, + category => $_->category, + active => $active_contacts{$_->id}, + } } @live_contacts; + $c->stash->{contacts} = \@all_contacts; + + if ($c->req->method eq 'POST') { + $defect_type->name( $c->get_param('name') ); + $defect_type->description( $c->get_param('description') ); + + my @extra_fields = @{ $c->cobrand->call_hook('defect_type_extra_fields') || [] }; + foreach ( @extra_fields ) { + $defect_type->set_extra_metadata( $_ => $c->get_param("extra[$_]") ); + } + + $defect_type->update_or_insert; + my @live_contact_ids = map { $_->id } @live_contacts; + my @new_contact_ids = $c->get_param_list('categories'); + @new_contact_ids = @{ mySociety::ArrayUtils::intersection(\@live_contact_ids, \@new_contact_ids) }; + $defect_type->contact_defect_types->search({ + contact_id => { '!=' => \@new_contact_ids }, + })->delete; + foreach my $contact_id (@new_contact_ids) { + $defect_type->contact_defect_types->find_or_create({ + contact_id => $contact_id, + }); + } + + $c->res->redirect( $c->uri_for( '', $c->stash->{body}->id ) ); + } + + $c->stash->{defect_type} = $defect_type; +} + +sub load_user_body : Private { + my ($self, $c, $body_id) = @_; + + my $has_permission = $c->user->has_body_permission_to('defect_type_edit', $body_id); + + unless ( $has_permission ) { + $c->detach( '/page_error_404_not_found' ); + } + + $c->stash->{body} = $c->model('DB::Body')->find($body_id) + or $c->detach( '/page_error_404_not_found' ); +} + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm b/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm index 013d710af..201742c81 100644 --- a/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm +++ b/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm @@ -141,22 +141,32 @@ sub download : Path('download') : Args(0) { foreach my $report (@$inspections) { my ($eastings, $northings) = $report->local_coords; my $description = sprintf("%s %s", $report->external_id || "", $report->get_extra_metadata('detailed_information') || ""); + my $activity_code = $report->defect_type ? + $report->defect_type->get_extra_metadata('activity_code') + : 'MC'; + my $traffic_information = $report->get_extra_metadata('traffic_information') ? + 'TM ' . $report->get_extra_metadata('traffic_information') + : 'TM none'; + $csv->combine( "I", # beginning of defect record - "MC", # activity code - minor carriageway, also FC (footway) + $activity_code, # activity code - minor carriageway, also FC (footway) "", # empty field, can also be A (seen on MC) or B (seen on FC) sprintf("%03d", ++$i), # randomised sequence number "${eastings}E ${northings}N", # defect location field, which we don't capture from inspectors $report->inspection_log_entry->whenedited->strftime("%H%M"), # defect time raised "","","","","","","", # empty fields - $report->get_extra_metadata('traffic_information') ? 'TM required' : 'TM none', # further description + $traffic_information, $description, # defect description ); push @body, $csv->string; + my $defect_type = $report->defect_type ? + $report->defect_type->get_extra_metadata('defect_code') + : 'SFP2'; $csv->combine( "J", # georeferencing record - $report->get_extra_metadata('defect_type') || 'SFP2', # defect type - SFP2: sweep and fill <1m2, POT2 also seen + $defect_type, # defect type - SFP2: sweep and fill <1m2, POT2 also seen $report->response_priority ? $report->response_priority->external_id : "2", # priority of defect diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 1c2e98bd4..fe7576893 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -340,10 +340,16 @@ sub inspect : Private { my %update_params = (); if ($permissions->{report_inspect}) { - foreach (qw/detailed_information traffic_information duplicate_of defect_type/) { + foreach (qw/detailed_information traffic_information duplicate_of/) { $problem->set_extra_metadata( $_ => $c->get_param($_) ); } + if ( $c->get_param('defect_type') ) { + $problem->defect_type($problem->defect_types->find($c->get_param('defect_type'))); + } else { + $problem->defect_type(undef); + } + if ( $c->get_param('include_update') ) { $update_text = Utils::cleanup_text( $c->get_param('public_update'), { allow_multiline => 1 } ); if (!$update_text) { diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index d585a5328..78247e39d 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -161,9 +161,13 @@ sub admin_pages { # Oxfordshire have a custom admin page for downloading reports in an Exor- # friendly format which anyone with report_instruct permission can use. - if ( $user->is_superuser || $user->has_body_permission_to('report_instruct') ) { + if ( $user->has_body_permission_to('report_instruct') ) { $pages->{exordefects} = [ _('Download Exor RDI'), 10 ]; } + if ( $user->has_body_permission_to('defect_type_edit') ) { + $pages->{defecttypes} = [ _('Defect Types'), 11 ]; + $pages->{defecttype_edit} = [ undef, undef ]; + }; return $pages; } @@ -190,4 +194,20 @@ sub user_extra_fields { sub display_days_ago_threshold { 28 } +sub defect_type_extra_fields { + return [ + 'activity_code', + 'defect_code', + ]; +}; + +sub available_permissions { + my $self = shift; + + my $perms = $self->next::method(); + $perms->{Bodies}->{defect_type_edit} = "Add/edit defect types"; + + return $perms; +} + 1; diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm index 6dac8821c..82015ad2d 100644 --- a/perllib/FixMyStreet/DB/Result/Body.pm +++ b/perllib/FixMyStreet/DB/Result/Body.pm @@ -75,6 +75,12 @@ __PACKAGE__->has_many( { "foreign.body_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->has_many( + "defect_types", + "FixMyStreet::DB::Result::DefectType", + { "foreign.body_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); __PACKAGE__->belongs_to( "parent", "FixMyStreet::DB::Result::Body", @@ -112,8 +118,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-06 15:33:04 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZuzscnLqcx0k512cTZ/kdg +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-02-13 15:11:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BOJANVwg3kR/1VjDq0LykA sub url { my ( $self, $c, $args ) = @_; diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm index f7e8ac5b5..a620b7358 100644 --- a/perllib/FixMyStreet/DB/Result/Contact.pm +++ b/perllib/FixMyStreet/DB/Result/Contact.pm @@ -56,6 +56,12 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->has_many( + "contact_defect_types", + "FixMyStreet::DB::Result::ContactDefectType", + { "foreign.contact_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); +__PACKAGE__->has_many( "contact_response_priorities", "FixMyStreet::DB::Result::ContactResponsePriority", { "foreign.contact_id" => "self.id" }, @@ -69,8 +75,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-06 15:33:04 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ocmQGeFJtO3wmvyx6W+EKQ +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-02-13 15:11:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:f9VepR/oPyr3z6PUpJ4w2A __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); __PACKAGE__->rabx_column('extra'); @@ -82,6 +88,7 @@ with 'FixMyStreet::Roles::Extra'; __PACKAGE__->many_to_many( response_templates => 'contact_response_templates', 'response_template' ); __PACKAGE__->many_to_many( response_priorities => 'contact_response_priorities', 'response_priority' ); +__PACKAGE__->many_to_many( defect_types => 'contact_defect_types', 'defect_type' ); sub get_metadata_for_input { my $self = shift; diff --git a/perllib/FixMyStreet/DB/Result/ContactDefectType.pm b/perllib/FixMyStreet/DB/Result/ContactDefectType.pm new file mode 100644 index 000000000..2199f0b42 --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/ContactDefectType.pm @@ -0,0 +1,46 @@ +use utf8; +package FixMyStreet::DB::Result::ContactDefectType; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; +__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn"); +__PACKAGE__->table("contact_defect_types"); +__PACKAGE__->add_columns( + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "contact_defect_types_id_seq", + }, + "contact_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "defect_type_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("id"); +__PACKAGE__->belongs_to( + "contact", + "FixMyStreet::DB::Result::Contact", + { id => "contact_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); +__PACKAGE__->belongs_to( + "defect_type", + "FixMyStreet::DB::Result::DefectType", + { id => "defect_type_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-02-13 15:11:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VIczmM0OXXpWgQVpop3SMw + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/perllib/FixMyStreet/DB/Result/DefectType.pm b/perllib/FixMyStreet/DB/Result/DefectType.pm new file mode 100644 index 000000000..a2969f59e --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/DefectType.pm @@ -0,0 +1,66 @@ +use utf8; +package FixMyStreet::DB::Result::DefectType; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; +__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn"); +__PACKAGE__->table("defect_types"); +__PACKAGE__->add_columns( + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "defect_types_id_seq", + }, + "body_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "name", + { data_type => "text", is_nullable => 0 }, + "description", + { data_type => "text", is_nullable => 0 }, + "extra", + { data_type => "text", is_nullable => 1 }, +); +__PACKAGE__->set_primary_key("id"); +__PACKAGE__->add_unique_constraint("defect_types_body_id_name_key", ["body_id", "name"]); +__PACKAGE__->belongs_to( + "body", + "FixMyStreet::DB::Result::Body", + { id => "body_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); +__PACKAGE__->has_many( + "contact_defect_types", + "FixMyStreet::DB::Result::ContactDefectType", + { "foreign.defect_type_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); +__PACKAGE__->has_many( + "problems", + "FixMyStreet::DB::Result::Problem", + { "foreign.defect_type_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-02-13 15:11:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BBLjb/aAoTKJZerdYCeBMQ + +__PACKAGE__->many_to_many( contacts => 'contact_defect_types', 'contact' ); + +__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); +__PACKAGE__->rabx_column('extra'); + +use Moo; +use namespace::clean -except => [ 'meta' ]; + +with 'FixMyStreet::Roles::Extra'; + + +1; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 0ab52628e..84db41490 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -108,6 +108,8 @@ __PACKAGE__->add_columns( { data_type => "text", is_nullable => 1 }, "response_priority_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, + "defect_type_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->has_many( @@ -116,6 +118,17 @@ __PACKAGE__->has_many( { "foreign.problem_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, ); +__PACKAGE__->belongs_to( + "defect_type", + "FixMyStreet::DB::Result::DefectType", + { id => "defect_type_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, +); __PACKAGE__->has_many( "moderation_original_datas", "FixMyStreet::DB::Result::ModerationOriginalData", @@ -153,8 +166,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-07 11:01:40 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:iH9c4VZZN/ONnhN6g89DFw +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-02-13 15:11:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:8zzWlJX7OQOdvrGxKuZUmg # Add fake relationship to stored procedure table __PACKAGE__->has_one( @@ -754,6 +767,18 @@ sub response_priorities { return $self->result_source->schema->resultset('ResponsePriority')->for_bodies($self->bodies_str_ids, $self->category); } +=head2 defect_types + +Returns all DefectTypes attached to this problem's category/contact, in +alphabetical order of name. + +=cut + +sub defect_types { + my $self = shift; + return $self->result_source->schema->resultset('DefectType')->for_bodies($self->bodies_str_ids, $self->category); +} + # returns true if the external id is the council's ref, i.e., useful to publish it # (by way of an example, the Oxfordshire send method returns a useful reference when # it succeeds, so that is the ref we should show on the problem report page). diff --git a/perllib/FixMyStreet/DB/ResultSet/DefectType.pm b/perllib/FixMyStreet/DB/ResultSet/DefectType.pm new file mode 100644 index 000000000..a873ef252 --- /dev/null +++ b/perllib/FixMyStreet/DB/ResultSet/DefectType.pm @@ -0,0 +1,22 @@ +package FixMyStreet::DB::ResultSet::DefectType; +use base 'DBIx::Class::ResultSet'; + +use strict; +use warnings; + +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, + }); +} + +1; diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index 902ae7a5a..881572a38 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -611,6 +611,7 @@ sub delete_body { my $body = shift; $mech->delete_problems_for_body($body->id); + $mech->delete_defect_type($_) for $body->defect_types; $mech->delete_contact($_) for $body->contacts; $mech->delete_user($_) for $body->users; $_->delete for $body->response_templates; @@ -642,6 +643,14 @@ sub delete_problems_for_body { } } +sub delete_defect_type { + my $mech = shift; + my $defect_type = shift; + + $defect_type->contact_defect_types->delete_all; + $defect_type->delete; +} + sub create_contact_ok { my $self = shift; my %contact_params = ( diff --git a/t/app/model/defecttype.t b/t/app/model/defecttype.t new file mode 100644 index 000000000..0f66ac684 --- /dev/null +++ b/t/app/model/defecttype.t @@ -0,0 +1,67 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::App; +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +my $oxfordshire = $mech->create_body_ok(2237, 'Oxfordshire County Council', id => 2237); +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 $potholes_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create( + { + body_id => 2237, + name => 'Potholes', + description => 'This defect type is to do with potholes' + } +); +$potholes_defect_type->contact_defect_types->find_or_create({ + contact_id => $potholes_contact->id, +}); + +my $general_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create( + { + body_id => 2237, + name => 'All categories', + description => 'This defect type is for all categories' + } +); + + +subtest 'for_bodies returns correct results' => sub { + my $defect_types = FixMyStreet::App->model('DB::DefectType')->for_bodies( + [ $oxfordshire->id ], + 'Potholes' + ); + + is $defect_types->count, 2, 'Both defect types are included for Potholes category'; + + $defect_types = FixMyStreet::App->model('DB::DefectType')->for_bodies( + [ $oxfordshire->id ], + 'Traffic lights' + ); + + is $defect_types->count, 1, 'Only 1 defect type is included for Traffic lights category'; + is $defect_types->first->name, $general_defect_type->name, 'Correct defect type is returned for Traffic lights category'; +}; + +subtest 'Problem->defect_types behaves correctly' => sub { + my ($problem) = $mech->create_problems_for_body(1, $oxfordshire->id, 'Test', { + category => 'Potholes', + }); + + is $problem->defect_types->count, 2, 'Both defect types are available for the problem'; + + $problem->update({ category => 'Traffic lights' }); + is $problem->defect_types->count, 1, 'Only 1 defect type is included for Traffic lights category'; + is $problem->defect_types->first->name, $general_defect_type->name, 'Correct defect type is returned for Traffic lights category'; +}; + + +END { + $mech->delete_body( $oxfordshire ); + + done_testing(); +} diff --git a/templates/web/base/admin/category-multiselect.html b/templates/web/base/admin/category-multiselect.html new file mode 100644 index 000000000..98416204f --- /dev/null +++ b/templates/web/base/admin/category-multiselect.html @@ -0,0 +1,10 @@ +<p> + <strong>[% loc('Categories:') %]</strong> +</p> +<p> + <select class="form-control js-multiple" name="categories" id="categories" multiple data-all="[% loc('All categories') %]"> + [% FOR contact IN contacts %] + <option value="[% contact.id %]" [% 'selected' IF contact.active %]>[% contact.category | html %]</option> + [% END %] + </select> +</p> diff --git a/templates/web/base/admin/defecttypes/edit.html b/templates/web/base/admin/defecttypes/edit.html new file mode 100644 index 000000000..65c8a5ab7 --- /dev/null +++ b/templates/web/base/admin/defecttypes/edit.html @@ -0,0 +1,37 @@ +[% INCLUDE 'admin/header.html' title=tprintf(loc('Defect Type for %s'), body.name) -%] +[% dt = defect_type %] + +[% UNLESS dt.id %]<h3>[% loc('New defect type') %]</h3>[% END %] + +<form method="post" + action="[% c.uri_for('', body.id, dt.id || 'new' ) %]" + enctype="application/x-www-form-urlencoded" + accept-charset="utf-8" + class="validate"> + + <p> + <strong>[% loc('Name:') %] </strong> + <input type="text" name="name" class="required form-control" size="30" value="[% dt.name | html %]"> + </p> + <p> + <strong>[% loc('Description:') %] </strong> + <input type="text" name="description" class="form-control" size="30" value="[% dt.description | html %]"> + </p> + + <div class="admin-hint"> + <p> + [% loc('If you only want this defect type to be an option for specific categories, pick them here. By default they will show for all categories.') %] + </p> + </div> + + [% INCLUDE 'admin/category-multiselect.html' %] + + [% TRY %][% INCLUDE 'admin/defecttypes/extra_fields.html' %][% CATCH file %][% END %] + + <p> + <input type="hidden" name="token" value="[% csrf_token %]" > + <input type="submit" class="btn" name="save" value="[% dt.id ? loc('Save changes') : loc('Create defect type') %]" > + </p> +</form> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/admin/defecttypes/index.html b/templates/web/base/admin/defecttypes/index.html new file mode 100644 index 000000000..2e6ce7e1b --- /dev/null +++ b/templates/web/base/admin/defecttypes/index.html @@ -0,0 +1,13 @@ +[% INCLUDE 'admin/header.html' title=loc('Defect Types') -%] + +<ul> + [% FOR body IN bodies %] + <li> + <a href="[% c.uri_for('', body.id) %]">[% body.name %]</a> + [% defect_types_count = body.defect_types.count %] + [% IF defect_types_count %]([% defect_types_count %])[% END %] + </li> + [% END %] +</ul> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/admin/defecttypes/list.html b/templates/web/base/admin/defecttypes/list.html new file mode 100644 index 000000000..1a9cb4fa7 --- /dev/null +++ b/templates/web/base/admin/defecttypes/list.html @@ -0,0 +1,35 @@ +[% INCLUDE 'admin/header.html' title=tprintf(loc('Defect Types for %s'), body.name) -%] + +<table> + <thead> + <tr> + <th> [% loc('Name') %] </th> + <th> [% loc('Description') %] </th> + <th> [% loc('Categories') %] </th> + <th> </th> + </tr> + </thead> + <tbody> + [% PROCESS 'defect_type/format.html' %] + [% FOR d IN defect_types %] + <tr> + <td> [% defect_type_format(defect_type=d) %] </td> + <td> [% d.description | html %] </td> + <td> + [% UNLESS d.contacts.size %] + <em>[% loc('All categories') %]</em> + [% ELSE %] + [% FOR contact IN d.contacts %] + [% contact.category %][% ',' UNLESS loop.last %] + [% END %] + [% END %] + </td> + <td> <a href="[% c.uri_for('', body.id, d.id) %]" class="btn">[% loc('Edit') %]</a> </td> + </tr> + [% END %] + </tbody> +</table> + +<a href="[% c.uri_for('', body.id, 'new') %]" class="btn">[% loc('New defect type') %]</a> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/defect_type/format.html b/templates/web/base/defect_type/format.html new file mode 100644 index 000000000..3c0781501 --- /dev/null +++ b/templates/web/base/defect_type/format.html @@ -0,0 +1,9 @@ +[% +# This template can be overridden by cobrands if they've added extra fields +# to the DefectType model (e.g Cobrand::Oxfordshire->defect_type_extra_fields) +# which should be used to represent this DefectType +# to the user in the inspect form. +~%] +[% MACRO defect_type_format BLOCK ~%] +[%~ defect_type.name | html ~%] +[%~ END %]
\ No newline at end of file diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html index 625887eff..5e97de3f4 100644 --- a/templates/web/base/report/_inspect.html +++ b/templates/web/base/report/_inspect.html @@ -62,18 +62,17 @@ [% END %] [% IF permissions.report_inspect %] - [% IF c.cobrand.defect_types %] - <p> - <label for="defect_type">[% loc('Defect type') %]</label> - [% defect_type = problem.get_extra_metadata('defect_type') %] - <select id="defect_type" name="defect_type" class="form-control"> - <option value=""[% ' selected' IF NOT defect_type %]>-</option> - [% FOREACH dt IN c.cobrand.defect_types.pairs %] - <option[% ' selected' IF defect_type == dt.key %] value="[% dt.key | html %]">[% dt.value | html %]</option> - [% END %] - </select> - </p> - [% END %] + [% PROCESS 'defect_type/format.html' %] + <p> + <label for="defect_type">[% loc('Defect type') %]</label> + <select id="defect_type" name="defect_type" class="form-control"> + <option value=""[% ' selected' IF NOT problem.defect_type %]>-</option> + [% FOREACH defect_type IN problem.defect_types %] + <option[% ' selected' IF problem.defect_type_id == defect_type.id %] value="[% defect_type.id %]">[% defect_type_format() %]</option> + [% END %] + </select> + </p> + <p> <label for="state">[% loc('State') %]</label> [% INCLUDE 'report/inspect/state_groups_select.html' %] diff --git a/templates/web/oxfordshire/admin/defecttypes/extra_fields.html b/templates/web/oxfordshire/admin/defecttypes/extra_fields.html new file mode 100644 index 000000000..73cc54f0c --- /dev/null +++ b/templates/web/oxfordshire/admin/defecttypes/extra_fields.html @@ -0,0 +1,8 @@ +<p> + <strong>[% loc('Activity Code:') %] </strong> + <input type="text" name="extra[activity_code]" class="form-control" size="30" value="[% dt.get_extra_metadata('activity_code') | html %]"> +</p> +<p> + <strong>[% loc('Defect Code:') %] </strong> + <input type="text" name="extra[defect_code]" class="form-control" size="30" value="[% dt.get_extra_metadata('defect_code') | html %]"> +</p> diff --git a/templates/web/oxfordshire/defect_type/format.html b/templates/web/oxfordshire/defect_type/format.html new file mode 100644 index 000000000..9cbf2d873 --- /dev/null +++ b/templates/web/oxfordshire/defect_type/format.html @@ -0,0 +1,4 @@ +[% MACRO defect_type_format BLOCK ~%] +[%~ defect_type.get_extra_metadata('defect_code') | html %] - [% defect_type.get_extra_metadata('activity_code') | html %] +([% defect_type.name | html %]) +[%~ END %]
\ No newline at end of file diff --git a/web/cobrands/fixmystreet/admin.js b/web/cobrands/fixmystreet/admin.js index 02eb30766..f7fcaf276 100644 --- a/web/cobrands/fixmystreet/admin.js +++ b/web/cobrands/fixmystreet/admin.js @@ -48,6 +48,8 @@ $(function(){ } }); + $("select.js-multiple[multiple]").make_multi(); + // on a body's page, hide/show deleted contact categories var $table_with_deleted_contacts = $('table tr.is-deleted td.contact-category').closest('table'); if ($table_with_deleted_contacts.length == 1) { diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js index c09eeb803..e92395661 100644 --- a/web/cobrands/fixmystreet/fixmystreet.js +++ b/web/cobrands/fixmystreet/fixmystreet.js @@ -109,6 +109,20 @@ function isR2L() { $drawer.hide(); }); }); + }, + + make_multi: function() { + var $this = $(this), + all = $this.data('all'); + $this.multiSelect({ + allText: all, + noneText: all, + positionMenuWithin: $('#side'), + presets: [{ + name: all, + options: [] + }] + }); } }); @@ -535,23 +549,8 @@ $.extend(fixmystreet.set_up, { // to refresh the map when the filter inputs are changed. $(".report-list-filters [type=submit]").hide(); - function make_multi(id) { - var $id = $('#' + id), - all = $id.data('all'), - none = $id.data('none') || all, - allOpts = $id.data('allOptions') || []; - $id.multiSelect({ - allText: all, - noneText: none, - positionMenuWithin: $('#side'), - presets: [{ - name: all, - options: allOpts - }] - }); - } - make_multi('statuses'); - make_multi('filter_categories'); + $('#statuses').make_multi(); + $('#filter_categories').make_multi(); }, mobile_ui_tweaks: function() { |