aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm90
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/AreaStats.pm27
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm15
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth/Phone.pm8
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth/Profile.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm6
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm46
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm11
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm2
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/State.pm6
-rw-r--r--perllib/FixMyStreet/SMS.pm4
-rw-r--r--perllib/FixMyStreet/Script/Alerts.pm21
-rw-r--r--t/Mock/MapIt.pm16
-rw-r--r--t/app/controller/alert_new.t229
-rw-r--r--t/app/controller/area_stats.t23
-rw-r--r--t/app/controller/around.t23
-rw-r--r--t/app/controller/auth_phone.t8
-rw-r--r--t/app/controller/report_inspect.t127
-rw-r--r--t/app/controller/reports.t12
-rw-r--r--templates/email/fixamingata/submit.html1
-rw-r--r--templates/web/base/admin/areastats/area.html2
-rw-r--r--templates/web/base/around/lookup_by_ref.html6
-rw-r--r--templates/web/base/maps/openlayers.html4
-rw-r--r--templates/web/base/report/_inspect.html2
-rwxr-xr-xtemplates/web/base/reports/body.html7
-rw-r--r--templates/web/oxfordshire/_email_sent_extra.html3
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js2
-rw-r--r--web/cobrands/sass/_base.scss35
-rw-r--r--web/cobrands/sass/_layout.scss8
31 files changed, 613 insertions, 144 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index baf561ebc..054564646 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,12 +6,19 @@
using confirmation by phone text.
- Improved email/phone management in your profile.
- Area summary statistics page in admin #1834
+ - Allow multiple wards to be shown on reports page
+ - Don't cover whole map with pin loading indicator.
+ - Add Expand map toggle to more mobile maps.
- Bugfixes
- Shortlist menu item always remains a link #1855
- Fix encoded entities in RSS output. #1859
+ - Only save category changes if staff user update valid #1857
+ - Only create one update when staff user updating category #1857
+ - Do not include blank updates in email alerts #1857
- Admin improvements:
- Character length limit can be placed on report detailed information #1848
- Inspector panel shows nearest address if available #1850
+ - Return a 200 rather than 404 for ref ID lookup.
* v2.2 (13th September 2017)
- New features:
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 0caa25710..719b04cf6 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -797,6 +797,19 @@ sub reports : Path('reports') {
}
+sub update_user : Private {
+ my ($self, $c, $object) = @_;
+ my $parsed = FixMyStreet::SMS->parse_username($c->get_param('username'));
+ if ($parsed->{email} || ($parsed->{phone} && $parsed->{may_be_mobile})) {
+ my $user = $c->model('DB::User')->find_or_create({ $parsed->{type} => $parsed->{username} });
+ if ($user->id && $user->id != $object->user->id) {
+ $object->user( $user );
+ return 1;
+ }
+ }
+ return 0;
+}
+
sub report_edit : Path('report_edit') : Args(1) {
my ( $self, $c, $id ) = @_;
@@ -901,14 +914,7 @@ sub report_edit : Path('report_edit') : Args(1) {
$problem->set_inflated_columns(\%columns);
$c->forward( '/admin/report_edit_category', [ $problem ] );
-
- my $parsed = FixMyStreet::SMS->parse_username($c->get_param('username'));
- if ($parsed->{email} || ($parsed->{phone} && $parsed->{phone}->is_mobile)) {
- my $user = $c->model('DB::User')->find_or_create({ $parsed->{type} => $parsed->{username} });
- if ($user->id && $user->id != $problem->user->id) {
- $problem->user( $user );
- }
- }
+ $c->forward('update_user', [ $problem ]);
# Deal with photos
my $remove_photo_param = $self->_get_remove_photo_param($c);
@@ -950,7 +956,7 @@ Handles changing a problem's category and the complexity that comes with it.
=cut
sub report_edit_category : Private {
- my ($self, $c, $problem) = @_;
+ my ($self, $c, $problem, $no_comment) = @_;
if ((my $category = $c->get_param('category')) ne $problem->category) {
my $category_old = $problem->category;
@@ -978,16 +984,21 @@ sub report_edit_category : Private {
}
$problem->bodies_str(join( ',', @new_body_ids ));
- $problem->add_to_comments({
- text => '*' . sprintf(_('Category changed from ‘%s’ to ‘%s’'), $category_old, $category) . '*',
- created => \'current_timestamp',
- confirmed => \'current_timestamp',
- user_id => $c->user->id,
- name => $c->user->from_body ? $c->user->from_body->name : $c->user->name,
- state => 'confirmed',
- mark_fixed => 0,
- anonymous => 0,
- });
+ my $update_text = '*' . sprintf(_('Category changed from ‘%s’ to ‘%s’'), $category_old, $category) . '*';
+ if ($no_comment) {
+ $c->stash->{update_text} = $update_text;
+ } else {
+ $problem->add_to_comments({
+ text => $update_text,
+ created => \'current_timestamp',
+ confirmed => \'current_timestamp',
+ user_id => $c->user->id,
+ name => $c->user->from_body ? $c->user->from_body->name : $c->user->name,
+ state => 'confirmed',
+ mark_fixed => 0,
+ anonymous => 0,
+ });
+ }
}
}
@@ -1251,14 +1262,7 @@ sub update_edit : Path('update_edit') : Args(1) {
$update->anonymous( $c->get_param('anonymous') );
$update->state( $new_state );
- my $parsed = FixMyStreet::SMS->parse_username($c->get_param('username'));
- if ($parsed->{email} || ($parsed->{phone} && $parsed->{phone}->is_mobile)) {
- my $user = $c->model('DB::User')->find_or_create({ $parsed->{type} => $parsed->{username} });
- if ($user->id && $user->id != $update->user->id) {
- $edited = 1;
- $update->user( $user );
- }
- }
+ $edited = 1 if $c->forward('update_user', [ $update ]);
if ( $new_state eq 'confirmed' and $old_state eq 'unconfirmed' ) {
$update->confirmed( \'current_timestamp' );
@@ -1298,6 +1302,18 @@ sub update_edit : Path('update_edit') : Args(1) {
return 1;
}
+sub phone_check : Private {
+ my ($self, $c, $phone) = @_;
+ my $parsed = FixMyStreet::SMS->parse_username($phone);
+ if ($parsed->{phone} && $parsed->{may_be_mobile}) {
+ return $parsed->{username};
+ } elsif ($parsed->{phone}) {
+ $c->stash->{field_errors}->{phone} = _('Please enter a mobile number');
+ } else {
+ $c->stash->{field_errors}->{phone} = _('Please check your phone number is correct');
+ }
+}
+
sub user_add : Path('user_edit') : Args(0) {
my ( $self, $c ) = @_;
@@ -1329,14 +1345,8 @@ sub user_add : Path('user_edit') : Args(0) {
}
if ($phone_v) {
- my $parsed = FixMyStreet::SMS->parse_username($phone);
- if ($parsed->{phone} && $parsed->{phone}->is_mobile) {
- $phone = $parsed->{username};
- } elsif ($parsed->{phone}) {
- $c->stash->{field_errors}->{phone} = _('Please enter a mobile number');
- } else {
- $c->stash->{field_errors}->{phone} = _('Please check your phone number is correct');
- }
+ my $parsed_phone = $c->forward('phone_check', [ $phone ]);
+ $phone = $parsed_phone if $parsed_phone;
}
my $existing_email = $email_v && $c->model('DB::User')->find( { email => $email } );
@@ -1417,14 +1427,8 @@ sub user_edit : Path('user_edit') : Args(1) {
}
if ($phone_v) {
- my $parsed = FixMyStreet::SMS->parse_username($phone);
- if ($parsed->{phone} && $parsed->{phone}->is_mobile) {
- $phone = $parsed->{username};
- } elsif ($parsed->{phone}) {
- $c->stash->{field_errors}->{phone} = _('Please enter a mobile number');
- } else {
- $c->stash->{field_errors}->{phone} = _('Please check your phone number is correct');
- }
+ my $parsed_phone = $c->forward('phone_check', [ $phone ]);
+ $phone = $parsed_phone if $parsed_phone;
}
unless ($user->name) {
diff --git a/perllib/FixMyStreet/App/Controller/Admin/AreaStats.pm b/perllib/FixMyStreet/App/Controller/Admin/AreaStats.pm
index 932631cba..2058ea872 100644
--- a/perllib/FixMyStreet/App/Controller/Admin/AreaStats.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin/AreaStats.pm
@@ -78,6 +78,8 @@ sub stats : Private {
my ($self, $c) = @_;
my $date = DateTime->now->subtract(days => 30);
+ # set it to midnight so we get consistent result through the day
+ $date->truncate( to => 'day' );
$c->forward('/admin/fetch_contacts');
@@ -145,21 +147,21 @@ sub stats : Private {
my $comments = $c->model('DB::Comment')->to_body(
$c->stash->{body}
)->search(
- $params,
{
- join => 'problem'
+ %$params,
+ 'me.id' => { 'in' => \"(select min(id) from comment where me.problem_id=comment.problem_id and problem_state not in ('', 'confirmed') group by problem_state)" },
+ },
+ {
+ join => 'problem',
+ group_by => [ 'problem_state' ],
+ select => [ 'problem_state', { count => 'me.id' } ],
+ as => [ qw/problem_state state_count/ ],
}
);
- # you can have multiple comments with the same problem state so need to only count
- # one instance.
- my %state_seen = ();
while (my $comment = $comments->next) {
my $meta_state = $state_map->{$comment->problem_state};
- my $key = $comment->problem->id . "-$meta_state";
- next if $state_seen{$key};
- $c->stash->{$meta_state} += 1;
- $state_seen{$key} = 1;
+ $c->stash->{$meta_state} += $comment->get_column('state_count');
}
$params = {
@@ -205,7 +207,12 @@ sub stats : Private {
join => 'problem'
}
)->first;
- $c->stash->{average} = int( ($comments->get_column('time')||0)/ 60 / 60 / 24 + 0.5 );
+ my $raw_average = $comments->get_column('time');
+ if (defined $raw_average) {
+ $c->stash->{average} = int( $raw_average / 60 / 60 / 24 + 0.5 );
+ } else {
+ $c->stash->{average} = -1;
+ }
}
sub load_user_body : Private {
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index 44ccb5259..6af780c35 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -8,6 +8,7 @@ use FixMyStreet::Map;
use Encode;
use JSON::MaybeXS;
use Utils;
+use Try::Tiny;
=head1 NAME
@@ -364,13 +365,17 @@ sub lookup_by_ref : Private {
external_id => $ref
]);
- if ( $problems->count == 0) {
- $c->detach( '/page_error_404_not_found', [] );
- } elsif ( $problems->count == 1 ) {
- $c->res->redirect( $c->uri_for( '/report', $problems->first->id ) );
- } else {
+ my $count = try {
+ $problems->count;
+ } catch {
+ 0;
+ };
+
+ if ($count > 1) {
$c->stash->{ref} = $ref;
$c->stash->{matching_reports} = [ $problems->all ];
+ } elsif ($count == 1) {
+ $c->res->redirect( $c->uri_for( '/report', $problems->first->id ) );
}
}
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index b453f593b..80e407147 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -119,7 +119,7 @@ sub code_sign_in : Private {
my $parsed = FixMyStreet::SMS->parse_username($username);
if ($parsed->{type} eq 'phone' && FixMyStreet->config('SMS_AUTHENTICATION')) {
- $c->forward('phone/sign_in', [ $parsed->{phone} ]);
+ $c->forward('phone/sign_in', [ $parsed ]);
} else {
$c->forward('email_sign_in', [ $parsed->{username} ]);
}
diff --git a/perllib/FixMyStreet/App/Controller/Auth/Phone.pm b/perllib/FixMyStreet/App/Controller/Auth/Phone.pm
index 4e9f92596..e4ffc2205 100644
--- a/perllib/FixMyStreet/App/Controller/Auth/Phone.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth/Phone.pm
@@ -45,19 +45,19 @@ and sets up the token/etc to deal with the response.
=cut
sub sign_in : Private {
- my ( $self, $c, $phone ) = @_;
+ my ( $self, $c, $parsed ) = @_;
- unless ($phone) {
+ unless ($parsed->{phone}) {
$c->stash->{username_error} = 'other_phone';
return;
}
- unless ($phone->is_mobile) {
+ unless ($parsed->{may_be_mobile}) {
$c->stash->{username_error} = 'nonmobile';
return;
}
- (my $number = $phone->format) =~ s/\s+//g;
+ (my $number = $parsed->{phone}->format) =~ s/\s+//g;
if ( FixMyStreet->config('SIGNUPS_DISABLED')
&& !$c->model('DB::User')->find({ phone => $number })
diff --git a/perllib/FixMyStreet/App/Controller/Auth/Profile.pm b/perllib/FixMyStreet/App/Controller/Auth/Profile.pm
index ecf009150..acffd3019 100644
--- a/perllib/FixMyStreet/App/Controller/Auth/Profile.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth/Profile.pm
@@ -118,14 +118,14 @@ sub change_phone : Path('/auth/change_phone') {
# If we've not used a mobile and we're not specifically verifying,
# and phone isn't our only verified way of logging in,
# then allow change of number (for e.g. landline).
- if (!FixMyStreet->config('SMS_AUTHENTICATION') || (!$parsed->{phone}->is_mobile && !$c->stash->{verifying} && $c->user->email_verified)) {
+ if (!FixMyStreet->config('SMS_AUTHENTICATION') || (!$parsed->{may_be_mobile} && !$c->stash->{verifying} && $c->user->email_verified)) {
$c->user->update({ phone => $phone, phone_verified => 0 });
$c->flash->{flash_message} = _('You have successfully added your phone number.');
$c->res->redirect('/my');
$c->detach;
}
- $c->forward('/auth/phone/sign_in', [ $parsed->{phone} ]);
+ $c->forward('/auth/phone/sign_in', [ $parsed ]);
}
sub verify_item : Path('/auth/verify') : Args(1) {
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index ba9fa11b9..c72c75d3a 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -424,7 +424,11 @@ sub inspect : Private {
}
if ($permissions->{report_inspect} || $permissions->{report_edit_category}) {
- $c->forward( '/admin/report_edit_category', [ $problem ] );
+ $c->forward( '/admin/report_edit_category', [ $problem, 1 ] );
+
+ if ($c->stash->{update_text}) {
+ $update_text .= "\n\n" . $c->stash->{update_text};
+ }
# The new category might require extra metadata (e.g. pothole size), so
# we need to update the problem with the new values.
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index 8f8205719..187dfb299 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -131,9 +131,10 @@ sub ward : Path : Args(2) {
$c->forward('/auth/get_csrf_token');
+ my @wards = split /\|/, $ward || "";
$c->forward( 'body_check', [ $body ] );
- $c->forward( 'ward_check', [ $ward ] )
- if $ward;
+ $c->forward( 'ward_check', [ @wards ] )
+ if @wards;
$c->forward( 'check_canonical_url', [ $body ] );
$c->forward( 'stash_report_filter_status' );
$c->forward( 'load_and_group_problems' );
@@ -166,7 +167,7 @@ sub ward : Path : Args(2) {
my %map_params = (
latitude => @$pins ? $pins->[0]{latitude} : 0,
longitude => @$pins ? $pins->[0]{longitude} : 0,
- area => $c->stash->{ward} ? $c->stash->{ward}->{id} : [ keys %{$c->stash->{body}->areas} ],
+ area => [ $c->stash->{wards} ? map { $_->{id} } @{$c->stash->{wards}} : keys %{$c->stash->{body}->areas} ],
any_zoom => 1,
);
FixMyStreet::Map::display_map(
@@ -176,7 +177,7 @@ sub ward : Path : Args(2) {
$c->cobrand->tweak_all_reports_map( $c );
# List of wards
- if ( !$c->stash->{ward} && $c->stash->{body}->id && $c->stash->{body}->body_areas->first ) {
+ if ( !$c->stash->{wards} && $c->stash->{body}->id && $c->stash->{body}->body_areas->first ) {
my $children = mySociety::MaPit::call('area/children', [ $c->stash->{body}->body_areas->first->area_id ],
type => $c->cobrand->area_types_children,
);
@@ -343,18 +344,20 @@ sub body_check : Private {
=head2 ward_check
-This action checks the ward name from a URI exists and is part of the right
+This action checks the ward names from a URI exists and are part of the right
parent, already found with body_check. It either stores the ward Area if
okay, or redirects to the body page if bad.
=cut
sub ward_check : Private {
- my ( $self, $c, $ward ) = @_;
+ my ( $self, $c, @wards ) = @_;
- $ward =~ s/\+/ /g;
- $ward =~ s/\.html//;
- $ward =~ s{_}{/}g;
+ foreach (@wards) {
+ s/\+/ /g;
+ s/\.html//;
+ s{_}{/}g;
+ }
# Could be from RSS area, or body...
my $parent_id;
@@ -366,15 +369,20 @@ sub ward_check : Private {
$parent_id = $c->stash->{area}->{id};
}
- my $qw = mySociety::MaPit::call('areas', $ward,
+ my $qw = mySociety::MaPit::call('area/children', [ $parent_id ],
type => $c->cobrand->area_types_children,
);
+ my %names = map { $_ => 1 } @wards;
+ my @areas;
foreach my $area (sort { $a->{name} cmp $b->{name} } values %$qw) {
- if ($area->{parent_area} == $parent_id) {
- $c->stash->{ward} = $area;
- return;
- }
+ push @areas, $area if $names{$area->{name}};
+ }
+ if (@areas) {
+ $c->stash->{ward} = $areas[0] if @areas == 1;
+ $c->stash->{wards} = \@areas;
+ return;
}
+
# Given a false ward name
$c->stash->{body} = $c->stash->{area}
unless $c->stash->{body};
@@ -448,8 +456,10 @@ sub load_and_group_problems : Private {
my $problems = $c->cobrand->problems;
- if ($c->stash->{ward}) {
- $where->{areas} = { 'like', '%,' . $c->stash->{ward}->{id} . ',%' };
+ if ($c->stash->{wards}) {
+ $where->{areas} = [
+ map { { 'like', '%,' . $_->{id} . ',%' } } @{$c->stash->{wards}}
+ ];
$problems = $problems->to_body($c->stash->{body});
} elsif ($c->stash->{body}) {
$problems = $problems->to_body($c->stash->{body});
@@ -510,8 +520,8 @@ sub redirect_body : Private {
$url .= "/rss" if $c->stash->{rss};
$url .= '/reports';
$url .= '/' . $c->cobrand->short_name( $c->stash->{body} );
- $url .= '/' . $c->cobrand->short_name( $c->stash->{ward} )
- if $c->stash->{ward};
+ $url .= '/' . join('|', map { $c->cobrand->short_name($_) } @{$c->stash->{wards}})
+ if $c->stash->{wards};
$c->res->redirect( $c->uri_for($url, $c->req->params ) );
}
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index 562f29693..409a6e1ab 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -274,14 +274,9 @@ sub problem_state_display {
return FixMyStreet::DB->resultset("State")->display('confirmed', 1);
} elsif ($self->problem_state) {
my $state = $self->problem_state;
- if ($state eq 'not responsible') {
- $update_state = _( "not the council's responsibility" );
- if ($cobrand eq 'bromley' || $self->problem->to_body_named('Bromley')) {
- $update_state = 'third party responsibility';
- }
- } else {
- $update_state = FixMyStreet::DB->resultset("State")->display($state, 1);
- }
+ my $cobrand_name = $cobrand;
+ $cobrand_name = 'bromley' if $self->problem->to_body_named('Bromley');
+ $update_state = FixMyStreet::DB->resultset("State")->display($state, 1, $cobrand_name);
}
return $update_state;
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index 296cf997d..d02039ac3 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -196,7 +196,7 @@ sub check_for_errors {
my $parsed = FixMyStreet::SMS->parse_username($self->phone);
if (!$parsed->{phone}) {
$errors{username} = _('Please check your phone number is correct');
- } elsif (!$parsed->{phone}->is_mobile) {
+ } elsif (!$parsed->{may_be_mobile}) {
$errors{username} = _('Please enter a mobile number');
}
}
diff --git a/perllib/FixMyStreet/DB/ResultSet/State.pm b/perllib/FixMyStreet/DB/ResultSet/State.pm
index de56c738c..3e6169aeb 100644
--- a/perllib/FixMyStreet/DB/ResultSet/State.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/State.pm
@@ -58,7 +58,7 @@ sub fixed { [ $_[0]->_filter(sub { $_->type eq 'fixed' }) ] }
# This function can be used to return that label's display name.
sub display {
- my ($rs, $label, $single_fixed) = @_;
+ my ($rs, $label, $single_fixed, $cobrand) = @_;
my $unchanging = {
unconfirmed => _("Unconfirmed"),
hidden => _("Hidden"),
@@ -72,6 +72,10 @@ sub display {
};
$label = 'fixed' if $single_fixed && $label =~ /^fixed - (council|user)$/;
return $unchanging->{$label} if $unchanging->{$label};
+ if ($cobrand && $label eq 'not responsible') {
+ return 'third party responsibility' if $cobrand eq 'bromley';
+ return _("not the council's responsibility");
+ }
my ($state) = $rs->_filter(sub { $_->label eq $label });
return $label unless $state;
$state->name($translate_now->{$label}) if $translate_now->{$label};
diff --git a/perllib/FixMyStreet/SMS.pm b/perllib/FixMyStreet/SMS.pm
index ec9251a1a..c71cceadc 100644
--- a/perllib/FixMyStreet/SMS.pm
+++ b/perllib/FixMyStreet/SMS.pm
@@ -94,15 +94,19 @@ sub parse_username {
}
};
+ my $may_be_mobile = 0;
if ($phone) {
$type = 'phone';
# Store phone without spaces
($username = $phone->format) =~ s/\s+//g;
+ # Is this mobile definitely or possibly a mobile? (+1 numbers)
+ $may_be_mobile = 1 if $phone->is_mobile || (!defined $phone->is_mobile && $phone->is_geographic);
}
return {
type => $type,
phone => $phone,
+ may_be_mobile => $may_be_mobile,
username => $username,
};
}
diff --git a/perllib/FixMyStreet/Script/Alerts.pm b/perllib/FixMyStreet/Script/Alerts.pm
index 86f11c7b5..4b5641f9e 100644
--- a/perllib/FixMyStreet/Script/Alerts.pm
+++ b/perllib/FixMyStreet/Script/Alerts.pm
@@ -39,6 +39,7 @@ sub send() {
$item_table.name as item_name, $item_table.anonymous as item_anonymous,
$item_table.confirmed as item_confirmed,
$item_table.photo as item_photo,
+ $item_table.problem_state as item_problem_state,
$head_table.*
from alert, $item_table, $head_table
where alert.parameter::integer = $head_table.id
@@ -65,6 +66,7 @@ sub send() {
$query = FixMyStreet::DB->schema->storage->dbh->prepare($query);
$query->execute();
my $last_alert_id;
+ my $last_problem_state = '';
my %data = ( template => $alert_type->template, data => [], schema => $schema );
while (my $row = $query->fetchrow_hashref) {
@@ -86,7 +88,26 @@ sub send() {
alert_id => $row->{alert_id},
parameter => $row->{item_id},
} );
+
+ # this is currently only for new_updates
+ if (defined($row->{item_text})) {
+ # this might throw up the odd false positive but only in cases where the
+ # state has changed and there was already update text
+ if ($row->{item_problem_state} &&
+ !( $last_problem_state eq '' && $row->{item_problem_state} eq 'confirmed' ) &&
+ $last_problem_state ne $row->{item_problem_state}
+ ) {
+ my $state = FixMyStreet::DB->resultset("State")->display($row->{item_problem_state}, 1, $cobrand);
+
+ my $update = _('State changed to:') . ' ' . $state;
+ $row->{item_text} = $row->{item_text} ? $row->{item_text} . "\n\n" . $update :
+ $update;
+ }
+ next unless $row->{item_text};
+ }
+
if ($last_alert_id && $last_alert_id != $row->{alert_id}) {
+ $last_problem_state = '';
_send_aggregated_alert_email(%data);
%data = ( template => $alert_type->template, data => [], schema => $schema );
}
diff --git a/t/Mock/MapIt.pm b/t/Mock/MapIt.pm
index 6e3c5d673..8dd10c53d 100644
--- a/t/Mock/MapIt.pm
+++ b/t/Mock/MapIt.pm
@@ -81,10 +81,6 @@ sub dispatch_request {
$self->output({2226 => {parent_area => undef, id => 2226, name => "Gloucestershire County Council", type => "CTY"}});
} elsif ($areas eq 'Cheltenham') {
$self->output({2326 => {parent_area => undef, id => 2326, name => "Cheltenham Borough Council", type => "DIS"}});
- } elsif ($areas eq 'Lansdown and Park') {
- $self->output({22261 => {parent_area => 2226, id => 22261, name => "Lansdown and Park", type => "CED"}});
- } elsif ($areas eq 'Lansdown') {
- $self->output({23261 => {parent_area => 2326, id => 23261, name => "Lansdown", type => "DIW"}});
} elsif ($areas eq 'UTA') {
$self->output({2650 => {parent_area => undef, id => 2650, name => "Aberdeen Council", type => "UTA"}});
}
@@ -104,6 +100,18 @@ sub dispatch_request {
sub (GET + /area/*/children) {
my ($self, $area) = @_;
+ if ($area eq '2514') {
+ return $self->output({
+ 8794 => {parent_area => 2514, id => 8794, name => "Aston", type => "MTW"},
+ 8773 => {parent_area => 2514, id => 8773, name => "Bournville", type => "MTW"},
+ });
+ }
+ if ($area eq '2326') {
+ return $self->output({23261 => {parent_area => 2326, id => 23261, name => "Lansdown", type => "DIW"}});
+ }
+ if ($area eq '2226') {
+ return $self->output({22261 => {parent_area => 2226, id => 22261, name => "Lansdown and Park", type => "CED"}});
+ }
my $response = {
"60705" => { "parent_area" => 2245, "generation_high" => 25, "all_names" => { }, "id" => 60705, "codes" => { "ons" => "00HY226", "gss" => "E04011842", "unit_id" => "17101" }, "name" => "Trowbridge", "country" => "E", "type_name" => "Civil parish/community", "generation_low" => 12, "country_name" => "England", "type" => "CPC" },
"62883" => { "parent_area" => 2245, "generation_high" => 25, "all_names" => { }, "id" => 62883, "codes" => { "ons" => "00HY026", "gss" => "E04011642", "unit_id" => "17205" }, "name" => "Bradford-on-Avon", "country" => "E", "type_name" => "Civil parish/community", "generation_low" => 12, "country_name" => "England", "type" => "CPC" },
diff --git a/t/app/controller/alert_new.t b/t/app/controller/alert_new.t
index 97a19b3b8..4e8fd1b29 100644
--- a/t/app/controller/alert_new.t
+++ b/t/app/controller/alert_new.t
@@ -475,7 +475,7 @@ subtest "Test normal alert signups and that alerts are sent" => sub {
$mech->delete_user($user2);
};
-subtest "Test alerts are correct for no-text updates" => sub {
+subtest "Test alerts are not sent for no-text updates" => sub {
$mech->delete_user( 'reporter@example.com' );
$mech->delete_user( 'alerts@example.com' );
@@ -513,6 +513,40 @@ subtest "Test alerts are correct for no-text updates" => sub {
my $report_id = $report->id;
ok $report, "created test report - $report_id";
+ my $report2 = FixMyStreet::App->model('DB::Problem')->create( {
+ postcode => 'EH1 1BB',
+ bodies_str => '1',
+ areas => ',11808,135007,14419,134935,2651,20728,',
+ category => 'Street lighting',
+ title => 'Testing',
+ detail => 'Testing Detail',
+ used_map => 1,
+ name => $user1->name,
+ anonymous => 0,
+ state => 'fixed - user',
+ confirmed => $dt_parser->format_datetime($dt),
+ lastupdate => $dt_parser->format_datetime($dt),
+ whensent => $dt_parser->format_datetime($dt->clone->add( minutes => 5 )),
+ lang => 'en-gb',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ send_questionnaire => 1,
+ latitude => '55.951963',
+ longitude => '-3.189944',
+ user_id => $user1->id,
+ } );
+ my $report2_id = $report2->id;
+ ok $report2, "created test report - $report2_id";
+
+ # Must be first
+ my $alert2 = FixMyStreet::App->model('DB::Alert')->create( {
+ parameter => $report2_id,
+ alert_type => 'new_updates',
+ user => $user2,
+ } )->confirm;
+ ok $alert2, 'created alert for other user';
+
my $alert = FixMyStreet::App->model('DB::Alert')->create( {
parameter => $report_id,
alert_type => 'new_updates',
@@ -533,6 +567,92 @@ subtest "Test alerts are correct for no-text updates" => sub {
my $update_id = $update->id;
ok $update, "created test update from staff user - $update_id";
+ my $update2 = FixMyStreet::App->model('DB::Comment')->create( {
+ problem_id => $report2_id,
+ user_id => $user3->id,
+ name => 'Staff User',
+ mark_fixed => 'false',
+ text => 'This is a normal update',
+ state => 'confirmed',
+ confirmed => $dt->clone->add( hours => 9 ),
+ anonymous => 'f',
+ } );
+ my $update2_id = $update2->id;
+ ok $update2, "created test update from staff user - $update2_id";
+
+ $mech->clear_emails_ok;
+ FixMyStreet::override_config {
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ FixMyStreet::Script::Alerts::send();
+ };
+
+ $mech->email_count_is(1);
+
+ $mech->delete_user($user1);
+ $mech->delete_user($user2);
+ $mech->delete_user($user3);
+};
+
+subtest "Test no marked as confirmed added to alerts" => sub {
+ $mech->delete_user( 'reporter@example.com' );
+ $mech->delete_user( 'alerts@example.com' );
+
+ my $user1 = $mech->create_user_ok('reporter@example.com', name => 'Reporter User' );
+ my $user2 = $mech->create_user_ok('alerts@example.com', name => 'Alert User' );
+ my $user3 = $mech->create_user_ok('staff@example.com', name => 'Staff User', from_body => $gloucester );
+ my $dt = DateTime->now(time_zone => 'Europe/London')->add(days => 2);
+
+ my $dt_parser = FixMyStreet::App->model('DB')->schema->storage->datetime_parser;
+
+ my $report_time = '2011-03-01 12:00:00';
+ my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( {
+ postcode => 'EH1 1BB',
+ bodies_str => '1',
+ areas => ',11808,135007,14419,134935,2651,20728,',
+ category => 'Street lighting',
+ title => 'Testing',
+ detail => 'Testing Detail',
+ used_map => 1,
+ name => $user1->name,
+ anonymous => 0,
+ state => 'confirmed',
+ confirmed => $dt_parser->format_datetime($dt),
+ lastupdate => $dt_parser->format_datetime($dt),
+ whensent => $dt_parser->format_datetime($dt->clone->add( minutes => 5 )),
+ lang => 'en-gb',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ send_questionnaire => 1,
+ latitude => '55.951963',
+ longitude => '-3.189944',
+ user_id => $user1->id,
+ } );
+ my $report_id = $report->id;
+ ok $report, "created test report - $report_id";
+
+ my $alert = FixMyStreet::App->model('DB::Alert')->create( {
+ parameter => $report_id,
+ alert_type => 'new_updates',
+ user => $user2,
+ } )->confirm;
+ ok $alert, 'created alert for other user';
+
+ my $update = FixMyStreet::App->model('DB::Comment')->create( {
+ problem_id => $report_id,
+ user_id => $user3->id,
+ name => 'Staff User',
+ mark_fixed => 'false',
+ text => 'this is update',
+ state => 'confirmed',
+ problem_state => 'confirmed',
+ confirmed => $dt->clone->add( hours => 9 ),
+ anonymous => 'f',
+ } );
+ my $update_id = $update->id;
+ ok $update, "created test update from staff user - $update_id";
+
$mech->clear_emails_ok;
FixMyStreet::override_config {
MAPIT_URL => 'http://mapit.uk/',
@@ -545,15 +665,116 @@ subtest "Test alerts are correct for no-text updates" => sub {
my $body = $mech->get_text_body_from_email($email);
like $body, qr/The following updates have been left on this report:/, 'email is about updates to existing report';
like $body, qr/Staff User/, 'Update comes from correct user';
-
- my @urls = $mech->get_link_from_email($email, 1);
- is $urls[0], "http://www.example.org/report/" . $report_id, "Correct report URL in email";
+ unlike $body, qr/State changed to: Open/s, 'no marked as confirmed text';
$mech->delete_user($user1);
$mech->delete_user($user2);
$mech->delete_user($user3);
};
+for my $test (
+ {
+ update_text => '',
+ problem_state => 'investigating',
+ expected_text => 'State changed to: Investigating',
+ desc => 'comment changing status included in email',
+ },
+ {
+ update_text => 'Category changed to Potholes',
+ problem_state => '',
+ expected_text => 'Category changed to Potholes',
+ desc => 'comment about category included',
+ },
+ {
+ update_text => 'Category changed to Potholes',
+ problem_state => 'investigating',
+ expected_text => 'Category changed to Potholes.*Investigating',
+ desc => 'comment about category and status change included',
+ },
+) {
+ subtest $test->{desc} => sub {
+ $mech->delete_user( 'reporter@example.com' );
+ $mech->delete_user( 'alerts@example.com' );
+
+ my $user1 = $mech->create_user_ok('reporter@example.com', name => 'Reporter User' );
+ my $user2 = $mech->create_user_ok('alerts@example.com', name => 'Alert User' );
+ my $user3 = $mech->create_user_ok('staff@example.com', name => 'Staff User', from_body => $gloucester );
+ my $dt = DateTime->now(time_zone => 'Europe/London')->add(days => 2);
+
+ my $dt_parser = FixMyStreet::App->model('DB')->schema->storage->datetime_parser;
+
+ my $report_time = '2011-03-01 12:00:00';
+ my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( {
+ postcode => 'EH1 1BB',
+ bodies_str => '1',
+ areas => ',11808,135007,14419,134935,2651,20728,',
+ category => 'Street lighting',
+ title => 'Testing',
+ detail => 'Testing Detail',
+ used_map => 1,
+ name => $user1->name,
+ anonymous => 0,
+ state => 'confirmed',
+ confirmed => $dt_parser->format_datetime($dt),
+ lastupdate => $dt_parser->format_datetime($dt),
+ whensent => $dt_parser->format_datetime($dt->clone->add( minutes => 5 )),
+ lang => 'en-gb',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ send_questionnaire => 1,
+ latitude => '55.951963',
+ longitude => '-3.189944',
+ user_id => $user1->id,
+ } );
+ my $report_id = $report->id;
+ ok $report, "created test report - $report_id";
+
+ my $alert = FixMyStreet::App->model('DB::Alert')->create( {
+ parameter => $report_id,
+ alert_type => 'new_updates',
+ user => $user2,
+ } )->confirm;
+ ok $alert, 'created alert for other user';
+
+ my $update = FixMyStreet::App->model('DB::Comment')->create( {
+ problem_id => $report_id,
+ user_id => $user3->id,
+ name => 'Staff User',
+ mark_fixed => 'false',
+ text => $test->{update_text},
+ problem_state => $test->{problem_state},
+ state => 'confirmed',
+ confirmed => $dt->clone->add( hours => 9 ),
+ anonymous => 'f',
+ } );
+ my $update_id = $update->id;
+ ok $update, "created test update from staff user - $update_id";
+
+ $mech->clear_emails_ok;
+ FixMyStreet::override_config {
+ MAPIT_URL => 'http://mapit.uk/',
+ }, sub {
+ FixMyStreet::Script::Alerts::send();
+ };
+
+ $mech->email_count_is(1);
+ my $expected_text = $test->{expected_text};
+ my $email = $mech->get_email;
+ my $body = $mech->get_text_body_from_email($email);
+ like $body, qr/The following updates have been left on this report:/, 'email is about updates to existing report';
+ like $body, qr/Staff User/, 'Update comes from correct user';
+ like $body, qr/$expected_text/s, 'Expected text present';
+
+ my @urls = $mech->get_link_from_email($email, 1);
+ is $urls[0], "http://www.example.org/report/" . $report_id, "Correct report URL in email";
+
+ $mech->delete_user($user1);
+ $mech->delete_user($user2);
+ $mech->delete_user($user3);
+ };
+}
+
subtest "Test signature template is used from cobrand" => sub {
$mech->delete_user( 'reporter@example.com' );
$mech->delete_user( 'alerts@example.com' );
diff --git a/t/app/controller/area_stats.t b/t/app/controller/area_stats.t
index 6ea03cabf..ce2e3d7d6 100644
--- a/t/app/controller/area_stats.t
+++ b/t/app/controller/area_stats.t
@@ -98,6 +98,8 @@ FixMyStreet::override_config {
$mech->text_contains('Potholes6');
$mech->text_contains('Traffic lights13');
+
+ $mech->text_contains('average time between issue being opened and set to another status was 0 days');
};
subtest 'shows correct stats to area user' => sub {
@@ -183,6 +185,17 @@ FixMyStreet::override_config {
$mech->text_contains('Traffic lights3730');
};
+ subtest 'ignores second state change if first was last month' => sub {
+ my $comment = $scheduled_problems[0]->comments->search({}, { order_by => { '-asc' => 'id' } } )->first;
+ $comment->update({ confirmed => DateTime->now->subtract(days => 40) });
+ $mech->get_ok("/admin/areastats/$body_id?area=20720");
+
+ $mech->content_contains('15 opened, 6 scheduled, 3 closed, 4 fixed');
+ $mech->text_contains('Potholes2004');
+ $mech->text_contains('Traffic lights3730');
+ $comment->update({ confirmed => DateTime->now });
+ };
+
subtest 'average is only to first state change' => sub {
for my $i (0..4) {
$scheduled_problems[$i]->comments->first->update({ confirmed => $scheduled_problems[$i]->confirmed });
@@ -201,6 +214,16 @@ FixMyStreet::override_config {
$mech->get_ok("/admin/areastats/$body_id?area=20720");
$mech->text_contains('average time between issue being opened and set to another status was 4 days');
};
+
+ subtest 'shows no problems changed state if no average' => sub {
+ for my $p (@scheduled_problems, @fixed_problems, @closed_problems) {
+ $p->comments->delete;
+ }
+
+ $mech->get_ok("/admin/areastats/$body_id?area=20720");
+ $mech->text_contains('17 opened, 0 scheduled, 0 closed, 0 fixed');
+ $mech->text_contains('no problems changed state');
+ }
};
END {
diff --git a/t/app/controller/around.t b/t/app/controller/around.t
index fbb4e76cd..cdaeaf363 100644
--- a/t/app/controller/around.t
+++ b/t/app/controller/around.t
@@ -92,15 +92,22 @@ foreach my $test (
};
}
-subtest 'check non public reports are not displayed on around page' => sub {
- my $params = {
- postcode => 'EH1 1BB',
- latitude => 55.9519637512,
- longitude => -3.17492254484,
- };
- my @edinburgh_problems =
- $mech->create_problems_for_body( 5, 2651, 'Around page', $params );
+my @edinburgh_problems = $mech->create_problems_for_body( 5, 2651, 'Around page', {
+ postcode => 'EH1 1BB',
+ latitude => 55.9519637512,
+ longitude => -3.17492254484,
+});
+subtest 'check lookup by reference' => sub {
+ $mech->get_ok('/');
+ $mech->submit_form_ok( { with_fields => { pc => 'ref:12345' } }, 'bad ref');
+ $mech->content_contains('Searching found no reports');
+ my $id = $edinburgh_problems[0]->id;
+ $mech->submit_form_ok( { with_fields => { pc => "ref:$id" } }, 'good ref');
+ is $mech->uri->path, "/report/$id", "redirected to report page";
+};
+
+subtest 'check non public reports are not displayed on around page' => sub {
$mech->get_ok('/');
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ],
diff --git a/t/app/controller/auth_phone.t b/t/app/controller/auth_phone.t
index 8673f5c62..435ea7552 100644
--- a/t/app/controller/auth_phone.t
+++ b/t/app/controller/auth_phone.t
@@ -47,7 +47,7 @@ subtest 'Log in using mobile, by text' => sub {
}, sub {
$mech->submit_form_ok({
form_name => 'general_auth',
- fields => { username => '+61491570156', password_register => 'secret' },
+ fields => { username => '+18165550100', password_register => 'secret' },
button => 'sign_in_by_code',
}, "sign in using mobile");
@@ -61,7 +61,7 @@ subtest 'Log in using mobile, by text' => sub {
with_fields => { code => $code }
}, 'submit correct code');
- my $user = FixMyStreet::App->model('DB::User')->find( { phone => '+61491570156' } );
+ my $user = FixMyStreet::App->model('DB::User')->find( { phone => '+18165550100' } );
ok $user, "user created";
is $mech->uri->path, '/my', "redirected to the 'my' section of site";
$mech->logged_in_ok;
@@ -76,13 +76,13 @@ subtest 'Log in using mobile, by password' => sub {
$mech->get_ok('/auth');
$mech->submit_form_ok({
form_name => 'general_auth',
- fields => { username => '+61491570156', password_sign_in => 'incorrect' },
+ fields => { username => '+18165550100', password_sign_in => 'incorrect' },
button => 'sign_in_by_password',
}, "sign in using wrong password");
$mech->content_contains('There was a problem');
$mech->submit_form_ok({
form_name => 'general_auth',
- fields => { username => '+61491570156', password_sign_in => 'secret' },
+ fields => { username => '+18165550100', password_sign_in => 'secret' },
button => 'sign_in_by_password',
}, "sign in using password");
diff --git a/t/app/controller/report_inspect.t b/t/app/controller/report_inspect.t
index 45bb4f8a7..f74c94c34 100644
--- a/t/app/controller/report_inspect.t
+++ b/t/app/controller/report_inspect.t
@@ -11,10 +11,18 @@ my $rp = FixMyStreet::DB->resultset("ResponsePriority")->create({
body => $oxon,
name => 'High Priority',
});
+my $rp2 = FixMyStreet::DB->resultset("ResponsePriority")->create({
+ body => $oxon,
+ name => 'Low Priority',
+});
FixMyStreet::DB->resultset("ContactResponsePriority")->create({
contact => $contact,
response_priority => $rp,
});
+FixMyStreet::DB->resultset("ContactResponsePriority")->create({
+ contact => $contact3,
+ response_priority => $rp2,
+});
my $wodc = $mech->create_body_ok(2420, 'West Oxfordshire District Council');
$mech->create_contact_ok( body_id => $wodc->id, category => 'Horses', email => 'horses@example.net' );
@@ -254,7 +262,7 @@ FixMyStreet::override_config {
$mech->submit_form_ok({
button => 'save',
with_fields => {
- $test->{priority} ? (priority => 1) : (),
+ $test->{priority} ? (priority => $rp->id) : (),
$test->{category} ? (category => 'Cows') : (),
$test->{detailed} ? (detailed_information => 'Highland ones') : (),
}
@@ -262,6 +270,68 @@ FixMyStreet::override_config {
};
}
+ subtest "check priority not set for category with no priorities" => sub {
+ $report->discard_changes;
+ $report->update({ category => 'Cows', response_priority_id => undef });
+ $report->discard_changes;
+ is $report->response_priority, undef, 'response priority not set';
+ $user->user_body_permissions->delete;
+ $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_category' });
+ $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_priority' });
+ $mech->get_ok("/report/$report_id");
+ $mech->submit_form_ok({
+ button => 'save',
+ with_fields => {
+ priority => $rp->id,
+ category => 'Sheep',
+ }
+ });
+
+ $report->discard_changes;
+ is $report->response_priority, undef, 'response priority not set';
+ };
+
+ subtest "check can set priority for category when changing from category with no priorities" => sub {
+ $report->discard_changes;
+ $report->update({ category => 'Sheep', response_priority_id => undef });
+ $report->discard_changes;
+ is $report->response_priority, undef, 'response priority not set';
+ $user->user_body_permissions->delete;
+ $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_category' });
+ $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_priority' });
+ $mech->get_ok("/report/$report_id");
+ $mech->submit_form_ok({
+ button => 'save',
+ with_fields => {
+ priority => $rp->id,
+ category => 'Cows',
+ }
+ });
+
+ $report->discard_changes;
+ is $report->response_priority->id, $rp->id, 'response priority set';
+ };
+
+ subtest "check can't set priority that isn't for a category" => sub {
+ $report->discard_changes;
+ $report->update({ category => 'Cows', response_priority_id => $rp->id });
+ $report->discard_changes;
+ is $report->response_priority->id, $rp->id, 'response priority set';
+ $user->user_body_permissions->delete;
+ $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_category' });
+ $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_priority' });
+ $mech->get_ok("/report/$report_id");
+ $mech->submit_form_ok({
+ button => 'save',
+ with_fields => {
+ priority => $rp2->id,
+ }
+ });
+
+ $report->discard_changes;
+ is $report->response_priority, undef, 'response priority set';
+ };
+
subtest "check nearest address display" => sub {
$mech->get_ok("/report/$report_id");
$mech->content_lacks('Nearest calculated address', 'No address displayed');
@@ -408,6 +478,61 @@ FixMyStreet::override_config {
};
FixMyStreet::override_config {
+ MAPIT_URL => 'http://mapit.uk/',
+ ALLOWED_COBRANDS => 'fixmystreet',
+}, sub {
+ subtest "test category not updated if fail to include public update" => sub {
+ $mech->get_ok("/report/$report_id");
+ $mech->submit_form(button => 'save', with_fields => { category => 'Badgers' });
+
+ $report->discard_changes;
+ is $report->category, "Cows", "Report in correct category";
+ $mech->content_contains('Badgers" selected', 'Changed category still selected');
+ };
+
+ subtest "test invalid form maintains Category and priority" => sub {
+ $mech->get_ok("/report/$report_id");
+ my $expected_fields = {
+ state => 'action scheduled',
+ category => 'Cows',
+ public_update => '',
+ priority => $rp->id,
+ include_update => '1',
+ detailed_information => 'XXX172XXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ defect_type => '',
+ traffic_information => ''
+ };
+ my $values = $mech->visible_form_values('report_inspect_form');
+ is_deeply $values, $expected_fields, 'correct form fields present';
+
+ $mech->submit_form(button => 'save', with_fields => { category => 'Badgers', priority => $rp2->id });
+
+ $expected_fields->{category} = 'Badgers';
+ $expected_fields->{priority} = $rp2->id;
+
+ my $new_values = $mech->visible_form_values('report_inspect_form');
+ is_deeply $new_values, $expected_fields, 'correct form fields present';
+ };
+
+ subtest "test changing category and leaving an update only creates one comment" => sub {
+ $report->comments->delete;
+ $mech->get_ok("/report/$report_id");
+ $mech->submit_form(
+ button => 'save',
+ with_fields => {
+ category => 'Badgers',
+ include_update => 1,
+ public_update => 'This is a public update',
+ });
+
+ $report->discard_changes;
+ is $report->category, "Badgers", "Report in correct category";
+ is $report->comments->count, 1, "Only leaves one update";
+ like $report->comments->first->text, qr/Category changed.*Badgers/, 'update text included category change';
+ };
+};
+
+FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'oxfordshire', 'fixmystreet' ],
BASE_URL => 'http://fixmystreet.site',
}, sub {
diff --git a/t/app/controller/reports.t b/t/app/controller/reports.t
index f3958a0a5..7773223dd 100644
--- a/t/app/controller/reports.t
+++ b/t/app/controller/reports.t
@@ -114,6 +114,18 @@ FixMyStreet::override_config {
MAPIT_URL => 'http://mapit.uk/',
}, sub {
$mech->submit_form_ok( { with_fields => { body => $body_edin_id } }, 'Submitted dropdown okay' );
+ is $mech->uri->path, '/reports/City+of+Edinburgh+Council';
+
+ subtest "test ward pages" => sub {
+ $mech->get_ok('/reports/Birmingham/Bad-Ward');
+ is $mech->uri->path, '/reports/Birmingham+City+Council';
+ $mech->get_ok('/reports/Birmingham/Aston');
+ is $mech->uri->path, '/reports/Birmingham+City+Council/Aston';
+ $mech->get_ok('/reports/Birmingham/Aston|Bournville');
+ is $mech->uri->path, '/reports/Birmingham+City+Council/Aston%7CBournville';
+ $mech->content_contains('Aston, Bournville');
+ };
+
$mech->get_ok('/reports/Westminster');
};
diff --git a/templates/email/fixamingata/submit.html b/templates/email/fixamingata/submit.html
index dfc56589a..65a692058 100644
--- a/templates/email/fixamingata/submit.html
+++ b/templates/email/fixamingata/submit.html
@@ -34,7 +34,6 @@ tror medborgaren behöver er uppmärksamhet.</p>
[%~ END ~%]
</td>
</tr>
- [% END %]
[%~ IF phone %]
<tr>
<th style="[% contact_th_style %]">Telefon</th>
diff --git a/templates/web/base/admin/areastats/area.html b/templates/web/base/admin/areastats/area.html
index 1b88b5885..a7330692d 100644
--- a/templates/web/base/admin/areastats/area.html
+++ b/templates/web/base/admin/areastats/area.html
@@ -47,7 +47,7 @@
[% END %]
</table>
-[% IF average > 0 %]
+[% IF average >= 0 %]
<p>[% tprintf(loc('In the last month – average time between issue being opened and set to another status was %s days'), average) %]</p>
[% ELSE %]
<p>[% loc('In the last month no problems changed state') %]</p>
diff --git a/templates/web/base/around/lookup_by_ref.html b/templates/web/base/around/lookup_by_ref.html
index aded05638..5c08a7ceb 100644
--- a/templates/web/base/around/lookup_by_ref.html
+++ b/templates/web/base/around/lookup_by_ref.html
@@ -1,7 +1,7 @@
[% pre_container_extra = INCLUDE 'around/postcode_form.html', pc = ref %]
[% INCLUDE 'header.html', title = loc('Reporting a problem'), bodyclass = 'frontpage fullwidthpage' %]
-<div class="tablewrapper">
+[% IF matching_reports %]
<p>[% loc('We found more than one match for that problem reference:') %]</p>
<ul class="pc_alternatives">
[% FOREACH report IN matching_reports %]
@@ -13,6 +13,8 @@
</li>
[% END %]
</ul>
-</div>
+ [% ELSE %]
+ <p>[% loc('Searching found no reports.') %]</p>
+[% END %]
[% INCLUDE 'footer.html' %]
diff --git a/templates/web/base/maps/openlayers.html b/templates/web/base/maps/openlayers.html
index 8f8d527e2..568a87e7c 100644
--- a/templates/web/base/maps/openlayers.html
+++ b/templates/web/base/maps/openlayers.html
@@ -36,6 +36,4 @@
[% IF map.copyright %]
<div class="olControlAttribution" style="position: absolute;">[% map.copyright %]</div>
[% END %]
- <div id="loading-indicator" class="hidden" aria-hidden="true">
- <img src="/i/loading.svg" alt="Loading..." />
- </div>
+ <img id="loading-indicator" class="hidden" aria-hidden="true" src="/i/loading.svg" alt="Loading...">
diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html
index 973db649e..e4e3ac9e6 100644
--- a/templates/web/base/report/_inspect.html
+++ b/templates/web/base/report/_inspect.html
@@ -6,7 +6,7 @@
[% INCLUDE 'errors.html' %]
- <form id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate">
+ <form name="report_inspect_form" id="report_inspect_form" method="post" action="[% c.uri_for( '/report', problem.id ) %]" class="validate">
<input type="hidden" name="js" value="">
<div class="inspect-section">
diff --git a/templates/web/base/reports/body.html b/templates/web/base/reports/body.html
index b6e6df73b..7931ae691 100755
--- a/templates/web/base/reports/body.html
+++ b/templates/web/base/reports/body.html
@@ -42,7 +42,12 @@
[% ward.name %]
</h1>
<a href="[% body_url %]">[% body.name %]</a>
- [% ELSE %]
+ [% ELSIF wards %]
+ <h1 id="reports_heading">
+ [% FOREACH w IN wards %][% w.name %][% IF NOT loop.last %], [% END %][% END %]
+ </h1>
+ <a href="[% body_url %]">[% body.name %]</a>
+ [% ELSE %]
<h1 id="reports_heading">
[% body.name %]
</h1>
diff --git a/templates/web/oxfordshire/_email_sent_extra.html b/templates/web/oxfordshire/_email_sent_extra.html
index 5fdcd3bfd..f01c2d5fb 100644
--- a/templates/web/oxfordshire/_email_sent_extra.html
+++ b/templates/web/oxfordshire/_email_sent_extra.html
@@ -1 +1,2 @@
-[% INCLUDE '_response_time.html' problem=report %]
+[% DEFAULT problem = report %]
+[% IF problem %][% INCLUDE '_response_time.html' %][% END %]
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index 3bf78ee31..cc156569f 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -659,7 +659,7 @@ $.extend(fixmystreet.set_up, {
}
$('#key-tools li:empty').remove();
$('#report-updates-data').insertAfter($('#map_box'));
- if (fixmystreet.page === 'report' || fixmystreet.page === 'reports') {
+ if (fixmystreet.page !== 'around') {
$('#sub_map_links').append('<a href="#" id="toggle-fullscreen" class="expand" data-expand-text="'+ translation_strings.expand_map +'" data-compress-text="'+ translation_strings.collapse_map +'" >'+ translation_strings.expand_map +'</span>');
}
}
diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss
index 9d6052c45..b13dc636a 100644
--- a/web/cobrands/sass/_base.scss
+++ b/web/cobrands/sass/_base.scss
@@ -1626,24 +1626,6 @@ html.js #map .noscript {
}
}
-// Loading indicator
-
-#loading-indicator {
- position: absolute;
- width: 100%;
- height: 100%;
- background-color: #000;
- opacity: 0.4;
- text-align: center;
-
- img {
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- }
-}
-
.big-green-banner {
position: relative;
top: -1.75em;
@@ -1786,6 +1768,23 @@ a:hover.rap-notes-trigger {
}
}
+#loading-indicator {
+ height: 32px;
+ width: 32px;
+ position: relative;
+ background-color: #333;
+ border-radius: 0.25em;
+ padding: 0.25em;
+ // Offset from top same as fms_pan_zoom, from left so as not
+ // to appear on top of zoom buttons (0.5em, 36px, 0.5em)
+ top: 0.5em;
+ left: 3.25em;
+ .map-reporting & {
+ // Same as fms_pan_zoom above, leaving space for the top bar when reporting
+ top: 2.75em;
+ }
+}
+
/* Reporting a problem bits */
label .muted {
diff --git a/web/cobrands/sass/_layout.scss b/web/cobrands/sass/_layout.scss
index a0c27863e..5a78ff4d5 100644
--- a/web/cobrands/sass/_layout.scss
+++ b/web/cobrands/sass/_layout.scss
@@ -720,6 +720,14 @@ body.authpage {
margin-bottom: 0;
}
+#loading-indicator {
+ height: 64px;
+ width: 64px;
+ background-color: rgba(0, 0, 0, 0.7);
+ // Reset the base left, as zoom buttons now elsewhere
+ left: 0.5em;
+}
+
.big-green-banner {
top: auto;
margin: (-1em/1.375) (-1em/1.375) 0 (-1em/1.375);