aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/App
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/App')
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm91
-rwxr-xr-xperllib/FixMyStreet/App/Controller/JS.pm30
-rw-r--r--perllib/FixMyStreet/App/Controller/My.pm11
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm96
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Questionnaire.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm21
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm120
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm11
-rw-r--r--perllib/FixMyStreet/App/Controller/Root.pm2
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Static.pm4
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm1
12 files changed, 257 insertions, 134 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 83f77f401..198acade6 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -6,6 +6,7 @@ BEGIN { extends 'Catalyst::Controller'; }
use POSIX qw(strftime strcoll);
use Digest::MD5 qw(md5_hex);
+use mySociety::EmailUtil qw(is_valid_email);
=head1 NAME
@@ -473,17 +474,33 @@ sub search_reports : Path('search_reports') {
$c->model('DB')->schema->storage->sql_maker->quote_char( '"' );
$c->model('DB')->schema->storage->sql_maker->name_sep( '.' );
+ my $query;
+ if (is_valid_email($search)) {
+ $query = [
+ 'user.email' => { ilike => $like_search },
+ ];
+ } elsif ($search =~ /^id:(\d+)$/) {
+ $query = [
+ 'me.id' => int($1),
+ ];
+ } elsif ($search =~ /^area:(\d+)$/) {
+ $query = [
+ 'me.areas' => { like => "%,$1,%" }
+ ];
+ } else {
+ $query = [
+ 'me.id' => $search_n,
+ 'user.email' => { ilike => $like_search },
+ 'me.name' => { ilike => $like_search },
+ title => { ilike => $like_search },
+ detail => { ilike => $like_search },
+ council => { like => $like_search },
+ cobrand_data => { like => $like_search },
+ ];
+ }
my $problems = $c->cobrand->problems->search(
{
- -or => [
- 'me.id' => $search_n,
- 'user.email' => { ilike => $like_search },
- 'me.name' => { ilike => $like_search },
- title => { ilike => $like_search },
- detail => { ilike => $like_search },
- council => { like => $like_search },
- cobrand_data => { like => $like_search },
- ]
+ -or => $query,
},
{
prefetch => 'user',
@@ -499,26 +516,44 @@ sub search_reports : Path('search_reports') {
$c->stash->{edit_council_contacts} = 1
if ( grep {$_ eq 'councilcontacts'} keys %{$c->stash->{allowed_pages}});
- my $updates = $c->model('DB::Comment')->search(
- {
- -or => [
- 'me.id' => $search_n,
- 'problem.id' => $search_n,
- 'user.email' => { ilike => $like_search },
- 'me.name' => { ilike => $like_search },
- text => { ilike => $like_search },
- 'me.cobrand_data' => { ilike => $like_search },
- %{ $site_restriction },
- ]
- },
- {
- -select => [ 'me.*', qw/problem.council problem.state/ ],
- prefetch => [qw/user problem/],
- order_by => [\"(me.state='hidden')",\"(problem.state='hidden')",'me.created']
- }
- );
+ if (is_valid_email($search)) {
+ $query = [
+ 'user.email' => { ilike => $like_search },
+ %{ $site_restriction },
+ ];
+ } elsif ($search =~ /^id:(\d+)$/) {
+ $query = [
+ 'me.id' => int($1),
+ 'problem.id' => int($1),
+ %{ $site_restriction },
+ ];
+ } elsif ($search =~ /^area:(\d+)$/) {
+ $query = [];
+ } else {
+ $query = [
+ 'me.id' => $search_n,
+ 'problem.id' => $search_n,
+ 'user.email' => { ilike => $like_search },
+ 'me.name' => { ilike => $like_search },
+ text => { ilike => $like_search },
+ 'me.cobrand_data' => { ilike => $like_search },
+ %{ $site_restriction },
+ ];
+ }
- $c->stash->{updates} = [ $updates->all ];
+ if (@$query) {
+ my $updates = $c->model('DB::Comment')->search(
+ {
+ -or => $query,
+ },
+ {
+ -select => [ 'me.*', qw/problem.council problem.state/ ],
+ prefetch => [qw/user problem/],
+ order_by => [\"(me.state='hidden')",\"(problem.state='hidden')",'me.created']
+ }
+ );
+ $c->stash->{updates} = [ $updates->all ];
+ }
# Switch quoting back off. See above for explanation of this.
$c->model('DB')->schema->storage->sql_maker->quote_char( '' );
diff --git a/perllib/FixMyStreet/App/Controller/JS.pm b/perllib/FixMyStreet/App/Controller/JS.pm
new file mode 100755
index 000000000..ae2f06605
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/JS.pm
@@ -0,0 +1,30 @@
+package FixMyStreet::App::Controller::JS;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+=head1 NAME
+
+FixMyStreet::App::Controller::JS - Catalyst Controller
+
+=head1 DESCRIPTION
+
+JS Catalyst Controller. To return a language-dependent list
+of validation strings.
+
+=head1 METHODS
+
+=cut
+
+sub validation_strings : LocalRegex('^validation_strings\.(.*?)\.js$') : Args(0) {
+ my ( $self, $c ) = @_;
+ my $lang = $c->req->captures->[0];
+ $c->cobrand->set_lang_and_domain( $lang, 1 );
+ $c->res->content_type( 'application/javascript' );
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
+
diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm
index 60e9dd09f..3de83b265 100644
--- a/perllib/FixMyStreet/App/Controller/My.pm
+++ b/perllib/FixMyStreet/App/Controller/My.pm
@@ -30,9 +30,16 @@ sub my : Path : Args(0) {
my $pins = [];
my $problems = {};
- my $rs = $c->user->problems->search( {
+
+ my $params = {
state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
- }, {
+ };
+ $params = {
+ %{ $c->cobrand->problems_clause },
+ %$params
+ } if $c->cobrand->problems_clause;
+
+ my $rs = $c->user->problems->search( $params, {
order_by => { -desc => 'confirmed' },
rows => 50
} )->page( $p_page );
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index 8711b19e9..a84c538cc 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -5,6 +5,7 @@ use namespace::autoclean;
BEGIN {extends 'Catalyst::Controller'; }
use DateTime::Format::HTTP;
+use Digest::SHA1 qw(sha1_hex);
use Path::Class;
=head1 NAME
@@ -36,7 +37,7 @@ sub during :LocalRegex('^([0-9a-f]{40})\.temp\.jpeg$') {
if ( $c->cobrand->default_photo_resize ) {
$photo = _shrink( $photo, $c->cobrand->default_photo_resize );
} else {
- $photo = _shrink( $photo, 'x250' );
+ $photo = _shrink( $photo, '250x250' );
}
$c->forward( 'output', [ $photo ] );
@@ -85,7 +86,7 @@ sub index :LocalRegex('^(c/)?(\d+)(?:\.(full|tn|fp))?\.jpeg$') {
} elsif ( $c->cobrand->default_photo_resize ) {
$photo = _shrink( $photo, $c->cobrand->default_photo_resize );
} else {
- $photo = _shrink( $photo, 'x250' );
+ $photo = _shrink( $photo, '250x250' );
}
$c->forward( 'output', [ $photo ] );
@@ -114,6 +115,7 @@ sub _shrink {
$image->BlobToImage($photo);
my $err = $image->Scale(geometry => "$size>");
throw Error::Simple("resize failed: $err") if "$err";
+ $image->Strip();
my @blobs = $image->ImageToBlob();
undef $image;
return $blobs[0];
@@ -129,11 +131,101 @@ sub _crop {
throw Error::Simple("resize failed: $err") if "$err";
$err = $image->Extent( geometry => '90x60', gravity => 'Center' );
throw Error::Simple("resize failed: $err") if "$err";
+ $image->Strip();
my @blobs = $image->ImageToBlob();
undef $image;
return $blobs[0];
}
+=head2 process_photo
+
+Handle the photo - either checking and storing it after an upload or retrieving
+it from the cache.
+
+Store any error message onto 'photo_error' in stash.
+=cut
+
+sub process_photo : Private {
+ my ( $self, $c ) = @_;
+
+ return
+ $c->forward('process_photo_upload')
+ || $c->forward('process_photo_cache')
+ || 1; # always return true
+}
+
+sub process_photo_upload : Private {
+ my ( $self, $c ) = @_;
+
+ # check for upload or return
+ my $upload = $c->req->upload('photo')
+ || return;
+
+ # check that the photo is a jpeg
+ my $ct = $upload->type;
+ $ct =~ s/x-citrix-//; # Thanks, Citrix
+ # Had a report of a JPEG from an Android 2.1 coming through as a byte stream
+ unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' || $ct eq 'application/octet-stream' ) {
+ $c->stash->{photo_error} = _('Please upload a JPEG image only');
+ return;
+ }
+
+ # get the photo into a variable
+ my $photo_blob = eval {
+ my $filename = $upload->tempname;
+ my $out = `jhead -se -autorot $filename 2>&1`;
+ die _("Please upload a JPEG image only"."\n") if $out =~ /Not JPEG:/;
+ my $photo = $upload->slurp;
+ return $photo;
+ };
+ if ( my $error = $@ ) {
+ my $format = _(
+"That image doesn't appear to have uploaded correctly (%s), please try again."
+ );
+ $c->stash->{photo_error} = sprintf( $format, $error );
+ return;
+ }
+
+ # we have an image we can use - save it to the upload dir for storage
+ my $cache_dir = dir( $c->config->{UPLOAD_DIR} );
+ $cache_dir->mkpath;
+ unless ( -d $cache_dir && -w $cache_dir ) {
+ warn "Can't find/write to photo cache directory '$cache_dir'";
+ return;
+ }
+
+ my $fileid = sha1_hex($photo_blob);
+ $upload->copy_to( file($cache_dir, $fileid . '.jpeg') );
+
+ # stick the hash on the stash, so don't have to reupload in case of error
+ $c->stash->{upload_fileid} = $fileid;
+
+ return 1;
+}
+
+=head2 process_photo_cache
+
+Look for the upload_fileid parameter and check it matches a file on disk. If it
+does return true and put fileid on stash, otherwise false.
+
+=cut
+
+sub process_photo_cache : Private {
+ my ( $self, $c ) = @_;
+
+ # get the fileid and make sure it is just a hex number
+ my $fileid = $c->req->param('upload_fileid') || '';
+ $fileid =~ s{[^0-9a-f]}{}gi;
+ return unless $fileid;
+
+ my $file = file( $c->config->{UPLOAD_DIR}, "$fileid.jpeg" );
+ return unless -e $file;
+
+ $c->stash->{upload_fileid} = $fileid;
+ return 1;
+}
+
+
=head1 AUTHOR
Struan Donald
diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm
index 6ed7ddd9d..fe71f3fbb 100755
--- a/perllib/FixMyStreet/App/Controller/Questionnaire.pm
+++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm
@@ -244,7 +244,7 @@ sub process_questionnaire : Private {
push @errors, _('Please provide some explanation as to why you\'re reopening this report')
if $c->stash->{been_fixed} eq 'No' && $c->stash->{problem}->is_fixed() && !$c->stash->{update};
- $c->forward('/report/new/process_photo');
+ $c->forward('/photo/process_photo');
push @errors, $c->stash->{photo_error}
if $c->stash->{photo_error};
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 59e3a4410..afe180c29 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -51,7 +51,7 @@ sub display : Path('') : Args(1) {
return $c->res->redirect( $c->uri_for($1), 301 );
}
- $c->forward('load_problem_or_display_error', [ $id ] );
+ $c->forward( 'load_problem_or_display_error', [ $id ] );
$c->forward( 'load_updates' );
$c->forward( 'format_problem_for_display' );
}
@@ -88,7 +88,24 @@ sub load_updates : Private {
{ order_by => 'confirmed' }
);
- $c->stash->{updates} = $updates;
+ my $questionnaires = $c->model('DB::Questionnaire')->search(
+ {
+ problem_id => $c->stash->{problem}->id,
+ whenanswered => { '!=', undef },
+ old_state => 'confirmed', new_state => 'confirmed',
+ },
+ { order_by => 'whenanswered' }
+ );
+
+ my @combined;
+ while (my $update = $updates->next) {
+ push @combined, [ $update->confirmed, $update ];
+ }
+ while (my $update = $questionnaires->next) {
+ push @combined, [ $update->whenanswered, $update ];
+ }
+ @combined = map { $_->[1] } sort { $a->[0] <=> $b->[0] } @combined;
+ $c->stash->{updates} = \@combined;
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 70dee63c6..70f937eed 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -5,7 +5,6 @@ use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
use FixMyStreet::Geocode;
-use Digest::SHA1 qw(sha1_hex);
use Encode;
use Image::Magick;
use List::MoreUtils qw(uniq);
@@ -78,6 +77,8 @@ partial
=cut
+use constant COUNCIL_ID_BARNET => 2489;
+
sub report_new : Path : Args(0) {
my ( $self, $c ) = @_;
@@ -97,7 +98,7 @@ sub report_new : Path : Args(0) {
return unless $c->forward('check_form_submitted');
$c->forward('process_user');
$c->forward('process_report');
- $c->forward('process_photo');
+ $c->forward('/photo/process_photo');
return unless $c->forward('check_for_errors');
$c->forward('save_user_and_report');
$c->forward('redirect_or_confirm_creation');
@@ -171,9 +172,14 @@ sub report_form_ajax : Path('ajax') : Args(0) {
$c->forward('initialize_report');
# work out the location for this report and do some checks
- # XXX We don't want to do this here if this actually happens!
- return $c->forward('redirect_to_around')
- unless $c->forward('determine_location');
+ if ( ! $c->forward('determine_location') ) {
+ my $body = JSON->new->utf8(1)->encode( {
+ error => $c->stash->{location_error},
+ } );
+ $c->res->content_type('application/json; charset=utf-8');
+ $c->res->body($body);
+ return;
+ }
$c->forward('setup_categories_and_councils');
@@ -266,7 +272,7 @@ sub report_import : Path('/import') {
}
# handle the photo upload
- $c->forward( 'process_photo_upload' );
+ $c->forward( '/photo/process_photo_upload' );
my $fileid = $c->stash->{upload_fileid};
if ( my $error = $c->stash->{photo_error} ) {
push @errors, $error;
@@ -602,9 +608,15 @@ sub setup_categories_and_councils : Private {
} elsif ($first_council->{type} eq 'LBO') {
$area_ids_to_list{ $first_council->{id} } = 1;
+ my @local_categories;
+ if ($first_council->{id} == COUNCIL_ID_BARNET) {
+ @local_categories = sort(keys %{ Utils::barnet_categories() }); # removed 'Other' option
+ } else {
+ @local_categories = sort keys %{ Utils::london_categories() }
+ }
@category_options = (
_('-- Pick a category --'),
- sort keys %{ Utils::london_categories() }
+ @local_categories
);
$category_label = _('Category:');
@@ -791,8 +803,15 @@ sub process_report : Private {
$councils = join( ',', @{ $c->stash->{area_ids_to_list} } ) || -1;
$report->council( $councils );
- } elsif ( $first_council->{type} eq 'LBO') {
+ } elsif ( $first_council->{id} == COUNCIL_ID_BARNET ) {
+ unless ( exists Utils::barnet_categories()->{ $report->category } or $report->category eq 'Other') {
+ $c->stash->{field_errors}->{category} = _('Please choose a category');
+ }
+ $report->council( $first_council->{id} );
+
+ } elsif ( $first_council->{type} eq 'LBO') {
+
unless ( Utils::london_categories()->{ $report->category } ) {
$c->stash->{field_errors}->{category} = _('Please choose a category');
}
@@ -871,91 +890,6 @@ sub process_report : Private {
return 1;
}
-=head2 process_photo
-
-Handle the photo - either checking and storing it after an upload or retrieving
-it from the cache.
-
-Store any error message onto 'photo_error' in stash.
-=cut
-
-sub process_photo : Private {
- my ( $self, $c ) = @_;
-
- return
- $c->forward('process_photo_upload')
- || $c->forward('process_photo_cache')
- || 1; # always return true
-}
-
-sub process_photo_upload : Private {
- my ( $self, $c ) = @_;
-
- # check for upload or return
- my $upload = $c->req->upload('photo')
- || return;
-
- # check that the photo is a jpeg
- my $ct = $upload->type;
- unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' ) {
- $c->stash->{photo_error} = _('Please upload a JPEG image only');
- return;
- }
-
- # get the photo into a variable
- my $photo_blob = eval {
- my $filename = $upload->tempname;
- my $out = `jhead -se -autorot $filename`;
- my $photo = $upload->slurp;
- return $photo;
- };
- if ( my $error = $@ ) {
- my $format = _(
-"That image doesn't appear to have uploaded correctly (%s), please try again."
- );
- $c->stash->{photo_error} = sprintf( $format, $error );
- return;
- }
-
- # we have an image we can use - save it to the upload dir for storage
- my $cache_dir = dir( $c->config->{UPLOAD_DIR} );
- $cache_dir->mkpath;
- unless ( -d $cache_dir && -w $cache_dir ) {
- warn "Can't find/write to photo cache directory '$cache_dir'";
- return;
- }
-
- my $fileid = sha1_hex($photo_blob);
- $upload->copy_to( file($cache_dir, $fileid . '.jpeg') );
-
- # stick the hash on the stash, so don't have to reupload in case of error
- $c->stash->{upload_fileid} = $fileid;
-
- return 1;
-}
-
-=head2 process_photo_cache
-
-Look for the upload_fileid parameter and check it matches a file on disk. If it
-does return true and put fileid on stash, otherwise false.
-
-=cut
-
-sub process_photo_cache : Private {
- my ( $self, $c ) = @_;
-
- # get the fileid and make sure it is just a hex number
- my $fileid = $c->req->param('upload_fileid') || '';
- $fileid =~ s{[^0-9a-f]}{}gi;
- return unless $fileid;
-
- my $file = file( $c->config->{UPLOAD_DIR}, "$fileid.jpeg" );
- return unless -e $file;
-
- $c->stash->{upload_fileid} = $fileid;
- return 1;
-}
-
=head2 check_for_errors
Examine the user and the report for errors. If found put them on stash and
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 15444f556..8a87fe7a2 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -23,7 +23,7 @@ sub report_update : Path : Args(0) {
$c->forward( '/report/load_problem_or_display_error', [ $c->req->param('id') ] );
$c->forward('process_update');
$c->forward('process_user');
- $c->forward('/report/new/process_photo');
+ $c->forward('/photo/process_photo');
$c->forward('check_for_errors')
or $c->go( '/report/display', [ $c->req->param('id') ] );
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index e7620f755..9fb72121e 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -341,9 +341,11 @@ sub load_and_group_problems : Private {
{
columns => [
'id', 'council', 'state', 'areas', 'latitude', 'longitude', 'title', 'cobrand',
- { duration => { extract => "epoch from current_timestamp-lastupdate" } },
- { age => { extract => "epoch from current_timestamp-confirmed" } },
- { confirmed => { extract => 'epoch from confirmed' } },
+ #{ duration => { extract => "epoch from current_timestamp-lastupdate" } },
+ #{ age => { extract => "epoch from current_timestamp-confirmed" } },
+ { confirmed => { extract => 'epoch from confirmed' } },
+ { whensent => { extract => 'epoch from whensent' } },
+ { lastupdate => { extract => 'epoch from lastupdate' } },
{ photo => 'photo is not null' },
],
order_by => { -desc => 'lastupdate' },
@@ -355,9 +357,10 @@ sub load_and_group_problems : Private {
my ( %problems, @pins );
my $re_councils = join('|', keys %{$c->stash->{areas_info}});
- my @cols = ( 'id', 'council', 'state', 'areas', 'latitude', 'longitude', 'title', 'cobrand', 'duration', 'age', 'confirmed', 'photo' );
+ my @cols = ( 'id', 'council', 'state', 'areas', 'latitude', 'longitude', 'title', 'cobrand', 'confirmed', 'whensent', 'lastupdate', 'photo' );
while ( my @problem = $problems->next ) {
my %problem = zip @cols, @problem;
+ $problem{is_fixed} = FixMyStreet::DB::Result::Problem->fixed_states()->{$problem{state}};
$c->log->debug( $problem{'cobrand'} . ', cobrand is ' . $c->cobrand->moniker );
if ( !$problem{council} ) {
# Problem was not sent to any council, add to possible councils
diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm
index 9cdf0b523..7f7d7f5fd 100644
--- a/perllib/FixMyStreet/App/Controller/Root.pm
+++ b/perllib/FixMyStreet/App/Controller/Root.pm
@@ -68,7 +68,7 @@ Forward to the standard 404 error page
sub default : Path {
my ( $self, $c ) = @_;
- $c->detach('/page_error_404_not_found');
+ $c->detach('/page_error_404_not_found', []);
}
=head2 page_error_404_not_found, page_error_410_gone
diff --git a/perllib/FixMyStreet/App/Controller/Static.pm b/perllib/FixMyStreet/App/Controller/Static.pm
index 52b230c27..d4b7a1b83 100755
--- a/perllib/FixMyStreet/App/Controller/Static.pm
+++ b/perllib/FixMyStreet/App/Controller/Static.pm
@@ -29,6 +29,10 @@ sub for_councils_faq : Path('/for-councils/faq') : Args(0) {
my ( $self, $c ) = @_;
}
+sub privacy : Global : Args(0) {
+ my ( $self, $c ) = @_;
+}
+
sub faq : Global : Args(0) {
my ( $self, $c ) = @_;
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index 755f1e405..092e362f9 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -75,6 +75,7 @@ sprintf (different name to avoid clash)
sub tprintf {
my ( $self, $c, $format, @args ) = @_;
+ @args = @{$args[0]} if ref $args[0] eq 'ARRAY';
return sprintf $format, @args;
}