Implement AddEmail resolver

This commit is contained in:
roschaefer 2019-09-24 15:58:12 +02:00
parent 3b6cd55c0f
commit 73d5abd724
4 changed files with 85 additions and 9 deletions

View File

@ -0,0 +1,4 @@
import uuid from 'uuid/v4'
export default function generateNonce() {
return uuid().substring(0, 6)
}

View File

@ -170,6 +170,8 @@ const permissions = shield(
block: isAuthenticated,
unblock: isAuthenticated,
markAsRead: isAuthenticated,
AddEmailAddress: isAuthenticated,
VerifyEmailAddress: isAuthenticated,
},
User: {
email: isMyOwn,

View File

@ -0,0 +1,41 @@
import generateNonce from '../../helpers/generateNonce'
import Resolver from './helpers/Resolver'
export default {
Mutation: {
AddEmailAddress: async (_parent, args, context, _resolveInfo) => {
let response
const nonce = generateNonce()
const {
user: { id: userId },
} = context
const { email } = args
const session = context.driver.session()
const writeTxResultPromise = session.writeTransaction(async txc => {
const result = await txc.run(
`
MATCH (user:User {id: $userId})
MERGE (user)<-[:BELONGS_TO]-(email:EmailAddress {email: $email, nonce: $nonce})
SET email.createdAt = toString(datetime())
RETURN email
`,
{ userId, email, nonce },
)
return result.records.map(record => record.get('email').properties)
})
try {
const txResult = await writeTxResultPromise
response = txResult[0]
} finally {
session.close()
}
return response
},
VerifyEmailAddress: async (_parent, args, context, _resolveInfo) => {},
},
EmailAddress: {
...Resolver('EmailAddress', {
undefinedToNull: ['verifiedAt'],
}),
},
}

View File

@ -37,7 +37,7 @@ afterEach(async () => {
describe('AddEmailAddress', () => {
const mutation = gql`
mutation($email: String!) {
AddEmailAddress(email: $email){
AddEmailAddress(email: $email) {
email
verifiedAt
createdAt
@ -62,14 +62,43 @@ describe('AddEmailAddress', () => {
})
describe('authenticated', () => {
it.todo('creates a new unverified `EmailAddress` node')
it.todo('connects EmailAddress to the authenticated user')
describe('even if an unverified `EmailAddress` already exists with that email', () =>{
it.todo('creates a new unverified `EmailAddress` node')
beforeEach(async () => {
user = await factory.create('User', { email: 'user@example.org' })
authenticatedUser = await user.toJson()
})
describe('but if a verified `EmailAddress` already exists with that email', () =>{
it('creates a new unverified `EmailAddress` node', async () => {
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
data: {
AddEmailAddress: {
email: 'new-email@example.org',
verifiedAt: null,
createdAt: expect.any(String),
},
},
errors: undefined,
})
})
it('connects `EmailAddress` to the authenticated user', async () => {
await mutate({ mutation, variables })
const result = await neode.cypher(`
MATCH(u:User)-[:PRIMARY_EMAIL]->(p:EmailAddress {email: "user@example.org"})
MATCH(u:User)<-[:BELONGS_TO]-(e:EmailAddress {email: "new-email@example.org"})
RETURN e
`)
const email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
await expect(email.toJson()).resolves.toMatchObject({
email: 'new-email@example.org',
nonce: expect.any(String),
})
})
describe('if a lone `EmailAddress` node already exists with that email', () => {
it.todo('returns this `EmailAddress` node')
})
describe('but if another user owns an `EmailAddress` already with that email', () => {
it.todo('throws UserInputError because of unique constraints')
})
})
@ -78,7 +107,7 @@ describe('AddEmailAddress', () => {
describe('VerifyEmailAddress', () => {
const mutation = gql`
mutation($email: String!, $nonce: String!) {
VerifyEmailAddress(email: $email, nonce: $nonce){
VerifyEmailAddress(email: $email, nonce: $nonce) {
email
createdAt
}
@ -117,7 +146,7 @@ describe('VerifyEmailAddress', () => {
})
describe('and the `EmailAddress` belongs to the authenticated user', () => {
it.todo('verifies the `EmailAddress`')
it.todo('adds `verifiedAt`')
it.todo('connects the new `EmailAddress` as PRIMARY')
it.todo('removes previous PRIMARY relationship')
})