#!/usr/bin/perl -w -I../perllib
#
# index.cgi:
# Main code for FixMyStreet
#
# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
# Email: matthew@mysociety.org. WWW: http://www.mysociety.org
use strict;
use Standard;
use Utils;
use Encode;
use Error qw(:try);
use File::Slurp;
use RABX;
use CGI::Carp;
use POSIX qw(strcoll);
use URI::Escape;
# use Carp::Always;
use CrossSell;
use FixMyStreet::Geocode;
use mySociety::AuthToken;
use mySociety::Config;
use mySociety::DBHandle qw(select_all);
use mySociety::EmailUtil;
use mySociety::Locale;
use mySociety::MaPit;
use mySociety::PostcodeUtil;
use mySociety::Random;
use mySociety::VotingArea;
use mySociety::Web qw(ent NewURL);
use Utils;
sub debug (@) {
return;
my ( $format, @args ) = @_;
warn sprintf $format, map { defined $_ ? $_ : 'undef' } @args;
}
BEGIN {
if (!dbh()->selectrow_array('select secret from secret for update of secret')) {
local dbh()->{HandleError};
dbh()->do('insert into secret (secret) values (?)', {}, unpack('h*', mySociety::Random::random_bytes(32)));
}
dbh()->commit();
}
# Main code for index.cgi
sub main {
my $q = shift;
if (my $partial = $q->param('partial_token')) {
# We have a partial token, so fetch data from database and see where we're at.
my $id = mySociety::AuthToken::retrieve('partial', $partial);
if ($id) {
my @row = dbh()->selectrow_array(
"select latitude, longitude, name, email, title, (photo is not null) as has_photo, phone, detail
from problem where id=? and state='partial'", {}, $id);
if (@row) {
$q->param('anonymous', 1);
$q->param('submit_map', 1);
$q->param('latitude', $row[0]);
$q->param('longitude', $row[1]);
$q->param('name', $row[2]);
$q->param('email', $row[3]);
$q->param('title', $row[4]);
$q->param('has_photo', $row[5]);
$q->param('phone', $row[6]);
$q->param('detail', $row[7]);
$q->param('partial', $partial);
} else {
my $base = mySociety::Config::get('BASE_URL');
print $q->redirect(-location => $base . '/report/' . $id);
}
}
}
my $out = '';
my %params;
if ($q->param('submit_problem')) {
$params{title} = _('Submitting your report');
($out, %params) = submit_problem($q);
} elsif ($q->param('submit_update')) {
$params{title} = _('Submitting your update');
($out, %params) = submit_update($q);
} elsif ($q->param('submit_map')) {
($out, %params) = display_form($q, [], {});
$params{title} = _('Reporting a problem');
} elsif ($q->param('id')) {
($out, %params) = display_problem($q, [], {});
$params{title} .= ' - ' . _('Viewing a problem');
} elsif ($q->param('pc') || ($q->param('x') && $q->param('y')) || ($q->param('lat') || $q->param('lon'))) {
($out, %params) = display_location($q);
$params{title} = _('Viewing a location');
} elsif ($q->param('e') && $q->param('n')) {
($out, %params) = redirect_from_osgb_to_wgs84($q);
} else {
($out, %params) = front_page($q);
}
print Page::header($q, %params);
print $out;
my %footerparams;
$footerparams{js} = $params{js} if $params{js};
$footerparams{template} = $params{template} if $params{template};
print Page::footer($q, %footerparams);
}
Page::do_fastcgi(\&main);
# Display front page
sub front_page {
my ($q, $error, $status_code) = @_;
my $pc_h = ent($q->param('pc') || '');
# Look up various cobrand things
my $cobrand = Page::get_cobrand($q);
my $cobrand_form_elements = Cobrand::form_elements($cobrand, 'postcodeForm', $q);
my $form_action = Cobrand::url($cobrand, '/', $q);
my $question = Cobrand::enter_postcode_text($cobrand, $q);
$question = _("Enter a nearby GB postcode, or street name and area")
unless $question;
my %params = ('context' => 'front-page');
$params{status_code} = $status_code if $status_code;
my %vars = (
error => $error || '',
pc_h => $pc_h,
cobrand_form_elements => $cobrand_form_elements,
form_action => $form_action,
question => "$question:",
);
my $cobrand_front_page = Page::template_include('front-page', $q, Page::template_root($q), %vars);
return ($cobrand_front_page, %params) if $cobrand_front_page;
my $out = '
' . _('Report, view, or discuss local problems') . '';
my $subhead = _('(like graffiti, fly tipping, broken paving slabs, or street lighting)');
$out .= ' ' . $subhead . '' if $subhead ne ' ';
$out .= '
';
#if (my $url = mySociety::Config::get('IPHONE_URL')) {
# my $getiphone = _("Get FixMyStreet on your iPhone");
# my $new = _("New!");
# if ($q->{site} eq 'fixmystreet') {
# $out .= <
#
#$getiphone
#
#EOF
# }
#}
$out .= '
' . $error . '
' if ($error);
# Add pretty commas for display
$out .= '
EOF
$out .= $q->h2(_('How to report a problem'));
$out .= $q->ol(
$q->li($question),
$q->li(_('Locate the problem on a map of the area')),
$q->li(_('Enter details of the problem')),
$q->li(_('We send it to the council on your behalf'))
);
$out .= Cobrand::front_stats(Page::get_cobrand($q), $q);
$out .= <
EOF
my $recent_photos = Cobrand::recent_photos(Page::get_cobrand($q), 3);
my $probs = Cobrand::recent(Page::get_cobrand($q));
if (@$probs || $recent_photos){
$out .= '
';
$out .= $q->h2(_('Photos of recent reports')) . $recent_photos if $recent_photos;
$out .= $q->h2(_('Recently reported problems')) . '
';
}
return ($out, %params);
}
sub submit_update {
my $q = shift;
my @vars = qw(id name rznvy update fixed upload_fileid add_alert);
my %input = map { $_ => $q->param($_) || '' } @vars;
my @errors;
my %field_errors;
my $fh = $q->upload('photo');
if ($fh) {
my $err = Page::check_photo($q, $fh);
push @errors, $err if $err;
}
$field_errors{update} = _('Please enter a message') unless $input{update} =~ /\S/;
$input{name} = undef unless $input{name} =~ /\S/;
if ($input{rznvy} !~ /\S/) {
$field_errors{email} = _('Please enter your email');
} elsif (!mySociety::EmailUtil::is_valid_email($input{rznvy})) {
$field_errors{email} = _('Please enter a valid email');
}
my $image;
if ($fh) {
try {
$image = Page::process_photo($fh);
} catch Error::Simple with {
my $e = shift;
push(@errors, sprintf(_("That image doesn't appear to have uploaded correctly (%s), please try again."), $e));
};
}
if ($input{upload_fileid}) {
open FP, mySociety::Config::get('UPLOAD_CACHE') . $input{upload_fileid};
$image = join('', );
close FP;
}
return display_problem($q, \@errors, \%field_errors) if (@errors || scalar(keys(%field_errors)));
my $cobrand = Page::get_cobrand($q);
my $cobrand_data = Cobrand::extra_update_data($cobrand, $q);
my $id = dbh()->selectrow_array("select nextval('comment_id_seq');");
Utils::workaround_pg_bytea("insert into comment
(id, problem_id, name, email, website, text, state, mark_fixed, photo, lang, cobrand, cobrand_data)
values (?, ?, ?, ?, '', ?, 'unconfirmed', ?, ?, ?, ?, ?)", 7,
$id, $input{id}, $input{name}, $input{rznvy}, $input{update},
$input{fixed} ? 't' : 'f', $image, $mySociety::Locale::lang, $cobrand, $cobrand_data);
my %h = ();
$h{update} = $input{update};
$h{name} = $input{name} ? $input{name} : _("Anonymous");
my $base = Page::base_url_with_lang($q, undef, 1);
$h{url} = $base . '/C/' . mySociety::AuthToken::store('update', { id => $id, add_alert => $input{add_alert} } );
dbh()->commit();
my $out = Page::send_email($q, $input{rznvy}, $input{name}, 'update', %h);
return $out;
}
sub submit_problem {
my $q = shift;
my @vars = qw(council title detail name email phone pc skipped anonymous category partial upload_fileid latitude longitude);
my %input = map { $_ => scalar $q->param($_) } @vars;
for (qw(title detail)) {
$input{$_} = lc $input{$_} if $input{$_} !~ /[a-z]/;
$input{$_} = ucfirst $input{$_};
$input{$_} =~ s/\b(dog\s*)shit\b/$1poo/ig;
$input{$_} =~ s/\b(porta)\s*([ck]abin|loo)\b/[$1ble $2]/ig;
$input{$_} =~ s/kabin\]/cabin\]/ig;
}
my @errors;
my %field_errors;
my $cobrand = Page::get_cobrand($q);
# If in UK and we have a lat,lon coocdinate check it is in UK
if ( $input{latitude} && mySociety::Config::get('COUNTRY') eq 'GB' ) {
try {
Utils::convert_latlon_to_en( $input{latitude}, $input{longitude} );
} catch Error::Simple with {
my $e = shift;
push @errors, "We had a problem with the supplied co-ordinates - outside the UK?";
};
}
my $fh = $q->upload('photo');
if ($fh) {
my $err = Page::check_photo($q, $fh);
$field_errors{photo} = $err if $err;
}
$input{council} = 2260 if $q->{site} eq 'scambs'; # All reports go to S. Cambs
push(@errors, _('No council selected')) unless ($input{council} && $input{council} =~ /^(?:-1|[\d,]+(?:\|[\d,]+)?)$/);
$field_errors{title} = _('Please enter a subject') unless $input{title} =~ /\S/;
$field_errors{detail} = _('Please enter some details') unless $input{detail} =~ /\S/;
if ($input{name} !~ /\S/) {
$field_errors{name} = _('Please enter your name');
} elsif (length($input{name}) < 5 || $input{name} !~ /\s/ || $input{name} =~ /\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i) {
$field_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');
}
if ($input{email} !~ /\S/) {
$field_errors{email} = _('Please enter your email');
} elsif (!mySociety::EmailUtil::is_valid_email($input{email})) {
$field_errors{email} = _('Please enter a valid email');
}
if ($input{category} && $input{category} eq _('-- Pick a category --')) {
$field_errors{category} = _('Please choose a category');
$input{category} = '';
} elsif ($input{category} && $input{category} eq _('-- Pick a property type --')) {
$field_errors{category} = _('Please choose a property type');
$input{category} = '';
}
return display_form($q, \@errors, \%field_errors) if (@errors || scalar keys %field_errors); # Short circuit
my $areas;
if (defined $input{latitude} && defined $input{longitude}) {
my $mapit_query = "4326/$input{longitude},$input{latitude}";
$areas = mySociety::MaPit::call( 'point', $mapit_query );
if ($input{council} =~ /^[\d,]+(\|[\d,]+)?$/) {
my $no_details = $1 || '';
my @area_types = Cobrand::area_types($cobrand);
my %va = map { $_ => 1 } @area_types;
my %councils;
foreach (keys %$areas) {
$councils{$_} = 1 if $va{$areas->{$_}->{type}};
}
my @input_councils = split /,|\|/, $input{council};
foreach (@input_councils) {
if (!$councils{$_}) {
push(@errors, _('That location is not part of that council'));
last;
}
}
if ($no_details) {
$input{council} =~ s/\Q$no_details\E//;
@input_councils = split /,/, $input{council};
}
# Check category here, won't be present if council is -1
my @valid_councils = @input_councils;
if ($input{category} && $q->{site} ne 'emptyhomes') {
my $categories = select_all("select area_id from contacts
where deleted='f' and area_id in ("
. $input{council} . ') and category = ?', $input{category});
$field_errors{category} = _('Please choose a category') unless @$categories;
@valid_councils = map { $_->{area_id} } @$categories;
foreach my $c (@valid_councils) {
if ($no_details =~ /$c/) {
push(@errors, _('We have details for that council'));
$no_details =~ s/,?$c//;
}
}
}
$input{council} = join(',', @valid_councils) . $no_details;
}
$areas = ',' . join(',', sort keys %$areas) . ',';
} elsif (defined $input{latitude} || defined $input{longitude}) {
push(@errors, _('Somehow, you only have one co-ordinate. Please try again.'));
} else {
push(@errors, _("You haven't specified any sort of co-ordinates. Please try again."));
}
my $image;
if ($fh) {
try {
$image = Page::process_photo($fh);
} catch Error::Simple with {
my $e = shift;
$field_errors{photo} = sprintf(_("That image doesn't appear to have uploaded correctly (%s), please try again."), $e);
};
}
if ($input{upload_fileid}) {
open FP, mySociety::Config::get('UPLOAD_CACHE') . $input{upload_fileid};
$image = join('', );
close FP;
}
return display_form($q, \@errors, \%field_errors) if (@errors || scalar keys %field_errors);
delete $input{council} if $input{council} eq '-1';
my $used_map = $input{skipped} ? 'f' : 't';
$input{category} = _('Other') unless $input{category};
my ($id, $out);
my $cobrand_data = Cobrand::extra_problem_data($cobrand, $q);
if (my $token = $input{partial}) {
my $id = mySociety::AuthToken::retrieve('partial', $token);
if ($id) {
dbh()->do("update problem set postcode=?, latitude=?, longitude=?, title=?, detail=?,
name=?, email=?, phone=?, state='confirmed', council=?, used_map='t',
anonymous=?, category=?, areas=?, cobrand=?, cobrand_data=?, confirmed=ms_current_timestamp(),
lastupdate=ms_current_timestamp() where id=?", {}, $input{pc}, $input{latitude}, $input{longitude},
$input{title}, $input{detail}, $input{name}, $input{email},
$input{phone}, $input{council}, $input{anonymous} ? 'f' : 't',
$input{category}, $areas, $cobrand, $cobrand_data, $id);
Utils::workaround_pg_bytea('update problem set photo=? where id=?', 1, $image, $id)
if $image;
dbh()->commit();
$out = $q->p(sprintf(_('You have successfully confirmed your report and you can now view it on the site.'), "/report/$id"));
my $display_advert = Cobrand::allow_crosssell_adverts($cobrand);
if ($display_advert) {
$out .= CrossSell::display_advert($q, $input{email}, $input{name});
}
} else {
$out = $q->p('There appears to have been a problem updating the details of your report.
Please let us know what went on and we\'ll look into it.');
}
} else {
$id = dbh()->selectrow_array("select nextval('problem_id_seq');");
Utils::workaround_pg_bytea("insert into problem
(id, postcode, latitude, longitude, title, detail, name,
email, phone, photo, state, council, used_map, anonymous, category, areas, lang, cobrand, cobrand_data)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'unconfirmed', ?, ?, ?, ?, ?, ?, ?, ?)", 10,
$id, $input{pc}, $input{latitude}, $input{longitude}, $input{title},
$input{detail}, $input{name}, $input{email}, $input{phone}, $image,
$input{council}, $used_map, $input{anonymous} ? 'f': 't', $input{category},
$areas, $mySociety::Locale::lang, $cobrand, $cobrand_data);
my %h = ();
$h{title} = $input{title};
$h{detail} = $input{detail};
$h{name} = $input{name};
my $base = Page::base_url_with_lang($q, undef, 1);
$h{url} = $base . '/P/' . mySociety::AuthToken::store('problem', $id);
dbh()->commit();
$out = Page::send_email($q, $input{email}, $input{name}, 'problem', %h);
}
return $out;
}
sub display_form {
my ($q, $errors, $field_errors) = @_;
my @errors = @$errors;
my %field_errors = %{$field_errors};
my $cobrand = Page::get_cobrand($q);
push @errors, _('There were problems with your report. Please see below.') if (scalar keys %field_errors);
my ($pin_x, $pin_y, $pin_tile_x, $pin_tile_y) = (0,0,0,0);
my @vars = qw(title detail name email phone pc latitude longitude x y skipped council anonymous partial upload_fileid);
my %input = ();
my %input_h = ();
foreach my $key (@vars) {
my $val = $q->param($key);
$input{$key} = defined($val) ? $val : ''; # '0' is valid for longitude
$input_h{$key} = ent( $input{$key} );
}
# Convert lat/lon to easting/northing if given
# if ($input{lat}) {
# try {
# ($input{easting}, $input{northing}) = mySociety::GeoUtil::wgs84_to_national_grid($input{lat}, $input{lon}, 'G');
# $input_h{easting} = $input{easting};
# $input_h{northing} = $input{northing};
# } catch Error::Simple with {
# my $e = shift;
# push @errors, "We had a problem with the supplied co-ordinates - outside the UK?";
# };
# }
# Get tile co-ordinates if map clicked
($input{x}) = $input{x} =~ /^(\d+)/; $input{x} ||= 0;
($input{y}) = $input{y} =~ /^(\d+)/; $input{y} ||= 0;
my @ps = $q->param;
foreach (@ps) {
($pin_tile_x, $pin_tile_y, $pin_x) = ($1, $2, $q->param($_)) if /^tile_(\d+)\.(\d+)\.x$/;
$pin_y = $q->param($_) if /\.y$/;
}
# We need either a map click, an E/N, to be skipping the map, or be filling in a partial form
return display_location($q, @errors)
unless ($pin_x && $pin_y)
|| ($input{latitude} && $input{longitude})
|| ($input{skipped} && $input{pc})
|| ($input{partial} && $input{pc});
# Work out some co-ordinates from whatever we've got
my ($latitude, $longitude);
if ($input{skipped}) {
# Map is being skipped
if ( length $input{latitude} && length $input{longitude} ) {
$latitude = $input{latitude};
$longitude = $input{longitude};
} else {
my ( $lat, $lon, $error ) =
FixMyStreet::Geocode::lookup( $input{pc}, $q );
$latitude = $lat;
$longitude = $lon;
}
} elsif ($pin_x && $pin_y) {
# tilma map was clicked on
($latitude, $longitude) = FixMyStreet::Map::click_to_wgs84($pin_tile_x, $pin_x, $pin_tile_y, $pin_y);
} elsif ( $input{partial} && $input{pc} && !length $input{latitude} && !length $input{longitude} ) {
my $error;
try {
($latitude, $longitude, $error) = FixMyStreet::Geocode::lookup($input{pc}, $q);
} catch Error::Simple with {
$error = shift;
};
return FixMyStreet::Geocode::list_choices($error, '/', $q) if ref($error) eq 'ARRAY';
return front_page($q, $error) if $error;
} else {
# Normal form submission
$latitude = $input_h{latitude};
$longitude = $input_h{longitude};
}
# Look up councils and do checks for the point we've got
my @area_types = Cobrand::area_types($cobrand);
# XXX: I think we want in_gb_locale around the next line, needs testing
my $all_councils = mySociety::MaPit::call('point', "4326/$longitude,$latitude", type => \@area_types);
# Let cobrand do a check
my ($success, $error_msg) = Cobrand::council_check($cobrand, { all_councils => $all_councils }, $q, 'submit_problem');
if (!$success) {
return front_page($q, $error_msg);
}
if (mySociety::Config::get('COUNTRY') eq 'GB') {
# Ipswich & St Edmundsbury are responsible for everything in their areas, not Suffolk
delete $all_councils->{2241} if $all_councils->{2446} || $all_councils->{2443};
# Norwich is responsible for everything in its areas, not Norfolk
delete $all_councils->{2233} if $all_councils->{2391};
} elsif (mySociety::Config::get('COUNTRY') eq 'NO') {
# Oslo is both a kommune and a fylke, we only want to show it once
delete $all_councils->{301} if $all_councils->{3};
}
return display_location($q, _('That spot does not appear to be covered by a council.
If you have tried to report an issue past the shoreline, for example,
please specify the closest point on land.')) unless %$all_councils;
# Look up categories for this council or councils
my $category = '';
my (%council_ok, @categories);
my $categories = select_all("select area_id, category from contacts
where deleted='f' and area_id in (" . join(',', keys %$all_councils) . ')');
if ($q->{site} ne 'emptyhomes') {
@$categories = sort { strcoll($a->{category}, $b->{category}) } @$categories;
foreach (@$categories) {
$council_ok{$_->{area_id}} = 1;
next if $_->{category} eq _('Other');
push @categories, $_->{category};
}
if ($q->{site} eq 'scambs') {
@categories = Page::scambs_categories();
}
if (@categories) {
@categories = (_('-- Pick a category --'), @categories, _('Other'));
$category = _('Category:');
}
} else {
foreach (@$categories) {
$council_ok{$_->{area_id}} = 1;
}
@categories = (_('-- Pick a property type --'), _('Empty house or bungalow'),
_('Empty flat or maisonette'), _('Whole block of empty flats'),
_('Empty office or other commercial'), _('Empty pub or bar'),
_('Empty public building - school, hospital, etc.'));
$category = _('Property type:');
}
$category = $q->label({'for'=>'form_category'}, $category) .
$q->popup_menu(-name=>'category', -values=>\@categories, -id=>'form_category',
-attributes=>{id=>'form_category'})
if $category;
# Work out what help text to show, depending on whether we have council details
my @councils = keys %council_ok;
my $details;
if (@councils == scalar keys %$all_councils) {
$details = 'all';
} elsif (@councils == 0) {
$details = 'none';
} else {
$details = 'some';
}
# Forms that allow photos need a different enctype
my $allow_photo_upload = Cobrand::allow_photo_upload($cobrand);
my $enctype = '';
if ($allow_photo_upload) {
$enctype = ' enctype="multipart/form-data"';
}
my %vars;
$vars{input_h} = \%input_h;
$vars{field_errors} = \%field_errors;
if ($input{skipped}) {
my $cobrand_form_elements = Cobrand::form_elements($cobrand, 'mapSkippedForm', $q);
my $form_action = Cobrand::url($cobrand, '/', $q);
$vars{form_start} = <
$cobrand_form_elements
EOF
} else {
my $type;
if ($allow_photo_upload) {
$type = 2;
} else {
$type = 1;
}
$vars{form_start} = FixMyStreet::Map::display_map($q,
latitude => $latitude, longitude => $longitude,
type => $type,
pins => [ [ $latitude, $longitude, 'purple' ] ],
);
my $partial_id;
if (my $token = $input{partial}) {
$partial_id = mySociety::AuthToken::retrieve('partial', $token);
if ($partial_id) {
$vars{form_start} .= $q->p({id=>'unknown'}, 'Please note your report has
not yet been sent. Choose a category
and add further information below, then submit.');
}
}
$vars{text_located} = $q->p(_('You have located the problem at the point marked with a purple pin on the map.
If this is not the correct location, simply click on the map again. '));
}
$vars{page_heading} = $q->h1(_('Reporting a problem'));
if ($details eq 'all') {
my $council_list = join('' . _(' or ') . '', map { $_->{name} } values %$all_councils);
if ($q->{site} eq 'emptyhomes'){
$vars{text_help} = '
' . sprintf(_('All the information you provide here will be sent to %s.
On the site, we will show the subject and details of the problem, plus your
name if you give us permission.'), $council_list);
} else {
$vars{text_help} = '
' . sprintf(_('All the information you provide here will be sent to %s.
The subject and details of the problem will be public, plus your
name if you give us permission.'), $council_list);
}
$vars{text_help} .= '';
} elsif ($details eq 'some') {
my $e = Cobrand::contact_email($cobrand);
my %councils = map { $_ => 1 } @councils;
my @missing;
foreach (keys %$all_councils) {
push @missing, $_ unless $councils{$_};
}
my $n = @missing;
my $list = join(_(' or '), map { $all_councils->{$_}->{name} } @missing);
$vars{text_help} = '
' . _('All the information you provide here will be sent to') . ' '
. join('' . _(' or ') . '', map { $all_councils->{$_}->{name} } @councils)
. '. ';
$vars{text_help} .= _('The subject and details of the problem will be public, plus your name if you give us permission.');
$vars{text_help} .= ' ' . mySociety::Locale::nget(
'We do not yet have details for the other council that covers this location.',
'We do not yet have details for the other councils that cover this location.',
$n
);
$vars{text_help} .= ' ' . sprintf(_("You can help us by finding a contact email address for local problems for %s and emailing it to us at %s."), $list, $e, $e);
$vars{text_help} .= '';
} else {
my $e = Cobrand::contact_email($cobrand);
my $list = join(_(' or '), map { $_->{name} } values %$all_councils);
my $n = scalar keys %$all_councils;
if ($q->{site} ne 'emptyhomes') {
$vars{text_help} = '
';
$vars{text_help} .= mySociety::Locale::nget(
'We do not yet have details for the council that covers this location.',
'We do not yet have details for the councils that cover this location.',
$n
);
$vars{text_help} .= _("If you submit a problem here the subject and details of the problem will be public, but the problem will not be reported to the council.");
$vars{text_help} .= sprintf(_("You can help us by finding a contact email address for local problems for %s and emailing it to us at %s."), $list, $e, $e);
} else {
$vars{text_help} = '
'
. _('We do not yet have details for the council that covers this location.')
. ' '
. _("If you submit a report here it will be left on the site, but not reported to the council – please still leave your report, so that we can show to the council the activity in their area.");
}
$vars{text_help} .= '';
}
if ($input{skipped}) {
$vars{text_help} .= $q->p(_('Please fill in the form below with details of the problem,
and describe the location as precisely as possible in the details box.'));
} elsif ($q->{site} eq 'scambs') {
$vars{text_help} .= '
Please fill in details of the problem below. We won\'t be able
to help unless you leave as much detail as you can, so please describe the exact location of
the problem (e.g. on a wall), what it is, how long it has been there, a description (and a
photo of the problem if you have one), etc.';
} elsif ($q->{site} eq 'emptyhomes') {
$vars{text_help} .= $q->p(_(<p(_('Please fill in details of the problem below. The council won\'t be able
to help unless you leave as much detail as you can, so please describe the exact location of
the problem (e.g. on a wall), what it is, how long it has been there, a description (and a
photo of the problem if you have one), etc.'));
} else {
$vars{text_help} .= $q->p(_('Please fill in details of the problem below.'));
}
$vars{text_help} .= '
';
if (@errors) {
$vars{errors} = '
' . join('
', @errors) . '
';
}
$vars{anon} = ($input{anonymous}) ? ' checked' : ($input{title} ? '' : ' checked');
$vars{form_heading} = $q->h2(_('Empty property details form')) if $q->{site} eq 'emptyhomes';
$vars{subject_label} = _('Subject:');
$vars{detail_label} = _('Details:');
$vars{photo_label} = _('Photo:');
$vars{name_label} = _('Name:');
$vars{email_label} = _('Email:');
$vars{phone_label} = _('Phone:');
$vars{optional} = _('(optional)');
if ($q->{site} eq 'emptyhomes') {
$vars{anonymous} = _('Can we show your name on the site?');
} else {
$vars{anonymous} = _('Can we show your name publicly?');
}
$vars{anonymous2} = _('(we never show your email address or phone number)');
my $partial_id;
if (my $token = $input{partial}) {
$partial_id = mySociety::AuthToken::retrieve('partial', $token);
if ($partial_id) {
$vars{partial_field} = '';
$vars{partial_field} .= '';
}
}
my $photo_input = '';
if ($allow_photo_upload) {
$photo_input = <
EOF
}
if ($partial_id && $q->param('has_photo')) {
$vars{photo_field} = "
The photo you uploaded was:
";
} else {
$vars{photo_field} = $photo_input;
}
if ($q->{site} ne 'emptyhomes') {
$vars{text_notes} =
$q->p(_("Please note:")) .
"
" .
$q->li(_("We will only use your personal information in accordance with our privacy policy.")) .
$q->li(_("Please be polite, concise and to the point.")) .
$q->li(_("Please do not be abusive — abusing your council devalues the service for all users.")) .
$q->li(_("Writing your message entirely in block capitals makes it hard to read, as does a lack of punctuation.")) .
$q->li(_("Remember that FixMyStreet is primarily for reporting physical problems that can be fixed. If your problem is not appropriate for submission via this site remember that you can contact your council directly using their own website."));
$vars{text_notes} .=
$q->li(_("FixMyStreet and the Guardian are providing this service in partnership in certain cities. In those cities, both have access to any information submitted, including names and email addresses, and will use it only to ensure the smooth running of the service, in accordance with their privacy policies."))
if mySociety::Config::get('COUNTRY') eq 'GB';
$vars{text_notes} .= "
\n";
}
%vars = (%vars,
category => $category,
map_end => FixMyStreet::Map::display_map_end(1),
url_home => Cobrand::url($cobrand, '/', $q),
submit_button => _('Submit')
);
return (Page::template_include('report-form', $q, Page::template_root($q), %vars),
robots => 'noindex,nofollow',
js => FixMyStreet::Map::header_js(),
);
}
# redirect from osgb
sub redirect_from_osgb_to_wgs84 {
my ($q) = @_;
my $e = $q->param('e');
my $n = $q->param('n');
my ( $lat, $lon ) = Utils::convert_en_to_latlon_truncated( $e, $n );
my $lat_lon_url = NewURL(
$q,
-retain => 1,
e => undef,
n => undef,
lat => $lat,
lon => $lon
);
print $q->redirect(
-location => $lat_lon_url,
-status => 301, # permanent
);
return '';
}
sub display_location {
my ($q, @errors) = @_;
my $cobrand = Page::get_cobrand($q);
my @vars = qw(pc x y lat lon all_pins no_pins);
my %input = ();
my %input_h = ();
foreach my $key (@vars) {
my $val = $q->param($key);
$input{$key} = defined($val) ? $val : ''; # '0' is valid for longitude
$input_h{$key} = ent( $input{$key} );
}
my $latitude = $input{lat};
my $longitude = $input{lon};
# X/Y referring to tiles old-school
(my $x) = $input{x} =~ /^(\d+)/; $x ||= 0;
(my $y) = $input{y} =~ /^(\d+)/; $y ||= 0;
return front_page( $q, @errors )
unless ( $x && $y )
|| $input{pc}
|| ( defined $latitude && defined $longitude );
if ( $x && $y ) {
# Convert the tile co-ordinates to real ones.
( $latitude, $longitude ) =
FixMyStreet::Map::tile_xy_to_wgs84( $x, $y );
}
elsif ( $latitude && $longitude ) {
# Don't need to do anything
}
else {
my $error;
try {
( $latitude, $longitude, $error ) =
FixMyStreet::Geocode::lookup( $input{pc}, $q );
debug 'Looked up postcode "%s": lat: "%s", lon: "%s", error: "%s"',
$input{pc}, $latitude, $longitude, $error;
}
catch Error::Simple with {
$error = shift;
};
return FixMyStreet::Geocode::list_choices( $error, '/', $q )
if ( ref($error) eq 'ARRAY' );
return front_page( $q, $error ) if $error;
}
# Check this location is okay to be displayed for the cobrand
my ($success, $error_msg) = Cobrand::council_check($cobrand, { lat => $latitude, lon => $longitude }, $q, 'display_location');
return front_page($q, $error_msg) unless $success;
# Deal with pin hiding/age
my ($hide_link, $hide_text, $all_link, $all_text, $interval);
if ($input{all_pins}) {
$all_link = NewURL($q, -retain=>1, no_pins=>undef, all_pins=>undef);
$all_text = _('Hide stale reports');
} else {
$all_link = NewURL($q, -retain=>1, no_pins=>undef, all_pins=>1);
$all_text = _('Include stale reports');
$interval = '6 months';
}
my ($on_map_all, $on_map, $around_map, $dist) = FixMyStreet::Map::map_features($q, $latitude, $longitude, $interval);
my @pins;
foreach (@$on_map_all) {
push @pins, [ $_->{latitude}, $_->{longitude}, ($_->{state} eq 'fixed' ? 'green' : 'red'), $_->{id} ];
}
my $on_list = '';
foreach (@$on_map) {
my $report_url = NewURL($q, -retain => 1, -url => '/report/' . $_->{id}, pc => undef, x => undef, 'y' => undef);
$report_url = Cobrand::url($cobrand, $report_url, $q);
$on_list .= '