396 lines
11 KiB
Perl
396 lines
11 KiB
Perl
package BeastBB::DAO::UserManager;
|
|
|
|
use 5.32.1;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Carp;
|
|
|
|
use Params::ValidationCompiler 'validation_for';
|
|
use Types::Standard qw/Bool Str Int/;
|
|
|
|
use Crypt::Bcrypt::Easy;
|
|
use Const::Fast;
|
|
use DateTime;
|
|
use DateTime::Format::Pg;
|
|
|
|
use BeastBB::Types (
|
|
'$MATRIX_ADDRESS_REGEX', 'IsClassTypeGenerator',
|
|
'$MATRIX_ADDRESS_TYPE'
|
|
);
|
|
use BeastBB::DAO::GroupManager;
|
|
use BeastBB::Model::User;
|
|
use BeastBB::Response;
|
|
|
|
const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
app => { type => IsClassTypeGenerator('Mojolicious::Controller') },
|
|
}
|
|
);
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
my %params = $validator->(@_);
|
|
return bless \%params, $class;
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
id_user => { type => Int, optional => 1 },
|
|
username => { type => Str, optional => 1 },
|
|
matrix_address => { type => $MATRIX_ADDRESS_TYPE, optional => 1 },
|
|
recover_group => { type => Bool, default => 0 },
|
|
}
|
|
);
|
|
|
|
sub Get {
|
|
my $self = shift;
|
|
|
|
my %params = $validator->(@_);
|
|
|
|
my $id_user = $params{id_user};
|
|
my $username = $params{username};
|
|
my $matrix_address = $params{matrix_address};
|
|
my $recover_group = $params{recover_group};
|
|
|
|
confess
|
|
'You should pass id_user xor matrix_address xor username to Get.'
|
|
unless ( defined $id_user xor defined $username
|
|
xor defined $matrix_address );
|
|
|
|
my $maybe_user_hash = $self->_RecoverUserFromDatabase(
|
|
( ( defined $id_user ) ? ( id_user => $id_user ) : () ),
|
|
( ( defined $username ) ? ( username => $username ) : () ),
|
|
(
|
|
( defined $matrix_address )
|
|
? ( matrix_address => $matrix_address )
|
|
: ()
|
|
)
|
|
);
|
|
return $maybe_user_hash if $maybe_user_hash->IsError;
|
|
my $user_hash = $maybe_user_hash->Content;
|
|
my $id_group = delete $user_hash->{id_group};
|
|
my $user = BeastBB::Model::User->new(%$user_hash);
|
|
|
|
if ($recover_group) {
|
|
my $maybe_recovered_group =
|
|
$self->_RecoverUserGroup( id_group => $id_group, user => $user );
|
|
return $maybe_recovered_group if $maybe_recovered_group->IsError;
|
|
}
|
|
return BeastBB::Response->new( content => $user );
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
id_group => { type => Int },
|
|
user => { type => IsClassTypeGenerator('BeastBB::Model::User') },
|
|
}
|
|
);
|
|
|
|
sub _RecoverUserGroup {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
|
|
my $id_group = $params{id_group};
|
|
my $user = $params{user};
|
|
my $app = $self->_App;
|
|
|
|
my $group_manager = BeastBB::DAO::GroupManager->new( app => $app );
|
|
my $maybe_group = $group_manager->Get( id_group => $id_group );
|
|
if ( $maybe_group->IsError ) {
|
|
return $maybe_group;
|
|
}
|
|
my $group = $maybe_group->Content;
|
|
$user->Group($group);
|
|
return BeastBB::Response->new;
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
id_user => { type => Int, optional => 1 },
|
|
username => { type => Str, optional => 1 },
|
|
matrix_address => { type => $MATRIX_ADDRESS_TYPE, optional => 1 },
|
|
}
|
|
|
|
);
|
|
|
|
sub _RecoverUserFromDatabase {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
|
|
my $app = $self->_App;
|
|
my $database = $app->db;
|
|
my $pg = $database->Pg->db;
|
|
|
|
my ( $id_user, $username, $matrix_address ) =
|
|
@params{ 'id_user', 'username', 'matrix_address' };
|
|
|
|
my $results = $pg->select(
|
|
'user',
|
|
[
|
|
'id_user', 'username', 'matrix_address', 'password_bcrypt',
|
|
'is_confirmed', 'creation_date', 'id_group', 'last_connection',
|
|
],
|
|
{
|
|
( ( defined $id_user ) ? ( id_user => $id_user ) : () ),
|
|
( ( defined $username ) ? ( username => $username ) : () ),
|
|
(
|
|
( defined $matrix_address )
|
|
? ( matrix_address => $matrix_address )
|
|
: ()
|
|
)
|
|
}
|
|
);
|
|
if ( !$results->rows ) {
|
|
return BeastBB::Response->new(
|
|
is_error => 1,
|
|
error_message => 'No such user found.',
|
|
);
|
|
}
|
|
my $user_hash = $results->hash;
|
|
$user_hash->{creation_date} = DateTime::Format::Pg->parse_datetime(
|
|
$user_hash->{creation_date} );
|
|
$user_hash->{last_connection} =
|
|
DateTime::Format::Pg->parse_datetime(
|
|
$user_hash->{last_connection} );
|
|
|
|
return BeastBB::Response->new( content => $user_hash );
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
username => { type => Str },
|
|
matrix_address => { type => Str },
|
|
password => { type => Str },
|
|
repeat_password => { type => Str },
|
|
is_confirmed => { type => Bool },
|
|
groupname => { type => Str },
|
|
}
|
|
);
|
|
|
|
sub Create {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
my (
|
|
$username, $matrix_address, $password, $repeat_password,
|
|
$is_confirmed, $groupname
|
|
)
|
|
= @params{
|
|
'username', 'matrix_address', 'password',
|
|
'repeat_password', 'is_confirmed', 'groupname'
|
|
};
|
|
my $app = $self->_App;
|
|
my $database = $app->db;
|
|
my $pg = $database->Pg->db;
|
|
|
|
my $response_check_user_creation_requeriments =
|
|
$self->CheckUserCreationRequeriments(
|
|
matrix_address => $matrix_address,
|
|
password => $password,
|
|
repeat_password => $repeat_password
|
|
);
|
|
|
|
return $response_check_user_creation_requeriments
|
|
if $response_check_user_creation_requeriments->IsError;
|
|
|
|
my $result =
|
|
$pg->select( 'group', 'id_group', { groupname => $groupname } );
|
|
if ( !$result->rows ) {
|
|
return BeastBB::Response->new(
|
|
is_error => 1,
|
|
error_message => "Unable to find the group $groupname."
|
|
);
|
|
}
|
|
|
|
my $id_group = $result->hash->{id_group};
|
|
|
|
my $result_create_user = $pg->insert(
|
|
'user',
|
|
{
|
|
username => $username,
|
|
password_bcrypt => bcrypt->crypt($password),
|
|
matrix_address => $matrix_address,
|
|
is_confirmed => $is_confirmed ? 1 : 0,
|
|
creation_date => "" . DateTime->now,
|
|
last_connection => "" . DateTime->now,
|
|
id_group => $id_group,
|
|
},
|
|
{
|
|
returning => ['id_user'],
|
|
}
|
|
);
|
|
if ( !$result_create_user->rows ) {
|
|
return BeastBB::Response->new(
|
|
is_error => 1,
|
|
error_message => "Unable to create user $username.",
|
|
);
|
|
}
|
|
return BeastBB::Response->new(
|
|
content => $result_create_user->hash->{id_user} );
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
matrix_address => { type => Str },
|
|
password => { type => Str },
|
|
repeat_password => { type => Str },
|
|
}
|
|
);
|
|
|
|
sub CheckUserCreationRequeriments {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
my ( $matrix_address, $password, $repeat_password ) =
|
|
@params{ 'matrix_address', 'password', 'repeat_password' };
|
|
my $response =
|
|
$self->CheckMatrixAddress( matrix_address => $matrix_address );
|
|
return $response if $response->IsError;
|
|
$response = $self->CheckPasswordLength( password => $password );
|
|
return $response if $response->IsError;
|
|
$response = $self->CheckPasswordNotOnlyNumeric( password => $password );
|
|
return $response if $response->IsError;
|
|
$response = $self->CheckTwoPasswordsEqual(
|
|
password => $password,
|
|
repeat_password => $repeat_password
|
|
);
|
|
return $response;
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
password => { type => Str },
|
|
repeat_password => { type => Str },
|
|
}
|
|
);
|
|
|
|
sub CheckTwoPasswordsEqual {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
my $password = $params{password};
|
|
my $repeat_password = $params{repeat_password};
|
|
|
|
my $error_message;
|
|
|
|
if ( $password ne $repeat_password ) {
|
|
$error_message = 'Password and repeat password not matching.';
|
|
}
|
|
return BeastBB::Response->new(
|
|
(
|
|
( defined $error_message )
|
|
? (
|
|
is_error => 1,
|
|
error_message => $error_message
|
|
)
|
|
: ()
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
password => { type => Str },
|
|
}
|
|
);
|
|
|
|
sub CheckPasswordNotOnlyNumeric {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
my $password = $params{'password'};
|
|
my $error_message;
|
|
if ( $password =~ /^\d+$/ ) {
|
|
$error_message = "Password is numeric, it is not allowed.";
|
|
}
|
|
return BeastBB::Response->new(
|
|
(
|
|
( defined $error_message )
|
|
? (
|
|
is_error => 1,
|
|
error_message => $error_message
|
|
)
|
|
: ()
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => {
|
|
password => { type => Str },
|
|
}
|
|
);
|
|
|
|
sub CheckPasswordLength {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
my $password = $params{'password'};
|
|
my $error_message;
|
|
if ( !length($password) > $MINIMUM_PASSWORD_LENGHT ) {
|
|
$error_message =
|
|
"Password has less than $MINIMUM_PASSWORD_LENGHT characters.";
|
|
}
|
|
return BeastBB::Response->new(
|
|
(
|
|
( defined $error_message )
|
|
? (
|
|
is_error => 1,
|
|
error_message => $error_message
|
|
)
|
|
: ()
|
|
)
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
{
|
|
my $validator = validation_for(
|
|
params => { matrix_address => { type => Str } },
|
|
);
|
|
|
|
sub CheckMatrixAddress {
|
|
my $self = shift;
|
|
my %params = $validator->(@_);
|
|
my $matrix_address = $params{matrix_address};
|
|
my $error_message;
|
|
if ( $matrix_address !~ /$MATRIX_ADDRESS_REGEX/ ) {
|
|
$error_message = "This does not look like a Matrix address.";
|
|
}
|
|
return BeastBB::Response->new(
|
|
(
|
|
( defined $error_message )
|
|
? (
|
|
is_error => 1,
|
|
error_message => $error_message
|
|
)
|
|
: ()
|
|
)
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
sub _App {
|
|
my $self = shift;
|
|
return $self->{app};
|
|
}
|
|
1;
|