<commit_before>package FixMyStreet::App::Controller::Contact;
use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller'; }

use mySociety::EmailUtil;
use FixMyStreet::Email;

=head1 NAME

FixMyStreet::App::Controller::Contact - Catalyst Controller

=head1 DESCRIPTION

Contact us page

=head1 METHODS

=cut

=head2 index

Display contact us page

=cut

sub index : Path : Args(0) {
    my ( $self, $c ) = @_;

    return
      unless $c->forward('setup_request')
          && $c->forward('determine_contact_type');
}

=head2 submit

Handle contact us form submission

=cut

sub submit : Path('submit') : Args(0) {
    my ( $self, $c ) = @_;

    if (my $testing = $c->get_param('_test_')) {
        $c->stash->{success} = $c->get_param('success');
        return;
    }

    $c->res->redirect( '/contact' ) and return unless $c->req->method eq 'POST';

    return
      unless $c->forward('setup_request')
          && $c->forward('determine_contact_type')
          && $c->forward('validate')
          && $c->forward('prepare_params_for_email')
          && $c->forward('send_email');
}

=head2 determine_contact_type

Work out if we have got here via a report/update or this is a
generic contact request and set up things accordingly

=cut

sub determine_contact_type : Private {
    my ( $self, $c ) = @_;

    my $id = $c->get_param('id');
    my $update_id = $c->get_param('update_id');
    my $token = $c->get_param('m');
    $id        = undef unless $id        && $id        =~ /^[1-9]\d*$/;
    $update_id = undef unless $update_id && $update_id =~ /^[1-9]\d*$/;

    if ($token) {
        my $token_obj = $c->forward('/tokens/load_auth_token', [ $token, 'moderation' ]);
        my $problem = $c->cobrand->problems->find( { id => $token_obj->data->{id} } );
        if ($problem) {
            $c->stash->{problem} = $problem;
            $c->stash->{moderation_complaint} = $token;
        } else {
            $c->forward( '/report/load_problem_or_display_error', [ $id ] );
        }

    } elsif ($id) {
        $c->forward( '/report/load_problem_or_display_error', [ $id ] );
        if ($update_id) {
            my $update = $c->model('DB::Comment')->find(
                { id => $update_id }
            );

            $c->stash->{update} = $update;
        }
    }

    return 1;
}

=head2 validate

Validate the form submission parameters. Sets error messages and redirect 
to index page if errors.

=cut

sub validate : Private {
    my ( $self, $c ) = @_;

    my ( %field_errors, @errors );
    my %required = (
        name    => _('Please enter your name'),
        em      => _('Please enter your email'),
        subject => _('Please enter a subject'),
        message => _('Please write a message')
    );

    foreach my $field ( keys %required ) {
        $field_errors{$field} = $required{$field}
          unless $c->get_param($field) =~ /\S/;
    }

    unless ( $field_errors{em} ) {
        $field_errors{em} = _('Please enter a valid email address')
          if !mySociety::EmailUtil::is_valid_email( $c->get_param('em') );
    }

    %field_errors = (
        %field_errors,
        $c->cobrand->extra_contact_validation($c)
    );

    push @errors, _('Illegal ID')
      if $c->get_param('id') && !$c->stash->{problem}
          or $c->get_param('update_id') && !$c->stash->{update};

    push @errors, _('There was a problem showing this page. Please try again later.')
      if $c->get_param('message') && $c->get_param('message') =~ /\[url=|<a/;

    unshift @errors,
      _('There were problems with your report. Please see below.')
      if scalar keys %field_errors;

    if ( @errors or scalar keys %field_errors ) {
        $c->stash->{errors}       = \@errors;
        $c->stash->{field_errors} = \%field_errors;
        $c->go('index');
    }

    return 1;
}

=head2 prepare_params_for_email

Does neccessary reformating of exiting params and add any additional
information required for emailing ( problem ids, admin page links etc )

=cut

sub prepare_params_for_email : Private {
    my ( $self, $c ) = @_;

    $c->stash->{message} =~ s/\r\n/\n/g;
    $c->stash->{subject} =~ s/\r|\n/ /g;

    my $base_url = $c->cobrand->base_url();
    my $admin_url = $c->cobrand->admin_base_url;

    if ( $c->stash->{update} ) {

        $c->stash->{problem_url} = $base_url . '/report/' . $c->stash->{update}->problem_id
            . '#update_' . $c->stash->{update}->id;
        $c->stash->{admin_url} = $admin_url . '/update_edit/' . $c->stash->{update}->id;
        $c->stash->{complaint} = sprintf(
            "Complaint about update %d on report %d",
            $c->stash->{update}->id,
            $c->stash->{update}->problem_id,
        );
    }
    elsif ( $c->stash->{problem} ) {

        $c->stash->{problem_url} = $base_url . '/report/' . $c->stash->{problem}->id;
        $c->stash->{admin_url} = $admin_url . '/report_edit/' . $c->stash->{problem}->id;
        $c->stash->{complaint} = sprintf(
            "Complaint about report %d",
            $c->stash->{problem}->id,
        );

        # flag this so it's automatically listed in the admin interface
        $c->stash->{problem}->flagged(1);
        $c->stash->{problem}->update;
    }

    return 1;
}

=head2 setup_request

Pulls things from request into stash and adds other information
generally required to stash

=cut

sub setup_request : Private {
    my ( $self, $c ) = @_;

    $c->stash->{contact_email} = $c->cobrand->contact_email;
    $c->stash->{contact_email} =~ s/\@/&#64;/;

    for my $param (qw/em subject message/) {
        $c->stash->{$param} = $c->get_param($param);
    }

    # name is already used in the stash for the app class name
    $c->stash->{form_name} = $c->get_param('name');

    return 1;
}

=head2 send_email
<commit_msg>Allow contact form to include extra fields.<commit_after>package FixMyStreet::App::Controller::Contact;
use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller'; }

use mySociety::EmailUtil;
use FixMyStreet::Email;

=head1 NAME

FixMyStreet::App::Controller::Contact - Catalyst Controller

=head1 DESCRIPTION

Contact us page

=head1 METHODS

=cut

=head2 index

Display contact us page

=cut

sub index : Path : Args(0) {
    my ( $self, $c ) = @_;

    return
      unless $c->forward('setup_request')
          && $c->forward('determine_contact_type');
}

=head2 submit

Handle contact us form submission

=cut

sub submit : Path('submit') : Args(0) {
    my ( $self, $c ) = @_;

    if (my $testing = $c->get_param('_test_')) {
        $c->stash->{success} = $c->get_param('success');
        return;
    }

    $c->res->redirect( '/contact' ) and return unless $c->req->method eq 'POST';

    return
      unless $c->forward('setup_request')
          && $c->forward('determine_contact_type')
          && $c->forward('validate')
          && $c->forward('prepare_params_for_email')
          && $c->forward('send_email');
}

=head2 determine_contact_type

Work out if we have got here via a report/update or this is a
generic contact request and set up things accordingly

=cut

sub determine_contact_type : Private {
    my ( $self, $c ) = @_;

    my $id = $c->get_param('id');
    my $update_id = $c->get_param('update_id');
    my $token = $c->get_param('m');
    $id        = undef unless $id        && $id        =~ /^[1-9]\d*$/;
    $update_id = undef unless $update_id && $update_id =~ /^[1-9]\d*$/;

    if ($token) {
        my $token_obj = $c->forward('/tokens/load_auth_token', [ $token, 'moderation' ]);
        my $problem = $c->cobrand->problems->find( { id => $token_obj->data->{id} } );
        if ($problem) {
            $c->stash->{problem} = $problem;
            $c->stash->{moderation_complaint} = $token;
        } else {
            $c->forward( '/report/load_problem_or_display_error', [ $id ] );
        }

    } elsif ($id) {
        $c->forward( '/report/load_problem_or_display_error', [ $id ] );
        if ($update_id) {
            my $update = $c->model('DB::Comment')->find(
                { id => $update_id }
            );

            $c->stash->{update} = $update;
        }
    }

    return 1;
}

=head2 validate

Validate the form submission parameters. Sets error messages and redirect 
to index page if errors.

=cut

sub validate : Private {
    my ( $self, $c ) = @_;

    my ( %field_errors, @errors );
    my %required = (
        name    => _('Please enter your name'),
        em      => _('Please enter your email'),
        subject => _('Please enter a subject'),
        message => _('Please write a message')
    );

    foreach my $field ( keys %required ) {
        $field_errors{$field} = $required{$field}
          unless $c->get_param($field) =~ /\S/;
    }

    unless ( $field_errors{em} ) {
        $field_errors{em} = _('Please enter a valid email address')
          if !mySociety::EmailUtil::is_valid_email( $c->get_param('em') );
    }

    %field_errors = (
        %field_errors,
        $c->cobrand->extra_contact_validation($c)
    );

    push @errors, _('Illegal ID')
      if $c->get_param('id') && !$c->stash->{problem}
          or $c->get_param('update_id') && !$c->stash->{update};

    push @errors, _('There was a problem showing this page. Please try again later.')
      if $c->get_param('message') && $c->get_param('message') =~ /\[url=|<a/;

    unshift @errors,
      _('There were problems with your report. Please see below.')
      if scalar keys %field_errors;

    if ( @errors or scalar keys %field_errors ) {
        $c->stash->{errors}       = \@errors;
        $c->stash->{field_errors} = \%field_errors;
        $c->go('index');
    }

    return 1;
}

=head2 prepare_params_for_email

Does neccessary reformating of exiting params and add any additional
information required for emailing ( problem ids, admin page links etc )

=cut

sub prepare_params_for_email : Private {
    my ( $self, $c ) = @_;

    $c->stash->{message} =~ s/\r\n/\n/g;
    $c->stash->{subject} =~ s/\r|\n/ /g;

    my $base_url = $c->cobrand->base_url();
    my $admin_url = $c->cobrand->admin_base_url;

    if ( $c->stash->{update} ) {

        $c->stash->{problem_url} = $base_url . '/report/' . $c->stash->{update}->problem_id
            . '#update_' . $c->stash->{update}->id;
        $c->stash->{admin_url} = $admin_url . '/update_edit/' . $c->stash->{update}->id;
        $c->stash->{complaint} = sprintf(
            "Complaint about update %d on report %d",
            $c->stash->{update}->id,
            $c->stash->{update}->problem_id,
        );
    }
    elsif ( $c->stash->{problem} ) {

        $c->stash->{problem_url} = $base_url . '/report/' . $c->stash->{problem}->id;
        $c->stash->{admin_url} = $admin_url . '/report_edit/' . $c->stash->{problem}->id;
        $c->stash->{complaint} = sprintf(
            "Complaint about report %d",
            $c->stash->{problem}->id,
        );

        # flag this so it's automatically listed in the admin interface
        $c->stash->{problem}->flagged(1);
        $c->stash->{problem}->update;
    }

    my @extra = grep { /^extra\./ } keys %{$c->req->params};
    foreach (@extra) {
        my $param = $c->get_param($_);
        my ($field_name) = /extra\.(.*)/;
        $c->stash->{message} = "\u$field_name: $param\n\n" . $c->stash->{message};
    }

    return 1;
}

=head2 setup_request

Pulls things from request into stash and adds other information
generally required to stash

=cut

sub setup_request : Private {
    my ( $self, $c ) = @_;

    $c->stash->{contact_email} = $c->cobrand->contact_email;
    $c->stash->{contact_email} =~ s/\@/&#64;/;

    for my $param (qw/em subject message/) {
        $c->stash->{$param} = $c->get_param($param);
    }

    # name is already used in the stash for the app class name
    $c->stash->{form_name} = $c->get_param('name');

    return 1;
}

=head2 send_email

{'fraction_non_alphanumeric': 0.17907309277483388, 'fraction_numerical': 0.0038691227184792665, 'mean_word_length': 2.5177514792899407, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 256, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3128960', 'n_tokens_mistral': 4239, 'n_tokens_neox': 4065, 'n_words': 918}