Making the installation basic.

This commit is contained in:
sergiotarxz 2021-05-24 15:19:04 +02:00
parent d3cedf05b5
commit 557ff979c8
Signed by: sergiotarxz
GPG Key ID: E5903508B6510AC2
17 changed files with 429 additions and 63 deletions

View File

@ -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/; ";
}
}

View File

@ -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;

6
cpanfile Normal file
View File

@ -0,0 +1,6 @@
requires 'Mojolicious';
requires 'Mojo::Pg';
requires 'ExtUtils::MakeMaker';
requires 'Crypt::URandom';
requires 'DBD::Pg';

View File

@ -1,2 +0,0 @@
{
}

View File

@ -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;

View File

@ -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;

18
lib/BeastBB/Constants.pm Normal file
View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,2 @@
package BeastBB::DAO::UserManager;
1;

88
lib/BeastBB/Database.pm Normal file
View File

@ -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;

29
lib/BeastBB/Types.pm Normal file
View File

@ -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;

View File

@ -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';
}
}

View File

@ -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();

View File

@ -1,9 +0,0 @@
% layout 'default';
% title 'Welcome';
<h2><%= $msg %></h2>
<p>
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.
</p>

View File

@ -0,0 +1,31 @@
<html>
<head>
<script src="js/install/welcome.js"></script>
</head>
<body>
% if ( !defined $config->{db} ) {
<h1>Welcome to the 1 minute BeastBB installation.</h1>
<h2>Please introduce your Postgresql database details.</h2>
<p>Blank fields will be attempted to be guess to sane value if posible</p>
% if ( defined $error ) {
<p style="color: red;"><%= $error %></p>
% }
<form method="POST" action="/install/database">
<h3>Username.</h3>
<label for="username"><input type="text" name="username"/></label>
<label for"password"><h3>Password.</h3></label>
<input type="password" name="password" id="postgres_password"/>
<br>
<a href="#" id="change_readable_password">Click here to toggle readable/unreadable the password</a>
<label for="host"><h3>Host</h3></label>
<input type="text" name="host"/>
<label for="port"><h3>Port</h3></label>
<input type="number" name="port"/>
<label for="dbname"><h3>Database Name</h3></label>
<input type="text" name="dbname"/>
<input type="submit" value="Submit"/>
</form>
% }
</body>
</html>

View File

@ -1,5 +0,0 @@
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>