<commit_before>package GADS::Schema::ResultSet::User;

use strict;
use warnings;

use DateTime;
use DateTime::Format::ISO8601;
use File::BOM qw( open_bom );
use GADS::Audit;
use GADS::Config;
use GADS::Email;
use GADS::Users;
use GADS::Util;
use Log::Report;
use Session::Token;
use Text::CSV;

use base qw(DBIx::Class::ResultSet);

__PACKAGE__->load_components(qw(Helper::ResultSet::CorrelateRelationship));

sub active
{   my ($self, %search) = @_;

    $self->search({
        account_request => 0,
        'me.deleted'    => undef,
        %search,
    });
}

sub active_and_requests
{   my ($self, %search) = @_;

    $self->search({
        'me.deleted'    => undef,
        %search,
    });
}

sub create_user
{   my ($self, %params) = @_;

    my $guard = $self->result_source->schema->txn_scope_guard;

    my $site = $self->result_source->schema->resultset('Site')->next;

    error __"An email address must be specified for the user"
        if !$params{email};

    error __"Please enter a valid email address for the new user"
        if !GADS::Util->email_valid($params{email});

    error __x"User {email} already exists", email => $params{email}
        if $self->active(email => $params{email})->count;

    error __x"Please select a {name} for the user", name => $site->organisation_name
        if !$params{organisation} && $site->register_organisation_mandatory;

    error __x"Please select a {name} for the user", name => $site->team_name
        if !$params{team_id} && $site->register_team_mandatory;

    error __x"Please select a {name} for the user", name => $site->department_name
        if !$params{department_id} && $site->register_department_mandatory;

    my $code         = Session::Token->new( length => 32 )->get;
    my $request_base = $params{request_base};

    my $user = $self->create({
        username => $params{username},
        resetpw  => $code,
        created  => DateTime->now,
    });

    my $audit = GADS::Audit->new(schema => $self->result_source->schema, user => $params{current_user});

    $audit->login_change(
        __x"User created, id: {id}, username: {username}",
            id => $user->id, username => $params{username}
    );

    $params{value} = _user_value(\%params);
    $user->update_user(%params);

    # Delete account request user if this is a new account request
    if (my $id = $params{account_request})
    {
        $self->find($id)->delete;
    }

    $self->_send_welcome_email(%params, code => $code)
        unless $params{no_welcome_email};

    $guard->commit;

    return $user;
}

sub _send_welcome_email
{   my ($self, %params) = @_;

    my %welcome_email = GADS::welcome_text(undef, %params);

    my $email = GADS::Email->instance;

    $email->send({
        subject => $welcome_email{subject},
        text    => $welcome_email{plain},
        html    => $welcome_email{html},
        emails  => [$params{email}],
    });
}

sub upload
{   my ($self, $file, %options) = @_;

    $file or error __"Please select a file to upload";

    my $fh;
    # Use Open::BOM to deal with BOM files being imported
    try { open_bom($fh, $file) }; # Can raise various exceptions which would cause panic
    error __"Unable to open CSV file for reading: ".$@->wasFatal->message if $@; # Make any error user friendly

    my $guard = $self->result_source->schema->txn_scope_guard;

    my $csv = Text::CSV->new({ binary => 1 }) # should set binary attribute?
        or error "Cannot use CSV: ".Text::CSV->error_diag ();

    my $userso = GADS::Users->new(schema => $self->result_source->schema);
    my $site   = $self->result_source->schema->resultset('Site')->next;

    # Get first row for column headings
    my $row = $csv->getline($fh);
    # Valid headings
    my %user_fields = map { lc $_->{description} => 1 } $site->user_fields;
    my %user_mapping;
    my @invalid;
    my $count = 0;
    foreach (@$row)
    {
        if ($user_fields{lc $_})
        {
            $user_mapping{lc $_} = $count;
        }
        else {
            push @invalid, $_;
        }
        $count++;
    }

    if (@invalid)
    {
        my $invalid = join ', ', @invalid;
        error __x"The following column headings were found which are invalid: {invalid}",
            invalid => $invalid;
    }

    defined $user_mapping{email}
        or error __"There must be an email column in the uploaded CSV";

    my $freetext1 = lc $site->register_freetext1_name;
    my $freetext2 = lc $site->register_freetext2_name;
    my $org_name  = lc $site->organisation_name;
    my $dep_name  = lc $site->department_name;
    my $team_name = lc $site->team_name;

    # Map out titles and organisations for conversion to ID
    my %titles        = map { lc $_->name => $_->id } @{$userso->titles};
    my %organisations = map { lc $_->name => $_->id } @{$userso->organisations};
    my %departments   = map { lc $_->name => $_->id } @{$userso->departments};
    my %teams         = map { lc $_->name => $_->id } @{$userso->teams};
<commit_msg>Better errors for user upload<commit_after>package GADS::Schema::ResultSet::User;

use strict;
use warnings;

use DateTime;
use DateTime::Format::ISO8601;
use File::BOM qw( open_bom );
use GADS::Audit;
use GADS::Config;
use GADS::Email;
use GADS::Users;
use GADS::Util;
use Log::Report;
use Session::Token;
use Text::CSV;

use base qw(DBIx::Class::ResultSet);

__PACKAGE__->load_components(qw(Helper::ResultSet::CorrelateRelationship));

sub active
{   my ($self, %search) = @_;

    $self->search({
        account_request => 0,
        'me.deleted'    => undef,
        %search,
    });
}

sub active_and_requests
{   my ($self, %search) = @_;

    $self->search({
        'me.deleted'    => undef,
        %search,
    });
}

sub create_user
{   my ($self, %params) = @_;

    my $guard = $self->result_source->schema->txn_scope_guard;

    my $site = $self->result_source->schema->resultset('Site')->next;

    error __"An email address must be specified for the user"
        if !$params{email};

    error __"Please enter a valid email address for the new user"
        if !GADS::Util->email_valid($params{email});

    error __x"User {email} already exists", email => $params{email}
        if $self->active(email => $params{email})->count;

    error __x"Please select a {name} for the user", name => $site->organisation_name
        if !$params{organisation} && $site->register_organisation_mandatory;

    error __x"Please select a {name} for the user", name => $site->team_name
        if !$params{team_id} && $site->register_team_mandatory;

    error __x"Please select a {name} for the user", name => $site->department_name
        if !$params{department_id} && $site->register_department_mandatory;

    my $code         = Session::Token->new( length => 32 )->get;
    my $request_base = $params{request_base};

    my $user = $self->create({
        username => $params{username},
        resetpw  => $code,
        created  => DateTime->now,
    });

    my $audit = GADS::Audit->new(schema => $self->result_source->schema, user => $params{current_user});

    $audit->login_change(
        __x"User created, id: {id}, username: {username}",
            id => $user->id, username => $params{username}
    );

    $params{value} = _user_value(\%params);
    $user->update_user(%params);

    # Delete account request user if this is a new account request
    if (my $id = $params{account_request})
    {
        $self->find($id)->delete;
    }

    $self->_send_welcome_email(%params, code => $code)
        unless $params{no_welcome_email};

    $guard->commit;

    return $user;
}

sub _send_welcome_email
{   my ($self, %params) = @_;

    my %welcome_email = GADS::welcome_text(undef, %params);

    my $email = GADS::Email->instance;

    $email->send({
        subject => $welcome_email{subject},
        text    => $welcome_email{plain},
        html    => $welcome_email{html},
        emails  => [$params{email}],
    });
}

sub upload
{   my ($self, $file, %options) = @_;

    $file or error __"Please select a file to upload";

    my $fh;
    # Use Open::BOM to deal with BOM files being imported
    try { open_bom($fh, $file) }; # Can raise various exceptions which would cause panic
    error __"Unable to open CSV file for reading: ".$@->wasFatal->message if $@; # Make any error user friendly

    my $guard = $self->result_source->schema->txn_scope_guard;

    my $csv = Text::CSV->new({ binary => 1 }) # should set binary attribute?
        or error "Cannot use CSV: ".Text::CSV->error_diag ();

    my $userso = GADS::Users->new(schema => $self->result_source->schema);
    my $site   = $self->result_source->schema->resultset('Site')->next;

    # Get first row for column headings
    my $row = $csv->getline($fh);
    # Valid headings
    my %user_fields = map { lc $_->{description} => 1 } $site->user_fields;
    my %user_mapping;
    my @invalid;
    my $count = 0;
    foreach (@$row)
    {
        if ($user_fields{lc $_})
        {
            $user_mapping{lc $_} = $count;
        }
        else {
            push @invalid, $_;
        }
        $count++;
    }

    if (@invalid)
    {
        my $invalid = join ', ', map qq("$_"), @invalid;
        my $valid = join ', ', keys %user_fields;
        error __x"The following column headings were found which are invalid: {invalid}. "
            ."Only the following fields can be used: {valid}",
                invalid => $invalid, valid => $valid;
    }

    defined $user_mapping{email}
        or error __"There must be an email column in the uploaded CSV";

    my $freetext1 = lc $site->register_freetext1_name;
    my $freetext2 = lc $site->register_freetext2_name;
    my $org_name  = lc $site->organisation_name;
    my $dep_name  = lc $site->department_name;
    my $team_name = lc $site->team_name;

    # Map out titles and organisations for conversion to ID
    my %titles        = map { lc $_->name => $_->id } @{$userso->titles};
    my %organisations = map { lc $_->name => $_->id } @{$userso->organisations};
    my %departments   = map { lc $_->name => $_->id } @{$userso->departments};
    my %teams         = map { lc $_->name => $_->id } @{$userso->teams};

{'fraction_non_alphanumeric': 0.1551064455999215, 'fraction_numerical': 0.002746983223781026, 'mean_word_length': 2.9252984212552944, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 200, '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': '3202162', 'n_tokens_mistral': 3432, 'n_tokens_neox': 3293, 'n_words': 871}