diff options
author | Dave Arter <davea@mysociety.org> | 2016-09-09 14:26:00 +0100 |
---|---|---|
committer | Dave Arter <davea@mysociety.org> | 2016-09-09 14:26:00 +0100 |
commit | 2acf9eb59867c299da568bf77c9019fe6c3eb9ff (patch) | |
tree | 574fe83a0dcf2cba219d32f440f44cde1dbc3132 | |
parent | f8f870be0f9f648b48896cb6411446b7f9e049ce (diff) | |
parent | 54a2b63fac54d01914fd2bb456da483e6982ee21 (diff) |
Merge branch 'issues/forcouncils/66-priority-management'
19 files changed, 525 insertions, 88 deletions
diff --git a/bin/update-schema b/bin/update-schema index eb44e4dda..bb0360fb2 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 '0045' if table_exists('response_priorities'); return '0044' if table_exists('contact_response_templates'); return '0043' if column_exists('users', 'area_id'); return '0042' if table_exists('user_planned_reports'); diff --git a/db/downgrade_0045---0044.sql b/db/downgrade_0045---0044.sql new file mode 100644 index 000000000..7ab7ab6fd --- /dev/null +++ b/db/downgrade_0045---0044.sql @@ -0,0 +1,7 @@ +BEGIN; + +ALTER TABLE problem DROP COLUMN response_priority_id; +DROP TABLE contact_response_priorities; +DROP TABLE response_priorities; + +COMMIT; diff --git a/db/schema.sql b/db/schema.sql index c96059fb1..27f4bad13 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -127,6 +127,15 @@ create trigger contacts_update_trigger after update on contacts create trigger contacts_insert_trigger after insert on contacts for each row execute procedure contacts_updated(); +-- Problems can have priorities. This table must be created before problem. +CREATE TABLE response_priorities ( + id serial not null primary key, + body_id int references body(id) not null, + deleted boolean not null default 'f', + name text not null, + unique(body_id, name) +); + -- Problems reported by users of site create table problem ( id serial not null primary key, @@ -185,7 +194,8 @@ create table problem ( extra text, -- extra fields required for open311 flagged boolean not null default 'f', geocode bytea, - + response_priority_id int REFERENCES response_priorities(id), + -- logging sending failures (used by webservices) send_fail_count integer not null default 0, send_fail_reason text, @@ -482,3 +492,9 @@ CREATE TABLE contact_response_templates ( contact_id int REFERENCES contacts(id) NOT NULL, response_template_id int REFERENCES response_templates(id) NOT NULL ); + +CREATE TABLE contact_response_priorities ( + id serial NOT NULL PRIMARY KEY, + contact_id int REFERENCES contacts(id) NOT NULL, + response_priority_id int REFERENCES response_priorities(id) NOT NULL +); diff --git a/db/schema_0045-response-priorities.sql b/db/schema_0045-response-priorities.sql new file mode 100644 index 000000000..16215e40c --- /dev/null +++ b/db/schema_0045-response-priorities.sql @@ -0,0 +1,20 @@ +BEGIN; + +CREATE TABLE response_priorities ( + id serial not null primary key, + body_id int references body(id) not null, + name text not null, + deleted boolean not null default 'f', + unique(body_id, name) +); + +CREATE TABLE contact_response_priorities ( + id serial NOT NULL PRIMARY KEY, + contact_id int REFERENCES contacts(id) NOT NULL, + response_priority_id int REFERENCES response_priorities(id) NOT NULL +); + +ALTER TABLE problem + ADD COLUMN response_priority_id int REFERENCES response_priorities(id); + +COMMIT; diff --git a/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm b/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm new file mode 100644 index 000000000..f1110fbf0 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm @@ -0,0 +1,107 @@ +package FixMyStreet::App::Controller::Admin::ResponsePriorities; +use Moose; +use namespace::autoclean; + +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('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 @priorities = $c->stash->{body}->response_priorities->search( + undef, + { + order_by => 'name' + } + ); + + $c->stash->{response_priorities} = \@priorities; +} + +sub edit : Path : Args(2) { + my ( $self, $c, $body_id, $priority_id ) = @_; + + $c->forward('load_user_body', [ $body_id ]); + + my $priority; + if ($priority_id eq 'new') { + $priority = $c->stash->{body}->response_priorities->new({}); + } + else { + $priority = $c->stash->{body}->response_priorities->find( $priority_id ) + or $c->detach( '/page_error_404_not_found' ); + } + + $c->forward('/admin/fetch_contacts'); + my @contacts = $priority->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') { + $priority->deleted( $c->get_param('deleted') ? 1 : 0 ); + $priority->name( $c->get_param('name') ); + $priority->update_or_insert; + + my @live_contact_ids = map { $_->id } @live_contacts; + my @new_contact_ids = grep { $c->get_param("contacts[$_]") } @live_contact_ids; + $priority->contact_response_priorities->search({ + contact_id => { '!=' => \@new_contact_ids }, + })->delete; + foreach my $contact_id (@new_contact_ids) { + $priority->contact_response_priorities->find_or_create({ + contact_id => $contact_id, + }); + } + + $c->res->redirect( $c->uri_for( '', $c->stash->{body}->id ) ); + } + + $c->stash->{response_priority} = $priority; +} + +sub load_user_body : Private { + my ($self, $c, $body_id) = @_; + + my $has_permission = $c->user->has_body_permission_to('responsepriority_edit') && + $c->user->from_body->id eq $body_id; + + unless ( $c->user->is_superuser || $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/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 7f1132117..6a7a14b5c 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -307,21 +307,10 @@ sub inspect : Private { $c->stash->{categories} = $c->forward('/admin/categories_for_point'); - # The available priorities for this problem are dependent on the cobrand it - # was reported to, not necessarily the active cobrand (e.g. inspecting a - # report on fms.com that was sent to Oxfordshire), so make sure the correct - # priorities are available for selection. - if ( $c->cobrand->can('get_body_handler_for_problem') ) { - my $handler = $c->cobrand->get_body_handler_for_problem($c->stash->{problem}); - if ( $handler->can('problem_response_priorities') ) { - $c->stash->{priorities} = $handler->problem_response_priorities; - } - } - if ( $c->get_param('save') || $c->get_param('save_inspected') ) { $c->forward('/auth/check_csrf_token'); - foreach (qw/priority detailed_location detailed_information traffic_information/) { + foreach (qw/detailed_location detailed_information traffic_information/) { $problem->set_extra_metadata( $_ => $c->get_param($_) ); } @@ -342,6 +331,8 @@ sub inspect : Private { $c->forward( '/admin/log_edit', [ $id, 'problem', 'state_change' ] ); } + $problem->response_priority( $problem->response_priorities->find({ id => $c->get_param('priority') }) ); + my $valid = 1; if ( !$c->forward( '/admin/report_edit_location', [ $problem ] ) ) { # New lat/lon isn't valid, show an error diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index b5487ea5b..48484d4bb 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -646,10 +646,10 @@ sub admin_pages { 'summary' => [_('Summary'), 0], 'bodies' => [_('Bodies'), 1], 'reports' => [_('Reports'), 2], - 'timeline' => [_('Timeline'), 4], - 'users' => [_('Users'), 5], - 'flagged' => [_('Flagged'), 6], - 'stats' => [_('Stats'), 7], + 'timeline' => [_('Timeline'), 5], + 'users' => [_('Users'), 6], + 'flagged' => [_('Flagged'), 7], + 'stats' => [_('Stats'), 8], 'user_edit' => [undef, undef], 'body' => [undef, undef], 'report_edit' => [undef, undef], @@ -659,12 +659,16 @@ sub admin_pages { # There are some pages that only super users can see if ( $user->is_superuser ) { - $pages->{config} = [ _('Configuration'), 8]; + $pages->{config} = [ _('Configuration'), 9]; }; # And some that need special permissions if ( $user->is_superuser || $user->has_body_permission_to('template_edit') ) { - $pages->{templates} = [_('Templates'), 3], - $pages->{template_edit} = [undef, undef], + $pages->{templates} = [_('Templates'), 3]; + $pages->{template_edit} = [undef, undef]; + }; + if ( $user->is_superuser || $user->has_body_permission_to('responsepriority_edit') ) { + $pages->{responsepriorities} = [_('Priorities'), 4]; + $pages->{responsepriority_edit} = [undef, undef]; }; @@ -719,6 +723,7 @@ sub available_permissions { }, _("Bodies") => { template_edit => _("Add/edit response templates"), + responsepriority_edit => _("Add/edit response priorities"), }, }; } diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index f8079565d..989d6f622 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -99,15 +99,6 @@ sub problem_response_days { return undef; } -sub problem_response_priorities { - return { - cat1a => 'Cat 1A (4 hours)', - cat1b => 'Cat 1B (24 hours)', - cat2 => 'Cat 2 (2 days)', - cat3 => 'Cat 3 (10 days)', - }; -} - sub reports_ordering { return { -desc => 'confirmed' }; } diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm index a2e004c6a..037b69352 100644 --- a/perllib/FixMyStreet/DB/Result/Body.pm +++ b/perllib/FixMyStreet/DB/Result/Body.pm @@ -87,6 +87,12 @@ __PACKAGE__->belongs_to( }, ); __PACKAGE__->has_many( + "response_priorities", + "FixMyStreet::DB::Result::ResponsePriority", + { "foreign.body_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); +__PACKAGE__->has_many( "response_templates", "FixMyStreet::DB::Result::ResponseTemplate", { "foreign.body_id" => "self.id" }, @@ -106,8 +112,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2015-02-19 16:13:43 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:d6GuQm8vrNmCc4NWw58srA +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-06 15:33:04 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ZuzscnLqcx0k512cTZ/kdg sub url { my ( $self, $c, $args ) = @_; diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm index ea9b656aa..b37734e7a 100644 --- a/perllib/FixMyStreet/DB/Result/Contact.pm +++ b/perllib/FixMyStreet/DB/Result/Contact.pm @@ -11,29 +11,29 @@ use base 'DBIx::Class::Core'; __PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn"); __PACKAGE__->table("contacts"); __PACKAGE__->add_columns( - "id", - { - data_type => "integer", - is_auto_increment => 1, - is_nullable => 0, - sequence => "contacts_id_seq", - }, "body_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, - "category", - { data_type => "text", default_value => "Other", is_nullable => 0 }, "email", { data_type => "text", is_nullable => 0 }, - "confirmed", - { data_type => "boolean", is_nullable => 0 }, - "deleted", - { data_type => "boolean", is_nullable => 0 }, "editor", { data_type => "text", is_nullable => 0 }, "whenedited", { data_type => "timestamp", is_nullable => 0 }, "note", { data_type => "text", is_nullable => 0 }, + "confirmed", + { data_type => "boolean", is_nullable => 0 }, + "category", + { data_type => "text", default_value => "Other", is_nullable => 0 }, + "deleted", + { data_type => "boolean", is_nullable => 0 }, + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "contacts_id_seq", + }, "extra", { data_type => "text", is_nullable => 1 }, "non_public", @@ -56,6 +56,12 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->has_many( + "contact_response_priorities", + "FixMyStreet::DB::Result::ContactResponsePriority", + { "foreign.contact_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); +__PACKAGE__->has_many( "contact_response_templates", "FixMyStreet::DB::Result::ContactResponseTemplate", { "foreign.contact_id" => "self.id" }, @@ -63,8 +69,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-08-24 11:29:04 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CXUabm3Yd11OoIYJceSPag +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-06 15:33:04 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ocmQGeFJtO3wmvyx6W+EKQ __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); __PACKAGE__->rabx_column('extra'); @@ -75,6 +81,7 @@ use namespace::clean -except => [ 'meta' ]; 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' ); sub get_metadata_for_input { my $self = shift; diff --git a/perllib/FixMyStreet/DB/Result/ContactResponsePriority.pm b/perllib/FixMyStreet/DB/Result/ContactResponsePriority.pm new file mode 100644 index 000000000..d5afd75a7 --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/ContactResponsePriority.pm @@ -0,0 +1,46 @@ +use utf8; +package FixMyStreet::DB::Result::ContactResponsePriority; + +# 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_response_priorities"); +__PACKAGE__->add_columns( + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "contact_response_priorities_id_seq", + }, + "contact_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "response_priority_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( + "response_priority", + "FixMyStreet::DB::Result::ResponsePriority", + { id => "response_priority_id" }, + { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-06 15:33:04 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:kM/9jY1QSgakyPTvutS+hw + + +# 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/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 8236524d6..27648ddad 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -20,36 +20,14 @@ __PACKAGE__->add_columns( }, "postcode", { data_type => "text", is_nullable => 0 }, - "latitude", - { data_type => "double precision", is_nullable => 0 }, - "longitude", - { data_type => "double precision", is_nullable => 0 }, - "bodies_str", - { data_type => "text", is_nullable => 1 }, - "areas", - { data_type => "text", is_nullable => 0 }, - "category", - { data_type => "text", default_value => "Other", is_nullable => 0 }, "title", { data_type => "text", is_nullable => 0 }, "detail", { data_type => "text", is_nullable => 0 }, "photo", { data_type => "bytea", is_nullable => 1 }, - "used_map", - { data_type => "boolean", is_nullable => 0 }, - "user_id", - { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, "name", { data_type => "text", is_nullable => 0 }, - "anonymous", - { data_type => "boolean", is_nullable => 0 }, - "external_id", - { data_type => "text", is_nullable => 1 }, - "external_body", - { data_type => "text", is_nullable => 1 }, - "external_team", - { data_type => "text", is_nullable => 1 }, "created", { data_type => "timestamp", @@ -57,18 +35,22 @@ __PACKAGE__->add_columns( is_nullable => 0, original => { default_value => \"now()" }, }, - "confirmed", - { data_type => "timestamp", is_nullable => 1 }, "state", { data_type => "text", is_nullable => 0 }, - "lang", - { data_type => "text", default_value => "en-gb", is_nullable => 0 }, - "service", - { data_type => "text", default_value => "", is_nullable => 0 }, - "cobrand", - { data_type => "text", default_value => "", is_nullable => 0 }, - "cobrand_data", - { data_type => "text", default_value => "", is_nullable => 0 }, + "whensent", + { data_type => "timestamp", is_nullable => 1 }, + "used_map", + { data_type => "boolean", is_nullable => 0 }, + "bodies_str", + { data_type => "text", is_nullable => 1 }, + "anonymous", + { data_type => "boolean", is_nullable => 0 }, + "category", + { data_type => "text", default_value => "Other", is_nullable => 0 }, + "confirmed", + { data_type => "timestamp", is_nullable => 1 }, + "send_questionnaire", + { data_type => "boolean", default_value => \"true", is_nullable => 0 }, "lastupdate", { data_type => "timestamp", @@ -76,14 +58,32 @@ __PACKAGE__->add_columns( is_nullable => 0, original => { default_value => \"now()" }, }, - "whensent", - { data_type => "timestamp", is_nullable => 1 }, - "send_questionnaire", - { data_type => "boolean", default_value => \"true", is_nullable => 0 }, - "extra", + "areas", + { data_type => "text", is_nullable => 0 }, + "service", + { data_type => "text", default_value => "", is_nullable => 0 }, + "lang", + { data_type => "text", default_value => "en-gb", is_nullable => 0 }, + "cobrand", + { data_type => "text", default_value => "", is_nullable => 0 }, + "cobrand_data", + { data_type => "text", default_value => "", is_nullable => 0 }, + "latitude", + { data_type => "double precision", is_nullable => 0 }, + "longitude", + { data_type => "double precision", is_nullable => 0 }, + "external_id", + { data_type => "text", is_nullable => 1 }, + "external_body", { data_type => "text", is_nullable => 1 }, + "external_team", + { data_type => "text", is_nullable => 1 }, + "user_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, "flagged", { data_type => "boolean", default_value => \"false", is_nullable => 0 }, + "extra", + { data_type => "text", is_nullable => 1 }, "geocode", { data_type => "bytea", is_nullable => 1 }, "send_fail_count", @@ -106,6 +106,8 @@ __PACKAGE__->add_columns( { data_type => "text", is_nullable => 1 }, "bodies_missing", { data_type => "text", is_nullable => 1 }, + "response_priority_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->has_many( @@ -127,6 +129,17 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->belongs_to( + "response_priority", + "FixMyStreet::DB::Result::ResponsePriority", + { id => "response_priority_id" }, + { + is_deferrable => 0, + join_type => "LEFT", + on_delete => "NO ACTION", + on_update => "NO ACTION", + }, +); +__PACKAGE__->belongs_to( "user", "FixMyStreet::DB::Result::User", { id => "user_id" }, @@ -140,8 +153,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-07-20 15:00:41 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:PMOhd1uloLTAYovW/fxgSg +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-07 11:01:40 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:iH9c4VZZN/ONnhN6g89DFw # Add fake relationship to stored procedure table __PACKAGE__->has_one( @@ -656,6 +669,27 @@ sub response_templates { ); } +=head2 response_priorities + +Returns all ResponsePriorities attached to this problem's category/contact, in +alphabetical order of name. + +=cut + +sub response_priorities { + my $self = shift; + return $self->result_source->schema->resultset('ResponsePriority')->search( + { + 'me.body_id' => $self->bodies_str_ids, + 'contact.category' => $self->category, + }, + { + order_by => 'name', + join => { 'contact_response_priorities' => 'contact' }, + } + ); +} + # 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/Result/ResponsePriority.pm b/perllib/FixMyStreet/DB/Result/ResponsePriority.pm new file mode 100644 index 000000000..d312fbcea --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/ResponsePriority.pm @@ -0,0 +1,57 @@ +use utf8; +package FixMyStreet::DB::Result::ResponsePriority; + +# 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("response_priorities"); +__PACKAGE__->add_columns( + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "response_priorities_id_seq", + }, + "body_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "name", + { data_type => "text", is_nullable => 0 }, + "deleted", + { data_type => "boolean", default_value => \"false", is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("id"); +__PACKAGE__->add_unique_constraint("response_priorities_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_response_priorities", + "FixMyStreet::DB::Result::ContactResponsePriority", + { "foreign.response_priority_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); +__PACKAGE__->has_many( + "problems", + "FixMyStreet::DB::Result::Problem", + { "foreign.response_priority_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-07 11:01:40 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:B1swGtQzC3qRa0LUM4IyzA + +__PACKAGE__->many_to_many( contacts => 'contact_response_priorities', 'contact' ); + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index ee9631bdf..54c39ffb9 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -603,6 +603,7 @@ sub delete_body { $mech->delete_contact($_) for $body->contacts; $mech->delete_user($_) for $body->users; $_->delete for $body->response_templates; + $_->delete for $body->response_priorities; $body->body_areas->delete; $body->delete; } @@ -612,6 +613,7 @@ sub delete_contact { my $contact = shift; $contact->contact_response_templates->delete_all; + $contact->contact_response_priorities->delete_all; $contact->delete; } diff --git a/t/app/controller/admin.t b/t/app/controller/admin.t index f7dcd4023..61e8b21e4 100644 --- a/t/app/controller/admin.t +++ b/t/app/controller/admin.t @@ -1177,6 +1177,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, changes => { name => 'Changed User', @@ -1208,6 +1209,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, changes => { email => 'changed@example.com', @@ -1239,6 +1241,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, changes => { body => $southend->id, @@ -1270,6 +1273,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, changes => { flagged => 'on', @@ -1301,6 +1305,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, changes => { flagged => undef, @@ -1332,6 +1337,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, changes => { is_superuser => 'on', @@ -1351,6 +1357,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]", "permissions[user_assign_areas]", "permissions[template_edit]", + "permissions[responsepriority_edit]", ], log_count => 5, log_entries => [qw/edit edit edit edit edit/], @@ -1384,6 +1391,7 @@ FixMyStreet::override_config { "permissions[user_assign_body]" => undef, "permissions[user_assign_areas]" => undef, "permissions[template_edit]" => undef, + "permissions[responsepriority_edit]" => undef, }, log_count => 5, log_entries => [qw/edit edit edit edit edit/], @@ -1529,13 +1537,78 @@ subtest "response templates are included on page" => sub { }; }; +$mech->log_in_ok( $superuser->email ); + +subtest "response priorities can be added" => sub { + is $oxfordshire->response_priorities->count, 0, "No response priorities yet"; + $mech->get_ok( "/admin/responsepriorities/" . $oxfordshire->id . "/new" ); + + my $fields = { + name => "Cat 1A", + deleted => undef, + "contacts[".$oxfordshirecontact->id."]" => 1, + }; + $mech->submit_form_ok( { with_fields => $fields } ); + + is $oxfordshire->response_priorities->count, 1, "Response template was added to body"; + is $oxfordshirecontact->response_priorities->count, 1, "Response template was added to contact"; +}; + +subtest "response priorities can be listed" => sub { + $mech->get_ok( "/admin/responsepriorities/" . $oxfordshire->id ); + + $mech->content_contains( $oxfordshire->response_priorities->first->name ); +}; + +subtest "response priorities are limited by body" => sub { + my $bromleypriority = $bromley->response_priorities->create( { + deleted => 0, + name => "Bromley Cat 0", + } ); + + is $bromley->response_priorities->count, 1, "Response template was added to Bromley"; + is $oxfordshire->response_priorities->count, 1, "Response template wasn't added to Oxfordshire"; + + $mech->get_ok( "/admin/responsepriorities/" . $oxfordshire->id ); + $mech->content_lacks( $bromleypriority->name ); + + $mech->get_ok( "/admin/responsepriorities/" . $bromley->id ); + $mech->content_contains( $bromleypriority->name ); +}; + $mech->log_out_ok; +subtest "response priorities can't be viewed across councils" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'oxfordshire' ], + }, sub { + $oxfordshireuser->user_body_permissions->create({ + body => $oxfordshire, + permission_type => 'responsepriority_edit', + }); + $mech->log_in_ok( $oxfordshireuser->email ); + $mech->get_ok( "/admin/responsepriorities/" . $oxfordshire->id ); + $mech->content_contains( $oxfordshire->response_priorities->first->name ); + + + $mech->get( "/admin/responsepriorities/" . $bromley->id ); + ok !$mech->res->is_success(), "want a bad response"; + is $mech->res->code, 404, "got 404"; + + my $bromley_priority_id = $bromley->response_priorities->first->id; + $mech->get( "/admin/responsepriorities/" . $bromley->id . "/" . $bromley_priority_id ); + ok !$mech->res->is_success(), "want a bad response"; + is $mech->res->code, 404, "got 404"; + }; +}; + + $mech->delete_user( $user ); $mech->delete_user( $user2 ); $mech->delete_user( $user3 ); $mech->delete_user( $superuser ); $mech->delete_user( 'test4@example.com' ); $mech->delete_body( $oxfordshire ); +$mech->delete_body( $bromley ); done_testing(); diff --git a/templates/web/base/admin/responsepriorities/edit.html b/templates/web/base/admin/responsepriorities/edit.html new file mode 100644 index 000000000..b05ebfaf9 --- /dev/null +++ b/templates/web/base/admin/responsepriorities/edit.html @@ -0,0 +1,41 @@ +[% INCLUDE 'admin/header.html' title=tprintf(loc('Response Priority for %s'), body.name) -%] +[% rp = response_priority %] + +[% UNLESS rp.id %]<h3>[% loc('New priority') %]</h3>[% END %] + +<form method="post" + action="[% c.uri_for('', body.id, rp.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" size="30" value="[% rp.name | html %]"> + </p> + <p> + <strong>[% loc('Categories:') %]</strong> + <ul> + [% FOR contact IN contacts %] + <li> + <label> + <input type="checkbox" name="contacts[[% contact.id %]]" [% 'checked' IF contact.active %]/> + [% contact.category %] + </label> + </li> + [% END %] + </ul> + </p> + <p> + <label> + <input type="checkbox" name="deleted" id="deleted" value="1"[% ' checked' IF rp.deleted %]> + [% loc('Flag as deleted') %] + </label> + </p> + <p> + <input type="hidden" name="token" value="[% csrf_token %]" > + <input type="submit" name="Edit priorities" value="[% rp.id ? loc('Save changes') : loc('Create priority') %]" > + </p> +</form> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/admin/responsepriorities/index.html b/templates/web/base/admin/responsepriorities/index.html new file mode 100644 index 000000000..d8a79420d --- /dev/null +++ b/templates/web/base/admin/responsepriorities/index.html @@ -0,0 +1,11 @@ +[% INCLUDE 'admin/header.html' title=loc('Response Priorities') -%] + +<ul> + [% FOR body IN bodies %] + <li> + <a href="/admin/responsepriorities/[% body.id %]">[% body.name %]</a> + </li> + [% END %] +</ul> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/admin/responsepriorities/list.html b/templates/web/base/admin/responsepriorities/list.html new file mode 100644 index 000000000..b64941f86 --- /dev/null +++ b/templates/web/base/admin/responsepriorities/list.html @@ -0,0 +1,22 @@ +[% INCLUDE 'admin/header.html' title=tprintf(loc('Response Priorities for %s'), body.name) -%] + +<table> + <thead> + <tr> + <th> [% loc('Name') %] </th> + <th> </th> + </tr> + </thead> + <tbody> + [% FOR p IN response_priorities %] + <tr [% 'class="is-deleted"' IF p.deleted %]> + <td> [% p.name %] </td> + <td> <a href="/admin/responsepriorities/[% body.id %]/[% p.id %]" class="btn">[% loc('Edit') %]</a> </td> + </tr> + [% END %] + </tbody> +</table> + +<a href="[% c.uri_for('', body.id, 'new') %]" class="btn">[% loc('New priority') %]</a> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html index 188816ec1..891d94c43 100644 --- a/templates/web/base/report/_inspect.html +++ b/templates/web/base/report/_inspect.html @@ -10,9 +10,9 @@ <p class="right"> <label for="problem_priority">[% loc('Priority:') %]</label> <select name="priority" id="problem_priority"> - <option value="" [% 'selected' UNLESS problem.get_extra_metadata('priority') %]>-</option> - [% FOREACH priority IN priorities %] - <option value="[% priority.key %]" [% 'selected' IF problem.get_extra_metadata('priority') == priority.key %]>[% priority.value %]</option> + <option value="" [% 'selected' UNLESS problem.response_priority_id %]>-</option> + [% FOREACH priority IN problem.response_priorities %] + <option value="[% priority.id %]" [% 'selected' IF problem.response_priority_id == priority.id %] [% 'disabled' IF priority.deleted %]>[% priority.name %]</option> [% END %] </select> </p> |