diff options
Diffstat (limited to 'perllib/FixMyStreet/App/Controller/Report/Update.pm')
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/Update.pm | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm new file mode 100644 index 000000000..2f1d88d08 --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm @@ -0,0 +1,321 @@ +package FixMyStreet::App::Controller::Report::Update; + +use Moose; +use namespace::autoclean; +BEGIN { extends 'Catalyst::Controller'; } + +use Path::Class; +use Utils; + +=head1 NAME + +FixMyStreet::App::Controller::Report::Update + +=head1 DESCRIPTION + +Creates an update to a report + +=cut + +sub report_update : Path : Args(0) { + my ( $self, $c ) = @_; + + # if there's no id then we should just stop now + $c->detach( '/page_error_404_not_found', [ _('Unknown problem ID') ] ) + unless $c->req->param('id'); + + $c->forward( '/report/load_problem_or_display_error', [ $c->req->param('id') ] ) + && $c->forward('process_user') + && $c->forward('process_update') + && $c->forward('/report/new/process_photo') + && $c->forward('check_for_errors') + or $c->go( '/report/display', [ $c->req->param('id') ] ); + + return $c->forward('save_update') + && $c->forward('redirect_or_confirm_creation'); +} + +sub confirm : Private { + my ( $self, $c ) = @_; + + $c->stash->{update}->confirm; + $c->stash->{update}->update; + + $c->forward('update_problem'); + $c->forward('signup_for_alerts'); + + return 1; +} + +sub update_problem : Private { + my ( $self, $c ) = @_; + + my $display_questionnaire = 0; + + my $update = $c->stash->{update}; + my $problem = $c->stash->{problem} || $update->problem; + + if ( $update->mark_fixed ) { + $problem->state('fixed'); + + if ( $update->user->id == $problem->user->id ) { + $problem->send_questionnaire(0); + + if ( $c->cobrand->ask_ever_reported + && !$problem->user->answered_ever_reported ) + { + $display_questionnaire = 1; + } + } + } + + $problem->lastupdate( \'ms_current_timestamp()' ); + $problem->update; + + $c->stash->{problem_id} = $problem->id; + + if ($display_questionnaire) { + $c->detach('/questionnaire/creator_fixed'); + } + + return 1; +} + +sub display_confirmation : Private { + my ( $self, $c ) = @_; + + $c->stash->{template} = 'tokens/confirm_update.html'; + + return 1; +} + +=head2 process_user + +Load user from the database or prepare a new one. + +=cut + +sub process_user : Private { + my ( $self, $c ) = @_; + + # FIXME - If user already logged in use them regardless + + # Extract all the params to a hash to make them easier to work with + my %params = # + map { $_ => scalar $c->req->param($_) } # + ( 'rznvy', 'name' ); + + # cleanup the email address + my $email = $params{rznvy} ? lc $params{rznvy} : ''; + $email =~ s{\s+}{}g; + + my $update_user = $c->model('DB::User')->find_or_new( { email => $email } ); + + # set the user's name if they don't have one + $update_user->name( Utils::trim_text( $params{name} ) ) + unless $update_user->name; + + $c->stash->{update_user} = $update_user; + $c->stash->{email} = $update_user->email; + + return 1; +} + +=head2 process_update + +Take the submitted params and create a new update item. Does not save +anything to the database. + +NB: relies on their being a problem and update_user in the stash. May +want to move adding these elsewhere + +=cut + +sub process_update : Private { + my ( $self, $c ) = @_; + + my %params = + map { $_ => scalar $c->req->param($_) } ( 'update', 'name', 'fixed' ); + + $params{update} = + Utils::cleanup_text( $params{update}, { allow_multiline => 1 } ); + + my $name = Utils::trim_text( $params{name} ); + + my $anonymous = 1; + + $anonymous = 0 if ( $name && $c->req->param('may_show_name') ); + + my $update = $c->model('DB::Comment')->new( + { + text => $params{update}, + name => $name, + problem => $c->stash->{problem}, + user => $c->stash->{update_user}, + state => 'unconfirmed', + mark_fixed => $params{fixed} ? 1 : 0, + cobrand => $c->cobrand->moniker, + cobrand_data => $c->cobrand->extra_update_data, + lang => $c->stash->{lang_code}, + anonymous => $anonymous, + } + ); + + $c->stash->{update} = $update; + $c->stash->{update_text} = $update->text; + $c->stash->{add_alert} = $c->req->param('add_alert'); + $c->stash->{may_show_name} = ' checked' if $c->req->param('may_show_name'); + + return 1; +} + + +=head2 check_for_errors + +Examine the user and the report for errors. If found put them on stash and +return false. + +=cut + +sub check_for_errors : Private { + my ( $self, $c ) = @_; + + # let the model check for errors + my %field_errors = ( + %{ $c->stash->{update_user}->check_for_errors }, + %{ $c->stash->{update}->check_for_errors }, + ); + + # we don't care if there are errors with this... + delete $field_errors{name}; + + # all good if no errors + return 1 + unless ( scalar keys %field_errors + || ( $c->stash->{errors} && scalar @{ $c->stash->{errors} } ) + || $c->stash->{photo_error} ); + + $c->stash->{field_errors} = \%field_errors; + + $c->stash->{errors} ||= []; + push @{ $c->stash->{errors} }, + _('There were problems with your update. Please see below.'); + + return; +} + +=head2 save_update + +Save the update and the user as appropriate. + +=cut + +sub save_update : Private { + my ( $self, $c ) = @_; + + my $user = $c->stash->{update_user}; + my $update = $c->stash->{update}; + + if ( !$user->in_storage ) { + $user->insert; + } + elsif ( $c->user && $c->user->id == $user->id ) { + $user->update; + $update->confirm; + } + + # If there was a photo add that too + 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); + } + + if ( $update->in_storage ) { + $update->update; + } + else { + $update->insert; + } + + return 1; +} + +=head2 redirect_or_confirm_creation + +Now that the update has been created either redirect the user to problem page if it +has been confirmed or email them a token if it has not been. + +=cut + +sub redirect_or_confirm_creation : Private { + my ( $self, $c ) = @_; + my $update = $c->stash->{update}; + + # If confirmed send the user straight there. + if ( $update->confirmed ) { + $c->forward( 'signup_for_alerts' ); + $c->forward( 'update_problem' ); + my $report_uri = $c->uri_for( '/report', $update->problem_id ); + $c->res->redirect($report_uri); + $c->detach; + } + + # otherwise create a confirm token and email it to them. + my $token = $c->model("DB::Token")->create( + { + scope => 'comment', + data => { + id => $update->id, + add_alert => ( $c->req->param('add_alert') ? 1 : 0 ), + } + } + ); + $c->stash->{token_url} = $c->uri_for_email( '/C', $token->token ); + $c->send_email( 'update-confirm.txt', { + to => $update->name + ? [ [ $update->user->email, $update->name ] ] + : $update->user->email, + } ); + + # tell user that they've been sent an email + $c->stash->{template} = 'email_sent.html'; + $c->stash->{email_type} = 'update'; + + return 1; +} + +=head2 signup_for_alerts + +If the user has selected to be signed up for alerts then create a +new_updates alert. + +NB: this does not check if they are a registered user so that should +happen before calling this. + +=cut + +sub signup_for_alerts : Private { + my ( $self, $c ) = @_; + + if ( $c->stash->{add_alert} ) { + my $update = $c->stash->{update}; + my $alert = $c->model('DB::Alert')->find_or_create( + user => $update->user, + alert_type => 'new_updates', + parameter => $update->problem_id, + cobrand => $update->cobrand, + cobrand_data => $update->cobrand_data, + lang => $update->lang, + ); + + $alert->confirm(); + } + + return 1; +} + +__PACKAGE__->meta->make_immutable; + +1; |