Adding a few dao and model to use the data defined in the database migration
Also some tests are added.
This commit is contained in:
parent
39c8bcbc89
commit
1bcb9bf973
@ -15,8 +15,8 @@ package MY {
|
|||||||
my $return = $self->SUPER::top_targets(@_);
|
my $return = $self->SUPER::top_targets(@_);
|
||||||
$return = [ split /\n/, $return ];
|
$return = [ split /\n/, $return ];
|
||||||
for my $i ( keys @$return ) {
|
for my $i ( keys @$return ) {
|
||||||
$return->[$i] .= ' install_frontend'
|
$return->[$i] .= ' install_frontend_and_migrations'
|
||||||
if $return->[$i] =~ /^all :/;
|
if $return->[$i] =~ /^install :/;
|
||||||
}
|
}
|
||||||
return join "\n", @$return;
|
return join "\n", @$return;
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ package MY {
|
|||||||
sub postamble {
|
sub postamble {
|
||||||
return
|
return
|
||||||
"\n"
|
"\n"
|
||||||
. "install_frontend:\n"
|
. "install_frontend_and_migrations:\n"
|
||||||
. "\tif [ ! -e lib/BeastBB/public ]; then "
|
. "\tif [ ! -e lib/BeastBB/public ]; then "
|
||||||
. "mkdir -pv lib/BeastBB/public; " . "fi;"
|
. "mkdir -pv lib/BeastBB/public; " . "fi;"
|
||||||
. "if [ ! -e lib/BeastBB/templates ]; then "
|
. "if [ ! -e lib/BeastBB/templates ]; then "
|
||||||
|
3
cpanfile
3
cpanfile
@ -8,3 +8,6 @@ requires 'Params::ValidationCompiler';
|
|||||||
requires 'Types::Standard';
|
requires 'Types::Standard';
|
||||||
requires 'Crypt::Bcrypt::Easy';
|
requires 'Crypt::Bcrypt::Easy';
|
||||||
requires 'DateTime';
|
requires 'DateTime';
|
||||||
|
requires 'DateTime::Format::ISO8601';
|
||||||
|
requires 'Test::Most';
|
||||||
|
requires 'Test::MockModule';
|
||||||
|
@ -19,6 +19,7 @@ use BeastBB::Constants (
|
|||||||
);
|
);
|
||||||
use BeastBB::ConfigWriter;
|
use BeastBB::ConfigWriter;
|
||||||
use BeastBB::Database;
|
use BeastBB::Database;
|
||||||
|
use BeastBB::Response;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
@ -48,6 +49,14 @@ sub PrepareHelpers {
|
|||||||
return $database;
|
return $database;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
$self->helper(
|
||||||
|
logged_user => sub {
|
||||||
|
my $self = shift;
|
||||||
|
my $session = $self->session;
|
||||||
|
return BeastBB::Response->new( is_error => 1, error_message => 'User is not logged in.');
|
||||||
|
my $username = $session->{username};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +69,7 @@ sub PrepareSecrets {
|
|||||||
sub PrepareRoutes {
|
sub PrepareRoutes {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $routes = $self->routes;
|
my $routes = $self->routes;
|
||||||
|
|
||||||
@{ $self->renderer->paths() } =
|
@{ $self->renderer->paths() } =
|
||||||
( Mojo::File::curfile->dirname->child('BeastBB')->child('templates')
|
( Mojo::File::curfile->dirname->child('BeastBB')->child('templates')
|
||||||
->to_string );
|
->to_string );
|
||||||
@ -68,11 +78,31 @@ sub PrepareRoutes {
|
|||||||
->to_string );
|
->to_string );
|
||||||
print Data::Dumper::Dumper $self->renderer->paths;
|
print Data::Dumper::Dumper $self->renderer->paths;
|
||||||
if ( !exists $self->config->{finished_install} ) {
|
if ( !exists $self->config->{finished_install} ) {
|
||||||
$routes->get('/')->to('install#welcome');
|
$self->PrepareInstallationRoutes;
|
||||||
$routes->post('/install/database')->to('install#install_database');
|
return;
|
||||||
$routes->post('/install/admin_user_create')
|
|
||||||
->to('install#admin_user_create');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$self->PrepareCommonRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub PrepareCommonRoutes {
|
||||||
|
my $self = shift;
|
||||||
|
my $routes = $self->routes;
|
||||||
|
|
||||||
|
$routes->get('/')->to('Main#Index');
|
||||||
|
$routes->get('/login')->to('Main#GetLogin');
|
||||||
|
$routes->post('/login')->to('Main#Login');
|
||||||
|
$routes->post('/logout')->to('Main#Logout');
|
||||||
|
}
|
||||||
|
|
||||||
|
sub PrepareInstallationRoutes {
|
||||||
|
my $self = shift;
|
||||||
|
my $routes = $self->routes;
|
||||||
|
|
||||||
|
$routes->get('/')->to('install#welcome');
|
||||||
|
$routes->post('/install/database')->to('install#install_database');
|
||||||
|
$routes->post('/install/admin_user_create')
|
||||||
|
->to('install#admin_user_create');
|
||||||
}
|
}
|
||||||
|
|
||||||
sub PrepareConfig {
|
sub PrepareConfig {
|
||||||
|
@ -85,7 +85,7 @@ sub admin_user_create {
|
|||||||
repeat_password => $repeat_password
|
repeat_password => $repeat_password
|
||||||
);
|
);
|
||||||
my $user_manager = BeastBB::DAO::UserManager->new( app => $self );
|
my $user_manager = BeastBB::DAO::UserManager->new( app => $self );
|
||||||
my $response_create_user = $user_manager->CreateUser(
|
my $response_create_user = $user_manager->Create(
|
||||||
username => $username,
|
username => $username,
|
||||||
matrix_address => $matrix_address,
|
matrix_address => $matrix_address,
|
||||||
password => $password,
|
password => $password,
|
||||||
|
15
lib/BeastBB/Controller/Main.pm
Normal file
15
lib/BeastBB/Controller/Main.pm
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package BeastBB::Controller::Main;
|
||||||
|
|
||||||
|
use 5.30.3;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Mojo::Base 'Mojolicious::Controller';
|
||||||
|
|
||||||
|
sub Index {
|
||||||
|
my $self = shift;
|
||||||
|
$self->stash( session => $self->session );
|
||||||
|
$self->render;
|
||||||
|
}
|
||||||
|
1;
|
160
lib/BeastBB/DAO/GroupManager.pm
Normal file
160
lib/BeastBB/DAO/GroupManager.pm
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package BeastBB::DAO::GroupManager;
|
||||||
|
|
||||||
|
use 5.32.1;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Carp;
|
||||||
|
|
||||||
|
use Params::ValidationCompiler 'validation_for';
|
||||||
|
use Types::Standard qw/Bool Str Int/;
|
||||||
|
|
||||||
|
use BeastBB::Response;
|
||||||
|
|
||||||
|
{
|
||||||
|
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_group => { type => Int, optional => 1 },
|
||||||
|
groupname => { type => Str, optional => 1 },
|
||||||
|
recover_privileges => { type => Bool, default => 0 },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub Get {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my ( $id_group, $groupname, $recover_privileges ) =
|
||||||
|
@params{ 'id_group', 'groupname', 'recover_privileges' };
|
||||||
|
|
||||||
|
$self->_CheckGetRequirements(
|
||||||
|
( ( defined $id_group ) ? ( id_group => $id_group ) : () ),
|
||||||
|
( ( defined $groupname ) ? ( groupname => $groupname ) : () )
|
||||||
|
);
|
||||||
|
|
||||||
|
my $maybe_group_hash = $self->_RecoverGroupFromDatabase(
|
||||||
|
( ( defined $id_group ) ? ( id_group => $id_group ) : () ),
|
||||||
|
( ( defined $groupname ) ? ( groupname => $groupname ) : () )
|
||||||
|
);
|
||||||
|
|
||||||
|
return $maybe_group_hash if $maybe_group_hash->IsError;
|
||||||
|
$group_hash = $maybe_group_hash;
|
||||||
|
my $group = BeastBB::Model::Group->new(%$group_hash);
|
||||||
|
|
||||||
|
my $privileges;
|
||||||
|
if ($recover_privileges) {
|
||||||
|
$self->RecoverPrivilegesGroup( group => $group );
|
||||||
|
}
|
||||||
|
|
||||||
|
return BeastBB::Response->new( content => $group );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
id_group => { type => Int, optional => 1 },
|
||||||
|
groupname => { type => Str, optional => 1 },
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _CheckGetRequirements {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my ( $id_group, $groupname, ) = @params{ 'id_group', 'groupname', };
|
||||||
|
|
||||||
|
confess "${class}::Get should be used passing id_group xor groupname."
|
||||||
|
unless ( defined $id_group xor defined $groupname );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
id_group => { type => Int, optional => 1 },
|
||||||
|
groupname => { type => Str, optional => 1 },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _RecoverGroupFromDatabase {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
|
||||||
|
my $id_group = $params{id_group};
|
||||||
|
my $groupname = $params{groupname};
|
||||||
|
|
||||||
|
my $app = $self->_App;
|
||||||
|
my $database = $app->db;
|
||||||
|
my $pg = $database->Pg->db;
|
||||||
|
|
||||||
|
my $selected_group = $pg->select(
|
||||||
|
'group',
|
||||||
|
[ 'id_group', 'groupname' ],
|
||||||
|
{
|
||||||
|
( ( defined $id_group ) ? ( id_group => $id_group ) : () ),
|
||||||
|
( ( defined $groupname ) ? ( groupname => $groupname ) : () )
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if ( !$selected_group->rows ) {
|
||||||
|
return BeastBB::Response->new(
|
||||||
|
is_error => 1,
|
||||||
|
error_message => 'No such group.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return BeastBB::Response->new( content => $selected_group->hash );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
group => { type => IsClassTypeGenerator('BeastBB::Model::Group') },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub RecoverPrivilegesGroup {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $group = $params{group};
|
||||||
|
my $id_group = $group->IdGroup;
|
||||||
|
|
||||||
|
my $app = $self->_App;
|
||||||
|
my $database = $app->db;
|
||||||
|
my $pg = $database->Pg->db;
|
||||||
|
|
||||||
|
my $selected_privileges = $pg->query(
|
||||||
|
'SELECT privilege.name'
|
||||||
|
. ' FROM group_privilege'
|
||||||
|
. ' INNER JOIN privilege USING (id_privilege)'
|
||||||
|
. ' WHERE id_group=?',
|
||||||
|
$id_group
|
||||||
|
);
|
||||||
|
if ( $selected_privileges->rows ) {
|
||||||
|
my $hashes_privileges = $selected_privileges->hashes;
|
||||||
|
$privileges =
|
||||||
|
{ map { $_->{name} => 1 } @$hashes_privileges };
|
||||||
|
}
|
||||||
|
$privileges //= {};
|
||||||
|
$group->Privileges($privileges);
|
||||||
|
return $group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _App {
|
||||||
|
return $self->{app};
|
||||||
|
}
|
||||||
|
1;
|
@ -1,10 +1,11 @@
|
|||||||
package BeastBB::DAO::UserManager;
|
package BeastBB::DAO::UserManager;
|
||||||
|
|
||||||
use 5.32.1;
|
use 5.32.1;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Data::Dumper;
|
use Carp;
|
||||||
|
|
||||||
use Params::ValidationCompiler 'validation_for';
|
use Params::ValidationCompiler 'validation_for';
|
||||||
use Types::Standard qw/Bool Str/;
|
use Types::Standard qw/Bool Str/;
|
||||||
@ -13,8 +14,11 @@ use Crypt::Bcrypt::Easy;
|
|||||||
use Const::Fast;
|
use Const::Fast;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
|
||||||
use BeastBB::Types ( '$MATRIX_ADDRESS_REGEX', 'IsClassTypeGenerator' );
|
use BeastBB::Types (
|
||||||
use BeastBB::DAO::Response;
|
'$MATRIX_ADDRESS_REGEX', 'IsClassTypeGenerator',
|
||||||
|
'$MATRIX_ADDRESS_TYPE'
|
||||||
|
);
|
||||||
|
use BeastBB::Response;
|
||||||
|
|
||||||
const my $MINIMUM_PASSWORD_LENGHT => 8;
|
const my $MINIMUM_PASSWORD_LENGHT => 8;
|
||||||
|
|
||||||
@ -32,6 +36,135 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
$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::ISO8601->parse_datetime(
|
||||||
|
$user_hash->{creation_date} );
|
||||||
|
$user_hash->{last_connection} =
|
||||||
|
DateTime::Format::ISO8601->parse_datetime(
|
||||||
|
$user_hash->{last_connection} );
|
||||||
|
|
||||||
|
return BeastBB::Response( content => $user_hash );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
my $validator = validation_for(
|
my $validator = validation_for(
|
||||||
params => {
|
params => {
|
||||||
@ -44,7 +177,7 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
sub CreateUser {
|
sub Create {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my %params = $validator->(@_);
|
my %params = $validator->(@_);
|
||||||
my (
|
my (
|
||||||
@ -72,7 +205,7 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
my $result =
|
my $result =
|
||||||
$pg->select( 'group', 'id_group', { groupname => $groupname } );
|
$pg->select( 'group', 'id_group', { groupname => $groupname } );
|
||||||
if ( !$result->rows ) {
|
if ( !$result->rows ) {
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
is_error => 1,
|
is_error => 1,
|
||||||
error_message => "Unable to find the group $groupname."
|
error_message => "Unable to find the group $groupname."
|
||||||
);
|
);
|
||||||
@ -96,14 +229,13 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( !$result_create_user->rows ) {
|
if ( !$result_create_user->rows ) {
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
is_error => 1,
|
is_error => 1,
|
||||||
error_message => "Unable to create user $username.",
|
error_message => "Unable to create user $username.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
content => $result_create_user->hash->{id_user}
|
content => $result_create_user->hash->{id_user} );
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +287,7 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
if ( $password ne $repeat_password ) {
|
if ( $password ne $repeat_password ) {
|
||||||
$error_message = 'Password and repeat password not matching.';
|
$error_message = 'Password and repeat password not matching.';
|
||||||
}
|
}
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
(
|
(
|
||||||
( defined $error_message )
|
( defined $error_message )
|
||||||
? (
|
? (
|
||||||
@ -183,7 +315,7 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
if ( $password =~ /^\d+$/ ) {
|
if ( $password =~ /^\d+$/ ) {
|
||||||
$error_message = "Password is numeric, it is not allowed.";
|
$error_message = "Password is numeric, it is not allowed.";
|
||||||
}
|
}
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
(
|
(
|
||||||
( defined $error_message )
|
( defined $error_message )
|
||||||
? (
|
? (
|
||||||
@ -212,7 +344,7 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
$error_message =
|
$error_message =
|
||||||
"Password has less than $MINIMUM_PASSWORD_LENGHT characters.";
|
"Password has less than $MINIMUM_PASSWORD_LENGHT characters.";
|
||||||
}
|
}
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
(
|
(
|
||||||
( defined $error_message )
|
( defined $error_message )
|
||||||
? (
|
? (
|
||||||
@ -239,7 +371,7 @@ const my $MINIMUM_PASSWORD_LENGHT => 8;
|
|||||||
if ( $matrix_address !~ /$MATRIX_ADDRESS_REGEX/ ) {
|
if ( $matrix_address !~ /$MATRIX_ADDRESS_REGEX/ ) {
|
||||||
$error_message = "This does not look like a Matrix address.";
|
$error_message = "This does not look like a Matrix address.";
|
||||||
}
|
}
|
||||||
return BeastBB::DAO::Response->new(
|
return BeastBB::Response->new(
|
||||||
(
|
(
|
||||||
( defined $error_message )
|
( defined $error_message )
|
||||||
? (
|
? (
|
||||||
|
102
lib/BeastBB/Model/Group.pm
Normal file
102
lib/BeastBB/Model/Group.pm
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package BeastBB::Model::Group;
|
||||||
|
use 5.32.1;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Params::ValidationCompiler 'validation_for';
|
||||||
|
use Types::Standard qw/Int Str HashRef Bool/;
|
||||||
|
|
||||||
|
use BeastBB::Response;
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
id_group => { type => Int, optional => 1 },
|
||||||
|
groupname => { type => Str },
|
||||||
|
privileges => { type => HashRef [Bool], optional => 1 },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
return bless \%params, $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Hash {
|
||||||
|
my $self = shift;
|
||||||
|
my $maybe_id_group = $self->IdGroup;
|
||||||
|
my $maybe_privileges = $self->Privileges;
|
||||||
|
return {
|
||||||
|
(
|
||||||
|
( !$maybe_id_group->IsError )
|
||||||
|
? ( id_group => $maybe_id_group->Content )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
( !$maybe_privileges->IsError )
|
||||||
|
? ( privileges => $maybe_privileges->Content )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
groupname => $self->{groupname},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub IdGroup {
|
||||||
|
my $self = shift;
|
||||||
|
my $id_group = $self->{id_group};
|
||||||
|
return BeastBB::Response->new(
|
||||||
|
is_error => 1,
|
||||||
|
error_message => 'No id group set to this model.'
|
||||||
|
) if !defined $id_group;
|
||||||
|
return BeastBB::Response->new( content => $id_group );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{ type => Int },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
sub SetIdGroup {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $id_group = shift;
|
||||||
|
$self->{id_group} = $id_group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Groupname {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{groupname};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{ type => HashRef [Bool], optional => 1 },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
sub Privileges {
|
||||||
|
my $self = shift;
|
||||||
|
@_ = $validator->(@_);
|
||||||
|
|
||||||
|
if (@_) {
|
||||||
|
$self->{privileges} = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !defined $self->{privileges} ) {
|
||||||
|
return BeastBB::Response->new(
|
||||||
|
is_error => 1,
|
||||||
|
error_message => 'Privileges not recovered yet for this group.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return BeastBB::Response->new( content => $self->{privileges} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
217
lib/BeastBB/Model/User.pm
Normal file
217
lib/BeastBB/Model/User.pm
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
package BeastBB::Model::User;
|
||||||
|
|
||||||
|
use 5.32.1;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Params::ValidationCompiler 'validation_for';
|
||||||
|
use Types::Standard qw/Str Bool Int/;
|
||||||
|
|
||||||
|
use BeastBB::Types qw/$MATRIX_ADDRESS_TYPE IsClassTypeGenerator/;
|
||||||
|
use BeastBB::Response;
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
id_user => { type => Int, optional => 1 },
|
||||||
|
group => {
|
||||||
|
type => IsClassTypeGenerator('BeastBB::Model::Group'),
|
||||||
|
optional => 1
|
||||||
|
},
|
||||||
|
username => { type => Str },
|
||||||
|
matrix_address => { type => Str },
|
||||||
|
password_bcrypt => { type => Str },
|
||||||
|
is_confirmed => { type => Bool, default => 0 },
|
||||||
|
creation_date => {
|
||||||
|
type => IsClassTypeGenerator('DateTime'),
|
||||||
|
default => sub { return DateTime->now }
|
||||||
|
},
|
||||||
|
last_connection => {
|
||||||
|
type => IsClassTypeGenerator('DateTime'),
|
||||||
|
default => sub { return DateTime->now }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
return bless \%params, $class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Hash {
|
||||||
|
my $self = shift;
|
||||||
|
return {
|
||||||
|
(
|
||||||
|
( !$self->IdUser->IsError )
|
||||||
|
? ( id_user => $self->IdUser->Content )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
( !$self->Group->IsError )
|
||||||
|
? ( group => $self->Group->Content->hash )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
username => $self->Username,
|
||||||
|
matrix_address => $self->MatrixAddress,
|
||||||
|
password_bcrypt => $self->PasswordBcrypt,
|
||||||
|
is_confirmed => $self->IsConfirmed,
|
||||||
|
creation_date => $self->CreationDate,
|
||||||
|
last_connection => $self->LastConnection,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{
|
||||||
|
type => IsClassTypeGenerator('BeastBB::Model::Group'),
|
||||||
|
optional => 1
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
sub Group {
|
||||||
|
my $self = shift;
|
||||||
|
@_ = $validator->(@_);
|
||||||
|
|
||||||
|
if (@_) {
|
||||||
|
$self->{group} = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !defined $self->{group} ) {
|
||||||
|
return BeastBB::Response->new(
|
||||||
|
is_error => 1,
|
||||||
|
error_message => 'No group recovered for this user.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return BeastBB::Model::Group->new(
|
||||||
|
content => $self->{group},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub IdUser {
|
||||||
|
my $self = shift;
|
||||||
|
my $id_user = $self->{id_user};
|
||||||
|
return BeastBB::Response->new(
|
||||||
|
is_error => 1,
|
||||||
|
error_message => 'Id user not set for this user model.'
|
||||||
|
) if !defined $id_user;
|
||||||
|
return BeastBB::Response->new( content => $self->{id_user} );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{ type => Int },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
sub SetIdUser {
|
||||||
|
my $self = shift;
|
||||||
|
@_ = $validator->(@_);
|
||||||
|
$self->{id_user} = shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub Username {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{username};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator =
|
||||||
|
validation_for(
|
||||||
|
params => [ { type => $MATRIX_ADDRESS_TYPE, optional => 1 } ] );
|
||||||
|
|
||||||
|
sub MatrixAddress {
|
||||||
|
my $self = shift;
|
||||||
|
@_ = $validator->(@_);
|
||||||
|
if (@_) {
|
||||||
|
$self->{matrix_address} = shift;
|
||||||
|
}
|
||||||
|
return $self->{matrix_address};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{
|
||||||
|
type => Str,
|
||||||
|
optional => 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
sub PasswordBcrypt {
|
||||||
|
my $self = shift;
|
||||||
|
@_ = $validator->(@_);
|
||||||
|
if (@_) {
|
||||||
|
$self->{password_bcrypt} = shift;
|
||||||
|
}
|
||||||
|
return $self->{password_bcrypt};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{
|
||||||
|
type => Bool,
|
||||||
|
optional => 1
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
sub IsConfirmed {
|
||||||
|
my $self = shift;
|
||||||
|
@_ = $validator->(@_);
|
||||||
|
if (@_) {
|
||||||
|
$self->{is_confirmed} = shift;
|
||||||
|
}
|
||||||
|
return $self->{is_confirmed};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{
|
||||||
|
type => IsClassTypeGenerator('DateTime'),
|
||||||
|
optional => 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
sub CreationDate {
|
||||||
|
my $self = shift;
|
||||||
|
if (@_) {
|
||||||
|
$self->{creation_date} = shift;
|
||||||
|
}
|
||||||
|
return $self->{creation_date};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
{
|
||||||
|
type => IsClassTypeGenerator('DateTime'),
|
||||||
|
optional => 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
sub LastConnection {
|
||||||
|
my $self = shift;
|
||||||
|
if (@_) {
|
||||||
|
$self->{last_connection} = shift;
|
||||||
|
}
|
||||||
|
return $self->{last_connection};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1;
|
@ -1,4 +1,4 @@
|
|||||||
package BeastBB::DAO::Response;
|
package BeastBB::Response;
|
||||||
|
|
||||||
use 5.32.1;
|
use 5.32.1;
|
||||||
|
|
@ -24,7 +24,7 @@ create table "user" (
|
|||||||
is_confirmed BOOLEAN DEFAULT false,
|
is_confirmed BOOLEAN DEFAULT false,
|
||||||
creation_date TIMESTAMP NOT NULL,
|
creation_date TIMESTAMP NOT NULL,
|
||||||
id_group BIGINT NOT NULL,
|
id_group BIGINT NOT NULL,
|
||||||
last_connection TIMESTAMP,
|
last_connection TIMESTAMP NOT NULL,
|
||||||
FOREIGN KEY (id_group) REFERENCES "group" (id_group)
|
FOREIGN KEY (id_group) REFERENCES "group" (id_group)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
62
t/Model/00-user.t
Normal file
62
t/Model/00-user.t
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use 5.32.1;
|
||||||
|
|
||||||
|
use Test::Most tests => 7;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Const::Fast;
|
||||||
|
use Crypt::Bcrypt::Easy;
|
||||||
|
use DateTime;
|
||||||
|
use Scalar::Util 'blessed';
|
||||||
|
|
||||||
|
const my %REQUIRED_FIELDS_USER => (
|
||||||
|
username => 'example_username',
|
||||||
|
matrix_address => '@example_username:example_host.com',
|
||||||
|
password_bcrypt => bcrypt->crypt('example_password'),
|
||||||
|
is_confirmed => 1,
|
||||||
|
creation_date => DateTime->new( year => 2021, month => 06, day => 3 ),
|
||||||
|
last_connection => DateTime->now,
|
||||||
|
);
|
||||||
|
{
|
||||||
|
use_ok 'BeastBB::Model::User';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $user = BeastBB::Model::User->new(%REQUIRED_FIELDS_USER);
|
||||||
|
ok defined $user && $user->isa('BeastBB::Model::User'),
|
||||||
|
'This user is made of BeastBB::Model::User.';
|
||||||
|
my $user_hash = $user->Hash;
|
||||||
|
%$user_hash = map {
|
||||||
|
my $value = $user_hash->{$_};
|
||||||
|
(
|
||||||
|
$_ => (
|
||||||
|
( blessed $value && $value->isa('DateTime') )
|
||||||
|
? "$value"
|
||||||
|
: $value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} keys %$user_hash;
|
||||||
|
is_deeply $user_hash, \%REQUIRED_FIELDS_USER, 'User has the expected hash.';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $user = BeastBB::Model::User->new(%REQUIRED_FIELDS_USER);
|
||||||
|
ok $user->IdUser->IsError, 'Id user can not be retrieved before set.';
|
||||||
|
$user->SetIdUser(1);
|
||||||
|
ok !$user->IdUser->IsError, 'Id user can be retrieved after set.';
|
||||||
|
is $user->IdUser->Content, 1, 'Id user can be set on runtime.';
|
||||||
|
my $user_hash = $user->Hash;
|
||||||
|
%$user_hash = map {
|
||||||
|
my $value = $user_hash->{$_};
|
||||||
|
(
|
||||||
|
$_ => (
|
||||||
|
( blessed $value && $value->isa('DateTime') )
|
||||||
|
? "$value"
|
||||||
|
: $value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} keys %$user_hash;
|
||||||
|
is_deeply $user_hash, { %REQUIRED_FIELDS_USER, id_user => 1 },
|
||||||
|
'User has the expected hash with id set after creation.';
|
||||||
|
}
|
22
t/Model/01-group.t
Normal file
22
t/Model/01-group.t
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use 5.32.1;
|
||||||
|
|
||||||
|
use Test::Most tests => 3;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Const::Fast;
|
||||||
|
|
||||||
|
const my %REQUIRED_FIELDS_GROUP => ( groupname => 'example_group' );
|
||||||
|
|
||||||
|
{
|
||||||
|
use_ok 'BeastBB::Model::Group';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $group = BeastBB::Model::Group->new(%REQUIRED_FIELDS_GROUP);
|
||||||
|
ok $group->isa('BeastBB::Model::Group'),
|
||||||
|
'Group is made of BeastBB::Model::Group.';
|
||||||
|
is_deeply $group->Hash, \%REQUIRED_FIELDS_GROUP,
|
||||||
|
'The generated hash of group is correct.';
|
||||||
|
}
|
1
templates/main/Index.html.ep
Normal file
1
templates/main/Index.html.ep
Normal file
@ -0,0 +1 @@
|
|||||||
|
<h1>Hello world</h1>
|
Loading…
Reference in New Issue
Block a user