mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Copy all relevant files changed from branch signup
This commit is contained in:
parent
a4a875c2e1
commit
d76923c471
125
webapp/components/Registration/CreateUserAccount.spec.js
Normal file
125
webapp/components/Registration/CreateUserAccount.spec.js
Normal file
@ -0,0 +1,125 @@
|
||||
import { mount, createLocalVue } from '@vue/test-utils'
|
||||
import CreateUserAccount, { SignupVerificationMutation } from './CreateUserAccount'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Styleguide)
|
||||
|
||||
describe('CreateUserAccount', () => {
|
||||
let wrapper
|
||||
let Wrapper
|
||||
let mocks
|
||||
let propsData
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
$toast: {
|
||||
success: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
$t: jest.fn(),
|
||||
$apollo: {
|
||||
loading: false,
|
||||
mutate: jest.fn(),
|
||||
},
|
||||
}
|
||||
propsData = {}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
Wrapper = () => {
|
||||
return mount(CreateUserAccount, {
|
||||
mocks,
|
||||
propsData,
|
||||
localVue,
|
||||
})
|
||||
}
|
||||
|
||||
describe('given email and nonce', () => {
|
||||
beforeEach(() => {
|
||||
propsData.nonce = '666777'
|
||||
propsData.email = 'sixseven@example.org'
|
||||
})
|
||||
|
||||
it('renders a form to create a new user', () => {
|
||||
wrapper = Wrapper()
|
||||
expect(wrapper.find('.create-user-account').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('submit', () => {
|
||||
let action
|
||||
beforeEach(() => {
|
||||
action = async () => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.find('input#name').setValue('John Doe')
|
||||
wrapper.find('input#password').setValue('hellopassword')
|
||||
wrapper.find('input#confirmPassword').setValue('hellopassword')
|
||||
await wrapper.find('form').trigger('submit')
|
||||
}
|
||||
})
|
||||
|
||||
it('calls CreateUserAccount graphql mutation', async () => {
|
||||
await action()
|
||||
const expected = expect.objectContaining({ mutation: SignupVerificationMutation })
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
it('delivers data to backend', async () => {
|
||||
await action()
|
||||
const expected = expect.objectContaining({
|
||||
variables: {
|
||||
about: '',
|
||||
name: 'John Doe',
|
||||
email: 'sixseven@example.org',
|
||||
nonce: '666777',
|
||||
password: 'hellopassword',
|
||||
},
|
||||
})
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
describe('in case mutation resolves', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.mutate = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
SignupVerification: {
|
||||
id: 'u1',
|
||||
name: 'John Doe',
|
||||
slug: 'john-doe',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('displays success', async () => {
|
||||
await action()
|
||||
expect(mocks.$t).toHaveBeenCalledWith('registration.create-user-account.success')
|
||||
})
|
||||
|
||||
describe('after timeout', () => {
|
||||
beforeEach(jest.useFakeTimers)
|
||||
|
||||
it('emits `userCreated` with user', async () => {
|
||||
await action()
|
||||
jest.runAllTimers()
|
||||
expect(wrapper.emitted('userCreated')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('in case mutation rejects', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.mutate.mockRejectedValue(new Error('Invalid nonce'))
|
||||
})
|
||||
|
||||
it('displays form errors', async () => {
|
||||
await action()
|
||||
jest.runAllTimers()
|
||||
expect(wrapper.find('.errors').text()).toContain('Invalid nonce')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
169
webapp/components/Registration/CreateUserAccount.vue
Normal file
169
webapp/components/Registration/CreateUserAccount.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<ds-card v-if="success" class="success">
|
||||
<ds-space>
|
||||
<sweetalert-icon icon="success" />
|
||||
<ds-text align="center" bold color="success">
|
||||
{{ $t('registration.create-user-account.success') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
<ds-form
|
||||
v-else
|
||||
class="create-user-account"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="submit"
|
||||
>
|
||||
<ds-card :header="$t('registration.create-user-account.title')">
|
||||
<ds-input
|
||||
id="name"
|
||||
model="name"
|
||||
icon="user"
|
||||
:label="$t('settings.data.labelName')"
|
||||
:placeholder="$t('settings.data.namePlaceholder')"
|
||||
/>
|
||||
<ds-input
|
||||
id="bio"
|
||||
model="about"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
:label="$t('settings.data.labelBio')"
|
||||
:placeholder="$t('settings.data.labelBio')"
|
||||
/>
|
||||
<ds-input
|
||||
id="password"
|
||||
model="password"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password')"
|
||||
/>
|
||||
<ds-input
|
||||
id="confirmPassword"
|
||||
model="confirmPassword"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password-confirm')"
|
||||
/>
|
||||
<password-strength :password="formData.password" />
|
||||
<template slot="footer">
|
||||
<ds-space class="errors" v-if="errors">
|
||||
<ds-text align="center" bold color="danger">
|
||||
{{ errors.message }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<ds-button
|
||||
style="float: right;"
|
||||
icon="check"
|
||||
type="submit"
|
||||
:loading="$apollo.loading"
|
||||
:disabled="disabled"
|
||||
primary
|
||||
>
|
||||
{{ $t('actions.save') }}
|
||||
</ds-button>
|
||||
</template>
|
||||
</ds-card>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import PasswordStrength from '../Password/Strength'
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
|
||||
export const SignupVerificationMutation = gql`
|
||||
mutation($nonce: String!, $name: String!, $email: String!, $password: String!) {
|
||||
SignupVerification(nonce: $nonce, email: $email, name: $name, password: $password) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
`
|
||||
export default {
|
||||
components: {
|
||||
PasswordStrength,
|
||||
SweetalertIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
name: '',
|
||||
about: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
},
|
||||
formSchema: {
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
min: 3,
|
||||
},
|
||||
about: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: this.$t('settings.security.change-password.message-new-password-required'),
|
||||
},
|
||||
confirmPassword: [
|
||||
{ validator: this.matchPassword },
|
||||
{
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: this.$t(
|
||||
'settings.security.change-password.message-new-password-confirm-required',
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: true,
|
||||
success: null,
|
||||
errors: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
nonce: { type: String, required: true },
|
||||
email: { type: String, required: true },
|
||||
},
|
||||
methods: {
|
||||
async handleInput() {
|
||||
this.disabled = true
|
||||
},
|
||||
async handleInputValid() {
|
||||
this.disabled = false
|
||||
},
|
||||
async submit() {
|
||||
const { name, password, about } = this.formData
|
||||
const { email, nonce } = this
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: SignupVerificationMutation,
|
||||
variables: { name, password, about, email, nonce }
|
||||
})
|
||||
this.success = true
|
||||
setTimeout(() => {
|
||||
this.$emit('userCreated', {
|
||||
email, password
|
||||
})
|
||||
}, 3000)
|
||||
} catch (err) {
|
||||
this.errors = err
|
||||
}
|
||||
},
|
||||
matchPassword(rule, value, callback, source, options) {
|
||||
var errors = []
|
||||
if (this.formData.password !== value) {
|
||||
errors.push(
|
||||
new Error(this.$t('settings.security.change-password.message-new-password-missmatch')),
|
||||
)
|
||||
}
|
||||
callback(errors)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
145
webapp/components/Registration/Signup.spec.js
Normal file
145
webapp/components/Registration/Signup.spec.js
Normal file
@ -0,0 +1,145 @@
|
||||
import { mount, createLocalVue } from '@vue/test-utils'
|
||||
import Signup, { SignupMutation, SignupByInvitationMutation } from './Signup'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Styleguide)
|
||||
|
||||
describe('Signup', () => {
|
||||
let wrapper
|
||||
let Wrapper
|
||||
let mocks
|
||||
let propsData
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
$toast: {
|
||||
success: jest.fn(),
|
||||
error: jest.fn(),
|
||||
},
|
||||
$t: jest.fn(),
|
||||
$apollo: {
|
||||
loading: false,
|
||||
mutate: jest.fn().mockResolvedValue({ data: { Signup: { email: 'mail@example.org' } } }),
|
||||
},
|
||||
}
|
||||
propsData = {}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(jest.useFakeTimers)
|
||||
|
||||
Wrapper = () => {
|
||||
return mount(Signup, {
|
||||
mocks,
|
||||
propsData,
|
||||
localVue,
|
||||
})
|
||||
}
|
||||
|
||||
describe('without invitation code', () => {
|
||||
it('renders signup form', () => {
|
||||
wrapper = Wrapper()
|
||||
expect(wrapper.find('.signup').exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('submit', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.find('input#email').setValue('mail@example.org')
|
||||
await wrapper.find('form').trigger('submit')
|
||||
})
|
||||
|
||||
it('calls Signup graphql mutation', () => {
|
||||
const expected = expect.objectContaining({ mutation: SignupMutation })
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
it('delivers email to backend', () => {
|
||||
const expected = expect.objectContaining({
|
||||
variables: { email: 'mail@example.org', token: null },
|
||||
})
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
it('hides form to avoid re-submission', () => {
|
||||
expect(wrapper.find('form').exists()).not.toBeTruthy()
|
||||
})
|
||||
|
||||
it('displays a message that a mail for email verification was sent', () => {
|
||||
const expected = ['registration.signup.form.success', { email: 'mail@example.org' }]
|
||||
expect(mocks.$t).toHaveBeenCalledWith(...expected)
|
||||
})
|
||||
|
||||
describe('after animation', () => {
|
||||
beforeEach(jest.runAllTimers)
|
||||
|
||||
it('emits `handleSubmitted`', () => {
|
||||
expect(wrapper.emitted('handleSubmitted')).toEqual([[{ email: 'mail@example.org' }]])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with invitation code', () => {
|
||||
let action
|
||||
beforeEach(() => {
|
||||
propsData.token = '666777'
|
||||
action = async () => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.find('input#email').setValue('mail@example.org')
|
||||
await wrapper.find('form').trigger('submit')
|
||||
}
|
||||
})
|
||||
|
||||
describe('submit', () => {
|
||||
it('calls SignupByInvitation graphql mutation', async () => {
|
||||
await action()
|
||||
const expected = expect.objectContaining({ mutation: SignupByInvitationMutation })
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
it('delivers invitation token to backend', async () => {
|
||||
await action()
|
||||
const expected = expect.objectContaining({
|
||||
variables: { email: 'mail@example.org', token: '666777' },
|
||||
})
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
describe('in case a user account with the email already exists', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.mutate = jest
|
||||
.fn()
|
||||
.mockRejectedValue(
|
||||
new Error('UserInputError: User account with this email already exists.'),
|
||||
)
|
||||
})
|
||||
|
||||
it.skip('explains the error', async () => {
|
||||
await action()
|
||||
expect(mocks.$t).toHaveBeenCalledWith('registration.signup.form.errors.email-exists')
|
||||
})
|
||||
})
|
||||
|
||||
describe('in case the invitation code was incorrect', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.mutate = jest
|
||||
.fn()
|
||||
.mockRejectedValue(
|
||||
new Error('UserInputError: Invitation code already used or does not exist.'),
|
||||
)
|
||||
})
|
||||
|
||||
it.skip('explains the error', async () => {
|
||||
await action()
|
||||
expect(mocks.$t).toHaveBeenCalledWith(
|
||||
'registration.signup.form.errors.invalid-invitation-token',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
141
webapp/components/Registration/Signup.vue
Normal file
141
webapp/components/Registration/Signup.vue
Normal file
@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<ds-card class="signup">
|
||||
<ds-space margin="large">
|
||||
<ds-form
|
||||
v-if="!success && !error"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<h1>{{ $t('registration.signup.title') }}</h1>
|
||||
<ds-space v-if="token" margin-botton="large">
|
||||
<ds-text v-html="$t('registration.signup.form.invitation-code', { code: token })" />
|
||||
</ds-space>
|
||||
<ds-space margin-botton="large">
|
||||
<ds-text>
|
||||
{{ $t('registration.signup.form.description') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<ds-input
|
||||
:placeholder="$t('login.email')"
|
||||
type="email"
|
||||
id="email"
|
||||
model="email"
|
||||
name="email"
|
||||
icon="envelope"
|
||||
/>
|
||||
<ds-button
|
||||
:disabled="disabled"
|
||||
:loading="$apollo.loading"
|
||||
primary
|
||||
fullwidth
|
||||
name="submit"
|
||||
type="submit"
|
||||
icon="envelope"
|
||||
>
|
||||
{{ $t('registration.signup.form.submit') }}
|
||||
</ds-button>
|
||||
</ds-form>
|
||||
<div v-else>
|
||||
<template v-if="!error">
|
||||
<sweetalert-icon icon="success" />
|
||||
<ds-text align="center" v-html="submitMessage" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<sweetalert-icon icon="error" />
|
||||
<ds-text align="center">
|
||||
{{ error.message }}
|
||||
</ds-text>
|
||||
</template>
|
||||
</div>
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
|
||||
export const SignupMutation = gql`
|
||||
mutation($email: String!) {
|
||||
Signup(email: $email) {
|
||||
email
|
||||
}
|
||||
}
|
||||
`
|
||||
export const SignupByInvitationMutation = gql`
|
||||
mutation($email: String!, $token: String!) {
|
||||
SignupByInvitation(email: $email, token: $token) {
|
||||
email
|
||||
}
|
||||
}
|
||||
`
|
||||
export default {
|
||||
components: {
|
||||
SweetalertIcon,
|
||||
},
|
||||
props: {
|
||||
token: { type: String, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
email: '',
|
||||
},
|
||||
formSchema: {
|
||||
email: {
|
||||
type: 'email',
|
||||
required: true,
|
||||
message: this.$t('common.validations.email'),
|
||||
},
|
||||
},
|
||||
disabled: true,
|
||||
success: false,
|
||||
error: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
submitMessage() {
|
||||
const { email } = this.formData
|
||||
return this.$t('registration.signup.form.success', { email })
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleInput() {
|
||||
this.disabled = true
|
||||
},
|
||||
handleInputValid() {
|
||||
this.disabled = false
|
||||
},
|
||||
async handleSubmit() {
|
||||
const mutation = this.token ? SignupByInvitationMutation : SignupMutation
|
||||
const { email } = this.formData
|
||||
const { token } = this
|
||||
|
||||
try {
|
||||
await this.$apollo.mutate({ mutation, variables: { email, token } })
|
||||
this.success = true
|
||||
|
||||
setTimeout(() => {
|
||||
this.$emit('handleSubmitted', { email })
|
||||
}, 3000)
|
||||
} catch (err) {
|
||||
const { message } = err
|
||||
const mapping = {
|
||||
'User account with this email already exists': 'email-exists',
|
||||
'Invitation code already used or does not exist': 'invalid-invitation-token',
|
||||
}
|
||||
for (const [pattern, key] of Object.entries(mapping)) {
|
||||
if (message.includes(pattern))
|
||||
this.error = { key, message: this.$t(`registration.signup.form.errors.${key}`) }
|
||||
}
|
||||
if (!this.error) {
|
||||
this.$toast.error(message)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -14,7 +14,8 @@
|
||||
"moreInfo": "Was ist Human Connection?",
|
||||
"moreInfoURL": "https://human-connection.org",
|
||||
"moreInfoHint": "zur Präsentationsseite",
|
||||
"hello": "Hallo"
|
||||
"hello": "Hallo",
|
||||
"success": "Du bist eingeloggt!"
|
||||
},
|
||||
"password-reset": {
|
||||
"title": "Passwort zurücksetzen",
|
||||
@ -24,6 +25,24 @@
|
||||
"submitted": "Eine E-Mail mit weiteren Instruktionen wurde verschickt an <b>{email}</b>"
|
||||
}
|
||||
},
|
||||
"registration": {
|
||||
"signup": {
|
||||
"title": "Mach mit bei Human Connection!",
|
||||
"form": {
|
||||
"description": "Um loszulegen, gib deine E-Mail Adresse ein:",
|
||||
"errors": {
|
||||
"email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail Adresse!",
|
||||
"invalid-invitation-token": "Es sieht so aus, als ob der Einladungscode schon eingelöst wurde. Jeder Code kann nur einmalig benutzt werden."
|
||||
},
|
||||
"submit": "Konto erstellen",
|
||||
"success": "Eine Mail mit einem Bestätigungslink für die Registrierung wurde an <b>{email}</b> geschickt"
|
||||
}
|
||||
},
|
||||
"create-user-account": {
|
||||
"title": "Benutzerkonto anlegen",
|
||||
"success": "Dein Benutzerkonto wurde erstellt!"
|
||||
}
|
||||
},
|
||||
"verify-code": {
|
||||
"form": {
|
||||
"code": "Code eingeben",
|
||||
@ -174,6 +193,11 @@
|
||||
},
|
||||
"settings": {
|
||||
"name": "Einstellungen"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Benutzer einladen",
|
||||
"title": "Benutzer als Admin anmelden",
|
||||
"description": "Dieses Anmeldeformular ist zu sehen sobald die Anmeldung öffentlich zugänglich ist."
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
"moreInfo": "What is Human Connection?",
|
||||
"moreInfoURL": "https://human-connection.org/en/",
|
||||
"moreInfoHint": "to the presentation page",
|
||||
"hello": "Hello"
|
||||
"hello": "Hello",
|
||||
"success": "You are logged in!"
|
||||
},
|
||||
"password-reset": {
|
||||
"title": "Reset your password",
|
||||
@ -24,6 +25,25 @@
|
||||
"submitted": "A mail with further instruction has been sent to <b>{email}</b>"
|
||||
}
|
||||
},
|
||||
"registration": {
|
||||
"signup": {
|
||||
"title": "Join Human Connection!",
|
||||
"form": {
|
||||
"description": "To get started, enter your email address:",
|
||||
"invitation-code": "Your invitation code is: <b>{code}</b>",
|
||||
"errors": {
|
||||
"email-exists": "There is already a user account with this email address!",
|
||||
"invalid-invitation-token": "It looks like as if the invitation has been used already. Invitation links can only be used once."
|
||||
},
|
||||
"submit": "Create an account",
|
||||
"success": "A mail with a link to complete your registration has been sent to <b>{email}</b>"
|
||||
}
|
||||
},
|
||||
"create-user-account": {
|
||||
"title": "Create user account",
|
||||
"success": "Your account has been created!"
|
||||
}
|
||||
},
|
||||
"verify-code": {
|
||||
"form": {
|
||||
"code": "Enter your code",
|
||||
@ -174,6 +194,11 @@
|
||||
},
|
||||
"settings": {
|
||||
"name": "Settings"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Invite users",
|
||||
"title": "Signup users as admin",
|
||||
"description": "This registration form will be visible as soon as the registration is open to the public."
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
|
||||
@ -31,10 +31,10 @@ module.exports = {
|
||||
'password-reset-request',
|
||||
'password-reset-verify-code',
|
||||
'password-reset-change-password',
|
||||
'register',
|
||||
'signup',
|
||||
'reset',
|
||||
'reset-token',
|
||||
// 'registration-signup', TODO: uncomment to open public registration
|
||||
'registration-signup-by-invitation-code',
|
||||
'registration-verify-code',
|
||||
'registration-create-user-account',
|
||||
'pages-slug',
|
||||
],
|
||||
// pages to keep alive
|
||||
|
||||
@ -54,6 +54,10 @@ export default {
|
||||
name: this.$t('admin.tags.name'),
|
||||
path: `/admin/tags`,
|
||||
},
|
||||
{
|
||||
name: this.$t('admin.invites.name'),
|
||||
path: `/admin/invite`,
|
||||
},
|
||||
// TODO implement
|
||||
/* {
|
||||
name: this.$t('admin.settings.name'),
|
||||
|
||||
23
webapp/pages/admin/invite.vue
Normal file
23
webapp/pages/admin/invite.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<ds-section>
|
||||
<ds-space>
|
||||
<ds-heading size="h3">
|
||||
{{ $t('admin.invites.title') }}
|
||||
</ds-heading>
|
||||
<ds-text>
|
||||
{{ $t('admin.invites.description') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<signup />
|
||||
</ds-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Signup from '~/components/Registration/Signup'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Signup,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -115,7 +115,7 @@ export default {
|
||||
async onSubmit() {
|
||||
try {
|
||||
await this.$store.dispatch('auth/login', { ...this.form })
|
||||
this.$toast.success('You are logged in!')
|
||||
this.$toast.success(this.$t('login.success'))
|
||||
this.$router.replace(this.$route.query.path || '/')
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
|
||||
27
webapp/pages/registration/create-user-account.vue
Normal file
27
webapp/pages/registration/create-user-account.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<create-user-account @userCreated="handleUserCreated" :email="email" :nonce="nonce" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CreateUserAccount from '~/components/Registration/CreateUserAccount'
|
||||
export default {
|
||||
data() {
|
||||
const { nonce = '', email = '' } = this.$route.query
|
||||
return { nonce, email }
|
||||
},
|
||||
components: {
|
||||
CreateUserAccount,
|
||||
},
|
||||
methods: {
|
||||
async handleUserCreated({email, password}) {
|
||||
try {
|
||||
await this.$store.dispatch('auth/login', { email, password })
|
||||
this.$toast.success('You are logged in!')
|
||||
this.$router.push('/')
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user