package FixMyStreet::App::Controller::Questionnaire;
use Moose;
use namespace::autoclean;
use Path::Class;
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->detach('missing_problem') unless $questionnaire;
$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 get in touch, or view your problem.\n"), $contact_url, $problem_url);
$c->stash->{template} = 'errors/generic.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} = 'errors/generic.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;