mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch 'master' of github.com:Human-Connection/Human-Connection into 906-maintenace-mode
This commit is contained in:
commit
7a3c432a0b
@ -68,7 +68,7 @@
|
||||
"helmet": "~3.18.0",
|
||||
"jsonwebtoken": "~8.5.1",
|
||||
"linkifyjs": "~2.1.8",
|
||||
"lodash": "~4.17.13",
|
||||
"lodash": "~4.17.14",
|
||||
"merge-graphql-schemas": "^1.5.8",
|
||||
"neo4j-driver": "~1.7.4",
|
||||
"neo4j-graphql-js": "^2.6.3",
|
||||
@ -88,7 +88,7 @@
|
||||
"@babel/core": "~7.5.4",
|
||||
"@babel/node": "~7.5.0",
|
||||
"@babel/plugin-proposal-throw-expressions": "^7.2.0",
|
||||
"@babel/preset-env": "~7.5.2",
|
||||
"@babel/preset-env": "~7.5.4",
|
||||
"@babel/register": "~7.4.4",
|
||||
"apollo-server-testing": "~2.6.8",
|
||||
"babel-core": "~7.0.0-0",
|
||||
|
||||
7
backend/src/schema/types/enum/Emotion.gql
Normal file
7
backend/src/schema/types/enum/Emotion.gql
Normal file
@ -0,0 +1,7 @@
|
||||
enum Emotion {
|
||||
surprised
|
||||
cry
|
||||
happy
|
||||
angry
|
||||
funny
|
||||
}
|
||||
10
backend/src/schema/types/type/EMOTED.gql
Normal file
10
backend/src/schema/types/type/EMOTED.gql
Normal file
@ -0,0 +1,10 @@
|
||||
type EMOTED @relation(name: "EMOTED") {
|
||||
from: User
|
||||
to: Post
|
||||
|
||||
emotion: Emotion
|
||||
#createdAt: DateTime
|
||||
#updatedAt: DateTime
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
}
|
||||
@ -48,6 +48,8 @@ type Post {
|
||||
RETURN COUNT(u) >= 1
|
||||
"""
|
||||
)
|
||||
|
||||
emotions: [EMOTED]
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
|
||||
@ -73,6 +73,8 @@ type User {
|
||||
|
||||
badges: [Badge]! @relation(name: "REWARDED", direction: "IN")
|
||||
badgesCount: Int! @cypher(statement: "MATCH (this)<-[:REWARDED]-(r:Badge) RETURN COUNT(r)")
|
||||
|
||||
emotions: [EMOTED]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -320,10 +320,10 @@
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-json-strings" "^7.2.0"
|
||||
|
||||
"@babel/plugin-proposal-object-rest-spread@^7.5.2":
|
||||
version "7.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.2.tgz#ec92b0c6419074ea7af77c78b7c5d42041f2f5a9"
|
||||
integrity sha512-C/JU3YOx5J4d9s0GGlJlYXVwsbd5JmqQ0AvB7cIDAx7nN57aDTnlJEsZJPuSskeBtMGFWSWU5Q+piTiDe0s7FQ==
|
||||
"@babel/plugin-proposal-object-rest-spread@^7.5.4":
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331"
|
||||
integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
|
||||
@ -649,17 +649,17 @@
|
||||
core-js "^2.5.7"
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/preset-env@~7.5.2":
|
||||
version "7.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.2.tgz#34a46f01aed617b174b8dbaf8fed9239300343d0"
|
||||
integrity sha512-7rRJLaUqJhQ+8xGrWtMROAgOi/+udIzyK2ES9NHhDIUvR2zfx/ON5lRR8ACUGehIYst8KVbl4vpkgOqn08gBxA==
|
||||
"@babel/preset-env@~7.5.4":
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.4.tgz#64bc15041a3cbb0798930319917e70fcca57713d"
|
||||
integrity sha512-hFnFnouyRNiH1rL8YkX1ANCNAUVC8Djwdqfev8i1415tnAG+7hlA5zhZ0Q/3Q5gkop4HioIPbCEWAalqcbxRoQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-proposal-async-generator-functions" "^7.2.0"
|
||||
"@babel/plugin-proposal-dynamic-import" "^7.5.0"
|
||||
"@babel/plugin-proposal-json-strings" "^7.2.0"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.5.2"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.5.4"
|
||||
"@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
|
||||
"@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
|
||||
"@babel/plugin-syntax-async-generators" "^7.2.0"
|
||||
@ -5382,9 +5382,9 @@ lodash.isstring@^4.0.1:
|
||||
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
|
||||
|
||||
lodash.mergewith@^4.6.1:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
||||
integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
|
||||
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
|
||||
|
||||
lodash.once@^4.0.0:
|
||||
version "4.1.1"
|
||||
@ -5401,10 +5401,10 @@ lodash@=3.10.1:
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
||||
integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
|
||||
|
||||
lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.13:
|
||||
version "4.17.13"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93"
|
||||
integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA==
|
||||
lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.14:
|
||||
version "4.17.14"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
|
||||
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
|
||||
|
||||
long@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@ -276,9 +276,9 @@ When("I fill the password form with:", table => {
|
||||
table = table.rowsHash();
|
||||
cy.get("input[id=oldPassword]")
|
||||
.type(table["Your old password"])
|
||||
.get("input[id=newPassword]")
|
||||
.get("input[id=password]")
|
||||
.type(table["Your new passsword"])
|
||||
.get("input[id=confirmPassword]")
|
||||
.get("input[id=passwordConfirmation]")
|
||||
.type(table["Confirm new password"]);
|
||||
});
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
MATCH (u:User)-[e:EMOTED]->(c:Post) DETACH DELETE e;
|
||||
@ -5,31 +5,54 @@
|
||||
// [-] Omitted in Nitro
|
||||
// [?] Unclear / has work to be done for Nitro
|
||||
{
|
||||
[ ] userId: {
|
||||
[ ] type: String,
|
||||
[ ] required: true,
|
||||
[X] userId: {
|
||||
[X] type: String,
|
||||
[X] required: true,
|
||||
[-] index: true
|
||||
},
|
||||
[ ] contributionId: {
|
||||
[ ] type: String,
|
||||
[ ] required: true,
|
||||
[X] contributionId: {
|
||||
[X] type: String,
|
||||
[X] required: true,
|
||||
[-] index: true
|
||||
},
|
||||
[ ] rated: {
|
||||
[ ] type: String,
|
||||
[?] rated: {
|
||||
[X] type: String,
|
||||
[ ] required: true,
|
||||
[ ] enum: ['funny', 'happy', 'surprised', 'cry', 'angry']
|
||||
[?] enum: ['funny', 'happy', 'surprised', 'cry', 'angry']
|
||||
},
|
||||
[ ] createdAt: {
|
||||
[ ] type: Date,
|
||||
[ ] default: Date.now
|
||||
[X] createdAt: {
|
||||
[X] type: Date,
|
||||
[X] default: Date.now
|
||||
},
|
||||
[ ] updatedAt: {
|
||||
[ ] type: Date,
|
||||
[ ] default: Date.now
|
||||
[X] updatedAt: {
|
||||
[X] type: Date,
|
||||
[X] default: Date.now
|
||||
},
|
||||
[ ] wasSeeded: { type: Boolean }
|
||||
[-] wasSeeded: { type: Boolean }
|
||||
}
|
||||
*/
|
||||
|
||||
CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL_FILE}") YIELD value as emotion;
|
||||
CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL_FILE}") YIELD value as emotion
|
||||
MATCH (u:User {id: emotion.userId}),
|
||||
(c:Post {id: emotion.contributionId})
|
||||
MERGE (u)-[e:EMOTED {
|
||||
id: emotion._id["$oid"],
|
||||
emotion: emotion.rated,
|
||||
createdAt: datetime(emotion.createdAt.`$date`),
|
||||
updatedAt: datetime(emotion.updatedAt.`$date`)
|
||||
}]->(c)
|
||||
RETURN e;
|
||||
/*
|
||||
// Queries
|
||||
// user sets an emotion emotion:
|
||||
// MERGE (u)-[e:EMOTED {id: ..., emotion: "funny", createdAt: ..., updatedAt: ...}]->(c)
|
||||
// user removes emotion
|
||||
// MATCH (u)-[e:EMOTED]->(c) DELETE e
|
||||
// contribution distributions over every `emotion` property value for one post
|
||||
// MATCH (u:User)-[e:EMOTED]->(c:Post {id: "5a70bbc8508f5b000b443b1a"}) RETURN e.emotion,COUNT(e.emotion)
|
||||
// contribution distributions over every `emotion` property value for one user (advanced - "whats the primary emotion used by the user?")
|
||||
// MATCH (u:User{id:"5a663b1ac64291000bf302a1"})-[e:EMOTED]->(c:Post) RETURN e.emotion,COUNT(e.emotion)
|
||||
// contribution distributions over every `emotion` property value for all posts created by one user (advanced - "how do others react to my contributions?")
|
||||
// MATCH (u:User)-[e:EMOTED]->(c:Post)<-[w:WROTE]-(a:User{id:"5a663b1ac64291000bf302a1"}) RETURN e.emotion,COUNT(e.emotion)
|
||||
// if we can filter the above an a variable timescale that would be great (should be possible on createdAt and updatedAt fields)
|
||||
*/
|
||||
@ -1 +1 @@
|
||||
// this is just a relation between users(?) - no need to delete
|
||||
MATCH (u1:User)-[f:FOLLOWS]->(u2:User) DETACH DELETE f;
|
||||
@ -60,8 +60,8 @@ delete_collection "contributions" "contributions_post"
|
||||
delete_collection "contributions" "contributions_cando"
|
||||
delete_collection "shouts" "shouts"
|
||||
delete_collection "comments" "comments"
|
||||
delete_collection "emotions" "emotions"
|
||||
|
||||
#delete_collection "emotions"
|
||||
#delete_collection "invites"
|
||||
#delete_collection "notifications"
|
||||
#delete_collection "organizations"
|
||||
@ -82,12 +82,12 @@ import_collection "users" "users/users.cql"
|
||||
import_collection "follows_users" "follows/follows.cql"
|
||||
#import_collection "follows_organizations" "follows/follows.cql"
|
||||
import_collection "contributions_post" "contributions/contributions.cql"
|
||||
import_collection "contributions_cando" "contributions/contributions.cql"
|
||||
#import_collection "contributions_cando" "contributions/contributions.cql"
|
||||
#import_collection "contributions_DELETED" "contributions/contributions.cql"
|
||||
import_collection "shouts" "shouts/shouts.cql"
|
||||
import_collection "comments" "comments/comments.cql"
|
||||
import_collection "emotions" "emotions/emotions.cql"
|
||||
|
||||
# import_collection "emotions"
|
||||
# import_collection "invites"
|
||||
# import_collection "notifications"
|
||||
# import_collection "organizations"
|
||||
|
||||
@ -54,7 +54,7 @@ describe('ChangePassword.vue', () => {
|
||||
describe('match', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('input#oldPassword').setValue('some secret')
|
||||
wrapper.find('input#newPassword').setValue('some secret')
|
||||
wrapper.find('input#password').setValue('some secret')
|
||||
})
|
||||
|
||||
it('invalid', () => {
|
||||
@ -90,8 +90,8 @@ describe('ChangePassword.vue', () => {
|
||||
describe('given valid input', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('input#oldPassword').setValue('supersecret')
|
||||
wrapper.find('input#newPassword').setValue('superdupersecret')
|
||||
wrapper.find('input#confirmPassword').setValue('superdupersecret')
|
||||
wrapper.find('input#password').setValue('superdupersecret')
|
||||
wrapper.find('input#passwordConfirmation').setValue('superdupersecret')
|
||||
})
|
||||
|
||||
describe('submit form', () => {
|
||||
@ -109,8 +109,8 @@ describe('ChangePassword.vue', () => {
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
oldPassword: 'supersecret',
|
||||
newPassword: 'superdupersecret',
|
||||
confirmPassword: 'superdupersecret',
|
||||
password: 'superdupersecret',
|
||||
passwordConfirmation: 'superdupersecret',
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -135,8 +135,8 @@ describe('ChangePassword.vue', () => {
|
||||
/* describe('mutation rejects', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('input#oldPassword').setValue('supersecret')
|
||||
await wrapper.find('input#newPassword').setValue('supersecret')
|
||||
await wrapper.find('input#confirmPassword').setValue('supersecret')
|
||||
await wrapper.find('input#password').setValue('supersecret')
|
||||
await wrapper.find('input#passwordConfirmation').setValue('supersecret')
|
||||
})
|
||||
|
||||
it('displays error message', async () => {
|
||||
|
||||
@ -1,12 +1,6 @@
|
||||
<template>
|
||||
<ds-form
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="handleSubmit"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
>
|
||||
<template>
|
||||
<ds-form v-model="formData" :schema="formSchema" @submit="handleSubmit">
|
||||
<template slot-scope="{ errors }">
|
||||
<ds-input
|
||||
id="oldPassword"
|
||||
model="oldPassword"
|
||||
@ -15,22 +9,22 @@
|
||||
:label="$t('settings.security.change-password.label-old-password')"
|
||||
/>
|
||||
<ds-input
|
||||
id="newPassword"
|
||||
model="newPassword"
|
||||
id="password"
|
||||
model="password"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password')"
|
||||
/>
|
||||
<ds-input
|
||||
id="confirmPassword"
|
||||
model="confirmPassword"
|
||||
id="passwordConfirmation"
|
||||
model="passwordConfirmation"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password-confirm')"
|
||||
/>
|
||||
<password-strength :password="formData.newPassword" />
|
||||
<password-strength :password="formData.password" />
|
||||
<ds-space margin-top="base">
|
||||
<ds-button :loading="loading" :disabled="disabled" primary>
|
||||
<ds-button :loading="loading" :disabled="errors" primary>
|
||||
{{ $t('settings.security.change-password.button') }}
|
||||
</ds-button>
|
||||
</ds-space>
|
||||
@ -41,6 +35,7 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import PasswordStrength from './Strength'
|
||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||
|
||||
export default {
|
||||
name: 'ChangePassword',
|
||||
@ -48,11 +43,11 @@ export default {
|
||||
PasswordStrength,
|
||||
},
|
||||
data() {
|
||||
const passwordForm = PasswordForm({ translate: this.$t })
|
||||
return {
|
||||
formData: {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
...passwordForm.formData,
|
||||
},
|
||||
formSchema: {
|
||||
oldPassword: {
|
||||
@ -60,38 +55,18 @@ export default {
|
||||
required: true,
|
||||
message: this.$t('settings.security.change-password.message-old-password-required'),
|
||||
},
|
||||
newPassword: {
|
||||
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',
|
||||
),
|
||||
},
|
||||
],
|
||||
...passwordForm.formSchema,
|
||||
},
|
||||
loading: false,
|
||||
disabled: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleInput(data) {
|
||||
this.disabled = true
|
||||
},
|
||||
async handleInputValid(data) {
|
||||
this.disabled = false
|
||||
},
|
||||
async handleSubmit(data) {
|
||||
this.loading = true
|
||||
const mutation = gql`
|
||||
mutation($oldPassword: String!, $newPassword: String!) {
|
||||
changePassword(oldPassword: $oldPassword, newPassword: $newPassword)
|
||||
mutation($oldPassword: String!, $password: String!) {
|
||||
changePassword(oldPassword: $oldPassword, newPassword: $password)
|
||||
}
|
||||
`
|
||||
const variables = this.formData
|
||||
@ -102,8 +77,8 @@ export default {
|
||||
this.$toast.success(this.$t('settings.security.change-password.success'))
|
||||
this.formData = {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
}
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
@ -111,15 +86,6 @@ export default {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
matchPassword(rule, value, callback, source, options) {
|
||||
var errors = []
|
||||
if (this.formData.newPassword !== value) {
|
||||
errors.push(
|
||||
new Error(this.$t('settings.security.change-password.message-new-password-missmatch')),
|
||||
)
|
||||
}
|
||||
callback(errors)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -47,8 +47,8 @@ describe('ChangePassword ', () => {
|
||||
describe('submitting new password', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.find('input#newPassword').setValue('supersecret')
|
||||
wrapper.find('input#confirmPassword').setValue('supersecret')
|
||||
wrapper.find('input#password').setValue('supersecret')
|
||||
wrapper.find('input#passwordConfirmation').setValue('supersecret')
|
||||
wrapper.find('form').trigger('submit')
|
||||
})
|
||||
|
||||
@ -58,7 +58,7 @@ describe('ChangePassword ', () => {
|
||||
|
||||
it('delivers new password to backend', () => {
|
||||
const expected = expect.objectContaining({
|
||||
variables: { code: '123456', email: 'mail@example.org', newPassword: 'supersecret' },
|
||||
variables: { code: '123456', email: 'mail@example.org', password: 'supersecret' },
|
||||
})
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
})
|
||||
|
||||
@ -1,54 +1,52 @@
|
||||
<template>
|
||||
<ds-card class="verify-code">
|
||||
<ds-space margin="large">
|
||||
<template>
|
||||
<ds-form
|
||||
v-if="!changePasswordResult"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="handleSubmitPassword"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
class="change-password"
|
||||
>
|
||||
<ds-form
|
||||
v-if="!changePasswordResult"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="handleSubmitPassword"
|
||||
class="change-password"
|
||||
>
|
||||
<template slot-scope="{ errors }">
|
||||
<ds-input
|
||||
id="newPassword"
|
||||
model="newPassword"
|
||||
id="password"
|
||||
model="password"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password')"
|
||||
/>
|
||||
<ds-input
|
||||
id="confirmPassword"
|
||||
model="confirmPassword"
|
||||
id="passwordConfirmation"
|
||||
model="passwordConfirmation"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password-confirm')"
|
||||
/>
|
||||
<password-strength :password="formData.newPassword" />
|
||||
<password-strength :password="formData.password" />
|
||||
<ds-space margin-top="base">
|
||||
<ds-button :loading="$apollo.loading" :disabled="disabled" primary>
|
||||
<ds-button :loading="$apollo.loading" :disabled="errors" primary>
|
||||
{{ $t('settings.security.change-password.button') }}
|
||||
</ds-button>
|
||||
</ds-space>
|
||||
</ds-form>
|
||||
<ds-text v-else>
|
||||
<template v-if="changePasswordResult === 'success'">
|
||||
<sweetalert-icon icon="success" />
|
||||
<ds-text>
|
||||
{{ $t(`verify-code.form.change-password.success`) }}
|
||||
</ds-text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<sweetalert-icon icon="error" />
|
||||
<ds-text align="left">
|
||||
{{ $t(`verify-code.form.change-password.error`) }}
|
||||
{{ $t('verify-code.form.change-password.help') }}
|
||||
</ds-text>
|
||||
<a href="mailto:support@human-connection.org">support@human-connection.org</a>
|
||||
</template>
|
||||
</ds-text>
|
||||
</template>
|
||||
</template>
|
||||
</ds-form>
|
||||
<ds-text v-else>
|
||||
<template v-if="changePasswordResult === 'success'">
|
||||
<sweetalert-icon icon="success" />
|
||||
<ds-text>
|
||||
{{ $t(`verify-code.form.change-password.success`) }}
|
||||
</ds-text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<sweetalert-icon icon="error" />
|
||||
<ds-text align="left">
|
||||
{{ $t(`verify-code.form.change-password.error`) }}
|
||||
{{ $t('verify-code.form.change-password.help') }}
|
||||
</ds-text>
|
||||
<a href="mailto:support@human-connection.org">support@human-connection.org</a>
|
||||
</template>
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
@ -57,6 +55,7 @@
|
||||
import PasswordStrength from '../Password/Strength'
|
||||
import gql from 'graphql-tag'
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -68,48 +67,28 @@ export default {
|
||||
code: { type: String, required: true },
|
||||
},
|
||||
data() {
|
||||
const passwordForm = PasswordForm({ translate: this.$t })
|
||||
return {
|
||||
formData: {
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
...passwordForm.formData,
|
||||
},
|
||||
formSchema: {
|
||||
newPassword: {
|
||||
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',
|
||||
),
|
||||
},
|
||||
],
|
||||
...passwordForm.formSchema,
|
||||
},
|
||||
disabled: true,
|
||||
changePasswordResult: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleInput() {
|
||||
this.disabled = true
|
||||
},
|
||||
async handleInputValid() {
|
||||
this.disabled = false
|
||||
},
|
||||
async handleSubmitPassword() {
|
||||
const mutation = gql`
|
||||
mutation($code: String!, $email: String!, $newPassword: String!) {
|
||||
resetPassword(code: $code, email: $email, newPassword: $newPassword)
|
||||
mutation($code: String!, $email: String!, $password: String!) {
|
||||
resetPassword(code: $code, email: $email, newPassword: $password)
|
||||
}
|
||||
`
|
||||
const { newPassword } = this.formData
|
||||
const { password } = this.formData
|
||||
const { email, code } = this
|
||||
const variables = { newPassword, email, code }
|
||||
const variables = { password, email, code }
|
||||
try {
|
||||
const {
|
||||
data: { resetPassword },
|
||||
@ -119,22 +98,13 @@ export default {
|
||||
this.$emit('passwordResetResponse', this.changePasswordResult)
|
||||
}, 3000)
|
||||
this.formData = {
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
}
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
},
|
||||
matchPassword(rule, value, callback, source, options) {
|
||||
var errors = []
|
||||
if (this.formData.newPassword !== value) {
|
||||
errors.push(
|
||||
new Error(this.$t('settings.security.change-password.message-new-password-missmatch')),
|
||||
)
|
||||
}
|
||||
callback(errors)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
132
webapp/components/Registration/CreateUserAccount.spec.js
Normal file
132
webapp/components/Registration/CreateUserAccount.spec.js
Normal file
@ -0,0 +1,132 @@
|
||||
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#passwordConfirmation').setValue('hellopassword')
|
||||
await wrapper.find('form').trigger('submit')
|
||||
await wrapper.html()
|
||||
}
|
||||
})
|
||||
|
||||
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 { password, email }', async () => {
|
||||
await action()
|
||||
jest.runAllTimers()
|
||||
expect(wrapper.emitted('userCreated')).toEqual([
|
||||
[
|
||||
{
|
||||
email: 'sixseven@example.org',
|
||||
password: 'hellopassword',
|
||||
},
|
||||
],
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('in case mutation rejects', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.mutate = jest.fn().mockRejectedValue(new Error('Invalid nonce'))
|
||||
})
|
||||
|
||||
it('displays form errors', async () => {
|
||||
await action()
|
||||
expect(wrapper.find('.backendErrors').text()).toContain('Invalid nonce')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
142
webapp/components/Registration/CreateUserAccount.vue
Normal file
142
webapp/components/Registration/CreateUserAccount.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<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"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="submit"
|
||||
>
|
||||
<template slot-scope="{ errors }">
|
||||
<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="passwordConfirmation"
|
||||
model="passwordConfirmation"
|
||||
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="backendErrors" v-if="backendErrors">
|
||||
<ds-text align="center" bold color="danger">
|
||||
{{ backendErrors.message }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<ds-button
|
||||
style="float: right;"
|
||||
icon="check"
|
||||
type="submit"
|
||||
:loading="$apollo.loading"
|
||||
:disabled="errors"
|
||||
primary
|
||||
>
|
||||
{{ $t('actions.save') }}
|
||||
</ds-button>
|
||||
</template>
|
||||
</ds-card>
|
||||
</template>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import PasswordStrength from '../Password/Strength'
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||
|
||||
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() {
|
||||
const passwordForm = PasswordForm({ translate: this.$t })
|
||||
return {
|
||||
formData: {
|
||||
name: '',
|
||||
about: '',
|
||||
...passwordForm.formData,
|
||||
},
|
||||
formSchema: {
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
min: 3,
|
||||
},
|
||||
about: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
...passwordForm.formSchema,
|
||||
},
|
||||
disabled: true,
|
||||
success: null,
|
||||
backendErrors: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
nonce: { type: String, required: true },
|
||||
email: { type: String, required: true },
|
||||
},
|
||||
methods: {
|
||||
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.backendErrors = err
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
146
webapp/components/Registration/Signup.spec.js
Normal file
146
webapp/components/Registration/Signup.spec.js
Normal file
@ -0,0 +1,146 @@
|
||||
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')
|
||||
await wrapper.html()
|
||||
}
|
||||
})
|
||||
|
||||
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('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('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="info" />
|
||||
<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>
|
||||
36
webapp/components/utils/PasswordFormHelper.js
Normal file
36
webapp/components/utils/PasswordFormHelper.js
Normal file
@ -0,0 +1,36 @@
|
||||
export default function PasswordForm({ translate }) {
|
||||
const passwordMismatchMessage = translate(
|
||||
'settings.security.change-password.message-new-password-missmatch',
|
||||
)
|
||||
return {
|
||||
formData: {
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
},
|
||||
formSchema: {
|
||||
password: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: translate('settings.security.change-password.message-new-password-required'),
|
||||
},
|
||||
passwordConfirmation: [
|
||||
{
|
||||
validator(rule, value, callback, source, options) {
|
||||
var errors = []
|
||||
if (source.password !== value) {
|
||||
errors.push(new Error(passwordMismatchMessage))
|
||||
}
|
||||
callback(errors)
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: translate(
|
||||
'settings.security.change-password.message-new-password-confirm-required',
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@
|
||||
</ds-container>
|
||||
</div>
|
||||
<ds-container style="word-break: break-all">
|
||||
<div style="padding: 6rem 2rem 5rem;" :width="{ base: '100%', md: '96%' }">
|
||||
<div class="main-container" :width="{ base: '100%', md: '96%' }">
|
||||
<nuxt />
|
||||
</div>
|
||||
</ds-container>
|
||||
@ -226,6 +226,11 @@ export default {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
padding-top: 6rem;
|
||||
padding-botton: 5rem;
|
||||
}
|
||||
|
||||
.main-navigation {
|
||||
a {
|
||||
color: $text-color-soft;
|
||||
|
||||
@ -29,7 +29,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",
|
||||
@ -39,6 +40,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",
|
||||
@ -189,6 +208,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": {
|
||||
|
||||
@ -29,7 +29,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",
|
||||
@ -39,6 +40,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",
|
||||
@ -189,6 +209,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
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.5.4",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/preset-env": "~7.4.5",
|
||||
"@babel/preset-env": "~7.5.4",
|
||||
"@vue/cli-shared-utils": "~3.9.0",
|
||||
"@vue/eslint-config-prettier": "~4.0.1",
|
||||
"@vue/server-test-utils": "~1.0.0-beta.29",
|
||||
|
||||
@ -52,6 +52,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)
|
||||
|
||||
14
webapp/pages/registration.vue
Normal file
14
webapp/pages/registration.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<nuxt-child />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'default',
|
||||
asyncData({ store, redirect }) {
|
||||
if (store.getters['auth/isLoggedIn']) {
|
||||
redirect('/')
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
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>
|
||||
136
webapp/yarn.lock
136
webapp/yarn.lock
@ -268,6 +268,14 @@
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-decorators" "^7.2.0"
|
||||
|
||||
"@babel/plugin-proposal-dynamic-import@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506"
|
||||
integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-dynamic-import" "^7.2.0"
|
||||
|
||||
"@babel/plugin-proposal-json-strings@^7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317"
|
||||
@ -276,10 +284,10 @@
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-json-strings" "^7.2.0"
|
||||
|
||||
"@babel/plugin-proposal-object-rest-spread@^7.4.4":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz#1ef173fcf24b3e2df92a678f027673b55e7e3005"
|
||||
integrity sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==
|
||||
"@babel/plugin-proposal-object-rest-spread@^7.5.4":
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331"
|
||||
integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
|
||||
@ -357,10 +365,10 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-transform-async-to-generator@^7.4.4":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz#a3f1d01f2f21cadab20b33a82133116f14fb5894"
|
||||
integrity sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==
|
||||
"@babel/plugin-transform-async-to-generator@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e"
|
||||
integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
@ -402,10 +410,10 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-transform-destructuring@^7.4.4":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz#9d964717829cc9e4b601fc82a26a71a4d8faf20f"
|
||||
integrity sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==
|
||||
"@babel/plugin-transform-destructuring@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a"
|
||||
integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
@ -418,10 +426,10 @@
|
||||
"@babel/helper-regex" "^7.4.4"
|
||||
regexpu-core "^4.5.4"
|
||||
|
||||
"@babel/plugin-transform-duplicate-keys@^7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3"
|
||||
integrity sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==
|
||||
"@babel/plugin-transform-duplicate-keys@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853"
|
||||
integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
@ -462,30 +470,33 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-transform-modules-amd@^7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6"
|
||||
integrity sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==
|
||||
"@babel/plugin-transform-modules-amd@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91"
|
||||
integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==
|
||||
dependencies:
|
||||
"@babel/helper-module-transforms" "^7.1.0"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
babel-plugin-dynamic-import-node "^2.3.0"
|
||||
|
||||
"@babel/plugin-transform-modules-commonjs@^7.4.4":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz#0bef4713d30f1d78c2e59b3d6db40e60192cac1e"
|
||||
integrity sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==
|
||||
"@babel/plugin-transform-modules-commonjs@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74"
|
||||
integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-transforms" "^7.4.4"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/helper-simple-access" "^7.1.0"
|
||||
babel-plugin-dynamic-import-node "^2.3.0"
|
||||
|
||||
"@babel/plugin-transform-modules-systemjs@^7.4.4":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz#dc83c5665b07d6c2a7b224c00ac63659ea36a405"
|
||||
integrity sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==
|
||||
"@babel/plugin-transform-modules-systemjs@^7.5.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249"
|
||||
integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==
|
||||
dependencies:
|
||||
"@babel/helper-hoist-variables" "^7.4.4"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
babel-plugin-dynamic-import-node "^2.3.0"
|
||||
|
||||
"@babel/plugin-transform-modules-umd@^7.2.0":
|
||||
version "7.2.0"
|
||||
@ -603,39 +614,41 @@
|
||||
"@babel/helper-regex" "^7.4.4"
|
||||
regexpu-core "^4.5.4"
|
||||
|
||||
"@babel/preset-env@^7.4.5", "@babel/preset-env@~7.4.5":
|
||||
version "7.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.5.tgz#2fad7f62983d5af563b5f3139242755884998a58"
|
||||
integrity sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==
|
||||
"@babel/preset-env@^7.4.5", "@babel/preset-env@~7.5.4":
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.4.tgz#64bc15041a3cbb0798930319917e70fcca57713d"
|
||||
integrity sha512-hFnFnouyRNiH1rL8YkX1ANCNAUVC8Djwdqfev8i1415tnAG+7hlA5zhZ0Q/3Q5gkop4HioIPbCEWAalqcbxRoQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-proposal-async-generator-functions" "^7.2.0"
|
||||
"@babel/plugin-proposal-dynamic-import" "^7.5.0"
|
||||
"@babel/plugin-proposal-json-strings" "^7.2.0"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.4.4"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.5.4"
|
||||
"@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
|
||||
"@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
|
||||
"@babel/plugin-syntax-async-generators" "^7.2.0"
|
||||
"@babel/plugin-syntax-dynamic-import" "^7.2.0"
|
||||
"@babel/plugin-syntax-json-strings" "^7.2.0"
|
||||
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
|
||||
"@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
|
||||
"@babel/plugin-transform-arrow-functions" "^7.2.0"
|
||||
"@babel/plugin-transform-async-to-generator" "^7.4.4"
|
||||
"@babel/plugin-transform-async-to-generator" "^7.5.0"
|
||||
"@babel/plugin-transform-block-scoped-functions" "^7.2.0"
|
||||
"@babel/plugin-transform-block-scoping" "^7.4.4"
|
||||
"@babel/plugin-transform-classes" "^7.4.4"
|
||||
"@babel/plugin-transform-computed-properties" "^7.2.0"
|
||||
"@babel/plugin-transform-destructuring" "^7.4.4"
|
||||
"@babel/plugin-transform-destructuring" "^7.5.0"
|
||||
"@babel/plugin-transform-dotall-regex" "^7.4.4"
|
||||
"@babel/plugin-transform-duplicate-keys" "^7.2.0"
|
||||
"@babel/plugin-transform-duplicate-keys" "^7.5.0"
|
||||
"@babel/plugin-transform-exponentiation-operator" "^7.2.0"
|
||||
"@babel/plugin-transform-for-of" "^7.4.4"
|
||||
"@babel/plugin-transform-function-name" "^7.4.4"
|
||||
"@babel/plugin-transform-literals" "^7.2.0"
|
||||
"@babel/plugin-transform-member-expression-literals" "^7.2.0"
|
||||
"@babel/plugin-transform-modules-amd" "^7.2.0"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.4.4"
|
||||
"@babel/plugin-transform-modules-systemjs" "^7.4.4"
|
||||
"@babel/plugin-transform-modules-amd" "^7.5.0"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.5.0"
|
||||
"@babel/plugin-transform-modules-systemjs" "^7.5.0"
|
||||
"@babel/plugin-transform-modules-umd" "^7.2.0"
|
||||
"@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5"
|
||||
"@babel/plugin-transform-new-target" "^7.4.4"
|
||||
@ -650,7 +663,7 @@
|
||||
"@babel/plugin-transform-template-literals" "^7.4.4"
|
||||
"@babel/plugin-transform-typeof-symbol" "^7.2.0"
|
||||
"@babel/plugin-transform-unicode-regex" "^7.4.4"
|
||||
"@babel/types" "^7.4.4"
|
||||
"@babel/types" "^7.5.0"
|
||||
browserslist "^4.6.0"
|
||||
core-js-compat "^3.1.1"
|
||||
invariant "^2.2.2"
|
||||
@ -2352,6 +2365,13 @@ babel-messages@^6.23.0:
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
babel-plugin-dynamic-import-node@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
|
||||
integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
|
||||
dependencies:
|
||||
object.assign "^4.1.0"
|
||||
|
||||
babel-plugin-istanbul@^5.1.0:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.4.tgz#841d16b9a58eeb407a0ddce622ba02fe87a752ba"
|
||||
@ -6843,7 +6863,7 @@ locate-path@^3.0.0:
|
||||
p-locate "^3.0.0"
|
||||
path-exists "^3.0.0"
|
||||
|
||||
lodash._reinterpolate@~3.0.0:
|
||||
lodash._reinterpolate@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
|
||||
@ -6904,19 +6924,19 @@ lodash.tail@^4.1.1:
|
||||
integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
|
||||
|
||||
lodash.template@^4.2.4, lodash.template@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
|
||||
integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
|
||||
integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
|
||||
dependencies:
|
||||
lodash._reinterpolate "~3.0.0"
|
||||
lodash._reinterpolate "^3.0.0"
|
||||
lodash.templatesettings "^4.0.0"
|
||||
|
||||
lodash.templatesettings@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
|
||||
integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33"
|
||||
integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==
|
||||
dependencies:
|
||||
lodash._reinterpolate "~3.0.0"
|
||||
lodash._reinterpolate "^3.0.0"
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
@ -6929,9 +6949,9 @@ lodash.uniqueid@^4.0.1:
|
||||
integrity sha1-MmjyanyI5PSxdY1nknGBTjH6WyY=
|
||||
|
||||
lodash@4.x, lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
version "4.17.14"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
|
||||
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
|
||||
|
||||
log-symbols@^2.2.0:
|
||||
version "2.2.0"
|
||||
@ -7710,7 +7730,7 @@ object-hash@^1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
|
||||
integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==
|
||||
|
||||
object-keys@^1.0.12:
|
||||
object-keys@^1.0.11, object-keys@^1.0.12:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
@ -7727,6 +7747,16 @@ object-visit@^1.0.0:
|
||||
dependencies:
|
||||
isobject "^3.0.0"
|
||||
|
||||
object.assign@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
|
||||
integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
|
||||
dependencies:
|
||||
define-properties "^1.1.2"
|
||||
function-bind "^1.1.1"
|
||||
has-symbols "^1.0.0"
|
||||
object-keys "^1.0.11"
|
||||
|
||||
object.getownpropertydescriptors@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user