From 44eb9d0bde3173e127e929367cc2a55f717c9cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Thu, 1 Sep 2022 09:31:50 +0200 Subject: [PATCH] Implement 'UpdateGroup' resolver, not working --- backend/src/middleware/excerptMiddleware.js | 1 + .../src/middleware/permissionsMiddleware.js | 3 + backend/src/middleware/sluggifyMiddleware.js | 1 + .../src/middleware/slugifyMiddleware.spec.js | 111 ++++++------------ backend/src/schema/resolvers/groups.js | 86 ++++++++++++-- backend/src/schema/resolvers/posts.js | 10 +- backend/src/schema/types/type/Group.gql | 18 +-- 7 files changed, 134 insertions(+), 96 deletions(-) diff --git a/backend/src/middleware/excerptMiddleware.js b/backend/src/middleware/excerptMiddleware.js index 68eea9a74..597b97714 100644 --- a/backend/src/middleware/excerptMiddleware.js +++ b/backend/src/middleware/excerptMiddleware.js @@ -8,6 +8,7 @@ export default { return resolve(root, args, context, info) }, UpdateGroup: async (resolve, root, args, context, info) => { + console.log('excerptMiddleware - UpdateGroup !!!') args.descriptionExcerpt = trunc(args.description, DESCRIPTION_EXCERPT_HTML_LENGTH).html return resolve(root, args, context, info) }, diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 40f336d2f..f0723e50b 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -55,9 +55,12 @@ const isMySocialMedia = rule({ const isAllowedToChangeGroupSettings = rule({ cache: 'no_cache', })(async (_parent, args, { user, driver }) => { + console.log('isAllowedToChangeGroupSettings !!!') if (!(user && user.id)) return false const ownerId = user.id const { id: groupId } = args + console.log('ownerId: ', ownerId) + console.log('groupId: ', groupId) const session = driver.session() const readTxPromise = session.readTransaction(async (transaction) => { const transactionResponse = await transaction.run( diff --git a/backend/src/middleware/sluggifyMiddleware.js b/backend/src/middleware/sluggifyMiddleware.js index 8fd200e8f..d5f75adb0 100644 --- a/backend/src/middleware/sluggifyMiddleware.js +++ b/backend/src/middleware/sluggifyMiddleware.js @@ -31,6 +31,7 @@ export default { return resolve(root, args, context, info) }, UpdateGroup: async (resolve, root, args, context, info) => { + console.log('sluggifyMiddleware - UpdateGroup !!!') args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Group'))) return resolve(root, args, context, info) }, diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index 4f0401cdc..9baef1fae 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -2,7 +2,8 @@ import { getNeode, getDriver } from '../db/neo4j' import createServer from '../server' import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '../db/factories' -import { createGroupMutation } from '../db/graphql/groups' +import { sleep } from '../helpers/jest.js' +import { createGroupMutation, updateGroupMutation } from '../db/graphql/groups' import { createPostMutation } from '../db/graphql/posts' import { signupVerificationMutation } from '../db/graphql/authentications' @@ -189,101 +190,61 @@ describe('slugifyMiddleware', () => { }) }) - describe.only('UpdateGroup', () => { + describe('UpdateGroup', () => { beforeEach(async () => { variables = { ...variables, - name: 'The Best Group', + name: 'Pre-Existing Group', + slug: 'pre-existing-group', about: 'Some about', description: 'Some description' + descriptionAdditional100, groupType: 'closed', actionRadius: 'national', categoryIds, } + console.log('createGroupMutation: ', createGroupMutation) await mutate({ mutation: createGroupMutation, variables, }) + // Wolle: console.log('sleep !!!') + // await sleep(4 * 1000) }) - describe('if slug not exists', () => { - it('generates a slug based on name', async () => { - await expect( - mutate({ - mutation: createGroupMutation, - variables, - }), - ).resolves.toMatchObject({ - data: { - CreateGroup: { - name: 'The Best Group', - slug: 'the-best-group', - about: 'Some about', - description: 'Some description' + descriptionAdditional100, - groupType: 'closed', - actionRadius: 'national', + describe('if group exists', () => { + describe('if new slug not(!) exists', () => { + it.only('has the new slug', async () => { + console.log('updateGroupMutation: ', updateGroupMutation) + await expect( + mutate({ + mutation: updateGroupMutation, + variables: { + ...variables, + slug: 'my-best-group', + }, + }), + ).resolves.toMatchObject({ + data: { + UpdateGroup: { + name: 'The Best Group', + slug: 'my-best-group', + about: 'Some about', + description: 'Some description' + descriptionAdditional100, + groupType: 'closed', + actionRadius: 'national', + myRole: 'owner', + }, }, - }, + }) }) }) - it('generates a slug based on given slug', async () => { - await expect( - mutate({ - mutation: createGroupMutation, - variables: { - ...variables, - slug: 'the-group', - }, - }), - ).resolves.toMatchObject({ - data: { - CreateGroup: { - slug: 'the-group', - }, - }, - }) - }) - }) - - describe('if slug exists', () => { - beforeEach(async () => { - await mutate({ - mutation: createGroupMutation, - variables: { - ...variables, - name: 'Pre-Existing Group', - slug: 'pre-existing-group', - about: 'As an about', - }, - }) - }) - - it('chooses another slug', async () => { - await expect( - mutate({ - mutation: createGroupMutation, - variables: { - ...variables, - name: 'Pre-Existing Group', - about: 'As an about', - }, - }), - ).resolves.toMatchObject({ - data: { - CreateGroup: { - slug: 'pre-existing-group-1', - }, - }, - }) - }) - - describe('but if the client specifies a slug', () => { - it('rejects CreateGroup', async (done) => { + describe('if new slug exists', () => { + it('rejects UpdateGroup', async (done) => { try { await expect( mutate({ - mutation: createGroupMutation, + mutation: updateGroupMutation, variables: { ...variables, name: 'Pre-Existing Group', @@ -443,6 +404,8 @@ describe('slugifyMiddleware', () => { }) }) + it.todo('UpdatePost') + describe('SignupVerification', () => { beforeEach(() => { variables = { diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js index abaa1716f..312c37e69 100644 --- a/backend/src/schema/resolvers/groups.js +++ b/backend/src/schema/resolvers/groups.js @@ -33,10 +33,10 @@ export default { ` } } - const result = await txc.run(groupCypher, { + const transactionResponse = await txc.run(groupCypher, { userId: context.user.id, }) - return result.records.map((record) => record.get('group')) + return transactionResponse.records.map((record) => record.get('group')) }) try { return await readTxResultPromise @@ -54,10 +54,10 @@ export default { MATCH (user:User)-[membership:MEMBER_OF]->(:Group {id: $groupId}) RETURN user {.*, myRoleInGroup: membership.role} ` - const result = await txc.run(groupMemberCypher, { + const transactionResponse = await txc.run(groupMemberCypher, { groupId, }) - return result.records.map((record) => record.get('user')) + return transactionResponse.records.map((record) => record.get('user')) }) try { return await readTxResultPromise @@ -131,6 +131,72 @@ export default { session.close() } }, + UpdateGroup: async (_parent, params, context, _resolveInfo) => { + console.log('UpdateGroup !!!') + const { categoryIds } = params + const { id: groupId } = params + console.log('categoryIds: ', categoryIds) + console.log('groupId: ', groupId) + delete params.categoryIds + if (CONFIG.CATEGORIES_ACTIVE && (!categoryIds || categoryIds.length < CATEGORIES_MIN)) { + throw new UserInputError('Too view categories!') + } + if (CONFIG.CATEGORIES_ACTIVE && categoryIds && categoryIds.length > CATEGORIES_MAX) { + throw new UserInputError('Too many categories!') + } + if ( + params.description === undefined || + params.description === null || + removeHtmlTags(params.description).length < DESCRIPTION_WITHOUT_HTML_LENGTH_MIN + ) { + throw new UserInputError('Description too short!') + } + const session = context.driver.session() + const writeTxResultPromise = session.writeTransaction(async (transaction) => { + let updateGroupCypher = ` + MATCH (group:Group {id: $groupId}) + SET group += $params + SET group.updatedAt = toString(datetime()) + WITH group + ` + if (CONFIG.CATEGORIES_ACTIVE && categoryIds && categoryIds.length) { + const cypherDeletePreviousRelations = ` + MATCH (group:Group {id: $groupId})-[previousRelations:CATEGORIZED]->(category:Category) + DELETE previousRelations + RETURN group, category + ` + await session.writeTransaction((transaction) => { + return transaction.run(cypherDeletePreviousRelations, { groupId }) + }) + updateGroupCypher += ` + UNWIND $categoryIds AS categoryId + MATCH (category:Category {id: categoryId}) + MERGE (group)-[:CATEGORIZED]->(category) + WITH group + OPTIONAL MATCH (:User {id: $userId})-[membership:MEMBER_OF]->(group) + WITH group, membership # Wolle: is not needed in my eyes + ` + } + updateGroupCypher += `RETURN group {.*, myRole: membership.role}` + const transactionResponse = await transaction.run(updateGroupCypher, { + groupId, + userId: context.user.id, + categoryIds, + params, + }) + const [group] = await transactionResponse.records.map((record) => record.get('group')) + return group + }) + try { + return await writeTxResultPromise + } catch (error) { + if (error.code === 'Neo.ClientError.Schema.ConstraintValidationFailed') + throw new UserInputError('Group with this slug already exists!') + throw new Error(error) + } finally { + session.close() + } + }, JoinGroup: async (_parent, params, context, _resolveInfo) => { const { groupId, userId } = params const session = context.driver.session() @@ -148,8 +214,8 @@ export default { END RETURN member {.*, myRoleInGroup: membership.role} ` - const result = await transaction.run(joinGroupCypher, { groupId, userId }) - const [member] = await result.records.map((record) => record.get('member')) + const transactionResponse = await transaction.run(joinGroupCypher, { groupId, userId }) + const [member] = await transactionResponse.records.map((record) => record.get('member')) return member }) try { @@ -176,8 +242,12 @@ export default { membership.role = $roleInGroup RETURN member {.*, myRoleInGroup: membership.role} ` - const result = await transaction.run(joinGroupCypher, { groupId, userId, roleInGroup }) - const [member] = await result.records.map((record) => record.get('member')) + const transactionResponse = await transaction.run(joinGroupCypher, { + groupId, + userId, + roleInGroup, + }) + const [member] = await transactionResponse.records.map((record) => record.get('member')) return member }) try { diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index d9a04732c..97230715f 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -131,11 +131,11 @@ export default { delete params.image const session = context.driver.session() let updatePostCypher = ` - MATCH (post:Post {id: $params.id}) - SET post += $params - SET post.updatedAt = toString(datetime()) - WITH post - ` + MATCH (post:Post {id: $params.id}) + SET post += $params + SET post.updatedAt = toString(datetime()) + WITH post + ` if (CONFIG.CATEGORIES_ACTIVE && categoryIds && categoryIds.length) { const cypherDeletePreviousRelations = ` diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql index e254e5086..aa28eccd1 100644 --- a/backend/src/schema/types/type/Group.gql +++ b/backend/src/schema/types/type/Group.gql @@ -102,15 +102,15 @@ type Mutation { locationName: String ): Group - # UpdateGroup( - # id: ID! - # name: String - # slug: String - # avatar: ImageInput - # locationName: String - # about: String - # description: String - # ): Group + UpdateGroup( + id: ID! + name: String + slug: String + avatar: ImageInput + locationName: String + about: String + description: String + ): Group # DeleteGroup(id: ID!): Group