Adding first working sign up.
This commit is contained in:
parent
21d9f46d03
commit
3396c36529
2
Build.PL
2
Build.PL
@ -29,6 +29,8 @@ my $build = Module::Build->new(
|
|||||||
'Lingua::Stem::Snowball' => 0,
|
'Lingua::Stem::Snowball' => 0,
|
||||||
'Mojo::Redis' => 0,
|
'Mojo::Redis' => 0,
|
||||||
'DBIx::Class' => 0,
|
'DBIx::Class' => 0,
|
||||||
|
'UUID::URandom' => 0,
|
||||||
|
'Crypt::Bcrypt' => 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
$build->create_build_script;
|
$build->create_build_script;
|
||||||
|
@ -14,17 +14,20 @@ export default class Conquer {
|
|||||||
private disableSetRotationOffset = false
|
private disableSetRotationOffset = false
|
||||||
private conquerLogin: HTMLDivElement
|
private conquerLogin: HTMLDivElement
|
||||||
private conquerLoginGoToRegister: HTMLAnchorElement
|
private conquerLoginGoToRegister: HTMLAnchorElement
|
||||||
|
private conquerLoginError: HTMLParagraphElement
|
||||||
|
private conquerLoginSuccess: HTMLParagraphElement
|
||||||
private conquerRegisterGoToLogin: HTMLAnchorElement
|
private conquerRegisterGoToLogin: HTMLAnchorElement
|
||||||
private conquerRegister: HTMLDivElement
|
private conquerRegister: HTMLDivElement
|
||||||
|
private conquerRegisterUsername: HTMLInputElement
|
||||||
|
private conquerRegisterPassword: HTMLInputElement
|
||||||
|
private conquerRegisterRepeatPassword: HTMLInputElement
|
||||||
|
private conquerRegisterSubmit: HTMLButtonElement
|
||||||
|
private conquerRegisterError: HTMLParagraphElement
|
||||||
private alpha = 0;
|
private alpha = 0;
|
||||||
private beta = 0;
|
private beta = 0;
|
||||||
private gamma = 0;
|
private gamma = 0;
|
||||||
static start() {
|
static start() {
|
||||||
const conquerContainer = document.querySelector(".conquer-container");
|
const conquerContainer = document.querySelector(".conquer-container");
|
||||||
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
|
|
||||||
alert("Error occured: " + errorMsg);//or any message
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (conquerContainer !== null) {
|
if (conquerContainer !== null) {
|
||||||
if (!(conquerContainer instanceof HTMLDivElement)) {
|
if (!(conquerContainer instanceof HTMLDivElement)) {
|
||||||
console.error(".conquer-container is not a div.");
|
console.error(".conquer-container is not a div.");
|
||||||
@ -60,6 +63,16 @@ export default class Conquer {
|
|||||||
this.conquerLoginGoToRegister.addEventListener('click', () => {
|
this.conquerLoginGoToRegister.addEventListener('click', () => {
|
||||||
this.goToRegister()
|
this.goToRegister()
|
||||||
})
|
})
|
||||||
|
const conquerLoginError = document.querySelector('.conquer-login-error')
|
||||||
|
if (conquerLoginError === null || !(conquerLoginError instanceof HTMLParagraphElement)) {
|
||||||
|
Conquer.fail('Unable to find conquer login error.')
|
||||||
|
}
|
||||||
|
this.conquerLoginError = conquerLoginError
|
||||||
|
const conquerLoginSuccess = document.querySelector('.conquer-login-success')
|
||||||
|
if (conquerLoginSuccess === null || !(conquerLoginSuccess instanceof HTMLParagraphElement)) {
|
||||||
|
Conquer.fail('Unable to find conquer login success.')
|
||||||
|
}
|
||||||
|
this.conquerLoginSuccess = conquerLoginSuccess
|
||||||
}
|
}
|
||||||
async goToRegister(): Promise<void> {
|
async goToRegister(): Promise<void> {
|
||||||
const isLogged = await this.isLogged();
|
const isLogged = await this.isLogged();
|
||||||
@ -95,6 +108,81 @@ export default class Conquer {
|
|||||||
this.conquerRegisterGoToLogin.addEventListener('click', () => {
|
this.conquerRegisterGoToLogin.addEventListener('click', () => {
|
||||||
this.goToLogin()
|
this.goToLogin()
|
||||||
})
|
})
|
||||||
|
const conquerRegisterUsername = document.querySelector('.conquer-register-username')
|
||||||
|
if (conquerRegisterUsername === null || !(conquerRegisterUsername instanceof HTMLInputElement)) {
|
||||||
|
Conquer.fail('No username field in conquer register.')
|
||||||
|
}
|
||||||
|
this.conquerRegisterUsername = conquerRegisterUsername
|
||||||
|
const conquerRegisterPassword = document.querySelector('.conquer-register-password')
|
||||||
|
if (conquerRegisterPassword === null || !(conquerRegisterPassword instanceof HTMLInputElement)) {
|
||||||
|
Conquer.fail('No password field in conquer register.')
|
||||||
|
}
|
||||||
|
this.conquerRegisterPassword = conquerRegisterPassword
|
||||||
|
const conquerRegisterRepeatPassword = document.querySelector('.conquer-register-repeat-password')
|
||||||
|
if (conquerRegisterRepeatPassword === null || !(conquerRegisterRepeatPassword instanceof HTMLInputElement)) {
|
||||||
|
Conquer.fail('No repeat password field in conquer register.')
|
||||||
|
}
|
||||||
|
this.conquerRegisterRepeatPassword = conquerRegisterRepeatPassword
|
||||||
|
const conquerRegisterSubmit = document.querySelector('.conquer-register-submit')
|
||||||
|
if (conquerRegisterSubmit === null || !(conquerRegisterSubmit instanceof HTMLButtonElement)) {
|
||||||
|
Conquer.fail('No register submit button found.')
|
||||||
|
}
|
||||||
|
this.conquerRegisterSubmit = conquerRegisterSubmit
|
||||||
|
this.conquerRegisterSubmit.addEventListener('click', (event: Event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
this.onRegisterRequest()
|
||||||
|
})
|
||||||
|
const conquerRegisterError = document.querySelector('.conquer-register-error')
|
||||||
|
if (conquerRegisterError === null || !(conquerRegisterError instanceof HTMLParagraphElement)) {
|
||||||
|
Conquer.fail('Unable to find the conquer error element.')
|
||||||
|
}
|
||||||
|
this.conquerRegisterError = conquerRegisterError
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetLoginAndRegisterErrors() {
|
||||||
|
this.conquerRegisterError.classList.add('conquer-display-none')
|
||||||
|
this.conquerLoginError.classList.add('conquer-display-none')
|
||||||
|
}
|
||||||
|
|
||||||
|
async onRegisterRequest(): Promise<void> {
|
||||||
|
const username = this.conquerRegisterUsername.value
|
||||||
|
const password = this.conquerRegisterPassword.value
|
||||||
|
const repeatPassword = this.conquerRegisterRepeatPassword.value
|
||||||
|
const urlUser = new URL('/conquer/user', window.location.protocol + '//' + window.location.hostname + ':' + window.location.port)
|
||||||
|
const response = await fetch(urlUser, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
repeat_password: repeatPassword
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let responseJson
|
||||||
|
try {
|
||||||
|
responseJson = await response.json()
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (response.status !== 200) {
|
||||||
|
this.addNewRegisterError(responseJson.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.addNewLoginSuccessText(`Usuario registrado ${username}.`)
|
||||||
|
this.goToLogin()
|
||||||
|
}
|
||||||
|
addNewLoginSuccessText(message: string): void {
|
||||||
|
this.unsetLoginAndRegisterErrors()
|
||||||
|
this.conquerLoginSuccess.innerText = message
|
||||||
|
this.conquerLoginSuccess.classList.remove('conquer-display-none')
|
||||||
|
|
||||||
|
}
|
||||||
|
addNewRegisterError(error: string): void {
|
||||||
|
this.unsetLoginAndRegisterErrors()
|
||||||
|
this.conquerLoginSuccess.classList.add('conquer-display-none')
|
||||||
|
this.conquerRegisterError.innerText = error
|
||||||
|
this.conquerRegisterError.classList.remove('conquer-display-none')
|
||||||
}
|
}
|
||||||
async run() {
|
async run() {
|
||||||
this.fillConquerLogin()
|
this.fillConquerLogin()
|
||||||
|
111
lib/BurguillosInfo/Controller/UserConquer.pm
Normal file
111
lib/BurguillosInfo/Controller/UserConquer.pm
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package BurguillosInfo::Controller::UserConquer;
|
||||||
|
|
||||||
|
use v5.34.1;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
|
||||||
|
use Mojo::Base 'Mojolicious::Controller', '-signatures';
|
||||||
|
|
||||||
|
use UUID::URandom qw/create_uuid_string/;
|
||||||
|
use Crypt::Bcrypt qw/bcrypt bcrypt_check/;
|
||||||
|
use Crypt::URandom qw/urandom/;
|
||||||
|
|
||||||
|
use BurguillosInfo::Schema;
|
||||||
|
|
||||||
|
my $username_minimum_chars = 3;
|
||||||
|
my $username_maximum_chars = 15;
|
||||||
|
my $password_minimum_chars = 8;
|
||||||
|
my $password_maximum_chars = 4096;
|
||||||
|
|
||||||
|
sub create ($self) {
|
||||||
|
my $input;
|
||||||
|
eval { $input = $self->req->json; };
|
||||||
|
if ($@) {
|
||||||
|
say STDERR $@;
|
||||||
|
return $self->render( text => 'Expecting json', status => 400 );
|
||||||
|
}
|
||||||
|
my $username = $input->{username};
|
||||||
|
my $password = $input->{password};
|
||||||
|
my $repeat_password = $input->{repeat_password};
|
||||||
|
return
|
||||||
|
unless $self->_createCheckInput( $username, $password, $repeat_password );
|
||||||
|
return $self->_createUser($username, $password);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _createUser ( $self, $username, $password ) {
|
||||||
|
my $user;
|
||||||
|
my $uuid = create_uuid_string();
|
||||||
|
my $new_salt = urandom(16);
|
||||||
|
my $encrypted_password = bcrypt $password, '2b', 12, $new_salt;
|
||||||
|
eval {
|
||||||
|
$user = BurguillosInfo::Schema->Schema->resultset('ConquerUser')->new(
|
||||||
|
{
|
||||||
|
uuid => $uuid,
|
||||||
|
encrypted_password => $encrypted_password,
|
||||||
|
username => $username
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$user->insert;
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
if ( $@ =~ /Key \((.*?)\)=\((.*?)\) already exists\./ ) {
|
||||||
|
return $self->renderError( 400,
|
||||||
|
"The key $1 ($2) already exists in the database.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
say STDERR $@;
|
||||||
|
return $self->renderError( 400,
|
||||||
|
'No se pudo crear el usuario por razones desconocidas.' );
|
||||||
|
}
|
||||||
|
$self->render(status => 200, json => $user->serialize_to_owner);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub renderError ( $self, $status, $message ) {
|
||||||
|
$self->render( status => $status, json => { error => $message } );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _createCheckInput ( $self, $username, $password, $repeat_password ) {
|
||||||
|
if ( !defined $username
|
||||||
|
|| $username !~
|
||||||
|
/^(?:\w|\d|[ÑÁÉÍÓÚñáéíóú ]){$username_minimum_chars,$username_maximum_chars}$/
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return $self->renderError( 400,
|
||||||
|
"Username invalido, las reglas son tamaño entre $username_minimum_chars y $username_maximum_chars"
|
||||||
|
. ' carácteres y solo se podrán usar letras, números y espacios.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( !defined $password
|
||||||
|
|| $password eq $username
|
||||||
|
|| $password !~ /^.{$password_minimum_chars,$password_maximum_chars}$/
|
||||||
|
|| $password =~ /^\d+$/ )
|
||||||
|
{
|
||||||
|
return $self->renderError(
|
||||||
|
400,
|
||||||
|
'Contraseña invalida, las reglas son la contraseña debe ser'
|
||||||
|
. ' distinta al nombre de usuario, la contraseña debe tener entre'
|
||||||
|
. " $password_minimum_chars y $password_maximum_chars carácteres"
|
||||||
|
. ' (Tu contraseña no se guardará en texto plano, el límite de'
|
||||||
|
. " $password_maximum_chars caracteres es para evitar denegaciones"
|
||||||
|
. ' de servicio), la contraseña no puede estar compuesta solo de números.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( !defined $repeat_password || $password ne $repeat_password ) {
|
||||||
|
$self->renderError(
|
||||||
|
400,
|
||||||
|
'El campo de repetir contraseña debe coincidir de forma'
|
||||||
|
. ' totalmente exacta con el campo de contraseña para asegurar'
|
||||||
|
. ' que podrás recordar la contraseña y/o que no has cometido'
|
||||||
|
. ' ningún error, si pierdes el acceso a tu cuenta no podrás'
|
||||||
|
. ' recuperarlo de ningún modo.',
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
1;
|
@ -56,6 +56,7 @@ sub MIGRATIONS {
|
|||||||
last_activity TEXT NOT NULL DEFAULT NOW(),
|
last_activity TEXT NOT NULL DEFAULT NOW(),
|
||||||
is_admin boolean NOT NULL DEFAULT false
|
is_admin boolean NOT NULL DEFAULT false
|
||||||
);',
|
);',
|
||||||
|
'ALTER TABLE conquer_user ADD COLUMN registration_date TIMESTAMP NOT NULL DEFAULT NOW();',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,32 +7,51 @@ use warnings;
|
|||||||
|
|
||||||
use parent 'DBIx::Class::Core';
|
use parent 'DBIx::Class::Core';
|
||||||
|
|
||||||
__PACKAGE__->table('players');
|
use feature 'signatures';
|
||||||
|
|
||||||
|
__PACKAGE__->table('conquer_user');
|
||||||
|
|
||||||
__PACKAGE__->add_columns(
|
__PACKAGE__->add_columns(
|
||||||
uuid => {
|
uuid => {
|
||||||
data_type => 'uuid',
|
data_type => 'uuid',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
},
|
},
|
||||||
username => {
|
username => {
|
||||||
data_type => 'text',
|
data_type => 'text',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
},
|
},
|
||||||
encrypted_password => {
|
encrypted_password => {
|
||||||
data_type => 'text',
|
data_type => 'text',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
},
|
},
|
||||||
last_activity => {
|
last_activity => {
|
||||||
data_type => 'timestamp',
|
data_type => 'timestamp',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
|
default_value => \'NOW()',
|
||||||
|
},
|
||||||
|
registration_date => {
|
||||||
|
data_type => 'timestamp',
|
||||||
|
is_nullable => 0,
|
||||||
default_value => \'NOW()',
|
default_value => \'NOW()',
|
||||||
},
|
},
|
||||||
is_admin => {
|
is_admin => {
|
||||||
data_type => 'boolean',
|
data_type => 'boolean',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
default_value => \'0',
|
default_value => \'0',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sub serialize_to_owner ($self) {
|
||||||
|
return {
|
||||||
|
kind => 'ConquerUser',
|
||||||
|
uuid => $self->uuid,
|
||||||
|
username => $self->username,
|
||||||
|
is_admin => $self->is_admin,
|
||||||
|
last_activity => $self->last_activity,
|
||||||
|
registration_date => $self->registration_date,
|
||||||
|
};
|
||||||
|
}
|
||||||
__PACKAGE__->set_primary_key('uuid');
|
__PACKAGE__->set_primary_key('uuid');
|
||||||
__PACKAGE__->add_unique_constraint("unique_constraint_username", ['username']);
|
__PACKAGE__->add_unique_constraint( "unique_constraint_username",
|
||||||
|
['username'] );
|
||||||
1;
|
1;
|
||||||
|
@ -8,10 +8,20 @@ body {
|
|||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%; }
|
height: 100%; }
|
||||||
|
body p.conquer-register-error, body p.conquer-login-error, body p.conquer-login-success {
|
||||||
|
color: red;
|
||||||
|
margin: 3px;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
background: blanchedalmond;
|
||||||
|
padding: 3px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: solid 1px black; }
|
||||||
|
body p.conquer-login-success {
|
||||||
|
color: green; }
|
||||||
body div.conquer-login, body div.conquer-register {
|
body div.conquer-login, body div.conquer-register {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 25px;
|
font-size: 1.5rem;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
background: darkseagreen;
|
background: darkseagreen;
|
||||||
top: calc( 50% - 200px - 10px);
|
top: calc( 50% - 200px - 10px);
|
||||||
@ -26,7 +36,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center; }
|
justify-content: center; }
|
||||||
body div.conquer-display-none {
|
body .conquer-display-none {
|
||||||
display: none; }
|
display: none; }
|
||||||
body div.conquer-container {
|
body div.conquer-container {
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
|
@ -16,6 +16,18 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
p.conquer-register-error, p.conquer-login-error, p.conquer-login-success {
|
||||||
|
color: red;
|
||||||
|
margin: 3px;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
background: blanchedalmond;
|
||||||
|
padding: 3px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: solid 1px black;
|
||||||
|
}
|
||||||
|
p.conquer-login-success {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
div.conquer-login,div.conquer-register {
|
div.conquer-login,div.conquer-register {
|
||||||
form {
|
form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -26,7 +38,7 @@ body {
|
|||||||
}
|
}
|
||||||
position: fixed;
|
position: fixed;
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 25px;
|
font-size: 1.5rem;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
background: darkseagreen;
|
background: darkseagreen;
|
||||||
top: calc( 50% - 200px - 10px );
|
top: calc( 50% - 200px - 10px );
|
||||||
@ -36,7 +48,7 @@ body {
|
|||||||
width: 300px;
|
width: 300px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
div.conquer-display-none {
|
.conquer-display-none {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
div.conquer-container {
|
div.conquer-container {
|
||||||
|
File diff suppressed because one or more lines are too long
@ -10,23 +10,26 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="conquer-login conquer-display-none">
|
<div class="conquer-login conquer-display-none">
|
||||||
<form>
|
<form>
|
||||||
|
<p class="conquer-login-error conquer-display-none"></p>
|
||||||
|
<p class="conquer-login-success conquer-display-none"></p>
|
||||||
<label>Nombre de usuario</label>
|
<label>Nombre de usuario</label>
|
||||||
<input class="conquer-login-username"/>
|
<input class="conquer-login-username"/>
|
||||||
<label>Contraseña</label>
|
<label>Contraseña</label>
|
||||||
<input class="conquer-login-password" type="password"/>
|
<input class="conquer-login-password" type="password"/>
|
||||||
<button class="conquer-login-sumbit">Inicia sesión</button>
|
<button class="conquer-login-submit">Inicia sesión</button>
|
||||||
<p>¿No tienes cuenta aun? <a href="#" class="conquer-login-go-to-register">Registrate</a></p>
|
<p>¿No tienes cuenta aun? <a href="#" class="conquer-login-go-to-register">Registrate</a></p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="conquer-register conquer-display-none">
|
<div class="conquer-register conquer-display-none">
|
||||||
<form>
|
<form>
|
||||||
|
<p class="conquer-register-error conquer-display-none"></p>
|
||||||
<label>Nombre de usuario</label>
|
<label>Nombre de usuario</label>
|
||||||
<input class="conquer-register-username"/>
|
<input class="conquer-register-username"/>
|
||||||
<label>Contraseña</label>
|
<label>Contraseña</label>
|
||||||
<input class="conquer-register-password" type="password"/>
|
<input class="conquer-register-password" type="password"/>
|
||||||
<label>Repite la contraseña</label>
|
<label>Repite la contraseña</label>
|
||||||
<input class="conquer-register-repeat-password" type="password"/>
|
<input class="conquer-register-repeat-password" type="password"/>
|
||||||
<button class="conquer-register-sumbit">Finaliza el registro</button>
|
<button class="conquer-register-submit">Finaliza el registro</button>
|
||||||
<p>¿Ya estás registrado? <a href="#" class="conquer-register-go-to-login">Inicia Sesión</a>.</p>
|
<p>¿Ya estás registrado? <a href="#" class="conquer-register-go-to-login">Inicia Sesión</a>.</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user