mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Resolvers for EmailAddress implemented
This commit is contained in:
parent
8c13234af9
commit
e51124f316
@ -1,6 +1,7 @@
|
|||||||
import generateNonce from './helpers/generateNonce'
|
import generateNonce from './helpers/generateNonce'
|
||||||
import Resolver from './helpers/Resolver'
|
import Resolver from './helpers/Resolver'
|
||||||
import existingEmailAddress from './helpers/existingEmailAddress'
|
import existingEmailAddress from './helpers/existingEmailAddress'
|
||||||
|
import { UserInputError } from 'apollo-server'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
@ -34,7 +35,36 @@ export default {
|
|||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
VerifyEmailAddress: async (_parent, args, context, _resolveInfo) => {},
|
VerifyEmailAddress: async (_parent, args, context, _resolveInfo) => {
|
||||||
|
let response
|
||||||
|
const {
|
||||||
|
user: { id: userId },
|
||||||
|
} = context
|
||||||
|
const { nonce, email } = args
|
||||||
|
const session = context.driver.session()
|
||||||
|
const writeTxResultPromise = session.writeTransaction(async txc => {
|
||||||
|
const result = await txc.run(
|
||||||
|
`
|
||||||
|
MATCH (user:User {id: $userId})-[previous:PRIMARY_EMAIL]->(:EmailAddress)
|
||||||
|
MATCH (user)<-[:BELONGS_TO]-(email:EmailAddress {email: $email, nonce: $nonce})
|
||||||
|
MERGE (user)-[:PRIMARY_EMAIL]->(email)
|
||||||
|
SET email.verifiedAt = toString(datetime())
|
||||||
|
DELETE previous
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
if (!response) throw new UserInputError('Invalid nonce or no email address found.')
|
||||||
|
return response
|
||||||
|
},
|
||||||
},
|
},
|
||||||
EmailAddress: {
|
EmailAddress: {
|
||||||
...Resolver('EmailAddress', {
|
...Resolver('EmailAddress', {
|
||||||
|
|||||||
@ -67,6 +67,11 @@ describe('AddEmailAddress', () => {
|
|||||||
authenticatedUser = await user.toJson()
|
authenticatedUser = await user.toJson()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('email attribute is not a valid email', () => {
|
||||||
|
it.todo('throws UserInputError')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('email attribute is a valid email', () => {
|
||||||
it('creates a new unverified `EmailAddress` node', async () => {
|
it('creates a new unverified `EmailAddress` node', async () => {
|
||||||
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||||
data: {
|
data: {
|
||||||
@ -83,7 +88,7 @@ describe('AddEmailAddress', () => {
|
|||||||
it('connects `EmailAddress` to the authenticated user', async () => {
|
it('connects `EmailAddress` to the authenticated user', async () => {
|
||||||
await mutate({ mutation, variables })
|
await mutate({ mutation, variables })
|
||||||
const result = await neode.cypher(`
|
const result = await neode.cypher(`
|
||||||
MATCH(u:User)-[:PRIMARY_EMAIL]->(p:EmailAddress {email: "user@example.org"})
|
MATCH(u:User)-[:PRIMARY_EMAIL]->(:EmailAddress {email: "user@example.org"})
|
||||||
MATCH(u:User)<-[:BELONGS_TO]-(e:EmailAddress {email: "new-email@example.org"})
|
MATCH(u:User)<-[:BELONGS_TO]-(e:EmailAddress {email: "new-email@example.org"})
|
||||||
RETURN e
|
RETURN e
|
||||||
`)
|
`)
|
||||||
@ -125,6 +130,7 @@ describe('AddEmailAddress', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('VerifyEmailAddress', () => {
|
describe('VerifyEmailAddress', () => {
|
||||||
const mutation = gql`
|
const mutation = gql`
|
||||||
@ -132,6 +138,7 @@ describe('VerifyEmailAddress', () => {
|
|||||||
VerifyEmailAddress(email: $email, nonce: $nonce) {
|
VerifyEmailAddress(email: $email, nonce: $nonce) {
|
||||||
email
|
email
|
||||||
createdAt
|
createdAt
|
||||||
|
verifiedAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@ -154,23 +161,102 @@ describe('VerifyEmailAddress', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('authenticated', () => {
|
describe('authenticated', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await factory.create('User', { email: 'user@example.org' })
|
||||||
|
authenticatedUser = await user.toJson()
|
||||||
|
})
|
||||||
|
|
||||||
describe('if no unverified `EmailAddress` node exists', () => {
|
describe('if no unverified `EmailAddress` node exists', () => {
|
||||||
it.todo('throws UserInputError')
|
it('throws UserInputError', async () => {
|
||||||
|
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||||
|
data: { VerifyEmailAddress: null },
|
||||||
|
errors: [{ message: 'Invalid nonce or no email address found.' }],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given an unverified `EmailAddress`', () => {
|
||||||
|
let emailAddress
|
||||||
|
beforeEach(async () => {
|
||||||
|
emailAddress = await factory.create('EmailAddress', {
|
||||||
|
nonce: 'abcdef',
|
||||||
|
verifiedAt: null,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
email: 'to-be-verified@example.org',
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('given invalid nonce', () => {
|
describe('given invalid nonce', () => {
|
||||||
it.todo('throws UserInputError')
|
it('throws UserInputError', async () => {
|
||||||
|
variables.nonce = 'asdfgh'
|
||||||
|
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||||
|
data: { VerifyEmailAddress: null },
|
||||||
|
errors: [{ message: 'Invalid nonce or no email address found.' }],
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('given valid nonce for unverified `EmailAddress` node', () => {
|
describe('given valid nonce for unverified `EmailAddress` node', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
variables = { ...variables, nonce: 'abcdef' }
|
||||||
|
})
|
||||||
|
|
||||||
describe('but the address does not belong to the authenticated user', () => {
|
describe('but the address does not belong to the authenticated user', () => {
|
||||||
it.todo('throws UserInputError')
|
it('throws UserInputError', async () => {
|
||||||
|
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||||
|
data: { VerifyEmailAddress: null },
|
||||||
|
errors: [{ message: 'Invalid nonce or no email address found.' }],
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('and the `EmailAddress` belongs to the authenticated user', () => {
|
describe('and the `EmailAddress` belongs to the authenticated user', () => {
|
||||||
it.todo('adds `verifiedAt`')
|
beforeEach(async () => {
|
||||||
it.todo('connects the new `EmailAddress` as PRIMARY')
|
await emailAddress.relateTo(user, 'belongsTo')
|
||||||
it.todo('removes previous PRIMARY relationship')
|
})
|
||||||
|
|
||||||
|
it('adds `verifiedAt`', async () => {
|
||||||
|
await expect(mutate({ mutation, variables })).resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
VerifyEmailAddress: {
|
||||||
|
email: 'to-be-verified@example.org',
|
||||||
|
verifiedAt: expect.any(String),
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('connects the new `EmailAddress` as PRIMARY', async () => {
|
||||||
|
await mutate({ mutation, variables })
|
||||||
|
const result = await neode.cypher(`
|
||||||
|
MATCH(u:User)-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "to-be-verified@example.org"})
|
||||||
|
MATCH(u:User)<-[:BELONGS_TO]-(:EmailAddress {email: "user@example.org"})
|
||||||
|
RETURN e
|
||||||
|
`)
|
||||||
|
const email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
|
||||||
|
await expect(email.toJson()).resolves.toMatchObject({
|
||||||
|
email: 'to-be-verified@example.org',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes previous PRIMARY relationship', async () => {
|
||||||
|
const cypherStatement = `
|
||||||
|
MATCH(u:User)-[:PRIMARY_EMAIL]->(e:EmailAddress {email: "user@example.org"})
|
||||||
|
RETURN e
|
||||||
|
`
|
||||||
|
let result = await neode.cypher(cypherStatement)
|
||||||
|
let email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
|
||||||
|
await expect(email.toJson()).resolves.toMatchObject({
|
||||||
|
email: 'user@example.org',
|
||||||
|
})
|
||||||
|
await mutate({ mutation, variables })
|
||||||
|
result = await neode.cypher(cypherStatement)
|
||||||
|
email = neode.hydrateFirst(result, 'e', neode.model('EmailAddress'))
|
||||||
|
await expect(email).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user