Making the installation basic.
This commit is contained in:
parent
d3cedf05b5
commit
557ff979c8
16
Makefile.PL
16
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/; ";
|
||||
}
|
||||
}
|
||||
|
13
bin/beastbb
13
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;
|
||||
|
6
cpanfile
Normal file
6
cpanfile
Normal file
@ -0,0 +1,6 @@
|
||||
requires 'Mojolicious';
|
||||
requires 'Mojo::Pg';
|
||||
requires 'ExtUtils::MakeMaker';
|
||||
requires 'Crypt::URandom';
|
||||
requires 'DBD::Pg';
|
||||
|
@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
@ -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;
|
||||
|
||||
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;
|
||||
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());
|
||||
$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;
|
||||
|
69
lib/BeastBB/ConfigWriter.pm
Normal file
69
lib/BeastBB/ConfigWriter.pm
Normal 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
18
lib/BeastBB/Constants.pm
Normal 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;
|
@ -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;
|
90
lib/BeastBB/Controller/Install.pm
Normal file
90
lib/BeastBB/Controller/Install.pm
Normal 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;
|
2
lib/BeastBB/DAO/UserManager.pm
Normal file
2
lib/BeastBB/DAO/UserManager.pm
Normal file
@ -0,0 +1,2 @@
|
||||
package BeastBB::DAO::UserManager;
|
||||
1;
|
88
lib/BeastBB/Database.pm
Normal file
88
lib/BeastBB/Database.pm
Normal 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
29
lib/BeastBB/Types.pm
Normal 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;
|
19
public/js/install/welcome.js
Normal file
19
public/js/install/welcome.js
Normal 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';
|
||||
}
|
||||
}
|
@ -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();
|
@ -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>
|
31
templates/install/welcome.html.ep
Normal file
31
templates/install/welcome.html.ep
Normal 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>
|
@ -1,5 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title><%= title %></title></head>
|
||||
<body><%= content %></body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user