diff options
author | Matthew Somerville <matthew@mysociety.org> | 2011-05-19 12:46:39 +0100 |
---|---|---|
committer | Matthew Somerville <matthew@mysociety.org> | 2011-05-19 12:46:39 +0100 |
commit | d44c6e58d1efe505006a38a62b61b1045031dd49 (patch) | |
tree | b9d453c4ca0ae8b3d869d82ec4f1607ff0d7666c | |
parent | d8534c980d298764a0956fb803e7b23f496e9a30 (diff) |
Migrate /reports page (minus RSS).
-rw-r--r-- | conf/httpd.conf | 12 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Reports.pm | 361 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Barnet.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Default.pm | 22 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/FiksGataMi.pm | 33 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 25 | ||||
-rw-r--r-- | perllib/Problems.pm | 7 | ||||
-rwxr-xr-x | templates/web/default/reports/council.html | 99 | ||||
-rwxr-xr-x | templates/web/default/reports/index.html | 35 | ||||
-rwxr-xr-x | templates/web/default/reports/ward.html | 1 | ||||
-rwxr-xr-x | templates/web/emptyhomes/reports/index.html | 33 | ||||
-rwxr-xr-x | templates/web/fiksgatami/reports/index.html | 34 | ||||
-rw-r--r-- | templates/website/reports | 12 | ||||
-rwxr-xr-x | web/reports.cgi | 341 |
15 files changed, 656 insertions, 362 deletions
diff --git a/conf/httpd.conf b/conf/httpd.conf index f1125e696..d9e6c470d 100644 --- a/conf/httpd.conf +++ b/conf/httpd.conf @@ -72,12 +72,12 @@ RewriteRule ^/rss/problems$ /rss.cgi?type=new_probl # RSS feeds for voting areas RewriteRule ^/rss/council/([0-9]+)$ /rss/reports/$1 [R=permanent,L] RewriteRule ^/report$ /reports [R=permanent,L] -RewriteRule ^/reports/([^/]+)/all$ /reports.cgi?council=$1;all=1 [QSA,L] -RewriteRule ^/reports/([^/]+)/([^/]+)$ /reports.cgi?council=$1;ward=$2 [QSA,L] -RewriteRule ^/rss/(reports|area)/([^/]+)/([^/]+)$ /reports.cgi?rss=$1;council=$2;ward=$3 [QSA,L] -RewriteRule ^/reports/([^/]+)$ /reports.cgi?council=$1 [QSA,L] +#RewriteRule ^/reports/([^/]+)/all$ /reports.cgi?council=$1;all=1 [QSA,L] +#RewriteRule ^/reports/([^/]+)/([^/]+)$ /reports.cgi?council=$1;ward=$2 [QSA,L] +#RewriteRule ^/rss/(reports|area)/([^/]+)/([^/]+)$ /reports.cgi?rss=$1;council=$2;ward=$3 [QSA,L] +#RewriteRule ^/reports/([^/]+)$ /reports.cgi?council=$1 [QSA,L] RewriteRule ^/rss/area/([0-9]+)$ /rss.cgi?type=area_problems;id=$1 [QSA,L] -RewriteRule ^/rss/(reports|area)/([^/]+)$ /reports.cgi?rss=$1;council=$2 [QSA,L] +#RewriteRule ^/rss/(reports|area)/([^/]+)$ /reports.cgi?rss=$1;council=$2 [QSA,L] # Fix incorrect RSS urls caused by my stupidity RewriteRule ^/{/rss/(.*)}$ /rss/$1 [R=permanent,L] @@ -113,7 +113,7 @@ RewriteRule ^/fun(.*) /fun.cgi$1 [L] RewriteRule ^/json(.*) /json.cgi$1 [L] RewriteRule ^/photo(.*) /photo.cgi$1 [L] RewriteRule ^/questionnaire(.*) /questionnaire.cgi$1 [L] -RewriteRule ^/reports(.*) /reports.cgi$1 [L] +# RewriteRule ^/reports(.*) /reports.cgi$1 [L] RewriteRule ^/rss(.*) /rss.cgi$1 [L] RewriteRule ^/test(.*) /test.cgi$1 [L] RewriteRule ^/tms-signup(.*) /tms-signup.cgi$1 [L] diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 1e1c6c974..ff4bb080c 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -238,6 +238,7 @@ sub generate_map_tags : Private { post => $map_links ); $c->stash->{map_end_html} = FixMyStreet::Map::display_map_end(0), + $c->stash->{map_js} = FixMyStreet::Map::header_js(); return 1; } diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm new file mode 100644 index 000000000..228d4dd60 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -0,0 +1,361 @@ +package FixMyStreet::App::Controller::Reports; +use Moose; +use namespace::autoclean; + +use Problems; +use POSIX qw(strcoll); +# use FixMyStreet::Alert; +use mySociety::MaPit; +use mySociety::VotingArea; + +BEGIN { extends 'Catalyst::Controller'; } + +=head1 NAME + +FixMyStreet::App::Controller::Reports - Catalyst Controller + +=head1 DESCRIPTION + +Catalyst Controller. + +=head1 METHODS + +=cut + +=head2 index + +Show the summary page of all reports. + +=cut + +sub index : Path : Args(0) { + my ( $self, $c ) = @_; + + $c->response->header('Cache-Control' => 'max-age=3600'); + + # Fetch all areas of the types we're interested in + my @area_types = $c->cobrand->area_types; + my $areas_info = mySociety::MaPit::call('areas', \@area_types, + min_generation => $c->cobrand->area_min_generation + ); + + # For each area, add its link and perhaps alter its name if we need to for + # places with the same name. + foreach (values %$areas_info) { + $_->{url} = $c->uri_for( '/reports/' . $c->cobrand->short_name( $_, $areas_info ) ); + if ($_->{parent_area} && $_->{url} =~ /,|%2C/) { + $_->{name} .= ', ' . $areas_info->{$_->{parent_area}}{name}; + } + } + + $c->stash->{areas_info} = $areas_info; + my @keys = sort { strcoll($areas_info->{$a}{name}, $areas_info->{$b}{name}) } keys %$areas_info; + $c->stash->{areas_info_sorted} = [ map { $areas_info->{$_} } @keys ]; + + $c->forward( 'load_problems' ); + $c->forward( 'group_problems' ); +} + +=head2 index + +Show the summary page for a particular council. + +=cut + +sub council : Path : Args(1) { + my ( $self, $c, $council ) = @_; + + $c->forward( 'council_check', [ $council ] ); + $c->forward( 'load_parent' ); + $c->forward( 'load_problems' ); + $c->forward( 'group_problems' ); + $c->forward( 'sort_problems' ); + + $c->stash->{rss_url} = '/rss/reports/' + . $c->cobrand->short_name( $c->stash->{council}, $c->stash->{areas_info} ); +} + +=head2 index + +Show the summary page for a particular ward. + +=cut + +sub ward : Path : Args(2) { + my ( $self, $c, $council, $ward ) = @_; + + $c->forward( 'council_check', [ $council ] ); + $c->forward( 'ward_check', [ $ward ] ); + $c->forward( 'load_parent' ); + $c->forward( 'load_problems' ); + $c->forward( 'group_problems' ); + $c->forward( 'sort_problems' ); + + $c->stash->{rss_url} = '/rss/reports/' + . $c->cobrand->short_name( $c->stash->{council}, $c->stash->{areas_info} ) + . '/' . $c->cobrand->short_name( $c->stash->{ward} ); +} + +#sub rss_ward : RegEx('/rss/(reports|area)') : Args(2) { +# my ( $self, $c, $council, $ward ) = @_; +# +# $c->stash->{q_council} = $council; +# $c->stash->{q_ward} = $ward; +# +#} +# +#sub rss_council : RegEx('/rss/(reports|area)') : Args(1) { +# my ( $self, $c, $council ) = @_; +# $c->stash->{rss} = $c->req->{rss}; +#} + +=head2 council_check + +This action checks the council name (or code) given in a URI exists, is valid +and so on. If it is, it stores the Area in the stash, otherwise it redirects +to the all reports page. + +=cut + +sub council_check : Private { + my ( $self, $c, $q_council ) = @_; + + $q_council =~ s/\+/ /g; + + # Manual misspelling redirect + if ($q_council =~ /^rhondda cynon taff$/i) { + my $url = $c->uri_for( '/reports/rhondda+cynon+taf' ); + $c->res->redirect( $url ); + $c->detach(); + } + + # Check cobrand specific incantations - e.g. ONS codes for UK, + # Oslo/ kommunes sharing a name in Norway + return if $c->cobrand->reports_council_check( $c, $q_council ); + + # If we're passed an ID number (don't think this is used anywhere, it + # certainly shouldn't be), just look that up on MaPit and redirect + if ($q_council =~ /^\d+$/) { + my $council = mySociety::MaPit::call('area', $q_council); + $c->detach( 'redirect_index') if $council->{error}; + $c->stash->{council} = $council; + $c->detach( 'redirect_council' ); + } + + # We must now have a string to check + my @area_types = $c->cobrand->area_types; + my $areas = mySociety::MaPit::call( 'areas', $q_council, + type => \@area_types, + min_generation => $c->cobrand->area_min_generation + ); + if (keys %$areas == 1) { + ($c->stash->{council}) = values %$areas; + return; + } else { + foreach (keys %$areas) { + if ($areas->{$_}->{name} eq $q_council || $areas->{$_}->{name} =~ /^\Q$q_council\E (Borough|City|District|County) Council$/) { + $c->stash->{council} = $areas->{$_}; + return; + } + } + } + + # No result, bad council name. + $c->detach( 'redirect_index' ); +} + +=head2 ward_check + +This action checks the ward name from a URI exists and is part of the right +parent, already found with council_check. It either stores the ward Area if +okay, or redirects to the council page if bad. +This is currently only used in the UK, hence the use of mySociety::VotingArea. + +=cut + +sub ward_check : Private { + my ( $self, $c, $ward ) = @_; + + $ward =~ s/\+/ /g; + my $council = $c->stash->{council}; + + my $qw = mySociety::MaPit::call('areas', $ward, + type => $mySociety::VotingArea::council_child_types, + min_generation => $c->cobrand->area_min_generation + ); + foreach my $id (sort keys %$qw) { + if ($qw->{$id}->{parent_area} == $council->{id}) { + $c->stash->{ward} = $qw->{$id}; + return; + } + } + # Given a false ward name + $c->detach( 'redirect_council' ); +} + +sub load_parent : Private { + my ( $self, $c ) = @_; + + my $council = $c->stash->{council}; + my $areas_info; + if ($council->{parent_area}) { + $c->stash->{areas_info} = mySociety::MaPit::call('areas', [ $council->{id}, $council->{parent_area} ]) + } else { + $c->stash->{areas_info} = { $council->{id} => $council }; + } +} + +sub load_problems : Private { + my ( $self, $c ) = @_; + + my $where = { + state => [ 'confirmed', 'fixed' ], + %{ Problems::site_restriction() } + }; + if ($c->stash->{ward}) { + $where->{areas} = { 'like', '%' . $c->stash->{ward}->{id} . '%' }; # FIXME Check this is secure + } elsif ($c->stash->{council}) { + $where->{areas} = { 'like', '%' . $c->stash->{council}->{id} . '%' }; + } + my $current_timestamp = Problems::current_timestamp(); + my $problems = $c->model('DB::Problem')->search( + $where, + { + columns => [ + 'id', 'title', 'detail', 'council', 'state', 'areas', + { duration => { extract => "epoch from $current_timestamp-lastupdate" } }, + { age => { extract => "epoch from $current_timestamp-confirmed" } }, + ], + order_by => { -desc => 'id' }, + } + ); + $c->stash->{problems} = [ $problems->all ]; + + return 1; +} + +sub group_problems : Private { + my ( $self, $c ) = @_; + + my ( %fixed, %open ); + my $re_councils = join('|', keys %{$c->stash->{areas_info}}); + foreach my $row (@{$c->stash->{problems}}) { + if (!$row->council) { + # Problem was not sent to any council, add to possible councils + while ($row->areas =~ /,($re_councils)(?=,)/g) { + add_row($row, $1, \%fixed, \%open); + } + } else { + # Add to councils it was sent to + foreach ($row->councils) { + next if $c->stash->{council} && $_ != $c->stash->{council}->{id}; + add_row($row, $_, \%fixed, \%open); + } + } + } + + $c->stash->{fixed} = \%fixed; + $c->stash->{open} = \%open; + + return 1; +} + +sub sort_problems : Private { + my ( $self, $c ) = @_; + + my $id = $c->stash->{council}->{id}; + my $fixed = $c->stash->{fixed}; + my $open = $c->stash->{open}; + + foreach (qw/new old/) { + $c->stash->{fixed}{$id}{$_} = [ sort { $a->{duration} <=> $b->{duration} } @{$fixed->{$id}{$_}} ] + if $fixed->{$id}{$_}; + } + foreach (qw/new older unknown/) { + $c->stash->{open}{$id}{$_} = [ sort { $a->{age} <=> $b->{age} } @{$open->{$id}{$_}} ] + if $open->{$id}{$_}; + } +} + +sub redirect_index : Private { + my ( $self, $c ) = @_; + my $url = '/reports'; + $c->res->redirect( $c->uri_for($url) ); +} + +sub redirect_council : Private { + my ( $self, $c ) = @_; + my $url = ''; + $url .= "/rss" if $c->stash->{rss}; + $url .= '/reports'; + $url .= '/' . $c->cobrand->short_name( $c->stash->{council} ); + $c->res->redirect( $c->uri_for($url) ); +} + +sub redirect_ward : Private { + my ( $self, $c ) = @_; + my $url = ''; + $url .= "/rss" if $c->stash->{rss}; + $url .= '/reports'; + $url .= '/' . $c->cobrand->short_name( $c->stash->{council} ); + $url .= '/' . $c->cobrand->short_name( $c->stash->{ward} ); + $c->res->redirect( $c->uri_for($url) ); +} + +sub add_row { + my ($row, $council, $fixed, $open) = @_; + my $fourweeks = 4*7*24*60*60; + my $duration = ($row->get_column('duration') > 2 * $fourweeks) ? 'old' : 'new'; + my $type = ($row->get_column('duration') > 2 * $fourweeks) + ? 'unknown' + : ($row->get_column('age') > $fourweeks ? 'older' : 'new'); + # Fixed problems are either old or new + push @{$fixed->{$council}{$duration}}, $row if $row->state eq 'fixed'; + # Open problems are either unknown, older, or new + push @{$open->{$council}{$type}}, $row if $row->state eq 'confirmed'; +} + +=head1 AUTHOR + +Matthew Somerville + +=head1 LICENSE + +Copyright (c) 2011 UK Citizens Online Democracy. All rights reserved. +Licensed under the Affero GPL. + +=cut + +__PACKAGE__->meta->make_immutable; + +1; + +# # RSS - reports for sent reports, area for all problems in area +# if ($rss && $council) { +# my $url = Page::short_name($council); +# $url .= '/' . Page::short_name($ward) if $ward; +# if ($rss eq 'area' && $area_type ne 'DIS' && $area_type ne 'CTY') { +# # Two possibilites are the same for one-tier councils, so redirect one to the other +# print $q->redirect($base_url . '/rss/reports/' . $url); +# return; +# } +# my $type = 'council_problems'; # Problems sent to a council +# my (@params, %title_params); +# $title_params{COUNCIL} = $area_name; +# push @params, $council->{id} if $rss eq 'reports'; +# push @params, $ward ? $ward->{id} : $council->{id}; +# if ($ward && $rss eq 'reports') { +# $type = 'ward_problems'; # Problems sent to a council, restricted to a ward +# $title_params{WARD} = $q_ward; +# } elsif ($rss eq 'area') { +# $title_params{NAME} = $ward ? $q_ward : $q_council; +# $type = 'area_problems'; # Problems within an area +# } +# print $q->header( -type => 'application/xml; charset=utf-8' ); +# my $xsl = Cobrand::feed_xsl($cobrand); +# my $out = FixMyStreet::Alert::generate_rss($type, $xsl, "/$url", \@params, \%title_params, $cobrand, $q); +# $out =~ s/matthew.fixmystreet/emptyhomes.matthew.fixmystreet/g if $q->{site} eq 'emptyhomes'; +# print $out; +# return; +# } + diff --git a/perllib/FixMyStreet/Cobrand/Barnet.pm b/perllib/FixMyStreet/Cobrand/Barnet.pm index 4d20d6522..eacb4ef70 100644 --- a/perllib/FixMyStreet/Cobrand/Barnet.pm +++ b/perllib/FixMyStreet/Cobrand/Barnet.pm @@ -9,7 +9,7 @@ use URI::Escape; use mySociety::VotingArea; sub site_restriction { - return ( "and council='2489'", 'barnet' ); + return ( "and council='2489'", 'barnet', { council => '2489' } ); } sub base_url { diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index e3c5ed821..7920a15d6 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -6,6 +6,7 @@ use FixMyStreet; use URI; use Carp; +use mySociety::MaPit; =head2 new @@ -111,7 +112,7 @@ empty string and site key 0 if the cobrand uses all the data. =cut -sub site_restriction { return ( "", 0 ) } +sub site_restriction { return ( "", 0, {} ) } =head2 contact_restriction @@ -793,5 +794,24 @@ sub generate_problem_banner { return $banner; } + +sub reports_council_check { + my ( $self, $c, $code ) = @_; + + if ($code =~ /^(\d\d)([a-z]{2})?([a-z]{2})?$/i) { + my $area = mySociety::MaPit::call( 'area', uc $code ); + $c->detach( 'redirect_index' ) if $area->{error}; # Given a bad/old ONS code + if (length($code) == 6) { + my $council = mySociety::MaPit::call( 'area', $area->{parent_area} ); + $c->stash->{ward} = $area; + $c->stash->{council} = $council; + $c->detach( 'redirect_ward' ); + } else { + $c->stash->{council} = $area; + $c->detach( 'redirect_council' ); + } + } +} + 1; diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm index 3981192c8..aaa5f281b 100644 --- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm +++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm @@ -5,6 +5,7 @@ use strict; use warnings; use Carp; +use mySociety::MaPit; sub set_lang_and_domain { my ( $self, $lang, $unicode, $dir ) = @_; @@ -77,4 +78,36 @@ sub short_name { } +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); + use Data::Dumper; + 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' ); + + } +} + 1; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index ca13f7130..57bbf5fb8 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -200,4 +200,29 @@ sub confirm { return 1; } +=head2 councils + +Returns an array of councils to which a report was sent. + +=cut + +sub councils { + my $self = shift; + return () unless $self->council; + (my $council = $self->council) =~ s/\|.*$//; + my @council = split /,/, $council; + return @council; +} + +=head2 url + +Returns a URL for this problem report. + +=cut + +sub url { + my $self = shift; + return "/report/" . $self->id; +} + 1; diff --git a/perllib/Problems.pm b/perllib/Problems.pm index 76ccdc677..48203b980 100644 --- a/perllib/Problems.pm +++ b/perllib/Problems.pm @@ -21,6 +21,11 @@ use mySociety::MaPit; my $site_restriction = ''; my $site_key = 0; +my $site_restriction_hash = {}; + +sub site_restriction { + return $site_restriction_hash; +} sub set_site_restriction { my $q = shift; @@ -41,7 +46,7 @@ sub set_site_restriction_with_cobrand_object { my $cobrand = shift; my $cobrand_data = $cobrand->extra_data; - ( $site_restriction, $site_key ) = + ( $site_restriction, $site_key, $site_restriction_hash ) = $cobrand->site_restriction($cobrand_data); } diff --git a/templates/web/default/reports/council.html b/templates/web/default/reports/council.html new file mode 100755 index 000000000..4067d0619 --- /dev/null +++ b/templates/web/default/reports/council.html @@ -0,0 +1,99 @@ +[% IF ward %] + [% name = "$ward.name, $council.name" + thing = loc('ward') + %] +[% ELSE %] + [% name = council.name + thing = loc('council') + %] +[% END %] + +[% INCLUDE 'header.html', + title = tprintf(loc('%s - Summary reports'), name) + context = 'reports' + rss = [ tprintf(loc('Problems within %s, FixMyStreet'), name), rss_url ] +%] + +<p><a href="[% rss_url %]"><img align="right" src="/i/feed.png" width="16" height="16" title="[% loc('RSS feed') %]" alt="[% tprintf(loc('RSS feed of problems in this %s'), thing) %]" border="0" hspace="4"></a> + +[% IF c.cobrand.all_councils_report %] + [% tprintf( loc('This is a summary of all reports for one %s.'), thing ) %] +[% ELSE %] + [% tprintf( loc('This is a summary of all reports for this %s.'), thing ) %] +[% END %] + +[%# FIXME: It should link to council from a ward page, and should have list of wards on a council page. And a map? + The reason c.req.base/path is used below is that passing undef to uri_with + in a template actually passes "", and so the key still appears in the URL. +%] + +[% IF c.req.parameters.all AND !c.cobrand.all_councils_report %] + [% tprintf( loc('You can <a href="%s">see less detail</a>.'), c.req.base _ c.req.path ) %] +[% ELSIF !c.cobrand.all_councils_report %] + [% tprintf( loc('You can <a href="%s">see more details</a>.'), c.req.uri_with( { all = 1 } ) ) %] +[% ELSIF c.req.parameters.all %] + [% tprintf( loc('You can <a href="%s">see less detail</a> or go back and <a href="/reports">show all councils</a>.'), c.req.base _ c.req.path ) %] +[% ELSE %] + [% tprintf( loc('You can <a href="%s">see more details</a> or go back and <a href="/reports">show all councils</a>.'), c.req.uri_with( { all = 1 } ) ) %] +[% END %] + +<h2>[% name %]</h2> + +<div id="col_problems"> + [% INCLUDE column + title = loc('New problems') + problems = open.${council.id}.new + %] + + [%# This doesn't really need a whole separate template %] + [% IF c.cobrand.moniker == 'emptyhomes' %] + [% + INCLUDE column + title = loc('Older problems') + problems = open.${council.id}.older.merge( open.${council.id}.unknown ) + %] + [% ELSE %] + [% INCLUDE column + title = loc('Older problems') + problems = open.${council.id}.older + %] + [% INCLUDE column + title = loc('Old problems, state unknown') + problems = open.${council.id}.unknown + %] + [% END %] +</div> + +<div id="col_fixed"> + [% INCLUDE column + title = loc('Recently fixed') + problems = fixed.${council.id}.new + %] + [% INCLUDE column + title = loc('Old fixed') + problems = fixed.${council.id}.old + %] +</div> + +[% INCLUDE 'footer.html' %] + +[% BLOCK column %] +[% IF problems %] + +<h3>[% title %]</h3> + +<ul> +[% FOREACH problem IN problems %] + <li><a href="[% c.uri_for(problem.url) %]">[% problem.title | html %]</a> + [% IF problem.councils.size > 1 %] <small>[% loc('(sent to both)') %]</small> [% END %] + [% IF c.cobrand.moniker != 'emptyhomes' %] + [% IF problem.councils.size == 0 %] <small>[% loc('(not sent to council)') %]</small> [% END %] + [% END %] + [% IF all %] <br><small>[% problem.detail %]</small> [% END %] + </li> +[% END %] +</ul> + +[% END %] +[% END %] + diff --git a/templates/web/default/reports/index.html b/templates/web/default/reports/index.html new file mode 100755 index 000000000..bb7824cad --- /dev/null +++ b/templates/web/default/reports/index.html @@ -0,0 +1,35 @@ +[% INCLUDE 'header.html', title = loc('Summary reports') %] + +<p> +[% loc('This is a summary of all reports on this site; select a particular council to see the reports sent there.') %] +[% loc('Greyed-out lines are councils that no longer exist.') %] +</p> + +<table cellpadding="3" cellspacing="1" border="0"> +<tr> +<th>[% loc('Name') %]</th> +<th>[% loc('New problems') %]</th> +<th>[% loc('Older problems') %]</th> +<th>[% loc('Old problems,<br>state unknown') %]</th> +<th>[% loc('Recently fixed') %]</th> +<th>[% loc('Older fixed') %]</th> +</tr> + +[% FOREACH area IN areas_info_sorted %] +<tr align="center" +[%- IF area.generation_high == 10 %] class="gone" +[%- ELSIF loop.count % 2 %] class="a" +[%- END -%] +> +<td align="left"><a href="[% area.url %]">[% area.name %]</a></td> +<td>[% open.${area.id}.new.size or 0 %]</td> +<td>[% open.${area.id}.older.size or 0 %]</td> +<td>[% open.${area.id}.unknown.size or 0 %]</td> +<td>[% fixed.${area.id}.new.size or 0 %]</td> +<td>[% fixed.${area.id}.old.size or 0 %]</td> +</tr> +[% END %] +</table> + +[% INCLUDE 'footer.html' %] + diff --git a/templates/web/default/reports/ward.html b/templates/web/default/reports/ward.html new file mode 100755 index 000000000..8b65ffb28 --- /dev/null +++ b/templates/web/default/reports/ward.html @@ -0,0 +1 @@ +[% INCLUDE reports/council.html %] diff --git a/templates/web/emptyhomes/reports/index.html b/templates/web/emptyhomes/reports/index.html new file mode 100755 index 000000000..13805ab43 --- /dev/null +++ b/templates/web/emptyhomes/reports/index.html @@ -0,0 +1,33 @@ +[% INCLUDE 'header.html', title = loc('Summary reports') %] + +<p> +[% loc('This is a summary of all reports on this site; select a particular council to see the reports sent there.') %] +[% loc('Greyed-out lines are councils that no longer exist.') %] +</p> + +<table cellpadding="3" cellspacing="1" border="0"> +<tr> +<th>[% loc('Name') %]</th> +<th>[% loc('New problems') %]</th> +<th>[% loc('Older problems') %]</th> +<th>[% loc('Recently fixed') %]</th> +<th>[% loc('Older fixed') %]</th> +</tr> + +[% FOREACH area IN areas_info_sorted %] +<tr align="center" +[%- IF area.generation_high == 10 %] class="gone" +[%- ELSIF loop.count % 2 %] class="a" +[%- END -%] +> +<td align="left"><a href="[% area.url %]">[% area.name %]</a></td> +<td>[% open.${area.id}.new.size or 0 %]</td> +<td>[% open.${area.id}.older.list.size + open.${area.id}.unknown.list.size %]</td> +<td>[% fixed.${area.id}.new.size or 0 %]</td> +<td>[% fixed.${area.id}.old.size or 0 %]</td> +</tr> +[% END %] +</table> + +[% INCLUDE 'footer.html' %] + diff --git a/templates/web/fiksgatami/reports/index.html b/templates/web/fiksgatami/reports/index.html new file mode 100755 index 000000000..ab8ff6381 --- /dev/null +++ b/templates/web/fiksgatami/reports/index.html @@ -0,0 +1,34 @@ +[% INCLUDE 'header.html', title = loc('Summary reports') %] + +<p> +[% loc('This is a summary of all reports on this site; select a particular council to see the reports sent there.') %] +</p> + +<table cellpadding="3" cellspacing="1" border="0"> +<tr> +<th>[% loc('Name') %]</th> +<th>[% loc('New problems') %]</th> +<th>[% loc('Older problems') %]</th> +<th>[% loc('Old problems,<br>state unknown') %]</th> +<th>[% loc('Recently fixed') %]</th> +<th>[% loc('Older fixed') %]</th> +</tr> + +[% FOREACH area IN areas_info_sorted %] +[% NEXT IF area.id == 301 %] +<tr align="center" +[%- IF loop.count % 2 %] class="a" +[%- END -%] +> +<td align="left"><a href="[% area.url %]">[% area.name %]</a></td> +<td>[% open.${area.id}.new.size or 0 %]</td> +<td>[% open.${area.id}.older.size or 0 %]</td> +<td>[% open.${area.id}.unknown.size or 0 %]</td> +<td>[% fixed.${area.id}.new.size or 0 %]</td> +<td>[% fixed.${area.id}.old.size or 0 %]</td> +</tr> +[% END %] +</table> + +[% INCLUDE 'footer.html' %] + diff --git a/templates/website/reports b/templates/website/reports deleted file mode 100644 index 2519a0301..000000000 --- a/templates/website/reports +++ /dev/null @@ -1,12 +0,0 @@ -<p><a href="{{ $rss_url }}"><img align="right" src="/i/feed.png" width="16" height="16" title="{{ $rss_title }}" alt="{{ $rss_alt }}" border="0" hspace="4"></a> {{ $summary_title }} {{ $summary_line }} - -<h2>{{ $name }}</h2> - -<div id="col_problems"> -{{ $col_problems }} -</div> - -<div id="col_fixed"> -{{ $col_fixed }} -</div> - diff --git a/web/reports.cgi b/web/reports.cgi deleted file mode 100755 index 22dbe344a..000000000 --- a/web/reports.cgi +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/perl -w -I../perllib - -# report.cgi: -# Display summary reports for FixMyStreet -# And RSS feeds for those reports etc. -# -# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. -# Email: matthew@mysociety.org. WWW: http://www.mysociety.org -# -# $Id: reports.cgi,v 1.41 2009-12-08 11:13:30 louise Exp $ - -use strict; -use Standard; -use Encode; -use POSIX qw(strcoll); -use URI::Escape; -use FixMyStreet::Alert; -use mySociety::MaPit; -use mySociety::Web qw(ent NewURL); -use mySociety::VotingArea; - -sub main { - my $q = shift; - my $all = $q->param('all') || 0; - my $rss = $q->param('rss') || ''; - my $cobrand = Page::get_cobrand($q); - - # Look up council name, if given - my $q_council = $q->param('council') || ''; - my $base_url = Cobrand::base_url($cobrand); - - # Manual misspelling redirect - if ($q_council =~ /^rhondda cynon taff$/i) { - print $q->redirect($base_url . '/reports/Rhondda+Cynon+Taf'); - return; - } - - my ($one_council, $area_type, $area_name); - if ($q_council =~ /^(\d\d)([a-z]{2})?([a-z]{2})?$/i) { - my $va_info = mySociety::MaPit::call('area', uc $q_council); - if ($va_info->{error}) { # Given a bad/old ONS code - print $q->redirect($base_url . '/reports'); - return; - } - $area_name = Page::short_name($va_info); - if (length($q_council) == 6) { - $va_info = mySociety::MaPit::call('area', $va_info->{parent_area}); - $area_name = Page::short_name($va_info) . '/' . $area_name; - } - $rss = '/rss' if $rss; - print $q->redirect($base_url . $rss . '/reports/' . $area_name); - return; - } elsif (mySociety::Config::get('COUNTRY') eq 'NO' && $q_council eq 'Oslo') { - $one_council = mySociety::MaPit::call('area', 3); - $area_type = $one_council->{type}; - $area_name = $one_council->{name}; - } elsif (mySociety::Config::get('COUNTRY') eq 'NO' && $q_council =~ /,/) { - my ($kommune, $fylke) = split /\s*,\s*/, $q_council; - my @area_types = Cobrand::area_types($cobrand); - 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}) { - $one_council = $_; - $area_type = $_->{type}; - $area_name = $_->{name}; - last; - } - } - } - if (!$one_council) { # Given a false council name - print $q->redirect($base_url . '/reports'); - return; - } - } elsif ($q_council =~ /\D/) { - my @area_types = Cobrand::area_types($cobrand); - my $areas = mySociety::MaPit::call('areas', $q_council, type => \@area_types, min_generation=>Cobrand::area_min_generation($cobrand) ); - if (keys %$areas == 1) { - ($one_council) = values %$areas; - $area_type = $one_council->{type}; - $area_name = $one_council->{name}; - } else { - foreach (keys %$areas) { - if ($areas->{$_}->{name} eq $q_council || $areas->{$_}->{name} =~ /^\Q$q_council\E (Borough|City|District|County) Council$/) { - $one_council = $areas->{$_}; - $area_type = $areas->{$_}->{type}; - $area_name = $q_council; - } - } - } - if (!$one_council) { # Given a false council name - print $q->redirect($base_url . '/reports'); - return; - } - } elsif ($q_council =~ /^\d+$/) { - my $va_info = mySociety::MaPit::call('area', $q_council); - if ($va_info->{error}) { - print $q->redirect($base_url . '/reports'); - return; - } - print $q->redirect($base_url . '/reports/' . Page::short_name($va_info)); - return; - } - $all = 0 unless $one_council; - - # Look up ward name, if given - my $q_ward = $q->param('ward') || ''; - my $ward; - if ($one_council && $q_ward) { - my $qw = mySociety::MaPit::call('areas', $q_ward, type => $mySociety::VotingArea::council_child_types, - min_generation => Cobrand::area_min_generation($cobrand)); - foreach my $id (sort keys %$qw) { - if ($qw->{$id}->{parent_area} == $one_council->{id}) { - $ward = $qw->{$id}; - last; - } - } - if (!$ward) { # Given a false ward name - print $q->redirect($base_url . '/reports/' . Page::short_name($one_council)); - return; - } - } - - # RSS - reports for sent reports, area for all problems in area - if ($rss && $one_council) { - my $url = Page::short_name($one_council); - $url .= '/' . Page::short_name($ward) if $ward; - if ($rss eq 'area' && $area_type ne 'DIS' && $area_type ne 'CTY') { - # Two possibilites are the same for one-tier councils, so redirect one to the other - print $q->redirect($base_url . '/rss/reports/' . $url); - return; - } - my $type = 'council_problems'; # Problems sent to a council - my (@params, %title_params); - $title_params{COUNCIL} = $area_name; - push @params, $one_council->{id} if $rss eq 'reports'; - push @params, $ward ? $ward->{id} : $one_council->{id}; - if ($ward && $rss eq 'reports') { - $type = 'ward_problems'; # Problems sent to a council, restricted to a ward - $title_params{WARD} = $q_ward; - } elsif ($rss eq 'area') { - $title_params{NAME} = $ward ? $q_ward : $q_council; - $type = 'area_problems'; # Problems within an area - } - print $q->header( -type => 'application/xml; charset=utf-8' ); - my $xsl = Cobrand::feed_xsl($cobrand); - my $out = FixMyStreet::Alert::generate_rss($type, $xsl, "/$url", \@params, \%title_params, $cobrand, $q); - $out =~ s/matthew.fixmystreet/emptyhomes.matthew.fixmystreet/g if $q->{site} eq 'emptyhomes'; - print $out; - return; - } - - my $areas_info; - if ($one_council) { - $areas_info = mySociety::MaPit::call('areas', [ $one_council->{id}, $one_council->{parent_area} ]) - if $one_council->{parent_area}; - $areas_info = { $one_council->{id} => $one_council } - unless $areas_info; - } else { - # Show all councils on main report page - my @area_types = Cobrand::area_types($cobrand); - $areas_info = mySociety::MaPit::call('areas', \@area_types, min_generation=>Cobrand::area_min_generation($cobrand) ); - } - - my $problems = Problems::council_problems( - $ward ? $ward->{id} : undef, - $one_council ? $one_council->{id} : undef - ); - - my (%fixed, %open); - my $re_councils = join('|', keys %$areas_info); - foreach my $row (@$problems) { - if (!$row->{council}) { - # Problem was not sent to any council, add to possible councils - while ($row->{areas} =~ /,($re_councils)(?=,)/g) { - add_row($row, 0, $1, \%fixed, \%open); - } - } else { - # Add to councils it was sent to - $row->{council} =~ s/\|.*$//; - my @council = split /,/, $row->{council}; - foreach (@council) { - next if $one_council && $_ != $one_council->{id}; - add_row($row, scalar @council, $_, \%fixed, \%open); - } - } - } - - if (!$one_council) { - print Page::header($q, title=>_('Summary reports'), expires=>'+1h'); - print $q->p( - _('This is a summary of all reports on this site; select a particular council to see the reports sent there.'), ' ', - _('Greyed-out lines are councils that no longer exist.') - ); - my $c = 0; - print '<table cellpadding="3" cellspacing="1" border="0">'; - print '<tr><th>' . _('Name') . '</th><th>' . _('New problems') . '</th><th>' . _('Older problems') . '</th>'; - if ($q->{site} ne 'emptyhomes') { - print '<th>' . _('Old problems,<br>state unknown') . '</th>'; - } - print '<th>' . _('Recently fixed') . '</th><th>' . _('Older fixed') . '</th></tr>'; - foreach (sort { strcoll($areas_info->{$a}->{name}, $areas_info->{$b}->{name}) } keys %$areas_info) { - next if mySociety::Config::get('COUNTRY') eq 'NO' && $_ eq 301; # Only want one Oslo - print '<tr align="center"'; - ++$c; - if (mySociety::Config::get('COUNTRY') eq 'GB' && $areas_info->{$_}->{generation_high} == 10) { - print ' class="gone"'; - } elsif ($c%2) { - print ' class="a"'; - } - my $url = Page::short_name($areas_info->{$_}, $areas_info); - my $cobrand_url = Cobrand::url($cobrand, "/reports/$url", $q); - print '><td align="left"><a href="' . $cobrand_url . '">' . - $areas_info->{$_}->{name}; - if ($areas_info->{$_}->{parent_area} && $url =~ /,|%2C/) { - print ', ' . $areas_info->{$areas_info->{$_}->{parent_area}}->{name}; - } - print '</a></td>'; - summary_cell(\@{$open{$_}{new}}); - if ($q->{site} eq 'emptyhomes') { - my $c = 0; - $c += @{$open{$_}{older}} if $open{$_}{older}; - $c += @{$open{$_}{unknown}} if $open{$_}{unknown}; - summary_cell($c); - } else { - summary_cell(\@{$open{$_}{older}}); - summary_cell(\@{$open{$_}{unknown}}); - } - summary_cell(\@{$fixed{$_}{new}}); - summary_cell(\@{$fixed{$_}{old}}); - print "</tr>\n"; - } - print '</table>'; - } else { - my $name = $one_council->{name}; - if (!$name) { - print Page::header($q, title=>_("Summary reports")); - print "Council with identifier " . ent($one_council->{id}). " not found. "; - print $q->a({href => Cobrand::url($cobrand, '/reports', $q) }, 'Show all councils'); - print "."; - } else { - my $rss_url = '/rss/reports/' . Page::short_name($one_council, $areas_info); - my $thing = _('council'); - if ($ward) { - $rss_url .= '/' . Page::short_name($ward); - $thing = 'ward'; - $name = ent($q_ward) . ", $name"; - } - my $all_councils_report = Cobrand::all_councils_report($cobrand); - - my %vars = ( - rss_title => _('RSS feed'), - rss_alt => sprintf(_('RSS feed of problems in this %s'), $thing), - rss_url => Cobrand::url($cobrand, $rss_url, $q), - url_home => Cobrand::url($cobrand, '/', $q), - summary_title => $all_councils_report - ? sprintf(_('This is a summary of all reports for one %s.'), $thing) - : sprintf(_('This is a summary of all reports for this %s.'), $thing), - name => $name, - ); - if ($all && ! $all_councils_report) { - $vars{summary_line} = sprintf(_('You can <a href="%s">see less detail</a>.'), Cobrand::url($cobrand, NewURL($q), $q)); - } elsif (! $all_councils_report) { - $vars{summary_line} = sprintf(_('You can <a href="%s">see more details</a>.'), Cobrand::url($cobrand, NewURL($q, all=>1), $q)); - } elsif ($all) { - $vars{summary_line} = sprintf(_('You can <a href="%s">see less detail</a> or go back and <a href="/reports">show all councils</a>.'), Cobrand::url($cobrand, NewURL($q), $q)); - } else { - $vars{summary_line} = sprintf(_('You can <a href="%s">see more details</a> or go back and <a href="/reports">show all councils</a>.'), Cobrand::url($cobrand, NewURL($q, all=>1), $q)); - } - - my $id = $one_council->{id}; - if ($open{$id}) { - my $col = list_problems($q, _('New problems'), $open{$id}{new}, $all, 0); - my $old = []; - if ($q->{site} eq 'emptyhomes') { - push @$old, @{$open{$id}{older}} if $open{$id}{older}; - push @$old, @{$open{$id}{unknown}} if $open{$id}{unknown}; - } else { - $old = $open{$id}{older}; - } - $col .= list_problems($q, _('Older problems'), $old, $all, 0); - if ($q->{site} ne 'emptyhomes') { - $col .= list_problems($q, _('Old problems, state unknown'), $open{$id}{unknown}, $all, 0); - } - $vars{col_problems} = $col; - } - if ($fixed{$id}) { - my $col = list_problems($q, _('Recently fixed'), $fixed{$id}{new}, $all, 1); - $col .= list_problems($q, _('Old fixed'), $fixed{$id}{old}, $all, 1); - $vars{col_fixed} = $col; - } - print Page::header($q, context => 'reports', title=>sprintf(_('%s - Summary reports'), $name), rss => [ sprintf(_('Problems within %s, FixMyStreet'), $name), Cobrand::url($cobrand, $rss_url, $q) ]); - print Page::template_include('reports', $q, Page::template_root($q), %vars); - } - } - print Page::footer($q); -} -Page::do_fastcgi(\&main); - -sub add_row { - my ($row, $councils, $council, $fixed, $open) = @_; - my $fourweeks = 4*7*24*60*60; - my $duration = ($row->{duration} > 2 * $fourweeks) ? 'old' : 'new'; - my $type = ($row->{duration} > 2 * $fourweeks) - ? 'unknown' - : ($row->{age} > $fourweeks ? 'older' : 'new'); - $row->{councils} = $councils; - #Fixed problems are either old or new - push @{$fixed->{$council}{$duration}}, $row if $row->{state} eq 'fixed'; - # Open problems are either unknown, older, or new - push @{$open->{$council}{$type}}, $row if $row->{state} eq 'confirmed'; -} - -sub summary_cell { - my $c = shift; - $c = 0 unless defined $c; - $c = @$c if ref($c) eq 'ARRAY'; - print '<td>' . $c . '</td>'; -} - -sub list_problems { - my ($q, $title, $problems, $all, $fixed) = @_; - return '' unless $problems; - my $cobrand = Page::get_cobrand($q); - my $out = "<h3>$title</h3>\n<ul>"; - foreach (sort { $fixed ? ($a->{duration} <=> $b->{duration}) : ($a->{age} <=> $b->{age}) } @$problems) { - my $url = Cobrand::url($cobrand, "/report/" . $_->{id}, $q); - $out .= '<li><a href="' . $url . '">'; - $out .= ent($_->{title}); - $out .= '</a>'; - $out .= ' <small>' . _('(sent to both)') . '</small>' if $_->{councils}>1; - $out .= ' <small>' . _('(not sent to council)') . '</small>' if $_->{councils}==0 && $q->{site} ne 'emptyhomes'; - $out .= '<br><small>' . ent($_->{detail}) . '</small>' if $all; - $out .= '</li>'; - } - $out .= '</ul>'; - return $out; -} - |