diff options
Diffstat (limited to 'perllib')
81 files changed, 1706 insertions, 1687 deletions
diff --git a/perllib/CrossSell.pm b/perllib/CrossSell.pm deleted file mode 100644 index 9567c2b38..000000000 --- a/perllib/CrossSell.pm +++ /dev/null @@ -1,297 +0,0 @@ -# CrossSell.pm: -# Adverts from FixMyStreet to another site. -# -# Unlike the PHP crosssell script, returns strings rather than prints them; -# and currently displays the same advert if e.g. there's a connection problem. -# -# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. -# Email: matthew@mysociety.org. WWW: http://www.mysociety.org -# -# $Id: CrossSell.pm,v 1.17 2009-09-10 09:36:42 matthew Exp $ - -# Config parameters site needs set to call these functions: -# OPTION_AUTH_SHARED_SECRET -# OPTION_HEARFROMYOURMP_BASE_URL - -package CrossSell; - -use strict; -use LWP::Simple qw($ua get); -use URI::Escape; -use mySociety::AuthToken; -use mySociety::Web qw(ent); - -sub display_random_hfymp_advert { - my ($email, $name, $text) = @_; - $name ||= ''; - my $auth_signature = mySociety::AuthToken::sign_with_shared_secret($email, mySociety::Config::get('AUTH_SHARED_SECRET')); - - # See if already signed up - my $url = mySociety::Config::get('HEARFROMYOURMP_BASE_URL'); - my $already_signed = get($url . '/authed?email=' . uri_escape($email) . "&sign=" . uri_escape($auth_signature)); - # Different from PHP version; display this advert if e.g. connection problem - return '' if $already_signed && $already_signed eq 'already signed'; - - $email = ent($email); - $name = ent($name); - $auth_signature = ent($auth_signature); - $text =~ s#\[form\]#<form action="http://www.hearfromyourmp.com/" method="post"> -<input type="hidden" name="name" value="$name"> -<input type="hidden" name="email" value="$email"> -<input type="hidden" name="sign" value="$auth_signature"> -<h2><input style="font-size:100%" type="submit" value="#; - $text =~ s#\[/form\]#"></h2>#; - - return '<div id="advert_hfymp">' . $text . '</div>'; -} - -sub display_random_gny_advert { - my ($email, $name, $text) = @_; - return '<div id="advert_thin">' . $text . '</div>'; -} - -sub display_random_twfy_alerts_advert { - my ($email, $name, $text) = @_; - my $auth_signature = mySociety::AuthToken::sign_with_shared_secret($email, mySociety::Config::get('AUTH_SHARED_SECRET')); - $text =~ s#\[button\]#<form action="http://www.theyworkforyou.com/alert/" method="post"> -<input type="hidden" name="email" value="$email"> -<input type="hidden" name="sign" value="$auth_signature"> -<input type="hidden" name="site" value="fms"> -<input style="font-size:150%" type="submit" value="#; - $text =~ s#\[/button\]#"></p>#; - return '<div id="advert_thin">' . $text . '</div>'; -} - -sub display_hfyc_cheltenham_advert { - my ($email, $name) = @_; - $name ||= ''; - my $auth_signature = mySociety::AuthToken::sign_with_shared_secret($email, mySociety::Config::get('AUTH_SHARED_SECRET')); - - # See if already signed up - my $already_signed = get('http://cheltenham.hearfromyourcouncillor.com/authed?email=' . uri_escape($email) . "&sign=" . uri_escape($auth_signature)); - # Different from PHP version; display this advert if e.g. connection problem - return '' if $already_signed && $already_signed eq 'already signed'; - - # If not, display advert - $email = ent($email); - $name = ent($name); - $auth_signature = ent($auth_signature); - my $out = <<EOF; -<form action="http://cheltenham.hearfromyourcouncillor.com/" method="post"> -<input type="hidden" name="name" value="$name"> -<input type="hidden" name="email" value="$email"> -<input type="hidden" name="sign" value="$auth_signature"> -<div id="advert_thin"> -EOF - - my $rand = int(rand(2)); - if ($rand == 0) { - $out .= "<h2>Cool! You're interested in Cheltenham!</h2> - <p>We've got an exciting new free service that works exclusively - for people in Cheltenham. Please sign up to help the charity - that runs WriteToThem, and to get a sneak preview of our new - service.</p>"; - } else { - $out .= "<h2>Get to know your councillors.</h2> - <p>Local councillors are really important, but hardly anyone knows them. - Use our new free service to build a low-effort, long term relationship - with your councillor.</p>"; - } - $out .= <<EOF; -<p align="center"> -<input type="submit" value="Sign up to HearFromYourCouncillor"> -</p> -</div> -</form> -EOF - return ($out, "cheltenhamhfyc$rand"); -} - -sub display_democracyclub { - my (%input) = @_; - return <<EOF; -<div id="advert_thin"> -<h2 style="margin-bottom:0">Help make the next election the most accountable ever</h2> <p style="font-size:120%;margin-top:0.5em;"><a href="http://www.democracyclub.org.uk/">Join Democracy Club</a> and have fun keeping an eye on your election candidates. <a href="http://www.democracyclub.org.uk/">Sign me up</a>! -</div> -EOF -} - -sub display_news_form { - my (%input) = @_; - my %input_h = map { $_ => $input{$_} ? ent($input{$_}) : '' } qw(name email signed_email); - my $auth_signature = $input_h{signed_email}; - return <<EOF; -<h1 style="padding-top:0.5em">mySociety newsletter</h1> - -<p>Interested in hearing more about FixMyStreet successes? Enter your email -address below and we’ll send you occasional emails about what mySociety -and our users have been up to.</p> - -<form method="post" action="//mysociety.us9.list-manage.com/subscribe/post?u=53d0d2026dea615ed488a8834&id=287dc28511"> -<label style="position: absolute; left: -5000px;"> -Leave this box empty: <input type="text" name="b_53d0d2026dea615ed488a8834_287dc28511" tabindex="-1" value="" /> -</label> -<label for="name">Name:</label> -<input type="text" name="NAME" id="name" value="$input_h{name}" size="30"> -<br><label for="email">Email:</label> -<input type="text" name="EMAIL" id="email" value="$input_h{email}" size="30"> - <input type="submit" name="subscribe" value="Add me to the list"> -</form> - -<p>mySociety respects your privacy, and we'll never sell or give away your private -details. You can unsubscribe at any time.</p> -EOF -} - -sub display_survey_link { - return <<EOF; -<h1 style="padding-top:0.5em">User Survey</h1> -<p> -We're running a survey to help us understand who uses our sites. If you have 10-15 minutes to spare then we'd be grateful if you could <a href="http://questions.mysociety.org/S/fms/w/" target="_blank">take part</a>. -</p> -EOF -} - -sub display_wtt_link { - return <<EOF; -<h1 style="padding-top:0.5em">WriteToThem</h1> -<p> -Need to write to a politician? Try <a href="https://writetothem.com">WriteToThem</a> - great -for campaigns too. -</p> -EOF -} - -sub display_app_links { - return <<EOF; -<h1>Next time, report your issue quicker.</h1> -<p>Download our awesome app, and make reporting and monitoring issues on the go a breeze.</p> - -<p class="app-links"> -<a href="https://play.google.com/store/apps/details?id=org.mysociety.FixMyStreet"> - <img alt="FixMyStreet Android app on Google Play" - src="/cobrands/fixmystreet/images/google_play_logo.png" /> -</a><a href="https://itunes.apple.com/gb/app/fixmystreet/id297456545"> - <img alt="FixMyStreet app on the App Store" - src="/cobrands/fixmystreet/images/itunes_store_logo.png" /> -</a> -</p> - -<p class="desktop-advice">Not on your mobile? No problem! Download now, and the app will be ready to use when you next pick up your phone.</p> -EOF -} - -# Not currently used, needs more explanation and testing; perhaps in future. -sub display_gny_groups { - my ($lon, $lat) = @_; - my $groups = get("http://www.groupsnearyou.com/rss.php?q=$lon,$lat&category=1&pointonly=1"); - my $out = ''; - my $count = 0; - while ($groups =~ /<item>\s*<title>New group! (.*?)<\/title>.*?<guid isPermaLink="true">(.*?)<\/guid>.*?<description>(.*?)<\/description>/gs) { - $out .= "<li><a href='$2'>$1</a> $3"; - $count++; - } - return unless $out; - return <<EOF; -<h1 style="padding-top:0.5em">$count local groups</h1> -<ul> -$out -</ul> -EOF -} - -# Choose appropriate advert and display it. -# $this_site is to stop a site advertising itself. -sub display_advert ($$;$%) { - my ($c, $email, $name, %data) = @_; - - return '' unless $c->cobrand->moniker eq 'fixmystreet'; - - $ua->timeout(5); - - #if (defined $data{council} && $data{council} eq '2326') { - # my ($out, $ad) = display_hfyc_cheltenham_advert($email, $name); - # if ($out) { - # $c->stash->{scratch} = "advert=$ad"; - # return $out; - # } - #} - - #if ($data{lat}) { - # my $out = display_gny_groups($data{lon}, $data{lat}); - # if ($out) { - # $c->stash->{scratch} = 'advert=gnygroups'; - # return '<div style="margin: 0 5em; border-top: dotted 1px #666666;">' - # . $out . '</div>'; - # } - #} - - #$c->stash->{scratch} = 'advert=demclub0'; - #return display_democracyclub(); - -# return <<EOF; -#<div id="advert_thin"> -#<p>Do you have an issue that’s too big for FixMyStreet? -#It could be time to petition your council. Try our new site: -#<h2 style="margin-top:0; font-size: 150%"> -#<a href="http://www.petitionyourcouncil.com/">PetitionYourCouncil</a></p> -#</h2> -#</div> -#EOF - - #unless (defined $data{done_tms} && $data{done_tms}==1) { - $c->stash->{scratch} = 'advert=wtt'; - return '<div class="advert-mobile-apps">' - . display_app_links() - . '</div>'; - - $c->stash->{scratch} = 'advert=news'; - my $auth_signature = ''; - unless (defined $data{emailunvalidated} && $data{emailunvalidated}==1) { - $auth_signature = mySociety::AuthToken::sign_with_shared_secret($email, mySociety::Config::get('AUTH_SHARED_SECRET')); - } - return '<div style="margin: 0 5em; border-top: dotted 1px #666666;">' - . display_news_form(email => $email, name => $name, signed_email => $auth_signature) - . '</div>'; - #} - - my @adverts = ( - [ 'gny0', '<h2>Are you a member of a local group…</h2> …which uses the internet to coordinate itself, such as a neighbourhood watch? If so, please help the charity that runs FixMyStreet by <a href="http://www.groupsnearyou.com/add/about/">adding some information about it</a> to our new site, GroupsNearYou.' ], - [ 'gny1', '<h2>Help us build a map of the world’s local communities –<br><a href="http://www.groupsnearyou.com/add/about/">Add one to GroupsNearYou</a></h2>' ], - # Since you're interested in your local area, why not - # start a long term relationship with your MP? - #[ 'hfymp0', '<h2 style="margin-bottom:0">Get email from your MP in the future</h2> <p style="font-size:120%;margin-top:0;">and have a chance to discuss what they say in a public forum [form]Sign up to HearFromYourMP[/form]' ], - #[ 'twfy_alerts0', '<h2>Get emailed every time your MP says something in Parliament</h2> [button]Keep an eye on them for free![/button]' ], - ); - while (@adverts) { - my $rand = int(rand(scalar @adverts)); - next unless $adverts[$rand]; - my ($advert_id, $advert_text) = @{$adverts[$rand]}; - (my $advert_site = $advert_id) =~ s/\d+$//; - my $func = "display_random_${advert_site}_advert"; - no strict 'refs'; - my $out = &$func($email, $name, $advert_text); - use strict 'refs'; - if ($out) { - $c->stash->{scratch} = "advert=$advert_id"; - return $out; - } - - for (my $i=0; $i<@adverts; $i++) { - (my $a = $adverts[$i][0]) =~ s/\d+$//; - delete $adverts[$i] if $advert_site eq $a; - } - } - - $c->stash->{scratch} = 'advert=pb'; - return <<EOF; -<div id="advert_thin"> -<h2 style="font-size: 150%"> -If you're interested in improving your local area, -<a href="http://www.pledgebank.com/">use PledgeBank</a> to -do so with other people!</h2> -</div> -EOF -} - -1; diff --git a/perllib/EastHantsWSDL.pm b/perllib/EastHantsWSDL.pm index d799f4025..181cc93a1 100644 --- a/perllib/EastHantsWSDL.pm +++ b/perllib/EastHantsWSDL.pm @@ -5,7 +5,7 @@ package EastHantsWSDL; my %methods = ( INPUTFEEDBACK => { - endpoint => 'http://www.easthants.gov.uk:80/forms.nsf/InputFeedback?OpenWebService', + endpoint => 'http://91.224.27.33/forms.nsf/InputFeedback?OpenWebService', soapaction => 'INPUTFEEDBACK', uri => 'urn:DefaultNamespace', parameters => [ diff --git a/perllib/FixMyStreet.pm b/perllib/FixMyStreet.pm index f3b72c4d0..76760b967 100644 --- a/perllib/FixMyStreet.pm +++ b/perllib/FixMyStreet.pm @@ -6,6 +6,7 @@ use warnings; use Path::Class; my $ROOT_DIR = file(__FILE__)->parent->parent->absolute->resolve; +use DateTime::TimeZone; use Readonly; use Sub::Override; @@ -217,4 +218,23 @@ sub get_email_template { return $template; } +my $tz = DateTime::TimeZone->new( name => "local" ); +my $tz_f; +$tz_f = DateTime::TimeZone->new( name => FixMyStreet->config('TIME_ZONE') ) + if FixMyStreet->config('TIME_ZONE'); + +sub local_time_zone { + return $tz; +} + +sub time_zone { + return $tz_f; +} + +sub set_time_zone { + my ($class, $dt) = @_; + $dt->set_time_zone($tz); + $dt->set_time_zone($tz_f) if $tz_f; +} + 1; diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm index 769a6bb8f..787755a05 100644 --- a/perllib/FixMyStreet/App.pm +++ b/perllib/FixMyStreet/App.pm @@ -89,15 +89,15 @@ __PACKAGE__->config( # Start the application __PACKAGE__->setup(); -# Due to some current issues with proxyings, need to manually -# tell the code we're secure if we are. +# If your site is secure but running behind a proxy, you might need to set the +# SECURE_PROXY_SSL_HEADER configuration variable so this can be spotted. after 'prepare_headers' => sub { my $self = shift; my $base_url = $self->config->{BASE_URL}; + my $ssl_header = $self->config->{SECURE_PROXY_SSL_HEADER}; my $host = $self->req->headers->header('Host'); - $self->req->secure( 1 ) if $base_url eq 'https://www.zueriwieneu.ch'; - $self->req->secure( 1 ) if $base_url eq 'https://www.fixmystreet.com' - && ( $host eq 'fix.bromley.gov.uk' || $host eq 'www.fixmystreet.com' ); + $self->req->secure(1) if $ssl_header && ref $ssl_header eq 'ARRAY' + && @$ssl_header == 2 && $self->req->header($ssl_header->[0]) eq $ssl_header->[1]; }; # set up DB handle for old code @@ -195,7 +195,7 @@ sub setup_request { Memcached::set_namespace( FixMyStreet->config('FMS_DB_NAME') . ":" ); - FixMyStreet::Map::set_map_class( $cobrand->map_type || $c->req->param('map_override') ); + FixMyStreet::Map::set_map_class( $cobrand->map_type || $c->get_param('map_override') ); unless ( FixMyStreet->config('MAPIT_URL') ) { my $port = $c->req->uri->port; @@ -529,6 +529,54 @@ sub is_abuser { return $c->model('DB::Abuse')->search( { email => [ $email, $domain ] } )->first; } +=head2 get_param + + $param = $c->get_param('name'); + +Return the parameter passed in the request, or undef if not present. Like +req->param() in a scalar context, this will return the first parameter if +multiple were provided; unlike req->param it will always return a scalar, +never a list, in order to avoid possible security issues. + +=cut + +sub get_param { + my ($c, $param) = @_; + my $value = $c->req->params->{$param}; + return $value->[0] if ref $value; + return $value; +} + +=head2 get_param_list + + @params = $c->get_param_list('name'); + +Return the parameters passed in the request, as a list. This will always return +a list, with an empty list if no parameter is present. + +=cut + +sub get_param_list { + my ($c, $param) = @_; + my $value = $c->req->params->{$param}; + return @$value if ref $value; + return ($value) if defined $value; + return (); +} + +=head2 set_param + + $c->set_param('name', 'My Name'); + +Sets the query parameter to the passed variable. + +=cut + +sub set_param { + my ($c, $param, $value) = @_; + $c->req->params->{$param} = $value; +} + =head1 SEE ALSO L<FixMyStreet::App::Controller::Root>, L<Catalyst> diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index de13a76de..6145a6eb0 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -246,19 +246,16 @@ sub bodies : Path('bodies') : Args(0) { $c->stash->{edit_activity} = $edit_activity; - my $posted = $c->req->param('posted') || ''; + my $posted = $c->get_param('posted') || ''; if ( $posted eq 'body' ) { $c->forward('check_for_super_user'); $c->forward('check_token'); my $params = $c->forward('body_params'); my $body = $c->model('DB::Body')->create( $params ); - my $area_ids = $c->req->params->{area_ids}; - if ($area_ids) { - $area_ids = [ $area_ids ] unless ref $area_ids; - foreach (@$area_ids) { - $c->model('DB::BodyArea')->create( { body => $body, area_id => $_ } ); - } + my @area_ids = $c->get_param_list('area_ids'); + foreach (@area_ids) { + $c->model('DB::BodyArea')->create( { body => $body, area_id => $_ } ); } $c->stash->{updated} = _('New body added'); @@ -266,9 +263,6 @@ sub bodies : Path('bodies') : Args(0) { $c->forward( 'fetch_all_bodies' ); - # XXX For fixmystreet.com, need to exclude bodies that are covering London. - # But soon, this means just don't have bodies covering London. - my $contacts = $c->model('DB::Contact')->search( undef, { @@ -317,7 +311,7 @@ sub body : Path('body') : Args(1) { $c->forward( 'fetch_all_bodies' ); $c->forward( 'body_form_dropdowns' ); - if ( $c->req->param('posted') ) { + if ( $c->get_param('posted') ) { $c->log->debug( 'posted' ); $c->forward('update_contacts'); } @@ -337,7 +331,7 @@ sub check_for_super_user : Private { sub update_contacts : Private { my ( $self, $c ) = @_; - my $posted = $c->req->param('posted'); + my $posted = $c->get_param('posted'); my $editor = $c->forward('get_user'); if ( $posted eq 'new' ) { @@ -345,11 +339,11 @@ sub update_contacts : Private { my %errors; - my $category = $self->trim( $c->req->param( 'category' ) ); + my $category = $self->trim( $c->get_param('category') ); $errors{category} = _("Please choose a category") unless $category; - my $email = $self->trim( $c->req->param( 'email' ) ); - $errors{email} = _('Please enter a valid email') unless is_valid_email($email); - $errors{note} = _('Please enter a message') unless $c->req->param('note'); + 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'); $category = 'Empty property' if $c->cobrand->moniker eq 'emptyhomes'; @@ -361,16 +355,16 @@ sub update_contacts : Private { ); $contact->email( $email ); - $contact->confirmed( $c->req->param('confirmed') ? 1 : 0 ); - $contact->deleted( $c->req->param('deleted') ? 1 : 0 ); - $contact->non_public( $c->req->param('non_public') ? 1 : 0 ); - $contact->note( $c->req->param('note') ); + $contact->confirmed( $c->get_param('confirmed') ? 1 : 0 ); + $contact->deleted( $c->get_param('deleted') ? 1 : 0 ); + $contact->non_public( $c->get_param('non_public') ? 1 : 0 ); + $contact->note( $c->get_param('note') ); $contact->whenedited( \'ms_current_timestamp()' ); $contact->editor( $editor ); - $contact->endpoint( $c->req->param('endpoint') ); - $contact->jurisdiction( $c->req->param('jurisdiction') ); - $contact->api_key( $c->req->param('api_key') ); - $contact->send_method( $c->req->param('send_method') ); + $contact->endpoint( $c->get_param('endpoint') ); + $contact->jurisdiction( $c->get_param('jurisdiction') ); + $contact->api_key( $c->get_param('api_key') ); + $contact->send_method( $c->get_param('send_method') ); if ( %errors ) { $c->stash->{updated} = _('Please correct the errors below'); @@ -389,7 +383,7 @@ sub update_contacts : Private { } elsif ( $posted eq 'update' ) { $c->forward('check_token'); - my @categories = $c->req->param('confirmed'); + my @categories = $c->get_param_list('confirmed'); my $contacts = $c->model('DB::Contact')->search( { @@ -416,13 +410,10 @@ sub update_contacts : Private { $c->stash->{body}->update( $params ); my @current = $c->stash->{body}->body_areas->all; my %current = map { $_->area_id => 1 } @current; - my $area_ids = $c->req->params->{area_ids}; - if ($area_ids) { - $area_ids = [ $area_ids ] unless ref $area_ids; - foreach (@$area_ids) { - $c->model('DB::BodyArea')->find_or_create( { body => $c->stash->{body}, area_id => $_ } ); - delete $current{$_}; - } + my @area_ids = $c->get_param_list('area_ids'); + foreach (@area_ids) { + $c->model('DB::BodyArea')->find_or_create( { body => $c->stash->{body}, area_id => $_ } ); + delete $current{$_}; } # Remove any others $c->stash->{body}->body_areas->search( { area_id => [ keys %current ] } )->delete; @@ -434,7 +425,7 @@ sub update_contacts : Private { sub body_params : Private { my ( $self, $c ) = @_; - my @fields = qw/name endpoint jurisdiction api_key send_method send_comments suppress_alerts send_extended_statuses comment_user_id can_be_devolved parent deleted/; + my @fields = qw/name endpoint jurisdiction api_key send_method external_url/; my %defaults = map { $_ => '' } @fields; %defaults = ( %defaults, send_comments => 0, @@ -445,7 +436,7 @@ sub body_params : Private { parent => undef, deleted => 0, ); - my %params = map { $_ => $c->req->param($_) || $defaults{$_} } @fields; + my %params = map { $_ => $c->get_param($_) || $defaults{$_} } keys %defaults; return \%params; } @@ -456,7 +447,7 @@ sub display_contacts : Private { $c->stash->{contacts} = $contacts; $c->stash->{live_contacts} = $contacts->search({ deleted => 0 }); - if ( $c->req->param('text') && $c->req->param('text') == 1 ) { + if ( $c->get_param('text') && $c->get_param('text') == 1 ) { $c->stash->{template} = 'admin/council_contacts.txt'; $c->res->content_type('text/plain; charset=utf-8'); return 1; @@ -535,16 +526,16 @@ sub reports : Path('reports') { } } - my $order = $c->req->params->{o} || 'created'; - my $dir = defined $c->req->params->{d} ? $c->req->params->{d} : 1; + my $order = $c->get_param('o') || 'created'; + my $dir = defined $c->get_param('d') ? $c->get_param('d') : 1; $c->stash->{order} = $order; $c->stash->{dir} = $dir; $order .= ' desc' if $dir; - my $p_page = $c->req->params->{p} || 1; - my $u_page = $c->req->params->{u} || 1; + my $p_page = $c->get_param('p') || 1; + my $u_page = $c->get_param('u') || 1; - if (my $search = $c->req->param('search')) { + if (my $search = $c->get_param('search')) { $c->stash->{searched} = $search; my $site_restriction = $c->cobrand->site_restriction; @@ -687,7 +678,7 @@ sub report_edit : Path('report_edit') : Args(1) { ); } - if ( $c->req->param('rotate_photo') ) { + if ( $c->get_param('rotate_photo') ) { $c->forward('rotate_photo'); return 1; } @@ -704,7 +695,7 @@ sub report_edit : Path('report_edit') : Args(1) { ->search( { problem_id => $problem->id }, { order_by => 'created' } ) ->all ]; - if ( $c->req->param('resend') ) { + if ( $c->get_param('resend') ) { $c->forward('check_token'); $problem->whensent(undef); @@ -714,24 +705,31 @@ sub report_edit : Path('report_edit') : Args(1) { $c->forward( 'log_edit', [ $id, 'problem', 'resend' ] ); } - elsif ( $c->req->param('flaguser') ) { + elsif ( $c->get_param('mark_sent') ) { + $c->forward('check_token'); + $problem->whensent(\'ms_current_timestamp()'); + $problem->update(); + $c->stash->{status_message} = '<p><em>' . _('That problem has been marked as sent.') . '</em></p>'; + $c->forward( 'log_edit', [ $id, 'problem', 'marked sent' ] ); + } + elsif ( $c->get_param('flaguser') ) { $c->forward('flag_user'); $c->stash->{problem}->discard_changes; } - elsif ( $c->req->param('removeuserflag') ) { + elsif ( $c->get_param('removeuserflag') ) { $c->forward('remove_user_flag'); $c->stash->{problem}->discard_changes; } - elsif ( $c->req->param('banuser') ) { + elsif ( $c->get_param('banuser') ) { $c->forward('ban_user'); } - elsif ( $c->req->param('submit') ) { + elsif ( $c->get_param('submit') ) { $c->forward('check_token'); my $done = 0; my $edited = 0; - my $new_state = $c->req->param('state'); + my $new_state = $c->get_param('state'); my $old_state = $problem->state; if ( $new_state eq 'confirmed' && $problem->state eq 'unconfirmed' @@ -744,35 +742,35 @@ sub report_edit : Path('report_edit') : Args(1) { $done = 1; } - my $flagged = $c->req->param('flagged') ? 1 : 0; - my $non_public = $c->req->param('non_public') ? 1 : 0; + my $flagged = $c->get_param('flagged') ? 1 : 0; + my $non_public = $c->get_param('non_public') ? 1 : 0; # do this here so before we update the values in problem - if ( $c->req->param('anonymous') ne $problem->anonymous - || $c->req->param('name') ne $problem->name - || $c->req->param('email') ne $problem->user->email - || $c->req->param('title') ne $problem->title - || $c->req->param('detail') ne $problem->detail - || ($c->req->param('body') && $c->req->param('body') ne $problem->bodies_str) + if ( $c->get_param('anonymous') ne $problem->anonymous + || $c->get_param('name') ne $problem->name + || $c->get_param('email') ne $problem->user->email + || $c->get_param('title') ne $problem->title + || $c->get_param('detail') ne $problem->detail + || ($c->get_param('body') && $c->get_param('body') ne $problem->bodies_str) || $flagged != $problem->flagged || $non_public != $problem->non_public ) { $edited = 1; } - $problem->anonymous( $c->req->param('anonymous') ); - $problem->title( $c->req->param('title') ); - $problem->detail( $c->req->param('detail') ); + $problem->anonymous( $c->get_param('anonymous') ); + $problem->title( $c->get_param('title') ); + $problem->detail( $c->get_param('detail') ); $problem->state( $new_state ); - $problem->name( $c->req->param('name') ); - $problem->bodies_str( $c->req->param('body') ) if $c->req->param('body'); + $problem->name( $c->get_param('name') ); + $problem->bodies_str( $c->get_param('body') ) if $c->get_param('body'); $problem->flagged( $flagged ); $problem->non_public( $non_public ); - if ( $c->req->param('email') ne $problem->user->email ) { + if ( $c->get_param('email') ne $problem->user->email ) { my $user = $c->model('DB::User')->find_or_create( - { email => $c->req->param('email') } + { email => $c->get_param('email') } ); $user->insert unless $user->in_storage; @@ -780,11 +778,11 @@ sub report_edit : Path('report_edit') : Args(1) { } # Deal with photos - if ( $c->req->param('remove_photo') ) { + if ( $c->get_param('remove_photo') ) { $problem->photo(undef); } - if ( $c->req->param('remove_photo') || $new_state eq 'hidden' ) { + if ( $c->get_param('remove_photo') || $new_state eq 'hidden' ) { unlink glob FixMyStreet->path_to( 'web', 'photo', $problem->id . '.*' ); } @@ -821,7 +819,7 @@ sub report_edit : Path('report_edit') : Args(1) { sub users: Path('users') : Args(0) { my ( $self, $c ) = @_; - if (my $search = $c->req->param('search')) { + if (my $search = $c->get_param('search')) { $c->stash->{searched} = $search; my $isearch = '%' . $search . '%'; @@ -893,52 +891,52 @@ sub update_edit : Path('update_edit') : Args(1) { $c->forward('check_email_for_abuse', [ $update->user->email ] ); - if ( $c->req->param('banuser') ) { + if ( $c->get_param('banuser') ) { $c->forward('ban_user'); } - elsif ( $c->req->param('flaguser') ) { + elsif ( $c->get_param('flaguser') ) { $c->forward('flag_user'); $c->stash->{update}->discard_changes; } - elsif ( $c->req->param('removeuserflag') ) { + elsif ( $c->get_param('removeuserflag') ) { $c->forward('remove_user_flag'); $c->stash->{update}->discard_changes; } - elsif ( $c->req->param('submit') ) { + elsif ( $c->get_param('submit') ) { $c->forward('check_token'); my $old_state = $update->state; - my $new_state = $c->req->param('state'); + my $new_state = $c->get_param('state'); my $edited = 0; # $update->name can be null which makes ne unhappy my $name = $update->name || ''; - if ( $c->req->param('name') ne $name - || $c->req->param('email') ne $update->user->email - || $c->req->param('anonymous') ne $update->anonymous - || $c->req->param('text') ne $update->text ){ + if ( $c->get_param('name') ne $name + || $c->get_param('email') ne $update->user->email + || $c->get_param('anonymous') ne $update->anonymous + || $c->get_param('text') ne $update->text ) { $edited = 1; } - if ( $c->req->param('remove_photo') ) { + if ( $c->get_param('remove_photo') ) { $update->photo(undef); } - if ( $c->req->param('remove_photo') || $new_state eq 'hidden' ) { + if ( $c->get_param('remove_photo') || $new_state eq 'hidden' ) { unlink glob FixMyStreet->path_to( 'web', 'photo', 'c', $update->id . '.*' ); } - $update->name( $c->req->param('name') || '' ); - $update->text( $c->req->param('text') ); - $update->anonymous( $c->req->param('anonymous') ); + $update->name( $c->get_param('name') || '' ); + $update->text( $c->get_param('text') ); + $update->anonymous( $c->get_param('anonymous') ); $update->state( $new_state ); - if ( $c->req->param('email') ne $update->user->email ) { + if ( $c->get_param('email') ne $update->user->email ) { my $user = $c->model('DB::User') - ->find_or_create( { email => $c->req->param('email') } ); + ->find_or_create( { email => $c->get_param('email') } ); $user->insert unless $user->in_storage; $update->user($user); @@ -989,22 +987,22 @@ sub user_add : Path('user_edit') : Args(0) { $c->forward('get_token'); $c->forward('fetch_all_bodies'); - return 1 unless $c->req->param('submit'); + return 1 unless $c->get_param('submit'); $c->forward('check_token'); - if ( $c->cobrand->moniker eq 'zurich' and $c->req->param('email') eq '' ) { + if ( $c->cobrand->moniker eq 'zurich' and $c->get_param('email') eq '' ) { $c->stash->{field_errors}->{email} = _('Please enter a valid email'); return 1; } - return unless $c->req->param('name') && $c->req->param('email'); + return unless $c->get_param('name') && $c->get_param('email'); my $user = $c->model('DB::User')->find_or_create( { - name => $c->req->param('name'), - email => $c->req->param('email'), - from_body => $c->req->param('body') || undef, - flagged => $c->req->param('flagged') || 0, + name => $c->get_param('name'), + email => $c->get_param('email'), + from_body => $c->get_param('body') || undef, + flagged => $c->get_param('flagged') || 0, }, { key => 'users_email_key' } ); @@ -1028,23 +1026,23 @@ sub user_edit : Path('user_edit') : Args(1) { $c->forward('fetch_all_bodies'); - if ( $c->req->param('submit') ) { + if ( $c->get_param('submit') ) { $c->forward('check_token'); my $edited = 0; - if ( $user->email ne $c->req->param('email') || - $user->name ne $c->req->param('name' ) || - ($user->from_body && $user->from_body->id ne $c->req->param('body')) || - (!$user->from_body && $c->req->param('body')) + if ( $user->email ne $c->get_param('email') || + $user->name ne $c->get_param('name') || + ($user->from_body && $user->from_body->id ne $c->get_param('body')) || + (!$user->from_body && $c->get_param('body')) ) { $edited = 1; } - $user->name( $c->req->param('name') ); - $user->email( $c->req->param('email') ); - $user->from_body( $c->req->param('body') || undef ); - $user->flagged( $c->req->param('flagged') || 0 ); + $user->name( $c->get_param('name') ); + $user->email( $c->get_param('email') ); + $user->from_body( $c->get_param('body') || undef ); + $user->flagged( $c->get_param('flagged') || 0 ); if ( $c->cobrand->moniker eq 'zurich' and $user->email eq '' ) { $c->stash->{field_errors}->{email} = _('Please enter a valid email'); @@ -1100,16 +1098,16 @@ sub stats : Path('stats') : Args(0) { return $c->cobrand->admin_stats(); } - if ( $c->req->param('getcounts') ) { + if ( $c->get_param('getcounts') ) { my ( $start_date, $end_date, @errors ); my $parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' ); - $start_date = $parser-> parse_datetime ( $c->req->param('start_date') ); + $start_date = $parser-> parse_datetime ( $c->get_param('start_date') ); push @errors, _('Invalid start date') unless defined $start_date; - $end_date = $parser-> parse_datetime ( $c->req->param('end_date') ) ; + $end_date = $parser-> parse_datetime ( $c->get_param('end_date') ) ; push @errors, _('Invalid end date') unless defined $end_date; @@ -1117,21 +1115,21 @@ sub stats : Path('stats') : Args(0) { $c->stash->{start_date} = $start_date; $c->stash->{end_date} = $end_date; - $c->stash->{unconfirmed} = $c->req->param('unconfirmed') eq 'on' ? 1 : 0; + $c->stash->{unconfirmed} = $c->get_param('unconfirmed') eq 'on' ? 1 : 0; return 1 if @errors; - my $bymonth = $c->req->param('bymonth'); + my $bymonth = $c->get_param('bymonth'); $c->stash->{bymonth} = $bymonth; my ( %body, %dates ); - $body{bodies_str} = { like => $c->req->param('body') } - if $c->req->param('body'); + $body{bodies_str} = { like => $c->get_param('body') } + if $c->get_param('body'); - $c->stash->{selected_body} = $c->req->param('body'); + $c->stash->{selected_body} = $c->get_param('body'); my $field = 'confirmed'; - $field = 'created' if $c->req->param('unconfirmed'); + $field = 'created' if $c->get_param('unconfirmed'); my $one_day = DateTime::Duration->new( days => 1 ); @@ -1143,7 +1141,7 @@ sub stats : Path('stats') : Args(0) { order_by => [ 'state' ], ); - if ( $c->req->param('bymonth') ) { + if ( $c->get_param('bymonth') ) { %select = ( select => [ { extract => \"year from $field", -as => 'c_year' }, @@ -1252,7 +1250,7 @@ not then display 404 page sub check_token : Private { my ( $self, $c ) = @_; - if ( !$c->req->param('token') || $c->req->param('token' ) ne $c->stash->{token} ) { + if ( !$c->get_param('token') || $c->get_param('token') ne $c->stash->{token} ) { $c->detach( '/page_error_404_not_found' ); } @@ -1290,7 +1288,7 @@ accordingly sub ban_user : Private { my ( $self, $c ) = @_; - my $email = $c->req->param('email'); + my $email = $c->get_param('email'); return unless $email; @@ -1317,7 +1315,7 @@ Sets the flag on a user with the given email sub flag_user : Private { my ( $self, $c ) = @_; - my $email = $c->req->param('email'); + my $email = $c->get_param('email'); return unless $email; @@ -1345,7 +1343,7 @@ Remove the flag on a user with the given email sub remove_user_flag : Private { my ( $self, $c ) = @_; - my $email = $c->req->param('email'); + my $email = $c->get_param('email'); return unless $email; @@ -1390,7 +1388,7 @@ Rotate a photo 90 degrees left or right sub rotate_photo : Private { my ( $self, $c ) =@_; - my $direction = $c->req->param('rotate_photo'); + my $direction = $c->get_param('rotate_photo'); return unless $direction eq _('Rotate Left') or $direction eq _('Rotate Right'); my $photo = $c->stash->{problem}->photo; diff --git a/perllib/FixMyStreet/App/Controller/Alert.pm b/perllib/FixMyStreet/App/Controller/Alert.pm index e821b7467..6972bbc04 100644 --- a/perllib/FixMyStreet/App/Controller/Alert.pm +++ b/perllib/FixMyStreet/App/Controller/Alert.pm @@ -53,14 +53,14 @@ Target for subscribe form sub subscribe : Path('subscribe') : Args(0) { my ( $self, $c ) = @_; - $c->detach('rss') if $c->req->param('rss'); + $c->detach('rss') if $c->get_param('rss'); # if it exists then it's been submitted so we should # go to subscribe email and let it work out the next step $c->detach('subscribe_email') - if exists $c->req->params->{'rznvy'} || $c->req->params->{'alert'}; + if $c->get_param('rznvy') || $c->get_param('alert'); - $c->go('updates') if $c->req->params->{'id'}; + $c->go('updates') if $c->get_param('id'); # shouldn't get to here but if we have then do something sensible $c->go('index'); @@ -74,7 +74,7 @@ Redirects to relevant RSS feed sub rss : Private { my ( $self, $c ) = @_; - my $feed = $c->req->params->{feed}; + my $feed = $c->get_param('feed'); unless ($feed) { $c->stash->{errors} = [ _('Please select the feed you want') ]; @@ -114,9 +114,9 @@ sub subscribe_email : Private { $c->stash->{errors} = []; $c->forward('process_user'); - my $type = $c->req->param('type'); + my $type = $c->get_param('type'); push @{ $c->stash->{errors} }, _('Please select the type of alert you want') - if $type && $type eq 'local' && !$c->req->param('feed'); + if $type && $type eq 'local' && !$c->get_param('feed'); if (@{ $c->stash->{errors} }) { $c->go('updates') if $type && $type eq 'updates'; $c->go('list') if $type && $type eq 'local'; @@ -145,8 +145,8 @@ sub subscribe_email : Private { sub updates : Path('updates') : Args(0) { my ( $self, $c ) = @_; - $c->stash->{email} = $c->req->param('rznvy'); - $c->stash->{problem_id} = $c->req->param('id'); + $c->stash->{email} = $c->get_param('rznvy'); + $c->stash->{problem_id} = $c->get_param('id'); } =head2 confirm @@ -209,7 +209,7 @@ Set up the options in the stash required to create a problem update alert sub set_update_alert_options : Private { my ( $self, $c ) = @_; - my $report_id = $c->req->param('id'); + my $report_id = $c->get_param('id'); my $options = { user => $c->stash->{alert_user}, @@ -229,7 +229,7 @@ Set up the options in the stash required to create a local problems alert sub set_local_alert_options : Private { my ( $self, $c ) = @_; - my $feed = $c->req->param('feed'); + my $feed = $c->get_param('feed'); my ( $type, @params, $alert ); if ( $feed =~ /^area:(?:\d+:)?(\d+)/ ) { @@ -305,12 +305,12 @@ This will canonicalise and prettify the postcode and stick a pretty_pc and prett sub prettify_pc : Private { my ( $self, $c ) = @_; - my $pretty_pc = $c->req->params->{'pc'}; + my $pretty_pc = $c->get_param('pc'); - if ( mySociety::PostcodeUtil::is_valid_postcode( $c->req->params->{'pc'} ) ) + if ( mySociety::PostcodeUtil::is_valid_postcode( $c->get_param('pc') ) ) { $pretty_pc = mySociety::PostcodeUtil::canonicalise_postcode( - $c->req->params->{'pc'} ); + $c->get_param('pc') ); my $pretty_pc_text = $pretty_pc; $pretty_pc_text =~ s/ //g; $c->stash->{pretty_pc_text} = $pretty_pc_text; @@ -336,7 +336,7 @@ sub process_user : Private { } # Extract all the params to a hash to make them easier to work with - my %params = map { $_ => scalar $c->req->param($_) } + my %params = map { $_ => $c->get_param($_) } ( 'rznvy' ); # , 'password_register' ); # cleanup the email address @@ -350,7 +350,7 @@ sub process_user : Private { $c->stash->{alert_user} = $alert_user; # # The user is trying to sign in. We only care about email from the params. -# if ( $c->req->param('submit_sign_in') ) { +# if ( $c->get_param('submit_sign_in') ) { # unless ( $c->forward( '/auth/sign_in', [ $email ] ) ) { # $c->stash->{field_errors}->{password} = _('There was a problem with your email/password combination. Please try again.'); # return 1; @@ -441,11 +441,6 @@ sub determine_location : Private { $c->go('index'); } - # truncate the lat,lon for nicer urls - ( $c->stash->{latitude}, $c->stash->{longitude} ) = - map { Utils::truncate_coordinate($_) } - ( $c->stash->{latitude}, $c->stash->{longitude} ); - my $dist = mySociety::Gaze::get_radius_containing_population( $c->stash->{latitude}, $c->stash->{longitude}, 200000 ); @@ -503,14 +498,14 @@ Setup the variables we need for the rest of the request sub setup_request : Private { my ( $self, $c ) = @_; - $c->stash->{rznvy} = $c->req->param('rznvy'); - $c->stash->{selected_feed} = $c->req->param('feed'); + $c->stash->{rznvy} = $c->get_param('rznvy'); + $c->stash->{selected_feed} = $c->get_param('feed'); if ( $c->user ) { $c->stash->{rznvy} ||= $c->user->email; } - $c->stash->{template} = 'alert/list-ajax.html' if $c->req->param('ajax'); + $c->stash->{template} = 'alert/list-ajax.html' if $c->get_param('ajax'); return 1; } diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index 0e42b8a17..723684793 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -40,8 +40,10 @@ sub around_index : Path : Args(0) { # Try to create a location for whatever we have my $ret = $c->forward('/location/determine_location_from_coords') || $c->forward('/location/determine_location_from_pc'); - return unless $ret; - return $c->res->redirect('/') if $ret == -1 && !$partial_report; + unless ($ret) { + return $c->res->redirect('/') unless $c->get_param('pc') || $partial_report; + return; + } # Check to see if the spot is covered by a area - if not show an error. return unless $c->cobrand->moniker eq 'fixmybarangay' || $c->forward('check_location_is_acceptable'); @@ -76,13 +78,12 @@ Handle coord systems that are no longer in use. sub redirect_en_or_xy_to_latlon : Private { my ( $self, $c ) = @_; - my $req = $c->req; # check for x,y or e,n requests - my $x = $req->param('x'); - my $y = $req->param('y'); - my $e = $req->param('e'); - my $n = $req->param('n'); + my $x = $c->get_param('x'); + my $y = $c->get_param('y'); + my $e = $c->get_param('e'); + my $n = $c->get_param('n'); # lat and lon - fill in below if we need to my ( $lat, $lon ); @@ -116,7 +117,7 @@ token to stash and return report. Otherwise return false. sub load_partial : Private { my ( $self, $c ) = @_; - my $partial = scalar $c->req->param('partial') + my $partial = $c->get_param('partial') || return; # is it in the database @@ -158,21 +159,20 @@ sub display_location : Private { my $latitude = $c->stash->{latitude}; my $longitude = $c->stash->{longitude}; - # truncate the lat,lon for nicer rss urls, and strings for outputting - my $short_latitude = Utils::truncate_coordinate($latitude); - my $short_longitude = Utils::truncate_coordinate($longitude); - $c->stash->{short_latitude} = $short_latitude; - $c->stash->{short_longitude} = $short_longitude; - # Deal with pin hiding/age - my $all_pins = $c->req->param('all_pins') ? 1 : undef; + my $all_pins = $c->get_param('all_pins') ? 1 : undef; $c->stash->{all_pins} = $all_pins; my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age; + $c->forward( '/reports/stash_report_filter_status' ); + + # Check the category to filter by, if any, is valid + $c->forward('check_and_stash_category'); + # get the map features my ( $on_map_all, $on_map, $around_map, $distance ) = - FixMyStreet::Map::map_features( $c, $short_latitude, $short_longitude, - $interval ); + FixMyStreet::Map::map_features( $c, $latitude, $longitude, + $interval, $c->stash->{filter_category}, $c->stash->{filter_problem_states} ); # copy the found reports to the stash $c->stash->{on_map} = $on_map; @@ -181,7 +181,7 @@ sub display_location : Private { # create a list of all the pins my @pins; - unless ($c->req->param('no_pins') || $c->cobrand->moniker eq 'emptyhomes') { + unless ($c->get_param('no_pins') || $c->cobrand->moniker eq 'emptyhomes') { @pins = map { # Here we might have a DB::Problem or a DB::Nearby, we always want the problem. my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_; @@ -199,8 +199,8 @@ sub display_location : Private { $c->stash->{page} = 'around'; # So the map knows to make clickable pins, update on pan FixMyStreet::Map::display_map( $c, - latitude => $short_latitude, - longitude => $short_longitude, + latitude => $latitude, + longitude => $longitude, clickable => 1, pins => \@pins, area => $c->cobrand->areas_on_around, @@ -225,6 +225,45 @@ sub check_location_is_acceptable : Private { return $c->forward('/council/load_and_check_areas'); } +=head2 check_and_stash_category + +Check that the 'filter_category' query param is valid, if it's present. Stores +the validated string in the stash as filter_category. +Puts all the valid categories in filter_categories on the stash. + +=cut + +sub check_and_stash_category : Private { + my ( $self, $c ) = @_; + + my $all_areas = $c->stash->{all_areas}; + my @bodies = $c->model('DB::Body')->search( + { 'body_areas.area_id' => [ keys %$all_areas ], deleted => 0 }, + { join => 'body_areas' } + )->all; + my %bodies = map { $_->id => $_ } @bodies; + + my @contacts = $c->model('DB::Contact')->not_deleted->search( + { + body_id => [ keys %bodies ], + }, + { + columns => [ 'category' ], + order_by => [ 'category' ], + distinct => 1 + } + )->all; + my @categories = map { $_->category } @contacts; + $c->stash->{filter_categories} = \@categories; + + + my $category = $c->get_param('filter_category'); + my %categories_mapped = map { $_ => 1 } @categories; + if ( defined $category && $categories_mapped{$category} ) { + $c->stash->{filter_category} = $category; + } +} + =head2 /ajax Handle the ajax calls that the map makes when it is dragged. The info returned @@ -238,7 +277,7 @@ sub ajax : Path('/ajax') { $c->res->content_type('application/json; charset=utf-8'); - unless ( $c->req->param('bbox') ) { + unless ( $c->get_param('bbox') ) { $c->res->status(404); $c->res->body(''); return; @@ -248,7 +287,7 @@ sub ajax : Path('/ajax') { $c->res->header( 'Cache_Control' => 'max-age=0' ); # how far back should we go? - my $all_pins = $c->req->param('all_pins') ? 1 : undef; + my $all_pins = $c->get_param('all_pins') ? 1 : undef; my $interval = $all_pins ? undef : $c->cobrand->on_map_default_max_pin_age; # Need to be the class that can handle it @@ -280,7 +319,7 @@ sub ajax : Path('/ajax') { sub location_autocomplete : Path('/ajax/geocode') { my ( $self, $c ) = @_; $c->res->content_type('application/json; charset=utf-8'); - unless ( $c->req->param('term') ) { + unless ( $c->get_param('term') ) { $c->res->status(404); $c->res->body(''); return; @@ -288,26 +327,26 @@ sub location_autocomplete : Path('/ajax/geocode') { # we want the match even if there's no ambiguity, so recommendation doesn't # disappear when it's the last choice being offered in the autocomplete. $c->stash->{allow_single_geocode_match_strings} = 1; - return $self->_geocode( $c, $c->req->param('term') ); + return $self->_geocode( $c, $c->get_param('term') ); } sub location_lookup : Path('/ajax/lookup_location') { my ( $self, $c ) = @_; $c->res->content_type('application/json; charset=utf-8'); - unless ( $c->req->param('term') ) { + unless ( $c->get_param('term') ) { $c->res->status(404); $c->res->body(''); return; } - return $self->_geocode( $c, $c->req->param('term') ); + return $self->_geocode( $c, $c->get_param('term') ); } sub _geocode : Private { my ( $self, $c, $term ) = @_; my ( $lat, $long, $suggestions ) = - FixMyStreet::Geocode::lookup( $c->req->param('term'), $c ); + FixMyStreet::Geocode::lookup( $c->get_param('term'), $c ); my ($response, @addresses, @locations); @@ -317,7 +356,7 @@ sub _geocode : Private { if ( ref($suggestions) eq 'ARRAY' ) { foreach (@$suggestions) { push @addresses, decode_utf8($_->{address}); - push @locations, { address => decode_utf8($_->{address}), lat => $_->{latitude}, long => $_->{longitude} }; + push @locations, { address => decode_utf8($_->{address}), lat => $_->{latitude}, long => $_->{longitude} }; } $response = { suggestions => \@addresses, locations => \@locations }; } else { diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index fad8941c5..63bf91ff5 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -28,22 +28,21 @@ Present the user with a sign in / create account page. sub general : Path : Args(0) { my ( $self, $c ) = @_; - my $req = $c->req; - $c->detach( 'redirect_on_signin', [ $req->param('r') ] ) - if $c->user && $req->param('r'); + $c->detach( 'redirect_on_signin', [ $c->get_param('r') ] ) + if $c->user && $c->get_param('r'); # all done unless we have a form posted to us - return unless $req->method eq 'POST'; + return unless $c->req->method eq 'POST'; # decide which action to take - my $has_password = $req->param('sign_in') || $req->param('password_sign_in'); - my $has_email = $req->param('email_sign_in') || $req->param('name') || $req->param('password_register'); + my $has_password = $c->get_param('sign_in') || $c->get_param('password_sign_in'); + my $has_email = $c->get_param('email_sign_in') || $c->get_param('name') || $c->get_param('password_register'); $c->detach('email_sign_in') if $has_email && !$has_password; $c->forward( 'sign_in' ) - && $c->detach( 'redirect_on_signin', [ $req->param('r') ] ); + && $c->detach( 'redirect_on_signin', [ $c->get_param('r') ] ); } @@ -56,9 +55,9 @@ Allow the user to sign in with a username and a password. sub sign_in : Private { my ( $self, $c, $email ) = @_; - $email ||= $c->req->param('email') || ''; - my $password = $c->req->param('password_sign_in') || ''; - my $remember_me = $c->req->param('remember_me') || 0; + $email ||= $c->get_param('email') || ''; + my $password = $c->get_param('password_sign_in') || ''; + my $remember_me = $c->get_param('remember_me') || 0; # Sign out just in case $c->logout(); @@ -95,7 +94,7 @@ sub email_sign_in : Private { my ( $self, $c ) = @_; # check that the email is valid - otherwise flag an error - my $raw_email = lc( $c->req->param('email') || '' ); + my $raw_email = lc( $c->get_param('email') || '' ); my $email_checker = Email::Valid->new( -mxcheck => 1, @@ -112,8 +111,8 @@ sub email_sign_in : Private { } my $user_params = {}; - $user_params->{password} = $c->req->param('password_register') - if $c->req->param('password_register'); + $user_params->{password} = $c->get_param('password_register') + if $c->get_param('password_register'); my $user = $c->model('DB::User')->new( $user_params ); my $token_obj = $c->model('DB::Token') # @@ -122,8 +121,8 @@ sub email_sign_in : Private { scope => 'email_sign_in', data => { email => $good_email, - r => $c->req->param('r'), - name => $c->req->param('name'), + r => $c->get_param('r'), + name => $c->get_param('name'), password => $user->password, } } @@ -156,6 +155,11 @@ sub token : Path('/M') : Args(1) { return; } + if ( $token_obj->created < DateTime->now->subtract( days => 1 ) ) { + $c->stash->{token_not_found} = 1; + return; + } + # Sign out in case we are another user $c->logout(); @@ -221,8 +225,8 @@ sub change_password : Local { return unless $c->req->method eq 'POST'; # get the passwords - my $new = $c->req->param('new_password') // ''; - my $confirm = $c->req->param('confirm') // ''; + my $new = $c->get_param('new_password') // ''; + my $confirm = $c->get_param('confirm') // ''; # check for errors my $password_error = diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm index f48518d77..912224649 100644 --- a/perllib/FixMyStreet/App/Controller/Contact.pm +++ b/perllib/FixMyStreet/App/Controller/Contact.pm @@ -41,6 +41,11 @@ Handle contact us form submission sub submit : Path('submit') : Args(0) { my ( $self, $c ) = @_; + if (my $testing = $c->get_param('_test_')) { + $c->stash->{success} = $c->get_param('success'); + return; + } + $c->res->redirect( '/contact' ) and return unless $c->req->method eq 'POST'; return @@ -61,9 +66,9 @@ generic contact request and set up things accordingly sub determine_contact_type : Private { my ( $self, $c ) = @_; - my $id = $c->req->param('id'); - my $update_id = $c->req->param('update_id'); - my $token = $c->req->param('m'); + my $id = $c->get_param('id'); + my $update_id = $c->get_param('update_id'); + my $token = $c->get_param('m'); $id = undef unless $id && $id =~ /^[1-9]\d*$/; $update_id = undef unless $update_id && $update_id =~ /^[1-9]\d*$/; @@ -111,12 +116,12 @@ sub validate : Private { foreach my $field ( keys %required ) { $field_errors{$field} = $required{$field} - unless $c->req->param($field) =~ /\S/; + unless $c->get_param($field) =~ /\S/; } unless ( $field_errors{em} ) { $field_errors{em} = _('Please enter a valid email address') - if !mySociety::EmailUtil::is_valid_email( $c->req->param('em') ); + if !mySociety::EmailUtil::is_valid_email( $c->get_param('em') ); } %field_errors = ( @@ -125,11 +130,11 @@ sub validate : Private { ); push @errors, _('Illegal ID') - if $c->req->param('id') && !$c->stash->{problem} - or $c->req->param('update_id') && !$c->stash->{update}; + if $c->get_param('id') && !$c->stash->{problem} + or $c->get_param('update_id') && !$c->stash->{update}; push @errors, _('There was a problem showing this page. Please try again later.') - if $c->req->params->{message} && $c->req->params->{message} =~ /\[url=|<a/; + if $c->get_param('message') && $c->get_param('message') =~ /\[url=|<a/; unshift @errors, _('There were problems with your report. Please see below.') @@ -206,11 +211,11 @@ sub setup_request : Private { $c->stash->{contact_email} =~ s/\@/@/; for my $param (qw/em subject message/) { - $c->stash->{$param} = $c->req->param($param); + $c->stash->{$param} = $c->get_param($param); } # name is already used in the stash for the app class name - $c->stash->{form_name} = $c->req->param('name'); + $c->stash->{form_name} = $c->get_param('name'); return 1; } diff --git a/perllib/FixMyStreet/App/Controller/Council.pm b/perllib/FixMyStreet/App/Controller/Council.pm index 8a174c254..a5915aa46 100644 --- a/perllib/FixMyStreet/App/Controller/Council.pm +++ b/perllib/FixMyStreet/App/Controller/Council.pm @@ -49,9 +49,6 @@ sub load_and_check_areas : Private { $area_types = $c->cobrand->area_types; } - my $short_latitude = Utils::truncate_coordinate($latitude); - my $short_longitude = Utils::truncate_coordinate($longitude); - my $all_areas; my %params; @@ -62,7 +59,7 @@ sub load_and_check_areas : Private { my %area_types = map { $_ => 1 } @$area_types; $all_areas = mySociety::MaPit::call( 'point', - "4326/$short_longitude,$short_latitude", %params ); + "4326/$longitude,$latitude", %params ); $c->stash->{all_areas_mapit} = $all_areas; $all_areas = { map { $_ => $all_areas->{$_} } @@ -72,7 +69,7 @@ sub load_and_check_areas : Private { } else { $all_areas = mySociety::MaPit::call( 'point', - "4326/$short_longitude,$short_latitude", %params, + "4326/$longitude,$latitude", %params, type => $area_types ); } if ($all_areas->{error}) { diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm index 25c6e1923..c3aa35008 100644 --- a/perllib/FixMyStreet/App/Controller/Dashboard.pm +++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm @@ -32,9 +32,9 @@ sub example : Local : Args(0) { #$c->forward( '/report/new/setup_categories_and_bodies' ); # See if we've had anything from the dropdowns - perhaps vary results if so - $c->stash->{ward} = $c->req->param('ward'); - $c->stash->{category} = $c->req->param('category'); - $c->stash->{q_state} = $c->req->param('state'); + $c->stash->{ward} = $c->get_param('ward'); + $c->stash->{category} = $c->get_param('category'); + $c->stash->{q_state} = $c->get_param('state'); eval { my $data = File::Slurp::read_file( @@ -108,8 +108,8 @@ sub index : Path : Args(0) { # See if we've had anything from the dropdowns - $c->stash->{ward} = $c->req->param('ward'); - $c->stash->{category} = $c->req->param('category'); + $c->stash->{ward} = $c->get_param('ward'); + $c->stash->{category} = $c->get_param('category'); my %where = ( bodies_str => $body->id, # XXX Does this break in a two tier council? Restriction needs looking at... @@ -128,7 +128,7 @@ sub index : Path : Args(0) { my $dtf = $c->model('DB')->storage->datetime_parser; my %counts; - my $now = DateTime->now( time_zone => 'local' ); + my $now = DateTime->now( time_zone => FixMyStreet->local_time_zone ); my $t = $now->clone->truncate( to => 'day' ); $counts{wtd} = $c->forward( 'updates_search', [ $dtf->format_datetime( $t->clone->subtract( days => $t->dow - 1 ) ) ] ); @@ -143,7 +143,7 @@ sub index : Path : Args(0) { # List of reports underneath summary table - $c->stash->{q_state} = $c->req->param('state') || ''; + $c->stash->{q_state} = $c->get_param('state') || ''; if ( $c->stash->{q_state} eq 'fixed' ) { $prob_where->{'me.state'} = [ FixMyStreet::DB::Result::Problem->fixed_states() ]; } elsif ( $c->stash->{q_state} ) { @@ -170,7 +170,7 @@ sub index : Path : Args(0) { } $c->stash->{lists} = \%problems; - if ( $c->req->params->{export} ) { + if ( $c->get_param('export') ) { $self->export_as_csv($c, $problems_rs, $body); } } diff --git a/perllib/FixMyStreet/App/Controller/JSON.pm b/perllib/FixMyStreet/App/Controller/JSON.pm index 17507a84b..959ead245 100644 --- a/perllib/FixMyStreet/App/Controller/JSON.pm +++ b/perllib/FixMyStreet/App/Controller/JSON.pm @@ -38,9 +38,9 @@ sub problems : Local { : ''; # gather the parameters - my $start_date = $c->req->param('start_date') || ''; - my $end_date = $c->req->param('end_date') || ''; - my $category = $c->req->param('category') || ''; + my $start_date = $c->get_param('start_date') || ''; + my $end_date = $c->get_param('end_date') || ''; + my $category = $c->get_param('category') || ''; my $yyyy_mm_dd = qr{^\d{4}-\d\d-\d\d$}; if ( $start_date !~ $yyyy_mm_dd diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm index 8a68b2b3d..ff90d3d60 100644 --- a/perllib/FixMyStreet/App/Controller/Location.pm +++ b/perllib/FixMyStreet/App/Controller/Location.pm @@ -6,6 +6,7 @@ BEGIN {extends 'Catalyst::Controller'; } use Encode; use FixMyStreet::Geocode; +use Utils; =head1 NAME @@ -28,15 +29,15 @@ Use latitude and longitude if provided in parameters. sub determine_location_from_coords : Private { my ( $self, $c ) = @_; - my $latitude = $c->req->param('latitude') || $c->req->param('lat'); - my $longitude = $c->req->param('longitude') || $c->req->param('lon'); + my $latitude = $c->get_param('latitude') || $c->get_param('lat'); + my $longitude = $c->get_param('longitude') || $c->get_param('lon'); if ( defined $latitude && defined $longitude ) { - $c->stash->{latitude} = $latitude; - $c->stash->{longitude} = $longitude; + ($c->stash->{latitude}, $c->stash->{longitude}) = + map { Utils::truncate_coordinate($_) } ($latitude, $longitude); # Also save the pc if there is one - if ( my $pc = $c->req->param('pc') ) { + if ( my $pc = $c->get_param('pc') ) { $c->stash->{pc} = $pc; } @@ -50,7 +51,7 @@ sub determine_location_from_coords : Private { User has searched for a location - try to find it for them. -Return -1 if nothing provided. +Return false if nothing provided. If one match is found returns true and lat/lng is set. @@ -64,18 +65,19 @@ sub determine_location_from_pc : Private { my ( $self, $c, $pc ) = @_; # check for something to search - $pc ||= $c->req->param('pc') || return -1; + $pc ||= $c->get_param('pc') || return; $c->stash->{pc} = $pc; # for template if ( $pc =~ /^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/ ) { - $c->stash->{latitude} = $1; - $c->stash->{longitude} = $2; + ($c->stash->{latitude}, $c->stash->{longitude}) = + map { Utils::truncate_coordinate($_) } ($1, $2); return $c->forward( 'check_location' ); } if ( $c->cobrand->country eq 'GB' && $pc =~ /^([A-Z])([A-Z])([\d\s]{4,})$/i) { if (my $convert = gridref_to_latlon( $1, $2, $3 )) { - $c->stash->{latitude} = $convert->{latitude}; - $c->stash->{longitude} = $convert->{longitude}; + ($c->stash->{latitude}, $c->stash->{longitude}) = + map { Utils::truncate_coordinate($_) } + ($convert->{latitude}, $convert->{longitude}); return $c->forward( 'check_location' ); } } diff --git a/perllib/FixMyStreet/App/Controller/Moderate.pm b/perllib/FixMyStreet/App/Controller/Moderate.pm index ad293fbd7..08c4280a1 100644 --- a/perllib/FixMyStreet/App/Controller/Moderate.pm +++ b/perllib/FixMyStreet/App/Controller/Moderate.pm @@ -65,7 +65,7 @@ sub report : Chained('moderate') : PathPart('report') : CaptureArgs(1) { }); $c->stash->{problem} = $problem; $c->stash->{problem_original} = $original; - $c->stash->{moderation_reason} = $c->req->param('moderation_reason') // ''; + $c->stash->{moderation_reason} = $c->get_param('moderation_reason') // ''; } sub moderate_report : Chained('report') : PathPart('') : Args(0) { @@ -127,7 +127,7 @@ sub report_moderate_hide : Private { my $problem = $c->stash->{problem} or die; - if ($c->req->param('problem_hide')) { + if ($c->get_param('problem_hide')) { $problem->update({ state => 'hidden' }); @@ -145,9 +145,9 @@ sub report_moderate_title : Private { my $old_title = $problem->title; my $original_title = $original->title; - my $title = $c->req->param('problem_revert_title') ? + my $title = $c->get_param('problem_revert_title') ? $original_title - : $self->diff($original_title, $c->req->param('problem_title')); + : $self->diff($original_title, $c->get_param('problem_title')); if ($title ne $old_title) { $original->insert unless $original->in_storage; @@ -166,9 +166,9 @@ sub report_moderate_detail : Private { my $old_detail = $problem->detail; my $original_detail = $original->detail; - my $detail = $c->req->param('problem_revert_detail') ? + my $detail = $c->get_param('problem_revert_detail') ? $original_detail - : $self->diff($original_detail, $c->req->param('problem_detail')); + : $self->diff($original_detail, $c->get_param('problem_detail')); if ($detail ne $old_detail) { $original->insert unless $original->in_storage; @@ -184,7 +184,7 @@ sub report_moderate_anon : Private { my $problem = $c->stash->{problem} or die; my $original = $c->stash->{problem_original}; - my $show_user = $c->req->param('problem_show_name') ? 1 : 0; + my $show_user = $c->get_param('problem_show_name') ? 1 : 0; my $anonymous = $show_user ? 0 : 1; my $old_anonymous = $problem->anonymous ? 1 : 0; @@ -205,7 +205,7 @@ sub report_moderate_photo : Private { return unless $original->photo; - my $show_photo = $c->req->param('problem_show_photo') ? 1 : 0; + my $show_photo = $c->get_param('problem_show_photo') ? 1 : 0; my $old_show_photo = $problem->photo ? 1 : 0; if ($show_photo != $old_show_photo) { @@ -268,7 +268,7 @@ sub update_moderate_hide : Private { my $problem = $c->stash->{problem} or die; my $comment = $c->stash->{comment} or die; - if ($c->req->param('update_hide')) { + if ($c->get_param('update_hide')) { $comment->update({ state => 'hidden' }); $c->detach( 'update_moderate_audit', ['hide'] ); # break chain here. } @@ -284,9 +284,9 @@ sub update_moderate_detail : Private { my $old_detail = $comment->text; my $original_detail = $original->detail; - my $detail = $c->req->param('update_revert_detail') ? + my $detail = $c->get_param('update_revert_detail') ? $original_detail - : $self->diff($original_detail, $c->req->param('update_detail')); + : $self->diff($original_detail, $c->get_param('update_detail')); if ($detail ne $old_detail) { $original->insert unless $original->in_storage; @@ -303,7 +303,7 @@ sub update_moderate_anon : Private { my $comment = $c->stash->{comment} or die; my $original = $c->stash->{comment_original}; - my $show_user = $c->req->param('update_show_name') ? 1 : 0; + my $show_user = $c->get_param('update_show_name') ? 1 : 0; my $anonymous = $show_user ? 0 : 1; my $old_anonymous = $comment->anonymous ? 1 : 0; @@ -324,7 +324,7 @@ sub update_moderate_photo : Private { return unless $original->photo; - my $show_photo = $c->req->param('update_show_photo') ? 1 : 0; + my $show_photo = $c->get_param('update_show_photo') ? 1 : 0; my $old_show_photo = $comment->photo ? 1 : 0; if ($show_photo != $old_show_photo) { diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm index bbef1f8d8..83d5f7adb 100644 --- a/perllib/FixMyStreet/App/Controller/My.pm +++ b/perllib/FixMyStreet/App/Controller/My.pm @@ -25,20 +25,29 @@ sub my : Path : Args(0) { $c->detach( '/auth/redirect' ) unless $c->user; - my $p_page = $c->req->params->{p} || 1; - my $u_page = $c->req->params->{u} || 1; + my $p_page = $c->get_param('p') || 1; + my $u_page = $c->get_param('u') || 1; + + $c->forward( '/reports/stash_report_filter_status' ); my $pins = []; my $problems = {}; + my $states = $c->stash->{filter_problem_states}; my $params = { - state => [ FixMyStreet::DB::Result::Problem->visible_states() ], + state => [ keys %$states ], }; $params = { %{ $c->cobrand->problems_clause }, %$params } if $c->cobrand->problems_clause; + my $category = $c->get_param('filter_category'); + if ( $category ) { + $params->{category} = $category; + $c->stash->{filter_category} = $category; + } + my $rs = $c->user->problems->search( $params, { order_by => { -desc => 'confirmed' }, rows => 50 @@ -55,6 +64,7 @@ sub my : Path : Args(0) { }; my $state = $problem->is_fixed ? 'fixed' : $problem->is_closed ? 'closed' : 'confirmed'; push @{ $problems->{$state} }, $problem; + push @{ $problems->{all} }, $problem; } $c->stash->{problems_pager} = $rs->pager; $c->stash->{problems} = $problems; @@ -71,6 +81,14 @@ sub my : Path : Args(0) { $c->stash->{updates} = \@updates; $c->stash->{updates_pager} = $rs->pager; + my @categories = $c->user->problems->search( undef, { + columns => [ 'category' ], + distinct => 1, + order_by => [ 'category' ], + } )->all; + @categories = map { $_->category } @categories; + $c->stash->{filter_categories} = \@categories; + $c->stash->{page} = 'my'; FixMyStreet::Map::display_map( $c, diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm index f3841acef..96066ca93 100644 --- a/perllib/FixMyStreet/App/Controller/Open311.pm +++ b/perllib/FixMyStreet/App/Controller/Open311.pm @@ -155,9 +155,9 @@ sub get_discovery : Private { sub get_services : Private { my ( $self, $c ) = @_; - my $jurisdiction_id = $c->req->param('jurisdiction_id') || ''; - my $lat = $c->req->param('lat') || ''; - my $lon = $c->req->param('long') || ''; + my $jurisdiction_id = $c->get_param('jurisdiction_id') || ''; + my $lat = $c->get_param('lat') || ''; + my $lon = $c->get_param('long') || ''; # Look up categories for this council or councils my $categories = $c->model('DB::Contact')->not_deleted; @@ -252,7 +252,12 @@ sub output_requests : Private { 'interface_used' => [ $problem->service ], # Not in Open311 v2 }; - if ( $c->cobrand->moniker ne 'zurich' ) { # XXX + if ( $c->cobrand->moniker eq 'zurich' ) { + $request->{service_notice} = [ + $problem->get_extra_metadata('public_response') + ]; + } + else { # FIXME Not according to Open311 v2 $request->{agency_responsible} = $problem->bodies; } @@ -304,7 +309,7 @@ sub get_requests : Private { $c->forward( 'is_jurisdiction_id_ok' ); - my $max_requests = $c->req->param('max_requests') || 0; + my $max_requests = $c->get_param('max_requests') || 0; # Only provide access to the published reports my $states = FixMyStreet::DB::Result::Problem->visible_states(); @@ -322,7 +327,7 @@ sub get_requests : Private { has_photo => [ '=', 'photo' ], ); for my $param (keys %rules) { - my $value = $c->req->param($param); + my $value = $c->get_param($param); next unless $value; my $op = $rules{$param}[0]; my $key = $rules{$param}[1]; @@ -361,12 +366,12 @@ sub get_requests : Private { $criteria->{$key} = { $op, $value }; } - if ( $c->req->param('start_date') and $c->req->param('end_date') ) { - $criteria->{confirmed} = [ '-and' => { '>=', $c->req->param('start_date') }, { '<', $c->req->param('end_date') } ]; - } elsif ( $c->req->param('start_date') ) { - $criteria->{confirmed} = { '>=', $c->req->param('start_date') }; - } elsif ( $c->req->param('end_date') ) { - $criteria->{confirmed} = { '<', $c->req->param('end_date') }; + if ( $c->get_param('start_date') and $c->get_param('end_date') ) { + $criteria->{confirmed} = [ '-and' => { '>=', $c->get_param('start_date') }, { '<', $c->get_param('end_date') } ]; + } elsif ( $c->get_param('start_date') ) { + $criteria->{confirmed} = { '>=', $c->get_param('start_date') }; + } elsif ( $c->get_param('end_date') ) { + $criteria->{confirmed} = { '<', $c->get_param('end_date') }; } if ('rss' eq $c->stash->{format}) { @@ -436,7 +441,7 @@ sub format_output : Private { sub is_jurisdiction_id_ok : Private { my ( $self, $c ) = @_; - unless (my $jurisdiction_id = $c->req->param('jurisdiction_id')) { + unless (my $jurisdiction_id = $c->get_param('jurisdiction_id')) { $c->detach( 'error', [ _('Missing jurisdiction_id') ] ); } } diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm index 09afabecf..a2ec7d4c8 100644 --- a/perllib/FixMyStreet/App/Controller/Photo.pm +++ b/perllib/FixMyStreet/App/Controller/Photo.pm @@ -8,6 +8,7 @@ use DateTime::Format::HTTP; use Digest::SHA qw(sha1_hex); use File::Path; use File::Slurp; +use Image::Size; use Path::Class; use if !$ENV{TRAVIS}, 'Image::Magick'; @@ -181,7 +182,11 @@ sub process_photo_upload : Private { 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:/; + unless (defined $out) { + my ($w, $h, $err) = Image::Size::imgsize($filename); + die _("Please upload a JPEG image only") . "\n" if !defined $w || $err ne 'JPG'; + } + die _("Please upload a JPEG image only") . "\n" if $out && $out =~ /Not JPEG:/; my $photo = $upload->slurp; return $photo; }; @@ -221,7 +226,7 @@ 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') || ''; + my $fileid = $c->get_param('upload_fileid') || ''; $fileid =~ s{[^0-9a-f]}{}gi; return unless $fileid; diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm index 46d6350d7..f9a08e408 100755 --- a/perllib/FixMyStreet/App/Controller/Questionnaire.pm +++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm @@ -67,9 +67,16 @@ token), or the mini own-report one (when we'll have a problem ID). sub submit : Path('submit') { my ( $self, $c ) = @_; - if ( $c->req->params->{token} ) { + if (my $token = $c->get_param('token')) { + if ($token eq '_test_') { + $c->stash->{been_fixed} = $c->get_param('been_fixed'); + $c->stash->{new_state} = $c->get_param('new_state'); + $c->stash->{template} = 'questionnaire/completed.html'; + return; + } $c->forward('submit_standard'); - } elsif ( $c->req->params->{problem} ) { + } elsif (my $p = $c->get_param('problem')) { + $c->detach('creator_fixed') if $p eq '_test_'; $c->forward('submit_creator_fixed'); } else { $c->detach( '/page_error_404_not_found' ); @@ -96,8 +103,8 @@ sub submit_creator_fixed : Private { my @errors; - $c->stash->{reported} = $c->req->params->{reported}; - $c->stash->{problem_id} = $c->req->params->{problem}; + $c->stash->{reported} = $c->get_param('reported'); + $c->stash->{problem_id} = $c->get_param('problem'); # should only be able to get to here if we are logged and we have a # problem @@ -106,6 +113,7 @@ sub submit_creator_fixed : Private { } my $problem = $c->cobrand->problems->find( { id => $c->stash->{problem_id} } ); + $c->stash->{problem} = $problem; # you should not be able to answer questionnaires about problems # that you've not submitted @@ -148,7 +156,7 @@ sub submit_creator_fixed : Private { sub submit_standard : Private { my ( $self, $c ) = @_; - $c->forward( '/tokens/load_questionnaire', [ $c->req->params->{token} ] ); + $c->forward( '/tokens/load_questionnaire', [ $c->get_param('token') ] ); $c->forward( 'check_questionnaire' ); $c->forward( 'process_questionnaire' ); @@ -224,7 +232,7 @@ sub submit_standard : Private { sub process_questionnaire : Private { my ( $self, $c ) = @_; - map { $c->stash->{$_} = $c->req->params->{$_} || '' } qw(been_fixed reported another update); + map { $c->stash->{$_} = $c->get_param($_) || '' } qw(been_fixed reported another update); # EHA questionnaires done for you if ($c->cobrand->moniker eq 'emptyhomes') { @@ -279,10 +287,6 @@ sub display : Private { my $problem = $c->stash->{questionnaire}->problem; - ( $c->stash->{short_latitude}, $c->stash->{short_longitude} ) = - map { Utils::truncate_coordinate($_) } - ( $problem->latitude, $problem->longitude ); - $c->stash->{updates} = [ $c->model('DB::Comment')->search( { problem_id => $problem->id, state => 'confirmed' }, { order_by => 'confirmed' } diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 88a49f6c9..7b001ee4c 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -24,7 +24,7 @@ Redirect to homepage unless C<id> parameter in query, in which case redirect to sub index : Path('') : Args(0) { my ( $self, $c ) = @_; - my $id = $c->req->param('id'); + my $id = $c->get_param('id'); my $uri = $id @@ -78,7 +78,7 @@ sub _display : Private { sub support : Path('support') : Args(0) { my ( $self, $c ) = @_; - my $id = $c->req->param('id'); + my $id = $c->get_param('id'); my $uri = $id @@ -151,6 +151,10 @@ sub load_updates : Private { @combined = map { $_->[1] } sort { $a->[0] <=> $b->[0] } @combined; $c->stash->{updates} = \@combined; + if ($c->sessionid && $c->flash->{alert_to_reporter}) { + $c->stash->{alert_to_reporter} = 1; + } + return 1; } @@ -159,18 +163,15 @@ sub format_problem_for_display : Private { my $problem = $c->stash->{problem}; - ( $c->stash->{short_latitude}, $c->stash->{short_longitude} ) = + ( $c->stash->{latitude}, $c->stash->{longitude} ) = map { Utils::truncate_coordinate($_) } ( $problem->latitude, $problem->longitude ); - unless ( $c->req->param('submit_update') ) { + unless ( $c->get_param('submit_update') ) { $c->stash->{add_alert} = 1; } $c->stash->{extra_name_info} = $problem->bodies_str && $problem->bodies_str eq '2482' ? 1 : 0; - if ( $c->sessionid && $c->flash->{created_report} ) { - $c->stash->{created_report} = $c->flash->{created_report}; - } $c->forward('generate_map_tags'); diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index ed5be4e99..b540a1961 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -74,7 +74,6 @@ partial =cut -use constant COUNCIL_ID_BARNET => 2489; use constant COUNCIL_ID_BROMLEY => 2482; sub report_new : Path : Args(0) { @@ -220,14 +219,22 @@ sub category_extras_ajax : Path('category_extras') : Args(0) { return 1; } $c->forward('setup_categories_and_bodies'); + $c->forward('check_for_category'); + my $category = $c->stash->{category}; my $category_extra = ''; - if ( $c->stash->{category_extras}->{ $c->req->param('category') } && @{ $c->stash->{category_extras}->{ $c->req->param('category') } } >= 1 ) { + my $generate; + if ( $c->stash->{category_extras}->{$category} && @{ $c->stash->{category_extras}->{$category} } >= 1 ) { $c->stash->{report_meta} = {}; - $c->stash->{report} = { category => $c->req->param('category') }; - $c->stash->{category_extras} = { $c->req->param('category' ) => $c->stash->{category_extras}->{ $c->req->param('category') } }; - - $category_extra= $c->render_fragment( 'report/new/category_extras.html'); + $c->stash->{category_extras} = { $category => $c->stash->{category_extras}->{$category} }; + $generate = 1; + } + if ($c->stash->{unresponsive}->{$category}) { + $generate = 1; + } + if ($generate) { + $c->stash->{report} = { category => $category }; + $category_extra = $c->render_fragment( 'report/new/category_extras.html'); } my $body = JSON->new->utf8(1)->encode( @@ -257,7 +264,7 @@ sub report_import : Path('/import') { $c->res->content_type('text/plain; charset=utf-8'); my %input = - map { $_ => $c->req->param($_) || '' } ( + map { $_ => $c->get_param($_) || '' } ( 'service', 'subject', 'detail', 'name', 'email', 'phone', 'easting', 'northing', 'lat', 'lon', 'id', 'phone_id', ); @@ -408,7 +415,7 @@ sub initialize_report : Private { # create a new one. Stick it on the stash. my $report = undef; - if ( my $partial = scalar $c->req->param('partial') ) { + if ( my $partial = $c->get_param('partial') ) { for (1) { # use as pseudo flow control @@ -462,15 +469,15 @@ sub initialize_report : Private { } - if ( $c->req->param('first_name') && $c->req->param('last_name') ) { - $c->stash->{first_name} = $c->req->param('first_name'); - $c->stash->{last_name} = $c->req->param('last_name'); + if ( $c->get_param('first_name') && $c->get_param('last_name') ) { + $c->stash->{first_name} = $c->get_param('first_name'); + $c->stash->{last_name} = $c->get_param('last_name'); - $c->req->param( 'name', sprintf( '%s %s', $c->req->param('first_name'), $c->req->param('last_name') ) ); + $c->set_param('name', sprintf( '%s %s', $c->get_param('first_name'), $c->get_param('last_name') )); } # Capture whether the map was used - $report->used_map( $c->req->param('skipped') ? 0 : 1 ); + $report->used_map( $c->get_param('skipped') ? 0 : 1 ); $c->stash->{report} = $report; @@ -524,8 +531,8 @@ sub determine_location_from_tile_click : Private { # Extract the data needed my ( $pin_tile_x, $pin_tile_y ) = $x_key =~ m{$param_key_regex}; - my $pin_x = $c->req->param($x_key); - my $pin_y = $c->req->param($y_key); + my $pin_x = $c->get_param($x_key); + my $pin_y = $c->get_param($y_key); # return if they are both 0 - this happens when you submit the form by # hitting enter and not using the button. It also happens if you click @@ -540,8 +547,8 @@ sub determine_location_from_tile_click : Private { ); # store it on the stash - $c->stash->{latitude} = $latitude; - $c->stash->{longitude} = $longitude; + ($c->stash->{latitude}, $c->stash->{longitude}) = + map { Utils::truncate_coordinate($_) } ($latitude, $longitude); # set a flag so that the form is not considered submitted. This will prevent # errors showing on the fields. @@ -604,6 +611,11 @@ sub setup_categories_and_bodies : Private { my %category_extras = (); # extra fields to fill in for open311 my %non_public_categories = (); # categories for which the reports are not public + $c->stash->{unresponsive} = {}; + + if (keys %bodies == 1 && $first_body->send_method && $first_body->send_method eq 'Refused') { + $c->stash->{unresponsive}{ALL} = $first_body->id; + } # FIXME - implement in cobrand if ( $c->cobrand->moniker eq 'emptyhomes' ) { @@ -624,18 +636,6 @@ sub setup_categories_and_bodies : Private { _('Empty public building - school, hospital, etc.') ); - } elsif ($first_area->{id} != COUNCIL_ID_BROMLEY - && $first_area->{id} != COUNCIL_ID_BARNET - && $first_area->{type} eq 'LBO') { - - $bodies_to_list{ $first_body->id } = 1; - my @local_categories; - @local_categories = sort keys %{ Utils::london_categories() }; - @category_options = ( - _('-- Pick a category --'), - @local_categories - ); - } else { # keysort does not appear to obey locale so use strcoll (see i18n.t) @@ -649,8 +649,12 @@ sub setup_categories_and_bodies : Private { unless ( $seen{$contact->category} ) { push @category_options, $contact->category; - $category_extras{ $contact->category } = $contact->extra - if $contact->extra; + my $metas = $contact->get_extra_fields; + $category_extras{ $contact->category } = $metas + if scalar @$metas; + + $c->stash->{unresponsive}{$contact->category} = $contact->body_id + if $contact->email =~ /^REFUSED$/i; $non_public_categories{ $contact->category } = 1 if $contact->non_public; } @@ -664,6 +668,9 @@ sub setup_categories_and_bodies : Private { } } + $c->cobrand->munge_category_list(\@category_options, \@contacts, \%category_extras) + if $c->cobrand->can('munge_category_list'); + if ($c->cobrand->can('hidden_categories')) { my %hidden_categories = map { $_ => 1 } $c->cobrand->hidden_categories; @@ -703,7 +710,7 @@ on the presence of the C<submit_problem> parameter. sub check_form_submitted : Private { my ( $self, $c ) = @_; return if $c->stash->{force_form_not_submitted}; - return $c->req->param('submit_problem') || ''; + return $c->get_param('submit_problem') || ''; } =head2 process_user @@ -718,7 +725,7 @@ sub process_user : Private { my $report = $c->stash->{report}; # Extract all the params to a hash to make them easier to work with - my %params = map { $_ => scalar $c->req->param($_) } + my %params = map { $_ => $c->get_param($_) } ( 'email', 'name', 'phone', 'password_register', 'fms_extra_title' ); my $user_title = Utils::trim_text( $params{fms_extra_title} ); @@ -750,7 +757,7 @@ sub process_user : Private { unless $report->user; # The user is trying to sign in. We only care about email from the params. - if ( $c->req->param('submit_sign_in') || $c->req->param('password_sign_in') ) { + if ( $c->get_param('submit_sign_in') || $c->get_param('password_sign_in') ) { unless ( $c->forward( '/auth/sign_in' ) ) { $c->stash->{field_errors}->{password} = _('There was a problem with your email/password combination. If you cannot remember your password, or do not have one, please fill in the ‘sign in by email’ section of the form.'); return 1; @@ -788,7 +795,7 @@ sub process_report : Private { # Extract all the params to a hash to make them easier to work with my %params = # - map { $_ => scalar $c->req->param($_) } # + map { $_ => $c->get_param($_) } ( 'title', 'detail', 'pc', # 'detail_size', 'detail_depth', @@ -851,15 +858,6 @@ sub process_report : Private { $report->extra( \%extra ); } - } elsif ($first_area->{id} != COUNCIL_ID_BROMLEY - && $first_area->{id} != COUNCIL_ID_BARNET - && $first_area->{type} eq 'LBO') { - - unless ( Utils::london_categories()->{ $report->category } ) { - $c->stash->{field_errors}->{category} = _('Please choose a category'); - } - $report->bodies_str( $first_body->id ); - } elsif ( $report->category ) { # FIXME All contacts were fetched in setup_categories_and_bodies, @@ -880,28 +878,34 @@ sub process_report : Private { return 1; } - # construct the bodies string: - # 'x,x' - x are body IDs that have this category - # 'x,x|y' - x are body IDs that have this category, y body IDs with *no* contact - my $body_string = join( ',', map { $_->body_id } @contacts ); - $body_string .= - '|' . join( ',', map { $_->id } @{ $c->stash->{missing_details_bodies} } ) - if $body_string && @{ $c->stash->{missing_details_bodies} }; - $report->bodies_str($body_string); + if ($c->stash->{unresponsive}{$report->category} || $c->stash->{unresponsive}{ALL}) { + # Unresponsive, don't try and send a report. + $report->bodies_str(-1); + } else { + # construct the bodies string: + # 'x,x' - x are body IDs that have this category + # 'x,x|y' - x are body IDs that have this category, y body IDs with *no* contact + my $body_string = join( ',', map { $_->body_id } @contacts ); + $body_string .= + '|' . join( ',', map { $_->id } @{ $c->stash->{missing_details_bodies} } ) + if $body_string && @{ $c->stash->{missing_details_bodies} }; + $report->bodies_str($body_string); + } - my @extra = (); - my $metas = $contacts[0]->extra; + my @extra; + # NB: we are only checking extras for the *first* retrieved contact. + my $metas = $contacts[0]->get_extra_fields(); foreach my $field ( @$metas ) { if ( lc( $field->{required} ) eq 'true' ) { - unless ( $c->request->param( $field->{code} ) ) { + unless ( $c->get_param($field->{code}) ) { $c->stash->{field_errors}->{ $field->{code} } = _('This information is required'); } } push @extra, { name => $field->{code}, description => $field->{description}, - value => $c->request->param( $field->{code} ) || '', + value => $c->get_param($field->{code}) || '', }; } @@ -913,7 +917,7 @@ sub process_report : Private { if ( @extra ) { $c->stash->{report_meta} = { map { $_->{name} => $_ } @extra }; - $report->extra( \@extra ); + $report->set_extra_fields( @extra ); } } elsif ( @{ $c->stash->{bodies_to_list} } ) { @@ -964,7 +968,7 @@ sub check_for_errors : Private { # We only want to validate the phone number web requests (where the # service parameter is blank) because previous versions of the mobile # apps don't validate the presence of a phone number. - if ( ! $c->req->param('phone') and ! $c->req->param('service') ) { + if ( ! $c->get_param('phone') and ! $c->get_param('service') ) { $field_errors{phone} = _("This information is required"); } } @@ -974,7 +978,7 @@ sub check_for_errors : Private { # if they're got the login details wrong when signing in then # we don't care about the name field even though it's validated # by the user object - if ( $c->req->param('submit_sign_in') and $field_errors{password} ) { + if ( $c->get_param('submit_sign_in') and $field_errors{password} ) { delete $field_errors{name}; } @@ -1060,9 +1064,9 @@ sub save_user_and_report : Private { $report->bodies_str( undef ) if $report->bodies_str eq '-1'; # if there is a Message Manager message ID, pass it back to the client view - if ($c->cobrand->moniker eq 'fixmybarangay' && $c->req->param('external_source_id')=~/^\d+$/) { - $c->stash->{external_source_id} = $c->req->param('external_source_id'); - $report->external_source_id( $c->req->param('external_source_id') ); + if ($c->cobrand->moniker eq 'fixmybarangay' && $c->get_param('external_source_id') =~ /^\d+$/) { + $c->stash->{external_source_id} = $c->get_param('external_source_id'); + $report->external_source_id( $c->get_param('external_source_id') ); $report->external_source( $c->config->{MESSAGE_MANAGER_URL} ) ; } @@ -1090,10 +1094,6 @@ sub generate_map : Private { my $latitude = $c->stash->{latitude}; my $longitude = $c->stash->{longitude}; - ( $c->stash->{short_latitude}, $c->stash->{short_longitude} ) = - map { Utils::truncate_coordinate($_) } - ( $c->stash->{latitude}, $c->stash->{longitude} ); - # Don't do anything if the user skipped the map if ( $c->stash->{report}->used_map ) { $c->stash->{page} = 'new'; @@ -1116,7 +1116,7 @@ sub generate_map : Private { sub check_for_category : Private { my ( $self, $c ) = @_; - $c->stash->{category} = $c->req->param('category'); + $c->stash->{category} = $c->get_param('category'); return 1; } @@ -1136,23 +1136,10 @@ sub redirect_or_confirm_creation : Private { if ( $report->confirmed ) { # Subscribe problem reporter to email updates $c->forward( 'create_reporter_alert' ); - my $report_uri; - - if ( $c->cobrand->moniker eq 'fixmybarangay' && $c->user->from_body && $c->stash->{external_source_id}) { - $report_uri = $c->uri_for( '/report', $report->id, undef, { external_source_id => $c->stash->{external_source_id} } ); - } elsif ( $c->cobrand->never_confirm_reports && $report->non_public ) { - $c->log->info( 'cobrand was set to always confirm reports and report was non public, success page showed'); - $c->stash->{template} = 'report_created.html'; - return 1; - } else { - $report_uri = $c->cobrand->base_url_for_report( $report ) . $report->url; - } - $c->log->info($report->user->id . ' was logged in, redirecting to /report/' . $report->id); - if ( $c->sessionid ) { - $c->flash->{created_report} = 'loggedin'; - } - $c->res->redirect($report_uri); - $c->detach; + $c->log->info($report->user->id . ' was logged in, showing confirmation page for ' . $report->id); + $c->stash->{created_report} = 'loggedin'; + $c->stash->{template} = 'tokens/confirm_problem.html'; + return 1; } # otherwise create a confirm token and email it to them. @@ -1199,7 +1186,7 @@ sub redirect_to_around : Private { my ( $self, $c ) = @_; my $params = { - pc => ( $c->stash->{pc} || $c->req->param('pc') || '' ), + pc => ( $c->stash->{pc} || $c->get_param('pc') || '' ), lat => $c->stash->{latitude}, lon => $c->stash->{longitude}, }; diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm index b97420238..17aec2113 100644 --- a/perllib/FixMyStreet/App/Controller/Report/Update.pm +++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm @@ -20,12 +20,12 @@ Creates an update to a report sub report_update : Path : Args(0) { my ( $self, $c ) = @_; - $c->forward( '/report/load_problem_or_display_error', [ $c->req->param('id') ] ); + $c->forward( '/report/load_problem_or_display_error', [ $c->get_param('id') ] ); $c->forward('process_update'); $c->forward('process_user'); $c->forward('/photo/process_photo'); $c->forward('check_for_errors') - or $c->go( '/report/display', [ $c->req->param('id') ] ); + or $c->go( '/report/display', [ $c->get_param('id') ] ); $c->forward('save_update'); $c->forward('redirect_or_confirm_creation'); @@ -76,7 +76,7 @@ sub update_problem : Private { $problem->state('confirmed'); } - if ( $c->cobrand->can_support_problems && $c->user && $c->user->from_body && $c->req->param('external_source_id') ) { + if ( $c->cobrand->can_support_problems && $c->user && $c->user->from_body && $c->get_param('external_source_id') ) { $problem->interest_count( \'interest_count + 1' ); } @@ -106,9 +106,9 @@ sub process_user : Private { if ( $c->user_exists ) { my $user = $c->user->obj; - my $name = scalar $c->req->param('name'); + my $name = $c->get_param('name'); $user->name( Utils::trim_text( $name ) ) if $name; - my $title = scalar $c->req->param('fms_extra_title'); + my $title = $c->get_param('fms_extra_title'); if ( $title ) { $c->log->debug( 'user exists and title is ' . $title ); $user->title( Utils::trim_text( $title ) ); @@ -118,7 +118,7 @@ sub process_user : Private { } # Extract all the params to a hash to make them easier to work with - my %params = map { $_ => scalar $c->req->param($_) } + my %params = map { $_ => $c->get_param($_) } ( 'rznvy', 'name', 'password_register', 'fms_extra_title' ); # cleanup the email address @@ -129,7 +129,7 @@ sub process_user : Private { unless $update->user; # The user is trying to sign in. We only care about email from the params. - if ( $c->req->param('submit_sign_in') || $c->req->param('password_sign_in') ) { + if ( $c->get_param('submit_sign_in') || $c->get_param('password_sign_in') ) { unless ( $c->forward( '/auth/sign_in', [ $email ] ) ) { $c->stash->{field_errors}->{password} = _('There was a problem with your email/password combination. If you cannot remember your password, or do not have one, please fill in the ‘sign in by email’ section of the form.'); return 1; @@ -164,23 +164,23 @@ want to move adding these elsewhere sub process_update : Private { my ( $self, $c ) = @_; - if ( $c->req->param('first_name' ) && $c->req->param('last_name' ) ) { - my $first_name = $c->req->param('first_name'); - my $last_name = $c->req->param('last_name'); - $c->req->param('name', sprintf( '%s %s', $first_name, $last_name ) ); + if ( $c->get_param('first_name') && $c->get_param('last_name') ) { + my $first_name = $c->get_param('first_name'); + my $last_name = $c->get_param('last_name'); + $c->set_param('name', sprintf( '%s %s', $first_name, $last_name )); $c->stash->{first_name} = $first_name; $c->stash->{last_name} = $last_name; } my %params = - map { $_ => scalar $c->req->param($_) } ( 'update', 'name', 'fixed', 'state', 'reopen' ); + map { $_ => $c->get_param($_) } ( 'update', 'name', 'fixed', 'state', 'reopen' ); $params{update} = Utils::cleanup_text( $params{update}, { allow_multiline => 1 } ); my $name = Utils::trim_text( $params{name} ); - my $anonymous = $c->req->param('may_show_name') ? 0 : 1; + my $anonymous = $c->get_param('may_show_name') ? 0 : 1; $params{reopen} = 0 unless $c->user && $c->user->id == $c->stash->{problem}->user->id; @@ -225,10 +225,10 @@ sub process_update : Private { # TODO Use extra here as it is used on reports. $c->cobrand->process_extras( $c, $update->problem->bodies_str, \@extra ); - if ( $c->req->param('fms_extra_title') ) { + if ( $c->get_param('fms_extra_title') ) { my %extras = (); - $extras{title} = $c->req->param('fms_extra_title'); - $extras{email_alerts_requested} = $c->req->param('add_alert'); + $extras{title} = $c->get_param('fms_extra_title'); + $extras{email_alerts_requested} = $c->get_param('add_alert'); $update->extra( \%extras ); } @@ -239,10 +239,10 @@ sub process_update : Private { $update->extra( $extra ); } - $c->log->debug( 'name is ' . $c->req->param('name') ); + $c->log->debug( 'name is ' . $c->get_param('name') ); - $c->stash->{update} = $update; - $c->stash->{add_alert} = $c->req->param('add_alert'); + $c->stash->{update} = $update; + $c->stash->{add_alert} = $c->get_param('add_alert'); return 1; } @@ -259,11 +259,11 @@ sub check_for_errors : Private { my ( $self, $c ) = @_; # they have to be an authority user to update the state - if ( $c->req->param('state') ) { + if ( $c->get_param('state') ) { my $error = 0; $error = 1 unless $c->user && $c->user->belongs_to_body( $c->stash->{update}->problem->bodies_str ); - my $state = $c->req->param('state'); + my $state = $c->get_param('state'); $state = 'fixed - council' if $state eq 'fixed'; $error = 1 unless ( grep { $state eq $_ } ( FixMyStreet::DB::Result::Problem->council_states() ) ); @@ -376,11 +376,8 @@ sub redirect_or_confirm_creation : Private { if ( $update->confirmed ) { $c->forward( 'update_problem' ); $c->forward( 'signup_for_alerts' ); - - my $report_uri = $c->cobrand->base_url_for_report( $update->problem ) . $update->problem->url; - $c->flash->{comment_created} = 1; - $c->res->redirect($report_uri); - $c->detach; + $c->stash->{template} = 'tokens/confirm_update.html'; + return 1; } # otherwise create a confirm token and email it to them. @@ -391,7 +388,7 @@ sub redirect_or_confirm_creation : Private { data => { %$data, id => $update->id, - add_alert => ( $c->req->param('add_alert') ? 1 : 0 ), + add_alert => ( $c->get_param('add_alert') ? 1 : 0 ), } } ); @@ -423,8 +420,8 @@ happen before calling this. sub signup_for_alerts : Private { my ( $self, $c ) = @_; + my $update = $c->stash->{update}; if ( $c->stash->{add_alert} ) { - my $update = $c->stash->{update}; my $options = { user => $update->user, alert_type => 'new_updates', @@ -441,7 +438,7 @@ sub signup_for_alerts : Private { } $alert->confirm(); - } elsif ( $c->user && ( my $alert = $c->user->alert_for_problem($c->stash->{update}->problem_id) ) ) { + } elsif ( my $alert = $update->user->alert_for_problem($update->problem_id) ) { $alert->disable(); } diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index 352c47da8..6b0d516a6 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -109,6 +109,7 @@ sub ward : Path : Args(2) { $c->forward( 'ward_check', [ $ward ] ) if $ward; $c->forward( 'check_canonical_url', [ $body ] ); + $c->forward( 'stash_report_filter_status' ); $c->forward( 'load_and_group_problems' ); my $body_short = $c->cobrand->short_name( $c->stash->{body} ); @@ -120,6 +121,15 @@ sub ward : Path : Args(2) { $c->stash->{stats} = $c->cobrand->get_report_stats(); + my @categories = $c->stash->{body}->contacts->search( undef, { + columns => [ 'category' ], + distinct => 1, + order_by => [ 'category' ], + } )->all; + @categories = map { $_->category } @categories; + $c->stash->{filter_categories} = \@categories; + $c->stash->{filter_category} = $c->get_param('filter_category'); + my $pins = $c->stash->{pins}; $c->stash->{page} = 'reports'; # So the map knows to make clickable pins @@ -373,13 +383,15 @@ sub check_canonical_url : Private { sub load_and_group_problems : Private { my ( $self, $c ) = @_; - my $page = $c->req->params->{p} || 1; - my $type = $c->req->params->{t} || 'all'; - my $category = $c->req->params->{c} || ''; + my $page = $c->get_param('p') || 1; + # NB: If 't' is specified, it will override 'status'. + my $type = $c->get_param('t') || 'all'; + my $category = $c->get_param('c') || $c->get_param('filter_category') || ''; + my $states = $c->stash->{filter_problem_states}; my $where = { non_public => 0, - state => [ FixMyStreet::DB::Result::Problem->visible_states() ] + state => [ keys %$states ] }; my $not_open = [ FixMyStreet::DB::Result::Problem::fixed_states(), FixMyStreet::DB::Result::Problem::closed_states() ]; @@ -430,7 +442,7 @@ sub load_and_group_problems : Private { my $problems = $c->cobrand->problems->search( $where, { - order_by => { -desc => 'lastupdate' }, + order_by => $c->cobrand->reports_ordering, rows => $c->cobrand->reports_per_page, } )->page( $page ); @@ -485,6 +497,26 @@ sub redirect_body : Private { $c->res->redirect( $c->uri_for($url, $c->req->params ) ); } +sub stash_report_filter_status : Private { + my ( $self, $c ) = @_; + + my $status = $c->get_param('status') || $c->cobrand->on_map_default_status; + if ( $status eq 'all' ) { + $c->stash->{filter_status} = 'all'; + $c->stash->{filter_problem_states} = FixMyStreet::DB::Result::Problem->visible_states(); + } elsif ( $status eq 'open' ) { + $c->stash->{filter_status} = 'open'; + $c->stash->{filter_problem_states} = FixMyStreet::DB::Result::Problem->open_states(); + } elsif ( $status eq 'fixed' ) { + $c->stash->{filter_status} = 'fixed'; + $c->stash->{filter_problem_states} = FixMyStreet::DB::Result::Problem->fixed_states(); + } else { + $c->stash->{filter_status} = $c->cobrand->on_map_default_status; + } + + return 1; +} + sub add_row { my ( $c, $problem, $body, $problems, $pins ) = @_; push @{$problems->{$body}}, $problem; diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm index 769a147bf..16f4aa491 100644 --- a/perllib/FixMyStreet/App/Controller/Root.pm +++ b/perllib/FixMyStreet/App/Controller/Root.pm @@ -47,7 +47,7 @@ sub index : Path : Args(0) { my %old_params = (); foreach my $key (@old_param_keys) { - my $val = $c->req->param($key); + my $val = $c->get_param($key); next unless $val; $old_params{$key} = $val; } diff --git a/perllib/FixMyStreet/App/Controller/Rss.pm b/perllib/FixMyStreet/App/Controller/Rss.pm index cbeddce85..7aafc99ff 100755 --- a/perllib/FixMyStreet/App/Controller/Rss.pm +++ b/perllib/FixMyStreet/App/Controller/Rss.pm @@ -350,7 +350,7 @@ sub get_query_parameters : Private { $d = '' unless $d && $d =~ /^\d+$/; $c->stash->{distance} = $d; - my $state = $c->req->param('state') || 'all'; + my $state = $c->get_param('state') || 'all'; $state = 'all' unless $state =~ /^(all|open|fixed)$/; $c->stash->{state_qs} = "?state=$state" unless $state eq 'all'; diff --git a/perllib/FixMyStreet/App/Controller/Static.pm b/perllib/FixMyStreet/App/Controller/Static.pm index 8cd82b68e..d91a07fea 100755 --- a/perllib/FixMyStreet/App/Controller/Static.pm +++ b/perllib/FixMyStreet/App/Controller/Static.pm @@ -61,6 +61,25 @@ sub council : Global : Args(0) { my ( $self, $c ) = @_; } +sub unresponsive : Global : Args(0) { + my ( $self, $c ) = @_; + my $body = $c->stash->{body} = $c->model('DB::Body')->find({ id => $c->get_param('body') }) + or $c->detach( '/page_error_404_not_found' ); + + $c->stash->{category} = $c->get_param('category'); + + # If the whole body isn't set to refused, we need to check the contacts + if (!$body->send_method || $body->send_method ne 'Refused') { + my @contacts = $c->model('DB::Contact')->not_deleted->search( { body_id => $body->id } )->all; + my $any_unresponsive = 0; + foreach my $contact (@contacts) { + $any_unresponsive = 1 if $contact->email =~ /^REFUSED$/i; + } + + $c->detach( '/page_error_404_not_found' ) unless $any_unresponsive; + } +} + __PACKAGE__->meta->make_immutable; 1; diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm index 44cb2429d..21c269502 100644 --- a/perllib/FixMyStreet/App/Controller/Tokens.pm +++ b/perllib/FixMyStreet/App/Controller/Tokens.pm @@ -28,22 +28,32 @@ problem but are not logged in. sub confirm_problem : Path('/P') { my ( $self, $c, $token_code ) = @_; + if ($token_code eq '_test_') { + $c->stash->{report} = { + id => 123, + title => 'Title of Report', + bodies_str => 'True', + url => '/report/123', + }; + return; + } + my $auth_token = $c->forward( 'load_auth_token', [ $token_code, 'problem' ] ); # Load the problem my $data = $auth_token->data; - my $problem_id = ref $data ? $data->{id} : $data; + $data = { id => $data } unless ref $data; + + my $problem_id = $data->{id}; # Look at all problems, not just cobrand, in case am approving something we don't actually show my $problem = $c->model('DB::Problem')->find( { id => $problem_id } ) || $c->detach('token_error'); - $c->stash->{problem} = $problem; + $c->stash->{report} = $problem; - if ( $problem->state eq 'unconfirmed' && $auth_token->created < DateTime->now->subtract( months => 1 ) ) { - $c->stash->{template} = 'errors/generic.html'; - $c->stash->{message} = _("I'm afraid we couldn't validate that token, as the report was made too long ago."); - return; - } + $c->detach('token_too_old') + if $problem->state eq 'unconfirmed' + && $auth_token->created < DateTime->now->subtract( months => 1 ); # check that this email or domain are not the cause of abuse. If so hide it. if ( $problem->is_from_abuser ) { @@ -56,14 +66,12 @@ sub confirm_problem : Path('/P') { # For Zurich, email confirmation simply sets a flag, it does not change the # problem state, log in, or anything else if ($c->cobrand->moniker eq 'zurich') { - my $extra = { %{ $problem->extra || {} } }; - $extra->{email_confirmed} = 1; + $problem->set_extra_metadata( email_confirmed => 1 ); $problem->update( { - extra => $extra, confirmed => \'ms_current_timestamp()', } ); - if ( ref($data) && ( $data->{name} || $data->{password} ) ) { + if ( $data->{name} || $data->{password} ) { $problem->user->name( $data->{name} ) if $data->{name}; $problem->user->phone( $data->{phone} ) if $data->{phone}; $problem->user->update; @@ -72,22 +80,26 @@ sub confirm_problem : Path('/P') { return 1; } - # We have a problem - confirm it if needed! - my $old_state = $problem->state; + if ($problem->state ne 'unconfirmed') { + my $report_uri = $c->cobrand->base_url_for_report( $problem ) . $problem->url; + $c->res->redirect($report_uri); + return; + } + + # We have an unconfirmed problem $problem->update( { state => 'confirmed', confirmed => \'ms_current_timestamp()', lastupdate => \'ms_current_timestamp()', } - ) if $problem->state eq 'unconfirmed'; + ); # Subscribe problem reporter to email updates - $c->stash->{report} = $c->stash->{problem}; $c->forward( '/report/new/create_reporter_alert' ); # log the problem creation user in to the site - if ( ref($data) && ( $data->{name} || $data->{password} ) ) { + if ( $data->{name} || $data->{password} ) { $problem->user->name( $data->{name} ) if $data->{name}; $problem->user->phone( $data->{phone} ) if $data->{phone}; $problem->user->password( $data->{password}, 1 ) if $data->{password}; @@ -97,11 +109,6 @@ sub confirm_problem : Path('/P') { $c->authenticate( { email => $problem->user->email }, 'no_password' ); $c->set_session_cookie_expire(0); - if ( FixMyStreet::DB::Result::Problem->visible_states()->{$old_state} ) { - my $report_uri = $c->cobrand->base_url_for_report( $problem ) . $problem->url; - $c->res->redirect($report_uri); - } - $c->stash->{created_report} = 'fromemail'; return 1; } @@ -135,23 +142,34 @@ alert but are not logged in. sub confirm_alert : Path('/A') { my ( $self, $c, $token_code ) = @_; + if ($token_code eq '_test_') { + $c->stash->{confirm_type} = $c->get_param('confirm_type'); + return; + } + my $auth_token = $c->forward( 'load_auth_token', [ $token_code, 'alert' ] ); - # Load the problem + # Load the alert my $alert_id = $auth_token->data->{id}; $c->stash->{confirm_type} = $auth_token->data->{type}; my $alert = $c->model('DB::Alert')->find( { id => $alert_id } ) || $c->detach('token_error'); $c->stash->{alert} = $alert; + $c->detach('token_too_old') + if $c->stash->{confirm_type} ne 'unsubscribe' + && $auth_token->created < DateTime->now->subtract( months => 1 ); + # check that this email or domain are not the cause of abuse. If so hide it. if ( $alert->is_from_abuser ) { $c->stash->{template} = 'tokens/abuse.html'; return; } - $c->authenticate( { email => $alert->user->email }, 'no_password' ); - $c->set_session_cookie_expire(0); + if (!$alert->confirmed && $c->stash->{confirm_type} ne 'unsubscribe') { + $c->authenticate( { email => $alert->user->email }, 'no_password' ); + $c->set_session_cookie_expire(0); + } $c->forward('/alert/confirm'); @@ -170,10 +188,20 @@ update but are not logged in. sub confirm_update : Path('/C') { my ( $self, $c, $token_code ) = @_; + if ($token_code eq '_test_') { + $c->stash->{problem} = { + id => 123, + title => 'Title of Report', + bodies_str => 'True', + url => '/report/123', + }; + return; + } + my $auth_token = $c->forward( 'load_auth_token', [ $token_code, 'comment' ] ); - # Load the problem + # Load the update my $data = $auth_token->data; my $comment_id = $data->{id}; $c->stash->{add_alert} = $data->{add_alert}; @@ -182,26 +210,32 @@ sub confirm_update : Path('/C') { || $c->detach('token_error'); $c->stash->{update} = $comment; + $c->detach('token_too_old') + if $comment->state ne 'confirmed' + && $auth_token->created < DateTime->now->subtract( months => 1 ); + # check that this email or domain are not the cause of abuse. If so hide it. if ( $comment->is_from_abuser ) { $c->stash->{template} = 'tokens/abuse.html'; return; } + if ( $comment->state ne 'unconfirmed' ) { + my $report_uri = $c->cobrand->base_url_for_report( $comment->problem ) . $comment->problem->url; + $c->res->redirect($report_uri); + return; + } + if ( $data->{name} || $data->{password} ) { $comment->user->name( $data->{name} ) if $data->{name}; $comment->user->password( $data->{password}, 1 ) if $data->{password}; $comment->user->update; } + $c->authenticate( { email => $comment->user->email }, 'no_password' ); $c->set_session_cookie_expire(0); - if ( $comment->confirmed ) { - my $report_uri = $c->cobrand->base_url_for_report( $comment->problem ) . $comment->problem->url; - $c->res->redirect($report_uri); - } else { - $c->forward('/report/update/confirm'); - } + $c->forward('/report/update/confirm'); return 1; } @@ -212,6 +246,7 @@ sub load_questionnaire : Private { my $auth_token = $c->forward( 'load_auth_token', [ $token_code, 'questionnaire' ] ); $c->stash->{id} = $auth_token->data; $c->stash->{token} = $token_code; + $c->stash->{token_obj} = $auth_token; my $questionnaire = $c->model('DB::Questionnaire')->find( { id => $c->stash->{id} }, @@ -225,11 +260,43 @@ sub questionnaire : Path('/Q') : Args(1) { my ( $self, $c, $token_code ) = @_; $c->forward( 'load_questionnaire', [ $token_code ] ); - $c->authenticate( { email => $c->stash->{questionnaire}->problem->user->email }, 'no_password' ); - $c->set_session_cookie_expire(0); + $c->detach('token_too_old') if $c->stash->{token_obj}->created < DateTime->now->subtract( months => 1 ); + + my $questionnaire = $c->stash->{questionnaire}; + if (!$questionnaire->whenanswered) { + $c->authenticate( { email => $questionnaire->problem->user->email }, 'no_password' ); + $c->set_session_cookie_expire(0); + } $c->forward( '/questionnaire/show' ); } +=head2 alert_to_reporter + + /R/([0-9A-Za-z]{16,18}).*$ + +A link in an update alert to a problem reporter - show the "reopen report" +tickbox but don't log the person in. + +=cut + +sub alert_to_reporter : Path('/R') { + my ( $self, $c, $token_code ) = @_; + + my $auth_token = + $c->forward( 'load_auth_token', [ $token_code, 'alert_to_reporter' ] ); + my $data = $auth_token->data; + + my $problem_id = $data->{id}; + my $problem = $c->model('DB::Problem')->find( { id => $problem_id } ) + || $c->detach('token_error'); + + $c->detach('token_too_old') if $auth_token->created < DateTime->now->subtract( months => 1 ); + + $c->flash->{alert_to_reporter} = 1; + my $report_uri = $c->cobrand->base_url_for_report( $problem ) . $problem->url; + $c->res->redirect($report_uri); +} + =head2 load_auth_token my $auth_token = @@ -276,6 +343,12 @@ sub token_error : Private { $c->stash->{template} = 'tokens/error.html'; } +sub token_too_old : Private { + my ( $self, $c ) = @_; + $c->stash->{token_not_found} = 1; + $c->stash->{template} = 'auth/token.html'; +} + __PACKAGE__->meta->make_immutable; 1; diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm index 033ad583f..da549ece8 100644 --- a/perllib/FixMyStreet/App/View/Web.pm +++ b/perllib/FixMyStreet/App/View/Web.pm @@ -7,7 +7,6 @@ use warnings; use mySociety::Locale; use mySociety::Web qw(ent); use FixMyStreet; -use CrossSell; use Utils; __PACKAGE__->config( @@ -18,7 +17,7 @@ __PACKAGE__->config( ENCODING => 'utf8', render_die => 1, expose_methods => [ - 'loc', 'nget', 'tprintf', 'display_crosssell_advert', 'prettify_dt', + 'loc', 'nget', 'tprintf', 'prettify_dt', 'add_links', 'version', 'decode', ], FILTERS => { @@ -79,19 +78,6 @@ sub tprintf { return sprintf $format, @args; } -=head2 display_crosssell_advert - - [% display_crosssell_advert( email, name ) %] - -Displays a crosssell advert (will be fixmystreet cobrand only). - -=cut - -sub display_crosssell_advert { - my ( $self, $c, $email, $name, %data ) = @_; - return CrossSell::display_advert( $c, $email, $name, %data ); -} - =head2 Utils::prettify_dt [% pretty = prettify_dt( $dt, $short_bool ) %] diff --git a/perllib/FixMyStreet/Cobrand/ArreglaMiBarrio.pm b/perllib/FixMyStreet/Cobrand/ArreglaMiBarrio.pm new file mode 100644 index 000000000..cc393f42e --- /dev/null +++ b/perllib/FixMyStreet/Cobrand/ArreglaMiBarrio.pm @@ -0,0 +1,10 @@ +package FixMyStreet::Cobrand::ArreglaMiBarrio; +use base 'FixMyStreet::Cobrand::Default'; + +use utf8; +use strict; +use warnings; + +sub language_override { 'es' } + +1; diff --git a/perllib/FixMyStreet/Cobrand/Base.pm b/perllib/FixMyStreet/Cobrand/Base.pm index 4941712b2..5a9842233 100644 --- a/perllib/FixMyStreet/Cobrand/Base.pm +++ b/perllib/FixMyStreet/Cobrand/Base.pm @@ -51,5 +51,8 @@ sub is_default { return $self->moniker eq 'default'; } +# NB: this Base class is for 'meta' features. To add base methods for all cobrands, +# you may want to look at FMS::Cobrand::Default instead! + 1; diff --git a/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm b/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm index df4d428e8..58bc6973d 100644 --- a/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm +++ b/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm @@ -12,7 +12,7 @@ sub example_places { return ( 'Dominica, Recoleta', 'Pio Nono' ); } -sub languages { [ 'es-cl,Castellano,es_CL', 'en-gb,English,en_GB' ] } +sub languages { [ 'es-cl,Castellano,es_CL' ] } sub disambiguate_location { return { diff --git a/perllib/FixMyStreet/Cobrand/Bromley.pm b/perllib/FixMyStreet/Cobrand/Bromley.pm index 99b38ca6a..9bee45128 100644 --- a/perllib/FixMyStreet/Cobrand/Bromley.pm +++ b/perllib/FixMyStreet/Cobrand/Bromley.pm @@ -20,14 +20,14 @@ sub disambiguate_location { my $town = 'Bromley'; - # Bing turns High St Bromley into Bromley High St which is in + # Bing turns High St Bromley into Bromley High St which is in # Bromley by Bow. $town .= ', BR1' if $string =~ /^high\s+st(reet)?$/i; # Disambiguations required for BR5 $town .= ', BR5' if $string =~ /^kelsey\s+r(?:oa)?d$/i; $town = 'BR5 Bromley' if $string =~ /^leith\s+hill$/i; # doesn't like appended BR5 for some reason - + # There has also been a road name change for a section of Ramsden Road # (BR5) between Church Hill and Court Road has changed to 'Old Priory # Avenue' - presently entering Old Priory Avenue simply takes the user to @@ -42,10 +42,14 @@ sub disambiguate_location { # and BR6 $town .= ', BR6' if $string =~ /^berrylands/i; - # White Horse Hill is on boundary with Greenwich, so need a + # White Horse Hill is on boundary with Greenwich, so need a # specific postcode $town = 'chislehurst, BR7 6DH' if $string =~ /^white\s+horse/i; + # Mottingham Lane is 90% inside Bromley, but goes outside too and Bing + # defaults to the top end of it. + $town = 'Mottingham Lane, SE9 4RW' if $string =~ /^mottingham\s+lane/i; + $town = '' if $string =~ /orpington/i; return { diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index 7f1fba67a..c3185ea05 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -7,6 +7,7 @@ use FixMyStreet; use FixMyStreet::Geocode::Bing; use DateTime; use Encode; +use List::MoreUtils 'none'; use URI; use Digest::MD5 qw(md5_hex); @@ -157,7 +158,9 @@ Set the language and domain of the site based on the cobrand and host. sub set_lang_and_domain { my ( $self, $lang, $unicode, $dir ) = @_; - my $languages = join('|', @{$self->languages}); + my @languages = @{$self->languages}; + push @languages, 'en-gb,English,en_GB' if none { /en-gb/ } @languages; + my $languages = join('|', @languages); my $lang_override = $self->language_override || $lang; my $lang_domain = $self->language_domain || 'FixMyStreet'; @@ -174,7 +177,7 @@ sub set_lang_and_domain { return $set_lang; } -sub languages { FixMyStreet->config('LANGUAGES') || [ 'en-gb,English,en_GB' ] } +sub languages { FixMyStreet->config('LANGUAGES') || [] } sub language_domain { } sub language_override { } @@ -337,6 +340,16 @@ sub reports_per_page { return FixMyStreet->config('ALL_REPORTS_PER_PAGE') || 100; } +=head2 reports_ordering + +The order_by clause to use for reports on all reports page + +=cut + +sub reports_ordering { + return { -desc => 'lastupdate' }; +} + =head2 on_map_list_limit Return the maximum number of items to be given in the list of reports on the map @@ -353,6 +366,14 @@ Return the default maximum age for pins. sub on_map_default_max_pin_age { return '6 months'; } +=head2 on_map_default_status + +Return the default ?status= query parameter to use for filter on map page. + +=cut + +sub on_map_default_status { return 'all'; } + =head2 allow_photo_upload Return a boolean indicating whether the cobrand allows photo uploads @@ -895,5 +916,9 @@ sub get_country_for_ip_address { return 0; } -1; +sub jurisdiction_id_example { + my $self = shift; + return $self->moniker; +} +1; diff --git a/perllib/FixMyStreet/Cobrand/EmptyHomes.pm b/perllib/FixMyStreet/Cobrand/EmptyHomes.pm index b87a1cf24..0b02f90c4 100644 --- a/perllib/FixMyStreet/Cobrand/EmptyHomes.pm +++ b/perllib/FixMyStreet/Cobrand/EmptyHomes.pm @@ -13,6 +13,12 @@ sub path_to_web_templates { return [ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify ]; } +sub _fallback_body_sender { + my ( $self, $body, $category ) = @_; + + return { method => 'EmptyHomes' }; +}; + =item Return the base url for this cobranded site @@ -132,7 +138,7 @@ sub process_extras { my $body_id = shift; my $extra = shift; - my $value = $ctx->request->params->{address} || ''; + my $value = $ctx->get_param('address') || ''; $ctx->stash->{field_errors}->{address} = _('This information is required') unless $value; $extra->{address} = $value; diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm index 822a0c43b..7b175f371 100644 --- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm +++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm @@ -12,7 +12,7 @@ sub country { return 'NO'; } -sub languages { [ 'en-gb,English,en_GB', 'nb,Norwegian,nb_NO' ] } +sub languages { [ 'nb,Norwegian,nb_NO' ] } sub language_override { 'nb' } sub enter_postcode_text { @@ -223,4 +223,8 @@ sub reports_body_check { } } +sub jurisdiction_id_example { + 'fiksgatami.no'; +} + 1; diff --git a/perllib/FixMyStreet/Cobrand/FixMindelo.pm b/perllib/FixMyStreet/Cobrand/FixMindelo.pm index 59debf157..60f69d589 100644 --- a/perllib/FixMyStreet/Cobrand/FixMindelo.pm +++ b/perllib/FixMyStreet/Cobrand/FixMindelo.pm @@ -8,7 +8,7 @@ sub country { return 'CV'; } -sub languages { [ 'pt-cv,Portuguese,pt_CV', 'en-gb,English,en_GB' ] } +sub languages { [ 'pt-cv,Portuguese,pt_CV' ] } sub language_override { 'pt-cv' } sub disambiguate_location { diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm index 9001ca5f7..f21d38ff8 100644 --- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm +++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm @@ -40,12 +40,12 @@ sub extra_contact_validation { my %errors; - $c->stash->{dest} = $c->req->param('dest'); + $c->stash->{dest} = $c->get_param('dest'); $errors{dest} = "Please enter who your message is for" - unless $c->req->param('dest'); + unless $c->get_param('dest'); - if ( $c->req->param('dest') eq 'council' || $c->req->param('dest') eq 'update' ) { + if ( $c->get_param('dest') eq 'council' || $c->get_param('dest') eq 'update' ) { $errors{not_for_us} = 1; } diff --git a/perllib/FixMyStreet/Cobrand/FixaMinGata.pm b/perllib/FixMyStreet/Cobrand/FixaMinGata.pm index 60f98dd47..e6e54926f 100644 --- a/perllib/FixMyStreet/Cobrand/FixaMinGata.pm +++ b/perllib/FixMyStreet/Cobrand/FixaMinGata.pm @@ -13,7 +13,7 @@ sub country { return 'SE'; } -sub languages { [ 'en-gb,English,en_GB', 'sv,Swedish,sv_SE' ] } +sub languages { [ 'sv,Swedish,sv_SE' ] } sub language_override { 'sv' } sub enter_postcode_text { @@ -121,119 +121,13 @@ sub filter_all_council_ids_list { return @all_councils_ids; # Är detta rätt? //Rikard } -# Vad ska vi göra för svenska förhÃ¥llanden här??? //Rikard -sub council_rss_alert_options { - my $self = shift; - my $all_councils = shift; - my $c = shift; - - my ( @options, @reported_to_options, $fylke, $kommune ); - - foreach ( values %$all_councils ) { - if ( $_->{type} eq 'NKO' ) { - $kommune = $_; - } - else { - $fylke = $_; - } - } - - if ( $fylke->{id} == 3 ) { # Oslo - my $short_name = $self->short_name($fylke, $all_councils); - ( my $id_name = $short_name ) =~ tr/+/_/; - - push @options, - { - type => 'council', - id => sprintf( 'council:%s:%s', $fylke->{id}, $id_name ), - rss_text => - sprintf( _('RSS feed of problems within %s'), $fylke->{name} ), - text => sprintf( _('Problems within %s'), $fylke->{name} ), - uri => $c->uri_for( '/rss/reports', $short_name ), - }; - } - else { - my $short_kommune_name = $self->short_name($kommune, $all_councils); - ( my $id_kommune_name = $short_kommune_name ) =~ tr/+/_/; - - my $short_fylke_name = $self->short_name($fylke, $all_councils); - ( my $id_fylke_name = $short_fylke_name ) =~ tr/+/_/; - - push @options, - { - type => 'area', - id => sprintf( 'area:%s:%s', $kommune->{id}, $id_kommune_name ), - rss_text => - sprintf( _('RSS feed of %s'), $kommune->{name} ), - text => $kommune->{name}, - uri => $c->uri_for( '/rss/area', $short_kommune_name ), - }, - { - type => 'area', - id => sprintf( 'area:%s:%s', $fylke->{id}, $id_fylke_name ), - rss_text => - sprintf( _('RSS feed of %s'), $fylke->{name} ), - text => $fylke->{name}, - uri => $c->uri_for( '/rss/area', $short_fylke_name ), - }; - - push @reported_to_options, - { - type => 'council', - id => sprintf( 'council:%s:%s', $kommune->{id}, $id_kommune_name ), - rss_text => - sprintf( _('RSS feed of %s'), $kommune->{name} ), - text => $kommune->{name}, - uri => $c->uri_for( '/rss/reports', $short_kommune_name ), - }, - { - type => 'council', - id => sprintf( 'council:%s:%s', $fylke->{id}, $id_fylke_name ), - rss_text => - sprintf( _('RSS feed of %s'), $fylke->{name} ), - text => $fylke->{name}, - uri => $c->uri_for( '/rss/reports/', $short_fylke_name ), - }; - } - - return ( - \@options, @reported_to_options - ? \@reported_to_options - : undef - ); - -} - -# Vad ska vi göra för svenska förhÃ¥llanden här??? //Rikard -sub reports_council_check { - my ( $self, $c, $council ) = @_; - - if ($council eq 'Oslo') { - - # There are two Oslos (kommune and fylke), we only want one of them. - $c->stash->{council} = mySociety::MaPit::call('area', 3); - return 1; - - } elsif ($council =~ /,/) { - - # Some kommunes have the same name, use the fylke name to work out which. - my ($kommune, $fylke) = split /\s*,\s*/, $council; - my $area_types = $c->cobrand->area_types; - my $areas_k = mySociety::MaPit::call('areas', $kommune, type => $area_types); - my $areas_f = mySociety::MaPit::call('areas', $fylke, type => $area_types); - if (keys %$areas_f == 1) { - ($fylke) = values %$areas_f; - foreach (values %$areas_k) { - if ($_->{name} eq $kommune && $_->{parent_area} == $fylke->{id}) { - $c->stash->{council} = $_; - return 1; - } - } - } - # If we're here, we've been given a bad name. - $c->detach( 'redirect_index' ); - - } +# The pin is green is it's fixed, yellow if it's closed (but not fixed), and +# red otherwise. +sub pin_colour { + my ( $self, $p, $context ) = @_; + return 'green' if $p->is_fixed; + return 'yellow' if $p->is_closed; + return 'red'; } 1; diff --git a/perllib/FixMyStreet/Cobrand/Greenwich.pm b/perllib/FixMyStreet/Cobrand/Greenwich.pm new file mode 100644 index 000000000..18b0c2f5e --- /dev/null +++ b/perllib/FixMyStreet/Cobrand/Greenwich.pm @@ -0,0 +1,47 @@ +package FixMyStreet::Cobrand::Greenwich; +use parent 'FixMyStreet::Cobrand::UKCouncils'; + +use strict; +use warnings; + +sub council_id { return 2493; } +sub council_area { return 'Greenwich'; } +sub council_name { return 'Royal Borough of Greenwich'; } +sub council_url { return 'greenwich'; } + +sub example_places { + return ( 'SE18 6HQ', "Woolwich Road" ); +} + +sub enter_postcode_text { + my ($self) = @_; + return 'Enter a Royal Greenwich postcode, or street name and area'; +} + +sub disambiguate_location { + my $self = shift; + my $string = shift; + + my $town = 'Greenwich'; + + # as it's the requested example location, try to avoid a disambiguation page + $town .= ', SE10 0EF' if $string =~ /^\s*woolwich\s+r(?:oa)?d\s*(?:,\s*green\w+\s*)?$/i; + + return { + %{ $self->SUPER::disambiguate_location() }, + town => $town, + centre => '51.4743770385684,0.0555696523982184', + span => '0.089851200483885,0.150572372434415', + bounds => [ 51.423679096602, -0.0263872255863898, 51.5135302970859, 0.124185146848025 ], + }; +} + +sub pin_colour { + my ( $self, $p, $context ) = @_; + return 'grey' if $p->state eq 'not responsible'; + return 'green' if $p->is_fixed || $p->is_closed; + return 'red' if $p->state eq 'confirmed'; + return 'yellow'; +} + +1; diff --git a/perllib/FixMyStreet/Cobrand/Harrogate.pm b/perllib/FixMyStreet/Cobrand/Harrogate.pm index 6bcc2f227..afda52385 100644 --- a/perllib/FixMyStreet/Cobrand/Harrogate.pm +++ b/perllib/FixMyStreet/Cobrand/Harrogate.pm @@ -112,7 +112,9 @@ sub temp_update_contacts { } $contact->update({ - extra => [ { %default, %$field } ], + # XXX: we're just setting extra with the expected layout, + # this could be encapsulated more nicely + extra => { _fields => [ { %default, %$field } ] }, confirmed => 1, deleted => 0, editor => 'automated script', @@ -223,7 +225,7 @@ sub process_additional_metadata_for_email { my ($self, $problem, $h) = @_; my $additional = ''; - if (my $extra = $problem->extra) { + if (my $extra = $problem->get_extra_fields) { $additional = join "\n\n", map { if ($_->{name} eq 'INFO_TEXT') { (); @@ -238,5 +240,45 @@ sub process_additional_metadata_for_email { $h->{additional_information} = $additional; } +sub send_questionnaires { + return 0; +} + +sub munge_category_list { + my ($self, $categories_ref, $contacts_ref, $extras_ref) = @_; + + # we want to know which contacts *only* belong to NYCC + # that's because for shared responsibility, we don't expect + # the user to have to figure out which authority to contact. + + # so we start building up the list of both + my (%harrogate_contacts, %nycc_contacts); + + my $harrogate_id = $self->council_id; # XXX: note reference to council_id as body id! + for my $contact (@$contacts_ref) { + my $category = $contact->category; + if ($contact->body_id == $harrogate_id) { + $harrogate_contacts{$category} = 1; + } + else { + $nycc_contacts{$category}++; + } + } + + # and then remove any that also have Harrogate involvement + delete $nycc_contacts{$_} for keys %harrogate_contacts; + + # here, we simply *mark* the text with (NYCC) at the end, and + # the rest will get done in the template with javascript + my @categories = map { + $nycc_contacts{$_} ? + "$_ (NYCC)" + : $_ + } @$categories_ref; + + # replace the entire list with this transformed one + @$categories_ref = @categories; +} + 1; diff --git a/perllib/FixMyStreet/Cobrand/MakeMyIsland.pm b/perllib/FixMyStreet/Cobrand/MakeMyIsland.pm deleted file mode 100644 index f263df4cc..000000000 --- a/perllib/FixMyStreet/Cobrand/MakeMyIsland.pm +++ /dev/null @@ -1,12 +0,0 @@ -package FixMyStreet::Cobrand::MakeMyIsland; -use base 'FixMyStreet::Cobrand::Default'; - -use strict; -use warnings; - -sub country { - return 'MV'; -} - -1; - diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm index 44b3a0fa9..b9d48a95c 100644 --- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm +++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm @@ -47,5 +47,60 @@ sub users_can_hide { return 1; } sub default_show_name { 0 } -1; +=head2 problem_response_days + +Returns the number of working days that are expected to elapse +between the problem being reported and it being responded to by +the council/body. + +=cut + +sub problem_response_days { + my $self = shift; + my $p = shift; + + return 10 if $p->category eq 'Bridges'; + return 10 if $p->category eq 'Carriageway Defect'; # phone if urgent + return 10 if $p->category eq 'Debris/Spillage'; + return 10 if $p->category eq 'Drainage'; + return 10 if $p->category eq 'Fences'; + return 10 if $p->category eq 'Flyposting'; + return 10 if $p->category eq 'Footpaths/ Rights of way (usually not tarmac)'; + return 10 if $p->category eq 'Gully and Catchpits'; + return 10 if $p->category eq 'Ice/Snow'; # phone if urgent + return 10 if $p->category eq 'Manhole'; + return 10 if $p->category eq 'Mud and Debris'; # phone if urgent + return 10 if $p->category eq 'Oil Spillage'; # phone if urgent + return 10 if $p->category eq 'Pavements'; + return 10 if $p->category eq 'Pothole'; # phone if urgent + return 10 if $p->category eq 'Property Damage'; + return 10 if $p->category eq 'Public rights of way'; + return 10 if $p->category eq 'Road Marking'; + return 10 if $p->category eq 'Road traffic signs'; + return 10 if $p->category eq 'Roads/highways'; + return 10 if $p->category eq 'Skips and scaffolding'; + return 10 if $p->category eq 'Street lighting'; + return 10 if $p->category eq 'Traffic lights'; # phone if urgent + return 10 if $p->category eq 'Traffic'; + return 10 if $p->category eq 'Trees'; + return 10 if $p->category eq 'Utilities'; + return 10 if $p->category eq 'Vegetation'; + + return undef; +} +sub reports_ordering { + return { -desc => 'confirmed' }; +} + +sub pin_colour { + my ( $self, $p, $context ) = @_; + return 'grey' if $p->state eq 'not responsible'; + return 'green' if $p->is_fixed || $p->is_closed; + return 'red' if $p->state eq 'confirmed'; + return 'yellow'; +} + +sub on_map_default_status { return 'open'; } + +1; diff --git a/perllib/FixMyStreet/Cobrand/SeeSomething.pm b/perllib/FixMyStreet/Cobrand/SeeSomething.pm index 775ba770b..75f1c32e8 100644 --- a/perllib/FixMyStreet/Cobrand/SeeSomething.pm +++ b/perllib/FixMyStreet/Cobrand/SeeSomething.pm @@ -99,22 +99,22 @@ sub admin_stats { $c->detach( '/page_error_404_not_found' ); } - if ( $c->req->param('category') ) { - $filters{category} = $c->req->param('category'); - $c->stash->{category} = $c->req->param('category'); + if ( $c->get_param('category') ) { + $filters{category} = $c->get_param('category'); + $c->stash->{category} = $c->get_param('category'); } - if ( $c->req->param('subcategory') ) { - $filters{subcategory} = $c->req->param('subcategory'); - $c->stash->{subcategory} = $c->req->param('subcategory'); + if ( $c->get_param('subcategory') ) { + $filters{subcategory} = $c->get_param('subcategory'); + $c->stash->{subcategory} = $c->get_param('subcategory'); } - if ( $c->req->param('service') ) { - $filters{service} = { -ilike => $c->req->param('service') }; - $c->stash->{service} = $c->req->param('service'); + if ( $c->get_param('service') ) { + $filters{service} = { -ilike => $c->get_param('service') }; + $c->stash->{service} = $c->get_param('service'); } - my $page = $c->req->params->{p} || 1; + my $page = $c->get_param('p') || 1; my $p = $c->model('DB::Problem')->search( { diff --git a/perllib/FixMyStreet/Cobrand/UK.pm b/perllib/FixMyStreet/Cobrand/UK.pm index 786b6038c..2473f386f 100644 --- a/perllib/FixMyStreet/Cobrand/UK.pm +++ b/perllib/FixMyStreet/Cobrand/UK.pm @@ -26,16 +26,6 @@ sub disambiguate_location { }; } -sub _fallback_body_sender { - my ( $self, $body, $category ) = @_; - - my $first_area = $body->body_areas->first->area_id; - my $area_info = mySociety::MaPit::call('area', $first_area); - return { method => 'London' } if $area_info->{type} eq 'LBO'; - return { method => 'NI' } if $area_info->{type} eq 'LGD'; - return { method => 'Email' }; -} - sub process_extras { my $self = shift; my $ctx = shift; @@ -47,7 +37,7 @@ sub process_extras { if ( $body_id eq '2482' ) { my @fields = ( 'fms_extra_title', @$fields ); for my $field ( @fields ) { - my $value = $ctx->request->param( $field ); + my $value = $ctx->get_param($field); if ( !$value ) { $ctx->stash->{field_errors}->{ $field } = _('This information is required'); @@ -59,8 +49,8 @@ sub process_extras { }; } - if ( $ctx->request->param('fms_extra_title') ) { - $ctx->stash->{fms_extra_title} = $ctx->request->param('fms_extra_title'); + if ( $ctx->get_param('fms_extra_title') ) { + $ctx->stash->{fms_extra_title} = $ctx->get_param('fms_extra_title'); $ctx->stash->{extra_name_info} = 1; } } @@ -312,5 +302,38 @@ sub council_rss_alert_options { return ( \@options, @reported_to_options ? \@reported_to_options : undef ); } +sub report_check_for_errors { + my $self = shift; + my $c = shift; + + my %errors = $self->next::method($c); + + my $report = $c->stash->{report}; + + if (!$errors{name} && (length($report->name) < 5 + || $report->name !~ m/\s/ + || $report->name =~ m/\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i)) + { + $errors{name} = _( +'Please enter your full name, councils need this information – if you do not wish your name to be shown on the site, untick the box below' + ); + } + + # XXX Hardcoded body ID matching mapit area ID + if ( $report->bodies_str && $report->detail ) { + # Custom character limit: + # Bromley Council + if ( $report->bodies_str eq '2482' && length($report->detail) > 1750 ) { + $errors{detail} = sprintf( _('Reports are limited to %s characters in length. Please shorten your report'), 1750 ); + } + # Oxfordshire + if ( $report->bodies_str eq '2237' && length($report->detail) > 1700 ) { + $errors{detail} = sprintf( _('Reports are limited to %s characters in length. Please shorten your report'), 1700 ); + } + } + + return %errors; +} + 1; diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm index 65930a092..e653ae522 100644 --- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm +++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm @@ -85,11 +85,11 @@ sub area_check { } else { $url .= 'around'; } - $url .= '?pc=' . URI::Escape::uri_escape( $self->{c}->req->param('pc') ) - if $self->{c}->req->param('pc'); - $url .= '?latitude=' . URI::Escape::uri_escape( $self->{c}->req->param('latitude') ) - . '&longitude=' . URI::Escape::uri_escape( $self->{c}->req->param('longitude') ) - if $self->{c}->req->param('latitude'); + $url .= '?pc=' . URI::Escape::uri_escape( $self->{c}->get_param('pc') ) + if $self->{c}->get_param('pc'); + $url .= '?latitude=' . URI::Escape::uri_escape( $self->{c}->get_param('latitude') ) + . '&longitude=' . URI::Escape::uri_escape( $self->{c}->get_param('longitude') ) + if $self->{c}->get_param('latitude'); my $error_msg = "That location is not covered by " . $self->council_name . ". Please visit <a href=\"$url\">the main FixMyStreet site</a>."; return ( 0, $error_msg ); diff --git a/perllib/FixMyStreet/Cobrand/ZeroTB.pm b/perllib/FixMyStreet/Cobrand/ZeroTB.pm index cdf4e5ad4..ef1b0b1e1 100644 --- a/perllib/FixMyStreet/Cobrand/ZeroTB.pm +++ b/perllib/FixMyStreet/Cobrand/ZeroTB.pm @@ -10,9 +10,6 @@ sub country { return 'IN'; } -sub languages { [ 'en-gb,English,en_GB' ] } -sub language_override { 'en-gb' } - sub disambiguate_location { return { country => 'in', diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 577da9dd5..c64fe1177 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -4,6 +4,7 @@ use base 'FixMyStreet::Cobrand::Default'; use DateTime; use POSIX qw(strcoll); use RABX; +use Scalar::Util 'blessed'; use strict; use warnings; @@ -76,7 +77,7 @@ sub example_places { return [ 'Langstrasse', 'Basteiplatz' ]; } -sub languages { [ 'de-ch,Deutsch,de_CH', 'en-gb,English,en_GB' ] } +sub languages { [ 'de-ch,Deutsch,de_CH' ] } sub language_override { 'de-ch' } # If lat/lon are in the URI, we must have zoom as well, otherwise OpenLayers defaults to 0. @@ -158,7 +159,8 @@ sub updates_as_hashref { $hashref->{update_pp} = $self->prettify_dt( $problem->lastupdate ); if ( $problem->state eq 'fixed - council' ) { - $hashref->{details} = FixMyStreet::App::View::Web->add_links( $ctx, $problem->extra ? $problem->extra->{public_response} : '' ); + $hashref->{details} = FixMyStreet::App::View::Web->add_links( + $ctx, $problem->get_extra_metadata('public_response') || '' ); } elsif ( $problem->state eq 'closed' ) { $hashref->{details} = sprintf( _('Assigned to %s'), $problem->body($ctx)->name ); } @@ -169,13 +171,16 @@ sub updates_as_hashref { sub allow_photo_display { my ( $self, $r ) = @_; - if (ref($r) ne 'HASH') { - return $r->extra && $r->extra->{publish_photo}; + if (blessed $r) { + return $r->get_extra_metadata( 'publish_photo' ); } + + # additional munging in case $r isn't an object, TODO see if we can remove this my $extra = $r->{extra}; utf8::encode($extra) if utf8::is_utf8($extra); my $h = new IO::String($extra); $extra = RABX::wire_rd($h); + return unless ref $extra eq 'HASH'; return $extra->{publish_photo}; } @@ -264,10 +269,9 @@ sub get_or_check_overdue { my ($self, $problem) = @_; # use the cached version is it exists (e.g. when called from template) - my $extra = $problem->extra; - if (exists $extra->{closed_overdue} and defined $extra->{closed_overdue}) { - return $extra->{closed_overdue} - } + my $overdue = $problem->get_extra_metadata('closed_overdue'); + return $overdue if defined $overdue; + return $self->overdue($problem); } @@ -338,8 +342,8 @@ sub admin { my @children = map { $_->id } $body->bodies->all; my @all = (@children, $body->id); - my $order = $c->req->params->{o} || 'created'; - my $dir = defined $c->req->params->{d} ? $c->req->params->{d} : 1; + my $order = $c->get_param('o') || 'created'; + my $dir = defined $c->get_param('d') ? $c->get_param('d') : 1; $c->stash->{order} = $order; $c->stash->{dir} = $dir; $order .= ' desc' if $dir; @@ -358,7 +362,7 @@ sub admin { order_by => $order, }); - my $page = $c->req->params->{p} || 1; + my $page = $c->get_param('p') || 1; $c->stash->{other} = $c->cobrand->problems->search({ state => { -not_in => [ 'unconfirmed', 'confirmed', 'planned' ] }, bodies_str => \@all, @@ -372,8 +376,8 @@ sub admin { my $body = $c->stash->{body}; - my $order = $c->req->params->{o} || 'created'; - my $dir = defined $c->req->params->{d} ? $c->req->params->{d} : 1; + my $order = $c->get_param('o') || 'created'; + my $dir = defined $c->get_param('d') ? $c->get_param('d') : 1; $c->stash->{order} = $order; $c->stash->{dir} = $dir; $order .= ' desc' if $dir; @@ -392,7 +396,7 @@ sub admin { order_by => $order } ); - my $page = $c->req->params->{p} || 1; + my $page = $c->get_param('p') || 1; $c->stash->{reports_published} = $c->cobrand->problems->search( { state => 'fixed - council', bodies_str => $body->parent->id, @@ -445,14 +449,14 @@ sub admin_report_edit { } # If super or sdm check that the token is correct before proceeding - if ( ($type eq 'super' || $type eq 'dm') && $c->req->param('submit') ) { + if ( ($type eq 'super' || $type eq 'dm') && $c->get_param('submit') ) { $c->forward('check_token'); } # All types of users can add internal notes - if ( ($type eq 'super' || $type eq 'dm' || $type eq 'sdm') && $c->req->param('submit') ) { + if ( ($type eq 'super' || $type eq 'dm' || $type eq 'sdm') && $c->get_param('submit') ) { # If there is a new note add it as a comment to the problem (with is_internal_note set true in extra). - if ( my $new_internal_note = $c->req->params->{new_internal_note} ) { + if ( my $new_internal_note = $c->get_param('new_internal_note') ) { $problem->add_to_comments( { text => $new_internal_note, user => $c->user->obj, @@ -465,13 +469,19 @@ sub admin_report_edit { } # Problem updates upon submission - if ( ($type eq 'super' || $type eq 'dm') && $c->req->param('submit') ) { - # Predefine the hash so it's there for lookups - my $extra = $problem->extra || {}; - $extra->{publish_photo} = $c->req->params->{publish_photo} || 0; - $extra->{third_personal} = $c->req->params->{third_personal} || 0; + if ( ($type eq 'super' || $type eq 'dm') && $c->get_param('submit') ) { + $problem->set_extra_metadata('publish_photo' => $c->get_param('publish_photo') || 0 ); + $problem->set_extra_metadata('third_personal' => $c->get_param('third_personal') || 0 ); + # Make sure we have a copy of the original detail field - $extra->{original_detail} = $problem->detail if !$extra->{original_detail} && $c->req->params->{detail} && $problem->detail ne $c->req->params->{detail}; + if (my $new_detail = $c->get_param('detail')) { + my $old_detail = $problem->detail; + if (! $problem->get_extra_metadata('original_detail') + && ($old_detail ne $new_detail)) + { + $problem->set_extra_metadata( original_detail => $old_detail ); + } + } # Some changes will be accompanied by an internal note, which if needed # should be stored in this variable. @@ -479,65 +489,62 @@ sub admin_report_edit { # Workflow things my $redirect = 0; - my $new_cat = $c->req->params->{category}; + my $new_cat = $c->get_param('category'); if ( $new_cat && $new_cat ne $problem->category ) { - my $cat = $c->model('DB::Contact')->search( { category => $c->req->params->{category} } )->first; + my $cat = $c->model('DB::Contact')->search( { category => $c->get_param('category') } )->first; my $old_cat = $problem->category; $problem->category( $new_cat ); $problem->external_body( undef ); $problem->bodies_str( $cat->body_id ); $problem->whensent( undef ); - $extra->{changed_category} = 1; + $problem->set_extra_metadata(changed_category => 1); $internal_note_text = "Weitergeleitet von $old_cat an $new_cat"; $redirect = 1 if $cat->body_id ne $body->id; - } elsif ( my $subdiv = $c->req->params->{body_subdivision} ) { - $extra->{moderated_overdue} //= $self->overdue( $problem ); + } elsif ( my $subdiv = $c->get_param('body_subdivision') ) { + $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) ); $self->set_problem_state($c, $problem, 'in progress'); $problem->external_body( undef ); $problem->bodies_str( $subdiv ); $problem->whensent( undef ); $redirect = 1; - } elsif ( my $external = $c->req->params->{body_external} ) { - $extra->{moderated_overdue} //= $self->overdue( $problem ); + } elsif ( my $external = $c->get_param('body_external') ) { + $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) ); $self->set_problem_state($c, $problem, 'closed'); - $extra->{closed_overdue} //= $self->overdue( $problem ); + $problem->set_extra_metadata_if_undefined( closed_overdue => $self->overdue( $problem ) ); $problem->external_body( $external ); $problem->whensent( undef ); _admin_send_email( $c, 'problem-external.txt', $problem ); $redirect = 1; } else { - if (my $state = $c->req->params->{state}) { + if (my $state = $c->get_param('state')) { if ($problem->state eq 'unconfirmed' and $state ne 'unconfirmed') { # only set this for the first state change - $extra->{moderated_overdue} //= $self->overdue( $problem ); + $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) ); } $self->set_problem_state($c, $problem, $state); if ($self->problem_is_closed($problem)) { - $extra->{closed_overdue} //= $self->overdue( $problem ); + $problem->set_extra_metadata_if_undefined( closed_overdue => $self->overdue( $problem ) ); } - if ( $state eq 'hidden' && $c->req->params->{send_rejected_email} ) { + if ( $state eq 'hidden' && $c->get_param('send_rejected_email') ) { _admin_send_email( $c, 'problem-rejected.txt', $problem ); } } } - $problem->extra( $extra ); - $problem->title( $c->req->param('title') ); - $problem->detail( $c->req->param('detail') ); - $problem->latitude( $c->req->param('latitude') ); - $problem->longitude( $c->req->param('longitude') ); + $problem->title( $c->get_param('title') ) if $c->get_param('title'); + $problem->detail( $c->get_param('detail') ) if $c->get_param('detail'); + $problem->latitude( $c->get_param('latitude') ); + $problem->longitude( $c->get_param('longitude') ); # Final, public, Update from DM - if (my $update = $c->req->param('status_update')) { - $extra->{public_response} = $update; - $problem->extra( $extra ); - if ($c->req->params->{publish_response}) { + if (my $update = $c->get_param('status_update')) { + $problem->set_extra_metadata(public_response => $update); + if ($c->get_param('publish_response')) { $self->set_problem_state($c, $problem, 'fixed - council'); - $extra->{closed_overdue} = $self->overdue( $problem ); - $problem->extra( { %$extra } ); + $problem->set_extra_metadata( closed_overdue => $self->overdue( $problem ) ); _admin_send_email( $c, 'problem-closed.txt', $problem ); } } @@ -581,7 +588,7 @@ sub admin_report_edit { # Has cut-down edit template for adding update and sending back up only $c->stash->{template} = 'admin/report_edit-sdm.html'; - if ($c->req->param('send_back')) { + if ($c->get_param('send_back')) { $c->forward('check_token'); $problem->bodies_str( $body->parent->id ); @@ -590,20 +597,20 @@ sub admin_report_edit { # log here $c->res->redirect( '/admin/summary' ); - } elsif ($c->req->param('submit')) { + } elsif ($c->get_param('submit')) { $c->forward('check_token'); my $db_update = 0; - if ( $c->req->param('latitude') != $problem->latitude || $c->req->param('longitude') != $problem->longitude ) { - $problem->latitude( $c->req->param('latitude') ); - $problem->longitude( $c->req->param('longitude') ); + if ( $c->get_param('latitude') != $problem->latitude || $c->get_param('longitude') != $problem->longitude ) { + $problem->latitude( $c->get_param('latitude') ); + $problem->longitude( $c->get_param('longitude') ); $db_update = 1; } $problem->update if $db_update; # Add new update from status_update - if (my $update = $c->req->param('status_update')) { + if (my $update = $c->get_param('status_update')) { FixMyStreet::App->model('DB::Comment')->create( { text => $update, user => $c->user->obj, @@ -618,10 +625,8 @@ sub admin_report_edit { $c->stash->{status_message} = '<p><em>' . _('Updated!') . '</em></p>'; # If they clicked the no more updates button, we're done. - if ($c->req->param('no_more_updates')) { - my $extra = $problem->extra || {}; - $extra->{subdiv_overdue} = $self->overdue( $problem ); - $problem->extra( $extra ); + if ($c->get_param('no_more_updates')) { + $problem->set_extra_metadata( subdiv_overdue => $self->overdue( $problem ) ); $problem->bodies_str( $body->parent->id ); $problem->whensent( undef ); $self->set_problem_state($c, $problem, 'planned'); @@ -645,7 +650,7 @@ sub admin_report_edit { sub _admin_send_email { my ( $c, $template, $problem ) = @_; - return unless $problem->extra && $problem->extra->{email_confirmed}; + return unless $problem->get_extra_metadata('email_confirmed'); my $to = $problem->name ? [ $problem->user->email, $problem->name ] @@ -707,7 +712,7 @@ sub admin_stats { my $c = $self->{c}; my %date_params; - my $ym = $c->req->params->{ym}; + my $ym = $c->get_param('ym'); my ($m, $y) = $ym ? ($ym =~ /^(\d+)\.(\d+)$/) : (); $c->stash->{ym} = $ym; if ($y && $m) { @@ -721,7 +726,7 @@ sub admin_stats { state => [ FixMyStreet::DB::Result::Problem->visible_states() ], ); - if ( $c->req->params->{export} ) { + if ( $c->get_param('export') ) { my $problems = $c->model('DB::Problem')->search( {%date_params}, { @@ -730,25 +735,55 @@ sub admin_stats { 'latitude', 'longitude', 'cobrand', 'category', 'state', 'user_id', - 'external_body' - ] + 'external_body', + 'title', 'detail', + 'photo', + 'whensent', 'lastupdate', + 'service', + 'extra', + ], } ); - my $body = "ID,Created,E,N,Category,Status,UserID,External Body\n"; + my $body = "Report ID,Created,Sent to Agency,Last Updated,E,N,Category,Status,UserID,External Body,Title,Detail,Media URL,Interface Used,Council Response\n"; + require Text::CSV; + my $csv = Text::CSV->new({ binary => 1 }); while ( my $report = $problems->next ) { my $external_body; my $body_name = ""; if ( $external_body = $report->body($c) ) { - $body_name = $external_body->name; + $body_name = $external_body->name || '[Unknown body]'; } - $body .= join( ',', - $report->id, $report->created, + + my $detail = $report->detail; + my $public_response = $report->get_extra_metadata('public_response') || ''; + + # replace newlines with HTML <br/> element + $detail =~ s{\r?\n}{ <br/> }g; + $public_response =~ s{\r?\n}{ <br/> }g; + + my @columns = ( + $report->id, + $report->created, + $report->whensent, + $report->lastupdate, $report->local_coords, $report->category, $report->state, $report->user_id, - "\"$body_name\"" ) - . "\n"; + $body_name, + $report->title, + $detail, + $c->cobrand->base_url . $report->get_photo_params->{url}, + $report->service || 'Web interface', + $public_response, + ); + if ($csv->combine(@columns)) { + $body .= $csv->string . "\n"; + } + else { + $body .= sprintf "{{error emitting CSV line: %s}}\n", $csv->error_diag; + } } $c->res->content_type('text/csv; charset=utf-8'); + $c->res->header('Content-Disposition' => 'attachment; filename=stats.csv'); $c->res->body($body); } diff --git a/perllib/FixMyStreet/DB/Result/Alert.pm b/perllib/FixMyStreet/DB/Result/Alert.pm index 4ce72f873..c64cb2ff4 100644 --- a/perllib/FixMyStreet/DB/Result/Alert.pm +++ b/perllib/FixMyStreet/DB/Result/Alert.pm @@ -69,24 +69,16 @@ __PACKAGE__->belongs_to( # You can replace this text with custom code or comments, and it will be preserved on regeneration -use DateTime::TimeZone; use Moose; use namespace::clean -except => [ 'meta' ]; with 'FixMyStreet::Roles::Abuser'; -my $tz = DateTime::TimeZone->new( name => "local" ); - -my $tz_f; -$tz_f = DateTime::TimeZone->new( name => FixMyStreet->config('TIME_ZONE') ) - if FixMyStreet->config('TIME_ZONE'); - my $stz = sub { my ( $orig, $self ) = ( shift, shift ); my $s = $self->$orig(@_); return $s unless $s && UNIVERSAL::isa($s, "DateTime"); - $s->set_time_zone($tz); - $s->set_time_zone($tz_f) if $tz_f; + FixMyStreet->set_time_zone($s); return $s; }; diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm index 3fae6860a..836462ed5 100644 --- a/perllib/FixMyStreet/DB/Result/Comment.pm +++ b/perllib/FixMyStreet/DB/Result/Comment.pm @@ -95,25 +95,17 @@ __PACKAGE__->belongs_to( __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); __PACKAGE__->rabx_column('extra'); -use DateTime::TimeZone; use Image::Size; use Moose; use namespace::clean -except => [ 'meta' ]; with 'FixMyStreet::Roles::Abuser'; -my $tz = DateTime::TimeZone->new( name => "local" ); - -my $tz_f; -$tz_f = DateTime::TimeZone->new( name => FixMyStreet->config('TIME_ZONE') ) - if FixMyStreet->config('TIME_ZONE'); - my $stz = sub { my ( $orig, $self ) = ( shift, shift ); my $s = $self->$orig(@_); return $s unless $s && UNIVERSAL::isa($s, "DateTime"); - $s->set_time_zone($tz); - $s->set_time_zone($tz_f) if $tz_f; + FixMyStreet->set_time_zone($s); return $s; }; diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm index eca028c9b..2fbb0716d 100644 --- a/perllib/FixMyStreet/DB/Result/Contact.pm +++ b/perllib/FixMyStreet/DB/Result/Contact.pm @@ -63,4 +63,12 @@ __PACKAGE__->belongs_to( __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); __PACKAGE__->rabx_column('extra'); +use Moose; +use namespace::clean -except => [ 'meta' ]; + +with 'FixMyStreet::Roles::Extra'; + +# we need the inline_constructor bit as we don't inherit from Moose +__PACKAGE__->meta->make_immutable( inline_constructor => 0 ); + 1; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 34d740912..bed2f160a 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -153,13 +153,13 @@ __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); __PACKAGE__->rabx_column('extra'); __PACKAGE__->rabx_column('geocode'); -use DateTime::TimeZone; use Image::Size; use Moose; use namespace::clean -except => [ 'meta' ]; use Utils; -with 'FixMyStreet::Roles::Abuser'; +with 'FixMyStreet::Roles::Abuser', + 'FixMyStreet::Roles::Extra'; =head2 @@ -228,38 +228,6 @@ sub closed_states { =head2 - @states = FixMyStreet::DB::Problem::visible_states(); - -Get a list of states that should be visible on the site. If called in -array context then returns an array of names, otherwise returns a -HASHREF. - -=cut - -my $visible_states = { - 'confirmed' => 1, - 'investigating' => 1, - 'in progress' => 1, - 'planned' => 1, - 'action scheduled' => 1, - 'fixed' => 1, - 'fixed - council' => 1, - 'fixed - user' => 1, - 'unable to fix' => 1, - 'not responsible' => 1, - 'duplicate' => 1, - 'closed' => 1, - 'internal referral' => 1, -}; -sub visible_states { - return wantarray ? keys %{$visible_states} : $visible_states; -} -sub visible_states_add_unconfirmed { - $visible_states->{unconfirmed} = 1; -} - -=head2 - @states = FixMyStreet::DB::Problem::all_states(); Get a list of all states that a problem can have. If called in @@ -293,6 +261,70 @@ sub all_states { =head2 + @visible_states = FixMyStreet::DB::Problem::visible_states(); + @hidden_states = FixMyStreet::DB::Problem::hidden_states(); + +Get a list of states that should be visible (or hidden) on the site. If called +in array context then returns an array of names, otherwise returns a HASHREF. + +=cut + +my $hidden_states = { + 'hidden' => 1, + 'partial' => 1, + 'unconfirmed' => 1, +}; + +my $visible_states = { + map { + $hidden_states->{$_} ? () : ($_ => 1) + } all_states() +}; + ## e.g.: + # 'confirmed' => 1, + # 'investigating' => 1, + # 'in progress' => 1, + # 'planned' => 1, + # 'action scheduled' => 1, + # 'fixed' => 1, + # 'fixed - council' => 1, + # 'fixed - user' => 1, + # 'unable to fix' => 1, + # 'not responsible' => 1, + # 'duplicate' => 1, + # 'closed' => 1, + # 'internal referral' => 1, + +sub hidden_states { + return wantarray ? keys %{$hidden_states} : $hidden_states; +} + +sub visible_states { + return wantarray ? keys %{$visible_states} : $visible_states; +} + +sub visible_states_add { + my ($self, @states) = @_; + for my $state (@states) { + delete $hidden_states->{$state}; + $visible_states->{$state} = 1; + } +} + +sub visible_states_remove { + my ($self, @states) = @_; + for my $state (@states) { + delete $visible_states->{$state}; + $hidden_states->{$state} = 1; + } +} + +sub visible_states_add_unconfirmed { + $_[0]->visible_states_add('unconfirmed') +} + +=head2 + @states = FixMyStreet::DB::Problem::council_states(); Get a list of states that are availble to council users. If called in @@ -316,18 +348,11 @@ sub council_states { return wantarray ? keys %{$states} : $states; } -my $tz = DateTime::TimeZone->new( name => "local" ); - -my $tz_f; -$tz_f = DateTime::TimeZone->new( name => FixMyStreet->config('TIME_ZONE') ) - if FixMyStreet->config('TIME_ZONE'); - my $stz = sub { my ( $orig, $self ) = ( shift, shift ); my $s = $self->$orig(@_); return $s unless $s && UNIVERSAL::isa($s, "DateTime"); - $s->set_time_zone($tz); - $s->set_time_zone($tz_f) if $tz_f; + FixMyStreet->set_time_zone($s); return $s; }; @@ -380,14 +405,6 @@ sub check_for_errors { if ( !$self->name || $self->name !~ m/\S/ ) { $errors{name} = _('Please enter your name'); } - elsif (length( $self->name ) < 5 - || $self->name !~ m/\s/ - || $self->name =~ m/\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i ) - { - $errors{name} = _( -'Please enter your full name, councils need this information – if you do not wish your name to be shown on the site, untick the box below' - ) unless $self->cobrand eq 'emptyhomes'; - } if ( $self->category && $self->category eq _('-- Pick a category --') ) @@ -402,18 +419,6 @@ sub check_for_errors { $self->category(undef); } - if ( $self->bodies_str && $self->detail ) { - # Custom character limit: - # Bromley Council - if ( $self->bodies_str eq '2482' && length($self->detail) > 1750 ) { - $errors{detail} = sprintf( _('Reports are limited to %s characters in length. Please shorten your report'), 1750 ); - } - # Oxfordshire - if ( $self->bodies_str eq '2237' && length($self->detail) > 1700 ) { - $errors{detail} = sprintf( _('Reports are limited to %s characters in length. Please shorten your report'), 1700 ); - } - } - return \%errors; } @@ -662,14 +667,14 @@ sub processed_summary_string { } if ($problem->can_display_external_id) { if ($duration_clause) { - $external_ref_clause = sprintf(_('council ref: %s'), $problem->external_id); + $external_ref_clause = '<strong>' . sprintf(_('Council ref: %s'), $problem->external_id) . '.</strong>'; } else { - $external_ref_clause = sprintf(_('%s ref: %s'), $problem->external_body, $problem->external_id); + $external_ref_clause = '<strong>' . sprintf(_('%s ref: %s'), $problem->external_body, $problem->external_id) . '.</strong>'; } } if ($duration_clause and $external_ref_clause) { - return "$duration_clause, $external_ref_clause" - } else { + return "$duration_clause. $external_ref_clause" + } else { return $duration_clause || $external_ref_clause } } @@ -688,6 +693,10 @@ sub local_coords { my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($self->latitude, $self->longitude); return ( int($x+0.5), int($y+0.5) ); } + else { + # return a dummy value until this function is implemented. useful for testing. + return (0, 0); + } } =head2 update_from_open311_service_request @@ -745,7 +754,7 @@ sub update_from_open311_service_request { # of course if local timezone is not the one that went into the data # base then we're also in trouble my $lastupdate = $self->lastupdate; - $lastupdate->set_time_zone( DateTime::TimeZone->new( name => 'local' ) ); + $lastupdate->set_time_zone( FixMyStreet->local_time_zone ); # update from open311 is older so skip if ( $req_time < $lastupdate ) { diff --git a/perllib/FixMyStreet/DB/Result/Questionnaire.pm b/perllib/FixMyStreet/DB/Result/Questionnaire.pm index 7f9c79d9a..6f2941546 100644 --- a/perllib/FixMyStreet/DB/Result/Questionnaire.pm +++ b/perllib/FixMyStreet/DB/Result/Questionnaire.pm @@ -43,22 +43,14 @@ __PACKAGE__->belongs_to( # Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:oL1Hk4/bNG14CY74GA75SA -use DateTime::TimeZone; use Moose; use namespace::clean -except => [ 'meta' ]; -my $tz = DateTime::TimeZone->new( name => "local" ); - -my $tz_f; -$tz_f = DateTime::TimeZone->new( name => FixMyStreet->config('TIME_ZONE') ) - if FixMyStreet->config('TIME_ZONE'); - my $stz = sub { my ( $orig, $self ) = ( shift, shift ); my $s = $self->$orig(@_); return $s unless $s && UNIVERSAL::isa($s, "DateTime"); - $s->set_time_zone($tz); - $s->set_time_zone($tz_f) if $tz_f; + FixMyStreet->set_time_zone($s); return $s; }; diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm index 6a93f97ec..f08b666c8 100644 --- a/perllib/FixMyStreet/DB/Result/User.pm +++ b/perllib/FixMyStreet/DB/Result/User.pm @@ -100,7 +100,7 @@ use mySociety::EmailUtil; =head2 check_for_errors - $error_hashref = $problem->check_for_errors(); + $error_hashref = $user->check_for_errors(); Look at all the fields and return a hashref with all errors found, keyed on the field name. This is intended to be passed back to the form to display the diff --git a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm index b704fa7dd..0b430008a 100644 --- a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm +++ b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm @@ -103,36 +103,25 @@ sub email_alerts ($) { } ); $data{alert_email} = $user->email; my $token_obj = FixMyStreet::App->model('DB::Token')->create( { - scope => 'email_sign_in', + scope => 'alert_to_reporter', data => { - email => $user->email, - r => 'report/' . $row->{id}, + id => $row->{id}, } } ); - $data{problem_url} = $url . "/M/" . $token_obj->token; + $data{problem_url} = $url . "/R/" . $token_obj->token; } else { $data{problem_url} = $url . "/report/" . $row->{id}; } $data{data} .= $row->{item_name} . ' : ' if $row->{item_name} && !$row->{item_anonymous}; if ( $cobrand->include_time_in_update_alerts ) { - # this is basically recreating the code from the inflate wrapper - # in the database model. - my $tz; - if ( FixMyStreet->config('TIME_ZONE') ) { - $tz = FixMyStreet->config('TIME_ZONE'); - } - my $parser = DateTime::Format::Pg->new(); my $dt = $parser->parse_timestamp( $row->{item_confirmed} ); - my $l_tz = DateTime::TimeZone->new( name => "local" ); # We need to always set this otherwise we end up with the DateTime # object being in the floating timezone in which case applying a # subsequent timezone set will have no effect. - $dt->set_time_zone( $l_tz ); - if ( $tz ) { - my $tz_obj = DateTime::TimeZone->new( name => $tz ); - $dt->set_time_zone( $tz_obj ); - } + # this is basically recreating the code from the inflate wrapper + # in the database model. + FixMyStreet->set_time_zone($dt); $data{data} .= $cobrand->prettify_dt( $dt, 'alert' ) . "\n\n"; } $data{data} .= $row->{item_text} . "\n\n------\n\n"; diff --git a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm index 91c44d5f4..a0ccb8a6d 100644 --- a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm +++ b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm @@ -5,11 +5,15 @@ use strict; use warnings; sub nearby { - my ( $rs, $c, $dist, $ids, $limit, $mid_lat, $mid_lon, $interval ) = @_; + my ( $rs, $c, $dist, $ids, $limit, $mid_lat, $mid_lon, $interval, $category, $states ) = @_; + + unless ( $states ) { + $states = FixMyStreet::DB::Result::Problem->visible_states(); + } my $params = { non_public => 0, - state => [ FixMyStreet::DB::Result::Problem::visible_states() ], + state => [ keys %$states ], }; $params->{'current_timestamp-lastupdate'} = { '<', \"'$interval'::interval" } if $interval; @@ -19,6 +23,7 @@ sub nearby { %{ $c->cobrand->problems_clause }, %$params } if $c->cobrand->problems_clause; + $params->{category} = $category if $category; my $attrs = { prefetch => 'problem', diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm index a84a309ee..7885c28b3 100644 --- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm +++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm @@ -131,20 +131,25 @@ sub _recent { # Problems around a location sub around_map { - my ( $rs, $min_lat, $max_lat, $min_lon, $max_lon, $interval, $limit ) = @_; + my ( $rs, $min_lat, $max_lat, $min_lon, $max_lon, $interval, $limit, $category, $states ) = @_; my $attr = { order_by => { -desc => 'created' }, }; $attr->{rows} = $limit if $limit; + unless ( $states ) { + $states = FixMyStreet::DB::Result::Problem->visible_states(); + } + my $q = { non_public => 0, - state => [ FixMyStreet::DB::Result::Problem->visible_states() ], + state => [ keys %$states ], latitude => { '>=', $min_lat, '<', $max_lat }, longitude => { '>=', $min_lon, '<', $max_lon }, }; $q->{'current_timestamp - lastupdate'} = { '<', \"'$interval'::interval" } if $interval; + $q->{category} = $category if $category; my @problems = mySociety::Locale::in_gb_locale { $rs->search( $q, $attr )->all }; return \@problems; @@ -295,19 +300,6 @@ sub send_reports { : _('The user could not locate the problem on a map, but to see the area around the location they entered'); $h{closest_address} = ''; - # If we are in the UK include eastings and northings, and nearest stuff - $h{easting_northing} = ''; - if ( $cobrand->country eq 'GB' ) { - - ( $h{easting}, $h{northing} ) = Utils::convert_latlon_to_en( $h{latitude}, $h{longitude} ); - - # email templates don't have conditionals so we need to farmat this here - $h{easting_northing} # - = "Easting: $h{easting}\n\n" # - . "Northing: $h{northing}\n\n"; - - } - if ( $row->used_map ) { $h{closest_address} = $cobrand->find_closest( $h{latitude}, $h{longitude}, $row ); } @@ -315,104 +307,106 @@ sub send_reports { if ( $cobrand->allow_anonymous_reports && $row->user->email eq $cobrand->anonymous_account->{'email'} ) { - $h{anonymous_report} = 1; - $h{user_details} = _('This report was submitted anonymously'); - } else { - $h{user_details} = sprintf(_('Name: %s'), $row->name) . "\n\n"; - $h{user_details} .= sprintf(_('Email: %s'), $row->user->email) . "\n\n"; - } + $h{anonymous_report} = 1; + $h{user_details} = _('This report was submitted anonymously'); + } else { + $h{user_details} = sprintf(_('Name: %s'), $row->name) . "\n\n"; + $h{user_details} .= sprintf(_('Email: %s'), $row->user->email) . "\n\n"; + } + + $h{easting_northing} = ''; if ($cobrand->can('process_additional_metadata_for_email')) { $cobrand->process_additional_metadata_for_email($row, \%h); } + # XXX Needs locks! + # XXX Only copes with at most one missing body + my ($bodies, $missing) = $row->bodies_str =~ /^([\d,]+)(?:\|(\d+))?/; + my @bodies = split(/,/, $bodies); + $bodies = FixMyStreet::App->model("DB::Body")->search( + { id => \@bodies }, + { order_by => 'name' }, + ); + $missing = FixMyStreet::App->model("DB::Body")->find($missing) if $missing; + + my @dear; my %reporters = (); - my ( $sender_count ); - if ($site eq 'emptyhomes') { + while (my $body = $bodies->next) { + my $sender_info = $cobrand->get_body_sender( $body, $row->category ); + my $sender = "FixMyStreet::SendReport::" . $sender_info->{method}; - my $body = $row->bodies_str; - $body = FixMyStreet::App->model("DB::Body")->find($body); - my $sender = "FixMyStreet::SendReport::EmptyHomes"; - $reporters{ $sender } = $sender->new() unless $reporters{$sender}; - $reporters{ $sender }->add_body( $body ); - $sender_count = 1; - - } else { - - # XXX Needs locks! - # XXX Only copes with at most one missing body - my ($bodies, $missing) = $row->bodies_str =~ /^([\d,]+)(?:\|(\d+))?/; - my @bodies = split(/,/, $bodies); - $bodies = FixMyStreet::App->model("DB::Body")->search( - { id => \@bodies }, - { order_by => 'name' }, - ); - $missing = FixMyStreet::App->model("DB::Body")->find($missing) if $missing; - my @dear; - - while (my $body = $bodies->next) { - my $sender_info = $cobrand->get_body_sender( $body, $row->category ); - my $sender = "FixMyStreet::SendReport::" . $sender_info->{method}; - - if ( ! exists $senders->{ $sender } ) { - warn "No such sender [ $sender ] for body $body->name ( $body->id )"; - next; - } - $reporters{ $sender } ||= $sender->new(); - - if ( $reporters{ $sender }->should_skip( $row ) ) { - debug_print("skipped by sender " . $sender_info->{method} . " (might be due to previous failed attempts?)", $row->id) if $debug_mode; - } else { - debug_print("OK, adding recipient body " . $body->id . ":" . $body->name . ", " . $body->send_method, $row->id) if $debug_mode; - push @dear, $body->name; - $reporters{ $sender }->add_body( $body, $sender_info->{config} ); - } + if ( ! exists $senders->{ $sender } ) { + warn "No such sender [ $sender ] for body $body->name ( $body->id )"; + next; } + $reporters{ $sender } ||= $sender->new(); - if ($h{category} eq _('Other')) { - $h{category_footer} = _('this type of local problem'); - $h{category_line} = ''; + if ( $reporters{ $sender }->should_skip( $row ) ) { + debug_print("skipped by sender " . $sender_info->{method} . " (might be due to previous failed attempts?)", $row->id) if $debug_mode; } else { - $h{category_footer} = "'" . $h{category} . "'"; - $h{category_line} = sprintf(_("Category: %s"), $h{category}) . "\n\n"; + debug_print("OK, adding recipient body " . $body->id . ":" . $body->name . ", " . $body->send_method, $row->id) if $debug_mode; + push @dear, $body->name; + $reporters{ $sender }->add_body( $body, $sender_info->{config} ); } - if ( $row->subcategory ) { - $h{subcategory_line} = sprintf(_("Subcategory: %s"), $row->subcategory) . "\n\n"; - } else { - $h{subcategory_line} = "\n\n"; - } + # If we are in the UK include eastings and northings, and nearest stuff + if ( $cobrand->country eq 'GB' && !$h{easting} ) { + my $coordsyst = 'G'; + my $first_area = $body->body_areas->first->area_id; + my $area_info = mySociety::MaPit::call('area', $first_area); + $coordsyst = 'I' if $area_info->{type} eq 'LGD'; - $h{bodies_name} = join(_(' and '), @dear); - if ($h{category} eq _('Other')) { - $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to both councils covering the location of the problem, as the user did not categorise it; please ignore it if you're not the correct council to deal with the issue, or let us know what category of problem this is so we can add it to our system.") . " ]\n\n" - : ''; - } else { - $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to several councils covering the location of the problem, as the category selected is provided for all of them; please ignore it if you're not the correct council to deal with the issue.") . " ]\n\n" - : ''; - } - $h{missing} = ''; - if ($missing) { - $h{missing} = '[ ' - . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $missing->name) - . " ]\n\n"; - } + ( $h{easting}, $h{northing} ) = Utils::convert_latlon_to_en( $h{latitude}, $h{longitude}, $coordsyst ); - $sender_count = scalar @dear; + # email templates don't have conditionals so we need to format this here + $h{easting_northing} = "Easting/Northing"; + $h{easting_northing} .= " (IE)" if $coordsyst eq 'I'; + $h{easting_northing} .= ": $h{easting}/$h{northing}\n\n"; + } } unless ( keys %reporters ) { die 'Report not going anywhere for ID ' . $row->id . '!'; } - if (! $sender_count) { + unless (@dear) { debug_print("can't send because sender count is zero", $row->id) if $debug_mode; next; } + if ($h{category} eq _('Other')) { + $h{category_footer} = _('this type of local problem'); + $h{category_line} = ''; + } else { + $h{category_footer} = "'" . $h{category} . "'"; + $h{category_line} = sprintf(_("Category: %s"), $h{category}) . "\n\n"; + } + + if ( $row->subcategory ) { + $h{subcategory_line} = sprintf(_("Subcategory: %s"), $row->subcategory) . "\n\n"; + } else { + $h{subcategory_line} = "\n\n"; + } + + $h{bodies_name} = join(_(' and '), @dear); + if ($h{category} eq _('Other')) { + $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to both councils covering the location of the problem, as the user did not categorise it; please ignore it if you're not the correct council to deal with the issue, or let us know what category of problem this is so we can add it to our system.") . " ]\n\n" + : ''; + } else { + $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to several councils covering the location of the problem, as the category selected is provided for all of them; please ignore it if you're not the correct council to deal with the issue.") . " ]\n\n" + : ''; + } + $h{missing} = ''; + if ($missing) { + $h{missing} = '[ ' + . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $missing->name) + . " ]\n\n"; + } + if (mySociety::Config::get('STAGING_SITE') && !mySociety::Config::get('SEND_REPORTS_ON_STAGING')) { # on a staging server send emails to ourselves rather than the bodies - %reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::(Email|NI|EmptyHomes)/ } keys %reporters; + %reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::(Email|EmptyHomes)/ } keys %reporters; unless (%reporters) { %reporters = ( 'FixMyStreet::SendReport::Email' => FixMyStreet::SendReport::Email->new() ); } diff --git a/perllib/FixMyStreet/Geocode.pm b/perllib/FixMyStreet/Geocode.pm index b5be152a8..aac52fbaa 100644 --- a/perllib/FixMyStreet/Geocode.pm +++ b/perllib/FixMyStreet/Geocode.pm @@ -7,11 +7,17 @@ package FixMyStreet::Geocode; use strict; +use Digest::MD5 qw(md5_hex); +use Encode; +use File::Slurp; +use File::Path (); +use LWP::Simple qw($ua); use URI::Escape; use FixMyStreet::Geocode::Bing; use FixMyStreet::Geocode::Google; use FixMyStreet::Geocode::OSM; use FixMyStreet::Geocode::Zurich; +use Utils; # lookup STRING CONTEXT # Given a user-inputted string, try and convert it into co-ordinates using either @@ -21,6 +27,11 @@ use FixMyStreet::Geocode::Zurich; sub lookup { my ($s, $c) = @_; my $data = $c->cobrand->geocode_postcode($s); + if (defined $data->{latitude}) { + ( $data->{latitude}, $data->{longitude} ) = + map { Utils::truncate_coordinate($_) } + ( $data->{latitude}, $data->{longitude} ); + } $data = string($s, $c) unless $data->{error} || defined $data->{latitude}; $data->{error} = _('Sorry, we could not find that location.') @@ -55,4 +66,25 @@ sub escape { return $s; } +sub cache { + my ($type, $url, $args, $re) = @_; + my $cache_dir = FixMyStreet->config('GEO_CACHE') . $type . '/'; + my $cache_file = $cache_dir . md5_hex($url); + my $js; + if (-s $cache_file && -M $cache_file <= 7) { + $js = File::Slurp::read_file($cache_file); + } else { + $url .= '&' . $args if $args; + $ua->timeout(15); + $js = LWP::Simple::get($url); + $js = encode_utf8($js) if utf8::is_utf8($js); + File::Path::mkpath($cache_dir); + if ($js && (!$re || $js !~ $re)) { + File::Slurp::write_file($cache_file, $js); + } + } + $js = JSON->new->utf8->allow_nonref->decode($js) if $js; + return $js; +} + 1; diff --git a/perllib/FixMyStreet/Geocode/Bing.pm b/perllib/FixMyStreet/Geocode/Bing.pm index 702e19814..d7db10ae6 100644 --- a/perllib/FixMyStreet/Geocode/Bing.pm +++ b/perllib/FixMyStreet/Geocode/Bing.pm @@ -7,13 +7,8 @@ package FixMyStreet::Geocode::Bing; use strict; -use Encode; -use File::Slurp; -use File::Path (); -use LWP::Simple; -use Digest::MD5 qw(md5_hex); -use mySociety::Locale; +use Utils; # string STRING CONTEXT # Looks up on Bing Maps API, and caches, a user-inputted location. @@ -34,24 +29,10 @@ sub string { $url .= '&userLocation=' . $params->{centre} if $params->{centre}; $url .= '&c=' . $params->{bing_culture} if $params->{bing_culture}; - my $cache_dir = FixMyStreet->config('GEO_CACHE') . 'bing/'; - my $cache_file = $cache_dir . md5_hex($url); - my $js; - if (-s $cache_file) { - $js = File::Slurp::read_file($cache_file); - } else { - $url .= '&key=' . FixMyStreet->config('BING_MAPS_API_KEY'); - $js = LWP::Simple::get($url); - $js = encode_utf8($js) if utf8::is_utf8($js); - File::Path::mkpath($cache_dir); - File::Slurp::write_file($cache_file, $js) if $js; - } - + my $js = FixMyStreet::Geocode::cache('bing', $url, 'key=' . FixMyStreet->config('BING_MAPS_API_KEY')); if (!$js) { return { error => _('Sorry, we could not parse that location. Please try again.') }; } - - $js = JSON->new->utf8->allow_nonref->decode($js); if ($js->{statusCode} ne '200') { return { error => _('Sorry, we could not find that location.') }; } @@ -71,15 +52,14 @@ sub string { || $valid_locations[-1]{address}{locality} eq $_->{address}{locality} ); - ( $latitude, $longitude ) = @{ $_->{point}->{coordinates} }; - # These co-ordinates are output as query parameters in a URL, make sure they have a "." - mySociety::Locale::in_gb_locale { - push (@$error, { - address => $address, - latitude => sprintf('%0.6f', $latitude), - longitude => sprintf('%0.6f', $longitude) - }); - }; + ( $latitude, $longitude ) = + map { Utils::truncate_coordinate($_) } + @{ $_->{point}->{coordinates} }; + push (@$error, { + address => $address, + latitude => $latitude, + longitude => $longitude + }); push (@valid_locations, $_); } @@ -88,33 +68,15 @@ sub string { } sub reverse { - my ( $latitude, $longitude, $bing_culture, $cache ) = @_; + my ( $latitude, $longitude, $bing_culture ) = @_; # Get nearest road-type thing from Bing my $key = mySociety::Config::get('BING_MAPS_API_KEY', ''); if ($key) { my $url = "http://dev.virtualearth.net/REST/v1/Locations/$latitude,$longitude?key=$key"; $url .= '&c=' . $bing_culture if $bing_culture; - my $j; - if ( $cache ) { - my $cache_dir = FixMyStreet->config('GEO_CACHE') . 'bing/'; - my $cache_file = $cache_dir . md5_hex($url); - - if (-s $cache_file) { - $j = File::Slurp::read_file($cache_file); - } else { - $j = LWP::Simple::get($url); - File::Path::mkpath($cache_dir); - File::Slurp::write_file($cache_file, $j) if $j; - } - } else { - $j = LWP::Simple::get($url); - } - - if ($j) { - $j = JSON->new->utf8->allow_nonref->decode($j); - return $j; - } + my $j = FixMyStreet::Geocode::cache('bing', $url); + return $j if $j; } return undef; diff --git a/perllib/FixMyStreet/Geocode/FixaMinGata.pm b/perllib/FixMyStreet/Geocode/FixaMinGata.pm index 2ea92c422..3ad98b148 100644 --- a/perllib/FixMyStreet/Geocode/FixaMinGata.pm +++ b/perllib/FixMyStreet/Geocode/FixaMinGata.pm @@ -14,16 +14,11 @@ package FixMyStreet::Geocode::FixaMinGata; use warnings; use strict; -use Data::Dumper; -use Digest::MD5 qw(md5_hex); -use Encode; -use File::Slurp; -use File::Path (); -use LWP::Simple qw($ua); +use LWP::Simple; use Memcached; use XML::Simple; -use mySociety::Locale; +use Utils; my $osmapibase = "http://www.openstreetmap.org/api/"; my $nominatimbase = "http://nominatim.openstreetmap.org/"; @@ -45,8 +40,8 @@ sub string { my %query_params = ( q => $s, format => 'json', - addressdetails => 1, - limit => 20, + addressdetails => 1, + limit => 20, #'accept-language' => '', email => 'info' . chr(64) . 'morus.se', ); @@ -56,53 +51,32 @@ sub string { if $params->{country}; $url .= join('&', map { "$_=$query_params{$_}" } keys %query_params); - my $cache_dir = FixMyStreet->config('GEO_CACHE') . 'osm/'; - my $cache_file = $cache_dir . md5_hex($url); - my $js; - if (-s $cache_file) { - $js = File::Slurp::read_file($cache_file); - } else { - $ua->timeout(15); - $js = LWP::Simple::get($url); - $js = encode_utf8($js) if utf8::is_utf8($js); - File::Path::mkpath($cache_dir); - File::Slurp::write_file($cache_file, $js) if $js; - } - + my $js = FixMyStreet::Geocode::cache('osm', $url); if (!$js) { return { error => _('Sorry, we could not find that location.') }; } - $js = JSON->new->utf8->allow_nonref->decode($js); - my ( %locations, $error, @valid_locations, $latitude, $longitude ); foreach (@$js) { - # These co-ordinates are output as query parameters in a URL, make sure they have a "." - next if $_->{class} eq "boundary"; - - my @s = split(/,/, $_->{display_name}); - - my $address = join(",", @s[0,1,2]); - + next if $_->{class} eq "boundary"; + my @s = split(/,/, $_->{display_name}); + my $address = join(",", @s[0,1,2]); $locations{$address} = [$_->{lat}, $_->{lon}]; } - my ($key) = keys %locations; - - return { latitude => $locations{$key}[0], longitude => $locations{$key}[1] } if scalar keys %locations == 1; - return { error => _('Sorry, we could not find that location.') } if scalar keys %locations == 0; - - foreach $key (keys %locations) { - ( $latitude, $longitude ) = ($locations{$key}[0], $locations{$key}[1]); - mySociety::Locale::in_gb_locale { - push (@$error, { - address => $key, - latitude => sprintf('%0.6f', $latitude), - longitude => sprintf('%0.6f', $longitude) - }); - }; + foreach my $key (keys %locations) { + ( $latitude, $longitude ) = + map { Utils::truncate_coordinate($_) } + ($locations{$key}[0], $locations{$key}[1]); + push (@$error, { + address => $key, + latitude => $latitude, + longitude => $longitude + }); + push (@valid_locations, $_); } + return { latitude => $latitude, longitude => $longitude } if scalar @valid_locations == 1; return { error => $error }; } diff --git a/perllib/FixMyStreet/Geocode/Google.pm b/perllib/FixMyStreet/Geocode/Google.pm index 11ff8ef80..35fcec36f 100644 --- a/perllib/FixMyStreet/Geocode/Google.pm +++ b/perllib/FixMyStreet/Geocode/Google.pm @@ -7,12 +7,7 @@ package FixMyStreet::Geocode::Google; use strict; -use Encode; -use File::Slurp; -use File::Path (); -use LWP::Simple; -use Digest::MD5 qw(md5_hex); -use mySociety::Locale; +use Utils; # string STRING CONTEXT # Looks up on Google Maps API, and caches, a user-inputted location. @@ -24,6 +19,13 @@ sub string { my $params = $c->cobrand->disambiguate_location($s); + # For some reason adding gl=uk is no longer sufficient to make google + # think we are in the UK for some locations so we explictly add UK to + # the address. + if ($c->cobrand->country eq 'GB' && $s !~ /, *UK/ && $s !~ /united *kingdom$/) { + $s .= ', UK'; + } + $s = FixMyStreet::Geocode::escape($s); my $url = 'http://maps.google.com/maps/geo?q=' . $s; @@ -36,38 +38,11 @@ sub string { } $url .= '&hl=' . $params->{lang} if $params->{lang}; - my $cache_dir = FixMyStreet->config('GEO_CACHE') . 'google/'; - my $cache_file = $cache_dir . md5_hex($url); - my $js; - if (-s $cache_file) { - $js = File::Slurp::read_file($cache_file); - } else { - # For some reason adding gl=uk is no longer sufficient to make google - # think we are in the UK for some locations so we explictly add UK to - # the address. We do it here so as not to invalidate existing cache - # entries - if ( $c->cobrand->country eq 'GB' - && $url !~ /,\+UK/ - && $url !~ /united\++kingdom$/ ) - { - if ( $url =~ /&/ ) { - $url =~ s/&/,+UK&/; - } else { - $url .= ',+UK'; - } - } - $url .= '&sensor=false&key=' . FixMyStreet->config('GOOGLE_MAPS_API_KEY'); - $js = LWP::Simple::get($url); - $js = encode_utf8($js) if utf8::is_utf8($js); - File::Path::mkpath($cache_dir); - File::Slurp::write_file($cache_file, $js) if $js && $js !~ /"code":6[12]0/; - } - + my $args = 'sensor=false&key=' . FixMyStreet->config('GOOGLE_MAPS_API_KEY'); + my $js = FixMyStreet::Geocode::cache('google', $url, $args, qr/"code":6[12]0/); if (!$js) { return { error => _('Sorry, we could not parse that location. Please try again.') }; } - - $js = JSON->new->utf8->allow_nonref->decode($js); if ($js->{Status}->{code} ne '200') { return { error => _('Sorry, we could not find that location.') }; } @@ -78,15 +53,14 @@ sub string { next unless $_->{AddressDetails}->{Accuracy} >= 4; my $address = $_->{address}; next unless $c->cobrand->geocoded_string_check( $address ); - ( $longitude, $latitude ) = @{ $_->{Point}->{coordinates} }; - # These co-ordinates are output as query parameters in a URL, make sure they have a "." - mySociety::Locale::in_gb_locale { - push (@$error, { - address => $address, - latitude => sprintf('%0.6f', $latitude), - longitude => sprintf('%0.6f', $longitude) - }); - }; + ( $longitude, $latitude ) = + map { Utils::truncate_coordinate($_) } + @{ $_->{Point}->{coordinates} }; + push (@$error, { + address => $address, + latitude => $latitude, + longitude => $longitude + }); push (@valid_locations, $_); } return { latitude => $latitude, longitude => $longitude } if scalar @valid_locations == 1; diff --git a/perllib/FixMyStreet/Geocode/OSM.pm b/perllib/FixMyStreet/Geocode/OSM.pm index 919940f78..f165963d7 100644 --- a/perllib/FixMyStreet/Geocode/OSM.pm +++ b/perllib/FixMyStreet/Geocode/OSM.pm @@ -9,14 +9,10 @@ package FixMyStreet::Geocode::OSM; use warnings; use strict; -use Digest::MD5 qw(md5_hex); -use Encode; -use File::Slurp; -use File::Path (); -use LWP::Simple qw($ua); +use LWP::Simple; use Memcached; use XML::Simple; -use mySociety::Locale; +use Utils; my $osmapibase = "http://www.openstreetmap.org/api/"; my $nominatimbase = "http://nominatim.openstreetmap.org/"; @@ -47,36 +43,21 @@ sub string { if $params->{country}; $url .= join('&', map { "$_=$query_params{$_}" } keys %query_params); - my $cache_dir = FixMyStreet->config('GEO_CACHE') . 'osm/'; - my $cache_file = $cache_dir . md5_hex($url); - my $js; - if (-s $cache_file) { - $js = File::Slurp::read_file($cache_file); - } else { - $ua->timeout(15); - $js = LWP::Simple::get($url); - $js = encode_utf8($js) if utf8::is_utf8($js); - File::Path::mkpath($cache_dir); - File::Slurp::write_file($cache_file, $js) if $js; - } - + my $js = FixMyStreet::Geocode::cache('osm', $url); if (!$js) { return { error => _('Sorry, we could not find that location.') }; } - $js = JSON->new->utf8->allow_nonref->decode($js); - my ( $error, @valid_locations, $latitude, $longitude ); foreach (@$js) { - # These co-ordinates are output as query parameters in a URL, make sure they have a "." - ( $latitude, $longitude ) = ( $_->{lat}, $_->{lon} ); - mySociety::Locale::in_gb_locale { - push (@$error, { - address => $_->{display_name}, - latitude => sprintf('%0.6f', $latitude), - longitude => sprintf('%0.6f', $longitude) - }); - }; + ( $latitude, $longitude ) = + map { Utils::truncate_coordinate($_) } + ( $_->{lat}, $_->{lon} ); + push (@$error, { + address => $_->{display_name}, + latitude => $latitude, + longitude => $longitude + }); push (@valid_locations, $_); } diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm index 1f0b4fc16..aad918b0e 100644 --- a/perllib/FixMyStreet/Geocode/Zurich.pm +++ b/perllib/FixMyStreet/Geocode/Zurich.pm @@ -15,7 +15,7 @@ use Digest::MD5 qw(md5_hex); use File::Path (); use Geo::Coordinates::CH1903; use Storable; -use mySociety::Locale; +use Utils; my ($soap, $method, $security); @@ -66,7 +66,7 @@ sub string { my $cache_dir = FixMyStreet->config('GEO_CACHE') . 'zurich/'; my $cache_file = $cache_dir . md5_hex($s); my $result; - if (-s $cache_file) { + if (-s $cache_file && -M $cache_file <= 7) { $result = retrieve($cache_file); } else { my $search = SOAP::Data->name('search' => $s)->type(''); @@ -92,14 +92,14 @@ sub string { my ( $error, @valid_locations, $latitude, $longitude ); foreach (@$results) { - ($latitude, $longitude) = Geo::Coordinates::CH1903::to_latlon($_->{easting}, $_->{northing}); - mySociety::Locale::in_gb_locale { - push (@$error, { - address => $_->{text}, - latitude => sprintf('%0.6f', $latitude), - longitude => sprintf('%0.6f', $longitude) - }); - }; + ($latitude, $longitude) = + map { Utils::truncate_coordinate($_) } + Geo::Coordinates::CH1903::to_latlon($_->{easting}, $_->{northing}); + push (@$error, { + address => $_->{text}, + latitude => $latitude, + longitude => $longitude + }); push (@valid_locations, $_); last if lc($_->{text}) eq lc($s); } diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm index 7d490fde3..b050592ba 100644 --- a/perllib/FixMyStreet/Map.pm +++ b/perllib/FixMyStreet/Map.pm @@ -55,7 +55,7 @@ sub display_map { } sub map_features { - my ( $c, $lat, $lon, $interval ) = @_; + my ( $c, $lat, $lon, $interval, $category, $states ) = @_; # TODO - be smarter about calculating the surrounding square # use deltas that are roughly 500m in the UK - so we get a 1 sq km search box @@ -65,12 +65,12 @@ sub map_features { $c, $lat, $lon, $lon - $lon_delta, $lat - $lat_delta, $lon + $lon_delta, $lat + $lat_delta, - $interval + $interval, $category, $states ); } sub map_features_bounds { - my ( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval ) = @_; + my ( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval, $category, $states ) = @_; my $lat = ( $max_lat + $min_lat ) / 2; my $lon = ( $max_lon + $min_lon ) / 2; @@ -78,20 +78,21 @@ sub map_features_bounds { $c, $lat, $lon, $min_lon, $min_lat, $max_lon, $max_lat, - $interval + $interval, $category, + $states ); } sub _map_features { - my ( $c, $lat, $lon, $min_lon, $min_lat, $max_lon, $max_lat, $interval ) = @_; + my ( $c, $lat, $lon, $min_lon, $min_lat, $max_lon, $max_lat, $interval, $category, $states ) = @_; # list of problems around map can be limited, but should show all pins my $around_limit = $c->cobrand->on_map_list_limit || undef; my @around_args = ( $min_lat, $max_lat, $min_lon, $max_lon, $interval ); - my $around_map = $c->cobrand->problems->around_map( @around_args, undef ); + my $around_map = $c->cobrand->problems->around_map( @around_args, undef, $category, $states ); my $around_map_list = $around_limit - ? $c->cobrand->problems->around_map( @around_args, $around_limit ) + ? $c->cobrand->problems->around_map( @around_args, $around_limit, $category, $states ) : $around_map; my $dist; @@ -105,7 +106,7 @@ sub _map_features { my $limit = 20; my @ids = map { $_->id } @$around_map_list; my $nearby = $c->model('DB::Nearby')->nearby( - $c, $dist, \@ids, $limit, $lat, $lon, $interval + $c, $dist, \@ids, $limit, $lat, $lon, $interval, $category, $states ); return ( $around_map, $around_map_list, $nearby, $dist ); @@ -114,11 +115,15 @@ sub _map_features { sub map_pins { my ($c, $interval) = @_; - my $bbox = $c->req->param('bbox'); + my $bbox = $c->get_param('bbox'); my ( $min_lon, $min_lat, $max_lon, $max_lat ) = split /,/, $bbox; + my $category = $c->get_param('filter_category'); + + $c->forward( '/reports/stash_report_filter_status' ); + my $states = $c->stash->{filter_problem_states}; my ( $around_map, $around_map_list, $nearby, $dist ) = - FixMyStreet::Map::map_features_bounds( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval ); + FixMyStreet::Map::map_features_bounds( $c, $min_lon, $min_lat, $max_lon, $max_lat, $interval, $category, $states ); # create a list of all the pins my @pins = map { diff --git a/perllib/FixMyStreet/Map/Bing.pm b/perllib/FixMyStreet/Map/Bing.pm index 09c951a5f..4c1887641 100644 --- a/perllib/FixMyStreet/Map/Bing.pm +++ b/perllib/FixMyStreet/Map/Bing.pm @@ -1,25 +1,45 @@ # FixMyStreet:Map::Bing -# Bing maps on FixMyStreet. -# -# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. -# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ +# Bing maps on FixMyStreet, using OpenLayers. package FixMyStreet::Map::Bing; +use base 'FixMyStreet::Map::OSM'; use strict; -# display_map C PARAMS -# PARAMS include: -# latitude, longitude for the centre point of the map -# CLICKABLE is set if the map is clickable -# PINS is array of pins to show, location and colour -sub display_map { - my ($self, $c, %params) = @_; - $c->stash->{map} = { - %params, - type => 'bing', - key => mySociety::Config::get('BING_MAPS_API_KEY'), - }; +# Is set by the JavaScript +sub map_type { '""' } + +sub map_template { 'bing' } + +sub copyright { '' } + +sub get_quadkey { + my ($self, $x, $y, $z) = @_; + my $key = ''; + for (my $i = $z; $i > 0; $i--) { + my $digit = 0; + my $mask = 1 << ($i - 1); + $digit++ if ($x & $mask) != 0; + $digit += 2 if ($y & $mask) != 0; + $key .= $digit; + } + return $key; +} + +sub map_tile_base { + '', "//ecn.%s.tiles.virtualearth.net/tiles/r%s.png?g=3467"; +} + +sub map_tiles { + my ( $self, %params ) = @_; + my ( $x, $y, $z ) = ( $params{x_tile}, $params{y_tile}, $params{zoom_act} ); + my ($tile_sep, $tile_base) = $self->map_tile_base; + return [ + sprintf($tile_base, 't0', $self->get_quadkey($x-1, $y-1, $z)), + sprintf($tile_base, 't1', $self->get_quadkey($x, $y-1, $z)), + sprintf($tile_base, 't2', $self->get_quadkey($x-1, $y, $z)), + sprintf($tile_base, 't3', $self->get_quadkey($x, $y, $z)), + ]; } 1; diff --git a/perllib/FixMyStreet/Map/FMS.pm b/perllib/FixMyStreet/Map/FMS.pm index 96e265a4d..50a21c125 100644 --- a/perllib/FixMyStreet/Map/FMS.pm +++ b/perllib/FixMyStreet/Map/FMS.pm @@ -5,35 +5,11 @@ # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ package FixMyStreet::Map::FMS; -use base 'FixMyStreet::Map::OSM'; +use base 'FixMyStreet::Map::Bing'; use strict; -# Is set by the JavaScript -sub map_type { - return '""'; -} - -sub map_template { - return 'fms'; -} - -sub copyright { - return ''; -} - -sub get_quadkey { - my ($x, $y, $z) = @_; - my $key = ''; - for (my $i = $z; $i > 0; $i--) { - my $digit = 0; - my $mask = 1 << ($i - 1); - $digit++ if ($x & $mask) != 0; - $digit += 2 if ($y & $mask) != 0; - $key .= $digit; - } - return $key; -} +sub map_template { 'fms' } sub map_tile_base { '-', "//%stilma.mysociety.org/sv/%d/%d/%d.png"; @@ -52,13 +28,14 @@ sub map_tiles { sprintf($tile_base, '', $z, $x, $y), ]; } else { - my $url = "g=701"; - $url .= "&productSet=mmOS" if $z > 10 && !$ni; + my $key = FixMyStreet->config('BING_MAPS_API_KEY'); + my $url = "g=3467"; + $url .= "&productSet=mmOS&key=$key" if $z > 10 && !$ni; return [ - "//ecn.t0.tiles.virtualearth.net/tiles/r" . get_quadkey($x-1, $y-1, $z) . ".png?$url", - "//ecn.t1.tiles.virtualearth.net/tiles/r" . get_quadkey($x, $y-1, $z) . ".png?$url", - "//ecn.t2.tiles.virtualearth.net/tiles/r" . get_quadkey($x-1, $y, $z) . ".png?$url", - "//ecn.t3.tiles.virtualearth.net/tiles/r" . get_quadkey($x, $y, $z) . ".png?$url", + "//ecn.t0.tiles.virtualearth.net/tiles/r" . $self->get_quadkey($x-1, $y-1, $z) . ".png?$url", + "//ecn.t1.tiles.virtualearth.net/tiles/r" . $self->get_quadkey($x, $y-1, $z) . ".png?$url", + "//ecn.t2.tiles.virtualearth.net/tiles/r" . $self->get_quadkey($x-1, $y, $z) . ".png?$url", + "//ecn.t3.tiles.virtualearth.net/tiles/r" . $self->get_quadkey($x, $y, $z) . ".png?$url", ]; } } diff --git a/perllib/FixMyStreet/Map/Google.pm b/perllib/FixMyStreet/Map/Google.pm index 172d2d60e..46823f358 100644 --- a/perllib/FixMyStreet/Map/Google.pm +++ b/perllib/FixMyStreet/Map/Google.pm @@ -35,12 +35,12 @@ sub display_map { $default_zoom = $numZoomLevels - 3 if $dist < 10; # Map centre may be overridden in the query string - $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0) - if defined $c->req->params->{lat}; - $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0) - if defined $c->req->params->{lon}; + $params{latitude} = Utils::truncate_coordinate($c->get_param('lat') + 0) + if defined $c->get_param('lat'); + $params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0) + if defined $c->get_param('lon'); - my $zoom = defined $c->req->params->{zoom} ? $c->req->params->{zoom} + 0 : $default_zoom; + my $zoom = defined $c->get_param('zoom') ? $c->get_param('zoom') + 0 : $default_zoom; $zoom = $numZoomLevels - 1 if $zoom >= $numZoomLevels; $zoom = 0 if $zoom < 0; $params{zoom_act} = $zoomOffset + $zoom; diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm index df2d16b82..7d91a9ee7 100644 --- a/perllib/FixMyStreet/Map/OSM.pm +++ b/perllib/FixMyStreet/Map/OSM.pm @@ -39,7 +39,7 @@ sub base_tile_url { } sub copyright { - return _('Map © <a id="osm_link" href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'); + _('© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'); } # display_map C PARAMS @@ -64,12 +64,12 @@ sub display_map { $default_zoom = $numZoomLevels - 3 if $dist < 10; # Map centre may be overridden in the query string - $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0) - if defined $c->req->params->{lat}; - $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0) - if defined $c->req->params->{lon}; + $params{latitude} = Utils::truncate_coordinate($c->get_param('lat') + 0) + if defined $c->get_param('lat'); + $params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0) + if defined $c->get_param('lon'); - my $zoom = defined $c->req->params->{zoom} ? $c->req->params->{zoom} + 0 : $default_zoom; + my $zoom = defined $c->get_param('zoom') ? $c->get_param('zoom') + 0 : $default_zoom; $zoom = $numZoomLevels - 1 if $zoom >= $numZoomLevels; $zoom = 0 if $zoom < 0; $params{zoom_act} = $zoomOffset + $zoom; @@ -168,7 +168,7 @@ sub click_to_wgs84 { my ($self, $c, $pin_tile_x, $pin_x, $pin_tile_y, $pin_y) = @_; my $tile_x = click_to_tile($pin_tile_x, $pin_x); my $tile_y = click_to_tile($pin_tile_y, $pin_y); - my $zoom = MIN_ZOOM_LEVEL + (defined $c->req->params->{zoom} ? $c->req->params->{zoom} : 3); + my $zoom = MIN_ZOOM_LEVEL + (defined $c->get_param('zoom') ? $c->get_param('zoom') : 3); my ($lat, $lon) = tile_to_latlon($tile_x, $tile_y, $zoom); return ( $lat, $lon ); } diff --git a/perllib/FixMyStreet/Map/OSM/MapQuest.pm b/perllib/FixMyStreet/Map/OSM/MapQuest.pm index 2c3cbaf00..4fc8ba57d 100644 --- a/perllib/FixMyStreet/Map/OSM/MapQuest.pm +++ b/perllib/FixMyStreet/Map/OSM/MapQuest.pm @@ -33,4 +33,8 @@ sub base_tile_url { return 'mqcdn.com/tiles/1.0.0/map/'; } +sub copyright { + 'Data, imagery and map information provided by <a href="http://www.mapquest.com/">MapQuest</a> <img src="http://developer.mapquest.com/content/osm/mq_logo.png" />, <a href="http://openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://opendatacommons.org/licenses/odbl/">ODbL</a>' +} + 1; diff --git a/perllib/FixMyStreet/Map/OSM/StreetView.pm b/perllib/FixMyStreet/Map/OSM/StreetView.pm index c70dd93aa..87c335dd6 100644 --- a/perllib/FixMyStreet/Map/OSM/StreetView.pm +++ b/perllib/FixMyStreet/Map/OSM/StreetView.pm @@ -22,6 +22,7 @@ sub base_tile_url { } sub copyright { + 'Contains OS data © Crown copyright and database right 2013'; } 1; diff --git a/perllib/FixMyStreet/Map/OSM/TonerLite.pm b/perllib/FixMyStreet/Map/OSM/TonerLite.pm new file mode 100644 index 000000000..543cd6002 --- /dev/null +++ b/perllib/FixMyStreet/Map/OSM/TonerLite.pm @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# +# FixMyStreet:Map::OSM::TonerLite +# OSM TonerLite maps on FixMyStreet. +# +# Map tiles by <http://stamen.com> Stamen Design, +# under <http://creativecommons.org/licenses/by/3.0>CC BY 3.0. +# Data by <http://openstreetmap.org> OpenStreetMap, +# under <http://www.openstreetmap.org/copyright> ODbL. +# +# Copyright (c) 2014 UK Citizens Online Democracy. All rights reserved. +# Email: hakim@mysociety.org; WWW: http://www.mysociety.org/ + +package FixMyStreet::Map::OSM::TonerLite; +use base 'FixMyStreet::Map::OSM'; + +use strict; + +sub map_type { 'OpenLayers.Layer.Stamen' } + +sub map_template { 'osm-toner-lite' } + +sub copyright { + 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.' +} + +sub map_tiles { + my ( $self, %params ) = @_; + my ( $x, $y, $z ) = ( $params{x_tile}, $params{y_tile}, $params{zoom_act} ); + return [ + "https://stamen-tiles-a.a.ssl.fastly.net/toner-lite/$z/" . ($x - 1) . "/" . ($y - 1) . ".png", + "https://stamen-tiles-b.a.ssl.fastly.net/toner-lite/$z/$x/" . ($y - 1) . ".png", + "https://stamen-tiles-c.a.ssl.fastly.net/toner-lite/$z/" . ($x - 1) . "/$y.png", + "https://stamen-tiles-d.a.ssl.fastly.net/toner-lite/$z/$x/$y.png", + ]; +} + +1; diff --git a/perllib/FixMyStreet/Map/Zurich.pm b/perllib/FixMyStreet/Map/Zurich.pm index d667a4701..9b01f2978 100644 --- a/perllib/FixMyStreet/Map/Zurich.pm +++ b/perllib/FixMyStreet/Map/Zurich.pm @@ -45,13 +45,13 @@ sub display_map { my ($self, $c, %params) = @_; # Map centre may be overridden in the query string - $params{latitude} = Utils::truncate_coordinate($c->req->params->{lat} + 0) - if defined $c->req->params->{lat}; - $params{longitude} = Utils::truncate_coordinate($c->req->params->{lon} + 0) - if defined $c->req->params->{lon}; + $params{latitude} = Utils::truncate_coordinate($c->get_param('lat') + 0) + if defined $c->get_param('lat'); + $params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0) + if defined $c->get_param('lon'); - my $zoom = defined $c->req->params->{zoom} - ? $c->req->params->{zoom} + 0 + my $zoom = defined $c->get_param('zoom') + ? $c->get_param('zoom') + 0 : $c->stash->{page} eq 'report' ? DEFAULT_ZOOM+1 : DEFAULT_ZOOM; @@ -159,7 +159,7 @@ sub click_to_wgs84 { my ($self, $c, $pin_tile_x, $pin_x, $pin_tile_y, $pin_y) = @_; my $tile_x = click_to_tile($pin_tile_x, $pin_x); my $tile_y = click_to_tile($pin_tile_y, $pin_y); - my $zoom = (defined $c->req->params->{zoom} ? $c->req->params->{zoom} : DEFAULT_ZOOM); + my $zoom = (defined $c->get_param('zoom') ? $c->get_param('zoom') : DEFAULT_ZOOM); my ($lat, $lon) = tile_to_latlon($tile_x, $tile_y, $zoom); return ( $lat, $lon ); } diff --git a/perllib/FixMyStreet/Roles/Extra.pm b/perllib/FixMyStreet/Roles/Extra.pm new file mode 100644 index 000000000..f815a3e9a --- /dev/null +++ b/perllib/FixMyStreet/Roles/Extra.pm @@ -0,0 +1,193 @@ +package FixMyStreet::Roles::Extra; +use Moose::Role; + +=head1 NAME + +FixMyStreet::Roles::Extra - role for accessing {extra} field + +=head1 SYNOPSIS + +This is to applied to a DB class like Problem or Contacts that has a rich {extra} field: + + use Moose; + with 'FixMyStreet::Roles::Extra'; + +(NB: there is actually a little more boilerplate, because DBIC doesn't actually +inherit from Moose, see ::Problem for an example.) + +Then: + + $contact->set_extra_fields( + { name => 'pothole_size', ... }, + { name => 'pothole_shape, ... } ); + my $metas = $contact->get_extra_fields(); + +And + + # e.g. for sites like Zurich (but handled gracefully otherwise) + $problem->set_extra_metadata( overdue => 1 ); + if ($problem->get_extra_metadata( 'overdue')) { ... } + +=head1 METHODS + +=head2 set_extra_metadata + + $problem->set_extra_metadata( overdue => 1); + +=cut + +sub set_extra_metadata { + my ($self, $key, $value) = @_; + my $extra = $self->get_extra(); + + $self->extra({ %$extra, $key => $value }); +}; + +=head2 set_extra_metadata_if_undefined + + $problem->set_extra_metadata_if_undefined( overdue => 1); + # as above, but won't set if, for example 'overdue' is already set to 0 + +=cut + +sub set_extra_metadata_if_undefined { + my ($self, $key, $value) = @_; + my $extra = $self->get_extra(); + + return if defined $extra->{$key}; + $self->extra({ %$extra, $key => $value }); +}; + +=head2 unset_extra_metadata + + $contact->unset_extra_metadata('photo_required'); + +=cut + +sub unset_extra_metadata { + my ($self, $key) = @_; + my $extra = $self->get_extra(); + + return 1 unless exists $extra->{$key}; + delete $extra->{$key}; + $self->extra($extra); +}; + +=head2 get_extra_metadata + + my $overdue = $problem->get_extra_metadata('overdue'); + +=cut + +sub get_extra_metadata { + my ($self, $key) = @_; + my $extra = $self->get_extra(); + + return $extra->{$key}; +}; + +=head2 get_extra_metadata_as_hashref + + my $hashref = $contact->get_extra_metadata_as_hashref(); + +=cut + +my $META_FIELD = '_fields'; + +sub get_extra_metadata_as_hashref { + my ($self) = @_; + my $extra = $self->get_extra(); + + my %extra = %$extra; + delete $extra{$META_FIELD}; + return \%extra; +} + +=head2 get_extra_fields + + my $metas = $problem->get_extra_fields(); + +=cut + +sub get_extra_fields { + my ($self) = @_; + my $extra = $self->get_extra(); + + return $extra->{$META_FIELD} ||= do { + my $metas = []; + $self->extra({ %$extra, $META_FIELD => $metas }); + $metas; + }; +} + +=head2 set_extra_fields + + $problem->set_extra_fields( { ... }, { ... } ); + +=cut + +sub set_extra_fields { + my ($self, @fields) = @_; + my $extra = $self->get_extra(); + + $self->extra({ %$extra, $META_FIELD => \@fields }); +} + +=head2 push_extra_fields + + $problem->push_extra_fields( { ... } ); + +like set_extra_fields, but pushes the new fields onto the end of the existing list. + +=cut + +sub push_extra_fields { + my ($self, @fields) = @_; + my $extra = $self->get_extra(); + + my $existing = $self->get_extra_fields; + + $self->extra({ %$extra, $META_FIELD => [ @$existing, @fields ] }); +} + +=head1 HELPER METHODS + +For internal use mostly. + +=head2 dirty_extra + +Set the extra field as dirty. (e.g. signalling that the DB object should be +updated). + +=cut + +sub dirty_extra { + my $self = shift; + $self->make_column_dirty('extra'); + return 1; +} + +=head2 get_extra + +Get the extra data. If this is not set, then returns a {} + +=cut + +sub get_extra { + my ($self) = @_; + my $extra = $self->extra or do { + my $extra = {}; + $self->extra({}); + return $extra; + }; + + if (ref $extra eq 'ARRAY') { + # upgrade layout transparently + $extra = { $META_FIELD => $extra }; + $self->extra($extra); + } + + return $extra; +} + +1; diff --git a/perllib/FixMyStreet/SendReport.pm b/perllib/FixMyStreet/SendReport.pm index 40e76ef72..9967b0663 100644 --- a/perllib/FixMyStreet/SendReport.pm +++ b/perllib/FixMyStreet/SendReport.pm @@ -23,8 +23,7 @@ sub should_skip { return 0 unless $row->send_fail_count; - my $tz = DateTime::TimeZone->new( name => 'local' ); - my $now = DateTime->now( time_zone => $tz ); + my $now = DateTime->now( time_zone => FixMyStreet->local_time_zone ); my $diff = $now - $row->send_fail_timestamp; my $backoff = $row->send_fail_count > 1 ? 30 : 5; diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm index 4507091c7..fa4d437fb 100644 --- a/perllib/FixMyStreet/SendReport/Email.pm +++ b/perllib/FixMyStreet/SendReport/Email.pm @@ -18,9 +18,6 @@ sub build_recipient_list { my ($body_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note ); - $body_email = essex_contact($row->latitude, $row->longitude) if $body->areas->{2225}; - $body_email = oxfordshire_contact($row->latitude, $row->longitude) if $body->areas->{2237} && $body_email eq 'SPECIAL'; - unless ($confirmed) { $all_confirmed = 0; $note = 'Body ' . $row->bodies_str . ' deleted' @@ -112,30 +109,6 @@ sub send { return $result; } -# Essex has different contact addresses depending upon the district -# Might be easier if we start storing in the db all areas covered by a point -# Will do for now :) -sub essex_contact { - my $district = _get_district_for_contact(@_); - my $email; - $email = 'eastarea' if $district == 2315 || $district == 2312; - $email = 'midarea' if $district == 2317 || $district == 2314 || $district == 2316; - $email = 'southarea' if $district == 2319 || $district == 2320 || $district == 2310; - $email = 'westarea' if $district == 2309 || $district == 2311 || $district == 2318 || $district == 2313; - die "Returned district $district which is not in Essex!" unless $email; - return "highways.$email\@essexcc.gov.uk"; -} - -# Oxfordshire has different contact addresses depending upon the district -sub oxfordshire_contact { - my $district = _get_district_for_contact(@_); - my $email; - $email = 'northernarea' if $district == 2419 || $district == 2420 || $district == 2421; - $email = 'southernarea' if $district == 2417 || $district == 2418; - die "Returned district $district which is not in Oxfordshire!" unless $email; - return "$email\@oxfordshire.gov.uk"; -} - sub _get_district_for_contact { my ( $lat, $lon ) = @_; my $district = diff --git a/perllib/FixMyStreet/SendReport/London.pm b/perllib/FixMyStreet/SendReport/London.pm deleted file mode 100644 index 2a1ebc1c3..000000000 --- a/perllib/FixMyStreet/SendReport/London.pm +++ /dev/null @@ -1,113 +0,0 @@ -package FixMyStreet::SendReport::London; - -use Moose; - -BEGIN { extends 'FixMyStreet::SendReport'; } - -use Digest::MD5; -use FindBin; -use LWP::UserAgent; -use LWP::Simple; - -use Utils; - -sub construct_message { - my %h = @_; - return <<EOF, -A user of FixMyStreet has submitted the following report of a local -problem that they believe might require your attention. - -Subject: $h{title} - -Details: $h{detail} - -$h{fuzzy}, or to provide an update on the problem, please visit the -following link: - -$h{url} - -$h{closest_address} -Yours, -The FixMyStreet team -EOF -} - -sub send { - return if mySociety::Config::get('STAGING_SITE'); - my ( $self, $row, $h ) = @_; - - $h->{message} = construct_message( %$h ); - my $phone = $h->{phone}; - my $mobile = ''; - if ($phone && $phone =~ /^\s*07/) { - $mobile = $phone; - $phone = ''; - } - my ($first, $last) = $h->{name} =~ /^(\S*)(?: (.*))?$/; - my %params = ( - Key => mySociety::Config::get('LONDON_REPORTIT_KEY'), - Signature => Digest::MD5::md5_hex( $h->{confirmed} . mySociety::Config::get('LONDON_REPORTIT_SECRET') ), - Type => Utils::london_categories()->{$h->{category}}, - RequestDate => $h->{confirmed}, - RequestMethod => 'Web', - ExternalId => $h->{url}, - 'Customer.Title' => '', - 'Customer.FirstName' => $first, - 'Customer.Surname' => $last, - 'Customer.Email' => $h->{email}, - 'Customer.Phone' => $phone, - 'Customer.Mobile' => $mobile, - 'ProblemDescription' => $h->{message}, - ); - if ($h->{used_map}) { - $params{'Location.Latitude'} = $h->{latitude}; - $params{'Location.Longitude'} = $h->{longitude}; - } elsif (mySociety::PostcodeUtil::is_valid_postcode($h->{query})) { - # Didn't use map, and entered postcode, so use that. - $params{'Location.Postcode'} = $h->{query}; - } else { - # Otherwise, lat/lon is all we have, even if it's wrong. - $params{'Location.Latitude'} = $h->{latitude}; - $params{'Location.Longitude'} = $h->{longitude}; - } - if ($h->{has_photo}) { - $params{'Document1.Name'} = 'Photograph'; - $params{'Document1.MimeType'} = 'image/jpeg'; - $params{'Document1.URL'} = $h->{image_url}; - $params{'Document1.URLPublic'} = 'true'; - } - my $browser = LWP::UserAgent->new; - my $response = $browser->post( mySociety::Config::get('LONDON_REPORTIT_URL'), \%params ); - my $out = $response->content; - if ($response->code ne 200) { - $self->error( "Failed to post $h->{id} to London API, response was " . $response->code . " $out" ); - return 1; - } - my ($id) = $out =~ /<caseid>(.*?)<\/caseid>/; - my ($org) = $out =~ /<organisation>(.*?)<\/organisation>/; - my ($team) = $out =~ /<team>(.*?)<\/team>/; - - $org = london_lookup($org); - $row->external_id( $id ); - $row->external_body( $org ); - $row->external_team( $team ); - $self->success(1); - return 0; -} - -sub london_lookup { - my $org = shift || ''; - my $str = "Unknown ($org)"; - open(FP, "$FindBin::Bin/../data/dft.csv"); - while (<FP>) { - /^(.*?),(.*)/; - if ($org eq $1) { - $str = $2; - last; - } - } - close FP; - return $str; -} - -1; diff --git a/perllib/FixMyStreet/SendReport/NI.pm b/perllib/FixMyStreet/SendReport/NI.pm deleted file mode 100644 index c60643566..000000000 --- a/perllib/FixMyStreet/SendReport/NI.pm +++ /dev/null @@ -1,37 +0,0 @@ -package FixMyStreet::SendReport::NI; - -use Moose; - -BEGIN { extends 'FixMyStreet::SendReport::Email'; } - -sub build_recipient_list { - my ( $self, $row, $h ) = @_; - - my $all_confirmed = 1; - foreach my $body ( @{ $self->bodies } ) { - my $contact = FixMyStreet::App->model("DB::Contact")->find( { - deleted => 0, - body_id => $body->id, - category => $row->category - } ); - - my ($email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note ); - - unless ($confirmed) { - $all_confirmed = 0; - $email = 'N/A' unless $email; - } - - my $name = $body->name; - if ( $email =~ /^roads.([^@]*)\@drdni/ ) { - $name = "Roads Service (\u$1)"; - $h->{bodies_name} = $name; - $row->external_body( 'Roads Service' ); - } - push @{ $self->to }, [ $email, $name ]; - } - - return $all_confirmed && @{$self->to}; -} - -1; diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm index c064eeef5..fa216466e 100644 --- a/perllib/FixMyStreet/SendReport/Open311.pm +++ b/perllib/FixMyStreet/SendReport/Open311.pm @@ -13,6 +13,7 @@ use Readonly; Readonly::Scalar my $COUNCIL_ID_OXFORDSHIRE => 2237; Readonly::Scalar my $COUNCIL_ID_WARWICKSHIRE => 2243; +Readonly::Scalar my $COUNCIL_ID_GREENWICH => 2493; sub send { my $self = shift; @@ -37,7 +38,7 @@ sub send { $revert = 1; - my $extra = $row->extra; + my $extra = $row->get_extra_fields(); if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) { push @$extra, { name => 'northing', value => $h->{northing} }; push @$extra, { name => 'easting', value => $h->{easting} }; @@ -49,33 +50,31 @@ sub send { push @$extra, { name => 'email_alerts_requested', value => 'FALSE' }; # always false as can never request them push @$extra, { name => 'requested_datetime', value => DateTime::Format::W3CDTF->format_datetime($row->confirmed->set_nanosecond(0)) }; push @$extra, { name => 'email', value => $row->user->email }; - $row->extra( $extra ); - - $always_send_latlong = 0; - $send_notpinpointed = 1; - $use_service_as_deviceid = 0; - # make sure we have last_name attribute present in row's extra, so # it is passed correctly to Bromley as attribute[] if ( $row->cobrand ne 'bromley' ) { my ( $firstname, $lastname ) = ( $row->name =~ /(\w+)\.?\s+(.+)/ ); push @$extra, { name => 'last_name', value => $lastname }; } + $row->set_extra_fields( @$extra ); + $always_send_latlong = 0; + $send_notpinpointed = 1; + $use_service_as_deviceid = 0; $extended_desc = 0; } # extra Oxfordshire fields: send nearest street, postcode, northing and easting, and the FMS id if ( $row->bodies_str =~ /\b(?:$COUNCIL_ID_OXFORDSHIRE|$COUNCIL_ID_WARWICKSHIRE)\b/ ) { - my $extra = $row->extra; + my $extra = $row->get_extra_fields; push @$extra, { name => 'external_id', value => $row->id }; push @$extra, { name => 'closest_address', value => $h->{closest_address} } if $h->{closest_address}; if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) { push @$extra, { name => 'northing', value => $h->{northing} }; push @$extra, { name => 'easting', value => $h->{easting} }; } - $row->extra( $extra ); + $row->set_extra_fields( @$extra ); if ($row->bodies_str =~ /$COUNCIL_ID_OXFORDSHIRE/) { $extended_desc = 'oxfordshire'; @@ -129,9 +128,9 @@ sub send { $revert = 1; } - if ($row->cobrand eq 'fixmybarangay') { - # FixMyBarangay endpoints expect external_id as an attribute, as do Oxfordshire - $row->extra( [ { 'name' => 'external_id', 'value' => $row->id } ] ); + if ($row->cobrand eq 'fixmybarangay' || $row->bodies_str =~ /$COUNCIL_ID_GREENWICH/) { + # FixMyBarangay endpoints expect external_id as an attribute, as do Greenwich + $row->set_extra_fields( { 'name' => 'external_id', 'value' => $row->id } ); $revert = 1; } diff --git a/perllib/FixMyStreet/SendReport/Refused.pm b/perllib/FixMyStreet/SendReport/Refused.pm new file mode 100644 index 000000000..d71fc5c2c --- /dev/null +++ b/perllib/FixMyStreet/SendReport/Refused.pm @@ -0,0 +1,7 @@ +package FixMyStreet::SendReport::Refused; + +use Moose; + +BEGIN { extends 'FixMyStreet::SendReport::Noop'; } + +1; diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index 72a6810bc..bd2ca4096 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -151,23 +151,21 @@ sub delete_user { ->find( { email => $email_or_user } ); # If no user found we can't delete them - if ( !$user ) { - ok( 1, "No user found to delete" ); - return 1; - } + return 1 unless $user; + + $mech->get('/auth/sign_out'); - $mech->log_out_ok; for my $p ( $user->problems ) { - ok( $_->delete, "delete comment " . $_->text ) for $p->comments; - ok( $_->delete, "delete questionnaire " . $_->id ) for $p->questionnaires; - ok( $p->delete, "delete problem " . $p->title ); + $p->comments->delete; + $p->questionnaires->delete; + $p->delete; } for my $a ( $user->alerts ) { $a->alerts_sent->delete; - ok( $a->delete, "delete alert " . $a->alert_type ); + $a->delete; } - ok( $_->delete, "delete comment " . $_->text ) for $user->comments; - ok $user->delete, "delete test user " . $user->email; + $_->delete for $user->comments; + $user->delete; return 1; } @@ -322,6 +320,7 @@ sub extract_problem_meta { my $result = scraper { process 'div#side p em', 'meta', 'TEXT'; process '.problem-header p em', 'meta', 'TEXT'; + process '.problem-header p.report_meta_info', 'meta', 'TEXT'; } ->scrape( $mech->response ); @@ -559,6 +558,21 @@ sub delete_problems_for_body { } } +sub create_contact_ok { + my $self = shift; + my %contact_params = ( + confirmed => 1, + deleted => 0, + editor => 'Test', + whenedited => \'current_timestamp', + note => 'Created for test', + @_ + ); + my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create( \%contact_params ); + ok $contact, 'found/created contact ' . $contact->category;; + return $contact; +} + sub create_body_ok { my $self = shift; my ( $area_id, $name, %extra ) = @_; diff --git a/perllib/Open311.pm b/perllib/Open311.pm index c02618725..58ae96bc2 100644 --- a/perllib/Open311.pm +++ b/perllib/Open311.pm @@ -150,19 +150,15 @@ sub _populate_service_request_params { $params->{deviceid} = $problem->service; } - if ( $problem->extra ) { - my $extras = $problem->extra; - - for my $attr ( @$extras ) { - my $attr_name = $attr->{name}; - if ( $attr_name eq 'first_name' || $attr_name eq 'last_name' ) { - $params->{$attr_name} = $attr->{value} if $attr->{value}; - next if $attr_name eq 'first_name'; - } - $attr_name =~ s/fms_extra_//; - my $name = sprintf( 'attribute[%s]', $attr_name ); - $params->{ $name } = $attr->{value}; + for my $attr ( @{$problem->get_extra_fields} ) { + my $attr_name = $attr->{name}; + if ( $attr_name eq 'first_name' || $attr_name eq 'last_name' ) { + $params->{$attr_name} = $attr->{value} if $attr->{value}; + next if $attr_name eq 'first_name'; } + $attr_name =~ s/fms_extra_//; + my $name = sprintf( 'attribute[%s]', $attr_name ); + $params->{ $name } = $attr->{value}; } return $params; diff --git a/perllib/Open311/PopulateServiceList.pm b/perllib/Open311/PopulateServiceList.pm index 0f6e32893..e4f0b8357 100644 --- a/perllib/Open311/PopulateServiceList.pm +++ b/perllib/Open311/PopulateServiceList.pm @@ -265,11 +265,7 @@ sub _add_meta_to_contact { @meta = grep { ! $ignore{ $_->{ code } } } @meta; } - if ( @meta ) { - $contact->extra( \@meta ); - } else { - $contact->extra( undef ); - } + $contact->set_extra_fields(@meta); $contact->update; } diff --git a/perllib/Utils.pm b/perllib/Utils.pm index 7f95d1f5a..21a7311f2 100644 --- a/perllib/Utils.pm +++ b/perllib/Utils.pm @@ -25,12 +25,13 @@ Takes the WGS84 latitude and longitude and returns OSGB36 easting and northing. =cut sub convert_latlon_to_en { - my ( $latitude, $longitude ) = @_; + my ( $latitude, $longitude, $coordsyst ) = @_; + $coordsyst ||= 'G'; local $SIG{__WARN__} = sub { die $_[0] }; my ( $easting, $northing ) = mySociety::Locale::in_gb_locale { - mySociety::GeoUtil::wgs84_to_national_grid( $latitude, $longitude, 'G' ); + mySociety::GeoUtil::wgs84_to_national_grid( $latitude, $longitude, $coordsyst ); }; return ( $easting, $northing ); @@ -90,35 +91,6 @@ sub truncate_coordinate { return $out; } -sub london_categories { - return { - 'Abandoned vehicle' => 'AbandonedVehicle', - 'Car parking' => 'Parking', - 'Dangerous structure' => 'DangerousStructure', - 'Dead animal' => 'DeadAnimal', - 'Dumped cylinder' => 'DumpedCylinder', - 'Dumped rubbish' => 'DumpedRubbish', - 'Flyposting' => 'FlyPosting', - 'Graffiti' => 'Graffiti', - 'Litter bin' => 'LitterBin', - 'Public toilet' => 'PublicToilet', - 'Refuse collection' => 'RefuseCollection', - 'Road or pavement defect' => 'Road', - 'Road or pavement obstruction' => 'Obstruction', - 'Skip problem' => 'Skip', - 'Street cleaning' => 'StreetCleaning', - 'Street drainage' => 'StreetDrainage', - 'Street furniture' => 'StreetFurniture', - 'Street needs gritting' => 'StreetGritting', - 'Street lighting' => 'StreetLighting', - 'Street sign' => 'StreetSign', - 'Traffic light' => 'TrafficLight', - 'Tree (dangerous)' => 'DangerousTree', - 'Tree (fallen branches)' => 'FallenTree', - 'Untaxed vehicle' => 'UntaxedVehicle', - }; -} - sub barnet_categories { # The values here are KBIDs from Barnet's system: see bin/send-reports for formatting. # They are no longer used since Barnet switched to email for delivery of problem reports. @@ -225,7 +197,7 @@ sub prettify_dt { $type ||= ''; $type = 'short' if $type eq '1'; - my $now = DateTime->now( time_zone => FixMyStreet->config('TIME_ZONE') || 'local' ); + my $now = DateTime->now( time_zone => FixMyStreet->time_zone || FixMyStreet->local_time_zone ); my $tt = ''; return "[unknown time]" unless ref $dt; |