mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2026-01-15 01:14:39 +00:00
Added backend support for a user's profile header image: added type in gql schema, resolvers, models and database seed. Also added tests everywhere a user's profile avatar is also tested.
This commit is contained in:
parent
c113fde014
commit
a551959b79
@ -91,14 +91,22 @@ Factory.define('user')
|
||||
url: faker.internet.avatar(),
|
||||
}),
|
||||
)
|
||||
/* Defaults to false since a lot of existing tests are based on finding a certain
|
||||
amount of images without further checks causing them to fail when finding these
|
||||
extra profile header images. A couple of users are given profile headers
|
||||
explicitly in seed.js.
|
||||
*/
|
||||
.option('profileHeader', () => false)
|
||||
.after(async (buildObject, options) => {
|
||||
const [user, email, avatar] = await Promise.all([
|
||||
const [user, email, avatar, profileHeader] = await Promise.all([
|
||||
neode.create('User', buildObject),
|
||||
neode.create('EmailAddress', { email: options.email }),
|
||||
options.avatar,
|
||||
options.profileHeader,
|
||||
])
|
||||
await Promise.all([user.relateTo(email, 'primaryEmail'), email.relateTo(user, 'belongsTo')])
|
||||
if (avatar) await user.relateTo(avatar, 'avatar')
|
||||
if (profileHeader) await user.relateTo(profileHeader, 'profileHeader')
|
||||
return user
|
||||
})
|
||||
|
||||
|
||||
@ -168,6 +168,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
{
|
||||
email: 'moderator@example.org',
|
||||
profileHeader: Factory.build('image'),
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
@ -180,6 +181,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
{
|
||||
email: 'user@example.org',
|
||||
profileHeader: Factory.build('image'),
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
@ -192,6 +194,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
{
|
||||
email: 'huey@example.org',
|
||||
profileHeader: Factory.build('image'),
|
||||
},
|
||||
),
|
||||
Factory.build(
|
||||
|
||||
@ -18,6 +18,7 @@ const obfuscate = async (resolve, root, args, context, info) => {
|
||||
root.title = 'UNAVAILABLE'
|
||||
root.slug = 'UNAVAILABLE'
|
||||
root.avatar = null
|
||||
root.profileHeader = null
|
||||
root.about = 'UNAVAILABLE'
|
||||
root.name = 'UNAVAILABLE'
|
||||
root.image = null
|
||||
|
||||
@ -41,6 +41,9 @@ beforeAll(async () => {
|
||||
avatar: Factory.build('image', {
|
||||
url: '/some/offensive/avatar.jpg',
|
||||
}),
|
||||
profileHeader: Factory.build('image', {
|
||||
url: '/some/offensive/profileHeader.jpg',
|
||||
}),
|
||||
},
|
||||
),
|
||||
neode.create('Category', {
|
||||
@ -225,6 +228,9 @@ describe('softDeleteMiddleware', () => {
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
profileHeader {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -270,6 +276,10 @@ describe('softDeleteMiddleware', () => {
|
||||
expect(subject.avatar).toEqual({
|
||||
url: expect.stringContaining('/some/offensive/avatar.jpg'),
|
||||
}))
|
||||
it('display profile header', () =>
|
||||
expect(subject.profileHeader).toEqual({
|
||||
url: expect.stringContaining('/some/offensive/profileHeader.jpg'),
|
||||
}))
|
||||
})
|
||||
|
||||
describe('Post', () => {
|
||||
@ -308,6 +318,7 @@ describe('softDeleteMiddleware', () => {
|
||||
it('obfuscates slug', () => expect(subject.slug).toEqual('UNAVAILABLE'))
|
||||
it('obfuscates about', () => expect(subject.about).toEqual('UNAVAILABLE'))
|
||||
it('obfuscates avatar', () => expect(subject.avatar).toEqual(null))
|
||||
it('obfuscates profile header', () => expect(subject.profileHeader).toEqual(null))
|
||||
})
|
||||
|
||||
describe('Post', () => {
|
||||
|
||||
@ -12,6 +12,12 @@ export default {
|
||||
target: 'Image',
|
||||
direction: 'out',
|
||||
},
|
||||
profileHeader: {
|
||||
type: 'relationship',
|
||||
relationship: 'PROFILE_HEADER_IMAGE',
|
||||
target: 'Image',
|
||||
direction: 'out',
|
||||
},
|
||||
deleted: { type: 'boolean', default: false },
|
||||
disabled: { type: 'boolean', default: false },
|
||||
role: { type: 'string', default: 'user' },
|
||||
|
||||
@ -105,7 +105,7 @@ const uploadImageFile = async (upload, uploadCallback) => {
|
||||
const sanitizeRelationshipType = (relationshipType) => {
|
||||
// Cypher query language does not allow to parameterize relationship types
|
||||
// See: https://github.com/neo4j/neo4j/issues/340
|
||||
if (!['HERO_IMAGE', 'AVATAR_IMAGE'].includes(relationshipType)) {
|
||||
if (!['HERO_IMAGE', 'AVATAR_IMAGE', 'PROFILE_HEADER_IMAGE'].includes(relationshipType)) {
|
||||
throw new Error(`Unknown relationship type ${relationshipType}`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,9 @@ const statisticsQuery = gql`
|
||||
}
|
||||
}
|
||||
`
|
||||
beforeAll(() => {
|
||||
beforeAll(async () => {
|
||||
// Clean the database so no artifacts from other test files are interfering.
|
||||
await cleanDatabase()
|
||||
authenticatedUser = undefined
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
|
||||
@ -109,6 +109,9 @@ describe('currentUser', () => {
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
profileHeader {
|
||||
url
|
||||
}
|
||||
email
|
||||
role
|
||||
}
|
||||
@ -142,6 +145,9 @@ describe('currentUser', () => {
|
||||
avatar: Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
}),
|
||||
profileHeader: Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/hellofeverrrr/128.jpg',
|
||||
}),
|
||||
},
|
||||
)
|
||||
const userBearerToken = encode({ id: 'u3' })
|
||||
@ -156,6 +162,9 @@ describe('currentUser', () => {
|
||||
avatar: Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
|
||||
}),
|
||||
profileHeader: Factory.build('image', {
|
||||
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/hellofeverrrr/128.jpg',
|
||||
}),
|
||||
email: 'test@example.org',
|
||||
name: 'Matilde Hermiston',
|
||||
slug: 'matilde-hermiston',
|
||||
|
||||
@ -140,8 +140,9 @@ export default {
|
||||
},
|
||||
UpdateUser: async (_parent, params, context, _resolveInfo) => {
|
||||
const { termsAndConditionsAgreedVersion } = params
|
||||
const { avatar: avatarInput } = params
|
||||
const { avatar: avatarInput, profileHeader: profileHeaderInput } = params
|
||||
delete params.avatar
|
||||
delete params.profileHeader
|
||||
if (termsAndConditionsAgreedVersion) {
|
||||
const regEx = new RegExp(/^[0-9]+\.[0-9]+\.[0-9]+$/g)
|
||||
if (!regEx.test(termsAndConditionsAgreedVersion)) {
|
||||
@ -165,6 +166,9 @@ export default {
|
||||
if (avatarInput) {
|
||||
await mergeImage(user, 'AVATAR_IMAGE', avatarInput, { transaction })
|
||||
}
|
||||
if (profileHeaderInput) {
|
||||
await mergeImage(user, 'PROFILE_HEADER_IMAGE', profileHeaderInput, { transaction })
|
||||
}
|
||||
return user
|
||||
})
|
||||
try {
|
||||
@ -235,6 +239,7 @@ export default {
|
||||
log(deleteUserTransactionResponse)
|
||||
const [user] = deleteUserTransactionResponse.records.map((record) => record.get('user'))
|
||||
await deleteImage(user, 'AVATAR_IMAGE', { transaction })
|
||||
await deleteImage(user, 'PROFILE_HEADER_IMAGE', { transaction })
|
||||
return user
|
||||
})
|
||||
try {
|
||||
@ -291,6 +296,7 @@ export default {
|
||||
},
|
||||
hasOne: {
|
||||
avatar: '-[:AVATAR_IMAGE]->(related:Image)',
|
||||
profileHeader: '-[:PROFILE_HEADER_IMAGE]->(related:Image)',
|
||||
invitedBy: '<-[:INVITED]-(related:User)',
|
||||
location: '-[:IS_IN]->(related:Location)',
|
||||
},
|
||||
|
||||
@ -341,11 +341,17 @@ describe('DeleteUser', () => {
|
||||
beforeEach(async () => {
|
||||
variables = { id: ' u343', resource: [] }
|
||||
|
||||
user = await Factory.build('user', {
|
||||
name: 'My name should be deleted',
|
||||
about: 'along with my about',
|
||||
id: 'u343',
|
||||
})
|
||||
user = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'My name should be deleted',
|
||||
about: 'along with my about',
|
||||
id: 'u343',
|
||||
},
|
||||
{
|
||||
profileHeader: Factory.build('image'),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
describe('authenticated as Admin', () => {
|
||||
@ -496,8 +502,8 @@ describe('DeleteUser', () => {
|
||||
).resolves.toMatchObject(expectedResponse)
|
||||
})
|
||||
|
||||
it('deletes user avatar and post hero images', async () => {
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(22)
|
||||
it('deletes user avatar, profile header and post hero images', async () => {
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(23)
|
||||
await mutate({ mutation: deleteUserMutation, variables })
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(20)
|
||||
})
|
||||
@ -627,11 +633,17 @@ describe('DeleteUser', () => {
|
||||
beforeEach(async () => {
|
||||
variables = { id: 'u343', resource: [] }
|
||||
|
||||
user = await Factory.build('user', {
|
||||
name: 'My name should be deleted',
|
||||
about: 'along with my about',
|
||||
id: 'u343',
|
||||
})
|
||||
user = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
name: 'My name should be deleted',
|
||||
about: 'along with my about',
|
||||
id: 'u343',
|
||||
},
|
||||
{
|
||||
profileHeader: Factory.build('image'),
|
||||
},
|
||||
)
|
||||
await Factory.build(
|
||||
'user',
|
||||
{
|
||||
@ -792,8 +804,8 @@ describe('DeleteUser', () => {
|
||||
).resolves.toMatchObject(expectedResponse)
|
||||
})
|
||||
|
||||
it('deletes user avatar and post hero images', async () => {
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(22)
|
||||
it('deletes user avatar, profile header and post hero images', async () => {
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(23)
|
||||
await mutate({ mutation: deleteUserMutation, variables })
|
||||
await expect(neode.all('Image')).resolves.toHaveLength(20)
|
||||
})
|
||||
|
||||
@ -26,6 +26,7 @@ type User {
|
||||
email: String! @cypher(statement: "MATCH (this)-[:PRIMARY_EMAIL]->(e:EmailAddress) RETURN e.email")
|
||||
slug: String!
|
||||
avatar: Image @relation(name: "AVATAR_IMAGE", direction: "OUT")
|
||||
profileHeader: Image @relation(name: "PROFILE_HEADER_IMAGE", direction: "OUT")
|
||||
deleted: Boolean
|
||||
disabled: Boolean
|
||||
role: UserGroup!
|
||||
@ -192,6 +193,7 @@ type Mutation {
|
||||
email: String
|
||||
slug: String
|
||||
avatar: ImageInput
|
||||
profileHeader: ImageInput
|
||||
locationName: String
|
||||
about: String
|
||||
termsAndConditionsAgreedVersion: String
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user