From 557ff979c8116346911b110b562dde6ace68d8e3 Mon Sep 17 00:00:00 2001 From: sergiotarxz Date: Mon, 24 May 2021 15:19:04 +0200 Subject: [PATCH] Making the installation basic. --- Makefile.PL | 16 +++--- bin/beastbb | 13 ++++- cpanfile | 6 +++ lib/BeastBB.conf | 2 - lib/BeastBB.pm | 75 ++++++++++++++++++++------ lib/BeastBB/ConfigWriter.pm | 69 ++++++++++++++++++++++++ lib/BeastBB/Constants.pm | 18 +++++++ lib/BeastBB/Controller/Example.pm | 11 ---- lib/BeastBB/Controller/Install.pm | 90 +++++++++++++++++++++++++++++++ lib/BeastBB/DAO/UserManager.pm | 2 + lib/BeastBB/Database.pm | 88 ++++++++++++++++++++++++++++++ lib/BeastBB/Types.pm | 29 ++++++++++ public/js/install/welcome.js | 19 +++++++ t/basic.t | 9 ---- templates/example/welcome.html.ep | 9 ---- templates/install/welcome.html.ep | 31 +++++++++++ templates/layouts/default.html.ep | 5 -- 17 files changed, 429 insertions(+), 63 deletions(-) create mode 100644 cpanfile delete mode 100644 lib/BeastBB.conf create mode 100644 lib/BeastBB/ConfigWriter.pm create mode 100644 lib/BeastBB/Constants.pm delete mode 100644 lib/BeastBB/Controller/Example.pm create mode 100644 lib/BeastBB/Controller/Install.pm create mode 100644 lib/BeastBB/DAO/UserManager.pm create mode 100644 lib/BeastBB/Database.pm create mode 100644 lib/BeastBB/Types.pm create mode 100644 public/js/install/welcome.js delete mode 100644 t/basic.t delete mode 100644 templates/example/welcome.html.ep create mode 100644 templates/install/welcome.html.ep delete mode 100644 templates/layouts/default.html.ep diff --git a/Makefile.PL b/Makefile.PL index 65d42ce..40de158 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -1,5 +1,3 @@ -## Please see file perltidy.ERR -## Please see file perltidy.ERR use ExtUtils::MakeMaker; WriteMakefile( @@ -27,13 +25,11 @@ package MY { return "\n" . "install_frontend:\n" - . "\tif [ ! -e blib/BeastBB/public ]; then " - . "mkdir -pv blib/BeastBB/public; " - . "fi;" - . "if [ ! -e blib/BeastBB/templates ]; then " - . "mkdir -pv blib/BeastBB/templates; " - . "fi; " - . "cp -rfv templates/* blib/BeastBB/templates; " - . "cp -rfv public/* blib/BeastBB/public; "; + . "\tif [ ! -e lib/BeastBB/public ]; then " + . "mkdir -pv lib/BeastBB/public; " . "fi;" + . "if [ ! -e lib/BeastBB/templates ]; then " + . "mkdir -pv lib/BeastBB/templates; " . "fi; " + . "cp -rfv templates/* lib/BeastBB/templates/; " + . "cp -rfv public/* lib/BeastBB/public/; "; } } diff --git a/bin/beastbb b/bin/beastbb index 1e12c9b..6f1c521 100755 --- a/bin/beastbb +++ b/bin/beastbb @@ -3,7 +3,18 @@ use strict; use warnings; +use Data::Dumper; + use Mojolicious::Commands; +use BeastBB; + # Start command line interface for application -Mojolicious::Commands->start_app('BeastBB'); +if (!scalar @ARGV || $ARGV[0] ne 'migrate') { + @ARGV = qw/daemon/; + Mojolicious::Commands->start_app('BeastBB'); + exit; +} + +my $beastbb = BeastBB->new(); +print Data::Dumper::Dumper $beastbb->config; diff --git a/cpanfile b/cpanfile new file mode 100644 index 0000000..08ac9be --- /dev/null +++ b/cpanfile @@ -0,0 +1,6 @@ +requires 'Mojolicious'; +requires 'Mojo::Pg'; +requires 'ExtUtils::MakeMaker'; +requires 'Crypt::URandom'; +requires 'DBD::Pg'; + diff --git a/lib/BeastBB.conf b/lib/BeastBB.conf deleted file mode 100644 index 2c63c08..0000000 --- a/lib/BeastBB.conf +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/lib/BeastBB.pm b/lib/BeastBB.pm index 5356c51..0bb0b62 100644 --- a/lib/BeastBB.pm +++ b/lib/BeastBB.pm @@ -1,24 +1,67 @@ package BeastBB; +use 5.30.3; + +use strict; +use warnings; + +use Data::Dumper; + use Mojo::Base 'Mojolicious'; use Mojo::File; -use Data::Dumper; -sub startup { - my $self = shift; - my $config = $self->plugin( - 'Config', - file => Mojo::File::curfile->dirname->child('BeastBB.conf')->to_string - ); - $self->secrets( $config->{secrets} ); - my $r = $self->routes; - $r->get('/')->to('example#welcome'); - @{ $self->renderer->paths() } = - ( Mojo::File::curfile->dirname->child('BeastBB')->child('templates')->to_string ); - @{ $self->static->paths() } = - ( Mojo::File::curfile->dirname->child('BeastBB')->child('public')->to_string ); - STDERR->print(Data::Dumper::Dumper $self->static->paths()); - STDERR->print(Data::Dumper::Dumper $self->renderer->paths()); +use Const::Fast; +use Params::ValidationCompiler 'validation_for'; +use Crypt::URandom 'urandom'; + +use BeastBB::Constants ( '$HOME_DIR', '$HOME_CONFIG_DIR', '$CONFIG_FILE', '$SECRET_DEFAULT_SIZE' ); +use BeastBB::ConfigWriter; + +sub new { + my $class = shift; + my $self = $class->SUPER::new(@_); + $self; } +sub startup { + my $self = shift; + $self->PrepareConfig; + $self->PrepareSecrets; + $self->PrepareRoutes; + return $self; +} + +sub PrepareSecrets { + my $self = shift; + my $config = $self->config; + $self->secrets( $config->{secrets} ); +} + +sub PrepareRoutes { + my $self = shift; + my $routes = $self->routes; + @{ $self->renderer->paths() } = + ( Mojo::File::curfile->dirname->child('BeastBB')->child('templates') + ->to_string ); + @{ $self->static->paths() } = + ( Mojo::File::curfile->dirname->child('BeastBB')->child('public') + ->to_string ); + print Data::Dumper::Dumper $self->renderer->paths; + if ( !exists $self->config->{installed} ) { + $routes->get('/')->to('install#welcome'); + $routes->post('/install/database')->to('install#install_database'); + } +} + +sub PrepareConfig { + my $self = shift; + $HOME_CONFIG_DIR->make_path if !-e $HOME_CONFIG_DIR; + if ( !-e $CONFIG_FILE ) { + my $config_writer = + BeastBB::ConfigWriter->new( config_file => $CONFIG_FILE ); + $config_writer->PopulateExampleConfigFile( + secret_size => $SECRET_DEFAULT_SIZE ); + } + $self->plugin( Config => file => $CONFIG_FILE->to_string ); +} 1; diff --git a/lib/BeastBB/ConfigWriter.pm b/lib/BeastBB/ConfigWriter.pm new file mode 100644 index 0000000..3c67073 --- /dev/null +++ b/lib/BeastBB/ConfigWriter.pm @@ -0,0 +1,69 @@ +package BeastBB::ConfigWriter; + +use 5.30.3; + +use strict; +use warnings; + +use Params::ValidationCompiler 'validation_for'; +use Types::Standard qw( Str Int ); + +use Crypt::URandom 'urandom'; + +use BeastBB::Types qw/IsClassTypeGenerator/; + +{ + my $validator = validation_for( + params => { + config_file => { type => IsClassTypeGenerator('Mojo::File') }, + }, + ); + + sub new { + my $class = shift; + my %params = $validator->(@_); + my $config_file = $params{config_file}; + return bless { config_file => $config_file }, $class; + } +} + +sub ConfigFile { + my $self = shift; + return $self->{config_file}; +} + +{ + my $validator = validation_for( + params => { + content => { type => Str }, + } + ); + + sub WriteToConfigFile { + my $self = shift; + my %params = $validator->(@_); + my $content = $params{content}; + my $config_file = $self->ConfigFile; + my $config_file_fh = $config_file->open('>') + or die "Unable to write the config file $config_file"; + $config_file_fh->print($content); + } +} +{ + my $validator = + validation_for( params => { secret_size => { type => Int } } ); + + sub PopulateExampleConfigFile { + my $self = shift; + my %params = $validator->(@_); + my $secret_size = $params{secret_size}; + my $config = { + secrets => [ + unpack 'H*', urandom($secret_size), + ] + }; + local $Data::Dumper::Terse = 1; + $self->WriteToConfigFile( content => Data::Dumper::Dumper $config); + } +} +1; diff --git a/lib/BeastBB/Constants.pm b/lib/BeastBB/Constants.pm new file mode 100644 index 0000000..34b2bbb --- /dev/null +++ b/lib/BeastBB/Constants.pm @@ -0,0 +1,18 @@ +package BeastBB::Constants; + +use 5.30.3; + +use strict; +use warnings; + +use Exporter qw/import/; +use Const::Fast; + +our @EXPORT_OK = + ( '$HOME_DIR', '$HOME_CONFIG_DIR', '$CONFIG_FILE', '$SECRET_DEFAULT_SIZE' ); + +const our $HOME_DIR => Mojo::File->new( $ENV{HOME} ); +const our $HOME_CONFIG_DIR => $HOME_DIR->child( '.config', 'beastbb' ); +const our $CONFIG_FILE => $HOME_CONFIG_DIR->child('BeastBB.conf'); +const our $SECRET_DEFAULT_SIZE => 64; +1; diff --git a/lib/BeastBB/Controller/Example.pm b/lib/BeastBB/Controller/Example.pm deleted file mode 100644 index 7710b1b..0000000 --- a/lib/BeastBB/Controller/Example.pm +++ /dev/null @@ -1,11 +0,0 @@ -package BeastBB::Controller::Example; - -use Mojo::Base 'Mojolicious::Controller'; - -sub welcome { - my $self = shift; - $self->render( - msg => 'Welcome to the Mojolicious real-time web framework!' ); -} - -1; diff --git a/lib/BeastBB/Controller/Install.pm b/lib/BeastBB/Controller/Install.pm new file mode 100644 index 0000000..da62ded --- /dev/null +++ b/lib/BeastBB/Controller/Install.pm @@ -0,0 +1,90 @@ +package BeastBB::Controller::Install; + +use 5.30.3; + +use strict; +use warnings; + +use Mojo::Base 'Mojolicious::Controller'; +use Mojo::URL; + +use Params::ValidationCompiler 'validation_for'; +use Types::Standard qw/HashRef/; + +use BeastBB::Database; +use BeastBB::ConfigWriter; +use BeastBB::Constants ('$CONFIG_FILE'); + +sub welcome { + my $self = shift; + my $error = $self->param('error'); + $self->stash( error => $error ); + $self->stash( config => $self->config ); + $self->render; +} + +sub install_database { + my $self = shift; + + if ( exists $self->config->{db} ) { + } + my $config_db; + my $user = $self->param('username'); + my $password = $self->param('password'); + my $host = $self->param('host'); + my $port = $self->param('port'); + my $dbname = $self->param('dbname'); + + $user = undef if ( length $user ) == 0; + $password = undef if ( length $password ) == 0; + $host = undef if ( length $host ) == 0; + $port = undef if ( length $port ) == 0; + $dbname = undef if ( length $dbname ) == 0; + + $config_db = { + ( defined $user ) ? ( user => $user ) : (), + ( defined $password ) ? ( password => $password ) : (), + ( defined $host ) ? ( host => $host ) : (), + ( defined $port ) ? ( port => $port ) : (), + ( defined $dbname ) ? ( dbname => $dbname ) : (), + }; + + eval { $self->TestNewDatabaseConfig( config => $config_db ); }; + + if ($@) { + STDERR->say($@); + my $error_url = Mojo::URL->new('/')->query( error => $@ ); + $self->redirect_to($error_url); + } + $self->config->{db} = $config_db; + local $Data::Dumper::Terse = 1; + my $config_writer = + BeastBB::ConfigWriter->new( config_file => $CONFIG_FILE ); + $config_writer->WriteToConfigFile( content => Data::Dumper::Dumper $self->config ); + $self->redirect_to('/'); +} + +{ + my $validator = + validation_for( params => { config => { type => HashRef } } ); + + sub TestNewDatabaseConfig { + my $self = shift; + my %params = $validator->(@_); + my $config = $params{config}; + my $database = BeastBB::Database->NewFromConfig( config => $config ); + my $succesful_query_result_array = + $database->DB->query('SELECT 1')->array; + if ( + !( + exists $succesful_query_result_array->[0] + && $succesful_query_result_array->[0] == 1 + ) + ) + { + die "Unable to retrieve data from the database."; + } + + } +} +1; diff --git a/lib/BeastBB/DAO/UserManager.pm b/lib/BeastBB/DAO/UserManager.pm new file mode 100644 index 0000000..8953779 --- /dev/null +++ b/lib/BeastBB/DAO/UserManager.pm @@ -0,0 +1,2 @@ +package BeastBB::DAO::UserManager; +1; diff --git a/lib/BeastBB/Database.pm b/lib/BeastBB/Database.pm new file mode 100644 index 0000000..9779c0b --- /dev/null +++ b/lib/BeastBB/Database.pm @@ -0,0 +1,88 @@ +package BeastBB::Database; + +use 5.30.3; + +use strict; +use warnings; + +use Params::ValidationCompiler 'validation_for'; +use Types::Standard qw( HashRef Str ); + +use Mojo::Pg; + +{ + my $validator = validation_for( + params => { config => { type => HashRef } }, + ); + + sub NewFromConfig { + my $class = shift; + my %params = $validator->(@_); + my $config = $params{config}; + $config = {%$config}; + my $user = delete $config->{user}; + my $password = delete $config->{password}; + my %other_params = %$config; + return $class->new( + ( ( defined $user ) ? ( user => $user ) : () ), + ( ( defined $password ) ? ( password => $password ) : () ), + dsn => 'dbi:Pg:' . ( + join ';', + ( + map { + "$_=" + . $class->_SingleQuoteString( $other_params{$_} ) + } keys %other_params + ) + ) + ); + } +} + +{ + my $validator = validation_for( + params => { + user => { type => Str, default => '' }, + password => { type => Str, default => '' }, + dsn => { type => Str }, + }, + ); + + sub new { + my $class = shift; + my $self = bless {}, $class; + $self->{Pg} = Mojo::Pg->new; + my %params = $validator->(@_); + my $user = $params{user}; + my $password = $params{password}; + my $dsn = $params{dsn}; + $self->Pg->username($user) if defined $user; + $self->Pg->password($password) if defined $password; + $self->Pg->dsn($dsn); + return $self; + } +} + +{ + my $validator = validation_for( + params => [ { type => Str->where('$_ !~ /\'/') } ], + ); + + sub _SingleQuoteString { + my $self = shift; + my @params = $validator->(@_); + my $string_to_single_quote = $params[0]; + return "'${string_to_single_quote}'"; + } +} + +sub Pg { + my $self = shift; + return $self->{Pg}; +} + +sub DB { + my $self = shift; + return $self->Pg->db; +} +1; diff --git a/lib/BeastBB/Types.pm b/lib/BeastBB/Types.pm new file mode 100644 index 0000000..637bac0 --- /dev/null +++ b/lib/BeastBB/Types.pm @@ -0,0 +1,29 @@ +package BeastBB::Types; + +use 5.30.3; + +use strict; +use warnings; + +use Exporter qw/import/; +use Scalar::Util qw/blessed/; +use Type::Tiny; +our @EXPORT_OK = qw( &IsClassTypeGenerator ); + +my %generated_classes; + +sub IsClassTypeGenerator { + my $class = shift; + if ( !exists $generated_classes{$class} ) { + my $sanitized_class = $class =~ s/:://gr; + $generated_classes{$class} = Type::Tiny->new( + name => "Is$sanitized_class", + constraint => sub { + my $item_to_test = shift; + return 1 if blessed $item_to_test && $item_to_test->isa($class); + }, + ); + } + return $generated_classes{$class}; +} +1; diff --git a/public/js/install/welcome.js b/public/js/install/welcome.js new file mode 100644 index 0000000..ee96ab4 --- /dev/null +++ b/public/js/install/welcome.js @@ -0,0 +1,19 @@ +window.addEventListener( 'load', (event) => { + load(); +}); + +function load() { + let postgres_password_change_readbility = document.querySelector('#change_readable_password'); + postgres_password_change_readbility.addEventListener('click', (event) => { + change_readbility_password(); + }); +} + +function change_readbility_password() { + let postgres_password = document.querySelector('#postgres_password'); + if ( postgres_password.type === 'password' ) { + postgres_password.type = 'text'; + } else { + postgres_password.type = 'password'; + } +} diff --git a/t/basic.t b/t/basic.t deleted file mode 100644 index fdb7d0c..0000000 --- a/t/basic.t +++ /dev/null @@ -1,9 +0,0 @@ -use Mojo::Base -strict; - -use Test::More; -use Test::Mojo; - -my $t = Test::Mojo->new('BeastBB'); -$t->get_ok('/')->status_is(200)->content_like(qr/Mojolicious/i); - -done_testing(); diff --git a/templates/example/welcome.html.ep b/templates/example/welcome.html.ep deleted file mode 100644 index 0a67219..0000000 --- a/templates/example/welcome.html.ep +++ /dev/null @@ -1,9 +0,0 @@ -% layout 'default'; -% title 'Welcome'; -

<%= $msg %>

-

- This page was generated from the template "templates/example/welcome.html.ep" - and the layout "templates/layouts/default.html.ep", - <%= link_to 'click here' => url_for %> to reload the page or - <%= link_to 'here' => '/index.html' %> to move forward to a static page. -

diff --git a/templates/install/welcome.html.ep b/templates/install/welcome.html.ep new file mode 100644 index 0000000..915e5f8 --- /dev/null +++ b/templates/install/welcome.html.ep @@ -0,0 +1,31 @@ + + + + + + % if ( !defined $config->{db} ) { +

Welcome to the 1 minute BeastBB installation.

+

Please introduce your Postgresql database details.

+

Blank fields will be attempted to be guess to sane value if posible

+ % if ( defined $error ) { +

<%= $error %>

+ % } + +
+

Username.

+ + + +
+ Click here to toggle readable/unreadable the password + + + + + + + +
+ % } + + diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep deleted file mode 100644 index 599c556..0000000 --- a/templates/layouts/default.html.ep +++ /dev/null @@ -1,5 +0,0 @@ - - - <%= title %> - <%= content %> -