diff options
32 files changed, 729 insertions, 110 deletions
diff --git a/conf/httpd.conf b/conf/httpd.conf index 1a090226b..8d70c475d 100644 --- a/conf/httpd.conf +++ b/conf/httpd.conf @@ -109,7 +109,7 @@ RewriteRule /(.+) /$1 [L] # RewriteRule ^/contact(.*) /contact.cgi$1 [L] RewriteRule ^/flickr(.*) /flickr.cgi$1 [L] RewriteRule ^/fun(.*) /fun.cgi$1 [L] -RewriteRule ^/json(.*) /json.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] diff --git a/db/schema_0004-create_users_from_comments_and_link.sql b/db/schema_0004-create_users_from_comments_and_link.sql index 6dc50f531..0e4e2b5f2 100644 --- a/db/schema_0004-create_users_from_comments_and_link.sql +++ b/db/schema_0004-create_users_from_comments_and_link.sql @@ -32,10 +32,10 @@ WHERE users.name = ''; ALTER table comment ADD COLUMN anonymous BOOL; -UPDATE comment SET anonymous = true WHERE name = ''; - UPDATE comment SET anonymous = false WHERE name <> ''; +UPDATE comment SET anonymous = true WHERE anonymous is NULL; + -- tidy up now everythings in place ALTER table comment ALTER COLUMN user_id SET NOT NULL; diff --git a/perl-external/files.txt b/perl-external/files.txt index 5df413ba8..82d7fe669 100644 --- a/perl-external/files.txt +++ b/perl-external/files.txt @@ -61,6 +61,7 @@ /authors/id/C/CI/CINE/Lingua-Stem-Snowball-Da-1.01.tar.gz /authors/id/C/CK/CKRAS/DateTime-Format-HTTP-0.40.tar.gz /authors/id/C/CO/COGENT/Tree-DAG_Node-1.06.tar.gz +/authors/id/C/CO/CORION/parent-0.225.tar.gz /authors/id/C/CR/CRENZ/Module-Find-0.10.tar.gz /authors/id/D/DA/DAGOLDEN/CPAN-Meta-2.110580.tar.gz /authors/id/D/DA/DAGOLDEN/CPAN-Meta-YAML-0.003.tar.gz @@ -80,6 +81,12 @@ /authors/id/D/DO/DOY/Package-Stash-0.26.tar.gz /authors/id/D/DO/DOY/Package-Stash-XS-0.22.tar.gz /authors/id/D/DO/DOY/Try-Tiny-0.09.tar.gz +/authors/id/D/DR/DROLSKY/Class-Factory-Util-1.7.tar.gz +/authors/id/D/DR/DROLSKY/DateTime-0.70.tar.gz +/authors/id/D/DR/DROLSKY/DateTime-Format-Builder-0.80.tar.gz +/authors/id/D/DR/DROLSKY/DateTime-Format-Strptime-1.5000.tar.gz +/authors/id/D/DR/DROLSKY/DateTime-Locale-0.45.tar.gz +/authors/id/D/DR/DROLSKY/DateTime-TimeZone-1.34.tar.gz /authors/id/D/DR/DROLSKY/File-ChangeNotify-0.19.tar.gz /authors/id/D/DR/DROLSKY/File-Slurp-9999.13.tar.gz /authors/id/D/DR/DROLSKY/Moose-1.24.tar.gz @@ -128,10 +135,12 @@ /authors/id/G/GB/GBARR/Scalar-List-Utils-1.23.tar.gz /authors/id/G/GE/GETTY/HTTP-Body-1.11.tar.gz /authors/id/G/GR/GRODITI/MooseX-Types-Common-0.001002.tar.gz +/authors/id/G/GR/GROMMEL/Math-Round-0.06.tar.gz /authors/id/I/IL/ILMARI/Class-Unload-0.07.tar.gz /authors/id/I/IN/INGY/Spiffy-0.30.tar.gz /authors/id/I/IN/INGY/Test-Base-0.59.tar.gz /authors/id/J/JE/JESSE/HTTP-Server-Simple-0.44.tar.gz +/authors/id/J/JH/JHOBLITT/DateTime-Format-ISO8601-0.07.tar.gz /authors/id/J/JP/JPEACOCK/version-0.88.tar.gz /authors/id/J/JR/JROCKWAY/Context-Preserve-0.01.tar.gz /authors/id/K/KA/KASEI/Class-Accessor-0.34.tar.gz diff --git a/perl-external/minicpan/modules/02packages.details.txt.gz b/perl-external/minicpan/modules/02packages.details.txt.gz Binary files differindex 3beda027e..c4bc9e1e8 100644 --- a/perl-external/minicpan/modules/02packages.details.txt.gz +++ b/perl-external/minicpan/modules/02packages.details.txt.gz diff --git a/perl-external/modules.txt b/perl-external/modules.txt index 1d027ca1a..63a40b770 100644 --- a/perl-external/modules.txt +++ b/perl-external/modules.txt @@ -21,6 +21,7 @@ DBIx::Class::FilterColumn DBIx::Class::Schema::Loader DBIx::Class::Storage::DBI DateTime::Format::HTTP +DateTime::Format::ISO8601 Email::Address Email::Send Email::Simple diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index 86e2ac001..cc7e84706 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -218,6 +218,7 @@ sub display_location : Private { if mySociety::Config::get('COUNTRY') eq 'GB'; $map_links .= "</p>"; + $c->stash->{map_links} = $map_links; $c->stash->{map_html} = FixMyStreet::Map::display_map( $c->fake_q, @@ -225,9 +226,7 @@ sub display_location : Private { longitude => $longitude, type => 1, pins => \@pins, - post => $map_links ); - $c->stash->{map_end_html} = FixMyStreet::Map::display_map_end(1); $c->stash->{map_js} = FixMyStreet::Map::header_js(); } diff --git a/perllib/FixMyStreet/App/Controller/JSON.pm b/perllib/FixMyStreet/App/Controller/JSON.pm new file mode 100644 index 000000000..c437aafc0 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/JSON.pm @@ -0,0 +1,114 @@ +package FixMyStreet::App::Controller::JSON; +use Moose; +use namespace::autoclean; + +BEGIN { extends 'Catalyst::Controller'; } + +use JSON; +use DateTime; +use DateTime::Format::ISO8601; + +=head1 NAME + +FixMyStreet::App::Controller::JSON - Catalyst Controller + +=head1 DESCRIPTION + +Provide information as JSON + +=head1 METHODS + +=head2 json + +=cut + +sub json : Path : Args(0) { + my ( $self, $c ) = @_; + + # gather the parameters + my $type = $c->req->param('type') || ''; + my $start_date = $c->req->param('start_date') || ''; + my $end_date = $c->req->param('end_date') || ''; + + my $yyyy_mm_dd = qr{^\d{4}-\d\d-\d\d$}; + if ( $start_date !~ $yyyy_mm_dd + || $end_date !~ $yyyy_mm_dd ) + { + $c->stash->{error} = 'Invalid dates supplied'; + return; + } + + # convert the dates to datetimes and trap errors + my $iso8601 = DateTime::Format::ISO8601->new; + my $start_dt = eval { $iso8601->parse_datetime($start_date); }; + my $end_dt = eval { $iso8601->parse_datetime($end_date); }; + unless ( $start_dt && $end_dt ) { + $c->stash->{error} = 'Invalid dates supplied'; + return; + } + + # check that the dates are sane + if ( $start_dt > $end_dt ) { + $c->stash->{error} = 'Start date after end date'; + return; + } + + # check that the type is supported + unless ( $type eq 'new_problems' || $type eq 'fixed_problems' ) { + $c->stash->{error} = 'Invalid type supplied'; + return; + } + + # query the database + $c->stash->{response} = + $type eq 'new_problems' + ? Problems::created_in_interval( $start_date, $end_date ) + : Problems::fixed_in_interval( $start_date, $end_date ); +} + +# If we convert this code to be fully DBIC based then the following snippet is a +# good start. The roadblock to doing it fully is the 'site_restriction' in the +# SQL which is currently provided as SQL, rather than something that could be +# easily added to the DBIC query. The hardest cobrand to change would be the +# cities - so perhaps do it after we know wether that needs to be kept or not. +# +# my $state = +# $type eq 'new_problems' ? 'confirmed' +# : $type eq 'fixed_problems' ? 'fixed_problems' +# : die; +# +# my $one_day = DateTime::Duration->new( days => 1 ); +# +# my $problems = $c->model('DB::Problem')->search( +# { +# created => { +# '>=' => $start_dt, +# '<=' => $end_dt + $one_day, +# }, +# state => $state, +# # ------ add is site_restriction here ------- +# }, +# { +# columns => [ +# 'id', 'title', 'council', 'category', +# 'detail', 'name', 'anonymous', 'confirmed', +# 'whensent', 'service', +# ] +# } +# ); + +sub end : Private { + my ( $self, $c ) = @_; + + my $response = + $c->stash->{error} + ? { error => $c->stash->{error} } + : $c->stash->{response}; + + $c->res->content_type('application/json; charset=utf-8'); + $c->res->body( encode_json( $response || {} ) ); +} + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm new file mode 100755 index 000000000..986543e9d --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm @@ -0,0 +1,228 @@ +package FixMyStreet::App::Controller::Questionnaire; + +use Moose; +use namespace::autoclean; +#use Utils; +#use Error qw(:try); +#use CrossSell; +#use mySociety::Locale; + +BEGIN { extends 'Catalyst::Controller'; } + +=head1 NAME + +FixMyStreet::App::Controller::Questionnaire - Catalyst Controller + +=head1 DESCRIPTION + +Catalyst Controller. + +=head1 METHODS + +=cut + +sub load_questionnaire : Private { + my ( $self, $c ) = @_; + + my $questionnaire = $c->model('DB::Questionnaire')->find( + { id => $c->stash->{id} }, + { prefetch => 'problem' } + ); + $c->stash->{questionnaire} = $questionnaire; + + my $problem_id = $questionnaire->problem_id; + + if ( $questionnaire->whenanswered ) { + my $problem_url = $c->uri_for( "/report/$problem_id" ); + my $contact_url = $c->uri_for( "/contact" ); + $c->stash->{message} = sprintf(_("You have already answered this questionnaire. If you have a question, please <a href='%s'>get in touch</a>, or <a href='%s'>view your problem</a>.\n"), $contact_url, $problem_url); + $c->stash->{template} = 'questionnaire/error.html'; + $c->detach; + } + + # FIXME problem fetched information + # extract(epoch from confirmed) as time, extract(epoch from whensent-confirmed) as whensent + # state in ('confirmed','fixed') + $c->stash->{problem} = $questionnaire->problem; + # throw Error::Simple(_("I'm afraid we couldn't locate your problem in the database.\n")) unless $problem; + + $c->stash->{answered_ever_reported} = $c->model('DB::Questionnaire')->count( + { 'problem.user_id' => $c->stash->{problem}->user_id, + ever_reported => { '!=', undef }, + }, + { join => 'problem' } + ); +} + +sub submit : Path('submit') { + my ( $self, $c ) = @_; + + $c->forward( '/tokens/load_questionnaire_id', [ $c->req->params->{token} ] ); + $c->forward( 'load_questionnaire' ); + + my $questionnaire = $c->stash->{questionnaire}; + my $problem = $questionnaire->problem; + + $c->stash->{num_questionnaire} = $c->model('DB::Questionnaire')->count( + { problem_id => $problem->id } + ); + + map { $c->stash->{$_} = $c->req->params->{$_} || '' } qw(been_fixed reported another update); + # EHA questionnaires done for you + if ($c->cobrand->moniker eq 'emptyhomes') { + $c->stash->{another} = $c->stash->{num_questionnaire}==1 ? 'Yes' : 'No'; + } + + my @errors; + push @errors, _('Please state whether or not the problem has been fixed') unless $c->stash->{been_fixed}; + my $ask_ever_reported = $c->cobrand->ask_ever_reported; + if ($ask_ever_reported) { + push @errors, _('Please say whether you\'ve ever reported a problem to your council before') unless $c->stash->{reported} || $c->stash->{answered_ever_reported}; + } + push @errors, _('Please indicate whether you\'d like to receive another questionnaire') + if ($c->stash->{been_fixed} eq 'No' || $c->stash->{been_fixed} eq 'Unknown') && !$c->stash->{another}; + push @errors, _('Please provide some explanation as to why you\'re reopening this report') + if $c->stash->{been_fixed} eq 'No' && $problem->state eq 'fixed' && !$c->stash->{update}; + if (@errors) { + $c->stash->{errors} = [ @errors ]; + $c->detach( 'display' ); + } + +# my $fh = $q->upload('photo'); +# my $image; +# if ($fh) { +# my $err = Page::check_photo($q, $fh); +# push @errors, $err if $err; +# try { +# $image = Page::process_photo($fh) unless $err; +# } catch Error::Simple with { +# my $e = shift; +# push(@errors, "That image doesn't appear to have uploaded correctly ($e), please try again."); +# }; +# } +# push @errors, _('Please provide some text as well as a photo') +# if $image && !$input{update}; +# return display_questionnaire($q, @errors) if @errors; +# +# my $new_state = ''; +# $new_state = 'fixed' if $input{been_fixed} eq 'Yes' && $problem->{state} eq 'confirmed'; +# $new_state = 'confirmed' if $input{been_fixed} eq 'No' && $problem->{state} eq 'fixed'; +# +# # Record state change, if there was one +# dbh()->do("update problem set state=?, lastupdate=ms_current_timestamp() +# where id=?", {}, $new_state, $problem->{id}) +# if $new_state; +# +# # If it's not fixed and they say it's still not been fixed, record time update +# dbh()->do("update problem set lastupdate=ms_current_timestamp() +# where id=?", {}, $problem->{id}) +# if $input{been_fixed} eq 'No' && $problem->{state} eq 'confirmed'; +# +# # Record questionnaire response +# my $reported = $input{reported} +# ? ($input{reported} eq 'Yes' ? 't' : ($input{reported} eq 'No' ? 'f' : undef)) +# : undef; +# dbh()->do('update questionnaire set whenanswered=ms_current_timestamp(), +# ever_reported=?, old_state=?, new_state=? where id=?', {}, +# $reported, $problem->{state}, $input{been_fixed} eq 'Unknown' +# ? 'unknown' +# : ($new_state ? $new_state : $problem->{state}), +# $questionnaire->{id}); +# +# # Record an update if they've given one, or if there's a state change +# my $name = $problem->{anonymous} ? undef : $problem->{name}; +# my $update = $input{update} ? $input{update} : _('Questionnaire filled in by problem reporter'); +# Utils::workaround_pg_bytea("insert into comment +# (problem_id, name, email, website, text, state, mark_fixed, mark_open, photo, lang, cobrand, cobrand_data, confirmed) +# values (?, ?, ?, '', ?, 'confirmed', ?, ?, ?, ?, ?, ?, ms_current_timestamp())", 7, +# $problem->{id}, $name, $problem->{email}, $update, +# $new_state eq 'fixed' ? 't' : 'f', $new_state eq 'confirmed' ? 't' : 'f', +# $image, $mySociety::Locale::lang, $cobrand, $c->cobrand->extra_data +# ) +# if $new_state || $input{update}; +# +# # If they've said they want another questionnaire, mark as such +# dbh()->do("update problem set send_questionnaire = 't' where id=?", {}, $problem->{id}) +# if ($input{been_fixed} eq 'No' || $input{been_fixed} eq 'Unknown') && $input{another} eq 'Yes'; +# dbh()->commit(); +# +# my $out; +# my $message; +# my $advert_outcome = 1; +# if ($input{been_fixed} eq 'Unknown') { +# $message = _(<<EOF); +# <p>Thank you very much for filling in our questionnaire; if you +# get some more information about the status of your problem, please come back to the +# site and leave an update.</p> +# EOF +# } elsif ($new_state eq 'confirmed' || (!$new_state && $problem->{state} eq 'confirmed')) { +# my $wtt_url = Cobrand::writetothem_url($cobrand, $c->cobrand->extra_data); +# $wtt_url = "http://www.writetothem.com" if (! $wtt_url); +# $message = sprintf(_(<<EOF), $wtt_url); +# <p style="font-size:150%%">We're sorry to hear that. We have two suggestions: why not try +# <a href="%s">writing direct to your councillor(s)</a> +# or, if it's a problem that could be fixed by local people working together, +# why not <a href="http://www.pledgebank.com/new">make and publicise a pledge</a>? +# </p> +# EOF +# $advert_outcome = 0; +# } else { +# $message = _(<<EOF); +# <p style="font-size:150%">Thank you very much for filling in our questionnaire; glad to hear it's been fixed.</p> +# EOF +# } +# $out = $message; +# my $display_advert = Cobrand::allow_crosssell_adverts($cobrand); +# if ($display_advert && $advert_outcome) { +# $out .= CrossSell::display_advert($q, $problem->{email}, $problem->{name}, +# council => $problem->{council}); +# } +# my %vars = (message => $message); +# my $template_page = Page::template_include('questionnaire-completed', $q, Page::template_root($q), %vars); +# return $template_page if ($template_page); +# return $out; +} + +# Sent here from email token action. Simply load and display questionnaire. +sub index : Private { + my ( $self, $c ) = @_; + $c->forward( 'load_questionnaire' ); + $c->forward( 'display' ); +} + +# Displays the questionnaire, either after bad submission or from email token +sub display : Private { + my ( $self, $c ) = @_; + + $c->stash->{template} = 'questionnaire/index.html'; + + my $problem = $c->stash->{questionnaire}->problem; + + my $problem_text = ''; # Page::display_problem_text($c->fake_q, $problem); # FIXME This needs to be in the template + $c->stash->{updates} = ''; # FIXME Should be database ResultSet of problem's pdates + $c->stash->{map_start_html} = FixMyStreet::Map::display_map( + $c->fake_q, + latitude => $problem->latitude, + longitude => $problem->longitude, + pins => [ [ $problem->latitude, $problem->longitude, $problem->state eq 'fixed' ? 'green' : 'red' ] ], + pre => $problem_text, + ); + $c->stash->{map_js} = FixMyStreet::Map::header_js(); + $c->stash->{cobrand_form_elements} = $c->cobrand->form_elements('questionnaireForm'); +} + +=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; + diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 0b235a06e..9041fa731 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -157,7 +157,7 @@ sub format_problem_for_display : Private { $c->stash->{banner} = $c->cobrand->generate_problem_banner($problem); - $c->stash->{allow_photo_upload} = $c->cobrand->allow_photo_display; + $c->stash->{allow_photo_upload} = $c->cobrand->allow_photo_display; # FIXME? $c->stash->{cobrand_alert_fields} = $c->cobrand->form_elements( '/alerts' ); $c->stash->{cobrand_update_fields} = $c->cobrand->form_elements( '/updateForm' ); @@ -187,7 +187,6 @@ sub format_problem_for_display : Private { sub generate_map_tags : Private { my ( $self, $c ) = @_; - my $map_links = ''; my $problem = $c->stash->{problem}; my ( $short_lat, $short_lon ) = @@ -196,7 +195,7 @@ sub generate_map_tags : Private { my $google_link = $c->cobrand->base_url_for_emails() . '/report/' . $problem->id; - $map_links = + $c->stash->{map_links} = "<p id='sub_map_links'>" . "<a href=\"http://maps.google.co.uk/maps?output=embed&z=16&q=" . URI::Escape::uri_escape_utf8( $problem->title . ' - ' . $google_link ) @@ -211,9 +210,7 @@ sub generate_map_tags : Private { pins => $problem->used_map ? [ [ $problem->latitude, $problem->longitude, 'blue' ] ] : [], - 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/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 4c2264c9f..5a33718da 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -621,7 +621,7 @@ sub process_report : Private { $report->latitude( $c->stash->{latitude} ); $report->longitude( $c->stash->{longitude} ); - # Capture wether the may was used + # Capture whether the may was used $report->used_map( $params{skipped} ? 0 : 1 ); # Short circuit unless the form has been submitted @@ -918,7 +918,7 @@ sub generate_map : Private { <input type="hidden" name="pc" value="$pc"> <input type="hidden" name="skipped" value="1"> $cobrand_form_elements -<div id="skipped-map"> +<div> END_MAP_HTML } @@ -934,9 +934,6 @@ END_MAP_HTML ); } - # get the closing for the map - $c->stash->{map_end} = FixMyStreet::Map::display_map_end(1); - return 1; } diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm index 1c3d89b54..7053edc95 100644 --- a/perllib/FixMyStreet/App/Controller/Tokens.pm +++ b/perllib/FixMyStreet/App/Controller/Tokens.pm @@ -156,6 +156,24 @@ sub confirm_update : Path('/C') { return 1; } +sub load_questionnaire_id : Private { + my ( $self, $c, $token_code ) = @_; + + # Set up error handling + $c->stash->{error_template} = 'questionnaire/error.html'; + $c->stash->{message} = _("I'm afraid we couldn't validate that token. If you've copied the URL from an email, please check that you copied it exactly.\n"); + + my $auth_token = $c->forward( 'load_auth_token', [ $token_code, 'questionnaire' ] ); + $c->stash->{id} = $auth_token->data; + $c->stash->{token} = $token_code; +} + +sub questionnaire : Path('/Q') : Args(1) { + my ( $self, $c, $token_code ) = @_; + $c->forward( 'load_questionnaire_id', [ $token_code ] ); + $c->forward( '/questionnaire/index'); +} + =head2 load_auth_token my $auth_token = @@ -193,7 +211,7 @@ Display an error page saying that there is something wrong with the token. sub token_error : Private { my ( $self, $c ) = @_; - $c->stash->{template} = 'tokens/error.html'; + $c->stash->{template} = $c->stash->{error_template} || 'tokens/error.html'; $c->detach; } diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index 7920a15d6..37c5f478b 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -783,7 +783,7 @@ sub generate_problem_banner { my ( $self, $problem ) = @_; my $banner = {}; - if ($problem->state eq 'confirmed' && $problem->get_column('time') > 8*7*24*60*60) { + if ($problem->state eq 'confirmed' && $problem->get_column('duration') > 8*7*24*60*60) { $banner->{id} = 'unknown'; $banner->{text} = _('This problem is old and of unknown status.'); } diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm index 62dab454b..1d9ce1527 100644 --- a/perllib/FixMyStreet/Map.pm +++ b/perllib/FixMyStreet/Map.pm @@ -63,13 +63,6 @@ sub display_map { return $map_class->display_map(@_); } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - sub header { my ( $q, $type ) = @_; return '' unless $type; diff --git a/perllib/FixMyStreet/Map/Bing.pm b/perllib/FixMyStreet/Map/Bing.pm index 335759b08..3d3f4bb09 100644 --- a/perllib/FixMyStreet/Map/Bing.pm +++ b/perllib/FixMyStreet/Map/Bing.pm @@ -28,7 +28,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my @pins; foreach my $pin (@{$params{pins}}) { @@ -55,9 +54,6 @@ var fixmystreet = { $params{pre} <div id="map"></div> <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/BingOL.pm b/perllib/FixMyStreet/Map/BingOL.pm index 4e93243a9..41b7c1051 100644 --- a/perllib/FixMyStreet/Map/BingOL.pm +++ b/perllib/FixMyStreet/Map/BingOL.pm @@ -30,7 +30,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my @pins; foreach my $pin (@{$params{pins}}) { @@ -55,9 +54,6 @@ var fixmystreet = { $params{pre} <div id="map"></div> <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/Google.pm b/perllib/FixMyStreet/Map/Google.pm index 35896108b..f51cae43d 100644 --- a/perllib/FixMyStreet/Map/Google.pm +++ b/perllib/FixMyStreet/Map/Google.pm @@ -28,7 +28,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my @pins; foreach my $pin (@{$params{pins}}) { @@ -53,9 +52,6 @@ var fixmystreet = { $params{pre} <div id="map"></div> <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm index b930a4e4d..028b48125 100644 --- a/perllib/FixMyStreet/Map/OSM.pm +++ b/perllib/FixMyStreet/Map/OSM.pm @@ -35,7 +35,6 @@ sub map_type { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; # Map centre may be overridden in the query string $params{latitude} = Utils::truncate_coordinate($q->param('lat')+0) @@ -96,9 +95,6 @@ var fixmystreet = { $compass </noscript></div> <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/OSM/StreetView.pm b/perllib/FixMyStreet/Map/OSM/StreetView.pm index 9c9a1ac8e..5cc1ed5ba 100644 --- a/perllib/FixMyStreet/Map/OSM/StreetView.pm +++ b/perllib/FixMyStreet/Map/OSM/StreetView.pm @@ -29,7 +29,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my @pins; foreach my $pin (@{$params{pins}}) { @@ -54,9 +53,6 @@ var fixmystreet = { $params{pre} <div id="map"></div> <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm b/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm index 9ae5829c4..785c8eafe 100644 --- a/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm +++ b/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm @@ -35,7 +35,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my @pins; foreach my $pin (@{$params{pins}}) { @@ -69,9 +68,6 @@ var fixmystreet = { <div id="watermark"></div> </div> <p id="copyright">$copyright</p> -$params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm b/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm index 7a898b55b..632e75e39 100644 --- a/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm +++ b/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm @@ -35,7 +35,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my @pins; foreach my $pin (@{$params{pins}}) { @@ -67,9 +66,6 @@ var fixmystreet = { $params{pre} <div id="map"></div> <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/Map/Tilma/Original.pm b/perllib/FixMyStreet/Map/Tilma/Original.pm index 0af6ed277..20fc79a60 100644 --- a/perllib/FixMyStreet/Map/Tilma/Original.pm +++ b/perllib/FixMyStreet/Map/Tilma/Original.pm @@ -43,7 +43,6 @@ sub header_js { sub display_map { my ($self, $q, %params) = @_; $params{pre} ||= ''; - $params{post} ||= ''; my $mid_point = TILE_WIDTH; # Map is 2 TILE_WIDTHs in size, square. if (my $mp = Cobrand::tilma_mid_point(Page::get_cobrand($q))) { $mid_point = $mp; @@ -139,9 +138,6 @@ EOF $out .= <<EOF; </div> <p id="copyright">$copyright</p> -$params{post} -</div> -<div id="side"> EOF return $out; } diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index 35f934299..4c4a3b3eb 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -15,6 +15,7 @@ use Web::Scraper; use Carp; use Email::Send::Test; use Digest::SHA1 'sha1_hex'; +use JSON; =head1 NAME @@ -53,6 +54,26 @@ sub logged_in_ok { "logged in" ); } +=head2 create_user_ok + + $user = $mech->create_user_ok( $email ); + +Create a test user (or find it and return if it already exists). + +=cut + +sub create_user_ok { + my $self = shift; + my ($email) = @_; + + my $user = + FixMyStreet::App->model('DB::User') + ->find_or_create( { email => $email } ); + ok $user, "found/created user for $email"; + + return $user; +} + =head2 log_in_ok $user = $mech->log_in_ok( $email_address ); @@ -65,10 +86,7 @@ sub log_in_ok { my $mech = shift; my $email = shift; - my $user = - FixMyStreet::App->model('DB::User') - ->find_or_create( { email => $email } ); - ok $user, "found/created user for $email"; + my $user = $mech->create_user_ok($email); # store the old password and then change it my $old_password_sha1 = $user->password; @@ -129,14 +147,11 @@ sub delete_user { $mech->log_out_ok; for my $p ( $user->problems ) { - ok( $_->delete, "delete comment " . $_->text ) - for $p->comments; + ok( $_->delete, "delete comment " . $_->text ) for $p->comments; ok( $p->delete, "delete problem " . $p->title ); } - ok( $_->delete, "delete comment " . $_->text ) - for $user->comments; - ok( $_->delete, "delete alert " . $_->alert_type ) - for $user->alerts; + ok( $_->delete, "delete comment " . $_->text ) for $user->comments; + ok( $_->delete, "delete alert " . $_->alert_type ) for $user->alerts; ok $user->delete, "delete test user " . $user->email; return 1; @@ -223,7 +238,7 @@ arrayref of TEXTs. If none found return empty arrayref. sub page_errors { my $mech = shift; my $result = scraper { - process 'p.error', 'errors[]', 'TEXT'; + process 'p.error', 'errors[]', 'TEXT'; process 'ul.error', 'errors[]', 'TEXT'; } ->scrape( $mech->response ); @@ -332,7 +347,6 @@ sub extract_problem_title { return $result->{title}; } - =head2 extract_problem_banner $banner = $mech->extract_problem_banner; @@ -434,4 +448,28 @@ sub session_cookie_expiry { return $expires || 0; } +=head2 get_ok_json + + $decoded = $mech->get_ok_json( $url ); + +Get the url, check that it was JSON and then decode and return the body. + +=cut + +sub get_ok_json { + my $mech = shift; + my $url = shift; + + # try to get the response + $mech->get_ok($url) + || return undef; + my $res = $mech->response; + + # check that the content-type of response is correct + croak "Response was not JSON" + unless $res->header('Content-Type') =~ m{^application/json\b}; + + return decode_json( $res->content ); +} + 1; diff --git a/t/app/controller/json.t b/t/app/controller/json.t new file mode 100644 index 000000000..2c9ff4a61 --- /dev/null +++ b/t/app/controller/json.t @@ -0,0 +1,109 @@ +use strict; +use warnings; + +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +subtest "check that a bad request produces the appropriate response" => sub { + + my $bad_date = "Invalid dates supplied"; + my $mad_date = "Start date after end date"; + my $bad_type = "Invalid type supplied"; + + my %tests = ( + '' => $bad_date, + 'foo=bar' => $bad_date, + 'type=&start_date=&end_date=' => $bad_date, + 'type=&start_date=bad&end_date=2000-02-01' => $bad_date, + 'type=&start_date=2000-01-01&end_date=bad' => $bad_date, + 'type=&start_date=2000-02-31&end_date=2000-02-01' => $bad_date, + 'type=&start_date=2000-01-01&end_date=2000-02-31' => $bad_date, + + 'type=&start_date=2000-02-01&end_date=2000-01-01' => $mad_date, + + 'type=&start_date=2000-01-01&end_date=2000-02-01' => $bad_type, + 'type=foo&start_date=2000-01-01&end_date=2000-02-01' => $bad_type, + ); + + foreach my $q ( sort keys %tests ) { + is_deeply # + $mech->get_ok_json("/json?$q"), # + { error => $tests{$q} }, # + "correct error for query '$q'"; + } + +}; + +is_deeply # + $mech->get_ok_json( + "/json?type=new_problems&start_date=2000-01-01&end_date=2000-02-01"), # + [], # + "correct response"; + +# put an entry in the database for this test +my $user = $mech->create_user_ok('test@example.com'); + +my $problem_args = { + postcode => 'sw1a 1aa', + council => '2501', + areas => ',105164,11806,11827,2247,2501,34817,42011,66045,70786,8519,', + category => 'test category', + title => 'Test title', + detail => 'Test detail', + used_map => 't', + name => 'Test Name', + created => '2000-01-01 12:00:00', + confirmed => '2000-01-01 12:01:00', + state => 'confirmed', + lang => 'en-gb', + service => '', + cobrand => '', + cobrand_data => '', + lastupdate => '2000-01-01 12:00:00', + whensent => undef, + send_questionnaire => 't', + latitude => '51.4531988729771', + longitude => '-0.23021896608596', +}; +my $problem = $user->add_to_problems( { %$problem_args, anonymous => 0 } ); +my $anon_problem = $user->add_to_problems( { %$problem_args, anonymous => 1 } ); + +ok $problem, "created normal test problem"; +ok $anon_problem, "created anon test problem"; + +is_deeply # + $mech->get_ok_json( + "/json?type=new_problems&start_date=2000-01-01&end_date=2000-02-01"), # + [ + { + 'anonymous' => 0, + 'category' => 'test category', + 'confirmed' => '2000-01-01 12:01:00', + 'council' => 'Wandsworth Borough Council', + 'detail' => 'Test detail', + 'id' => $problem->id, + 'name' => 'Test Name', + 'service' => 'Web interface', + 'title' => 'Test title', + 'whensent' => undef + }, + { + 'anonymous' => 1, + 'category' => 'test category', + 'confirmed' => '2000-01-01 12:01:00', + 'council' => 'Wandsworth Borough Council', + 'detail' => 'Test detail', + 'id' => $anon_problem->id, + 'name' => '', + 'service' => 'Web interface', + 'title' => 'Test title', + 'whensent' => undef + } + ], + "correct response"; + +$mech->delete_user($user); + +done_testing(); diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t index aa7e507d9..1f857a387 100644 --- a/t/app/controller/report_display.t +++ b/t/app/controller/report_display.t @@ -190,6 +190,14 @@ foreach my $meta ( for my $test ( { + description => 'new report', + date => DateTime->now, + state => 'confirmed', + banner_id => '', + banner_text => '', + fixed => 0 + }, + { description => 'old report', date => DateTime->new( year => 2009, @@ -230,6 +238,7 @@ for my $test ( ) { subtest "banner for $test->{description}" => sub { $report->confirmed( $test->{date}->ymd . ' ' . $test->{date}->hms ); + $report->lastupdate( $test->{date}->ymd . ' ' . $test->{date}->hms ); $report->state( $test->{state} ); $report->update; diff --git a/templates/web/default/around/display_location.html b/templates/web/default/around/display_location.html index 6801552e6..61d31e5a5 100755 --- a/templates/web/default/around/display_location.html +++ b/templates/web/default/around/display_location.html @@ -35,6 +35,9 @@ %] [% map_html %] +[% map_links %] +</div> +<div id="side"> <h1>[% loc('Problems in this area') %]</h1> @@ -88,6 +91,7 @@ </div> -[% map_end_html %] +</div> +</form> [% INCLUDE 'footer.html' %] diff --git a/templates/web/default/questionnaire/error.html b/templates/web/default/questionnaire/error.html new file mode 100755 index 000000000..12aa8e170 --- /dev/null +++ b/templates/web/default/questionnaire/error.html @@ -0,0 +1,8 @@ +[% INCLUDE 'header.html', title = loc('Error') %] + +<h1>[% loc('Error') %]</h1> + +<p>[% message %]</p> + +[% INCLUDE 'footer.html' %] + diff --git a/templates/web/default/questionnaire/index.html b/templates/web/default/questionnaire/index.html new file mode 100644 index 000000000..142a8b909 --- /dev/null +++ b/templates/web/default/questionnaire/index.html @@ -0,0 +1,114 @@ +[% INCLUDE 'header.html', title = loc('Questionnaire') %] + +# FIXME The below should be in the template, by including a map template. +[% map_start_html %] + +[% INCLUDE 'report/updates.html' %] + +</div> +<div id="side"> + +<h1>[% loc('Questionnaire') %]</h1> + +<form method="post" action="/questionnaire/submit" id="questionnaire" +[%- IF c.cobrand.allow_photo_upload -%] + enctype="multipart/form-data" +[%- END -%] +> + +<input type="hidden" name="token" value="[% token | html %]"> + +[% IF c.cobrand.moniker == 'emptyhomes' %] +[% IF num_questionnaires == 1 %] + _(<<EOF); +<p>Getting empty homes back into use can be difficult. You shouldn't expect +the property to be back into use yet. But a good council will have started work +and should have reported what they have done on the website. If you are not +satisfied with progress or information from the council, now is the right time +to say. You may also want to try contacting some other people who may be able +to help. For advice on how to do this and other useful information please +go to <a href="http://www.emptyhomes.com/getinvolved/campaign.html">http://www.emptyhomes.com/getinvolved/campaign.html</a>.</p> +EOF +[% ELSE %] + _(<<EOF); +<p>Getting empty homes back into use can be difficult, but by now a good council +will have made a lot of progress and reported what they have done on the +website. Even so properties can remain empty for many months if the owner is +unwilling or the property is in very poor repair. If nothing has happened or +you are not satisfied with the progress the council is making, now is the right +time to say so. We think it's a good idea to contact some other people who +may be able to help or put pressure on the council For advice on how to do +this and other useful information please go to <a +href="http://www.emptyhomes.com/getinvolved/campaign.html">http://www.emptyhomes.com/getinvolved/campaign.html</a>.</p> +EOF +[% END %] +[% END %] + +<p> +[% loc('The details of your problem are available on the right hand side of this page.') %] +[% loc('Please take a look at the updates that have been left.') IF updates %] +</p> + +[% IF errors %] +<ul class="error"> +<li>[% errors.join("</li>\n<li>") %]</li> +</ul> +[% END %] + +<p> +[% loc('An update marked this problem as fixed.') IF problem.state == 'fixed' %] +[% loc('Has this problem been fixed?') %] +</p> + +<p> +<input type="radio" name="been_fixed" id="been_fixed_yes" value="Yes"[% ' checked' IF been_fixed == 'Yes' %]> +<label for="been_fixed_yes">[% loc('Yes') %]</label> +<input type="radio" name="been_fixed" id="been_fixed_no" value="No"[% ' checked' IF been_fixed == 'No' %]> +<label for="been_fixed_no">[% loc('No') %]</label> +<input type="radio" name="been_fixed" id="been_fixed_unknown" value="Unknown"[% ' checked' IF been_fixed == 'Unknown' %]> +<label for="been_fixed_unknown">[% loc('Don’t know') %]</label> +</p> + +[% UNLESS answered_ever_reported %] +<p>[% loc('Have you ever reported a problem to a council before, or is this your first time?') %]</p> +<p> +<input type="radio" name="reported" id="reported_yes" value="Yes"[% ' checked' IF reported == 'Yes' %]> +<label for="reported_yes">[% loc('Reported before') %]</label> +<input type="radio" name="reported" id="reported_no" value="No"[% ' checked' IF reported == 'No' %]> +<label for="reported_no">[% loc('First time') %]</label> +</p> +[% END %] + +<p>[% loc('If you wish to leave a public update on the problem, please enter it here +(please note it will not be sent to the council). For example, what was +your experience of getting the problem fixed?') %]</p> + +<p><textarea name="update" style="max-width:90%" rows="7" cols="30">[% update | html %]</textarea></p> + +[% IF c.cobrand.allow_photo_upload %] +<div id="fileupload_normalUI"> + <label for="form_photo">[% loc('Photo:') %]</label> + <input type="file" name="photo" id="form_photo"> +</div> +[% END %] + +[% IF c.cobrand.moniker != 'emptyhomes' %] +<div id="another_qn"> + <p>[% loc('Would you like to receive another questionnaire in 4 weeks, reminding you to check the status?') %]</p> + <p> + <input type="radio" name="another" id="another_yes" value="Yes"[% ' checked' IF another == 'Yes' %]> + <label for="another_yes">[% loc('Yes') %]</label> + <input type="radio" name="another" id="another_no" value="No"[% ' checked' IF another == 'No' %]> + <label for="another_no">[% loc('No') %]</label> + </p> +</div> +[% END %] + +<p><input type="submit" name="submit" value="[% loc('Submit questionnaire') %]"></p> + +</form> + +</div> + +[% INCLUDE 'footer.html' %] + diff --git a/templates/web/default/report/_main.html b/templates/web/default/report/_main.html new file mode 100644 index 000000000..42cb4895d --- /dev/null +++ b/templates/web/default/report/_main.html @@ -0,0 +1,13 @@ +<h1>[% problem_title %]</h1> + +<p><em>[% meta | html %]</em></p> + +[% FOREACH line IN split_into_lines( problem.detail ) %] +<p> +[% line | html %] +</p> +[% END %] + +[% INCLUDE 'report/photo.html' object=problem center=1 %] + + diff --git a/templates/web/default/report/display.html b/templates/web/default/report/display.html index 7e0501610..558b89692 100644 --- a/templates/web/default/report/display.html +++ b/templates/web/default/report/display.html @@ -7,23 +7,17 @@ %] [% map_start_html %] +[% map_links %] +</div> +<div id="side"> + [% IF banner %] <p id="[% banner.id %]"> [% banner.text %] </p> [% END %] -<h1>[% problem_title %]</h1> - -<p><em>[% meta | html %]</em></p> - -[% FOREACH line IN split_into_lines( problem.detail ) %] -<p> -[% line | html %] -</p> -[% END %] - -[% INCLUDE 'report/photo.html' object=problem center=1 %] +[% INCLUDE 'report/_main.html' %] <p align="right"> <small> @@ -131,6 +125,6 @@ </form> </div> -[% map_end_html %] +</div> [% INCLUDE 'footer.html' %] diff --git a/templates/web/default/report/new/fill_in_details.html b/templates/web/default/report/new/fill_in_details.html index 6b8a4aaa9..5bcce220a 100644 --- a/templates/web/default/report/new/fill_in_details.html +++ b/templates/web/default/report/new/fill_in_details.html @@ -1,6 +1,12 @@ [% INCLUDE 'header.html', title => loc('Reporting a problem') %] [% map_html %] +</div> +[% IF report.used_map %] +<div id="side"> +[% ELSE %] +<div id="skipped-map"> +[% END %] <h1>[% loc('Reporting a problem') %]</h1> @@ -144,6 +150,7 @@ </div> </div> -[% map_end %] +</div> +</form> [% INCLUDE 'footer.html' %] diff --git a/templates/web/default/report/updates.html b/templates/web/default/report/updates.html index 188bacca6..db6a78279 100644 --- a/templates/web/default/report/updates.html +++ b/templates/web/default/report/updates.html @@ -21,10 +21,9 @@ [% line | html %] </p> [% END %] - </div> - - [% INCLUDE 'report/photo.html' object=update %] + [% INCLUDE 'report/photo.html' object=update %] + </div> </div> [% '</div>' IF loop.last %] [% END %] diff --git a/web/json.cgi b/web/json.cgi index 512750988..70ae2a76f 100755 --- a/web/json.cgi +++ b/web/json.cgi @@ -8,28 +8,28 @@ # # $Id: json.cgi,v 1.4 2010-01-20 11:31:26 matthew Exp $ -use strict; -use Error qw(:try); -use JSON; -use Standard; - -sub main { - my $q = shift; - my $problems; - my $type = $q->param('type') || ''; - my $start_date = $q->param('start_date') || ''; - my $end_date = $q->param('end_date') || ''; - if ($start_date !~ /^\d{4}-\d\d-\d\d$/ || $end_date !~ /^\d{4}-\d\d-\d\d$/) { - $problems = { error => 'Invalid dates supplied' }; - } elsif ($type eq 'new_problems') { - $problems = Problems::created_in_interval($start_date, $end_date); - } elsif ($type eq 'fixed_problems') { - $problems = Problems::fixed_in_interval($start_date, $end_date); - } - print $q->header( -type => 'application/json; charset=utf-8' ); - print JSON::to_json($problems); -} - - -Page::do_fastcgi(\&main); - +# use strict; +# use Error qw(:try); +# use JSON; +# use Standard; +# +# sub main { +# my $q = shift; +# my $problems; +# my $type = $q->param('type') || ''; +# my $start_date = $q->param('start_date') || ''; +# my $end_date = $q->param('end_date') || ''; +# if ($start_date !~ /^\d{4}-\d\d-\d\d$/ || $end_date !~ /^\d{4}-\d\d-\d\d$/) { +# $problems = { error => 'Invalid dates supplied' }; +# } elsif ($type eq 'new_problems') { +# $problems = Problems::created_in_interval($start_date, $end_date); +# } elsif ($type eq 'fixed_problems') { +# $problems = Problems::fixed_in_interval($start_date, $end_date); +# } +# print $q->header( -type => 'application/json; charset=utf-8' ); +# print JSON::to_json($problems); +# } +# +# +# Page::do_fastcgi(\&main); +# |