Add job queue; e-mail sending; password reset support

This commit is contained in:
garrettmills
2020-05-25 15:45:26 -05:00
parent f371310620
commit 76ba843348
22 changed files with 884 additions and 30 deletions

View File

@@ -1,6 +1,8 @@
import { Component } from '../../../lib/vues6/vues6.js'
import { auth_api } from '../../service/AuthApi.service.js'
import { location_service } from '../../service/Location.service.js'
import { message_service } from '../../service/Message.service.js'
import { password_service } from '../../service/Password.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">
@@ -41,6 +43,10 @@ const template = `
class="mr-3"
v-if="!step_two && !loading && registration_enabled"
><a href="#" class="text-secondary" @click="on_register_click">Need an account?</a></small>
<small
class="mr-3"
v-if="!loading"
><a href="#" class="text-secondary" @click="on_forgot_password">Forgot password?</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>
@@ -147,5 +153,38 @@ export default class AuthLoginForm extends Component {
location_service.redirect('/auth/register', 1500) // TODO get this dynamically
}
async on_forgot_password() {
console.log(message_service)
await message_service.modal({
title: 'Reset Password',
message: 'If you have forgotten your password, you can request a reset e-mail to be sent to your account. Enter your e-mail address:',
inputs: [
{
type: 'email',
name: 'email',
placeholder: 'jdoe@contoso.com',
},
],
buttons: [
{
type: 'close',
text: 'Cancel',
},
{
type: 'close',
class: ['btn', 'btn-primary'],
text: 'Request',
on_click: async ($event, { email }) => {
await password_service.request_reset(email)
await message_service.alert({
type: 'success',
message: 'Success! If that e-mail address is associated with a valid ' + this.app_name + ' account, it will receive an e-mail with more instructions shortly.',
})
},
},
],
})
}
do_nothing() {}
}

View File

@@ -6,6 +6,7 @@ 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'
import MessageContainerComponent from './dash/message/MessageContainer.component.js'
const components = {
AuthLoginForm,
@@ -16,6 +17,7 @@ const components = {
PasswordResetComponent,
InvokeActionComponent,
RegistrationFormComponent,
MessageContainerComponent,
}
export { components }

View File

@@ -36,6 +36,16 @@ const template = `
</div>
<div class="modal-body">
{{ modal.message }}
<div v-if="Array.isArray(modal.inputs)" class="mt-4 mb-3">
<span v-for="input of modal.inputs">
<input
type="input.type"
v-model="modal.data[input.name]"
:placeholder="input.placeholder"
class="form-control"
>
</span>
</div>
</div>
<div class="modal-footer" v-if="modal.buttons && modal.buttons.length > 0">
<button
@@ -68,8 +78,8 @@ export default class MessageContainerComponent extends Component {
})
this.modal_event = event_bus.event('message.modal')
this.modal_event.subscribe(({ title, message, buttons = [] }) => {
this.create_modal(title, message, buttons)
this.modal_event.subscribe(({ title, message, buttons = [], inputs = [] }) => {
this.create_modal(title, message, buttons, inputs)
})
message_service.init_listener()
@@ -96,12 +106,14 @@ export default class MessageContainerComponent extends Component {
}
}
create_modal(title, message, buttons = []) {
create_modal(title, message, buttons = [], inputs = []) {
const index = this.modals.length
const modal = {
title,
message,
buttons
buttons,
inputs,
data: {},
}
this.modals.push(modal)
@@ -112,7 +124,7 @@ export default class MessageContainerComponent extends Component {
modal_button_click($event, modal, button) {
if ( typeof button.on_click === 'function' ) {
button.on_click($event)
button.on_click($event, modal.data)
}
}
}

View File

@@ -7,8 +7,8 @@ class MessageService {
event_bus.event('message.alert').fire({ type, message, timeout, on_dismiss })
}
modal({title, message, buttons = [] }) {
event_bus.event('message.modal').fire({ title, message, buttons })
modal({title, message, buttons = [], inputs = []}) {
event_bus.event('message.modal').fire({ title, message, buttons, inputs })
}
async fetch() {
@@ -24,7 +24,11 @@ class MessageService {
this.message_ids = []
this.listener = setInterval(() => this._listener_tick(), this.listener_interval)
window.addEventListener('beforeunload', () => this.stop_listener())
this._listener_tick()
try {
this._listener_tick()
} catch (e) {
this.stop_listener()
}
}
async _listener_tick() {

View File

@@ -7,6 +7,10 @@ class PasswordService {
async reset(password) {
await axios.post('/api/v1/password/resets', { password })
}
async request_reset(email) {
await axios.post('/api/v1/password/request_reset', { email })
}
}
const password_service = new PasswordService()

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB