aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/Bodies.pm328
-rw-r--r--perllib/FixMyStreet/App/Controller/My.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/BathNES.pm13
-rw-r--r--perllib/FixMyStreet/Cobrand/Bexley.pm5
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm2
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm23
-rw-r--r--perllib/FixMyStreet/Roles/Translatable.pm13
-rw-r--r--t/app/controller/admin/bodies.t17
-rw-r--r--t/app/controller/admin/translations.t2
-rw-r--r--t/cobrand/bathnes.t18
-rw-r--r--t/roles/translatable.t7
-rw-r--r--templates/web/base/admin/bodies/_category_field.html17
-rw-r--r--templates/web/base/admin/bodies/contact-form.html22
-rw-r--r--templates/web/bathnes/admin/bodies/_category_field.html21
-rw-r--r--web/cobrands/fixmystreet/staff.js2
16 files changed, 296 insertions, 198 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e718a42a9..0deef93a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
- Contact form emails now include user admin links.
- Allow categories/Open311 questions to disable the reporting form. #2599
- Improve category edit form. #2469
+ - Allow editing of category name. #1398
- New features:
- Categories can be listed under more than one group #2475
- OpenID Connect login support. #2523
@@ -47,6 +48,7 @@
- Add front-end testing support for WSL. #2514
- Allow cobrands to disable admin resending.
- Sass variables for default link colour and decoration.
+ - Make contact edit note optional on staging sites.
- Open311 improvements:
- Support use of 'private' service definition <keywords> to mark
reports made in that category private. #2488
diff --git a/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm b/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm
index fa5a55213..165fdc783 100644
--- a/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm
@@ -51,27 +51,7 @@ sub index : Path : Args(0) {
my $posted = $c->get_param('posted') || '';
if ( $posted eq 'body' ) {
- $c->forward('check_for_super_user');
- $c->forward('/auth/check_csrf_token');
-
- my $values = $c->forward('body_params');
- unless ( keys %{$c->stash->{body_errors}} ) {
- my $body = $c->model('DB::Body')->create( $values->{params} );
- if ($values->{extras}) {
- $body->set_extra_metadata( $_ => $values->{extras}->{$_} )
- for keys %{$values->{extras}};
- $body->update;
- }
- my @area_ids = $c->get_param_list('area_ids');
- foreach (@area_ids) {
- $c->model('DB::BodyArea')->create( { body => $body, area_id => $_ } );
- }
-
- $c->stash->{object} = $body;
- $c->stash->{translation_col} = 'name';
- $c->forward('update_translations');
- $c->stash->{updated} = _('New body added');
- }
+ $c->forward('update_body', [ undef, _('New body added') ]);
}
$c->forward( '/admin/fetch_all_bodies' );
@@ -158,7 +138,8 @@ sub category : Chained('body') : PathPart('') {
$c->forward( '/auth/get_csrf_token' );
my $contact = $c->stash->{body}->contacts->search( { category => $category } )->first;
- $c->stash->{contact} = $contact;
+ $c->detach( '/page_error_404_not_found', [] ) unless $contact;
+ $c->stash->{contact} = $c->stash->{current_contact} = $contact;
$c->stash->{translation_col} = 'category';
$c->stash->{object} = $c->stash->{contact};
@@ -220,161 +201,197 @@ sub check_for_super_user : Private {
sub update_contacts : Private {
my ( $self, $c ) = @_;
- my $posted = $c->get_param('posted');
- my $editor = $c->forward('/admin/get_user');
-
+ my $posted = $c->get_param('posted') || '';
if ( $posted eq 'new' ) {
- $c->forward('/auth/check_csrf_token');
+ $c->forward('update_contact');
+ } elsif ( $posted eq 'update' ) {
+ $c->forward('confirm_contacts');
+ } elsif ( $posted eq 'body' ) {
+ $c->forward('update_body', [ $c->stash->{body}, _('Values updated') ]);
+ }
+}
- my %errors;
+sub update_contact : Private {
+ my ( $self, $c ) = @_;
- my $category = $self->trim( $c->get_param('category') );
- $errors{category} = _("Please choose a category") unless $category;
- $errors{note} = _('Please enter a message') unless $c->get_param('note');
+ my $editor = $c->forward('/admin/get_user');
+ $c->forward('/auth/check_csrf_token');
- my $contact = $c->model('DB::Contact')->find_or_new(
- {
- body_id => $c->stash->{body_id},
- category => $category,
- }
- );
+ my %errors;
- my $email = $c->get_param('email');
- $email =~ s/\s+//g;
- my $send_method = $c->get_param('send_method') || $contact->body->send_method || "";
- unless ( $send_method eq 'Open311' ) {
- $errors{email} = _('Please enter a valid email') unless is_valid_email_list($email) || $email eq 'REFUSED';
- }
+ my $current_category = $c->get_param('current_category') || '';
+ my $current_contact = $c->model('DB::Contact')->find({
+ body_id => $c->stash->{body_id},
+ category => $current_category,
+ });
+ $c->stash->{current_contact} = $current_contact;
- $contact->email( $email );
- $contact->state( $c->get_param('state') );
- $contact->non_public( $c->get_param('non_public') ? 1 : 0 );
- $contact->note( $c->get_param('note') );
- $contact->whenedited( \'current_timestamp' );
- $contact->editor( $editor );
- $contact->endpoint( $c->get_param('endpoint') );
- $contact->jurisdiction( $c->get_param('jurisdiction') );
- $contact->api_key( $c->get_param('api_key') );
- $contact->send_method( $c->get_param('send_method') );
-
- # Set flags in extra to the appropriate values
- if ( $c->get_param('photo_required') ) {
- $contact->set_extra_metadata_if_undefined( photo_required => 1 );
- }
- else {
- $contact->unset_extra_metadata( 'photo_required' );
- }
- if ( $c->get_param('inspection_required') ) {
- $contact->set_extra_metadata( inspection_required => 1 );
- }
- else {
- $contact->unset_extra_metadata( 'inspection_required' );
- }
- if ( $c->get_param('reputation_threshold') ) {
- $contact->set_extra_metadata( reputation_threshold => int($c->get_param('reputation_threshold')) );
- }
- if ( my @group = $c->get_param_list('group') ) {
- @group = grep { $_ } @group;
- if (scalar @group == 0) {
- $contact->unset_extra_metadata( 'group' );
- } else {
- $contact->set_extra_metadata( group => \@group );
- }
- } else {
- $contact->unset_extra_metadata( 'group' );
+ my $category = $self->trim( $c->get_param('category') );
+ $errors{category} = _("Please choose a category") unless $category;
+ $errors{note} = _('Please enter a message') unless $c->get_param('note') || FixMyStreet->config('STAGING_SITE');
+
+ my $contact = $c->model('DB::Contact')->find_or_new(
+ {
+ body_id => $c->stash->{body_id},
+ category => $category,
}
+ );
+ if ($current_contact && $contact->id && $contact->id != $current_contact->id) {
+ $errors{category} = _('You cannot rename a category to an existing category');
+ } elsif ($current_contact && !$contact->id) {
+ # Changed name
+ $contact = $current_contact;
+ $c->model('DB::Problem')->to_body($c->stash->{body_id})->search({ category => $current_category })->update({ category => $category });
+ $contact->category($category);
+ }
+ my $email = $c->get_param('email');
+ $email =~ s/\s+//g;
+ my $send_method = $c->get_param('send_method') || $contact->body->send_method || "";
+ unless ( $send_method eq 'Open311' ) {
+ $errors{email} = _('Please enter a valid email') unless is_valid_email_list($email) || $email eq 'REFUSED';
+ }
- $c->forward('/admin/update_extra_fields', [ $contact ]);
- $c->forward('contact_cobrand_extra_fields', [ $contact ]);
-
- # Special form disabling form
- if ($c->get_param('disable')) {
- my $msg = $c->get_param('disable_message');
- $errors{category} = _('Please enter a message') unless $msg;
- my $meta = {
- code => '_fms_disable_',
- variable => 'false',
- protected => 'true',
- disable_form => 'true',
- description => $msg,
- };
- $contact->update_extra_field($meta);
+ $contact->email( $email );
+ $contact->state( $c->get_param('state') );
+ $contact->non_public( $c->get_param('non_public') ? 1 : 0 );
+ $contact->note( $c->get_param('note') );
+ $contact->whenedited( \'current_timestamp' );
+ $contact->editor( $editor );
+ $contact->endpoint( $c->get_param('endpoint') );
+ $contact->jurisdiction( $c->get_param('jurisdiction') );
+ $contact->api_key( $c->get_param('api_key') );
+ $contact->send_method( $c->get_param('send_method') );
+
+ # Set flags in extra to the appropriate values
+ if ( $c->get_param('photo_required') ) {
+ $contact->set_extra_metadata_if_undefined( photo_required => 1 );
+ } else {
+ $contact->unset_extra_metadata( 'photo_required' );
+ }
+ if ( $c->get_param('inspection_required') ) {
+ $contact->set_extra_metadata( inspection_required => 1 );
+ } else {
+ $contact->unset_extra_metadata( 'inspection_required' );
+ }
+ if ( $c->get_param('reputation_threshold') ) {
+ $contact->set_extra_metadata( reputation_threshold => int($c->get_param('reputation_threshold')) );
+ }
+ if ( my @group = $c->get_param_list('group') ) {
+ @group = grep { $_ } @group;
+ if (scalar @group == 0) {
+ $contact->unset_extra_metadata( 'group' );
} else {
- $contact->remove_extra_field('_fms_disable_');
+ $contact->set_extra_metadata( group => \@group );
}
+ } else {
+ $contact->unset_extra_metadata( 'group' );
+ }
- if ( %errors ) {
- $c->stash->{updated} = _('Please correct the errors below');
- $c->stash->{contact} = $contact;
- $c->stash->{errors} = \%errors;
- } elsif ( $contact->in_storage ) {
- $c->stash->{updated} = _('Values updated');
- # NB: History is automatically stored by a trigger in the database
- $contact->update;
- } else {
- $c->stash->{updated} = _('New category contact added');
- $contact->insert;
+ $c->forward('/admin/update_extra_fields', [ $contact ]);
+ $c->forward('contact_cobrand_extra_fields', [ $contact, \%errors ]);
+
+ # Special form disabling form
+ if ($c->get_param('disable')) {
+ my $msg = $c->get_param('disable_message');
+ $errors{category} = _('Please enter a message') unless $msg;
+ my $meta = {
+ code => '_fms_disable_',
+ variable => 'false',
+ protected => 'true',
+ disable_form => 'true',
+ description => $msg,
+ };
+ $contact->update_extra_field($meta);
+ } else {
+ $contact->remove_extra_field('_fms_disable_');
+ }
+
+ if ( %errors ) {
+ $c->stash->{updated} = _('Please correct the errors below');
+ $c->stash->{contact} = $contact;
+ $c->stash->{errors} = \%errors;
+ } elsif ( $contact->in_storage ) {
+ $c->stash->{updated} = _('Values updated');
+
+ # NB: History is automatically stored by a trigger in the database
+ $contact->update;
+ } else {
+ $c->stash->{updated} = _('New category contact added');
+ $contact->insert;
+ }
+
+ unless ( %errors ) {
+ $c->stash->{translation_col} = 'category';
+ $c->stash->{object} = $contact;
+ $c->forward('update_translations');
+ }
+
+}
+
+sub confirm_contacts : Private {
+ my ( $self, $c ) = @_;
+
+ $c->forward('/auth/check_csrf_token');
+
+ my @categories = $c->get_param_list('confirmed');
+
+ my $contacts = $c->model('DB::Contact')->search(
+ {
+ body_id => $c->stash->{body_id},
+ category => { -in => \@categories },
}
+ );
- unless ( %errors ) {
- $c->stash->{translation_col} = 'category';
- $c->stash->{object} = $contact;
- $c->forward('update_translations');
+ my $editor = $c->forward('/admin/get_user');
+ $contacts->update(
+ {
+ state => 'confirmed',
+ whenedited => \'current_timestamp',
+ note => 'Confirmed',
+ editor => $editor,
}
+ );
- } elsif ( $posted eq 'update' ) {
- $c->forward('/auth/check_csrf_token');
+ $c->stash->{updated} = _('Values updated');
+}
- my @categories = $c->get_param_list('confirmed');
+sub update_body : Private {
+ my ($self, $c, $body, $msg) = @_;
- my $contacts = $c->model('DB::Contact')->search(
- {
- body_id => $c->stash->{body_id},
- category => { -in => \@categories },
- }
- );
-
- $contacts->update(
- {
- state => 'confirmed',
- whenedited => \'current_timestamp',
- note => 'Confirmed',
- editor => $editor,
- }
- );
+ $c->forward('check_for_super_user');
+ $c->forward('/auth/check_csrf_token');
- $c->stash->{updated} = _('Values updated');
- } elsif ( $posted eq 'body' ) {
- $c->forward('check_for_super_user');
- $c->forward('/auth/check_csrf_token');
-
- my $values = $c->forward( 'body_params' );
- unless ( keys %{$c->stash->{body_errors}} ) {
- $c->stash->{body}->update( $values->{params} );
- if ($values->{extras}) {
- $c->stash->{body}->set_extra_metadata( $_ => $values->{extras}->{$_} )
- for keys %{$values->{extras}};
- $c->stash->{body}->update;
- }
- my @current = $c->stash->{body}->body_areas->all;
- my %current = map { $_->area_id => 1 } @current;
- my @area_ids = $c->get_param_list('area_ids');
- foreach (@area_ids) {
- $c->model('DB::BodyArea')->find_or_create( { body => $c->stash->{body}, area_id => $_ } );
- delete $current{$_};
- }
- # Remove any others
- $c->stash->{body}->body_areas->search( { area_id => [ keys %current ] } )->delete;
+ my $values = $c->forward('body_params');
+ return if %{$c->stash->{body_errors}};
- $c->stash->{translation_col} = 'name';
- $c->stash->{object} = $c->stash->{body};
- $c->forward('update_translations');
+ if ($body) {
+ $body->update( $values->{params} );
+ } else {
+ $body = $c->model('DB::Body')->create( $values->{params} );
+ }
- $c->stash->{updated} = _('Values updated');
- }
+ if ($values->{extras}) {
+ $body->set_extra_metadata( $_ => $values->{extras}->{$_} )
+ for keys %{$values->{extras}};
+ $body->update;
}
+ my @current = $body->body_areas->all;
+ my %current = map { $_->area_id => 1 } @current;
+ my @area_ids = $c->get_param_list('area_ids');
+ foreach (@area_ids) {
+ $c->model('DB::BodyArea')->find_or_create( { body => $body, area_id => $_ } );
+ delete $current{$_};
+ }
+ # Remove any others
+ $body->body_areas->search( { area_id => [ keys %current ] } )->delete;
+
+ $c->stash->{translation_col} = 'name';
+ $c->stash->{object} = $body;
+ $c->forward('update_translations');
+
+ $c->stash->{updated} = $msg;
}
sub body_params : Private {
@@ -417,12 +434,13 @@ sub check_body_params : Private {
}
sub contact_cobrand_extra_fields : Private {
- my ( $self, $c, $contact ) = @_;
+ my ( $self, $c, $contact, $errors ) = @_;
my $extra_fields = $c->cobrand->call_hook('contact_extra_fields');
foreach ( @$extra_fields ) {
$contact->set_extra_metadata( $_ => $c->get_param("extra[$_]") );
}
+ $c->cobrand->call_hook(contact_extra_fields_validation => $contact, $errors);
}
sub fetch_translations : Private {
diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm
index ed890ad82..b181acd04 100644
--- a/perllib/FixMyStreet/App/Controller/My.pm
+++ b/perllib/FixMyStreet/App/Controller/My.pm
@@ -161,7 +161,7 @@ sub setup_page_data : Private {
my @categories = $c->stash->{problems_rs}->search({
state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
}, {
- columns => [ 'category' ],
+ columns => [ 'category', 'bodies_str' ],
distinct => 1,
order_by => [ 'category' ],
} )->all;
diff --git a/perllib/FixMyStreet/Cobrand/BathNES.pm b/perllib/FixMyStreet/Cobrand/BathNES.pm
index b6014a276..6de28bca8 100644
--- a/perllib/FixMyStreet/Cobrand/BathNES.pm
+++ b/perllib/FixMyStreet/Cobrand/BathNES.pm
@@ -27,6 +27,19 @@ sub get_geocoder {
return 'OSM'; # default of Bing gives poor results, let's try overriding.
}
+sub contact_extra_fields { [ 'display_name' ] }
+
+sub contact_extra_fields_validation {
+ my ($self, $contact, $errors) = @_;
+ return unless $contact->get_extra_metadata('display_name');
+
+ my @contacts = $contact->body->contacts->not_deleted->search({ id => { '!=', $contact->id } });
+ my %display_names = map { $_->get_extra_metadata('display_name') => 1 } @contacts;
+ if ($display_names{$contact->get_extra_metadata('display_name')}) {
+ $errors->{display_name} = 'That display name is already in use';
+ }
+}
+
sub disambiguate_location {
my $self = shift;
my $string = shift;
diff --git a/perllib/FixMyStreet/Cobrand/Bexley.pm b/perllib/FixMyStreet/Cobrand/Bexley.pm
index 0fbb8944b..1a303d633 100644
--- a/perllib/FixMyStreet/Cobrand/Bexley.pm
+++ b/perllib/FixMyStreet/Cobrand/Bexley.pm
@@ -31,10 +31,7 @@ sub open311_munge_update_params {
$params->{service_request_id_ext} = $comment->problem->id;
- my $contact = $comment->result_source->schema->resultset("Contact")->not_deleted->find({
- body_id => $body->id,
- category => $comment->problem->category
- });
+ my $contact = $comment->problem->category_row;
$params->{service_code} = $contact->email;
}
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index a99915fb4..d8695683c 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -95,7 +95,7 @@ __PACKAGE__->many_to_many( defect_types => 'contact_defect_types', 'defect_type'
sub category_display {
my $self = shift;
- $self->translate_column('category');
+ $self->get_extra_metadata('display_name') || $self->translate_column('category');
}
sub groups {
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 08b768719..97f0666e0 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -404,7 +404,28 @@ sub confirm {
sub category_display {
my $self = shift;
- $self->translate_column('category');
+ my $contact = $self->category_row;
+ return $self->category unless $contact; # Fallback; shouldn't happen, but some tests
+ return $contact->category_display;
+}
+
+=head2 category_row
+
+Returns the corresponding Contact object for this problem's category and body.
+If the report was sent to multiple bodies, only returns the first.
+
+=cut
+
+sub category_row {
+ my $self = shift;
+ my $schema = $self->result_source->schema;
+ my $body_id = $self->bodies_str_ids->[0];
+ return unless $body_id && $body_id =~ /^[0-9]+$/;
+ my $contact = $schema->resultset("Contact")->find({
+ body_id => $body_id,
+ category => $self->category,
+ });
+ return $contact;
}
sub bodies_str_ids {
diff --git a/perllib/FixMyStreet/Roles/Translatable.pm b/perllib/FixMyStreet/Roles/Translatable.pm
index d39d97bf8..0c84bbf0f 100644
--- a/perllib/FixMyStreet/Roles/Translatable.pm
+++ b/perllib/FixMyStreet/Roles/Translatable.pm
@@ -40,19 +40,6 @@ sub _translate {
my $translated = $self->translated->{$col}{$lang};
return $translated if $translated;
- # Deal with the fact problem table has denormalized copy of category string
- if ($table eq 'problem' && $col eq 'category') {
- my $body_id = $self->bodies_str_ids->[0];
- return $fallback unless $body_id && $body_id =~ /^[0-9]+$/;
- my $contact = $schema->resultset("Contact")->find( {
- body_id => $body_id,
- category => $fallback,
- } );
- return $fallback unless $contact; # Shouldn't happen, but some tests
- $table = 'contact';
- $id = $contact->id;
- }
-
if (ref $schema) {
my $translation = $schema->resultset('Translation')->find({
lang => $lang,
diff --git a/t/app/controller/admin/bodies.t b/t/app/controller/admin/bodies.t
index 75f0f606f..cd86e3da6 100644
--- a/t/app/controller/admin/bodies.t
+++ b/t/app/controller/admin/bodies.t
@@ -51,7 +51,7 @@ subtest 'check contact creation' => sub {
non_public => 'on',
} } );
$mech->get_ok('/admin/body/' . $body->id . '/test/category');
- $mech->content_contains('<h1>test/category</h1>');
+ $mech->content_contains('test/category');
};
subtest 'check contact editing' => sub {
@@ -91,6 +91,21 @@ subtest 'check contact editing' => sub {
$mech->content_contains( '<td><strong>test2@example.com' );
};
+subtest 'check contact renaming' => sub {
+ my ($report) = $mech->create_problems_for_body(1, $body->id, 'Title', { category => 'test category' });
+ $mech->get_ok('/admin/body/' . $body->id .'/test%20category');
+ $mech->submit_form_ok( { with_fields => { category => 'private category' } } );
+ $mech->content_contains('You cannot rename');
+ $mech->submit_form_ok( { with_fields => { category => 'testing category' } } );
+ $mech->content_contains( 'testing category' );
+ $mech->get('/admin/body/' . $body->id . '/test%20category');
+ is $mech->res->code, 404;
+ $mech->get_ok('/admin/body/' . $body->id . '/testing%20category');
+ $report->discard_changes;
+ is $report->category, 'testing category';
+ $mech->submit_form_ok( { with_fields => { category => 'test category' } } );
+};
+
subtest 'check contact updating' => sub {
$mech->get_ok('/admin/body/' . $body->id . '/test%20category');
$mech->content_like(qr{test2\@example.com</strong>[^<]*</td>[^<]*<td>unconfirmed}s);
diff --git a/t/app/controller/admin/translations.t b/t/app/controller/admin/translations.t
index f5c32baa6..442be68d5 100644
--- a/t/app/controller/admin/translations.t
+++ b/t/app/controller/admin/translations.t
@@ -59,7 +59,7 @@ subtest 'check add category with translation' => sub {
$mech->submit_form_ok( { with_fields => {
category => 'Potholes',
translation_de => 'DE potholes',
- email => 'potholes@example.org',
+ email => 'potholes',
} } );
# check that error page includes translations
diff --git a/t/cobrand/bathnes.t b/t/cobrand/bathnes.t
index d434d1160..42a8ffe93 100644
--- a/t/cobrand/bathnes.t
+++ b/t/cobrand/bathnes.t
@@ -1,6 +1,10 @@
+use Test::MockModule;
use FixMyStreet::TestMech;
my $mech = FixMyStreet::TestMech->new;
+my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::BathNES');
+$cobrand->mock('area_types', sub { [ 'UTA' ] });
+
my $body = $mech->create_body_ok(2551, 'Bath and North East Somerset Council');
my @cats = ('Litter', 'Other', 'Potholes', 'Traffic lights');
for my $contact ( @cats ) {
@@ -59,6 +63,20 @@ subtest 'cobrand displays council name' => sub {
$mech->content_like( qr/Bath and North East Somerset\b/ );
};
+subtest 'check override contact display name' => sub {
+ $mech->log_in_ok( $superuser->email );
+ $mech->get_ok("/admin/body/" . $body->id . '/Litter');
+ $mech->content_contains('<h1>Litter</h1>');
+ $mech->content_contains('extra[display_name]');
+ $mech->submit_form_ok({ with_fields => {
+ 'extra[display_name]' => 'Wittering'
+ }});
+ $mech->get_ok('/reports/Bath+and+North+East+Somerset');
+ $mech->content_contains('Wittering</option>');
+ $mech->content_contains('value="Litter"');
+ $mech->content_lacks('Litter</option>');
+};
+
subtest 'extra CSV columns are absent if permission not granted' => sub {
$mech->log_in_ok( $counciluser->email );
diff --git a/t/roles/translatable.t b/t/roles/translatable.t
index e13f49fc6..9f8c67394 100644
--- a/t/roles/translatable.t
+++ b/t/roles/translatable.t
@@ -74,4 +74,11 @@ FixMyStreet::override_config {
$mech->content_contains('Hull i veien');
};
+subtest 'Check display_name override' => sub {
+ $contact->set_extra_metadata( display_name => 'Override name' );
+ $contact->update;
+ is $contact->category_display, "Override name";
+ is $problem->category_display, "Override name";
+};
+
done_testing;
diff --git a/templates/web/base/admin/bodies/_category_field.html b/templates/web/base/admin/bodies/_category_field.html
new file mode 100644
index 000000000..8c5a1c352
--- /dev/null
+++ b/templates/web/base/admin/bodies/_category_field.html
@@ -0,0 +1,17 @@
+<div class="admin-hint">
+ <p>
+ [% loc('Choose a <strong>category</strong> name that makes sense to the public (e.g., "Pothole", "Street lighting") but is helpful
+ to the body too. These will appear in the drop-down menu on the report-a-problem page.') %]
+ <br>
+ [% loc("If two or more bodies serve the same location, FixMyStreet combines identical categories into a single entry in
+ the menu. Make sure you use the same category name in the bodies if you want this to happen.") %]
+ </p>
+</div>
+
+<p>
+ <strong>[% loc('Category') %] </strong><input type="text" class="form-control" name="category" size="30" value="[% contact.category | html %]" required>
+</p>
+
+[% IF contact.in_storage %]
+ <input type="hidden" name="current_category" value="[% current_contact.category | html %]" >
+[% END %]
diff --git a/templates/web/base/admin/bodies/contact-form.html b/templates/web/base/admin/bodies/contact-form.html
index 7f559274d..ba47327cd 100644
--- a/templates/web/base/admin/bodies/contact-form.html
+++ b/templates/web/base/admin/bodies/contact-form.html
@@ -1,24 +1,6 @@
<form method="post" action="[% c.uri_for_action('admin/bodies/edit', [ body_id ] ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8" id="category_edit">
- [% IF contact.in_storage %]
- <p>
- <h1>[% contact.category_display | html %]</h1>
- <input type="hidden" name="category" value="[% contact.category | html %]" >
- </p>
- [% ELSE %]
- <div class="admin-hint">
- <p>
- [% loc('Choose a <strong>category</strong> name that makes sense to the public (e.g., "Pothole", "Street lighting") but is helpful
- to the body too. These will appear in the drop-down menu on the report-a-problem page.') %]
- <br>
- [% loc("If two or more bodies serve the same location, FixMyStreet combines identical categories into a single entry in
- the menu. Make sure you use the same category name in the bodies if you want this to happen.") %]
- </p>
- </div>
- <p>
- <strong>[% loc('Category') %] </strong><input type="text" class="form-control" name="category" size="30" value="[% contact.category | html %]" required>
- </p>
- [% END %]
+ [% PROCESS 'admin/bodies/_category_field.html' %]
[% INCLUDE 'admin/bodies/_translations.html' %]
@@ -143,7 +125,7 @@
<p class="form-group" style="margin-top: 2em">
<label for="note">[% loc('Summarise your changes') %]</label>
<span class="form-hint" id="note-hint">[% loc("If you’ve made changes, leave a note explaining what, for other admins to see.") %]</span>
- <input class="form-control" type="text" id="note" name="note" size="30" aria-describedby="note-hint" required>
+ <input class="form-control" type="text" id="note" name="note" size="30" aria-describedby="note-hint"[% ' required' UNLESS c.config.STAGING_SITE %]>
</p>
<p>
diff --git a/templates/web/bathnes/admin/bodies/_category_field.html b/templates/web/bathnes/admin/bodies/_category_field.html
new file mode 100644
index 000000000..6497e3511
--- /dev/null
+++ b/templates/web/bathnes/admin/bodies/_category_field.html
@@ -0,0 +1,21 @@
+[% IF contact.in_storage %]
+ <h1>[% contact.category | html %]</h1>
+ <input type="hidden" name="category" value="[% contact.category | html %]" >
+
+ <div class="admin-hint">
+ <p>A display name will be used in preference to the main category name on web pages and dropdown menus, but not in URLs.</p>
+ </div>
+
+ <p>
+ <label>
+ Display name:
+ <input type="text" class="form-control" name="extra[display_name]" id="display_name"
+ value="[% contact.get_extra_metadata('display_name') | html %]" size="30">
+ </label>
+ </p>
+
+[% ELSE %]
+ <p>
+ <strong>[% loc('Category') %] </strong><input type="text" class="form-control" name="category" size="30" value="[% contact.category | html %]" required>
+ </p>
+[% END %]
diff --git a/web/cobrands/fixmystreet/staff.js b/web/cobrands/fixmystreet/staff.js
index 86e9bf449..a504f641e 100644
--- a/web/cobrands/fixmystreet/staff.js
+++ b/web/cobrands/fixmystreet/staff.js
@@ -369,7 +369,7 @@ $(fixmystreet).on('display:report', function() {
$(fixmystreet).on('report_new:category_change', function() {
var $this = $('#form_category');
- var category = $this.val();
+ var category = $this.find("option:selected").text();
if (category === '-- Pick a category --') { return; }
var prefill_reports = $this.data('prefill');
var display_names = fixmystreet.reporting_data ? fixmystreet.reporting_data.display_names || {} : {};