aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/fixmystreet.com/fixture39
-rw-r--r--conf/general.yml-example3
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm67
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/Moderate.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm6
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm6
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm8
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/FixaMinGata.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm4
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm30
-rw-r--r--perllib/FixMyStreet/Script/Reports.pm11
-rw-r--r--perllib/Utils.pm17
-rw-r--r--t/app/controller/admin.t1
-rw-r--r--t/app/controller/contact.t4
-rw-r--r--t/app/controller/my_planned.t10
-rw-r--r--t/app/sendreport/inspection_required.t20
-rw-r--r--t/utils.t36
-rw-r--r--t/utils/email.t34
-rw-r--r--templates/web/base/admin/response_templates_select.html2
-rw-r--r--templates/web/base/admin/user-form.html29
-rw-r--r--templates/web/base/contact/submit.html2
-rw-r--r--templates/web/base/my/planned.html6
-rw-r--r--templates/web/base/questionnaire/index.html20
-rw-r--r--templates/web/base/report/_main.html66
-rw-r--r--templates/web/base/report/new/after_photo.html3
-rw-r--r--templates/web/base/report/new/form_user_loggedin.html4
-rw-r--r--templates/web/base/report/update.html2
-rw-r--r--templates/web/base/report/update/form_name.html4
-rw-r--r--templates/web/fixmystreet.com/about/council.html1
-rw-r--r--templates/web/fixmystreet.com/report/new/extra_name.html2
-rw-r--r--templates/web/oxfordshire/header.html2
-rw-r--r--templates/web/zurich/maps/noscript_map.html30
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js21
-rw-r--r--web/cobrands/sass/_base.scss81
37 files changed, 446 insertions, 139 deletions
diff --git a/bin/fixmystreet.com/fixture b/bin/fixmystreet.com/fixture
new file mode 100755
index 000000000..93982af8a
--- /dev/null
+++ b/bin/fixmystreet.com/fixture
@@ -0,0 +1,39 @@
+#!/usr/bin/env perl
+#
+# This script will create a test body and its categories, covering the area of
+# Westminster, and a user associated with that body, which should help testing
+# of report interactions.
+
+use strict;
+use warnings;
+
+BEGIN {
+ use File::Basename qw(dirname);
+ use File::Spec;
+ my $d = dirname(File::Spec->rel2abs($0));
+ require "$d/../../setenv.pl";
+}
+
+use FixMyStreet::DB;
+
+my $body = FixMyStreet::DB->resultset("Body")->find_or_create({ name => 'Test City Council' });
+$body->body_areas->find_or_create({ area_id => 2504 });
+foreach ("Potholes", "Street lighting", "Graffiti") {
+ (my $email = lc $_) =~ s/ /-/g;
+ $body->contacts->find_or_create({
+ category => $_,
+ email => $email . '@example.net',
+ confirmed => 't',
+ deleted => 'f',
+ whenedited => \'current_timestamp',
+ editor => 'fixture',
+ note => 'Created by fixture'
+ });
+}
+
+FixMyStreet::DB->resultset("User")->find_or_create({
+ email => 'council@example.net',
+ name => 'Test City Council User',
+ from_body => $body,
+ password => 'password',
+});
diff --git a/conf/general.yml-example b/conf/general.yml-example
index 54bbd6a7f..3b2c597b9 100644
--- a/conf/general.yml-example
+++ b/conf/general.yml-example
@@ -46,6 +46,9 @@ STAGING_SITE: 1
# reports to live places. Set this to 1 if you want a dev site to route
# reports as normal.
SEND_REPORTS_ON_STAGING: 0
+# Manual testing of multiple cobrands can be made easier by skipping some
+# checks they have in them, if this variable is set
+SKIP_CHECKS_ON_STAGING: 0
# What to use as front page/alert example places placeholder
# Defaults to High Street, Main Street
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index b643c9633..46ac10d36 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -345,8 +345,6 @@ sub update_contacts : Private {
my $category = $self->trim( $c->get_param('category') );
$errors{category} = _("Please choose a category") unless $category;
- my $email = $self->trim( $c->get_param('email') );
- $errors{email} = _('Please enter a valid email') unless is_valid_email($email) || $email eq 'REFUSED';
$errors{note} = _('Please enter a message') unless $c->get_param('note');
my $contact = $c->model('DB::Contact')->find_or_new(
@@ -356,6 +354,12 @@ sub update_contacts : Private {
}
);
+ my $email = $self->trim( $c->get_param('email') );
+ my $send_method = $c->get_param('send_method') || $contact->send_method || $contact->body->send_method || "";
+ unless ( $send_method eq 'Open311' ) {
+ $errors{email} = _('Please enter a valid email') unless is_valid_email($email) || $email eq 'REFUSED';
+ }
+
$contact->email( $email );
$contact->confirmed( $c->get_param('confirmed') ? 1 : 0 );
$contact->deleted( $c->get_param('deleted') ? 1 : 0 );
@@ -683,7 +687,7 @@ sub report_edit : Path('report_edit') : Args(1) {
unless (
$c->cobrand->moniker eq 'zurich'
- || $c->user->has_permission_to(report_edit => $problem->bodies_str)
+ || $c->user->has_permission_to(report_edit => $problem->bodies_str_ids)
) {
$c->detach( '/page_error_403_access_denied', [] );
}
@@ -1030,15 +1034,17 @@ sub users: Path('users') : Args(0) {
my %email2user = map { $_->email => $_ } @users;
$c->stash->{users} = [ @users ];
- my $emails = $c->model('DB::Abuse')->search(
- { email => { ilike => $isearch } }
- ) if $c->user->is_superuser;
- foreach my $email ($emails->all) {
- # Slight abuse of the boolean flagged value
- if ($email2user{$email->email}) {
- $email2user{$email->email}->flagged( 2 );
- } else {
- push @{$c->stash->{users}}, { email => $email->email, flagged => 2 };
+ if ( $c->user->is_superuser ) {
+ my $emails = $c->model('DB::Abuse')->search(
+ { email => { ilike => $isearch } }
+ );
+ foreach my $email ($emails->all) {
+ # Slight abuse of the boolean flagged value
+ if ($email2user{$email->email}) {
+ $email2user{$email->email}->flagged( 2 );
+ } else {
+ push @{$c->stash->{users}}, { email => $email->email, flagged => 2 };
+ }
}
}
@@ -1218,7 +1224,7 @@ sub user_edit : Path('user_edit') : Args(1) {
my $user = $c->cobrand->users->find( { id => $id } );
$c->detach( '/page_error_404_not_found', [] ) unless $user;
- unless ( $c->user->is_superuser || $c->user->has_body_permission_to('user_edit') ) {
+ unless ( $c->user->is_superuser || $c->user->has_body_permission_to('user_edit') || $c->cobrand->moniker eq 'zurich' ) {
$c->detach('/page_error_403_access_denied', []);
}
@@ -1253,7 +1259,7 @@ sub user_edit : Path('user_edit') : Args(1) {
$user->is_superuser( ( $c->user->is_superuser && $c->get_param('is_superuser') ) || 0 );
# Superusers can set from_body to any value, but other staff can only
# set from_body to the same value as their own from_body.
- if ( $c->user->is_superuser ) {
+ if ( $c->user->is_superuser || $c->cobrand->moniker eq 'zurich' ) {
$user->from_body( $c->get_param('body') || undef );
} elsif ( $c->user->has_body_permission_to('user_assign_body') &&
$c->get_param('body') && $c->get_param('body') eq $c->user->from_body->id ) {
@@ -1270,14 +1276,14 @@ sub user_edit : Path('user_edit') : Args(1) {
if (!$user->from_body) {
# Non-staff users aren't allowed any permissions or to be in an area
- $user->user_body_permissions->delete_all;
+ $user->admin_user_body_permissions->delete;
$user->area_id(undef);
delete $c->stash->{areas};
delete $c->stash->{fetched_areas_body_id};
} elsif ($c->stash->{available_permissions}) {
my @all_permissions = map { keys %$_ } values %{ $c->stash->{available_permissions} };
my @user_permissions = grep { $c->get_param("permissions[$_]") ? 1 : undef } @all_permissions;
- $user->user_body_permissions->search({
+ $user->admin_user_body_permissions->search({
body_id => $user->from_body->id,
permission_type => { '!=' => \@user_permissions },
})->delete;
@@ -1295,6 +1301,35 @@ sub user_edit : Path('user_edit') : Args(1) {
$user->area_id( $valid_areas{$new_area} ? $new_area : undef );
}
+ # Handle 'trusted' flag(s)
+ my @trusted_bodies = $c->get_param_list('trusted_bodies');
+ if ( $c->user->is_superuser ) {
+ $user->user_body_permissions->search({
+ body_id => { '!=' => \@trusted_bodies },
+ permission_type => 'trusted',
+ })->delete;
+ foreach my $body_id (@trusted_bodies) {
+ $user->user_body_permissions->find_or_create({
+ body_id => $body_id,
+ permission_type => 'trusted',
+ });
+ }
+ } elsif ( $c->user->from_body ) {
+ my %trusted = map { $_ => 1 } @trusted_bodies;
+ my $body_id = $c->user->from_body->id;
+ if ( $trusted{$body_id} ) {
+ $user->user_body_permissions->find_or_create({
+ body_id => $body_id,
+ permission_type => 'trusted',
+ });
+ } else {
+ $user->user_body_permissions->search({
+ body_id => $body_id,
+ permission_type => 'trusted',
+ })->delete;
+ }
+ }
+
unless ($user->email) {
$c->stash->{field_errors}->{email} = _('Please enter a valid email');
return;
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index c2cc54832..b98bdbcc7 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -236,6 +236,10 @@ sub send_email : Private {
my $recipient = $c->cobrand->contact_email;
my $recipient_name = $c->cobrand->contact_name();
+ if (my $localpart = $c->get_param('recipient')) {
+ $recipient = join('@', $localpart, FixMyStreet->config('EMAIL_DOMAIN'));
+ }
+
$c->stash->{host} = $c->req->header('HOST');
$c->stash->{ip} = $c->req->address;
$c->stash->{ip} .=
diff --git a/perllib/FixMyStreet/App/Controller/Moderate.pm b/perllib/FixMyStreet/App/Controller/Moderate.pm
index dadec5c53..94e6cd62a 100644
--- a/perllib/FixMyStreet/App/Controller/Moderate.pm
+++ b/perllib/FixMyStreet/App/Controller/Moderate.pm
@@ -54,7 +54,7 @@ sub report : Chained('moderate') : PathPart('report') : CaptureArgs(1) {
# ... and immediately, if the user isn't authorized
$c->detach unless $c->user_exists;
- $c->detach unless $c->user->has_permission_to(moderate => $problem->bodies_str);
+ $c->detach unless $c->user->has_permission_to(moderate => $problem->bodies_str_ids);
$c->forward('/auth/check_csrf_token');
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 1d67afd0e..34392782b 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -133,7 +133,7 @@ sub load_problem_or_display_error : Private {
}
$c->stash->{problem} = $problem;
- if ( $c->user_exists && $c->user->has_permission_to(moderate => $problem->bodies_str) ) {
+ if ( $c->user_exists && $c->user->has_permission_to(moderate => $problem->bodies_str_ids) ) {
$c->stash->{problem_original} = $problem->find_or_new_related(
moderation_original_data => {
title => $problem->title,
@@ -401,7 +401,7 @@ to the current Problem in $c->stash->{problem}. Shows the 403 page if not.
sub check_has_permission_to : Private {
my ( $self, $c, @permissions ) = @_;
- my $bodies = $c->stash->{problem}->bodies_str;
+ my $bodies = $c->stash->{problem}->bodies_str_ids;
my %permissions = map { $_ => $c->user->has_permission_to($_, $bodies) } @permissions
if $c->user_exists;
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index cee72244f..f26120829 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -190,9 +190,9 @@ sub report_form_ajax : Path('ajax') : Args(0) {
my $contribute_as = {};
if ($c->user_exists) {
- my $bodies = join(',', keys %{$c->stash->{bodies}});
- my $ca_another_user = $c->user->has_permission_to('contribute_as_another_user', $bodies);
- my $ca_body = $c->user->has_permission_to('contribute_as_body', $bodies);
+ my @bodies = keys %{$c->stash->{bodies}};
+ my $ca_another_user = $c->user->has_permission_to('contribute_as_another_user', \@bodies);
+ my $ca_body = $c->user->has_permission_to('contribute_as_body', \@bodies);
$contribute_as->{another_user} = $ca_another_user if $ca_another_user;
$contribute_as->{body} = $ca_body if $ca_body;
}
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 705e6ee99..4c2d92d5e 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -113,7 +113,7 @@ sub process_user : Private {
if ( $c->user_exists ) { {
my $user = $c->user->obj;
- if ($c->stash->{contributing_as_another_user} = $user->contributing_as('another_user', $c, $update->problem->bodies_str)) {
+ if ($c->stash->{contributing_as_another_user} = $user->contributing_as('another_user', $c, $update->problem->bodies_str_ids)) {
# Act as if not logged in (and it will be auto-confirmed later on)
last;
}
@@ -276,7 +276,7 @@ sub process_update : Private {
$update->mark_fixed($params{fixed} ? 1 : 0);
$update->mark_open($params{reopen} ? 1 : 0);
- $c->stash->{contributing_as_body} = $c->user_exists && $c->user->contributing_as('body', $c, $update->problem->bodies_str);
+ $c->stash->{contributing_as_body} = $c->user_exists && $c->user->contributing_as('body', $c, $update->problem->bodies_str_ids);
if ($c->stash->{contributing_as_body}) {
$update->name($c->user->from_body->name);
$update->anonymous(0);
@@ -286,7 +286,7 @@ sub process_update : Private {
}
if ( $params{state} ) {
- $params{state} = 'fixed - council'
+ $params{state} = 'fixed - council'
if $params{state} eq 'fixed' && $c->user && $c->user->belongs_to_body( $update->problem->bodies_str );
$update->problem_state( $params{state} );
} else {
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 47e577372..c44842dea 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -717,9 +717,15 @@ sub available_permissions {
report_edit_priority => _("Edit report priority"), # future use
report_inspect => _("Markup problem details"),
report_instruct => _("Instruct contractors to fix problems"), # future use
- planned_reports => _("Manage planned reports list"),
+ planned_reports => _("Manage shortlist"),
contribute_as_another_user => _("Create reports/updates on a user's behalf"),
contribute_as_body => _("Create reports/updates as the council"),
+
+ # NB this permission is special in that it can be assigned to users
+ # without their from_body being set. It's included here for
+ # reference, but left commented out because it's not assigned in the
+ # same way as other permissions.
+ # trusted => _("Trusted to make reports that don't need to be inspected"),
},
_("Users") => {
user_edit => _("Edit other users' details"),
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
index ba26b7a2c..242735073 100644
--- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -29,6 +29,8 @@ sub disambiguate_location {
}
sub area_types {
+ my $self = shift;
+ return $self->next::method() if FixMyStreet->config('STAGING_SITE') && FixMyStreet->config('SKIP_CHECKS_ON_STAGING');
[ 'NKO', 'NFY', 'NRA' ];
}
diff --git a/perllib/FixMyStreet/Cobrand/FixaMinGata.pm b/perllib/FixMyStreet/Cobrand/FixaMinGata.pm
index 9ffbf00b8..a321d5c7c 100644
--- a/perllib/FixMyStreet/Cobrand/FixaMinGata.pm
+++ b/perllib/FixMyStreet/Cobrand/FixaMinGata.pm
@@ -30,6 +30,8 @@ sub disambiguate_location {
}
sub area_types {
+ my $self = shift;
+ return $self->next::method() if FixMyStreet->config('STAGING_SITE') && FixMyStreet->config('SKIP_CHECKS_ON_STAGING');
[ 'KOM' ];
}
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 5d72c4962..42c9c5cbc 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -42,11 +42,13 @@ sub restriction {
sub problems_restriction {
my ($self, $rs) = @_;
+ return $rs if FixMyStreet->config('STAGING_SITE') && FixMyStreet->config('SKIP_CHECKS_ON_STAGING');
return $rs->to_body($self->council_id);
}
sub updates_restriction {
my ($self, $rs) = @_;
+ return $rs if FixMyStreet->config('STAGING_SITE') && FixMyStreet->config('SKIP_CHECKS_ON_STAGING');
return $rs->to_body($self->council_id);
}
@@ -96,6 +98,8 @@ sub enter_postcode_text {
sub area_check {
my ( $self, $params, $context ) = @_;
+ return 1 if FixMyStreet->config('STAGING_SITE') && FixMyStreet->config('SKIP_CHECKS_ON_STAGING');
+
my $councils = $params->{all_areas};
my $council_match = defined $councils->{$self->council_id};
if ($council_match) {
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index 0ba7e252c..2a2d0d5e3 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -257,15 +257,14 @@ sub permissions {
}
sub has_permission_to {
- my ($self, $permission_type, $body_id) = @_;
+ my ($self, $permission_type, $body_ids) = @_;
return 1 if $self->is_superuser;
+ return 0 unless $body_ids;
- return 0 unless $self->belongs_to_body($body_id);
-
- my $permission = $self->user_body_permissions->find({
+ my $permission = $self->user_body_permissions->find({
permission_type => $permission_type,
- body_id => $self->from_body->id,
+ body_id => $body_ids,
});
return $permission ? 1 : 0;
}
@@ -293,10 +292,25 @@ sub has_body_permission_to {
return $self->has_permission_to($permission_type, $self->from_body->id);
}
+=head2 admin_user_body_permissions
+
+Some permissions aren't managed in the normal way via the admin, e.g. the
+'trusted' permission. This method returns a query that excludes such exceptional
+permissions.
+
+=cut
+
+sub admin_user_body_permissions {
+ my $self = shift;
+
+ return $self->user_body_permissions->search({
+ permission_type => { '!=' => 'trusted' },
+ });
+}
+
sub contributing_as {
my ($self, $other, $c, $bodies) = @_;
- $bodies = join(',', keys %$bodies) if ref $bodies eq 'HASH';
- $c->log->error("Bad data $bodies passed to contributing_as") if ref $bodies;
+ $bodies = [ keys %$bodies ] if ref $bodies eq 'HASH';
my $form_as = $c->get_param('form_as') || '';
return 1 if $form_as eq $other && $self->has_permission_to("contribute_as_$other", $bodies);
}
@@ -327,7 +341,7 @@ sub adopt {
$other->delete;
}
-# Planned reports
+# Planned reports / shortlist
# Override the default auto-created function as we only want one live entry per user
around add_to_planned_reports => sub {
diff --git a/perllib/FixMyStreet/Script/Reports.pm b/perllib/FixMyStreet/Script/Reports.pm
index ab0d90ba8..8d3b2ddbc 100644
--- a/perllib/FixMyStreet/Script/Reports.pm
+++ b/perllib/FixMyStreet/Script/Reports.pm
@@ -144,9 +144,14 @@ sub send(;$) {
$reporters{ $sender } ||= $sender->new();
my $inspection_required = $sender_info->{contact}->get_extra_metadata('inspection_required') if $sender_info->{contact};
- if ( $inspection_required && !$row->get_extra_metadata('inspected') ) {
- $skip = 1;
- debug_print("skipped because not yet inspected", $row->id) if $debug_mode;
+ if ( $inspection_required ) {
+ unless (
+ $row->get_extra_metadata('inspected') ||
+ $row->user->has_permission_to( trusted => $row->bodies_str_ids )
+ ) {
+ $skip = 1;
+ debug_print("skipped because not yet inspected", $row->id) if $debug_mode;
+ }
}
if ( $reporters{ $sender }->should_skip( $row ) ) {
diff --git a/perllib/Utils.pm b/perllib/Utils.pm
index 87c1a10d6..84c09d09d 100644
--- a/perllib/Utils.pm
+++ b/perllib/Utils.pm
@@ -15,6 +15,7 @@ use Encode;
use File::Slurp qw();
use mySociety::GeoUtil;
use mySociety::Locale;
+use FixMyStreet;
=head2 convert_latlon_to_en
@@ -199,7 +200,7 @@ sub prettify_duration {
$s = int(($s+60*60*12)/60/60/24)*60*60*24;
} elsif ($nearest eq 'hour') {
$s = int(($s+60*30)/60/60)*60*60;
- } elsif ($nearest eq 'minute') {
+ } else { # minute
$s = int(($s+30)/60)*60;
return _('less than a minute') if $s == 0;
}
@@ -221,7 +222,7 @@ sub _part {
$str = mySociety::Locale::nget("%d day", "%d days", $i);
} elsif ($m == 60*60) {
$str = mySociety::Locale::nget("%d hour", "%d hours", $i);
- } elsif ($m == 60) {
+ } else {
$str = mySociety::Locale::nget("%d minute", "%d minutes", $i);
}
push @$o, sprintf($str, $i);
@@ -229,17 +230,5 @@ sub _part {
}
}
-=head2 read_file
-
-Reads in a UTF-8 encoded file using File::Slurp and decodes it from UTF-8.
-This appears simplest, rather than getting confused with binmodes and so on.
-
-=cut
-sub read_file {
- my $filename = shift;
- my $data = File::Slurp::read_file( $filename );
- $data = Encode::decode( 'utf8', $data );
- return $data;
-}
1;
diff --git a/t/app/controller/admin.t b/t/app/controller/admin.t
index 8c3cde4b7..7ba84b652 100644
--- a/t/app/controller/admin.t
+++ b/t/app/controller/admin.t
@@ -1165,6 +1165,7 @@ my %default_perms = (
"permissions[template_edit]" => undef,
"permissions[responsepriority_edit]" => undef,
"permissions[category_edit]" => undef,
+ trusted_bodies => undef,
);
FixMyStreet::override_config {
diff --git a/t/app/controller/contact.t b/t/app/controller/contact.t
index dd94fc431..7c2769b9c 100644
--- a/t/app/controller/contact.t
+++ b/t/app/controller/contact.t
@@ -250,7 +250,7 @@ for my $test (
$mech->get_ok('/contact');
}
$mech->submit_form_ok( { with_fields => $test->{fields} } );
- $mech->content_contains('Thank you for your feedback');
+ $mech->content_contains('Thank you for your enquiry');
my $email = $mech->get_email;
@@ -376,7 +376,7 @@ for my $test (
$mech->clear_emails_ok;
$mech->get_ok('/contact');
$mech->submit_form_ok( { with_fields => $test->{fields} } );
- $mech->content_contains('Thank you for your feedback');
+ $mech->content_contains('Thank you for your enquiry');
$mech->email_count_is(1);
}
};
diff --git a/t/app/controller/my_planned.t b/t/app/controller/my_planned.t
index 25f82224e..7bd1dd2cd 100644
--- a/t/app/controller/my_planned.t
+++ b/t/app/controller/my_planned.t
@@ -13,8 +13,8 @@ my $body = $mech->create_body_ok(2237, 'Oxfordshire');
my ($problem) = $mech->create_problems_for_body(1, $body->id, 'Test Title');
$mech->get_ok($problem->url);
-$mech->content_lacks('Add to planned reports');
-$mech->content_lacks('Remove from planned reports');
+$mech->content_lacks('Shortlist');
+$mech->content_lacks('Shortlisted');
my $user = $mech->log_in_ok( 'test@example.com' );
$user->update({ from_body => $body });
@@ -39,11 +39,11 @@ $mech->get_ok('/my/planned');
$mech->content_contains('Test Title');
$mech->get_ok($problem->url);
-$mech->content_contains('Remove from planned reports');
+$mech->content_contains('Shortlisted');
$mech->submit_form_ok({ with_fields => { change => 'remove' } });
-$mech->content_contains('Add to planned reports');
+$mech->content_contains('Shortlist');
$mech->submit_form_ok({ with_fields => { change => 'add' } });
-$mech->content_contains('Remove from planned reports');
+$mech->content_contains('Shortlisted');
done_testing();
diff --git a/t/app/sendreport/inspection_required.t b/t/app/sendreport/inspection_required.t
index 178fa2a1f..88a48e991 100644
--- a/t/app/sendreport/inspection_required.t
+++ b/t/app/sendreport/inspection_required.t
@@ -52,8 +52,28 @@ subtest 'Report is sent when inspected' => sub {
ok $report->whensent, 'Report marked as sent';
};
+subtest 'Uninspected report is sent when made by trusted user' => sub {
+ $mech->clear_emails_ok;
+ $report->unset_extra_metadata('inspected');
+ $report->whensent( undef );
+ $report->update;
+
+ $user->user_body_permissions->find_or_create({
+ body => $body,
+ permission_type => 'trusted',
+ });
+ ok $user->has_permission_to('trusted', $report->bodies_str_ids), 'User can make trusted reports';
+
+ FixMyStreet::DB->resultset('Problem')->send_reports();
+
+ $report->discard_changes;
+ $mech->email_count_is( 1 );
+ ok $report->whensent, 'Report marked as sent';
+};
+
done_testing();
END {
+ $mech->delete_user($user);
$mech->delete_body($body);
}
diff --git a/t/utils.t b/t/utils.t
index 29759cddc..ac9eb1a4a 100644
--- a/t/utils.t
+++ b/t/utils.t
@@ -4,6 +4,9 @@ use strict;
use warnings;
use Test::More;
+use mySociety::Locale;
+mySociety::Locale::gettext_domain('FixMyStreet');
+
use Utils;
my @truncate_tests = (
@@ -34,9 +37,14 @@ foreach my $test (@convert_en_to_latlon_tests) {
[ Utils::convert_en_to_latlon_truncated( $e, $n ) ], #
[ $lat, $lon ], #
"convert ($e,$n) to ($lat,$lon)";
+ is_deeply
+ [ Utils::convert_latlon_to_en( $lat, $lon ) ],
+ [ $e, $n ],
+ "convert ($lat,$lon) to ($e,$n)";
}
my @cleanup_tests = (
+ [ '', '', '' ],
[ 'dog shit', 'Dog poo', 'dog poo' ],
[ 'dog shit', 'Dog poo', 'with spaces' ],
[ 'dog shite', 'Dog poo', 'with extra e' ],
@@ -57,4 +65,32 @@ foreach my $test ( @cleanup_tests ) {
is Utils::cleanup_text( "This has new\n\n\nlines in it", { allow_multiline => 1 } ), "This has new\n\nLines in it", 'new lines allowed';
+
+is Utils::prettify_dt(), "[unknown time]";
+my $dt = DateTime->now;
+is Utils::prettify_dt($dt), $dt->strftime("%H:%M today");
+
+# Same week test
+if ($dt->day_of_week == 7) { # Sunday
+ $dt = DateTime->now->add(days => 1);
+} else {
+ $dt = DateTime->now->subtract(days => 1);
+}
+is Utils::prettify_dt($dt), $dt->strftime("%H:%M, %A");
+
+$dt = DateTime->now->subtract(days => 100);
+is Utils::prettify_dt($dt), $dt->strftime("%H:%M, %A %e %B %Y");
+is Utils::prettify_dt($dt, "date"), $dt->strftime("%A %e %B %Y");
+is Utils::prettify_dt($dt, "zurich"), $dt->strftime("%H:%M, %e. %B %Y");
+is Utils::prettify_dt($dt, "short"), $dt->strftime("%H:%M, %e %b %Y");
+is Utils::prettify_dt($dt, 1), $dt->strftime("%H:%M, %e %b %Y");
+$dt = DateTime->now->subtract(days => 400);
+is Utils::prettify_dt($dt), $dt->strftime("%H:%M, %a %e %B %Y");
+
+is Utils::prettify_duration(7*86400+3600+60+1, 'week'), '1 week';
+is Utils::prettify_duration(86400+3600+60+1, 'day'), '1 day';
+is Utils::prettify_duration(86400+3600+60+1, 'hour'), '1 day, 1 hour';
+is Utils::prettify_duration(86400+3600+60+1, 'minute'), '1 day, 1 hour, 1 minute';
+is Utils::prettify_duration(20, 'minute'), 'less than a minute';
+
done_testing();
diff --git a/t/utils/email.t b/t/utils/email.t
new file mode 100644
index 000000000..23814c1d7
--- /dev/null
+++ b/t/utils/email.t
@@ -0,0 +1,34 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use Test::More;
+use Test::MockModule;
+
+use Utils::Email;
+
+my $resolver = Test::MockModule->new('Net::DNS::Resolver');
+$resolver->mock('send', sub {
+ my ($self, $domain, $type) = @_;
+ my @rrs;
+ is $type, 'TXT';
+ if ($domain eq '_dmarc.yahoo.com') {
+ @rrs = (
+ Net::DNS::RR->new(name => '_dmarc.yahoo.com', type => 'TXT', txtdata => 'p=reject'),
+ Net::DNS::RR->new(name => '_dmarc.yahoo.com', type => 'A'),
+ );
+ } elsif ($domain eq 'cname.example.com') {
+ @rrs = Net::DNS::RR->new(name => 'cname.example.com', type => 'TXT', txtdata => 'p=none');
+ } else {
+ @rrs = Net::DNS::RR->new(name => '_dmarc.example.net', type => 'CNAME', cname => 'cname.example.com');
+ }
+ my $pkt = Net::DNS::Packet->new;
+ push @{$pkt->{answer}}, @rrs;
+ return $pkt;
+});
+
+is Utils::Email::test_dmarc('BAD'), undef;
+is Utils::Email::test_dmarc('test@yahoo.com'), 1;
+is Utils::Email::test_dmarc('test@example.net'), undef;
+
+done_testing();
diff --git a/templates/web/base/admin/response_templates_select.html b/templates/web/base/admin/response_templates_select.html
index 33f50170e..fbe09268e 100644
--- a/templates/web/base/admin/response_templates_select.html
+++ b/templates/web/base/admin/response_templates_select.html
@@ -1,3 +1,4 @@
+[% IF problem.response_templates %]
<div class="response_templates_select">
<select id="templates_for_[% for %]" class="js-template-name" data-for="[% for %]" name="response_template">
<option value="">[% loc('--Choose a template--') %]</option>
@@ -6,3 +7,4 @@
[% END %]
</select>
</div>
+[% END %]
diff --git a/templates/web/base/admin/user-form.html b/templates/web/base/admin/user-form.html
index 8a9ba5a77..40e0b510a 100644
--- a/templates/web/base/admin/user-form.html
+++ b/templates/web/base/admin/user-form.html
@@ -23,7 +23,7 @@
<li><label for="phone">[% loc('Phone:') %]</label>
<input type='text' id='phone' name='phone' value='[% user.phone | html %]'></li>
- [% IF c.user.is_superuser %]
+ [% IF c.user.is_superuser || c.cobrand.moniker == 'zurich' %]
<li>
<div class="admin-hint">
<p>
@@ -53,7 +53,7 @@
</li>
[% END %]
- [% IF areas %]
+ [% IF areas AND c.cobrand.moniker != 'zurich' %]
<li>
<div class="admin-hint">
<p>
@@ -85,10 +85,33 @@
[% loc("You can add an abusive user's email to the abuse list, which automatically hides (and never sends) reports they create.") %]
</p>
</div>
-
+
[% loc('Flagged:') %] <input type="checkbox" id="flagged" name="flagged"[% user.flagged ? ' checked' : '' %]>
</li>
+ [% UNLESS user.is_superuser %]
+ <li>
+ <div class="admin-hint">
+ <p>
+ [% loc("Reports made by trusted users will be sent to the responsible body without being inspected first.") %]
+ </p>
+ </div>
+ [% IF c.user.is_superuser %]
+ [% loc('Trusted by bodies:') %]<br />
+ <select id='body' name='trusted_bodies' multiple>
+ [% FOR body IN bodies %]
+ <option value="[% body.id %]"[% ' selected' IF user.has_permission_to('trusted', body.id) %]>[% body.name %]</option>
+ [% END %]
+ </select>
+ [% ELSE %]
+ <label>
+ [% loc('Trusted:') %]
+ <input type="checkbox" id="trusted_bodies" name="trusted_bodies" value="[% c.user.from_body.id %]" [% 'checked' IF user.has_permission_to('trusted', c.user.from_body.id) %]>
+ </label>
+ [% END %]
+ </li>
+ [% END %]
+
[% IF c.user.is_superuser %]
<li>
<div class="admin-hint">
diff --git a/templates/web/base/contact/submit.html b/templates/web/base/contact/submit.html
index 5adb87e2d..4bf82dcd6 100644
--- a/templates/web/base/contact/submit.html
+++ b/templates/web/base/contact/submit.html
@@ -3,7 +3,7 @@
[% IF success %]
<div class="confirmation-header">
- <h1>[% loc('Thank you for your feedback') %]</h1>
+ <h1>[% loc('Thank you for your enquiry') %]</h1>
<p>[% loc('We’ll get back to you as soon as we can.') %]</p>
</div>
diff --git a/templates/web/base/my/planned.html b/templates/web/base/my/planned.html
index 2e852ea01..19d29f970 100644
--- a/templates/web/base/my/planned.html
+++ b/templates/web/base/my/planned.html
@@ -1,7 +1,7 @@
[%
SET bodyclass = 'mappage';
PROCESS "maps/${map.type}.html" IF problems.size;
- INCLUDE 'header.html', title = loc('Your planned reports')
+ INCLUDE 'header.html', title = loc('Your shortlist')
%]
[% IF problems.size %]
@@ -14,10 +14,10 @@
<div id="skipped-map">
[% END %]
-<h1>[% loc('Your planned reports') %]</h1>
+<h1>[% loc('Your shortlist') %]</h1>
[% IF ! has_content %]
-[% loc('You haven&rsquo;t planned any reports yet.') %]
+[% loc('You haven&rsquo;t shortlisted any reports yet.') %]
[% END %]
<section class="full-width">
diff --git a/templates/web/base/questionnaire/index.html b/templates/web/base/questionnaire/index.html
index a93039827..217bd827e 100644
--- a/templates/web/base/questionnaire/index.html
+++ b/templates/web/base/questionnaire/index.html
@@ -48,22 +48,22 @@
[% loc('Has this problem been fixed?') %]
</p>
-<p class="radio-segmented-control">
+<p class="segmented-control segmented-control--radio">
<input type="radio" name="been_fixed" id="been_fixed_yes" value="Yes"[% ' checked' IF been_fixed == 'Yes' %]>
- <label class="inline" for="been_fixed_yes">[% loc('Yes') %]</label>
+ <label for="been_fixed_yes">[% loc('Yes') %]</label>
<input type="radio" name="been_fixed" id="been_fixed_no" value="No"[% ' checked' IF been_fixed == 'No' %]>
- <label class="inline" for="been_fixed_no">[% loc('No') %]</label>
+ <label for="been_fixed_no">[% loc('No') %]</label>
<input type="radio" name="been_fixed" id="been_fixed_unknown" value="Unknown"[% ' checked' IF been_fixed == 'Unknown' %]>
- <label class="inline" for="been_fixed_unknown">[% loc('Don&rsquo;t know') %]</label>
+ <label for="been_fixed_unknown">[% loc('Don&rsquo;t know') %]</label>
</p>
[% UNLESS answered_ever_reported %]
<p>[% loc('Have you ever reported a problem to a council before, or is this your first time?') %]</p>
-<p class="radio-segmented-control">
+<p class="segmented-control segmented-control--radio">
<input type="radio" name="reported" id="reported_yes" value="Yes"[% ' checked' IF reported == 'Yes' %]>
- <label class="inline" for="reported_yes">[% loc('Reported before') %]</label>
+ <label for="reported_yes">[% loc('Reported before') %]</label>
<input type="radio" name="reported" id="reported_no" value="No"[% ' checked' IF reported == 'No' %]>
- <label class="inline" for="reported_no">[% loc('First time') %]</label>
+ <label for="reported_no">[% loc('First time') %]</label>
</p>
[% END %]
@@ -99,11 +99,11 @@
<div class="js-another-questionnaire">
<p>[% loc('Would you like to receive another questionnaire in 4 weeks, reminding you to check the status?') %]</p>
- <p class="radio-segmented-control">
+ <p class="segmented-control segmented-control--radio">
<input type="radio" name="another" id="another_yes" value="Yes"[% ' checked' IF another == 'Yes' %]>
- <label class="inline" for="another_yes">[% loc('Yes') %]</label>
+ <label for="another_yes">[% loc('Yes') %]</label>
<input type="radio" name="another" id="another_no" value="No"[% ' checked' IF another == 'No' %]>
- <label class="inline" for="another_no">[% loc('No') %]</label>
+ <label for="another_no">[% loc('No') %]</label>
</p>
</div>
diff --git a/templates/web/base/report/_main.html b/templates/web/base/report/_main.html
index e02d4b2b0..a85bca08f 100644
--- a/templates/web/base/report/_main.html
+++ b/templates/web/base/report/_main.html
@@ -7,20 +7,26 @@
<div class="problem-header clearfix" problem-id="[% problem.id %]">
-[% IF c.user.has_permission_to('planned_reports', problem.bodies_str) %]
-<form method="post" action="/my/planned/change" id="planned_form">
+[% IF c.user.has_permission_to('planned_reports', problem.bodies_str_ids) %]
+<form method="post" action="/my/planned/change" id="planned_form" class="hidden-label-target">
<input type="hidden" name="id" value="[% problem.id %]">
<input type="hidden" name="token" value="[% csrf_token %]">
<input type="hidden" name="change" value="[% IF c.user.is_planned_report(problem) %]remove[% ELSE %]add[% END %]">
- <p><input type="submit"
- data-remove="[% loc('Remove from planned reports') %]" data-add="[% loc('Add to planned reports') %]"
- value="
+ <p><input
+ type="submit"
+ id="shortlist-report"
+ data-label-remove="[% loc('Remove from shortlist') %]"
+ data-label-add="[% loc('Add to shortlist') %]"
+ data-value-remove="[% loc('Shortlisted') %]"
+ data-value-add="[% loc('Shortlist') %]"
[%~ IF c.user.is_planned_report(problem) ~%]
- [% loc('Remove from planned reports') %]
+ value="[% loc('Shortlisted') %]"
+ aria-label="[% loc('Remove from shortlist') %]"
[%~ ELSE ~%]
- [% loc('Add to planned reports') %]
+ value="[% loc('Shortlist') %]"
+ aria-label="[% loc('Add to shortlist') %]"
[%~ END ~%]
- "></p>
+ ></p>
</form>
[% END %]
@@ -106,25 +112,39 @@
</div>
[% END %]
- [% IF permissions.keys.grep('moderate|report_inspect|report_edit_category|report_edit_priority').size %]
- <p class="moderate-display">
+ [% IF permissions.moderate %]
+ </form>
+ [% END %]
+
+ [% IF
+ (permissions.moderate)
+ OR
+ (!hide_inspect_button AND
+ permissions.keys.grep('report_inspect|report_edit_category|report_edit_priority').size)
+ OR
+ (c.user.has_permission_to('planned_reports', problem.bodies_str_ids))
+ %]
+ <div class="moderate-display segmented-control" role="menu">
[% IF permissions.moderate %]
- <input type="button" class="btn moderate" value="Moderate this report">
+ <a id="moderate-report" role="menuitem" aria-label="[% loc('Moderate this report') %]">[% loc('Moderate') %]</a>
[% END %]
[% IF !hide_inspect_button AND permissions.keys.grep('report_inspect|report_edit_category|report_edit_priority').size %]
- <a href="/report/[% problem.id %]/inspect" class="btn inspect">
- [%- IF permissions.report_inspect %]
- [%- loc('Inspect') %]
- [%- ELSE %]
- [%- loc('Manage') %]
- [%- END ~%]
- </a>
+ <a href="/report/[% problem.id %]/inspect" role="menuitem">
+ [%~ IF permissions.report_inspect ~%]
+ [%~ loc('Inspect') ~%]
+ [%~ ELSE ~%]
+ [%~ loc('Manage') ~%]
+ [%~ END ~%]
+ </a>
[% END %]
- </p>
- [% END %]
-
- [% IF permissions.moderate %]
- </form>
+ [% IF c.user.has_permission_to('planned_reports', problem.bodies_str_ids) %]
+ [%~ IF c.user.is_planned_report(problem) ~%]
+ <label for="shortlist-report" role="menuitem" aria-label="[% loc('Remove from shortlist') %]">[% loc('Shortlisted') %]</label>
+ [%~ ELSE ~%]
+ <label for="shortlist-report" role="menuitem" aria-label="[% loc('Add to shortlist') %]">[% loc('Shortlist') %]</label>
+ [%~ END ~%]
+ [% END %]
+ </div>
[% END %]
[% TRY %][% PROCESS 'report/_main_after.html' %][% CATCH file %][% END %]
diff --git a/templates/web/base/report/new/after_photo.html b/templates/web/base/report/new/after_photo.html
index cdebab462..b337977e4 100644
--- a/templates/web/base/report/new/after_photo.html
+++ b/templates/web/base/report/new/after_photo.html
@@ -1,7 +1,6 @@
<div class="description_tips" aria-label="[% loc('Tips for perfect photos') %]">
<ul class="do">
- <li>[% loc('Show what the problem is') %]</li>
- <li>[% loc('Show where it’s located') %]</li>
+ <li>[% loc('For best results include a close-up and a wide shot') %]</li>
</ul>
<ul class="dont">
<li>[% loc('Avoid personal information and vehicle number plates') %]</li>
diff --git a/templates/web/base/report/new/form_user_loggedin.html b/templates/web/base/report/new/form_user_loggedin.html
index 4935a6481..7fc1b1b5f 100644
--- a/templates/web/base/report/new/form_user_loggedin.html
+++ b/templates/web/base/report/new/form_user_loggedin.html
@@ -5,8 +5,8 @@
[% INCLUDE form_as %]
</div>
[% ELSE %]
- [% can_contribute_as_another_user = c.user.has_permission_to("contribute_as_another_user", bodies.keys.join(",")) %]
- [% can_contribute_as_body = c.user.from_body AND c.user.has_permission_to("contribute_as_body", bodies.keys.join(",")) %]
+ [% can_contribute_as_another_user = c.user.has_permission_to("contribute_as_another_user", bodies.keys) %]
+ [% can_contribute_as_body = c.user.from_body AND c.user.has_permission_to("contribute_as_body", bodies.keys) %]
[% IF can_contribute_as_another_user OR can_contribute_as_body %]
[% INCLUDE form_as %]
[% END %]
diff --git a/templates/web/base/report/update.html b/templates/web/base/report/update.html
index 55fdeb3b1..104e1d6f9 100644
--- a/templates/web/base/report/update.html
+++ b/templates/web/base/report/update.html
@@ -1,4 +1,4 @@
-[% moderating = c.user && c.user.has_permission_to('moderate', problem.bodies_str) %]
+[% moderating = c.user && c.user.has_permission_to('moderate', problem.bodies_str_ids) %]
[% IF loop.first %]
<section class="full-width">
diff --git a/templates/web/base/report/update/form_name.html b/templates/web/base/report/update/form_name.html
index 5d4c719ae..19c31998e 100644
--- a/templates/web/base/report/update/form_name.html
+++ b/templates/web/base/report/update/form_name.html
@@ -2,8 +2,8 @@
[% PROCESS 'user/_anonymity.html' anonymous = update.anonymous %]
- [% can_contribute_as_another_user = c.user.has_permission_to("contribute_as_another_user", problem.bodies_str) %]
- [% can_contribute_as_body = c.user.from_body AND c.user.has_permission_to("contribute_as_body", problem.bodies_str) %]
+ [% can_contribute_as_another_user = c.user.has_permission_to("contribute_as_another_user", problem.bodies_str_ids) %]
+ [% can_contribute_as_body = c.user.from_body AND c.user.has_permission_to("contribute_as_body", problem.bodies_str_ids) %]
[% IF can_contribute_as_another_user OR can_contribute_as_body %]
<label for="form_as">[% loc('Provide update as') %]</label>
diff --git a/templates/web/fixmystreet.com/about/council.html b/templates/web/fixmystreet.com/about/council.html
index cd28a7269..651e4f57f 100644
--- a/templates/web/fixmystreet.com/about/council.html
+++ b/templates/web/fixmystreet.com/about/council.html
@@ -260,6 +260,7 @@
</div>
<div class="form-group submit-group">
<input type="hidden" name="subject" value="Councils submission">
+ <input type="hidden" name="recipient" value="enquiries">
<input type="hidden" name="dest" value="from_council">
<input type="submit" value="Send">
</div>
diff --git a/templates/web/fixmystreet.com/report/new/extra_name.html b/templates/web/fixmystreet.com/report/new/extra_name.html
index 80ab1837a..f329541c3 100644
--- a/templates/web/fixmystreet.com/report/new/extra_name.html
+++ b/templates/web/fixmystreet.com/report/new/extra_name.html
@@ -8,7 +8,7 @@ shared with the council or displayed publicly.</em>
</p>
[% SET gender = report.get_extra_metadata('gender') %]
-<p class="radio-segmented-control" style="font-size: 80%">
+<p class="segmented-control segmented-control--radio" style="font-size: 80%">
<input type="radio" name="gender" id="gender_female" value="female"[% ' checked' IF gender == 'female' %]>
<label for="gender_female">Female</label>
<input type="radio" name="gender" id="gender_male" value="male"[% ' checked' IF gender == 'male' %]>
diff --git a/templates/web/oxfordshire/header.html b/templates/web/oxfordshire/header.html
index d5884272b..5b5532b67 100644
--- a/templates/web/oxfordshire/header.html
+++ b/templates/web/oxfordshire/header.html
@@ -45,7 +45,7 @@
[% IF c.user_exists AND c.user.has_body_permission_to('planned_reports') %]
<li>
<[% IF c.req.uri.path == '/my/planned' %]span[% ELSE %]a href="/my/planned"[% END
- %]>[% loc('Planned reports') %]</[% c.req.uri.path == '/my/planned' ? 'span' : 'a' %]>
+ %]>[% loc('Shortlist') %]</[% c.req.uri.path == '/my/planned' ? 'span' : 'a' %]>
</li>
[% END %]
<li>
diff --git a/templates/web/zurich/maps/noscript_map.html b/templates/web/zurich/maps/noscript_map.html
index dcd577c52..4925f9260 100644
--- a/templates/web/zurich/maps/noscript_map.html
+++ b/templates/web/zurich/maps/noscript_map.html
@@ -1,3 +1,4 @@
+[% IF map.cols %]
<div class="noscript square-map__outer">
<div class="square-map__inner">
<div id="[% nsm_prefix %]drag">
@@ -19,6 +20,35 @@
[% INCLUDE 'maps/_compass.html' %]
</div>
</div>
+[% ELSE %]
+<div class="noscript">
+ <div id="[% nsm_prefix %]drag">
+ <[% map.img_type %]
+ alt="NW map tile" id="[% nsm_prefix %]t2.2"
+ name="tile_[% map.x_tile - 1 %].[% map.y_tile - 1 %]"
+ src="[% map.tiles.0 %]"
+ style="top:0; left:0;">
+ <[% map.img_type %]
+ alt="NE map tile" id="[% nsm_prefix %]t2.3"
+ name="tile_[% map.x_tile %].[% map.y_tile - 1 %]"
+ src="[% map.tiles.1 %]"
+ style="top:0px; left:256px;">
+ <br>
+ <[% map.img_type %]
+ alt="SW map tile" id="[% nsm_prefix %]t3.2"
+ name="tile_[% map.x_tile - 1 %].[% map.y_tile %]"
+ src="[% map.tiles.2 %]"
+ style="top:256px; left:0;">
+ <[% map.img_type %]
+ alt="SE map tile" id="[% nsm_prefix %]t3.3"
+ name="tile_[% map.x_tile %].[% map.y_tile %]"
+ src="[% map.tiles.3 %]"
+ style="top:256px; left:256px;">
+ </div>
+ <div id="[% nsm_prefix %]pins">[% FOR pin IN map.pins %][% INCLUDE 'maps/pin.html' %][% END %]</div>
+ [% INCLUDE 'maps/_compass.html' %]
+</div>
+[% END %]
[% BLOCK pin %]
[%
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index 51ed30880..8d45e4017 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -281,16 +281,25 @@ $.extend(fixmystreet.set_up, {
var $form = $(this),
$change = $form.find("input[name='change']" ),
$submit = $form.find("input[type='submit']" ),
- data = $form.serialize() + '&ajax=1';
+ $labels = $('label[for="' + $submit.attr('id') + '"]'),
+ data = $form.serialize() + '&ajax=1',
+ changeValue,
+ buttonLabel,
+ buttonValue;
$.post(this.action, data, function(data) {
if (data.outcome == 'add') {
- $change.val('remove');
- $submit.val($submit.data('remove'));
+ changeValue = "remove";
+ buttonLabel = $submit.data('label-remove');
+ buttonValue = $submit.data('value-remove');
} else if (data.outcome == 'remove') {
- $change.val('add');
- $submit.val($submit.data('add'));
+ changeValue = "add";
+ buttonLabel = $submit.data('label-add');
+ buttonValue = $submit.data('value-add');
}
+ $change.val(changeValue);
+ $submit.val(buttonValue).attr('aria-label', buttonLabel);
+ $labels.text(buttonValue).attr('aria-label', buttonLabel);
});
});
},
@@ -793,7 +802,7 @@ $.extend(fixmystreet.set_up, {
function add_handlers (elem, word) {
elem.each( function () {
var $elem = $(this);
- $elem.find('.moderate').click( function () {
+ $elem.find('#moderate-report').on('click', function () {
$elem.find('.moderate-display').hide();
$elem.find('.moderate-edit').show();
});
diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss
index e5d2c48dd..7462682ee 100644
--- a/web/cobrands/sass/_base.scss
+++ b/web/cobrands/sass/_base.scss
@@ -1035,6 +1035,11 @@ input.final-submit {
.problem-header {
margin-bottom: 1em;
+
+ // Clear the admin actions after the floated photo(s).
+ .segmented-control {
+ clear: both;
+ }
}
.report_meta_info,
@@ -1796,41 +1801,49 @@ table.nicetable {
margin-left: 0;
}
-.radio-segmented-control {
- overflow: auto; // clear floats (if browser doesn't support flexbox)
+.segmented-control {
+ @include clearfix();
display: flex; // fancy full-width buttons for browsers that support flexbox
- input {
- position: absolute;
- left: -999px;
- }
-
- label {
+ & > * {
display: block;
margin: 0;
- padding: 0.75em 1.5em;
+ padding: 0.75em 0.5em;
text-align: center;
background: #fff linear-gradient(to bottom, #fff 0%, #eee 100%) 0 0 no-repeat;
- border: 1px solid #ddd;
+ border: 1px solid #ccc;
border-right-width: 0; // avoid double border between items
font-weight: bold;
+ color: inherit !important;
+ text-decoration: none !important;
+ cursor: pointer;
float: left; // float fallback for browsers that don't support flexbox
flex: 1 0 auto;
- @media(max-width: 400px){
- // Shameful hack to stop the control expanding wider than the window
- // on narrow devices (eg: 320px iPhone), which would cause horizontal
- // scrolling, and clipped text on the new report page, for example.
- // Flexbox will add the spacing back in anyway. Ideally we'd only apply
- // this style if flexbox is supported, but there's no easy way to do that.
- padding: 0.75em 0;
- }
-
- &:hover, &:focus {
+ &:hover {
background: #f3f3f3 linear-gradient(to bottom, #f9f9f9 0%, #e9e9e9 100%) 0 0 no-repeat;
}
}
+ & > :first-child {
+ border-radius: 0.25em 0 0 0.25em;
+ }
+
+ & > :last-child {
+ border-radius: 0 0.25em 0.25em 0;
+ border-right-width: 1px; // reinstate border on last item
+ }
+}
+
+// A special case of segmented control, where each "button" (or label) is
+// preceded by a radio button, which needs to be hidden but interactive.
+// Checked checkboxes give their following label a "pressed" appearance.
+.segmented-control--radio {
+ input {
+ position: absolute;
+ left: -999px;
+ }
+
input:checked + label {
color: $primary_text;
background: $primary;
@@ -1841,17 +1854,14 @@ table.nicetable {
}
input:checked + label + input + label {
- border-left-width: none; // in favour of the realistic coloured border on the selected item
+ border-left-width: 0; // in favour of the realistic coloured border on the selected label
}
+ // The first label is no longer the first child, so we need to
+ // fish it out specially with a next sibling selector.
input:first-child + label {
border-radius: 0.25em 0 0 0.25em;
}
-
- label:last-child {
- border-radius: 0 0.25em 0.25em 0;
- border-right-width: 1px; // reinstate border on last item
- }
}
.my-account-buttons a {
@@ -1861,6 +1871,25 @@ table.nicetable {
border-radius: 0.2em;
}
+// Useful for inserting hidden forms on the page, but still allowing
+// inputs inside the form to be toggled by labels outside the form.
+// Try using this in combination with .segmented-control for funtimes.
+.hidden-label-target {
+ position: absolute;
+ top: -100px;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ opacity: 0;
+
+ // Tell assistive devices to ignore this element.
+ visibility: hidden;
+
+ // Hack for IE8 which doesn't allow interaction with
+ // `visibility:hidden` elements.
+ visibility: visible\9;
+}
+
@media screen {
.print-only {