diff options
29 files changed, 525 insertions, 325 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index dae414090..d1771247c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Releases * Unreleased + - Bugfixes: + - Prevent creation of two templates with same title. - Development improvements: - Upgrade the underlying framework and a number of other packages. diff --git a/docs/install/ami.md b/docs/install/ami.md index fd283945a..5b7c31e0a 100644 --- a/docs/install/ami.md +++ b/docs/install/ami.md @@ -24,9 +24,9 @@ for a year](http://aws.amazon.com/free/). ### Using our pre-built AMI The AMI we've prepared for you can be found in the **EU West (Ireland)** -region, with the ID `ami-05386aa7b2b4faee9` and name "FixMyStreet installation -full 2018-12-21". You can launch an instance based on that AMI with -[this link](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchAmi=ami-05386aa7b2b4faee9). +region, with the ID `ami-0351dd8e5e3bfb51d` and name "FixMyStreet installation +full 2019-05-03". You can launch an instance based on that AMI with +[this link](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchAmi=ami-0351dd8e5e3bfb51d). This AMI is based on the [latest tagged release](https://github.com/mysociety/fixmystreet/releases) and contains everything you need to get a base install up and running. diff --git a/perllib/Catalyst/Authentication/Store/FixMyStreetUser.pm b/perllib/Catalyst/Authentication/Store/FixMyStreetUser.pm new file mode 100644 index 000000000..240f4b1de --- /dev/null +++ b/perllib/Catalyst/Authentication/Store/FixMyStreetUser.pm @@ -0,0 +1,54 @@ +package Catalyst::Authentication::Store::FixMyStreetUser; + +use Moose; +use namespace::autoclean; +extends 'Catalyst::Authentication::Store::DBIx::Class::User'; + +use Carp; +use Try::Tiny; + +sub AUTOLOAD { + my $self = shift; + (my $method) = (our $AUTOLOAD =~ /([^:]+)$/); + return if $method eq "DESTROY"; + + if (my $code = $self->_user->can($method)) { + return $self->_user->$code(@_); + } + elsif (my $accessor = + try { $self->_user->result_source->column_info($method)->{accessor} }) { + return $self->_user->$accessor(@_); + } else { + croak sprintf("Can't locate object method '%s'", $method); + } +} + +__PACKAGE__->meta->make_immutable(inline_constructor => 0); + +1; +__END__ + +=head1 NAME + +Catalyst::Authentication::Store::FixMyStreetUser - The backing user +class for the Catalyst::Authentication::Store::DBIx::Class storage +module, adjusted to die on unknown lookups. + +=head1 DESCRIPTION + +The Catalyst::Authentication::Store::FixMyStreetUser class implements user +storage connected to an underlying DBIx::Class schema object. + +=head1 SUBROUTINES / METHODS + +=head2 AUTOLOAD + +Delegates method calls to the underlying user row. +Unlike the default, dies if an unknown method is called. + +=head1 LICENSE + +Copyright (c) 2007-2019. All rights reserved. This program is free software; +you can redistribute it and/or modify it under the same terms as Perl itself. + +=cut diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm index aa8d04988..27a5a4580 100644 --- a/perllib/FixMyStreet/App.pm +++ b/perllib/FixMyStreet/App.pm @@ -33,6 +33,12 @@ extends 'Catalyst'; our $VERSION = '0.01'; +my $store = { # Catalyst::Authentication::Store::DBIx::Class + class => 'DBIx::Class', + user_model => 'DB::User', + store_user_class => 'Catalyst::Authentication::Store::FixMyStreetUser', +}; + __PACKAGE__->config( # Use REQUEST_URI, not PATH_INFO, to infer path. This fixes an issue @@ -80,20 +86,14 @@ __PACKAGE__->config( }, ], }, - store => { # Catalyst::Authentication::Store::DBIx::Class - class => 'DBIx::Class', - user_model => 'DB::User', - }, + store => $store, }, no_password => { # use post confirm etc credential => { # Catalyst::Authentication::Credential::Password class => 'Password', password_type => 'none', }, - store => { # Catalyst::Authentication::Store::DBIx::Class - class => 'DBIx::Class', - user_model => 'DB::User', - }, + store => $store, }, access_token => { use_session => 0, @@ -103,10 +103,7 @@ __PACKAGE__->config( # This means the token has to be 18 characters long (as generated by AuthToken) token_lookup => { like => "%access_token,T18:TOKEN,%" }, }, - store => { - class => 'DBIx::Class', - user_model => 'DB::User', - }, + store => $store, }, }, ); diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 2f4669456..6167a16f5 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -535,8 +535,8 @@ sub report_edit : Path('report_edit') : Args(1) { $self->remove_photo($c, $problem, $remove_photo_param); } - if ($problem->state eq 'hidden') { - $problem->get_photoset->delete_cached; + if ($problem->state eq 'hidden' || $problem->non_public) { + $problem->get_photoset->delete_cached(plus_updates => 1); } if ( $problem->is_visible() and $old_state eq 'unconfirmed' ) { @@ -782,6 +782,15 @@ sub template_edit : Path('templates') : Args(2) { } $template->title( $c->get_param('title') ); + my $query = { title => $template->title }; + if ($template->in_storage) { + $query->{id} = { '!=', $template->id }; + } + if ($c->stash->{body}->response_templates->search($query)->count) { + $c->stash->{errors} ||= {}; + $c->stash->{errors}->{title} = _("There is already a template with that title."); + } + $template->text( $c->get_param('text') ); $template->state( $c->get_param('state') ); $template->external_status_code( $c->get_param('external_status_code') ); diff --git a/perllib/FixMyStreet/App/Controller/Admin/Users.pm b/perllib/FixMyStreet/App/Controller/Admin/Users.pm index bcbc808ed..6af4ae831 100644 --- a/perllib/FixMyStreet/App/Controller/Admin/Users.pm +++ b/perllib/FixMyStreet/App/Controller/Admin/Users.pm @@ -497,7 +497,7 @@ sub user_hide_everywhere : Private { my ( $self, $c, $user ) = @_; my $problems = $user->problems->search({ state => { '!=' => 'hidden' } }); while (my $problem = $problems->next) { - $problem->get_photoset->delete_cached; + $problem->get_photoset->delete_cached(plus_updates => 1); $problem->update({ state => 'hidden' }); } my $updates = $user->comments->search({ state => { '!=' => 'hidden' } }); diff --git a/perllib/FixMyStreet/App/Controller/Moderate.pm b/perllib/FixMyStreet/App/Controller/Moderate.pm index 22869d531..f71698e84 100644 --- a/perllib/FixMyStreet/App/Controller/Moderate.pm +++ b/perllib/FixMyStreet/App/Controller/Moderate.pm @@ -214,7 +214,7 @@ sub report_moderate_hide : Private { if ($c->get_param('problem_hide')) { $problem->update({ state => 'hidden' }); - $problem->get_photoset->delete_cached; + $problem->get_photoset->delete_cached(plus_updates => 1); $c->res->redirect( '/' ); # Go directly to front-page $c->detach( 'report_moderate_audit', ['hide'] ); # break chain here. diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm index 7b536a292..d7a5b4bb3 100644 --- a/perllib/FixMyStreet/App/Controller/Photo.pm +++ b/perllib/FixMyStreet/App/Controller/Photo.pm @@ -39,6 +39,7 @@ sub during :LocalRegex('^(temp|fulltemp)\.([0-9a-f]{40}\.(?:jpeg|png|gif|tiff))$ $size = $size eq 'temp' ? 'default' : 'full'; my $photo = $photoset->get_image_data(size => $size, default => $c->cobrand->default_photo_resize); + $c->stash->{non_public} = 0; $c->forward( 'output', [ $photo ] ); } @@ -52,10 +53,11 @@ sub index :LocalRegex('^(c/)?([1-9]\d*)(?:\.(\d+))?(?:\.(full|tn|fp))?\.(?:jpeg| my $item; if ( $is_update ) { ($item) = $c->model('DB::Comment')->search( { - id => $id, - state => 'confirmed', - photo => { '!=', undef }, - } ); + 'me.id' => $id, + 'me.state' => 'confirmed', + 'problem.state' => [ FixMyStreet::DB::Result::Problem->visible_states() ], + 'me.photo' => { '!=', undef }, + }, { prefetch => 'problem' }); } else { ($item) = $c->cobrand->problems->search( { id => $id, @@ -68,6 +70,19 @@ sub index :LocalRegex('^(c/)?([1-9]\d*)(?:\.(\d+))?(?:\.(full|tn|fp))?\.(?:jpeg| $c->detach( 'no_photo' ) unless $c->cobrand->allow_photo_display($item, $photo_number); # Should only be for reports, not updates + my $problem = $is_update ? $item->problem : $item; + $c->stash->{non_public} = $problem->non_public; + + if ($c->stash->{non_public}) { + my $body_ids = $problem->bodies_str_ids; + # Check permission + $c->detach('no_photo') unless $c->user_exists; + $c->detach('no_photo') unless $c->user->is_superuser + || $c->user->id == $problem->user->id + || $c->user->has_permission_to('report_inspect', $body_ids) + || $c->user->has_permission_to('report_mark_private', $body_ids); + } + my $photo; $photo = $item->get_photoset ->get_image_data( num => $photo_number, size => $size, default => $c->cobrand->default_photo_resize ) @@ -80,10 +95,12 @@ sub output : Private { my ( $self, $c, $photo ) = @_; # Save to file - path(FixMyStreet->path_to('web', 'photo', 'c'))->mkpath; - my $out = FixMyStreet->path_to('web', $c->req->path); - my $symlink_exists = $photo->{symlink} ? symlink($photo->{symlink}, $out) : undef; - path($out)->spew_raw($photo->{data}) unless $symlink_exists; + if (!FixMyStreet->config('LOGIN_REQUIRED') && !$c->stash->{non_public}) { + path(FixMyStreet->path_to('web', 'photo', 'c'))->mkpath; + my $out = FixMyStreet->path_to('web', $c->req->path); + my $symlink_exists = $photo->{symlink} ? symlink($photo->{symlink}, $out) : undef; + path($out)->spew_raw($photo->{data}) unless $symlink_exists; + } $c->res->content_type( $photo->{content_type} ); $c->res->body( $photo->{data} ); diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 7f798f4f4..f2f411635 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -435,7 +435,7 @@ sub inspect : Private { $problem->confirmed( \'current_timestamp' ); } if ( $problem->state eq 'hidden' ) { - $problem->get_photoset->delete_cached; + $problem->get_photoset->delete_cached(plus_updates => 1); } if ( $problem->state eq 'duplicate') { if (my $duplicate_of = $c->get_param('duplicate_of')) { @@ -477,6 +477,9 @@ sub inspect : Private { } $problem->non_public($c->get_param('non_public') ? 1 : 0); + if ($problem->non_public) { + $problem->get_photoset->delete_cached(plus_updates => 1); + } if ( !$c->forward( '/admin/report_edit_location', [ $problem ] ) ) { # New lat/lon isn't valid, show an error diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index b352b049e..fc5176a07 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -659,7 +659,7 @@ sub check_non_public_reports_permission : Private { if ( $c->user_exists ) { my $user_has_permission; - if ( $c->user->is_super_user ) { + if ( $c->user->is_superuser ) { $user_has_permission = 1; } else { my $body = $c->stash->{body}; diff --git a/perllib/FixMyStreet/App/Model/PhotoSet.pm b/perllib/FixMyStreet/App/Model/PhotoSet.pm index 58b352c73..8621286b0 100644 --- a/perllib/FixMyStreet/App/Model/PhotoSet.pm +++ b/perllib/FixMyStreet/App/Model/PhotoSet.pm @@ -235,7 +235,7 @@ sub get_image_data { } sub delete_cached { - my ($self) = @_; + my ($self, %params) = @_; my $object = $self->object or return; my $id = $object->id or return; @@ -256,6 +256,11 @@ sub delete_cached { unlink FixMyStreet->path_to(@dirs, "$id.$i$size.$type"); } } + + # Loop through all the updates as well if requested + if ($params{plus_updates}) { + $_->get_photoset->delete_cached() foreach $object->comments->all; + } } sub remove_images { diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm index dae946816..4f7c1dc5f 100644 --- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm +++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm @@ -158,7 +158,7 @@ sub _recent { # Need to reattach schema so that confirmed column gets reinflated. $probs->[0]->result_source->schema( $rs->result_source->schema ) if $probs->[0]; # Catch any cached ones since hidden - $probs = [ grep { $_->photo && ! $_->is_hidden } @$probs ]; + $probs = [ grep { $_->photo && ! $_->is_hidden && !$_->non_public } @$probs ]; } else { $probs = [ $rs->search( $query, $attrs )->all ]; Memcached::set($key, $probs, _cache_timeout()); diff --git a/perllib/FixMyStreet/Roles/PhotoSet.pm b/perllib/FixMyStreet/Roles/PhotoSet.pm index 4a40ef3f9..27a63bad5 100644 --- a/perllib/FixMyStreet/Roles/PhotoSet.pm +++ b/perllib/FixMyStreet/Roles/PhotoSet.pm @@ -38,15 +38,18 @@ sub photos { my $id = $self->id; my $typ = $self->result_source->name eq 'comment' ? 'c/' : ''; + my $non_public = $self->result_source->name eq 'comment' + ? $self->problem->non_public : $self->non_public; + my @photos = map { my $cachebust = substr($_, 0, 8); # Some Varnish configurations (e.g. on mySociety infra) strip cookies from # images, which means image requests will be redirected to the login page - # if LOGIN_REQUIRED is set. To stop this happening, Varnish should be + # if e.g. LOGIN_REQUIRED is set. To stop this happening, Varnish should be # configured to not strip cookies if the cookie_passthrough param is # present, which this line ensures will be if LOGIN_REQUIRED is set. my $extra = ''; - if (FixMyStreet->config('LOGIN_REQUIRED')) { + if (FixMyStreet->config('LOGIN_REQUIRED') || $non_public) { $cachebust .= '&cookie_passthrough=1'; $extra = '?cookie_passthrough=1'; } diff --git a/t/app/controller/admin/templates.t b/t/app/controller/admin/templates.t index 0d4430cad..6944f4b04 100644 --- a/t/app/controller/admin/templates.t +++ b/t/app/controller/admin/templates.t @@ -66,6 +66,30 @@ subtest "response templates can be added" => sub { is $oxfordshire->response_templates->count, 1, "Response template was added"; }; +subtest "but not another with the same title" => sub { + my $fields = { + title => "Report acknowledgement", + text => "Another report acknowledgement.", + auto_response => undef, + "contacts[".$oxfordshirecontact->id."]" => 1, + }; + my $list_url = "/admin/templates/" . $oxfordshire->id; + $mech->get_ok( "$list_url/new" ); + $mech->submit_form_ok( { with_fields => $fields } ); + is $mech->uri->path, "$list_url/new", 'not redirected'; + $mech->content_contains( 'Please correct the errors below' ); + $mech->content_contains( 'There is already a template with that title.' ); + + my @ts = $oxfordshire->response_templates->all; + is @ts, 1, "No new response template was added"; + + my $url = "$list_url/" . $ts[0]->id; + $mech->get_ok($url); + $mech->submit_form_ok( { with_fields => $fields } ); + is $mech->uri->path, $list_url, 'redirected'; + is $oxfordshire->response_templates->count, 1, "No new response template was added"; +}; + subtest "response templates are included on page" => sub { FixMyStreet::override_config { ALLOWED_COBRANDS => [ 'oxfordshire' ], diff --git a/t/app/controller/photo.t b/t/app/controller/photo.t index 842daa0dc..e1bf35fcf 100644 --- a/t/app/controller/photo.t +++ b/t/app/controller/photo.t @@ -13,7 +13,7 @@ my $mech = FixMyStreet::TestMech->new; my $sample_file = path(__FILE__)->parent->child("sample.jpg"); ok $sample_file->exists, "sample file $sample_file exists"; -my $westminster = $mech->create_body_ok(2527, 'Liverpool City Council'); +my $body = $mech->create_body_ok(2527, 'Liverpool City Council'); subtest "Check multiple upload worked" => sub { $mech->get_ok('/around'); @@ -112,4 +112,73 @@ subtest "Check photo uploading URL and endpoints work" => sub { }; }; +subtest "Check no access to update photos on hidden reports" => sub { + my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); + + my ($report) = $mech->create_problems_for_body(1, $body->id, 'Title'); + my $update = $mech->create_comment_for_problem($report, $report->user, $report->name, 'Text', $report->anonymous, 'confirmed', 'confirmed', { photo => $report->photo }); + + FixMyStreet::override_config { + PHOTO_STORAGE_BACKEND => 'FileSystem', + PHOTO_STORAGE_OPTIONS => { + UPLOAD_DIR => $UPLOAD_DIR, + }, + }, sub { + my $image_path = path('t/app/controller/sample.jpg'); + $image_path->copy( path($UPLOAD_DIR, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg') ); + + $mech->get_ok('/photo/c/' . $update->id . '.0.jpeg'); + + $report->update({ state => 'hidden' }); + $report->get_photoset->delete_cached(plus_updates => 1); + + my $res = $mech->get('/photo/c/' . $update->id . '.0.jpeg'); + is $res->code, 404, 'got 404'; + }; +}; + +subtest 'non_public photos only viewable by correct people' => sub { + my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); + path(FixMyStreet->path_to('web/photo'))->remove_tree({ keep_root => 1 }); + + my ($report) = $mech->create_problems_for_body(1, $body->id, 'Title', { + non_public => 1, + }); + + FixMyStreet::override_config { + PHOTO_STORAGE_BACKEND => 'FileSystem', + PHOTO_STORAGE_OPTIONS => { + UPLOAD_DIR => $UPLOAD_DIR, + }, + }, sub { + my $image_path = path('t/app/controller/sample.jpg'); + $image_path->copy( path($UPLOAD_DIR, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg') ); + + $mech->log_out_ok; + my $i = '/photo/' . $report->id . '.0.jpeg'; + my $res = $mech->get($i); + is $res->code, 404, 'got 404'; + + $mech->log_in_ok('test@example.com'); + $i = '/photo/' . $report->id . '.0.jpeg'; + $mech->get_ok($i); + my $image_file = FixMyStreet->path_to("web$i"); + ok !-e $image_file, 'File not cached out'; + + my $user = $mech->log_in_ok('someoneelse@example.com'); + $i = '/photo/' . $report->id . '.0.jpeg'; + $res = $mech->get($i); + is $res->code, 404, 'got 404'; + + $user->update({ from_body => $body }); + $user->user_body_permissions->create({ body => $body, permission_type => 'report_inspect' }); + $i = '/photo/' . $report->id . '.0.jpeg'; + $mech->get_ok($i); + + $user->update({ from_body => undef, is_superuser => 1 }); + $i = '/photo/' . $report->id . '.0.jpeg'; + $mech->get_ok($i); + }; +}; + done_testing(); diff --git a/t/app/model/user.t b/t/app/model/user.t index 5a9c898a2..cbc0fe6cf 100644 --- a/t/app/model/user.t +++ b/t/app/model/user.t @@ -1,5 +1,8 @@ use FixMyStreet::TestMech; use FixMyStreet::DB; +use Catalyst::Test 'FixMyStreet::App'; +use HTTP::Request::Common; +use Test::Exception; my $mech = FixMyStreet::TestMech->new(); $mech->log_in_ok('test@example.com'); @@ -63,9 +66,16 @@ FixMyStreet::override_config { $mech->content_like(qr/may_show_name[^>c]*>/); }; -END { - done_testing(); -} +subtest 'Check non-existent methods on user object die' => sub { + my $c = ctx_request(POST '/auth', { username => 'test@example.com', password_sign_in => 'secret' }); + throws_ok( + sub { $c->user->is_super_user }, + qr/Can't locate object method 'is_super_user'/, + 'attempt to call non-existent method' + ); +}; + +done_testing(); sub create_update { my ($problem, %params) = @_; diff --git a/templates/web/base/admin/report_edit.html b/templates/web/base/admin/report_edit.html index e38932d7f..a26a35c50 100644 --- a/templates/web/base/admin/report_edit.html +++ b/templates/web/base/admin/report_edit.html @@ -87,6 +87,11 @@ class="admin-offsite-link">[% problem.latitude %], [% problem.longitude %]</a> <input type="submit" class="btn" name="mark_sent" value="[% loc('Mark as sent') %]"> [% END %] </li> +[% IF c.user.is_superuser AND problem.send_fail_count > 0 %] +<li class="sm">[% loc('Send Fail Count:') %] [% problem.send_fail_count %]</li> +<li class="sm">[% loc('Last failure:') %] [% PROCESS format_time time=problem.send_fail_timestamp %]</li> +<li class="sm truncate_height">[% loc('Reason:') %] [% problem.send_fail_reason | html %]</li> +[% END %] <li class="sm">[% loc('Last update:') %] [% PROCESS format_time time=problem.lastupdate %]</li> <li>[% loc('Alerts:') %] [% alert_count %]</li> <li>[% loc('Service:') %] [% problem.service OR '<em>' _ loc('None') _ '</em>' %]</li> diff --git a/templates/web/base/admin/template_edit.html b/templates/web/base/admin/template_edit.html index 2945e36c5..87218c7dd 100644 --- a/templates/web/base/admin/template_edit.html +++ b/templates/web/base/admin/template_edit.html @@ -13,7 +13,9 @@ <p class="error">[% loc('Please correct the errors below') %]</p> [% END %] - + [% IF errors.title %] + <div class="form-error">[% errors.title %]</div> + [% END %] <div class="admin-hint"> <p> [% loc('This is a <strong>private</strong> name for this template so you can identify it when updating reports or editing in the admin.') %] diff --git a/templates/web/fixmystreet.com/report/new/roads_message.html b/templates/web/fixmystreet.com/report/new/roads_message.html index f6a5d903a..6d1243354 100644 --- a/templates/web/fixmystreet.com/report/new/roads_message.html +++ b/templates/web/fixmystreet.com/report/new/roads_message.html @@ -13,20 +13,10 @@ </p> </div> <div id="js-not-a-road" class="hidden js-responsibility-message"> - <p>The location you have selected doesn't appear to be on a road.</p> - <p>Please select a road on which to make a report.</p> + <p>The location you have selected doesn't appear to be on <span class="js-roads-asset" data-original="a road">a road</span>.</p> + <p>Please select <span class="js-roads-asset" data-original="a road">a road</span> on which to make a report.</p> </div> <div id="js-not-an-asset" class="hidden js-responsibility-message"> - <p>Please select <span id="js-roads-asset">an item</span> from the map on which to make a report.</p> - </div> - <div id="js-not-a-speedhump" class="hidden js-responsibility-message"> - <p>Please select <b>a speed hump</b> from the map on which to make a report.</p> - </div> - <div id="js-not-a-ped-barrier" class="hidden js-responsibility-message"> - <p>Please select <b>a pedestrian barrier</b> from the map on which to make a report.</p> - </div> - <div id="js-not-a-prow" class="hidden js-responsibility-message"> - <p>The location you have selected doesn't appear to be on a right of way.</p> - <p>Please select a right of way on which to make a report.</p> + <p>Please select <span class="js-roads-asset" data-original="an item">an item</span> from the map on which to make a report.</p> </div> </div> diff --git a/templates/web/northamptonshire/report/new/roads_message.html b/templates/web/northamptonshire/report/new/roads_message.html index a6185a668..06244b36e 100644 --- a/templates/web/northamptonshire/report/new/roads_message.html +++ b/templates/web/northamptonshire/report/new/roads_message.html @@ -1,19 +1,9 @@ <div id="js-roads-responsibility" class="box-warning hidden"> <div id="js-not-an-asset" class="hidden js-responsibility-message"> - <p>Please select <span id="js-roads-asset">an item</span> from the map on which to make a report.</p> - </div> - <div id="js-not-a-speedhump" class="hidden js-responsibility-message"> - <p>Please select <b>a speed hump</b> from the map on which to make a report.</p> - </div> - <div id="js-not-a-ped-barrier" class="hidden js-responsibility-message"> - <p>Please select <b>a pedestrian barrier</b> from the map on which to make a report.</p> - </div> - <div id="js-not-a-prow" class="hidden js-responsibility-message"> - <p>The location you have selected doesn't appear to be on a right of way.</p> - <p>Please select a right of way on which to make a report.</p> + <p>Please select <span class="js-roads-asset" data-original="an item">an item</span> from the map on which to make a report.</p> </div> <div id="js-not-a-road" class="hidden js-responsibility-message"> - <p>The location you have selected doesn't appear to be on a road.</p> - <p>Please select a road on which to make a report.</p> + <p>The location you have selected doesn't appear to be on <span class="js-roads-asset" data-original="a road">a road</span>.</p> + <p>Please select <span class="js-roads-asset" data-original="a road">a road</span> on which to make a report.</p> </div> </div> diff --git a/templates/web/zurich/admin/template_edit.html b/templates/web/zurich/admin/template_edit.html index e954d566c..b6f68106c 100644 --- a/templates/web/zurich/admin/template_edit.html +++ b/templates/web/zurich/admin/template_edit.html @@ -16,6 +16,9 @@ accept-charset="utf-8" class="validate"> + [% IF errors.title %] + <div class="form-error">[% errors.title %]</div> + [% END %] <p> <strong>[% loc('Title:') %] </strong> <input type="text" name="title" class="form-control required" size="30" value="[% rt.title| html %]"> diff --git a/web/cobrands/buckinghamshire/assets.js b/web/cobrands/buckinghamshire/assets.js index 8135fe184..66590ca71 100644 --- a/web/cobrands/buckinghamshire/assets.js +++ b/web/cobrands/buckinghamshire/assets.js @@ -229,6 +229,8 @@ var bucks_types = [ "3B", // HW: SECONDARY DISTRIBUTOR "4A", // HW: LINK ROAD "4B", // HW: LOCAL ACCESS ROAD + "98", // HW: METALLED PUBLIC FOOTPATH + "99" // HW: METALLED PUBLIC BRIDLEWAY ]; // And these are roads they don't maintain. var non_bucks_types = [ @@ -287,51 +289,11 @@ var rule_not_owned = new OpenLayers.Rule({ }); highways_style.addRules([rule_owned, rule_not_owned]); -function show_responsibility_error(id) { - hide_responsibility_errors(); - $("#js-roads-responsibility").removeClass("hidden"); - $("#js-roads-responsibility .js-responsibility-message").addClass("hidden"); - $('.js-update-coordinates').attr('href', function(i, href) { - if (href.indexOf('?') != -1) { - href = href.substring(0, href.indexOf('?')); - } - href += '?' + OpenLayers.Util.getParameterString({ - latitude: $('#fixmystreet\\.latitude').val(), - longitude: $('#fixmystreet\\.longitude').val() - }); - return href; - }); - $(id).removeClass("hidden"); -} - -function hide_responsibility_errors() { - $("#js-roads-responsibility").addClass("hidden"); - $("#js-roads-responsibility .js-responsibility-message").addClass("hidden"); -} - -function disable_report_form() { - $("#problem_form").hide(); -} - -function enable_report_form() { - $("#problem_form").show(); -} - -function is_only_body(body) { - if (fixmystreet.bodies && fixmystreet.bodies.length == 1 && fixmystreet.bodies[0] == body) { - return true; - } - return false; -} - $(fixmystreet).on('report_new:highways_change', function() { if (fixmystreet.body_overrides.get_only_send() === 'Highways England') { - hide_responsibility_errors(); - enable_report_form(); $('#bucks_dangerous_msg').hide(); } else { $('#bucks_dangerous_msg').show(); - $(fixmystreet).trigger('report_new:category_change', [ $('#form_category') ]); } }); @@ -352,54 +314,31 @@ fixmystreet.assets.add($.extend(true, {}, defaults, { all_categories: true, actions: { found: function(layer, feature) { - fixmystreet.body_overrides.allow_send(layer.fixmystreet.body); - fixmystreet.body_overrides.remove_only_send(); + var map = { + "HE": '#js-not-council-road-he', + "HWOA": '#js-not-council-road-other' + }; + var msg_id = map[feature.attributes.feature_ty] || '#js-not-council-road'; + + fixmystreet.message_controller.road_found(layer, feature, function(feature) { + if (OpenLayers.Util.indexOf(bucks_types, feature.attributes.feature_ty) != -1) { + var cat = $('select#form_category').val(); + if (cat === 'Flytipping') { + fixmystreet.body_overrides.only_send(layer.fixmystreet.body); + } + return true; + } else { + return false; + } + }, msg_id); // Make sure Flytipping related things reset $('#category_meta').show(); $('#form_road-placement').attr('required', ''); - - if (fixmystreet.assets.selectedFeature()) { - hide_responsibility_errors(); - enable_report_form(); - } else if (OpenLayers.Util.indexOf(bucks_types, feature.attributes.feature_ty) != -1) { - var cat = $('select#form_category').val(); - if (cat === 'Flytipping') { - fixmystreet.body_overrides.only_send(layer.fixmystreet.body); - } - hide_responsibility_errors(); - enable_report_form(); - } else { - // User has clicked a road that Bucks don't maintain. - - var map = { - "HE": '#js-not-council-road-he', - "HWOA": '#js-not-council-road-other' - }; - - fixmystreet.body_overrides.do_not_send(layer.fixmystreet.body); - if (is_only_body(layer.fixmystreet.body)) { - var id = map[feature.attributes.feature_ty] || '#js-not-council-road'; - show_responsibility_error(id); - disable_report_form(); - } - } }, not_found: function(layer) { - // If a feature wasn't found at the location they've clicked, it's - // probably a field or something. Show an error to that effect, - // unless an asset is selected. - fixmystreet.body_overrides.do_not_send(layer.fixmystreet.body); - fixmystreet.body_overrides.remove_only_send(); - if (fixmystreet.assets.selectedFeature()) { - fixmystreet.body_overrides.allow_send(layer.fixmystreet.body); - hide_responsibility_errors(); - enable_report_form(); - } else if (is_only_body(layer.fixmystreet.body)) { - show_responsibility_error("#js-not-a-road"); - disable_report_form(); - } + fixmystreet.message_controller.road_not_found(layer); // If flytipping is picked, we don't want to ask the extra question var cat = $('select#form_category').val(); @@ -411,6 +350,7 @@ fixmystreet.assets.add($.extend(true, {}, defaults, { } } }, + no_asset_msg_id: '#js-not-a-road', usrn: { attribute: 'site_code', field: 'site_code' @@ -465,27 +405,10 @@ fixmystreet.assets.add($.extend(true, {}, defaults, { } })); -function check_rights_of_way() { - var relevant_body = OpenLayers.Util.indexOf(fixmystreet.bodies, defaults.body) > -1; - var relevant_cat = $('#form_category').val() == 'Rights of Way'; - var relevant = relevant_body && relevant_cat; - var currently_shown = !!$('#row-message').length; - - if (relevant === currently_shown) { - // Either should be shown and already is, or shouldn't be shown and isn't - return; - } - - if (!relevant) { - $('#row-message').remove(); - $('.js-hide-if-invalid-category').show(); - return; - } - - var $msg = $('<p id="row-message" class="box-warning">If you wish to report an issue on a Public Right of Way, please use <a href="https://www.buckscc.gov.uk/services/environment/public-rights-of-way/report-a-rights-of-way-issue/">this service</a>.</p>'); - $msg.insertBefore('#js-post-category-messages'); - $('.js-hide-if-invalid-category').hide(); -} -$(fixmystreet).on('report_new:category_change', check_rights_of_way); +fixmystreet.message_controller.register_category({ + body: defaults.body, + category: 'Rights of Way', + message: 'If you wish to report an issue on a Public Right of Way, please use <a href="https://www.buckscc.gov.uk/services/environment/public-rights-of-way/report-a-rights-of-way-issue/">this service</a>.' +}); })(); diff --git a/web/cobrands/fixmystreet-uk-councils/roadworks.js b/web/cobrands/fixmystreet-uk-councils/roadworks.js index f7451f801..ea95d1d40 100644 --- a/web/cobrands/fixmystreet-uk-councils/roadworks.js +++ b/web/cobrands/fixmystreet-uk-councils/roadworks.js @@ -183,7 +183,7 @@ fixmystreet.roadworks.display_message = function(feature) { tag_top = config.tag_top || 'p', colon = config.colon ? ':' : ''; - var $msg = $('<div class="js-roadworks-message-' + feature.layer.id + ' box-warning"><' + tag_top + '>Roadworks are scheduled near this location, so you may not need to report your issue.</' + tag_top + '></div>'); + var $msg = $('<div class="js-roadworks-message js-roadworks-message-' + feature.layer.id + ' box-warning"><' + tag_top + '>Roadworks are scheduled near this location, so you may not need to report your issue.</' + tag_top + '></div>'); var $dl = $("<dl></dl>").appendTo($msg); $dl.append("<dt>Dates" + colon + "</dt>"); $dl.append($("<dd></dd>").text(start + " until " + end)); diff --git a/web/cobrands/fixmystreet/assets.js b/web/cobrands/fixmystreet/assets.js index 8b121066b..724628930 100644 --- a/web/cobrands/fixmystreet/assets.js +++ b/web/cobrands/fixmystreet/assets.js @@ -921,3 +921,194 @@ $(fixmystreet).on('body_overrides:change', function() { fixmystreet.update_public_councils_text( $('#js-councils_text').html(), bodies); }); + +/* +Handling of the form-top messaging: This handles categories that hide the form +and show a message, and categories where assets must be selected or the pin +must be on a road, taking into account Highways England roads. +*/ + +fixmystreet.message_controller = (function() { + var stopperId = 'js-category-stopper', + stoppers = []; + + // This shows an error message because e.g. an asset isn't selected or a road hasn't been clicked + function show_responsibility_error(id, asset_item, asset_type) { + $("#js-roads-responsibility").removeClass("hidden"); + $("#js-roads-responsibility .js-responsibility-message").addClass("hidden"); + var asset_strings = $('.js-roads-asset'); + if (asset_item) { + asset_strings.html('a <b class="asset-' + asset_type + '">' + asset_item + '</b>'); + } else { + asset_strings.html(asset_strings.data('original')); + } + $('.js-update-coordinates').attr('href', function(i, href) { + if (href.indexOf('?') != -1) { + href = href.substring(0, href.indexOf('?')); + } + href += '?' + OpenLayers.Util.getParameterString({ + latitude: $('#fixmystreet\\.latitude').val(), + longitude: $('#fixmystreet\\.longitude').val() + }); + return href; + }); + $(id).removeClass("hidden"); + } + + // This hides the asset/road not found message + function hide_responsibility_errors() { + $("#js-roads-responsibility").addClass("hidden"); + $("#js-roads-responsibility .js-responsibility-message").addClass("hidden"); + } + + // This shows the reporting form + function enable_report_form() { + $(".js-hide-if-invalid-category").show(); + } + + // This hides the reporting form, apart from the category selection + function disable_report_form() { + $(".js-hide-if-invalid-category").hide(); + } + + // This hides the responsibility message, and (unless a + // stopper message is shown) reenables the report form + function responsibility_off() { + hide_responsibility_errors(); + if (!document.getElementById(stopperId)) { + enable_report_form(); + } + } + + // This disables the report form and (unless a stopper + // message is shown) shows a responsibility message + function responsibility_on(id, asset_item, asset_type) { + disable_report_form(); + hide_responsibility_errors(); + if (!document.getElementById(stopperId)) { + show_responsibility_error(id, asset_item, asset_type); + } + } + + function is_only_body(body) { + if (fixmystreet.bodies && fixmystreet.bodies.length == 1 && fixmystreet.bodies[0] == body) { + return true; + } + return false; + } + + // make sure we fire the code to check if an asset is selected if + // we change options in the Highways England message + $(fixmystreet).on('report_new:highways_change', function() { + if (fixmystreet.body_overrides.get_only_send() === 'Highways England') { + $('#' + stopperId).remove(); // Get rid of any stopper message + responsibility_off(); // Will also reenable form + } else { + $(fixmystreet).trigger('report_new:category_change', [ $('#form_category') ]); + } + }); + + $(fixmystreet).on('report_new:category_change', function() { + if (fixmystreet.body_overrides.get_only_send() == 'Highways England') { + // If we're sending to Highways England, this message doesn't matter + return; + } + + var $id = $('#' + stopperId); + var body = $('#form_category').data('body'); + var matching = $.grep(stoppers, function(stopper, i) { + if (stopper.staff_ignore && body) { + return false; + } + + var relevant_body = OpenLayers.Util.indexOf(fixmystreet.bodies, stopper.body) > -1; + var relevant_cat; + if (typeof stopper.category === 'function') { + relevant_cat = stopper.category(); + } else { + relevant_cat = $('#form_category').val() == stopper.category; + } + var relevant = relevant_body && relevant_cat; + return relevant; + }); + + if (!matching.length) { + $id.remove(); + if ( !$('#js-roads-responsibility').is(':visible') ) { + enable_report_form(); + } + return; + } + + var stopper = matching[0]; // Assume only one match possible at present + var $msg; + if (typeof stopper.message === 'function') { + $msg = stopper.message(); + $msg.attr('id', stopperId); + } else { + $msg = $('<p id="' + stopperId + '" class="box-warning">' + stopper.message + '</p>'); + } + + if ($id.length) { + $id.replaceWith($msg); + } else { + $msg.insertBefore('#js-post-category-messages'); + } + disable_report_form(); + }); + + return { + asset_found: function() { + responsibility_off(); + return ($('#' + stopperId).length); + }, + + asset_not_found: function(layer) { + if (!layer.visibility) { + responsibility_off(); + } else { + responsibility_on('#js-not-an-asset', layer.fixmystreet.asset_item, layer.fixmystreet.asset_type); + } + }, + + // A road was found; if some roads should still cause disabling/message, + // then you should pass in a criterion function to test the found feature, + // plus an ID of the message to be shown + road_found: function(layer, feature, criterion, msg_id) { + fixmystreet.body_overrides.allow_send(layer.fixmystreet.body); + fixmystreet.body_overrides.remove_only_send(); + if (fixmystreet.assets.selectedFeature()) { + responsibility_off(); + } else if (!criterion || criterion(feature)) { + responsibility_off(); + } else { + fixmystreet.body_overrides.do_not_send(layer.fixmystreet.body); + if (is_only_body(layer.fixmystreet.body)) { + responsibility_on(msg_id); + } + } + }, + + road_not_found: function(layer) { + // If a feature wasn't found at the location they've clicked, it's + // probably a field or something. Show an error to that effect, + // unless an asset is selected. + fixmystreet.body_overrides.do_not_send(layer.fixmystreet.body); + fixmystreet.body_overrides.remove_only_send(); + // don't show the message if clicking on a highways england road + if (fixmystreet.body_overrides.get_only_send() == 'Highways England' || !layer.visibility) { + responsibility_off(); + } else if (fixmystreet.assets.selectedFeature()) { + fixmystreet.body_overrides.allow_send(layer.fixmystreet.body); + responsibility_off(); + } else if (is_only_body(layer.fixmystreet.body)) { + responsibility_on(layer.fixmystreet.no_asset_msg_id, layer.fixmystreet.asset_item, layer.fixmystreet.asset_type); + } + }, + + register_category: function(params) { + stoppers.push(params); + } + }; + +})(); diff --git a/web/cobrands/lincolnshire/assets.js b/web/cobrands/lincolnshire/assets.js index 40187e188..f4b1861a9 100644 --- a/web/cobrands/lincolnshire/assets.js +++ b/web/cobrands/lincolnshire/assets.js @@ -140,7 +140,10 @@ fixmystreet.assets.add($.extend(true, {}, defaults, { TYPENAME: "ST_All_Structures" } }, - asset_category: "Bridge", + asset_category: [ + "Bridge", + "Bridge or Structure" + ], asset_item: 'bridge', filter_key: 'Type', filter_value: [ diff --git a/web/cobrands/lincolnshire/roadworks.js b/web/cobrands/lincolnshire/roadworks.js index 7b42a12f2..760e8f00e 100644 --- a/web/cobrands/lincolnshire/roadworks.js +++ b/web/cobrands/lincolnshire/roadworks.js @@ -11,4 +11,19 @@ fixmystreet.assets.add($.extend(true, {}, fixmystreet.roadworks.layer_future, { // NB Lincs don't want forward planning works displayed, so // fixmystreet.roadworks.layer_planned is deliberately missing here. + +// Lincs want to also display the responsible party in roadworks messages +var original_display_message = fixmystreet.roadworks.display_message; +fixmystreet.roadworks.display_message = function(feature) { + var retval = original_display_message.apply(this, arguments); + + if (feature.attributes.promoter) { + var $dl = $(".js-roadworks-message-" + feature.layer.id + " dl"); + $dl.append("<dt>Responsibility</dt>"); + $dl.append($("<dd></dd>").text(feature.attributes.promoter)); + } + + return retval; +}; + })(); diff --git a/web/cobrands/northamptonshire/assets.js b/web/cobrands/northamptonshire/assets.js index 36f354761..dda51407e 100644 --- a/web/cobrands/northamptonshire/assets.js +++ b/web/cobrands/northamptonshire/assets.js @@ -4,32 +4,6 @@ if (!fixmystreet.maps) { return; } -/* utility functions */ -function show_responsibility_error(id, asset_item, asset_type) { - hide_responsibility_errors(); - $("#js-roads-responsibility").removeClass("hidden"); - $("#js-roads-responsibility .js-responsibility-message").addClass("hidden"); - if (asset_item) { - $('#js-roads-asset').html('a <b class="asset-' + asset_type + '">' + asset_item + '</b>'); - } else { - $('#js-roads-asset').html('an item'); - } - $(id).removeClass("hidden"); -} - -function hide_responsibility_errors() { - $("#js-roads-responsibility").addClass("hidden"); - $("#js-roads-responsibility .js-responsibility-message").addClass("hidden"); -} - -function enable_report_form() { - $(".js-hide-if-invalid-category").show(); -} - -function disable_report_form() { - $(".js-hide-if-invalid-category").hide(); -} - var is_live = false; if ( location.hostname === 'www.fixmystreet.com' || location.hostname == 'fixmystreet.northamptonshire.gov.uk' ) { is_live = true; @@ -340,18 +314,6 @@ var layers = [ }, ]; -// make sure we fire the code to check if an asset is selected if -// we change options in the Highways England message -$(fixmystreet).on('report_new:highways_change', function() { - if (fixmystreet.body_overrides.get_only_send() === 'Highways England') { - hide_responsibility_errors(); - enable_report_form(); - $('#ncc_streetlights').remove(); - } else { - $(fixmystreet).trigger('report_new:category_change', [ $('#form_category') ]); - } -}); - // This is required so that the found/not found actions are fired on category // select and pin move rather than just on asset select/not select. OpenLayers.Layer.NCCVectorAsset = OpenLayers.Class(OpenLayers.Layer.VectorAsset, { @@ -383,12 +345,9 @@ var northants_defaults = $.extend(true, {}, fixmystreet.assets.alloy_defaults, { select_action: true, actions: { asset_found: function(asset) { - var emergency_state = ncc_is_emergency_category(); - if (emergency_state.relevant && !emergency_state.body) { + if (fixmystreet.message_controller.asset_found()) { return; } - hide_responsibility_errors(); - enable_report_form(); var lonlat = asset.geometry.getBounds().getCenterLonLat(); // Features considered overlapping if within 1M of each other // TODO: Should zoom/marker size be considered when determining if markers overlap? @@ -419,14 +378,7 @@ var northants_defaults = $.extend(true, {}, fixmystreet.assets.alloy_defaults, { }, asset_not_found: function() { $("#overlapping_features_msg").addClass('hidden'); - var emergency_state = ncc_is_emergency_category(); - - disable_report_form(); - if ((!emergency_state.relevant || emergency_state.body) && this.visibility) { - show_responsibility_error('#js-not-an-asset', this.fixmystreet.asset_item, this.fixmystreet.asset_type); - } else { - hide_responsibility_errors(); - } + fixmystreet.message_controller.asset_not_found(this); } } }); @@ -465,30 +417,8 @@ var northants_road_defaults = $.extend(true, {}, fixmystreet.assets.alloy_defaul return feature.fid; }, actions: { - found: function(layer, feature) { - var emergency_state = ncc_is_emergency_category(); - if (!emergency_state.relevant || emergency_state.body) { - enable_report_form(); - } - hide_responsibility_errors(); - }, - not_found: function(layer) { - // don't show the message if clicking on a highways england road - var emergency_state = ncc_is_emergency_category(); - if (fixmystreet.body_overrides.get_only_send() == 'Highways England' || !layer.visibility) { - if (!emergency_state.relevant || emergency_state.body) { - enable_report_form(); - } - hide_responsibility_errors(); - } else { - disable_report_form(); - if (!emergency_state.relevant || emergency_state.body) { - show_responsibility_error(layer.fixmystreet.no_asset_msg_id); - } else { - hide_responsibility_errors(); - } - } - }, + found: fixmystreet.message_controller.road_found, + not_found: fixmystreet.message_controller.road_not_found } }); @@ -498,7 +428,8 @@ fixmystreet.assets.add($.extend(true, {}, northants_road_defaults, { layerid: 221, layerVersion: '221.4-', }, - no_asset_msg_id: '#js-not-a-speedhump', + no_asset_msg_id: '#js-not-an-asset', + asset_item: 'speed hump', asset_type: "area", asset_category: [ "Damaged Speed Humps", @@ -520,7 +451,9 @@ fixmystreet.assets.add($.extend(true, {}, northants_road_defaults, { stylemap: new OpenLayers.StyleMap({ 'default': barrier_style }), - no_asset_msg_id: '#js-not-a-ped-barrier', + no_asset_msg_id: '#js-not-an-asset', + asset_item: 'pedestrian barrier', + asset_type: 'area', asset_category: [ "Pedestrian Barriers - Damaged / Missing", ] @@ -589,66 +522,29 @@ fixmystreet.assets.add($.extend(true, {}, northants_road_defaults, { stylemap: new OpenLayers.StyleMap({ 'default': prow_style }), - no_asset_msg_id: "#js-not-a-prow", + no_asset_msg_id: "#js-not-a-road", + asset_item: 'right of way', asset_category: [ "Livestock", "Passage-Obstructed/Overgrown" ] })); -function ncc_is_emergency_category() { - var relevant_body = OpenLayers.Util.indexOf(fixmystreet.bodies, northants_defaults.body) > -1; - var relevant_cat = !!$('label[for=form_emergency]').length; - var relevant = relevant_body && relevant_cat; - var currently_shown = !!$('#northants-emergency-message').length; - var body = $('#form_category').data('body'); - - return {relevant: relevant, currently_shown: currently_shown, body: body}; -} - -// Hide form when emergency category used -function check_emergency() { - var state = ncc_is_emergency_category(); - - if (state.relevant === state.currently_shown || state.body || fixmystreet.body_overrides.get_only_send() == 'Highways England') { - // Either should be shown and already is, or shouldn't be shown and isn't - return; - } - - if (!state.relevant) { - $('#northants-emergency-message').remove(); - if ( !$('#js-roads-responsibility').is(':visible') ) { - $('.js-hide-if-invalid-category').show(); - } - return; - } - - var $msg = $('<div class="box-warning" id="northants-emergency-message"></div>'); - $msg.html($('label[for=form_emergency]').html()); - $msg.insertBefore('#js-post-category-messages'); - $('.js-hide-if-invalid-category').hide(); -} -$(fixmystreet).on('report_new:category_change', check_emergency); - -function ncc_check_streetlights() { - var relevant_body = OpenLayers.Util.indexOf(fixmystreet.bodies, northants_defaults.body) > -1; - var relevant_cat = $('#form_category').val() == 'Street lighting'; - var relevant = relevant_body && relevant_cat; - var currently_shown = !!$('#ncc_streetlights').length; - - if (relevant === currently_shown || fixmystreet.body_overrides.get_only_send() == 'Highways England') { - return; - } - - if (!relevant) { - $('#ncc_streetlights').remove(); - return; - } +fixmystreet.message_controller.register_category({ + body: northants_defaults.body, + category: function() { + return !!$('label[for=form_emergency]').length; + }, + message: function() { + return $('<div class="box-warning">' + $('label[for=form_emergency]').html() + '</div>'); + }, + staff_ignore: true +}); - var $msg = $('<p id="ncc_streetlights" class="box-warning">Street lighting in Northamptonshire is maintained by Balfour Beatty on behalf of the County Council under a Street Lighting Private Finance Initiative (PFI) contract. Please view our <b><a href="https://www3.northamptonshire.gov.uk/councilservices/northamptonshire-highways/roads-and-streets/Pages/street-lighting.aspx">Street Lighting</a></b> page to report any issues.</p>'); - $msg.insertBefore('#js-post-category-messages'); - disable_report_form(); -} -$(fixmystreet).on('report_new:category_change', ncc_check_streetlights); +fixmystreet.message_controller.register_category({ + body: northants_defaults.body, + category: 'Street lighting', + message: 'Street lighting in Northamptonshire is maintained by Balfour Beatty on behalf of the County Council under a Street Lighting Private Finance Initiative (PFI) contract. Please view our <b><a href="https://www3.northamptonshire.gov.uk/councilservices/northamptonshire-highways/roads-and-streets/Pages/street-lighting.aspx">Street Lighting</a></b> page to report any issues.' +}); })(); diff --git a/web/cobrands/oxfordshire/assets.js b/web/cobrands/oxfordshire/assets.js index 46b555b02..df60b89c7 100644 --- a/web/cobrands/oxfordshire/assets.js +++ b/web/cobrands/oxfordshire/assets.js @@ -1,26 +1,5 @@ -(function(){ - -function check_rights_of_way() { - var relevant_body = OpenLayers.Util.indexOf(fixmystreet.bodies, 'Oxfordshire County Council') > -1; - var relevant_cat = $('#form_category').val() == 'Countryside Paths / Public Rights of Way (usually not tarmac)'; - var relevant = relevant_body && relevant_cat; - var currently_shown = !!$('#occ_prow').length; - - if (relevant === currently_shown) { - // Either should be shown and already is, or shouldn't be shown and isn't - return; - } - - if (!relevant) { - $('#occ_prow').remove(); - $('.js-hide-if-invalid-category').show(); - return; - } - - var $msg = $('<p id="occ_prow" class="box-warning">Please report problems with rights of way using <a href="https://publicrightsofway.oxfordshire.gov.uk/web/standardmap.aspx">this page</a>.</p>'); - $msg.insertBefore('#js-post-category-messages'); - $('.js-hide-if-invalid-category').hide(); -} -$(fixmystreet).on('report_new:category_change', check_rights_of_way); - -})(); +fixmystreet.message_controller.register_category({ + body: 'Oxfordshire County Council', + category: 'Countryside Paths / Public Rights of Way (usually not tarmac)', + message: 'Please report problems with rights of way using <a href="https://publicrightsofway.oxfordshire.gov.uk/web/standardmap.aspx">this page</a>.' +}); diff --git a/web/cobrands/sass/_admin.scss b/web/cobrands/sass/_admin.scss index 1f55c62df..745c74fd7 100644 --- a/web/cobrands/sass/_admin.scss +++ b/web/cobrands/sass/_admin.scss @@ -240,3 +240,13 @@ $button_bg_col: #a1a1a1; // also search bar (tables) font-weight: normal; } } + +.truncate_height { + max-height: 3em; + overflow: hidden; + text-overflow: ellipsis; + + &:hover { + max-height: initial; + } +} |