Add traps; user registration

This commit is contained in:
garrettmills
2020-05-20 09:56:03 -05:00
parent 7663cea2ea
commit ea77402750
19 changed files with 493 additions and 24 deletions

View File

@@ -37,6 +37,10 @@ const template = `
<div v-if="error_message" class="error-message">{{ error_message }}</div>
<div v-if="other_message" class="other-message">{{ other_message }}</div>
<div class="buttons text-right">
<small
class="mr-3"
v-if="!step_two && !loading && registration_enabled"
><a href="#" class="text-secondary" @click="on_register_click">Need an account?</a></small>
<button type="button" class="btn btn-primary" :disabled="loading" v-if="step_two" v-on:click="back_click">Back</button>
<button type="button" class="btn btn-primary" :disabled="loading || btn_disabled" v-on:click="step_click">{{ button_text }}</button>
</div>
@@ -49,7 +53,7 @@ const template = `
export default class AuthLoginForm extends Component {
static get selector() { return 'coreid-login-form' }
static get props() { return [
'app_name', 'login_message', 'additional_params', 'no_session',
'app_name', 'login_message', 'additional_params', 'no_session', 'registration_enabled',
] }
static get template() { return template }
@@ -126,5 +130,11 @@ export default class AuthLoginForm extends Component {
}
}
on_register_click() {
this.loading = true
this.other_message = 'Okay! Let\'s get started...'
location_service.redirect('/auth/register', 1500) // TODO get this dynamically
}
do_nothing() {}
}

View File

@@ -0,0 +1,217 @@
import { Component } from '../../../lib/vues6/vues6.js'
import { location_service } from '../../service/Location.service.js'
import { auth_api } from '../../service/AuthApi.service.js'
const template = `
<div class="coreid-login-form col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left">
<div class="coreid-login-form-inner">
<div class="coreid-login-form-header font-weight-light">{{ app_name }}</div>
<div class="coreid-login-form-message">{{ message }}</div>
<form class="coreid-form" v-on:submit.prevent="do_nothing">
<div class="form-group">
<input
v-if="step === 1"
type="text"
id="coreid-registration-form-first"
name="first_name"
class="form-control"
placeholder="First Name"
v-model="first_name"
autofocus
@keyup="on_key_up"
:disabled="loading || step > 1"
>
</div>
<div class="form-group">
<input
v-if="step === 1"
type="text"
id="coreid-registration-form-last"
name="last_name"
class="form-control"
placeholder="Last Name"
v-model="last_name"
autofocus
@keyup="on_key_up"
:disabled="loading || step > 1"
>
</div>
<div class="form-group">
<input
v-if="step === 2 || step === 3"
type="text"
id="coreid-registration-form-username"
name="username"
class="form-control"
placeholder="Username"
v-model="username"
autofocus
@keyup="on_key_up"
:disabled="loading || step != 2"
ref="input_username"
>
</div>
<div class="form-group">
<input
v-if="step === 3"
type="email"
id="coreid-registration-form-email"
name="email"
class="form-control"
placeholder="E-Mail"
v-model="email"
autofocus
@keyup="on_key_up"
:disabled="loading || step != 3"
ref="input_email"
>
</div>
<div v-if="error_message" class="error-message">{{ error_message }}</div>
<div v-if="other_message" class="other-message">{{ other_message }}</div>
<div class="buttons text-right">
<small
class="mr-3"
v-if="step === 1 && !loading"
><a href="#" class="text-secondary" @click="on_login_click">Already have an account?</a></small>
<button
type="button"
class="btn btn-primary"
:disabled="loading"
v-if="step > 1"
v-on:click="back_click"
>Back</button>
<button
type="button"
class="btn btn-primary"
:disabled="loading || btn_disabled"
v-on:click="step_click"
>{{ button_text }}</button>
</div>
</form>
<div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div>
</div>
</div>
`
// Required: First Name, Last Name, Username, E-Mail, Password (Confirm)
export default class RegistrationFormComponent extends Component {
static get selector() { return 'coreid-registration-form' }
static get template() { return template }
static get props() { return ['app_name'] }
loading = false
step = 1
other_message = ''
error_message = ''
message = ''
btn_disabled = true
button_text = 'Continue'
first_name = ''
last_name = ''
username = ''
email = ''
async vue_on_create() {
this.message = 'Create an account to continue:'
}
async step_click() {
this.loading = true
this.error_message = ''
this.other_message = ''
if ( this.step === 1 ) {
if ( !this.first_name.trim() || !this.last_name.trim() ) {
this.error_message = 'Please provide your first and last name.'
this.loading = false
return
}
this.message = `Hi, ${this.first_name.trim()}. Now, you need to choose a username:`
this.$nextTick(() => {
this.$refs.input_username.focus()
})
} else if ( this.step === 2 ) {
if ( await auth_api.username_taken(this.username) ) {
this.error_message = 'That username is already taken.'
this.loading = false
return
}
this.$nextTick(function() {
this.$nextTick(() => {
this.$refs.input_email.focus()
})
})
} else if ( this.step === 3 ) {
if ( !(await auth_api.validate_email(this.email)) ) {
this.error_message = 'Please provide a valid e-mail address.'
this.loading = false
return
}
if ( await auth_api.email_taken(this.email) ) {
this.error_message = 'That e-mail address is already taken.'
this.loading = false
return
}
try {
const user = await auth_api.register_user({
first_name: this.first_name,
last_name: this.last_name,
uid: this.username,
email: this.email,
})
if ( !user ) this.error_message = 'Sorry, an unknown error has occurred and we are unable to continue at this time.'
else this.other_message = 'Welcome! Let\'s get your password set up...'
this.btn_disabled = true
return location_service.redirect('/dash', 2000)
} catch (e) {
this.error_message = e.message || 'Sorry, an unknown error has occurred and we are unable to continue at this time.'
this.loading = false
return
}
}
if ( this.step < 3 ) this.step += 1
this.loading = false
this.btn_disabled = true
}
async back_click() {
this.error_message = ''
this.other_message = ''
this.step -= 1
this.on_key_up()
if ( this.step === 1 ) {
this.message = 'Create an account to continue:'
}
}
on_key_up(event) {
if ( this.step === 1 ) {
this.btn_disabled = !(this.first_name.trim() && this.last_name.trim())
} else if ( this.step === 2 ) {
this.btn_disabled = !this.username.trim() || !this.username.match(/^([A-Z]|[a-z]|[0-9]|_|-|\.)+$/)
} else if ( this.step === 3 ) {
this.btn_disabled = !this.email.trim()
}
if ( event.keyCode === 13 ) {
// Enter was pressed
event.preventDefault()
event.stopPropagation()
if ( !this.btn_disabled ) return this.step_click()
}
}
on_login_click() {
this.loading = true
this.other_message = 'Okay! We\'ll have you login instead...'
location_service.redirect('/auth/login', 1500)
}
do_nothing() {}
}

View File

@@ -5,6 +5,7 @@ import MFAChallengePage from './auth/MFAChallenge.component.js'
import MFADisableComponent from './auth/MFADisable.component.js'
import PasswordResetComponent from './auth/PasswordReset.component.js'
import InvokeActionComponent from './InvokeAction.component.js'
import RegistrationFormComponent from './auth/register/Form.component.js'
const components = {
AuthLoginForm,
@@ -14,6 +15,7 @@ const components = {
MFADisableComponent,
PasswordResetComponent,
InvokeActionComponent,
RegistrationFormComponent,
}
export { components }

View File

@@ -4,6 +4,21 @@ class AuthAPI {
return result && result.data && result.data.data && result.data.data.is_valid
}
async validate_email(email) {
const result = await axios.post('/api/v1/auth/validate/email', { email })
return result && result.data && result.data.data && result.data.data.is_valid
}
async username_taken(username) {
const result = await axios.post('/api/v1/auth/validate/user_exists', { username })
return result && result.data && result.data.data && result.data.data.username_taken
}
async email_taken(email) {
const result = await axios.post('/api/v1/auth/validate/user_exists', { email })
return result && result.data && result.data.data && result.data.data.email_taken
}
async attempt({ username, password, create_session, ...others }) {
try {
const result = await axios.post('/api/v1/auth/attempt', {
@@ -56,6 +71,11 @@ class AuthAPI {
async delete_app_password(uuid) {
await axios.delete(`/api/v1/password/app_passwords/${uuid}`)
}
async register_user({ first_name, last_name, uid, email }) {
const result = await axios.post('/api/v1/auth/registration', { first_name, last_name, uid, email })
if ( result && result.data && result.data.data ) return result.data.data
}
}
const auth_api = new AuthAPI()