diff options
40 files changed, 760 insertions, 335 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d9326b2b4..991ad63ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Unreleased - New features: - Body and category names can now be translated in the admin. #1244 + - Report states can be edited and translated in the admin. #1826 - Body users can now create reports as an anonymous user. #1796 - Extra fields can be added to report form site-wide. #1743 - Body users can filter reports by all states. #1790 diff --git a/bin/fixmystreet.com/fixture b/bin/fixmystreet.com/fixture index 6df675f7c..6cf5ad199 100755 --- a/bin/fixmystreet.com/fixture +++ b/bin/fixmystreet.com/fixture @@ -54,7 +54,7 @@ BEGIN END $func$; }) or die $!; - $db->dbh->do( scalar FixMyStreet->path_to('db/alert_types.sql')->slurp ) or die $!; + $db->dbh->do( scalar FixMyStreet->path_to('db/fixture.sql')->slurp ) or die $!; $db->dbh->do( scalar FixMyStreet->path_to('db/generate_secret.sql')->slurp ) or die $!; say "Emptied database"; } diff --git a/bin/update-schema b/bin/update-schema index 32c00ff5e..a27bbbba1 100755 --- a/bin/update-schema +++ b/bin/update-schema @@ -40,6 +40,7 @@ BEGIN { } use FixMyStreet; +use FixMyStreet::Cobrand; use FixMyStreet::DB; use mySociety::MaPit; use Getopt::Long; @@ -112,7 +113,7 @@ if ($upgrade && $current_version eq 'EMPTY') { if ($commit) { run_statements(get_statements("$bin_dir/../db/schema.sql")); run_statements(get_statements("$bin_dir/../db/generate_secret.sql")); - run_statements(get_statements("$bin_dir/../db/alert_types.sql")); + run_statements(get_statements("$bin_dir/../db/fixture.sql")); } } elsif ($upgrade) { if ($version) { @@ -139,12 +140,28 @@ if ($upgrade && $current_version eq 'EMPTY') { my $area_ids = $db->dbh->selectcol_arrayref('SELECT area_id FROM body_areas'); if ( @$area_ids ) { my $areas = mySociety::MaPit::call('areas', $area_ids); + $db->txn_begin; foreach (values %$areas) { $db->dbh->do('UPDATE body SET name=? WHERE id=?', {}, $_->{name}, $_->{id}); } $db->txn_commit; } } + + if ( $commit && $current_version lt '0054' ) { + $nothing = 0; + print "States created, importing names\n"; + my @avail = FixMyStreet::Cobrand->available_cobrand_classes; + # Pick first available cobrand and language for database name import + my $cobrand = $avail[0] ? FixMyStreet::Cobrand::class($avail[0]) : 'FixMyStreet::Cobrand::Default'; + my $lang = $cobrand->new->set_lang_and_domain(undef, 1, FixMyStreet->path_to('locale')->stringify); + my $names = $db->dbh->selectcol_arrayref('SELECT name FROM state'); + $db->txn_begin; + foreach (@$names) { + $db->dbh->do('UPDATE state SET name=? WHERE name=?', {}, _($_), $_); + } + $db->txn_commit; + } } if ($downgrade) { @@ -195,6 +212,7 @@ else { # (assuming schema change files are never half-applied, which should be the case) sub get_db_version { return 'EMPTY' if ! table_exists('problem'); + return '0054' if table_exists('state'); return '0053' if table_exists('report_extra_fields'); return '0052' if table_exists('translation'); return '0051' if column_exists('contacts', 'state'); diff --git a/db/downgrade_0054---0053.sql b/db/downgrade_0054---0053.sql new file mode 100644 index 000000000..6fcc41c33 --- /dev/null +++ b/db/downgrade_0054---0053.sql @@ -0,0 +1,39 @@ +BEGIN; + +DROP TABLE state; + +ALTER TABLE problem ADD CONSTRAINT problem_state_check CHECK ( + state = 'unconfirmed' + or state = 'hidden' + or state = 'partial' + or state = 'confirmed' + or state = 'investigating' + or state = 'planned' + or state = 'in progress' + or state = 'action scheduled' + or state = 'fixed' + or state = 'fixed - council' + or state = 'fixed - user' + or state = 'closed' + or state = 'unable to fix' + or state = 'not responsible' + or state = 'duplicate' + or state = 'internal referral' +); +ALTER TABLE comment ADD CONSTRAINT comment_problem_state_check CHECK ( + problem_state = 'confirmed' + or problem_state = 'investigating' + or problem_state = 'planned' + or problem_state = 'in progress' + or problem_state = 'action scheduled' + or problem_state = 'fixed' + or problem_state = 'fixed - council' + or problem_state = 'fixed - user' + or problem_state = 'closed' + or problem_state = 'unable to fix' + or problem_state = 'not responsible' + or problem_state = 'duplicate' + or problem_state = 'internal referral' +); + +COMMIT; diff --git a/db/alert_types.sql b/db/fixture.sql index 471fd905f..840906223 100644 --- a/db/alert_types.sql +++ b/db/fixture.sql @@ -1,3 +1,13 @@ +INSERT INTO state (label, type, name) VALUES ('investigating', 'open', 'Investigating'); +INSERT INTO state (label, type, name) VALUES ('in progress', 'open', 'In progress'); +INSERT INTO state (label, type, name) VALUES ('planned', 'open', 'Planned'); +INSERT INTO state (label, type, name) VALUES ('action scheduled', 'open', 'Action scheduled'); +INSERT INTO state (label, type, name) VALUES ('unable to fix', 'closed', 'No further action'); +INSERT INTO state (label, type, name) VALUES ('not responsible', 'closed', 'Not responsible'); +INSERT INTO state (label, type, name) VALUES ('duplicate', 'closed', 'Duplicate'); +INSERT INTO state (label, type, name) VALUES ('internal referral', 'closed', 'Internal referral'); +INSERT INTO state (label, type, name) VALUES ('fixed', 'fixed', 'Fixed'); + -- New updates on a particular problem report insert into alert_type (ref, head_sql_query, head_table, @@ -18,11 +28,8 @@ insert into alert_type values ('new_problems', '', '', 'New problems on FixMyStreet', '/', 'The latest problems reported by users', 'problem', - 'problem.non_public = ''f'' and problem.state in - (''confirmed'', ''investigating'', ''planned'', ''in progress'', - ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'' - ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'', - ''internal referral'' )', + 'problem.non_public = ''f'' and problem.state NOT IN + (''unconfirmed'', ''hidden'', ''partial'')', 'created desc', '{{title}}, {{confirmed}}', '/report/{{id}}', '{{detail}}', 'alert-problem'); @@ -46,11 +53,8 @@ insert into alert_type values ('local_problems', '', '', 'New local problems on FixMyStreet', '/', 'The latest local problems reported by users', 'problem_find_nearby(?, ?, ?) as nearby,problem', - 'nearby.problem_id = problem.id and problem.non_public = ''f'' and problem.state in - (''confirmed'', ''investigating'', ''planned'', ''in progress'', - ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', - ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'', - ''internal referral'')', + 'nearby.problem_id = problem.id and problem.non_public = ''f'' and problem.state NOT IN + (''unconfirmed'', ''hidden'', ''partial'')', 'created desc', '{{title}}, {{confirmed}}', '/report/{{id}}', '{{detail}}', 'alert-problem-nearby'); @@ -74,11 +78,8 @@ insert into alert_type values ('postcode_local_problems', '', '', 'New problems near {{POSTCODE}} on FixMyStreet', '/', 'The latest local problems reported by users', 'problem_find_nearby(?, ?, ?) as nearby,problem', - 'nearby.problem_id = problem.id and problem.non_public = ''f'' and problem.state in - (''confirmed'', ''investigating'', ''planned'', ''in progress'', - ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', - ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'', - ''internal referral'')', + 'nearby.problem_id = problem.id and problem.non_public = ''f'' and problem.state NOT IN + (''unconfirmed'', ''hidden'', ''partial'')', 'created desc', '{{title}}, {{confirmed}}', '/report/{{id}}', '{{detail}}', 'alert-problem-nearby'); @@ -102,11 +103,8 @@ insert into alert_type values ('council_problems', '', '', 'New problems to {{COUNCIL}} on FixMyStreet', '/reports', 'The latest problems for {{COUNCIL}} reported by users', 'problem', - 'problem.non_public = ''f'' and problem.state in - (''confirmed'', ''investigating'', ''planned'', ''in progress'', - ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', - ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'', - ''internal referral'' ) AND + 'problem.non_public = ''f'' and problem.state NOT IN + (''unconfirmed'', ''hidden'', ''partial'') AND regexp_split_to_array(bodies_str, '','') && ARRAY[?]', 'created desc', '{{title}}, {{confirmed}}', '/report/{{id}}', '{{detail}}', 'alert-problem-council' @@ -122,11 +120,8 @@ values ('ward_problems', '', '', 'New problems for {{COUNCIL}} within {{WARD}} ward on FixMyStreet', '/reports', 'The latest problems for {{COUNCIL}} within {{WARD}} ward reported by users', 'problem', - 'problem.non_public = ''f'' and problem.state in - (''confirmed'', ''investigating'', ''planned'', ''in progress'', - ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', - ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'', - ''internal referral'' ) AND + 'problem.non_public = ''f'' and problem.state NOT IN + (''unconfirmed'', ''hidden'', ''partial'') AND (regexp_split_to_array(bodies_str, '','') && ARRAY[?] or bodies_str is null) and areas like ''%,''||?||'',%''', 'created desc', @@ -142,11 +137,8 @@ insert into alert_type values ('area_problems', '', '', 'New problems within {{NAME}}''s boundary on FixMyStreet', '/reports', 'The latest problems within {{NAME}}''s boundary reported by users', 'problem', - 'problem.non_public = ''f'' and problem.state in - (''confirmed'', ''investigating'', ''planned'', ''in progress'', - ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', - ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'', - ''internal referral'' ) AND + 'problem.non_public = ''f'' and problem.state NOT IN + (''unconfirmed'', ''hidden'', ''partial'') AND areas like ''%,''||?||'',%''', 'created desc', '{{title}}, {{confirmed}}', '/report/{{id}}', '{{detail}}', 'alert-problem-area' diff --git a/db/schema.sql b/db/schema.sql index ed930a13e..fedab2b9d 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -177,24 +177,7 @@ create table problem ( -- Metadata created timestamp not null default current_timestamp, confirmed timestamp, - state text not null check ( - state = 'unconfirmed' - or state = 'confirmed' - or state = 'investigating' - or state = 'planned' - or state = 'in progress' - or state = 'action scheduled' - or state = 'closed' - or state = 'fixed' - or state = 'fixed - council' - or state = 'fixed - user' - or state = 'hidden' - or state = 'partial' - or state = 'unable to fix' - or state = 'not responsible' - or state = 'duplicate' - or state = 'internal referral' - ), + state text not null, lang text not null default 'en-gb', service text not null default '', cobrand text not null default '' check (cobrand ~* '^[a-z0-9_]*$'), @@ -327,21 +310,7 @@ create table comment ( cobrand_data text not null default '' check (cobrand_data ~* '^[a-z0-9_]*$'), -- Extra data used in cobranded versions of the site mark_fixed boolean not null, mark_open boolean not null default 'f', - problem_state text check ( - problem_state = 'confirmed' - or problem_state = 'investigating' - or problem_state = 'planned' - or problem_state = 'in progress' - or problem_state = 'action scheduled' - or problem_state = 'closed' - or problem_state = 'fixed' - or problem_state = 'fixed - council' - or problem_state = 'fixed - user' - or problem_state = 'unable to fix' - or problem_state = 'not responsible' - or problem_state = 'duplicate' - or problem_state = 'internal referral' - ), + problem_state text, -- other fields? one to indicate whether this was written by the council -- and should be highlighted in the display? external_id text, @@ -546,3 +515,10 @@ CREATE TABLE report_extra_fields ( language text, extra text ); + +CREATE TABLE state ( + id serial not null primary key, + label text not null unique, + type text not null check (type = 'open' OR type = 'closed' OR type = 'fixed'), + name text not null unique +); diff --git a/db/schema_0054-add-state-table.sql b/db/schema_0054-add-state-table.sql new file mode 100644 index 000000000..c4be36015 --- /dev/null +++ b/db/schema_0054-add-state-table.sql @@ -0,0 +1,51 @@ +BEGIN; + +CREATE TABLE state ( + id serial not null primary key, + label text not null unique, + type text not null check (type = 'open' OR type = 'closed' OR type = 'fixed'), + name text not null unique +); + +INSERT INTO state (label, type, name) VALUES ('investigating', 'open', 'Investigating'); +INSERT INTO state (label, type, name) VALUES ('in progress', 'open', 'In progress'); +INSERT INTO state (label, type, name) VALUES ('planned', 'open', 'Planned'); +INSERT INTO state (label, type, name) VALUES ('action scheduled', 'open', 'Action scheduled'); +INSERT INTO state (label, type, name) VALUES ('unable to fix', 'closed', 'No further action'); +INSERT INTO state (label, type, name) VALUES ('not responsible', 'closed', 'Not responsible'); +INSERT INTO state (label, type, name) VALUES ('duplicate', 'closed', 'Duplicate'); +INSERT INTO state (label, type, name) VALUES ('internal referral', 'closed', 'Internal referral'); +INSERT INTO state (label, type, name) VALUES ('fixed', 'fixed', 'Fixed'); + +ALTER TABLE problem DROP CONSTRAINT problem_state_check; +ALTER TABLE comment DROP CONSTRAINT comment_problem_state_check; + +UPDATE alert_type SET item_where = 'nearby.problem_id = problem.id + and problem.non_public = ''f'' + and problem.state NOT IN (''hidden'', ''unconfirmed'', ''partial'')' + WHERE ref = 'postcode_local_problems'; +UPDATE alert_type set item_where = 'problem.non_public = ''f'' + and problem.state NOT IN (''hidden'', ''unconfirmed'', ''partial'')' + WHERE ref = 'new_problems'; +UPDATE alert_type set item_where = 'problem.non_public = ''f'' + and problem.state in (''fixed'', ''fixed - user'', ''fixed - council'')' + WHERE ref = 'new_fixed_problems'; +UPDATE alert_type set item_where = 'nearby.problem_id = problem.id + and problem.non_public = ''f'' + and problem.state NOT IN (''hidden'', ''unconfirmed'', ''partial'')' + WHERE ref = 'local_problems'; +UPDATE alert_type set item_where = 'problem.non_public = ''f'' + AND problem.state NOT IN (''hidden'', ''unconfirmed'', ''partial'') + AND regexp_split_to_array(bodies_str, '','') && ARRAY[?]' + WHERE ref = 'council_problems'; +UPDATE alert_type set item_where = 'problem.non_public = ''f'' + AND problem.state NOT IN (''hidden'', ''unconfirmed'', ''partial'') + AND (regexp_split_to_array(bodies_str, '','') && ARRAY[?] or bodies_str is null) and + areas like ''%,''||?||'',%''' + WHERE ref = 'ward_problems'; +UPDATE alert_type set item_where = 'problem.non_public = ''f'' + AND problem.state NOT IN (''hidden'', ''unconfirmed'', ''partial'') + AND areas like ''%,''||?||'',%''' + WHERE ref = 'area_problems'; + +COMMIT; diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm index 25d3d744e..a09f86f85 100644 --- a/perllib/FixMyStreet/App.pm +++ b/perllib/FixMyStreet/App.pm @@ -218,6 +218,7 @@ sub setup_request { mySociety::MaPit::configure( "http://$host/fakemapit/" ); } + $c->stash->{has_fixed_state} = FixMyStreet::DB::Result::Problem::fixed_states->{fixed}; $c->cobrand->call_hook('setup_states'); if (FixMyStreet->test_mode) { diff --git a/perllib/FixMyStreet/App/Controller/Admin/States.pm b/perllib/FixMyStreet/App/Controller/Admin/States.pm new file mode 100644 index 000000000..e4c07c9ca --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Admin/States.pm @@ -0,0 +1,102 @@ +package FixMyStreet::App::Controller::Admin::States; +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 ) = @_; + + $c->forward('/auth/get_csrf_token'); + $c->forward('/admin/fetch_languages'); + my $rs = $c->model('DB::State'); + + if ($c->req->method eq 'POST') { + $c->forward('/auth/check_csrf_token'); + + $c->forward('process_new') + && $c->forward('delete') + && $c->forward('update'); + + $rs->clear; + } + + $c->stash->{open_states} = $rs->open; + $c->stash->{closed_states} = $rs->closed; + $c->stash->{fixed_states} = $rs->fixed; +} + +sub process_new : Private { + my ($self, $c) = @_; + if ($c->get_param('new_fixed')) { + $c->model('DB::State')->create({ + label => 'fixed', + type => 'fixed', + name => _('Fixed'), + }); + return 0; + } + return 1 unless $c->get_param('new'); + my %params = map { $_ => $c->get_param($_) } qw/label type name/; + $c->model('DB::State')->create(\%params); + return 0; +} + +sub delete : Private { + my ($self, $c) = @_; + + my @params = keys %{ $c->req->params }; + my ($to_delete) = map { /^delete:(.*)/ } grep { /^delete:/ } @params; + if ($to_delete) { + $c->model('DB::State')->search({ label => $to_delete })->delete; + return 0; + } + return 1; +} + +sub update : Private { + my ($self, $c) = @_; + + my $rs = $c->model('DB::State'); + my %db_states = map { $_->label => $_ } @{$rs->states}; + my @params = keys %{ $c->req->params }; + my @states = map { /^type:(.*)/ } grep { /^type:/ } @params; + + foreach my $state (@states) { + # If there is only one language, we still store confirmed/closed + # as translations, as that seems a sensible place to store them. + if ($state eq 'confirmed' or $state eq 'closed') { + if (my $name = $c->get_param("name:$state")) { + my ($lang) = keys %{$c->stash->{languages}}; + $db_states{$state}->add_translation_for('name', $lang, $name); + } + } else { + $db_states{$state}->update({ + type => $c->get_param("type:$state"), + name => $c->get_param("name:$state"), + }); + } + + foreach my $lang (keys(%{$c->stash->{languages}})) { + my $id = $c->get_param("translation_id:$state:$lang"); + my $text = $c->get_param("translation:$state:$lang"); + if ($text) { + $db_states{$state}->add_translation_for('name', $lang, $text); + } elsif ($id) { + $c->model('DB::Translation')->find({ id => $id })->delete; + } + } + } + + return 1; +} + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm index fbe5a2dc9..f3989e760 100644 --- a/perllib/FixMyStreet/App/Controller/Dashboard.pm +++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm @@ -24,6 +24,8 @@ sub example : Local : Args(0) { my ( $self, $c ) = @_; $c->stash->{template} = 'dashboard/index.html'; + $c->stash->{filter_states} = $c->cobrand->state_groups_inspect; + $c->stash->{children} = {}; for my $i (1..3) { $c->stash->{children}{$i} = { id => $i, name => "Ward $i" }; @@ -93,6 +95,7 @@ sub index : Path : Args(0) { $c->stash->{body} = $body; # Set up the data for the dropdowns + $c->stash->{filter_states} = $c->cobrand->state_groups_inspect; # Just take the first area ID we find my $area_id = $body->body_areas->first->area_id; @@ -145,12 +148,10 @@ sub index : Path : Args(0) { # List of reports underneath summary table $c->stash->{q_state} = $c->get_param('state') || ''; - if ( $c->stash->{q_state} eq 'fixed' ) { + if ( $c->stash->{q_state} eq 'fixed - council' ) { $prob_where->{'me.state'} = [ FixMyStreet::DB::Result::Problem->fixed_states() ]; } elsif ( $c->stash->{q_state} ) { $prob_where->{'me.state'} = $c->stash->{q_state}; - $prob_where->{'me.state'} = { IN => [ 'planned', 'action scheduled' ] } - if $prob_where->{'me.state'} eq 'action scheduled'; } my $params = { %$prob_where, diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index b597cb7a8..8f8205719 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -558,12 +558,11 @@ sub stash_report_filter_status : Private { if ($c->user and ($c->user->is_superuser or ( $c->stash->{body} and $c->user->belongs_to_body($c->stash->{body}->id) ))) { + $c->stash->{filter_states} = $c->cobrand->state_groups_inspect; foreach my $state (FixMyStreet::DB::Result::Problem->visible_states()) { if ($status{$state}) { - %filter_problem_states = (%filter_problem_states, ($state => 1)); - my $pretty_state = $state; - $pretty_state =~ tr/ /_/; - $filter_status{$pretty_state} = 1; + $filter_problem_states{$state} = 1; + $filter_status{$state} = 1; } } } diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm index 93c459e26..93aa0e2fb 100644 --- a/perllib/FixMyStreet/App/View/Web.pm +++ b/perllib/FixMyStreet/App/View/Web.pm @@ -170,12 +170,8 @@ sub decode { sub prettify_state { my ($self, $c, $text, $single_fixed) = @_; - # New template to prevent interaction with current one - my $tt = FixMyStreet::Template->new({ INCLUDE_PATH => $self->{include_path} }); - my $var; - $tt->process('report/state-list.html', { state => $text }, \$var); - $var =~ s/ - .*// if $single_fixed; - return $var; + + return FixMyStreet::DB->resultset("State")->display($text, $single_fixed); } 1; diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index 5dcdc9a4b..250919d09 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -179,7 +179,7 @@ sub restriction { return $self->moniker ? { cobrand => $self->moniker } : {}; } -=head2 base_url_with_lang +=head2 base_url_with_lang =cut @@ -358,7 +358,7 @@ sub front_stats_data { Returns any disambiguating information available. Defaults to none. -=cut +=cut sub disambiguate_location { FixMyStreet->config('GEOCODING_DISAMBIGUATION') or {}; } @@ -642,6 +642,7 @@ sub admin_pages { # There are some pages that only super users can see if ( $user->is_superuser ) { $pages->{flagged} = [ _('Flagged'), 7 ]; + $pages->{states} = [ _('States'), 8 ]; $pages->{config} = [ _('Configuration'), 9]; }; # And some that need special permissions @@ -820,7 +821,7 @@ sub is_two_tier { 0; } =item council_rss_alert_options -Generate a set of options for council rss alerts. +Generate a set of options for council rss alerts. =cut @@ -1066,6 +1067,28 @@ sub show_unconfirmed_reports { 0; } +sub state_groups_admin { + my $rs = FixMyStreet::DB->resultset("State"); + my @fixed = FixMyStreet::DB::Result::Problem->fixed_states; + [ + [ $rs->display('confirmed'), [ FixMyStreet::DB::Result::Problem->open_states ] ], + @fixed ? [ $rs->display('fixed'), [ FixMyStreet::DB::Result::Problem->fixed_states ] ] : (), + [ $rs->display('closed'), [ FixMyStreet::DB::Result::Problem->closed_states ] ], + [ $rs->display('hidden'), [ FixMyStreet::DB::Result::Problem->hidden_states ] ] + ] +} + +sub state_groups_inspect { + my $rs = FixMyStreet::DB->resultset("State"); + my @fixed = FixMyStreet::DB::Result::Problem->fixed_states; + [ + [ $rs->display('confirmed'), [ grep { $_ ne 'planned' } FixMyStreet::DB::Result::Problem->open_states ] ], + @fixed ? [ $rs->display('fixed'), [ 'fixed - council' ] ] : (), + [ $rs->display('closed'), [ grep { $_ ne 'closed' } FixMyStreet::DB::Result::Problem->closed_states ] ], + [ $rs->display('hidden'), [ 'hidden' ] ] + ] +} + =head2 never_confirm_updates If true then we never send an email to confirm an update diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index a061ff46c..b3d6b28c3 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -122,12 +122,19 @@ sub path_to_pin_icons { sub pin_hover_title { my ($self, $problem, $title) = @_; - my $state = $self->{c}->render_fragment( - 'report/state-list.html', - { state => $problem->state }); + my $state = FixMyStreet::DB->resultset("State")->display($problem->state, 1); return "$state: $title"; } +sub state_groups_inspect { + [ + [ _('New'), [ 'confirmed', 'investigating' ] ], + [ _('Scheduled'), [ 'action scheduled' ] ], + [ _('Fixed'), [ 'fixed - council' ] ], + [ _('Closed'), [ 'not responsible', 'duplicate', 'unable to fix' ] ], + ] +} + sub open311_config { my ($self, $row, $h, $params) = @_; diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm index d688eb8b9..562f29693 100644 --- a/perllib/FixMyStreet/DB/Result/Comment.pm +++ b/perllib/FixMyStreet/DB/Result/Comment.pm @@ -227,8 +227,6 @@ sub meta_line { my $meta = ''; - $c->stash->{last_state} ||= ''; - if ($self->anonymous or !$self->name) { $meta = sprintf( _( 'Posted anonymously at %s' ), Utils::prettify_dt( $self->confirmed ) ) } elsif ($self->user->from_body) { @@ -257,60 +255,36 @@ sub meta_line { $meta = sprintf( _( 'Posted by %s at %s' ), FixMyStreet::Template::html_filter($self->name), Utils::prettify_dt( $self->confirmed ) ) } + if ($self->get_extra_metadata('defect_raised')) { + $meta .= ', ' . _( 'and a defect raised' ); + } + + return $meta; +}; + +sub problem_state_display { + my ( $self, $c ) = @_; + my $update_state = ''; + my $cobrand = $c->cobrand->moniker; if ($self->mark_fixed) { - $update_state = _( 'marked as fixed' ); + return FixMyStreet::DB->resultset("State")->display('fixed', 1); } elsif ($self->mark_open) { - $update_state = _( 'reopened' ); + return FixMyStreet::DB->resultset("State")->display('confirmed', 1); } elsif ($self->problem_state) { my $state = $self->problem_state; - - if ($state eq 'confirmed') { - if ($c->stash->{last_state}) { - $update_state = _( 'reopened' ) - } - } elsif ($state eq 'investigating') { - $update_state = _( 'marked as investigating' ) - } elsif ($state eq 'planned') { - $update_state = _( 'marked as planned' ) - } elsif ($state eq 'in progress') { - $update_state = _( 'marked as in progress' ) - } elsif ($state eq 'action scheduled') { - $update_state = _( 'marked as action scheduled' ) - } elsif ($state eq 'closed') { - $update_state = _( 'marked as closed' ) - } elsif ($state =~ /^fixed/) { - $update_state = _( 'marked as fixed' ) - } elsif ($state eq 'unable to fix') { - $update_state = _( 'marked as no further action' ) - } elsif ($state eq 'not responsible') { - $update_state = _( "marked as not the council's responsibility" ) - } elsif ($state eq 'duplicate') { - $update_state = _( 'closed as a duplicate report' ) - } elsif ($state eq 'internal referral') { - $update_state = _( 'marked as an internal referral' ) - } - - if ($c->cobrand->moniker eq 'bromley' || $self->problem->to_body_named('Bromley')) { - if ($state eq 'not responsible') { - $update_state = 'marked as third party responsibility' + if ($state eq 'not responsible') { + $update_state = _( "not the council's responsibility" ); + if ($cobrand eq 'bromley' || $self->problem->to_body_named('Bromley')) { + $update_state = 'third party responsibility'; } + } else { + $update_state = FixMyStreet::DB->resultset("State")->display($state, 1); } - } - if ($update_state ne $c->stash->{last_state} and $update_state) { - $meta .= ", $update_state"; - } - - if ($self->get_extra_metadata('defect_raised')) { - $meta .= ', ' . _( 'and a defect raised' ); - } - - $c->stash->{last_state} = $update_state; - - return $meta; -}; + return $update_state; +} 1; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 51805fa51..77190679b 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -220,15 +220,8 @@ HASHREF. =cut sub open_states { - my $states = { - 'confirmed' => 1, - 'investigating' => 1, - 'in progress' => 1, - 'planned' => 1, - 'action scheduled' => 1, - }; - - return wantarray ? keys %{$states} : $states; + my @states = map { $_->label } @{FixMyStreet::DB->resultset("State")->open}; + return wantarray ? @states : { map { $_ => 1 } @states }; } =head2 @@ -242,13 +235,9 @@ HASHREF. =cut sub fixed_states { - my $states = { - 'fixed' => 1, - 'fixed - user' => 1, - 'fixed - council' => 1, - }; - - return wantarray ? keys %{ $states } : $states; + my @states = map { $_->label } @{FixMyStreet::DB->resultset("State")->fixed}; + push @states, 'fixed - user', 'fixed - council' if @states; + return wantarray ? @states : { map { $_ => 1 } @states }; } =head2 @@ -262,18 +251,10 @@ HASHREF. =cut sub closed_states { - my $states = { - 'closed' => 1, - 'unable to fix' => 1, - 'not responsible' => 1, - 'duplicate' => 1, - 'internal referral' => 1, - }; - - return wantarray ? keys %{$states} : $states; + my @states = map { $_->label } @{FixMyStreet::DB->resultset("State")->closed}; + return wantarray ? @states : { map { $_ => 1 } @states }; } - =head2 @states = FixMyStreet::DB::Problem::all_states(); @@ -289,21 +270,10 @@ sub all_states { 'hidden' => 1, 'partial' => 1, 'unconfirmed' => 1, - 'confirmed' => 1, - 'investigating' => 1, - 'in progress' => 1, - 'planned' => 1, - 'action scheduled' => 1, - 'fixed' => 1, 'fixed - council' => 1, 'fixed - user' => 1, - 'unable to fix' => 1, - 'not responsible' => 1, - 'duplicate' => 1, - 'closed' => 1, - 'internal referral' => 1, }; - + map { $states->{$_->label} = 1 } @{FixMyStreet::DB->resultset("State")->states}; return wantarray ? keys %{$states} : $states; } diff --git a/perllib/FixMyStreet/DB/Result/State.pm b/perllib/FixMyStreet/DB/Result/State.pm new file mode 100644 index 000000000..b8a35d42b --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/State.pm @@ -0,0 +1,48 @@ +use utf8; +package FixMyStreet::DB::Result::State; + +# 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("state"); +__PACKAGE__->add_columns( + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "state_id_seq", + }, + "label", + { data_type => "text", is_nullable => 0 }, + "type", + { data_type => "text", is_nullable => 0 }, + "name", + { data_type => "text", is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("id"); +__PACKAGE__->add_unique_constraint("state_label_key", ["label"]); +__PACKAGE__->add_unique_constraint("state_name_key", ["name"]); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-08-22 15:17:43 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dvtAOpeYqEF9T3otHHgLqw + +use Moo; +use namespace::clean; + +with 'FixMyStreet::Roles::Translatable'; + +sub msgstr { + my $self = shift; + my $lang = $self->result_source->schema->lang; + return $self->name unless $lang && $self->translated->{name}{$lang}; + return $self->translated->{name}{$lang}{msgstr}; +} + +1; diff --git a/perllib/FixMyStreet/DB/ResultSet/State.pm b/perllib/FixMyStreet/DB/ResultSet/State.pm new file mode 100644 index 000000000..8b6a8963e --- /dev/null +++ b/perllib/FixMyStreet/DB/ResultSet/State.pm @@ -0,0 +1,78 @@ +package FixMyStreet::DB::ResultSet::State; +use base 'DBIx::Class::ResultSet'; + +use strict; +use warnings; +use Memcached; + +sub _hardcoded_states { + my $rs = shift; + my $open = $rs->new({ id => -1, label => 'confirmed', type => 'open', name => _("Open") }); + my $closed = $rs->new({ id => -2, label => 'closed', type => 'closed', name => _("Closed") }); + return ($open, $closed); +} + +# As states will change rarely, and then only through the admin, +# we cache these in the package on first use, and clear on update. + +sub clear { + Memcached::set('states', ''); +} + +sub states { + my $rs = shift; + + my $states = Memcached::get('states'); + if ($states && !FixMyStreet->test_mode) { + # Need to reattach schema + $states->[0]->result_source->schema( $rs->result_source->schema ) if $states->[0]; + return $states; + } + + # Pick up and cache any translations + my $q = $rs->result_source->schema->resultset("Translation")->search({ + tbl => 'state', + col => 'name', + }); + my %trans; + $trans{$_->object_id}{$_->lang} = { id => $_->id, msgstr => $_->msgstr } foreach $q->all; + + my @states = ($rs->_hardcoded_states, $rs->search(undef, { order_by => 'label' })->all); + $_->translated->{name} = $trans{$_->id} || {} foreach @states; + $states = \@states; + Memcached::set('states', $states); + return $states; +} + +# Some functions to provide filters on the above data + +sub open { [ $_[0]->_filter(sub { $_->type eq 'open' }) ] } +sub closed { [ $_[0]->_filter(sub { $_->type eq 'closed' }) ] } +sub fixed { [ $_[0]->_filter(sub { $_->type eq 'fixed' }) ] } + +# We sometimes have only a state label to display, no associated object. +# This function can be used to return that label's display name. + +sub display { + my ($rs, $label, $single_fixed) = @_; + my $unchanging = { + unconfirmed => _("Unconfirmed"), + hidden => _("Hidden"), + partial => _("Partial"), + 'fixed - council' => _("Fixed - Council"), + 'fixed - user' => _("Fixed - User"), + }; + $label = 'fixed' if $single_fixed && $label =~ /^fixed - (council|user)$/; + return $unchanging->{$label} if $unchanging->{$label}; + my ($state) = $rs->_filter(sub { $_->label eq $label }); + return $label unless $state; + return $state->msgstr; +} + +sub _filter { + my ($rs, $fn) = @_; + my $states = $rs->states; + grep &$fn, @$states; +} + +1; diff --git a/perllib/FixMyStreet/Script/Questionnaires.pm b/perllib/FixMyStreet/Script/Questionnaires.pm index 3f22eb150..ec6139d2d 100644 --- a/perllib/FixMyStreet/Script/Questionnaires.pm +++ b/perllib/FixMyStreet/Script/Questionnaires.pm @@ -16,6 +16,9 @@ sub send { sub send_questionnaires_period { my ( $period, $params ) = @_; + # Don't send if we don't have a fixed state + return unless FixMyStreet::DB::Result::Problem::fixed_states->{fixed}; + my $rs = FixMyStreet::DB->resultset('Questionnaire'); # Select all problems that need a questionnaire email sending diff --git a/perllib/FixMyStreet/TestAppProve.pm b/perllib/FixMyStreet/TestAppProve.pm index f6e09fbe9..7a387547d 100644 --- a/perllib/FixMyStreet/TestAppProve.pm +++ b/perllib/FixMyStreet/TestAppProve.pm @@ -75,7 +75,7 @@ sub run { $SIG{__WARN__} = sub { print STDERR @_ if $_[0] !~ m/NOTICE: CREATE TABLE/; }; $dbh->do( path('db/schema.sql')->slurp ) or die $!; - $dbh->do( path('db/alert_types.sql')->slurp ) or die $!; + $dbh->do( path('db/fixture.sql')->slurp ) or die $!; $dbh->do( path('db/generate_secret.sql')->slurp ) or die $!; $SIG{__WARN__} = $tmpwarn; diff --git a/t/app/controller/admin_states.t b/t/app/controller/admin_states.t new file mode 100644 index 000000000..60ffe5b88 --- /dev/null +++ b/t/app/controller/admin_states.t @@ -0,0 +1,24 @@ +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; + +my $user = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); + +$mech->log_in_ok( $user->email ); + +subtest 'basic states admin' => sub { + $mech->get_ok('/admin/states'); + $mech->submit_form_ok({ button => 'new', with_fields => { label => 'third party', type => 'closed', name => 'Third party referral' } }); + $mech->content_contains('Third party referral'); + $mech->content_contains('Fixed'); + $mech->submit_form_ok({ button => 'delete:fixed' }); + $mech->content_lacks('Fixed'); + $mech->submit_form_ok({ form_number => 2, button => 'new_fixed' }); + $mech->content_contains('Fixed'); + $mech->submit_form_ok({ with_fields => { 'name:third party' => 'Third party incident' } }); + $mech->content_contains('Third party incident'); +}; + +# TODO Language tests + +done_testing; diff --git a/t/app/controller/dashboard.t b/t/app/controller/dashboard.t index 9d424c1ae..b87b58b38 100644 --- a/t/app/controller/dashboard.t +++ b/t/app/controller/dashboard.t @@ -545,22 +545,11 @@ FixMyStreet::override_config { }, { desc => 'limit by state works', - state => 'fixed', + state => 'fixed - council', report_counts => [2,0,0], report_counts_after => [1,0,0], }, { - desc => 'planned counted as action scheduled', - p1 => { - state => 'planned', - conf_dt => DateTime->now(), - category => 'Potholes', - }, - state => 'action scheduled', - report_counts => [3,0,0], - report_counts_after => [1,0,0], - }, - { desc => 'All fixed states count as fixed', p1 => { state => 'fixed - council', @@ -573,7 +562,7 @@ FixMyStreet::override_config { category => 'Potholes', }, state => 'fixed', - report_counts => [5,0,0], + report_counts => [4,0,0], report_counts_after => [3,0,0], }, ) { @@ -612,7 +601,7 @@ FixMyStreet::override_config { while ( my $row = $csv->getline( $data_handle ) ) { push @rows, $row; } - is scalar @rows, 7, '1 (header) + 6 (reports) = 7 lines'; + is scalar @rows, 6, '1 (header) + 5 (reports) = 6 lines'; }; }; restore_time; diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t index 093ea9cf8..4d73a5204 100644 --- a/t/app/controller/report_display.t +++ b/t/app/controller/report_display.t @@ -313,7 +313,7 @@ for my $test ( date => DateTime->now, state => 'investigating', banner_id => 'progress', - banner_text => 'progress', + banner_text => 'investigating', fixed => 0 }, { @@ -321,7 +321,7 @@ for my $test ( date => DateTime->now, state => 'action scheduled', banner_id => 'progress', - banner_text => 'progress', + banner_text => 'action scheduled', fixed => 0 }, { @@ -329,7 +329,7 @@ for my $test ( date => DateTime->now, state => 'planned', banner_id => 'progress', - banner_text => 'progress', + banner_text => 'planned', fixed => 0 }, { diff --git a/t/app/controller/report_inspect.t b/t/app/controller/report_inspect.t index fcd7c724d..68f9063cf 100644 --- a/t/app/controller/report_inspect.t +++ b/t/app/controller/report_inspect.t @@ -57,7 +57,7 @@ FixMyStreet::override_config { }; subtest "test basic inspect submission" => sub { - $mech->submit_form_ok({ button => 'save', with_fields => { traffic_information => 'Yes', state => 'Action Scheduled', include_update => undef } }); + $mech->submit_form_ok({ button => 'save', with_fields => { traffic_information => 'Yes', state => 'Action scheduled', include_update => undef } }); $report->discard_changes; my $alert = FixMyStreet::App->model('DB::Alert')->find( { user => $user, alert_type => 'new_updates', confirmed => 1, } @@ -90,9 +90,8 @@ FixMyStreet::override_config { is $report->user->get_extra_metadata('reputation'), $reputation, "User reputation wasn't changed"; $mech->get_ok("/report/$report_id"); my $meta = $mech->extract_update_metas; - like $meta->[0], qr/Updated by .*action scheduled/, 'First update mentions action scheduled'; - like $meta->[1], qr/Posted by .*defect raised/, 'Update mentions defect raised'; - unlike $meta->[2], qr/Posted by .*action scheduled/, 'Update does not mention action scheduled'; + like $meta->[0], qr/State changed to: Action scheduled/, 'First update mentions action scheduled'; + like $meta->[2], qr/Posted by .*defect raised/, 'Update mentions defect raised'; $user->unset_extra_metadata('categories'); $user->update; @@ -300,7 +299,7 @@ FixMyStreet::override_config { subtest "Oxfordshire-specific traffic management options are shown" => sub { $report->update({ state => 'confirmed' }); $mech->get_ok("/report/$report_id"); - $mech->submit_form_ok({ button => 'save', with_fields => { traffic_information => 'Signs and Cones', state => 'Action Scheduled', include_update => undef } }); + $mech->submit_form_ok({ button => 'save', with_fields => { traffic_information => 'Signs and Cones', state => 'Action scheduled', include_update => undef } }); $report->discard_changes; is $report->state, 'action scheduled', 'report state changed'; is $report->get_extra_metadata('traffic_information'), 'Signs and Cones', 'report data changed'; diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t index 4cb035bac..0526b2fd7 100644 --- a/t/app/controller/report_updates.t +++ b/t/app/controller/report_updates.t @@ -93,8 +93,7 @@ for my $test ( anonymous => 't', mark_fixed => 'true', mark_open => 'false', - meta => -'Posted anonymously at 15:47, Sat 16 April 2011, marked as fixed', + meta => [ 'State changed to: Fixed', 'Posted anonymously at 15:47, Sat 16 April 2011' ] }, { description => 'named user, anon is true, reopened', @@ -102,7 +101,7 @@ for my $test ( anonymous => 't', mark_fixed => 'false', mark_open => 'true', - meta => 'Posted anonymously at 15:47, Sat 16 April 2011, reopened', + meta => [ 'State changed to: Open', 'Posted anonymously at 15:47, Sat 16 April 2011' ] } ) { @@ -118,8 +117,9 @@ for my $test ( $mech->content_contains('This is some update text'); my $meta = $mech->extract_update_metas; - is scalar @$meta, 1, 'number of updates'; - is $meta->[0], $test->{meta}; + my $test_meta = ref $test->{meta} ? $test->{meta} : [ $test->{meta} ]; + is scalar @$meta, scalar @$test_meta, 'number of updates'; + is_deeply $meta, $test_meta; }; } @@ -131,7 +131,7 @@ subtest "updates displayed on report with empty bodies_str" => sub { $mech->get_ok("/report/$report_id"); my $meta = $mech->extract_update_metas; - is scalar @$meta, 1, 'update displayed'; + is scalar @$meta, 2, 'update displayed'; $report->update({ bodies_str => $old_bodies_str }); }; @@ -185,10 +185,11 @@ subtest "several updates shown in correct order" => sub { $mech->get_ok("/report/$report_id"); my $meta = $mech->extract_update_metas; - is scalar @$meta, 3, 'number of updates'; + is scalar @$meta, 4, 'number of updates'; is $meta->[0], 'Posted by Other User at 12:23, Thu 10 March 2011', 'first update'; is $meta->[1], 'Posted by Main User at 12:23, Thu 10 March 2011', 'second update'; - is $meta->[2], 'Posted anonymously at 08:12, Tue 15 March 2011, marked as fixed', 'third update'; + is $meta->[2], 'State changed to: Fixed', 'third update, part 1'; + is $meta->[3], 'Posted anonymously at 08:12, Tue 15 March 2011', 'third update, part 2'; }; for my $test ( @@ -613,7 +614,6 @@ for my $test ( state => 'internal referral', }, state => 'internal referral', - meta => "an internal referral", }, { desc => 'from authority user marks report as not responsible', @@ -635,7 +635,6 @@ for my $test ( state => 'duplicate', }, state => 'duplicate', - meta => 'a duplicate report', }, { desc => 'from authority user marks report as internal referral', @@ -646,7 +645,6 @@ for my $test ( state => 'internal referral', }, state => 'internal referral', - meta => 'an internal referral', }, { desc => 'from authority user marks report sent to two councils as fixed', @@ -711,19 +709,13 @@ for my $test ( my $update_meta = $mech->extract_update_metas; my $meta_state = $test->{meta} || $test->{fields}->{state}; - if ( $test->{reopened} ) { - like $update_meta->[0], qr/reopened/, 'update meta says reopened'; - } elsif ( $test->{state} eq 'duplicate' ) { - like $update_meta->[0], qr/closed as $meta_state/, 'update meta includes state change'; - } else { - like $update_meta->[0], qr/marked as $meta_state/, 'update meta includes state change'; - } + like $update_meta->[0], qr/$meta_state/i, 'update meta includes state change'; if ($test->{view_username}) { - like $update_meta->[0], qr{Westminster City Council \(Test User\)}, 'update meta includes council and user name'; + like $update_meta->[1], qr{Westminster City Council \(Test User\)}, 'update meta includes council and user name'; $user->user_body_permissions->delete_all; } else { - like $update_meta->[0], qr{Westminster City Council}, 'update meta includes council name'; + like $update_meta->[1], qr{Westminster City Council}, 'update meta includes council name'; $mech->content_contains( '<strong>Westminster City Council</strong>', 'council name in bold'); } @@ -751,24 +743,22 @@ subtest 'check meta correct for comments marked confirmed but not marked open' = $mech->get_ok( "/report/" . $report->id ); my $update_meta = $mech->extract_update_metas; - unlike $update_meta->[0], qr/reopened/, + unlike $update_meta->[0], qr/Open/, 'update meta does not say reopened'; $comment->update( { mark_open => 1, problem_state => undef } ); $mech->get_ok( "/report/" . $report->id ); $update_meta = $mech->extract_update_metas; - unlike $update_meta->[0], qr/marked as open/, - 'update meta does not says marked as open'; - like $update_meta->[0], qr/reopened/, 'update meta does say reopened'; + like $update_meta->[0], qr/Open/, 'update meta does say open'; $comment->update( { mark_open => 0, problem_state => undef } ); $mech->get_ok( "/report/" . $report->id ); $update_meta = $mech->extract_update_metas; - unlike $update_meta->[0], qr/marked as open/, + unlike $update_meta->[0], qr/Open/, 'update meta does not says marked as open'; - unlike $update_meta->[0], qr/reopened/, 'update meta does not say reopened'; + unlike $update_meta->[0], qr/Open/, 'update meta does not say reopened'; }; subtest "check first comment with no status change has no status in meta" => sub { @@ -782,7 +772,7 @@ subtest "check first comment with no status change has no status in meta" => sub $mech->get_ok("/report/$report_id"); my $update_meta = $mech->extract_update_metas; - unlike $update_meta->[0], qr/marked as|reopened/, 'update meta does not include state change'; + unlike $update_meta->[0], qr/State changed to/, 'update meta does not include state change'; }; subtest "check comment with no status change has not status in meta" => sub { @@ -820,7 +810,7 @@ subtest "check comment with no status change has not status in meta" => sub { is $report->state, 'fixed - council', 'correct report state'; is $update->problem_state, 'fixed - council', 'correct update state'; my $update_meta = $mech->extract_update_metas; - unlike $update_meta->[1], qr/marked as/, 'update meta does not include state change'; + unlike $update_meta->[1], qr/State changed to/, 'update meta does not include state change'; $user->from_body( $body->id ); $user->update; @@ -854,9 +844,9 @@ subtest "check comment with no status change has not status in meta" => sub { is $report->state, 'investigating', 'correct report state'; is $update->problem_state, 'investigating', 'correct update state'; $update_meta = $mech->extract_update_metas; - like $update_meta->[0], qr/marked as fixed/, 'first update meta says fixed'; - unlike $update_meta->[1], qr/marked as/, 'second update meta does not include state change'; - like $update_meta->[2], qr/marked as investigating/, 'third update meta says investigating'; + like $update_meta->[0], qr/fixed/i, 'first update meta says fixed'; + unlike $update_meta->[2], qr/State changed to/, 'second update meta does not include state change'; + like $update_meta->[3], qr/investigating/i, 'third update meta says investigating'; my $dt = DateTime->now( time_zone => "local" )->add( seconds => 1 ); $comment = FixMyStreet::App->model('DB::Comment')->find_or_create( @@ -883,10 +873,10 @@ subtest "check comment with no status change has not status in meta" => sub { is $report->state, 'investigating', 'correct report state'; is $update->problem_state, undef, 'no update state'; $update_meta = $mech->extract_update_metas; - like $update_meta->[0], qr/marked as fixed/, 'first update meta says fixed'; - unlike $update_meta->[1], qr/marked as/, 'second update meta does not include state change'; - like $update_meta->[2], qr/marked as investigating/, 'third update meta says investigating'; - unlike $update_meta->[3], qr/marked as/, 'fourth update meta has no state change'; + like $update_meta->[0], qr/fixed/i, 'first update meta says fixed'; + unlike $update_meta->[2], qr/State changed to/, 'second update meta does not include state change'; + like $update_meta->[3], qr/investigating/i, 'third update meta says investigating'; + unlike $update_meta->[5], qr/State changed to/, 'fourth update meta has no state change'; }; subtest 'check meta correct for second comment marking as reopened' => sub { @@ -907,7 +897,7 @@ subtest 'check meta correct for second comment marking as reopened' => sub { $mech->get_ok( "/report/" . $report->id ); my $update_meta = $mech->extract_update_metas; - like $update_meta->[0], qr/fixed/, 'update meta says fixed'; + like $update_meta->[0], qr/fixed/i, 'update meta says fixed'; $comment = FixMyStreet::App->model('DB::Comment')->create( { @@ -925,7 +915,7 @@ subtest 'check meta correct for second comment marking as reopened' => sub { $mech->get_ok( "/report/" . $report->id ); $update_meta = $mech->extract_update_metas; - like $update_meta->[1], qr/reopened/, 'update meta says reopened'; + like $update_meta->[2], qr/Open/, 'update meta says reopened'; }; subtest "check first comment with status change but no text is displayed" => sub { @@ -953,9 +943,9 @@ subtest "check first comment with status change but no text is displayed" => sub $mech->get_ok("/report/$report_id"); my $update_meta = $mech->extract_update_metas; - like $update_meta->[0], qr/Updated by/, 'updated by meta if no text'; - unlike $update_meta->[0], qr/Test User/, 'commenter name not included'; - like $update_meta->[0], qr/investigating/, 'update meta includes state change'; + like $update_meta->[1], qr/Updated by/, 'updated by meta if no text'; + unlike $update_meta->[1], qr/Test User/, 'commenter name not included'; + like $update_meta->[0], qr/investigating/i, 'update meta includes state change'; ok $user->user_body_permissions->create({ body => $body, @@ -964,9 +954,9 @@ subtest "check first comment with status change but no text is displayed" => sub $mech->get_ok("/report/$report_id"); $update_meta = $mech->extract_update_metas; - like $update_meta->[0], qr/Updated by/, 'updated by meta if no text'; - like $update_meta->[0], qr/Test User/, 'commenter name included if user has view contribute permission'; - like $update_meta->[0], qr/investigating/, 'update meta includes state change'; + like $update_meta->[1], qr/Updated by/, 'updated by meta if no text'; + like $update_meta->[1], qr/Test User/, 'commenter name included if user has view contribute permission'; + like $update_meta->[0], qr/investigating/i, 'update meta includes state change'; }; @@ -1712,10 +1702,10 @@ for my $test ( desc => 'update unable to fix without marking as fixed leaves state unchanged', initial_state => 'unable to fix', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 0, + reopen => 0, }, end_state => 'unable to fix', }, @@ -1723,10 +1713,10 @@ for my $test ( desc => 'update internal referral without marking as fixed leaves state unchanged', initial_state => 'internal referral', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 0, + reopen => 0, }, end_state => 'internal referral', }, @@ -1734,10 +1724,10 @@ for my $test ( desc => 'update not responsible without marking as fixed leaves state unchanged', initial_state => 'not responsible', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 0, + reopen => 0, }, end_state => 'not responsible', }, @@ -1745,10 +1735,10 @@ for my $test ( desc => 'update duplicate without marking as fixed leaves state unchanged', initial_state => 'duplicate', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 0, + reopen => 0, }, end_state => 'duplicate', }, @@ -1808,48 +1798,48 @@ for my $test ( end_state => 'confirmed', }, { - desc => 'can mark unable to fix as fixed, cannot mark not closed', + desc => 'cannot mark unable to fix as fixed, can reopen', initial_state => 'unable to fix', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 1, + reopen => 1, }, - end_state => 'fixed - user', + end_state => 'confirmed', }, { - desc => 'can mark internal referral as fixed, cannot mark not closed', + desc => 'cannot mark internal referral as fixed, can reopen', initial_state => 'internal referral', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 1, + reopen => 1, }, - end_state => 'fixed - user', + end_state => 'confirmed', }, { - desc => 'can mark not responsible as fixed, cannot mark not closed', + desc => 'cannot mark not responsible as fixed, can reopen', initial_state => 'not responsible', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 1, + reopen => 1, }, - end_state => 'fixed - user', + end_state => 'confirmed', }, { - desc => 'can mark duplicate as fixed, cannot mark not closed', + desc => 'cannot mark duplicate as fixed, can reopen', initial_state => 'duplicate', expected_form_fields => { - fixed => undef, + reopen => undef, }, submitted_form_fields => { - fixed => 1, + reopen => 1, }, - end_state => 'fixed - user', + end_state => 'confirmed', }, ) { subtest $test->{desc} => sub { diff --git a/t/app/model/state.t b/t/app/model/state.t new file mode 100644 index 000000000..1653e36e2 --- /dev/null +++ b/t/app/model/state.t @@ -0,0 +1,62 @@ +use FixMyStreet::Test; +use Test::More; + +my $rs = FixMyStreet::DB->resultset('State'); +my $trans_rs = FixMyStreet::DB->resultset('Translation'); + +for ( + { label => 'in progress', lang => 'de' }, + { label => 'investigating', lang => 'fr' }, + { label => 'duplicate', lang => 'de' }, +) { + my $lang = $_->{lang}; + my $obj = $rs->find({ label => $_->{label} }); + $trans_rs->create({ tbl => 'state', col => 'name', object_id => $obj->id, + lang => $lang, msgstr => "$lang $_->{label}" }); +} + +my $states = $rs->states; +my %states = map { $_->label => $_ } @$states; + +subtest 'Open/closed database data is as expected' => sub { + my $open = $rs->open; + is @$open, 5; + my $closed = $rs->closed; + is @$closed, 5; +}; + +is $rs->display('investigating'), 'Investigating'; +is $rs->display('bad'), 'bad'; +is $rs->display('confirmed'), 'Open'; +is $rs->display('closed'), 'Closed'; +is $rs->display('fixed - council'), 'Fixed - Council'; +is $rs->display('fixed - user'), 'Fixed - User'; +is $rs->display('fixed'), 'Fixed'; + +subtest 'default name is untranslated' => sub { + is $states{'in progress'}->name, 'In progress'; + is $states{'in progress'}->msgstr, 'In progress'; + is $states{'action scheduled'}->name, 'Action scheduled'; + is $states{'action scheduled'}->msgstr, 'Action scheduled'; +}; + +subtest 'msgstr gets translated if available when the language changes' => sub { + FixMyStreet::DB->schema->lang('de'); + is $states{'in progress'}->name, 'In progress'; + is $states{'in progress'}->msgstr, 'de in progress'; + is $states{'investigating'}->name, 'Investigating'; + is $states{'investigating'}->msgstr, 'Investigating'; + is $states{'unable to fix'}->name, 'No further action'; + is $states{'unable to fix'}->msgstr, 'No further action'; +}; + +$rs->clear; + +is_deeply [ sort FixMyStreet::DB::Result::Problem->open_states ], + ['action scheduled', 'confirmed', 'in progress', 'investigating', 'planned'], 'open states okay'; +is_deeply [ sort FixMyStreet::DB::Result::Problem->closed_states ], + ['closed', 'duplicate', 'internal referral', 'not responsible', 'unable to fix'], 'closed states okay'; +is_deeply [ sort FixMyStreet::DB::Result::Problem->fixed_states ], + ['fixed', 'fixed - council', 'fixed - user'], 'fixed states okay'; + +done_testing(); diff --git a/t/cobrand/bromley.t b/t/cobrand/bromley.t index 46c2472cd..f3053c29a 100644 --- a/t/cobrand/bromley.t +++ b/t/cobrand/bromley.t @@ -41,9 +41,9 @@ for my $update ('in progress', 'unable to fix') { # Test Bromley special casing of 'unable to fix' $mech->get_ok( '/report/' . $report->id ); $mech->content_contains( 'marks it as in progress' ); -$mech->content_contains( 'marked as in progress' ); +$mech->content_contains( 'State changed to: In progress' ); $mech->content_contains( 'marks it as unable to fix' ); -$mech->content_contains( 'marked as no further action' ); +$mech->content_contains( 'State changed to: No further action' ); subtest 'testing special Open311 behaviour', sub { $report->set_extra_fields(); diff --git a/templates/web/base/admin/problem_row.html b/templates/web/base/admin/problem_row.html index 79461367e..446e94d66 100644 --- a/templates/web/base/admin/problem_row.html +++ b/templates/web/base/admin/problem_row.html @@ -34,8 +34,8 @@ [% loc('Created') %]: [% PROCESS format_time time=problem.created %] <br>[% loc('When sent') %]: [% PROCESS format_time time=problem.whensent %] [%- IF problem.is_visible %]<br>[% loc('Confirmed:' ) %] [% PROCESS format_time time=problem.confirmed %][% END -%] - [%- IF problem.is_fixed %]<br>[% loc('Fixed:') %] [% PROCESS format_time time=problem.lastupdate %][% END -%] - [%- IF problem.is_closed %]<br>[% loc('Closed:') %] [% PROCESS format_time time=problem.lastupdate %][% END -%] + [%- IF problem.is_fixed %]<br>[% prettify_state('fixed') %]: [% PROCESS format_time time=problem.lastupdate %][% END -%] + [%- IF problem.is_closed %]<br>[% prettify_state('closed') %]: [% PROCESS format_time time=problem.lastupdate %][% END -%] [%- IF problem.is_open %]<br>[% loc('Last update:') %] [% PROCESS format_time time=problem.lastupdate %][% END -%] </small></td> <td><a href="[% c.uri_for( 'report_edit', problem.id ) %]">[% loc('Edit') %]</a></td> diff --git a/templates/web/base/admin/report_blocks.html b/templates/web/base/admin/report_blocks.html index 933521b94..f5896b88f 100644 --- a/templates/web/base/admin/report_blocks.html +++ b/templates/web/base/admin/report_blocks.html @@ -1,13 +1,7 @@ [% SET report_blocks_included = 1; - -SET state_groups = [ - [ loc('Open'), [ 'confirmed', 'investigating', 'planned', 'in progress', 'action scheduled' ] ], - [ loc('Fixed'), [ 'fixed', 'fixed - user', 'fixed - council' ] ], - [ loc('Closed'), [ 'unable to fix', 'not responsible', 'duplicate', 'closed', 'internal referral' ] ], - [ loc('Hidden'), [ 'hidden', 'partial', 'unconfirmed' ] ] -]; +SET state_groups = c.cobrand.state_groups_admin; %] diff --git a/templates/web/base/admin/states/index.html b/templates/web/base/admin/states/index.html new file mode 100644 index 000000000..bd87f5013 --- /dev/null +++ b/templates/web/base/admin/states/index.html @@ -0,0 +1,118 @@ +[% INCLUDE 'admin/header.html' title=loc('States') ~%] + +[% SET rows = languages.size + 1 IF languages.size > 1 ~%] + +<form method="post" accept-charset="utf-8"> + +<table> + <tr> + <th>Label</th> + <th>Type</th> + <th colspan="2">Name</th> + <th> </th> + </tr> + [% FOREACH state IN open_states.merge(closed_states).merge(fixed_states) %] + <tr> + <td rowspan="[% rows %]"> + [% IF state.label == 'confirmed' %] + open + [% ELSE %] + [% state.label %] + [% END %] + </td> + <td rowspan="[% rows %]"> + [% IF state.label == 'confirmed' %] + [% loc('Open') %]<input type="hidden" name="type:confirmed" value="open"> + [% ELSIF state.label == 'closed' %] + [% loc('Closed') %]<input type="hidden" name="type:closed" value="closed"> + [% ELSIF state.label == 'fixed' %] + [% loc('Fixed') %]<input type="hidden" name="type:fixed" value="fixed"> + [% ELSE %] + <select name="type:[% state.label %]"> + <option value="open"[% ' selected' IF state.type == 'open' %]>[% loc('Open') %]</option> + <option value="closed"[% ' selected' IF state.type == 'closed' %]>[% loc('Closed') %]</option> + </select> + [% END %] + </td> + <td colspan="2"> + [% IF state.label != 'confirmed' AND state.label != 'closed' %] + <input type="text" name="name:[% state.label %]" value="[% state.name %]"> + [% ELSIF languages.size == 1 %] + <input type="text" name="name:[% state.label %]" value="[% state.msgstr %]"> + [% ELSE %] + [% state.name %] + [% END %] + </td> + <td style="text-align:center;vertical-align:middle" rowspan="[% rows %]"> + [% IF state.label != 'confirmed' AND state.label != 'closed' %] + <input class="btn btn--small" type="submit" name="delete:[% state.label %]" value="Delete"> + [% END %] + </td> + </tr> + [% IF languages.size > 1 %] + [% FOREACH language IN languages.keys.sort %] + <tr> + <td style="vertical-align:middle; text-align:right;"> + <label style="margin:0" for="translation:[% state.label %]:[% language %]"> + [% languages.$language.name %] ([% language %]) + </label> + </td> + <td> + <input type="hidden" name="translation_id:[% state.label %]:[% language %]" + value="[% state.translated.name.$language.id %]"> + <input type="text" name="translation:[% state.label %]:[% language %]" + id="translation:[% state.label %]:[% language %]" value="[% state.translated.name.$language.msgstr %]"> + </td> + </tr> + [% END %] + [% END %] + </td> + </tr> + [% END %] +</table> + + <p> + <input type="hidden" name="token" value="[% csrf_token %]"> + <input type="submit" class="btn" value="[% loc('Update') %]"> + </p> + +</form> + +[% IF fixed_states.size == 0 %] +<form method="post" accept-charset="utf-8"> + <p> + <input type="hidden" name="token" value="[% csrf_token %]"> + <input type="submit" class="btn" name="new_fixed" value="[% loc('Add fixed state') %]"> + </p> +</form> + +[% END %] + +<h2>[% loc('New state') %]</h2> + +<form method="post" accept-charset="utf-8"> + <p> + <label for="label">[% loc('Label') %] <small>[% loc('(a-z and space only)') %]</small></label> + <input type="text" class="form-control" name="label" id="label" value="" size="20" pattern="[a-z ]+"> + </p> + + <p> + <label for="type">[% loc('Label') %]</label> + <select name="type" id="type"> + <option value="open">[% loc('Open') %]</option> + <option value="closed">[% loc('Closed') %]</option> + </select> + </p> + + <p> + <label for="name">[% loc('Name') %]</label> + <input type="text" class="form-control" name="name" id="name" value="" size="20"> + </p> + + <p> + <input type="hidden" name="token" value="[% csrf_token %]"> + <input type="submit" class="btn" name="new" value="[% loc('Create') %]"> + </p> +</form> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/base/dashboard/index.html b/templates/web/base/dashboard/index.html index 6033ef36b..e47798573 100644 --- a/templates/web/base/dashboard/index.html +++ b/templates/web/base/dashboard/index.html @@ -136,11 +136,12 @@ </select> <p>[% loc('Report state:') %] <select class="form-control" name="state"> <option value=''>[% loc('All') %]</option> - [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating', - loc('Investigating')], ['action scheduled', loc('Planned')], ['in progress', - loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %] - <option [% 'selected ' IF state.0 == q_state %] value="[% state.0 %]">[% state.1 %]</option> - [% END %] + [% FOR group IN filter_states %] + [% FOR state IN group.1 %] + [% NEXT IF state == 'hidden' %] + <option [% 'selected ' IF state == q_state %] value="[% state %]">[% prettify_state(state, 1) %]</option> + [% END %] + [% END %] </select> <input type="submit" class="btn" value="[% loc('Look up') %]"> <a class="export_as_csv" href="[% c.req.uri_with({ export => 1 }) %]">[% loc('Export as CSV') %]</a> diff --git a/templates/web/base/front/stats.html b/templates/web/base/front/stats.html index eb671137b..41358c869 100644 --- a/templates/web/base/front/stats.html +++ b/templates/web/base/front/stats.html @@ -35,7 +35,9 @@ <div id="front_stats"> <div>[% tprintf( new_text, decode(new_n) ) %]</div> + [% IF has_fixed_state %] <div>[% tprintf( fixed_text, decode(fixed_n) ) %]</div> + [% END %] [% IF c.cobrand.moniker != 'zurich' %] <div>[% tprintf( updates_text, decode(updates_n) ) %]</div> [% END %] diff --git a/templates/web/base/report/_item.html b/templates/web/base/report/_item.html index 3f5c5464b..9449ca55d 100644 --- a/templates/web/base/report/_item.html +++ b/templates/web/base/report/_item.html @@ -40,9 +40,9 @@ [% END %] <small> [% IF NOT no_fixed AND problem.is_fixed %] - <span class="item-list__item__state">[% loc('Fixed') %]</span> + <span class="item-list__item__state">[% prettify_state('fixed') %]</span> [% ELSIF NOT no_fixed AND problem.is_closed %] - <span class="item-list__item__state">[% loc('Closed') %]</span> + <span class="item-list__item__state">[% prettify_state('closed') %]</span> [% ELSIF (c.user.has_permission_to('report_edit_priority', problem.bodies_str_ids) OR c.user.has_permission_to('report_inspect', problem.bodies_str_ids)) AND problem.response_priority %] <span class="item-list__item__state">[% problem.response_priority.name %]</span> [% END %] diff --git a/templates/web/base/report/banner.html b/templates/web/base/report/banner.html index c80d129eb..ee73d287a 100644 --- a/templates/web/base/report/banner.html +++ b/templates/web/base/report/banner.html @@ -9,11 +9,11 @@ [% INCLUDE banner, id = 'unknown', text = loc('Unknown') %] [% END %] [% IF problem.is_fixed %] - [% INCLUDE banner, id = 'fixed', text = loc('Fixed') %] + [% INCLUDE banner, id = 'fixed', text = prettify_state('fixed') %] [% END %] [% IF problem.is_closed %] - [% INCLUDE banner, id = 'closed', text = loc('Closed') %] + [% INCLUDE banner, id = 'closed', text = prettify_state('closed') %] [% END %] [% IF problem.is_in_progress %] - [% INCLUDE banner, id = 'progress', text = loc('In progress') %] + [% INCLUDE banner, id = 'progress', text = prettify_state(problem.state) %] [% END %] diff --git a/templates/web/base/report/inspect/state_groups_select.html b/templates/web/base/report/inspect/state_groups_select.html index 2cf1a4de5..998b99739 100644 --- a/templates/web/base/report/inspect/state_groups_select.html +++ b/templates/web/base/report/inspect/state_groups_select.html @@ -1,11 +1,6 @@ [% -SET state_groups = [ - [ loc('Open'), [ 'confirmed', 'investigating', 'in progress', 'action scheduled' ] ], - [ loc('Fixed'), [ 'fixed - council' ] ], - [ loc('Closed'), [ 'unable to fix', 'not responsible', 'duplicate', 'internal referral' ] ], - [ loc('Hidden'), [ 'hidden' ] ] -]; +SET state_groups = c.cobrand.state_groups_inspect; %] [% DEFAULT current_state = problem.state %] diff --git a/templates/web/base/report/state-list.html b/templates/web/base/report/state-list.html deleted file mode 100644 index e137c81e2..000000000 --- a/templates/web/base/report/state-list.html +++ /dev/null @@ -1,21 +0,0 @@ -[% -SET state_pretty = { - 'confirmed' = loc('Open') - 'investigating' = loc('Investigating') - 'planned' = loc('Planned') - 'in progress' = loc('In progress') - 'action scheduled' = loc('Action Scheduled') - 'fixed' = loc('Fixed') - 'fixed - user' = loc('Fixed - User') - 'fixed - council' = loc('Fixed - Council') - 'unable to fix' = loc('No further action') - 'not responsible' = loc('Not Responsible') - 'duplicate' = loc('Duplicate') - 'closed' = loc('Closed') - 'internal referral' = loc('Internal referral') - 'hidden' = loc('Hidden') - 'partial' = loc('Partial') - 'unconfirmed' = loc('Unconfirmed') -}; -state_pretty.$state -~%] diff --git a/templates/web/base/report/update.html b/templates/web/base/report/update.html index 1f1438bfc..85624669a 100644 --- a/templates/web/base/report/update.html +++ b/templates/web/base/report/update.html @@ -43,6 +43,12 @@ </div> [% END %] + [% SET update_state = update.problem_state_display(c) %] + [% IF update_state AND update_state != global.last_state AND NOT (global.last_state == "" AND update.problem_state == 'confirmed') %] + <p class="meta-2">[% loc('State changed to:') %] [% update_state %]</p> + [%- global.last_state = update_state %] + [% END %] + <p class="meta-2"> [% INCLUDE meta_line %] [% IF c.user_exists AND c.user.id == update.user_id AND !update.anonymous %] diff --git a/templates/web/base/report/update/form_update.html b/templates/web/base/report/update/form_update.html index 34abf53c5..5a1b3b602 100644 --- a/templates/web/base/report/update/form_update.html +++ b/templates/web/base/report/update/form_update.html @@ -39,7 +39,7 @@ <label for="state">[% loc( 'State' ) %]</label> [% INCLUDE 'report/inspect/state_groups_select.html' %] [% ELSE %] - [% IF (problem.is_fixed OR problem.state == 'closed') AND ((c.user_exists AND c.user.id == problem.user_id) OR alert_to_reporter) %] + [% IF (problem.is_fixed OR problem.is_closed) AND ((c.user_exists AND c.user.id == problem.user_id) OR alert_to_reporter) %] <input type="checkbox" name="reopen" id="form_reopen" value="1"[% ' checked' IF (update.mark_open || c.req.params.reopen) %]> [% IF problem.is_closed %] @@ -48,7 +48,7 @@ <label class="inline" for="form_reopen">[% loc('This problem has not been fixed') %]</label> [% END %] - [% ELSIF !problem.is_fixed %] + [% ELSIF !problem.is_fixed AND has_fixed_state %] <div class="checkbox-group"> <input type="checkbox" name="fixed" id="form_fixed" value="1"[% ' checked' IF update.mark_fixed %]> diff --git a/templates/web/base/reports/_list-filters.html b/templates/web/base/reports/_list-filters.html index ef7c7ad78..50e88857d 100644 --- a/templates/web/base/reports/_list-filters.html +++ b/templates/web/base/reports/_list-filters.html @@ -1,6 +1,6 @@ [% select_status = BLOCK %] <select class="form-control js-multiple" name="status" id="statuses" multiple - data-all="[% loc('All reports') %]" data-all-options='["open","closed","fixed"]' + data-all="[% loc('All') %]" data-all-options='["open","closed","fixed"]' [%~ IF c.cobrand.on_map_default_status == 'open' %] data-none="[% loc('Unfixed reports') %]" [%~ END ~%] @@ -10,19 +10,18 @@ <option value="unshortlisted"[% ' selected' IF filter_status.unshortlisted %]>[% loc('Unshortlisted') %]</option> [% END %] [% IF c.user_exists AND c.user.is_superuser OR c.user.belongs_to_body(body.id) %] - <option value="confirmed"[% ' selected' IF filter_status.confirmed %]>[% loc('Open') %]</option> - <option value="investigating"[% ' selected' IF filter_status.investigating %]>[% loc('Investigating') %]</option> - <option value="in progress"[% ' selected' IF filter_status.in_progress %]>[% loc('In progress') %]</option> - <option value="action scheduled"[% ' selected' IF filter_status.action_scheduled %]>[% loc('Action scheduled') %]</option> - <option value="fixed"[% ' selected' IF filter_status.fixed %]>[% loc('Fixed reports') %]</option> - <option value="unable to fix"[% ' selected' IF filter_status.unable_to_fix %]>[% loc('No further action') %]</option> - <option value="not responsible"[% ' selected' IF filter_status.not_responsible %]>[% loc('Not responsible') %]</option> - <option value="internal referral"[% ' selected' IF filter_status.internal_referral %]>[% loc('Internal referral') %]</option> - <option value="duplicate"[% ' selected' IF filter_status.duplicate %]>[% loc('Duplicate') %]</option> + [% FOR group IN filter_states %] + [% FOR state IN group.1 %] + [% NEXT IF state == 'hidden' %] + <option value="[% state %]"[% ' selected' IF filter_status.$state %]>[% prettify_state(state, 1) %]</option> + [% END %] + [% END %] [% ELSE %] - <option value="open"[% ' selected' IF filter_status.open %]>[% loc('Unfixed reports') %]</option> - <option value="closed"[% ' selected' IF filter_status.closed %]>[% loc('Closed reports') %]</option> - <option value="fixed"[% ' selected' IF filter_status.fixed %]>[% loc('Fixed reports') %]</option> + <option value="open"[% ' selected' IF filter_status.open %]>[% prettify_state('confirmed') %]</option> + <option value="closed"[% ' selected' IF filter_status.closed %]>[% prettify_state('closed') %]</option> + [% IF has_fixed_state %] + <option value="fixed"[% ' selected' IF filter_status.fixed %]>[% prettify_state('fixed') %]</option> + [% END %] [% END %] </select> [% END %] @@ -46,7 +45,7 @@ [% END %] <p class="report-list-filters"> - [% tprintf(loc('<label for="statuses">Show</label> %s <label for="filter_categories">about</label> %s', "The first %s is a dropdown of all/fixed/etc, the second is a dropdown of categories"), select_status, select_category) %] + [% tprintf(loc('<label for="statuses">Show</label> %s reports <label for="filter_categories">about</label> %s', "The first %s is a dropdown of all/fixed/etc, the second is a dropdown of categories"), select_status, select_category) %] <input type="submit" name="filter_update" value="[% loc('Go') %]"> </p> diff --git a/templates/web/oxfordshire/report/inspect/state_groups_select.html b/templates/web/oxfordshire/report/inspect/state_groups_select.html deleted file mode 100644 index d36fb0191..000000000 --- a/templates/web/oxfordshire/report/inspect/state_groups_select.html +++ /dev/null @@ -1,12 +0,0 @@ -[% - -SET state_groups = [ - [ loc('New'), [ 'confirmed', 'investigating' ] ], - [ loc('Scheduled'), [ 'action scheduled' ] ], - [ loc('Fixed'), [ 'fixed - council' ] ], - [ loc('Closed'), [ 'not responsible', 'duplicate', 'unable to fix' ] ] -]; - -%] -[% DEFAULT current_state = problem.state %] -[% INCLUDE 'report/_state_select_field.html' single_fixed=1 %] |