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;
|
use ExtUtils::MakeMaker;
|
||||||
|
|
||||||
WriteMakefile(
|
WriteMakefile(
|
||||||
@ -27,13 +25,11 @@ package MY {
|
|||||||
return
|
return
|
||||||
"\n"
|
"\n"
|
||||||
. "install_frontend:\n"
|
. "install_frontend:\n"
|
||||||
. "\tif [ ! -e blib/BeastBB/public ]; then "
|
. "\tif [ ! -e lib/BeastBB/public ]; then "
|
||||||
. "mkdir -pv blib/BeastBB/public; "
|
. "mkdir -pv lib/BeastBB/public; " . "fi;"
|
||||||
. "fi;"
|
. "if [ ! -e lib/BeastBB/templates ]; then "
|
||||||
. "if [ ! -e blib/BeastBB/templates ]; then "
|
. "mkdir -pv lib/BeastBB/templates; " . "fi; "
|
||||||
. "mkdir -pv blib/BeastBB/templates; "
|
. "cp -rfv templates/* lib/BeastBB/templates/; "
|
||||||
. "fi; "
|
. "cp -rfv public/* lib/BeastBB/public/; ";
|
||||||
. "cp -rfv templates/* blib/BeastBB/templates; "
|
|
||||||
. "cp -rfv public/* blib/BeastBB/public; ";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
bin/beastbb
13
bin/beastbb
@ -3,7 +3,18 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
use Mojolicious::Commands;
|
use Mojolicious::Commands;
|
||||||
|
|
||||||
|
use BeastBB;
|
||||||
|
|
||||||
# Start command line interface for application
|
# 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;
|
package BeastBB;
|
||||||
|
|
||||||
|
use 5.30.3;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
use Mojo::Base 'Mojolicious';
|
use Mojo::Base 'Mojolicious';
|
||||||
use Mojo::File;
|
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 {
|
sub startup {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $config = $self->plugin(
|
$self->PrepareConfig;
|
||||||
'Config',
|
$self->PrepareSecrets;
|
||||||
file => Mojo::File::curfile->dirname->child('BeastBB.conf')->to_string
|
$self->PrepareRoutes;
|
||||||
);
|
return $self;
|
||||||
$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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
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