#!/usr/bin/perl -w # index.pl: # Main code for BCI - not really. # # Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org. WWW: http://www.mysociety.org # # $Id: index.cgi,v 1.17 2006-09-22 14:30:16 matthew Exp $ use strict; require 5.8.0; # Horrible boilerplate to set up appropriate library paths. use FindBin; use lib "$FindBin::Bin/../perllib"; use lib "$FindBin::Bin/../../perllib"; use Error qw(:try); use LWP::Simple; use RABX; use Page; use mySociety::Config; BEGIN { mySociety::Config::set_file("$FindBin::Bin/../conf/general"); } use mySociety::MaPit; mySociety::MaPit::configure(); use mySociety::Web qw(ent NewURL); # Main code for index.cgi sub main { my $q = shift; my $out = ''; if ($q->param('submit_problem')) { $out = submit_problem($q); } elsif ($q->param('submit_comment')) { $out = submit_comment($q); } elsif ($q->param('map')) { $out = display_form($q); } elsif ($q->param('pc')) { $out = display($q); } elsif ($q->param('id')) { $out = display_problem($q); } else { $out = front_page(); } print Page::header($q, ''); print $out; print Page::footer($q); } Page::do_fastcgi(\&main); # Display front page sub front_page { my $error = shift; my $out = ''; $out .= '

' . $error . '

' if ($error); $out .= <Report a problem with refuse, recycling, fly tipping, pest control, abandoned vechicles, street lighting, graffiti, street cleaning, litter or similar to your local council. Or view reports other people have made.

This is currently only for Newham and Lewisham Councils

It’s very simple:

  1. Enter a postcode;
  2. Locate the problem on a high-scale map;
  3. Enter details of the problem;
  4. Submit to your council.

Enter your postcode:

EOF return $out; } sub submit_comment { my $q = shift; my @vars = qw(id name email comment updates); my %input = map { $_ => $q->param($_) } @vars; my @errors; push(@errors, 'Please enter a comment') unless $input{comment}; push(@errors, 'Please enter your name') unless $input{name}; push(@errors, 'Please enter your email') unless $input{email}; return display_problem($q, @errors) if (@errors); # Send confirmation email my $out = <Nearly Done! Now check your email...

The confirmation email may take a few minutes to arrive — please be patient.

If you use web-based email or have 'junk mail' filters, you may wish to check your bulk/spam mail folders: sometimes, our messages are marked that way.

You must now click on the link within the email we've just sent you -
if you do not, your comment will not be posted.

(Don't worry - we'll hang on to your comment while you're checking your email.)

EOF return $out; } sub submit_problem { my $q = shift; my @vars = qw(title detail name email pc easting northing updates); my %input = map { $_ => $q->param($_) } @vars; my @errors; push(@errors, 'Please enter a title') unless $input{title}; push(@errors, 'Please enter some details') unless $input{detail}; push(@errors, 'Please enter your name') unless $input{name}; push(@errors, 'Please enter your email') unless $input{email}; return display_form($q, @errors) if (@errors); # Send confirmation email my $out = <Nearly Done! Now check your email...

The confirmation email may take a few minutes to arrive — please be patient.

If you use web-based email or have 'junk mail' filters, you may wish to check your bulk/spam mail folders: sometimes, our messages are marked that way.

You must now click on the link within the email we've just sent you -
if you do not, your problem will not be posted on the site.

(Don't worry - we'll hang on to your message while you're checking your email.)

EOF return $out; } sub display_form { my ($q, @errors) = @_; my ($pin_x, $pin_y, $pin_tile_x, $pin_tile_y); my @vars = qw(title detail name email updates pc easting northing x y skipped); my %input = map { $_ => $q->param($_) || '' } @vars; my %input_h = map { $_ => $q->param($_) ? ent($q->param($_)) : '' } @vars; 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$/; } return display($q) unless $input{skipped} || ($pin_x && $pin_y) || ($input{easting} && $input{northing}); my $out = ''; $out .= '

Reporting a problem

'; if ($input{skipped}) { $out .= '

Please fill in the form below with details of the problem:

'; } else { my ($px, $py, $easting, $northing); if ($pin_x && $pin_y) { $pin_x -= 254 while $pin_x > 254; $pin_y -= 254 while $pin_y > 254; $pin_y = 254 - $pin_y; $px = 508 - ($pin_tile_x - $input{x})*254 - $pin_x; $py = 508 - ($pin_tile_y - $input{y})*254 - $pin_y; $easting = 5000/31 * ($pin_tile_x + $pin_x/254); $northing = 5000/31 * ($pin_tile_y + $pin_y/254); } else { $px = 508 - ($input{easting} / (5000/31) - $input{x})*254; $py = 508 - ($input{northing} / (5000/31) - $input{y})*254; $easting = $input_h{easting}; $northing = $input_h{northing}; } $out .= display_map($q, $input{x}, $input{y}, 1, 0); $out .= '

You have located the problem at the location marked with a yellow pin on the map. If this is not the correct location, simply click on the map again.

Please fill in details of the problem below:

'; $out .= display_pin($px, $py, 'yellow'); $out .= ' '; } if (@errors) { $out .= '
  • ' . join('
  • ', @errors) . '
'; } my $updates = $input{updates} ? ' checked' : ''; $out .= <
(work out from details?)
EOF $out .= display_map_end(1); return $out; } sub display { my $q = shift; my $pc = $q->param('pc'); my($error, $x, $y, $name); try { ($name, $x, $y) = postcode_check($q, $pc); } catch RABX::Error with { my $e = shift; if ($e->value() == mySociety::MaPit::BAD_POSTCODE || $e->value() == mySociety::MaPit::POSTCODE_NOT_FOUND) { $error = 'That postcode was not recognised, sorry.'; } else { $error = $e; } }; return front_page($error) if ($error); my $out = "

$name

"; $out .= display_map($q, $x, $y, 1, 1); $out .= <To report a problem, please select the location of it on the map below. Use the arrows to the left of the map to scroll around.

Or just view existing problems that have already been reported.

EOF $out .= <

Current problems

    EOF my %current = ( 1 => 'Broken lamppost', 2 => 'Shards of glass', 3 => 'Abandoned car', ); my %fixed = ( 4 => 'Broken lamppost', 5 => 'Shards of glass', 6 => 'Abandoned car', ); foreach (sort keys %current) { my $px = int(rand(508)); my $py = int(rand(508)); $out .= '
  • '; $out .= display_pin($px, $py); $out .= $current{$_}; $out .= '
  • '; } $out .= <

    Recently fixed problems

    '; $out .= display_map_end(1); $out .= <If you cannot see a map – if you have images turned off, or are using a text only browser, for example – please skip this step and we will ask you to describe the location of your problem instead.

    EOF return $out; } sub display_pin { my ($px, $py, $col) = @_; $col = 'red' unless $col; return '' if ($px<0 || $px>508 || $py<0 || $py>508); return 'Problem'; } sub display_problem { my ($q, @errors) = @_; my @vars = qw(id name email comment updates x y); my %input = map { $_ => $q->param($_) } @vars; my %input_h = map { $_ => $q->param($_) ? ent($q->param($_)) : '' } @vars; $input{x} += 0; $input{y} += 0; # Get all information from database my $title = 'Broken lamppost'; my $desc = 'The bulb has clearly gone. This is a shame, as there are no other lampposts nearby, so the whole area is dark.'; my $name = 'Matthew Somerville'; my $time = '5.30pm, yesterday'; my $easting = 541120; my $northing = 185450; my $x = $easting / (5000/31); my $y = $northing / (5000/31); my $x_tile = $input{x} || int($x); my $y_tile = $input{y} || int($y); my $created = time(); my $py = 508 - 254 * ($y - $y_tile); my $px = 508 - 254 * ($x - $x_tile); my $out = ''; $out .= "

    $title

    "; $out .= display_map($q, $x_tile, $y_tile, 0, 1); # Display information about problem $out .= '

    '; $out .= display_pin($px, $py); $out .= 'Reported by ' . $name . ' at ' . $time; $out .= '

    '; $out .= ent($desc); $out .= '

    '; # Display comments my $comments = ''; if ($comments) { $out .= '

    Comments

    '; } $out .= '

    Add Comment

    '; if (@errors) { $out .= '
    • ' . join('
    • ', @errors) . '
    '; } my $updates = $input{updates} ? ' checked' : ''; $out .= <
    (needed?)
    EOF $out .= display_map_end(0); return $out; } # display_map Q X Y TYPE COMPASS # X,Y is bottom left tile of 2x2 grid # TYPE is 1 if the map is clickable, 0 if not # COMPASS is 1 to show the compass, 0 to not sub display_map { my ($q, $x, $y, $type, $compass) = @_; my $url = mySociety::Config::get('TILES_URL'); my $tiles = $url . $x . '-' . ($x+1) . ',' . $y . '-' . ($y+1) . '/RABX'; $tiles = LWP::Simple::get($tiles); my $tileids = RABX::unserialise($tiles); my $tl = $x . '.' . ($y+1); my $tr = ($x+1) . '.' . ($y+1); my $bl = $x . '.' . $y; my $br = ($x+1) . '.' . $y; my $tl_src = $url . $tileids->[0][0]; my $tr_src = $url . $tileids->[0][1]; my $bl_src = $url . $tileids->[1][0]; my $br_src = $url . $tileids->[1][1]; my $out = ''; my $img_type; if ($type) { my $pc_enc = ent($q->param('pc')); $out .= < EOF $img_type = '
    $img_type id="2.2" name="tile_$tl" src="$tl_src" style="top:0px; left:0px;">$img_type id="3.2" name="tile_$tr" src="$tr_src" style="top:0px; left:254px;">
    $img_type id="2.3" name="tile_$bl" src="$bl_src" style="top:254px; left:0px;">$img_type id="3.3" name="tile_$br" src="$br_src" style="top:254px; left:254px;">
    EOF $out .= Page::compass($q, $x, $y) if $compass; $out .= '
    '; return $out; } sub display_map_end { my ($type) = @_; my $out = '
    '; $out .= '' if ($type); return $out; } # Checks the postcode is in one of the two London boroughs # and sets default X/Y co-ordinates if not provided in the URI sub postcode_check { my ($q, $pc) = @_; my $areas; $areas = mySociety::MaPit::get_voting_areas($pc); # Check for London Borough throw RABX::Error("I'm afraid that postcode isn't in our covered area.", 123456) if (!$areas || !$areas->{LBO}); # Check for Lewisham or Newham my $lbo = $areas->{LBO}; throw RABX::Error("I'm afraid that postcode isn't in our covered London boroughs.", 123457) unless ($lbo == 2510 || $lbo == 2492); my $area_info = mySociety::MaPit::get_voting_area_info($lbo); my $name = $area_info->{name}; my $x = $q->param('x') || 0; my $y = $q->param('y') || 0; $x += 0; $y += 0; if (!$x && !$y) { my $location = mySociety::MaPit::get_location($pc); my $northing = $location->{northing}; my $easting = $location->{easting}; $x = int($easting / (5000/31)); $y = int($northing/ (5000/31)); } return ($name, $x, $y); }