mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
refactor(backend): types for context + slug (#8486)
Also these changes saw merge conflicts in #8463 so let's get them merged already. Co-authored-by: mahula <lenzmath@posteo.de>
This commit is contained in:
parent
e4ae0dfe50
commit
fac818a3e4
@ -95,6 +95,7 @@
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^22.15.3",
|
||||
"@types/slug": "^5.0.9",
|
||||
"@types/uuid": "~9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
|
||||
@ -12,6 +12,7 @@ import CONFIG from '@config/index'
|
||||
import { CATEGORIES_MIN, CATEGORIES_MAX } from '@constants/categories'
|
||||
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '@constants/groups'
|
||||
import { removeHtmlTags } from '@middleware/helpers/cleanHtml'
|
||||
import type { Context } from '@src/server'
|
||||
|
||||
import Resolver, {
|
||||
removeUndefinedNullValuesFromObject,
|
||||
@ -22,7 +23,7 @@ import { createOrUpdateLocations } from './users/location'
|
||||
|
||||
export default {
|
||||
Query: {
|
||||
Group: async (_object, params, context, _resolveInfo) => {
|
||||
Group: async (_object, params, context: Context, _resolveInfo) => {
|
||||
const { isMember, id, slug, first, offset } = params
|
||||
let pagination = ''
|
||||
const orderBy = 'ORDER BY group.createdAt DESC'
|
||||
@ -75,10 +76,10 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
GroupMembers: async (_object, params, context, _resolveInfo) => {
|
||||
GroupMembers: async (_object, params, context: Context, _resolveInfo) => {
|
||||
const { id: groupId } = params
|
||||
const session = context.driver.session()
|
||||
const readTxResultPromise = session.readTransaction(async (txc) => {
|
||||
@ -96,7 +97,7 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
GroupCount: async (_object, params, context, _resolveInfo) => {
|
||||
@ -134,7 +135,7 @@ export default {
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
CreateGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
CreateGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { categoryIds } = params
|
||||
delete params.categoryIds
|
||||
params.locationName = params.locationName === '' ? null : params.locationName
|
||||
@ -182,7 +183,7 @@ export default {
|
||||
`,
|
||||
{ userId: context.user.id, categoryIds, params },
|
||||
)
|
||||
const [group] = await ownerCreateGroupTransactionResponse.records.map((record) =>
|
||||
const [group] = ownerCreateGroupTransactionResponse.records.map((record) =>
|
||||
record.get('group'),
|
||||
)
|
||||
return group
|
||||
@ -197,10 +198,10 @@ export default {
|
||||
throw new UserInputError('Group with this slug already exists!')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
UpdateGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
UpdateGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { categoryIds } = params
|
||||
delete params.categoryIds
|
||||
const { id: groupId, avatar: avatarInput } = params
|
||||
@ -257,7 +258,7 @@ export default {
|
||||
categoryIds,
|
||||
params,
|
||||
})
|
||||
const [group] = await transactionResponse.records.map((record) => record.get('group'))
|
||||
const [group] = transactionResponse.records.map((record) => record.get('group'))
|
||||
if (avatarInput) {
|
||||
await mergeImage(group, 'AVATAR_IMAGE', avatarInput, { transaction })
|
||||
}
|
||||
@ -273,10 +274,10 @@ export default {
|
||||
throw new UserInputError('Group with this slug already exists!')
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
JoinGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
JoinGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { groupId, userId } = params
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
@ -294,7 +295,7 @@ export default {
|
||||
RETURN member {.*, myRoleInGroup: membership.role}
|
||||
`
|
||||
const transactionResponse = await transaction.run(joinGroupCypher, { groupId, userId })
|
||||
const [member] = await transactionResponse.records.map((record) => record.get('member'))
|
||||
const [member] = transactionResponse.records.map((record) => record.get('member'))
|
||||
return member
|
||||
})
|
||||
try {
|
||||
@ -302,10 +303,10 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
LeaveGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
LeaveGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { groupId, userId } = params
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
@ -313,10 +314,10 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
ChangeGroupMemberRole: async (_parent, params, context, _resolveInfo) => {
|
||||
ChangeGroupMemberRole: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { groupId, userId, roleInGroup } = params
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
@ -353,7 +354,7 @@ export default {
|
||||
userId,
|
||||
roleInGroup,
|
||||
})
|
||||
const [member] = await transactionResponse.records.map((record) => record.get('member'))
|
||||
const [member] = transactionResponse.records.map((record) => record.get('member'))
|
||||
return member
|
||||
})
|
||||
try {
|
||||
@ -361,10 +362,10 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
RemoveUserFromGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
RemoveUserFromGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { groupId, userId } = params
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
@ -372,10 +373,10 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
muteGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
muteGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { groupId } = params
|
||||
const userId = context.user.id
|
||||
const session = context.driver.session()
|
||||
@ -393,7 +394,7 @@ export default {
|
||||
userId,
|
||||
},
|
||||
)
|
||||
const [group] = await transactionResponse.records.map((record) => record.get('group'))
|
||||
const [group] = transactionResponse.records.map((record) => record.get('group'))
|
||||
return group
|
||||
})
|
||||
try {
|
||||
@ -401,10 +402,10 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
unmuteGroup: async (_parent, params, context, _resolveInfo) => {
|
||||
unmuteGroup: async (_parent, params, context: Context, _resolveInfo) => {
|
||||
const { groupId } = params
|
||||
const userId = context.user.id
|
||||
const session = context.driver.session()
|
||||
@ -422,7 +423,7 @@ export default {
|
||||
userId,
|
||||
},
|
||||
)
|
||||
const [group] = await transactionResponse.records.map((record) => record.get('group'))
|
||||
const [group] = transactionResponse.records.map((record) => record.get('group'))
|
||||
return group
|
||||
})
|
||||
try {
|
||||
@ -430,7 +431,7 @@ export default {
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
import type { Context } from '@src/server'
|
||||
|
||||
import uniqueSlug from './slugify/uniqueSlug'
|
||||
|
||||
const isUniqueFor = (context, type) => {
|
||||
return async (slug) => {
|
||||
const isUniqueFor = (context: Context, type: string) => {
|
||||
return async (slug: string) => {
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
const existingSlug = await session.readTransaction((transaction) => {
|
||||
@ -20,26 +20,50 @@ const isUniqueFor = (context, type) => {
|
||||
})
|
||||
return existingSlug.records.length === 0
|
||||
} finally {
|
||||
session.close()
|
||||
await session.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
Mutation: {
|
||||
SignupVerification: async (resolve, root, args, context, info) => {
|
||||
SignupVerification: async (
|
||||
resolve,
|
||||
root,
|
||||
args: { slug: string; name: string },
|
||||
context: Context,
|
||||
info,
|
||||
) => {
|
||||
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'User')))
|
||||
return resolve(root, args, context, info)
|
||||
},
|
||||
CreateGroup: async (resolve, root, args, context, info) => {
|
||||
CreateGroup: async (
|
||||
resolve,
|
||||
root,
|
||||
args: { slug: string; name: string },
|
||||
context: Context,
|
||||
info,
|
||||
) => {
|
||||
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Group')))
|
||||
return resolve(root, args, context, info)
|
||||
},
|
||||
CreatePost: async (resolve, root, args, context, info) => {
|
||||
CreatePost: async (
|
||||
resolve,
|
||||
root,
|
||||
args: { slug: string; title: string },
|
||||
context: Context,
|
||||
info,
|
||||
) => {
|
||||
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
|
||||
return resolve(root, args, context, info)
|
||||
},
|
||||
UpdatePost: async (resolve, root, args, context, info) => {
|
||||
UpdatePost: async (
|
||||
resolve,
|
||||
root,
|
||||
args: { slug: string; title: string },
|
||||
context: Context,
|
||||
info,
|
||||
) => {
|
||||
// TODO: is this absolutely correct? what happens if "args.title" is not defined? may it works accidentally, because "args.title" or "args.slug" is always send?
|
||||
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
|
||||
return resolve(root, args, context, info)
|
||||
|
||||
@ -14,9 +14,11 @@ describe('uniqueSlug', () => {
|
||||
})
|
||||
|
||||
it('slugify null string', async () => {
|
||||
const string = null
|
||||
const nullString = null
|
||||
const isUnique = jest.fn().mockResolvedValue(true)
|
||||
await expect(uniqueSlug(string, isUnique)).resolves.toEqual('anonymous')
|
||||
await expect(uniqueSlug(nullString as unknown as string, isUnique)).resolves.toEqual(
|
||||
'anonymous',
|
||||
)
|
||||
})
|
||||
|
||||
it('Converts umlaut to a two letter equivalent', async () => {
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import slugify from 'slug'
|
||||
|
||||
export default async function uniqueSlug(string, isUnique) {
|
||||
const slug = slugify(string || 'anonymous', {
|
||||
type IsUnique = (slug: string) => Promise<boolean>
|
||||
export default async function uniqueSlug(str: string, isUnique: IsUnique) {
|
||||
const slug = slugify(str || 'anonymous', {
|
||||
lower: true,
|
||||
multicharmap: { Ä: 'AE', ä: 'ae', Ö: 'OE', ö: 'oe', Ü: 'UE', ü: 'ue', ß: 'ss' },
|
||||
})
|
||||
if (await isUnique(slug)) return slug
|
||||
|
||||
let count = 0
|
||||
let uniqueSlug
|
||||
let uniqueSlug: string
|
||||
do {
|
||||
count += 1
|
||||
uniqueSlug = `${slug}-${count}`
|
||||
|
||||
@ -102,3 +102,4 @@ const createServer = (options?) => {
|
||||
}
|
||||
|
||||
export default createServer
|
||||
export type Context = Awaited<ReturnType<ReturnType<typeof getContext>>>
|
||||
|
||||
@ -1533,6 +1533,11 @@
|
||||
"@types/express-serve-static-core" "*"
|
||||
"@types/mime" "*"
|
||||
|
||||
"@types/slug@^5.0.9":
|
||||
version "5.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/slug/-/slug-5.0.9.tgz#e5b213a9d7797d40d362ba85e2a7bbcd4df4ed40"
|
||||
integrity sha512-6Yp8BSplP35Esa/wOG1wLNKiqXevpQTEF/RcL/NV6BBQaMmZh4YlDwCgrrFSoUE4xAGvnKd5c+lkQJmPrBAzfQ==
|
||||
|
||||
"@types/stack-utils@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user