diff options
Diffstat (limited to 'perllib/FixMyStreet/App/Controller/Questionnaire.pm')
-rwxr-xr-x | perllib/FixMyStreet/App/Controller/Questionnaire.pm | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm new file mode 100755 index 000000000..b4c9ade92 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm @@ -0,0 +1,328 @@ +package FixMyStreet::App::Controller::Questionnaire; + +use Moose; +use namespace::autoclean; +use Utils; + +BEGIN { extends 'Catalyst::Controller'; } + +=head1 NAME + +FixMyStreet::App::Controller::Questionnaire - Catalyst Controller + +=head1 DESCRIPTION + +Deals with report questionnaires. + +=head1 METHODS + +=cut + +=head2 load_questionnaire + +Loads the questionnaire from the database, and checks it still needs answering +and is in the right state. Also finds out if this user has answered the +"ever reported" question before. + +=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; + } + + unless ( $questionnaire->problem->state eq 'confirmed' || $questionnaire->problem->state eq 'fixed' ) { + $c->detach('missing_problem'); + } + + $c->stash->{problem} = $questionnaire->problem; + $c->stash->{answered_ever_reported} = $questionnaire->problem->user->answered_ever_reported; + + # EHA needs to know how many to alter display, and whether to send another or not + if ($c->cobrand->moniker eq 'emptyhomes') { + $c->stash->{num_questionnaire} = $c->model('DB::Questionnaire')->count( + { problem_id => $c->stash->{problem}->id } + ); + } + +} + +=head2 submit + +If someone submits a questionnaire - either a full style one (when we'll have a +token), or the mini own-report one (when we'll have a problem ID). + +=cut + +sub submit : Path('submit') { + my ( $self, $c ) = @_; + + if ( $c->req->params->{token} ) { + $c->forward('submit_standard'); + } elsif ( $c->req->params->{problem} ) { + $c->forward('submit_creator_fixed'); + } else { + return; + } + + return 1; +} + +=head2 missing_problem + +Display couldn't locate problem error message + +=cut + +sub missing_problem : Private { + my ( $self, $c ) = @_; + + $c->stash->{message} = _("I'm afraid we couldn't locate your problem in the database.\n"); + $c->stash->{template} = 'questionnaire/error.html'; +} + +sub submit_creator_fixed : Private { + my ( $self, $c ) = @_; + + my @errors; + + map { $c->stash->{$_} = $c->req->params->{$_} || '' } qw(reported problem); + + # should only be able to get to here if we are logged and we have a + # problem + unless ( $c->user && $c->stash->{problem} ) { + $c->detach('missing_problem'); + } + + my $problem = $c->cobrand->problems->find( { id => $c->stash->{problem} } ); + + # you should not be able to answer questionnaires about problems + # that you've not submitted + if ( $c->user->id != $problem->user->id ) { + $c->detach('missing_problem'); + } + + push @errors, _('Please say whether you\'ve ever reported a problem to your council before') unless $c->stash->{reported}; + + $c->stash->{problem_id} = $c->stash->{problem}; + $c->stash->{errors} = \@errors; + $c->detach( 'creator_fixed' ) if scalar @errors; + + my $questionnaire = $c->model( 'DB::Questionnaire' )->find_or_new( + { + problem_id => $c->stash->{problem}, + old_state => 'confirmed', + new_state => 'fixed', + } + ); + + unless ( $questionnaire->in_storage ) { + $questionnaire->ever_reported( $c->stash->{reported} eq 'Yes' ? 1 : 0 ); + $questionnaire->whensent( \'ms_current_timestamp()' ); + $questionnaire->whenanswered( \'ms_current_timestamp()' ); + $questionnaire->insert; + } + + $c->stash->{creator_fixed} = 1; + $c->stash->{template} = 'tokens/confirm_update.html'; + + return 1; +} + +sub submit_standard : Private { + my ( $self, $c ) = @_; + + $c->forward( '/tokens/load_questionnaire_id', [ $c->req->params->{token} ] ); + $c->forward( 'load_questionnaire' ); + $c->forward( 'process_questionnaire' ); + + my $problem = $c->stash->{problem}; + my $old_state = $problem->state; + my $new_state = ''; + $new_state = 'fixed' if $c->stash->{been_fixed} eq 'Yes' && $old_state eq 'confirmed'; + $new_state = 'confirmed' if $c->stash->{been_fixed} eq 'No' && $old_state eq 'fixed'; + + # Record state change, if there was one + if ( $new_state ) { + $problem->state( $new_state ); + $problem->lastupdate( \'ms_current_timestamp()' ); + } + + # If it's not fixed and they say it's still not been fixed, record time update + if ( $c->stash->{been_fixed} eq 'No' && $old_state eq 'confirmed' ) { + $problem->lastupdate( \'ms_current_timestamp()' ); + } + + # Record questionnaire response + my $reported = undef; + $reported = 1 if $c->stash->{reported} eq 'Yes'; + $reported = 0 if $c->stash->{reported} eq 'No'; + + my $q = $c->stash->{questionnaire}; + $q->update( { + whenanswered => \'ms_current_timestamp()', + ever_reported => $reported, + old_state => $old_state, + new_state => $c->stash->{been_fixed} eq 'Unknown' ? 'unknown' : ($new_state || $old_state), + } ); + + # Record an update if they've given one, or if there's a state change + if ( $new_state || $c->stash->{update} ) { + my $update = $c->stash->{update} || _('Questionnaire filled in by problem reporter'); + $update = $c->model('DB::Comment')->new( + { + problem => $problem, + name => $problem->name, + user => $problem->user, + text => $update, + state => 'confirmed', + mark_fixed => $new_state eq 'fixed' ? 1 : 0, + mark_open => $new_state eq 'confirmed' ? 1 : 0, + lang => $c->stash->{lang_code}, + cobrand => $c->cobrand->moniker, + cobrand_data => $c->cobrand->extra_update_data, + confirmed => \'ms_current_timestamp()', + anonymous => $problem->anonymous, + } + ); + if ( my $fileid = $c->stash->{upload_fileid} ) { + my $file = file( $c->config->{UPLOAD_CACHE}, "$fileid.jpg" ); + my $blob = $file->slurp; + $file->remove; + $update->photo($blob); + } + $update->insert; + } + + # If they've said they want another questionnaire, mark as such + $problem->send_questionnaire( 1 ) + if ($c->stash->{been_fixed} eq 'No' || $c->stash->{been_fixed} eq 'Unknown') && $c->stash->{another} eq 'Yes'; + $problem->update; + + $c->stash->{new_state} = $new_state; + $c->stash->{template} = 'questionnaire/completed.html'; +} + +sub process_questionnaire : Private { + my ( $self, $c ) = @_; + + 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}; + + if ($c->cobrand->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' && $c->stash->{problem}->state eq 'fixed' && !$c->stash->{update}; + + $c->forward('/report/new/process_photo'); + push @errors, $c->stash->{photo_error} + if $c->stash->{photo_error}; + + push @errors, _('Please provide some text as well as a photo') + if $c->stash->{upload_fileid} && !$c->stash->{update}; + + if (@errors) { + $c->stash->{errors} = [ @errors ]; + $c->detach( 'display' ); + } +} + +# Sent here from email token action. Simply load and display questionnaire. +sub index : Private { + my ( $self, $c ) = @_; + $c->forward( 'load_questionnaire' ); + $c->forward( 'display' ); +} + +=head2 display + +Displays a questionnaire, either after bad submission or directly from email token. + +=cut + +sub display : Private { + my ( $self, $c ) = @_; + + $c->stash->{template} = 'questionnaire/index.html'; + + my $problem = $c->stash->{questionnaire}->problem; + + ( $c->stash->{short_latitude}, $c->stash->{short_longitude} ) = + map { Utils::truncate_coordinate($_) } + ( $problem->latitude, $problem->longitude ); + + $c->stash->{updates} = $c->model('DB::Comment')->search( + { problem_id => $problem->id, state => 'confirmed' }, + { order_by => 'confirmed' } + ); + + FixMyStreet::Map::display_map( + $c, + latitude => $problem->latitude, + longitude => $problem->longitude, + pins => [ { + latitude => $problem->latitude, + longitude => $problem->longitude, + colour => $problem->state eq 'fixed' ? 'green' : 'red', + } ], + ); +} + +=head2 creator_fixed + +Display the reduced questionnaire that we display when the reporter of a +problem submits an update marking it as fixed. + +=cut + +sub creator_fixed : Private { + my ( $self, $c ) = @_; + + $c->stash->{template} = 'questionnaire/creator_fixed.html'; + + return 1; +} + +=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; + |