Merge pull request #1513 from Human-Connection/bugfix_about_me_not_saved_on_signup_verification

Bugfix: `about me` not saved on signup
This commit is contained in:
mattwr18 2019-09-10 17:37:22 +02:00 committed by GitHub
commit 3712a5d2cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 209 additions and 108 deletions

View File

@ -1,62 +1,81 @@
import { GraphQLClient } from 'graphql-request'
import Factory from '../seed/factories'
import { host, login, gql } from '../jest/helpers'
import { neode } from '../bootstrap/neo4j'
import { gql } from '../jest/helpers'
import { neode as getNeode, getDriver } from '../bootstrap/neo4j'
import createServer from '../server'
import { createTestClient } from 'apollo-server-testing'
let authenticatedClient
let headers
const factory = Factory()
const instance = neode()
const categoryIds = ['cat9']
const createPostMutation = gql`
mutation($title: String!, $content: String!, $categoryIds: [ID]!, $slug: String) {
CreatePost(title: $title, content: $content, categoryIds: $categoryIds, slug: $slug) {
slug
}
}
`
let createPostVariables = {
title: 'I am a brand new post',
content: 'Some content',
categoryIds,
}
let mutate
let authenticatedUser
let variables
const driver = getDriver()
const neode = getNeode()
beforeAll(() => {
const { server } = createServer({
context: () => {
return {
driver,
neode,
user: authenticatedUser,
}
},
})
mutate = createTestClient(server).mutate
})
beforeEach(async () => {
const adminParams = { role: 'admin', email: 'admin@example.org', password: '1234' }
await factory.create('User', adminParams)
variables = {}
const admin = await factory.create('User', { role: 'admin' })
await factory.create('User', {
email: 'someone@example.org',
password: '1234',
})
await instance.create('Category', {
await factory.create('Category', {
id: 'cat9',
name: 'Democracy & Politics',
icon: 'university',
})
// we need to be an admin, otherwise we're not authorized to create a user
headers = await login(adminParams)
authenticatedClient = new GraphQLClient(host, { headers })
authenticatedUser = await admin.toJson()
})
afterEach(async () => {
await factory.cleanDatabase()
})
describe('slugify', () => {
describe('slugifyMiddleware', () => {
describe('CreatePost', () => {
const categoryIds = ['cat9']
const createPostMutation = gql`
mutation($title: String!, $content: String!, $categoryIds: [ID]!, $slug: String) {
CreatePost(title: $title, content: $content, categoryIds: $categoryIds, slug: $slug) {
slug
}
}
`
beforeEach(() => {
variables = {
...variables,
title: 'I am a brand new post',
content: 'Some content',
categoryIds,
}
})
it('generates a slug based on title', async () => {
const response = await authenticatedClient.request(createPostMutation, createPostVariables)
expect(response).toEqual({
CreatePost: { slug: 'i-am-a-brand-new-post' },
await expect(mutate({ mutation: createPostMutation, variables })).resolves.toMatchObject({
data: {
CreatePost: { slug: 'i-am-a-brand-new-post' },
},
})
})
describe('if slug exists', () => {
beforeEach(async () => {
const asSomeoneElse = await Factory().authenticateAs({
email: 'someone@example.org',
password: '1234',
})
await asSomeoneElse.create('Post', {
await factory.create('Post', {
title: 'Pre-existing post',
slug: 'pre-existing-post',
content: 'as Someone else content',
@ -65,72 +84,110 @@ describe('slugify', () => {
})
it('chooses another slug', async () => {
createPostVariables = { title: 'Pre-existing post', content: 'Some content', categoryIds }
const response = await authenticatedClient.request(createPostMutation, createPostVariables)
expect(response).toEqual({
CreatePost: { slug: 'pre-existing-post-1' },
variables = {
...variables,
title: 'Pre-existing post',
content: 'Some content',
categoryIds,
}
await expect(mutate({ mutation: createPostMutation, variables })).resolves.toMatchObject({
data: { CreatePost: { slug: 'pre-existing-post-1' } },
})
})
describe('but if the client specifies a slug', () => {
it('rejects CreatePost', async () => {
createPostVariables = {
variables = {
...variables,
title: 'Pre-existing post',
content: 'Some content',
slug: 'pre-existing-post',
categoryIds,
}
await expect(
authenticatedClient.request(createPostMutation, createPostVariables),
).rejects.toThrow('already exists')
await expect(mutate({ mutation: createPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Post with this slug already exists!' }],
})
})
})
})
})
describe('SignupVerification', () => {
const mutation = `mutation($password: String!, $email: String!, $name: String!, $slug: String, $nonce: String!, $termsAndConditionsAgreedVersion: String!) {
SignupVerification(email: $email, password: $password, name: $name, slug: $slug, nonce: $nonce, termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion) {
slug
const mutation = gql`
mutation(
$password: String!
$email: String!
$name: String!
$slug: String
$nonce: String!
$termsAndConditionsAgreedVersion: String!
) {
SignupVerification(
email: $email
password: $password
name: $name
slug: $slug
nonce: $nonce
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
) {
slug
}
}
}
`
const action = async variables => {
// required for SignupVerification
await instance.create('EmailAddress', { email: '123@example.org', nonce: '123456' })
const defaultVariables = {
beforeEach(() => {
variables = {
...variables,
name: 'I am a user',
nonce: '123456',
password: 'yo',
email: '123@example.org',
termsAndConditionsAgreedVersion: '0.0.1',
}
return authenticatedClient.request(mutation, { ...defaultVariables, ...variables })
}
it('generates a slug based on name', async () => {
await expect(action({ name: 'I am a user' })).resolves.toEqual({
SignupVerification: { slug: 'i-am-a-user' },
})
})
describe('if slug exists', () => {
describe('given a user has signed up with their email address', () => {
beforeEach(async () => {
await factory.create('User', { name: 'pre-existing user', slug: 'pre-existing-user' })
})
it('chooses another slug', async () => {
await expect(action({ name: 'pre-existing-user' })).resolves.toEqual({
SignupVerification: { slug: 'pre-existing-user-1' },
await factory.create('EmailAddress', {
email: '123@example.org',
nonce: '123456',
verifiedAt: null,
})
})
describe('but if the client specifies a slug', () => {
it('rejects SignupVerification', async () => {
await expect(
action({ name: 'Pre-existing user', slug: 'pre-existing-user' }),
).rejects.toThrow('already exists')
it('generates a slug based on name', async () => {
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
data: { SignupVerification: { slug: 'i-am-a-user' } },
})
})
describe('if slug exists', () => {
beforeEach(async () => {
await factory.create('User', { name: 'I am a user', slug: 'i-am-a-user' })
})
it('chooses another slug', async () => {
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
data: {
SignupVerification: { slug: 'i-am-a-user-1' },
},
})
})
describe('but if the client specifies a slug', () => {
beforeEach(() => {
variables = { ...variables, slug: 'i-am-a-user' }
})
it('rejects SignupVerification', async () => {
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
errors: [
{
message: 'User with this slug already exists!',
},
],
})
})
})
})
})

View File

@ -3,6 +3,7 @@ import { neo4jgraphql } from 'neo4j-graphql-js'
import fileUpload from './fileUpload'
import { getBlockedUsers, getBlockedByUsers } from './users.js'
import { mergeWith, isArray } from 'lodash'
import { UserInputError } from 'apollo-server'
import Resolver from './helpers/Resolver'
const filterForBlockedUsers = async (params, context) => {
@ -78,6 +79,7 @@ export default {
delete params.categoryIds
params = await fileUpload(params, { file: 'imageUpload', url: 'image' })
params.id = params.id || uuid()
let post
const createPostCypher = `CREATE (post:Post {params})
WITH post
@ -92,15 +94,21 @@ export default {
const createPostVariables = { userId: context.user.id, categoryIds, params }
const session = context.driver.session()
const transactionRes = await session.run(createPostCypher, createPostVariables)
try {
const transactionRes = await session.run(createPostCypher, createPostVariables)
const posts = transactionRes.records.map(record => {
return record.get('post').properties
})
post = posts[0]
} catch (e) {
if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
throw new UserInputError('Post with this slug already exists!')
throw new Error(e)
} finally {
session.close()
}
const [post] = transactionRes.records.map(record => {
return record.get('post')
})
session.close()
return post.properties
return post
},
UpdatePost: async (object, params, context, resolveInfo) => {
const { categoryIds } = params

View File

@ -1,4 +1,4 @@
import { ForbiddenError, UserInputError } from 'apollo-server'
import { UserInputError } from 'apollo-server'
import uuid from 'uuid/v4'
import { neode } from '../../bootstrap/neo4j'
import fileUpload from './fileUpload'
@ -80,7 +80,7 @@ export default {
const { termsAndConditionsAgreedVersion } = args
const regEx = new RegExp(/^[0-9]+\.[0-9]+\.[0-9]+$/g)
if (!regEx.test(termsAndConditionsAgreedVersion)) {
throw new ForbiddenError('Invalid version format!')
throw new UserInputError('Invalid version format!')
}
let { nonce, email } = args
@ -106,6 +106,8 @@ export default {
])
return user.toJson()
} catch (e) {
if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed')
throw new UserInputError('User with this slug already exists!')
throw new UserInputError(e.message)
}
},

View File

@ -327,6 +327,7 @@ describe('SignupVerification', () => {
$password: String!
$email: String!
$nonce: String!
$about: String
$termsAndConditionsAgreedVersion: String!
) {
SignupVerification(
@ -334,6 +335,7 @@ describe('SignupVerification', () => {
password: $password
email: $email
nonce: $nonce
about: $about
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
) {
id
@ -423,6 +425,15 @@ describe('SignupVerification', () => {
expect(emails).toHaveLength(1)
})
it('sets `about` attribute of User', async () => {
variables = { ...variables, about: 'Find this description in the user profile' }
await mutate({ mutation, variables })
const user = await neode.first('User', { name: 'John Doe' })
await expect(user.toJson()).resolves.toMatchObject({
about: 'Find this description in the user profile',
})
})
it('marks the EmailAddress as primary', async () => {
const cypher = `
MATCH(email:EmailAddress)<-[:PRIMARY_EMAIL]-(u:User {name: {name}})

View File

@ -0,0 +1,17 @@
import faker from 'faker'
export default function create() {
return {
factory: async ({ args, neodeInstance }) => {
const defaults = {
email: faker.internet.email(),
verifiedAt: new Date().toISOString(),
}
args = {
...defaults,
...args,
}
return neodeInstance.create('EmailAddress', args)
},
}
}

View File

@ -8,6 +8,7 @@ import createCategory from './categories.js'
import createTag from './tags.js'
import createSocialMedia from './socialMedia.js'
import createLocation from './locations.js'
import createEmailAddress from './emailAddresses.js'
export const seedServerHost = 'http://127.0.0.1:4001'
@ -30,6 +31,7 @@ const factories = {
Tag: createTag,
SocialMedia: createSocialMedia,
Location: createLocation,
EmailAddress: createEmailAddress,
}
export const cleanDatabase = async (options = {}) => {

View File

@ -5,7 +5,7 @@ import slugify from 'slug'
export default function create() {
return {
factory: async ({ args, neodeInstance }) => {
factory: async ({ args, neodeInstance, factoryInstance }) => {
const defaults = {
id: uuid(),
name: faker.name.findName(),
@ -24,7 +24,7 @@ export default function create() {
}
args = await encryptPassword(args)
const user = await neodeInstance.create('User', args)
const email = await neodeInstance.create('EmailAddress', { email: args.email })
const email = await factoryInstance.create('EmailAddress', { email: args.email })
await user.relateTo(email, 'primaryEmail')
await email.relateTo(user, 'belongsTo')
return user

View File

@ -1,5 +1,6 @@
import { config, mount, createLocalVue } from '@vue/test-utils'
import CreateUserAccount, { SignupVerificationMutation } from './CreateUserAccount'
import CreateUserAccount from './CreateUserAccount'
import { SignupVerificationMutation } from '~/graphql/Registration.js'
import Styleguide from '@human-connection/styleguide'
const localVue = createLocalVue()
@ -55,6 +56,7 @@ describe('CreateUserAccount', () => {
wrapper = Wrapper()
wrapper.find('input#name').setValue('John Doe')
wrapper.find('input#password').setValue('hellopassword')
wrapper.find('textarea#about').setValue('Hello I am the `about` attribute')
wrapper.find('input#passwordConfirmation').setValue('hellopassword')
wrapper.find('input#checkbox').setChecked()
await wrapper.find('form').trigger('submit')
@ -72,7 +74,7 @@ describe('CreateUserAccount', () => {
await action()
const expected = expect.objectContaining({
variables: {
about: '',
about: 'Hello I am the `about` attribute',
name: 'John Doe',
email: 'sixseven@example.org',
nonce: '666777',

View File

@ -25,7 +25,7 @@
:placeholder="$t('settings.data.namePlaceholder')"
/>
<ds-input
id="bio"
id="about"
model="about"
type="textarea"
rows="3"
@ -83,34 +83,12 @@
</template>
<script>
import gql from 'graphql-tag'
import PasswordStrength from '../Password/Strength'
import { SweetalertIcon } from 'vue-sweetalert-icons'
import PasswordForm from '~/components/utils/PasswordFormHelper'
import { VERSION } from '~/constants/terms-and-conditions-version.js'
import { SignupVerificationMutation } from '~/graphql/Registration.js'
/* TODO: hier muss die version rein */
export const SignupVerificationMutation = gql`
mutation(
$nonce: String!
$name: String!
$email: String!
$password: String!
$termsAndConditionsAgreedVersion: String!
) {
SignupVerification(
nonce: $nonce
email: $email
name: $name
password: $password
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
) {
id
name
slug
}
}
`
export default {
components: {
PasswordStrength,

View File

@ -0,0 +1,24 @@
import gql from 'graphql-tag'
export const SignupVerificationMutation = gql`
mutation(
$nonce: String!
$name: String!
$email: String!
$password: String!
$about: String
$termsAndConditionsAgreedVersion: String!
) {
SignupVerification(
nonce: $nonce
email: $email
name: $name
password: $password
about: $about
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
) {
id
name
slug
}
}
`