chore: update biome configuration and enhance error handling in schema files

- Enabled useIgnoreFile in biome.json for better file management.
- Updated various correctness and style rules in biome.json to enforce stricter coding standards.
- Added new biome lint command in package.json for improved code quality checks.
- Refactored error handling in multiple schema files to use consistent error throwing patterns, enhancing readability and maintainability.
- Improved user authentication checks across various schemas to ensure proper access control.
This commit is contained in:
2024-12-08 21:01:26 +07:00
parent 10e20092ab
commit 45dca51990
17 changed files with 430 additions and 159 deletions

View File

@@ -3,7 +3,7 @@
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": false,
@@ -30,42 +30,42 @@
"complexity": {
"noUselessThisAlias": "error",
"noUselessTypeConstraint": "error",
"useArrowFunction": "off"
"useArrowFunction": "error"
},
"correctness": {
"noConstAssign": "off",
"noGlobalObjectCalls": "off",
"noInvalidBuiltinInstantiation": "off",
"noInvalidConstructorSuper": "off",
"noNewSymbol": "off",
"noSetterReturn": "off",
"noConstAssign": "error",
"noGlobalObjectCalls": "error",
"noInvalidBuiltinInstantiation": "error",
"noInvalidConstructorSuper": "error",
"noNewSymbol": "error",
"noSetterReturn": "error",
"noUndeclaredVariables": "off",
"noUnreachable": "off",
"noUnreachableSuper": "off",
"noUnreachable": "error",
"noUnreachableSuper": "error",
"noUnusedVariables": "error",
"useArrayLiterals": "off"
"useArrayLiterals": "error"
},
"style": {
"noArguments": "error",
"noNamespace": "error",
"noVar": "error",
"useAsConstAssertion": "error",
"useBlockStatements": "off",
"useBlockStatements": "error",
"useConst": "error"
},
"suspicious": {
"noDuplicateClassMembers": "off",
"noDuplicateObjectKeys": "off",
"noDuplicateParameters": "off",
"noDuplicateClassMembers": "error",
"noDuplicateObjectKeys": "error",
"noDuplicateParameters": "error",
"noExplicitAny": "error",
"noExtraNonNullAssertion": "error",
"noFunctionAssign": "off",
"noImportAssign": "off",
"noFunctionAssign": "error",
"noImportAssign": "error",
"noMisleadingInstantiator": "error",
"noRedeclare": "off",
"noRedeclare": "error",
"noUnsafeDeclarationMerging": "error",
"noUnsafeNegation": "off",
"useGetterReturn": "off",
"noUnsafeNegation": "error",
"useGetterReturn": "error",
"useNamespaceKeyword": "error"
}
},
@@ -80,7 +80,7 @@
"arrowParentheses": "always",
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto",
"attributePosition": "multiline",
"bracketSpacing": true
},
"parser": {

View File

@@ -19,8 +19,10 @@
"prisma:seed": "npx prisma db seed --schema=./epess-database/prisma/schema.prisma",
"prisma:format": "npx prisma format --schema=./epess-database/prisma/schema.prisma",
"prisma:studio": "dotenv -e .env -- npx prisma studio --schema=./epess-database/prisma/schema.prisma",
"biome:check": "biome check --write --unsafe",
"biome:check": "biome check --write",
"biome:format": "biome format --write",
"biome:lint": "biome lint",
"biome:check:unsafe": "biome check --write --unsafe",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",

View File

@@ -171,9 +171,15 @@ export class AnalyticSchema extends PothosSchema {
type: this.customerAnalytic(),
description: 'Retrieve a single customer analytic.',
resolve: async (_parent, _args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.http.me.role !== Role.CUSTOMER) throw new Error('Only customers can access this data')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
if (ctx.http.me.role !== Role.CUSTOMER) {
throw new Error('Only customers can access this data')
}
// calculate analytic
const activeServiceCount = await this.prisma.order.count({
where: {
@@ -217,9 +223,15 @@ export class AnalyticSchema extends PothosSchema {
type: this.mentorAnalytic(),
description: 'Retrieve a single mentor analytic.',
resolve: async (_parent, _args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.http.me.role !== Role.CENTER_MENTOR) throw new Error('Only center mentors can access this data')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
if (ctx.http.me.role !== Role.CENTER_MENTOR) {
throw new Error('Only center mentors can access this data')
}
// calculate analytic
return {
userId: ctx.http.me.id,
@@ -230,16 +242,24 @@ export class AnalyticSchema extends PothosSchema {
type: this.centerAnalytic(),
description: 'Retrieve a single center analytic.',
resolve: async (_parent, _args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.http.me.role !== Role.CENTER_OWNER) throw new Error('Only center owners can access this data')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
if (ctx.http.me.role !== Role.CENTER_OWNER) {
throw new Error('Only center owners can access this data')
}
// get center by owner id
const center = await this.prisma.center.findUnique({
where: {
centerOwnerId: ctx.http.me.id,
},
})
if (!center) throw new Error('Center not found')
if (!center) {
throw new Error('Center not found')
}
// calculate analytic
// active mentor include center owner
@@ -277,7 +297,9 @@ export class AnalyticSchema extends PothosSchema {
const service = await this.prisma.service.findUnique({
where: { id: order.serviceId },
})
if (!service) continue
if (!service) {
continue
}
const commission = service.commission
const actualRevenue = (order.total || 0) - (order.total || 0) * commission
revenue += actualRevenue
@@ -318,10 +340,15 @@ export class AnalyticSchema extends PothosSchema {
},
description: 'Retrieve a single platform analytic.',
resolve: async (_parent, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.http.me.role !== Role.ADMIN && ctx.http.me.role !== Role.MODERATOR)
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
if (ctx.http.me.role !== Role.ADMIN && ctx.http.me.role !== Role.MODERATOR) {
throw new Error('Only admins and moderators can access this data')
}
// calculate analytic for services sorted by args.serviceSortBy and args.timeframes
const topServices = await this.prisma.service.findMany({
where: {
@@ -428,7 +455,9 @@ export class AnalyticSchema extends PothosSchema {
const service = await this.prisma.service.findUnique({
where: { id: order.serviceId },
})
if (!service) continue
if (!service) {
continue
}
const commission = service.commission
const actualRevenue = (order.total || 0) - (order.total || 0) * commission
revenue += actualRevenue

View File

@@ -73,14 +73,20 @@ export class CollaborationSessionSchema extends PothosSchema {
},
description: 'Retrieve a single collaboration session by its unique identifier.',
resolve: async (_query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Cannot get your info')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Cannot get your info')
}
const scheduleDate = await this.prisma.scheduleDate.findUnique({
where: {
id: args.scheduleDateId,
},
})
if (!scheduleDate) throw new Error('Schedule date not found')
if (!scheduleDate) {
throw new Error('Schedule date not found')
}
let collaborationSession: CollaborationSession | null = null
collaborationSession = await this.prisma.collaborationSession.findUnique({
where: {
@@ -90,7 +96,9 @@ export class CollaborationSessionSchema extends PothosSchema {
/* ---------- use case 1 : customer get collaboration session by id --------- */
if (ctx.http.me?.role === Role.CUSTOMER && collaborationSession) {
// check if user is participant
if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id)) throw new Error('User not allowed')
if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id)) {
throw new Error('User not allowed')
}
// update schedule date status
await this.prisma.scheduleDate.update({
where: {
@@ -104,20 +112,30 @@ export class CollaborationSessionSchema extends PothosSchema {
}
/* ---------- use case 2 : center mentor get collaboration session by schedule date id --------- */
if (ctx.http.me.role !== Role.CENTER_MENTOR && ctx.http.me.role !== Role.CENTER_OWNER) {
if (!collaborationSession) throw new Error('Mentor does not created collaboration session yet')
if (!collaborationSession) {
throw new Error('Mentor does not created collaboration session yet')
}
throw new Error('User not allowed')
}
// check if user is participant
if (!scheduleDate.participantIds.includes(ctx.http.me.id)) throw new Error('User not allowed')
if (!scheduleDate.participantIds.includes(ctx.http.me.id)) {
throw new Error('User not allowed')
}
// check if order is exist in schedule date
if (!scheduleDate.orderId) throw new Error('Order not found')
if (!scheduleDate.orderId) {
throw new Error('Order not found')
}
const order = await this.prisma.order.findUnique({
where: {
id: scheduleDate.orderId,
},
})
if (!order) throw new Error('Order not found')
if (!order.chatRoomId) throw new Error('Order chat room not found')
if (!order) {
throw new Error('Order not found')
}
if (!order.chatRoomId) {
throw new Error('Order chat room not found')
}
// only in time before 10 minutes from start time or less and not after end time can create new collaboration session
const now = DateTimeUtils.now()
const startTime = DateTimeUtils.fromDate(scheduleDate.start)
@@ -135,7 +153,9 @@ export class CollaborationSessionSchema extends PothosSchema {
id: order.chatRoomId,
},
})
if (!chatRoom) throw new Error('Chat room not found')
if (!chatRoom) {
throw new Error('Chat room not found')
}
// create new one
Logger.log(`chatRoom: ${chatRoom.id}`)
const newCollaborationSession = await this.prisma.collaborationSession.create({
@@ -198,21 +218,29 @@ export class CollaborationSessionSchema extends PothosSchema {
liveKitToken: t.field({
type: 'String',
resolve: async (_, _args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http?.me?.id) throw new Error('User not found')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http?.me?.id) {
throw new Error('User not found')
}
// check if participantId is in meetingRoomCollaborators
const meetingRoomCollaborator = await this.prisma.meetingRoomCollaborator.findFirst({
where: {
userId: ctx.http.me.id,
},
})
if (!meetingRoomCollaborator) throw new Error('Meeting room collaborator not found')
if (!meetingRoomCollaborator) {
throw new Error('Meeting room collaborator not found')
}
const meetingRoom = await this.prisma.meetingRoom.findUnique({
where: {
id: meetingRoomCollaborator.meetingRoomId,
},
})
if (!meetingRoom) throw new Error('Meeting room not found')
if (!meetingRoom) {
throw new Error('Meeting room not found')
}
const token = await this.liveKitService.createToken(ctx.http.me, meetingRoom.id)
return token
},
@@ -235,8 +263,12 @@ export class CollaborationSessionSchema extends PothosSchema {
},
description: 'Update the active document ID for a collaboration session.',
resolve: async (_query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Cannot get your info')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Cannot get your info')
}
// check permission
const collaborationSession = await this.prisma.collaborationSession.findUnique({
where: {
@@ -246,9 +278,12 @@ export class CollaborationSessionSchema extends PothosSchema {
scheduleDate: true,
},
})
if (!collaborationSession) throw new Error('Collaboration session not found')
if (!collaborationSession.scheduleDate.participantIds.includes(ctx.http.me.id))
if (!collaborationSession) {
throw new Error('Collaboration session not found')
}
if (!collaborationSession.scheduleDate.participantIds.includes(ctx.http.me.id)) {
throw new Error('User not allowed')
}
const updatedCollaborationSession = await this.prisma.collaborationSession.update({
where: {
id: args.collaborationSessionId,
@@ -275,14 +310,20 @@ export class CollaborationSessionSchema extends PothosSchema {
}),
},
subscribe: async (_parent, args, ctx) => {
if (!ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.websocket.me) throw new Error('Cannot get your info')
if (!ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.websocket.me) {
throw new Error('Cannot get your info')
}
const collaborationSession = await this.prisma.collaborationSession.findUnique({
where: {
id: args.collaborationSessionId,
},
})
if (!collaborationSession) throw new Error('Collaboration session not found')
if (!collaborationSession) {
throw new Error('Collaboration session not found')
}
return ctx.websocket.pubSub.asyncIterableIterator(`collaborationSessionUpdated:${collaborationSession.id}`)
},
resolve: async (payload: CollaborationSession) => payload,

View File

@@ -94,8 +94,12 @@ export class DocumentSchema extends PothosSchema {
type: [this.document()],
args: this.builder.generator.findManyArgs('Document'),
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http?.me?.id) throw new Error('User not found')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http?.me?.id) {
throw new Error('User not found')
}
return await this.prisma.document.findMany({
...query,
orderBy: args.orderBy ?? undefined,
@@ -133,9 +137,13 @@ export class DocumentSchema extends PothosSchema {
type: this.document(),
args: {},
resolve: async (query, _args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
const userId = ctx.http?.me?.id
if (!userId) throw new Error('User not found')
if (!userId) {
throw new Error('User not found')
}
// const fileUrl = await this.minio.getFileUrl('document', 'document', 'document')
// if (!fileUrl) throw new Error('File not found')
const document = await this.prisma.document.create({
@@ -156,10 +164,18 @@ export class DocumentSchema extends PothosSchema {
pageIndex: t.arg({ type: 'Int', required: true }),
},
resolve: async (_, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http?.me?.id) throw new Error('User not found')
if (!args.documentId) throw new Error('Document id not found')
if (args.pageIndex === undefined || args.pageIndex === null) throw new Error('Page index not found')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http?.me?.id) {
throw new Error('User not found')
}
if (!args.documentId) {
throw new Error('Document id not found')
}
if (args.pageIndex === undefined || args.pageIndex === null) {
throw new Error('Page index not found')
}
let delta = null
try {
delta = await this.minio.getDocumentPage(args.documentId, args.pageIndex)
@@ -197,9 +213,13 @@ export class DocumentSchema extends PothosSchema {
}),
},
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
const userId = ctx.http?.me?.id
if (!userId) throw new Error('Unauthorized')
if (!userId) {
throw new Error('Unauthorized')
}
return await this.prisma.document.create({
...query,
data: {
@@ -225,12 +245,16 @@ export class DocumentSchema extends PothosSchema {
}),
},
resolve: async (_, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
const {
http: { pubSub },
} = ctx
const senderId = ctx.http?.me?.id
if (!senderId) throw new Error('User not found')
if (!senderId) {
throw new Error('User not found')
}
pubSub.publish(`${DocumentEvent.CHANGED}.${args.data.documentId}`, {
...args.data,
senderId,
@@ -245,14 +269,24 @@ export class DocumentSchema extends PothosSchema {
data: t.arg({ type: this.documentDeltaInput(), required: true }),
},
resolve: async (_, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
const senderId = ctx.http?.me?.id
if (!args.data.documentId) throw new Error('Document id not found')
if (!senderId) throw new Error('User not found')
if (args.data.pageIndex === undefined || args.data.pageIndex === null) throw new Error('Page index not found')
if (!args.data.documentId) {
throw new Error('Document id not found')
}
if (!senderId) {
throw new Error('User not found')
}
if (args.data.pageIndex === undefined || args.data.pageIndex === null) {
throw new Error('Page index not found')
}
// save delta to minio
const delta = args.data.delta
if (!delta) throw new Error('Delta not found')
if (!delta) {
throw new Error('Delta not found')
}
await this.minio.upsertDocumentPage(args.data.documentId, args.data.pageIndex, delta)
const totalPage = await this.minio.countDocumentPages(args.data.documentId)
return {
@@ -283,8 +317,12 @@ export class DocumentSchema extends PothosSchema {
}),
},
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http?.me?.id) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http?.me?.id) {
throw new Error('Unauthorized')
}
// check if user is owner or collaborator
const document = await this.prisma.document.findUnique({
where: { id: args.documentId },
@@ -292,7 +330,9 @@ export class DocumentSchema extends PothosSchema {
collaborators: true,
},
})
if (!document) throw new Error('Document not found')
if (!document) {
throw new Error('Document not found')
}
if (
!document.isPublic &&
!document.collaborators.some((c) => c.userId === ctx.http?.me?.id && c.writable) &&
@@ -316,13 +356,19 @@ export class DocumentSchema extends PothosSchema {
writable: t.arg({ type: 'Boolean', required: true }),
},
resolve: async (_, __, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
// check if ctx user is owner of document
const document = await this.prisma.document.findUnique({
where: { id: args.documentId },
})
if (!document) throw new Error('Document not found')
if (document.ownerId !== ctx.http?.me?.id) throw new Error('User is not owner of document')
if (!document) {
throw new Error('Document not found')
}
if (document.ownerId !== ctx.http?.me?.id) {
throw new Error('User is not owner of document')
}
return await this.prisma.documentCollaborator.create({
data: {
documentId: args.documentId,
@@ -340,13 +386,19 @@ export class DocumentSchema extends PothosSchema {
userId: t.arg({ type: 'String', required: true }),
},
resolve: async (_, __, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
// check if ctx user is owner of document
const document = await this.prisma.document.findUnique({
where: { id: args.documentId },
})
if (!document) throw new Error('Document not found')
if (document.ownerId !== ctx.http?.me?.id) throw new Error('User is not owner of document')
if (!document) {
throw new Error('Document not found')
}
if (document.ownerId !== ctx.http?.me?.id) {
throw new Error('User is not owner of document')
}
return await this.prisma.documentCollaborator.delete({
where: { documentId_userId: { documentId: args.documentId, userId: args.userId } },
})
@@ -361,13 +413,19 @@ export class DocumentSchema extends PothosSchema {
writable: t.arg({ type: 'Boolean', required: true }),
},
resolve: async (_, __, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
// check if ctx user is owner of document
const document = await this.prisma.document.findUnique({
where: { id: args.documentId },
})
if (!document) throw new Error('Document not found')
if (document.ownerId !== ctx.http?.me?.id) throw new Error('User is not owner of document')
if (!document) {
throw new Error('Document not found')
}
if (document.ownerId !== ctx.http?.me?.id) {
throw new Error('User is not owner of document')
}
return await this.prisma.documentCollaborator.update({
where: { documentId_userId: { documentId: args.documentId, userId: args.userId } },
data: { readable: args.readable, writable: args.writable },
@@ -386,7 +444,9 @@ export class DocumentSchema extends PothosSchema {
}),
},
subscribe: async (_, args, ctx: SchemaContext) => {
if (!ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.isSubscription) {
throw new Error('Not allowed')
}
const {
websocket: { pubSub },
} = ctx
@@ -398,14 +458,17 @@ export class DocumentSchema extends PothosSchema {
collaborators: true,
},
})
if (!document) throw new Error('Document not found')
if (!document) {
throw new Error('Document not found')
}
if (!document.isPublic) {
if (
document.ownerId !== ctx.websocket?.me?.id &&
!document.collaborators.some((c) => c.userId === ctx.websocket?.me?.id && c.writable && c.readable)
)
) {
throw new Error('User is not owner or collaborator of document')
}
}
return pubSub.asyncIterableIterator([
`${DocumentEvent.CHANGED}.${documentId}`,
`${DocumentEvent.DELETED}.${documentId}`,
@@ -416,7 +479,9 @@ export class DocumentSchema extends PothosSchema {
]) as unknown as AsyncIterable<DocumentDelta>
},
resolve: async (payload: DocumentDelta, _args, ctx: SchemaContext) => {
if (!ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!payload.requestSync) {
// using randomize sync mechanism to avoid performance issue
const random = Math.random()

View File

@@ -76,19 +76,25 @@ export class MeetingRoomSchema extends PothosSchema {
}),
},
resolve: async (_query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
const collaborationSession = await this.prisma.collaborationSession.findUnique({
where: {
scheduleDateId: args.scheduleDateId,
},
})
if (!collaborationSession) throw new Error('Collaboration session not found')
if (!collaborationSession) {
throw new Error('Collaboration session not found')
}
const meetingRoom = await this.prisma.meetingRoom.findUnique({
where: {
collaborationSessionId: collaborationSession.id,
},
})
if (meetingRoom) return meetingRoom
if (meetingRoom) {
return meetingRoom
}
return await this.prisma.meetingRoom.create({
data: {
collaborationSessionId: collaborationSession.id,
@@ -106,19 +112,28 @@ export class MeetingRoomSchema extends PothosSchema {
}),
},
resolve: async (_, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
const meetingRoom = await this.prisma.meetingRoom.findUnique({
where: { collaborationSessionId: args.collaborationSessionId },
})
if (!meetingRoom) throw new Error('Meeting room not found')
if (!meetingRoom) {
throw new Error('Meeting room not found')
}
// check if user is collaborator of collaboration session
const collaborationSession = await this.prisma.collaborationSession.findUnique({
where: { id: meetingRoom.collaborationSessionId },
})
if (!collaborationSession) throw new Error('Collaboration session not found')
if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id))
if (!collaborationSession) {
throw new Error('Collaboration session not found')
}
if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id)) {
throw new Error('User is not collaborator')
}
// create new token
const token = await this.livekitService.createToken(ctx.http.me, meetingRoom.id)
return {
@@ -144,8 +159,12 @@ export class MeetingRoomSchema extends PothosSchema {
}),
},
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
return await this.prisma.meetingRoom.create({
...query,
data: args.input,
@@ -166,8 +185,12 @@ export class MeetingRoomSchema extends PothosSchema {
}),
},
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
return await this.prisma.meetingRoom.update({
...query,
where: {

View File

@@ -194,7 +194,9 @@ export class MessageSchema extends PothosSchema {
}),
},
subscribe: (_, args, ctx: SchemaContext) => {
if (!ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.isSubscription) {
throw new Error('Not allowed')
}
const {
websocket: { pubSub },
} = ctx

View File

@@ -117,8 +117,12 @@ export class OrderSchema extends PothosSchema {
description: 'Retrieve a list of completed orders',
args: this.builder.generator.findManyArgs('Order'),
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Orders cannot be retrieved in subscription context')
if (!ctx.http.me) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Orders cannot be retrieved in subscription context')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
// return orders where user is the one who made the order and status is PAID and schedule.dates is in the past
return await this.prisma.order.findMany({
...query,

View File

@@ -65,8 +65,12 @@ export class PersonalMilestoneSchema extends PothosSchema {
args: this.builder.generator.findUniqueArgs('PersonalMilestone'),
description: 'Retrieve a single personal milestone by its unique identifier.',
resolve: async (_query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Cannot get your info')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Cannot get your info')
}
return this.prisma.personalMilestone.findUnique({
where: args.where,
})
@@ -77,8 +81,12 @@ export class PersonalMilestoneSchema extends PothosSchema {
args: this.builder.generator.findManyArgs('PersonalMilestone'),
description: 'Retrieve multiple personal milestones.',
resolve: async (_query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http.me) throw new Error('Cannot get your info')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http.me) {
throw new Error('Cannot get your info')
}
return this.prisma.personalMilestone.findMany({
where: args.filter ?? undefined,
orderBy: args.orderBy ?? undefined,

View File

@@ -135,8 +135,12 @@ export class QuizSchema extends PothosSchema {
type: this.quiz(),
args: this.builder.generator.findUniqueArgs('Quiz'),
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Subscription is not allowed')
if (!ctx.http.me) throw new Error('User is not authenticated')
if (ctx.isSubscription) {
throw new Error('Subscription is not allowed')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated')
}
return await this.prisma.quiz.findUnique({ ...query, where: { id: args.where.id } })
},
}),
@@ -144,8 +148,12 @@ export class QuizSchema extends PothosSchema {
type: [this.quiz()],
args: this.builder.generator.findManyArgs('Quiz'),
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Subscription is not allowed')
if (!ctx.http.me) throw new Error('User is not authenticated')
if (ctx.isSubscription) {
throw new Error('Subscription is not allowed')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated')
}
return await this.prisma.quiz.findMany({
...query,
where: args.filter ?? undefined,
@@ -167,9 +175,15 @@ export class QuizSchema extends PothosSchema {
}),
},
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Subscription is not allowed')
if (!ctx.http.me) throw new Error('User is not authenticated')
if (!args.data) throw new Error('Data is required')
if (ctx.isSubscription) {
throw new Error('Subscription is not allowed')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated')
}
if (!args.data) {
throw new Error('Data is required')
}
return await this.prisma.quiz.create({
...query,
@@ -193,8 +207,12 @@ export class QuizSchema extends PothosSchema {
}),
},
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Subscription is not allowed')
if (!ctx.http.me) throw new Error('User is not authenticated')
if (ctx.isSubscription) {
throw new Error('Subscription is not allowed')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated')
}
return await this.prisma.quiz.update({
...query,
where: args.where,
@@ -218,15 +236,25 @@ export class QuizSchema extends PothosSchema {
}),
},
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Subscription is not allowed')
if (!ctx.http.me) throw new Error('User is not authenticated')
if (!args.data) throw new Error('Data is required')
if (!args.data.quiz?.connect?.id) throw new Error('Quiz ID is required')
if (ctx.isSubscription) {
throw new Error('Subscription is not allowed')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated')
}
if (!args.data) {
throw new Error('Data is required')
}
if (!args.data.quiz?.connect?.id) {
throw new Error('Quiz ID is required')
}
// query the quiz to get the questions
const quiz = await this.prisma.quiz.findUnique({
where: { id: args.data.quiz.connect.id },
})
if (!quiz) throw new Error('Quiz not found')
if (!quiz) {
throw new Error('Quiz not found')
}
return await this.prisma.quizAttempt.create({
...query,
data: {

View File

@@ -156,14 +156,21 @@ export class RefundTicketSchema extends PothosSchema {
const diffTime = Math.abs(now.diff(orderDate).toMillis())
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
let refundAmount = 0
if (diffDays < 1) refundAmount = order.total
else if (diffDays < 3) refundAmount = order.total * 0.5
if (refundAmount === 0) throw new Error('Cannot refund after 3 days')
if (diffDays < 1) {
refundAmount = order.total
} else if (diffDays < 3) {
refundAmount = order.total * 0.5
}
if (refundAmount === 0) {
throw new Error('Cannot refund after 3 days')
}
// create refund ticket
// get bank name from bank bin from banks.json
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
const bank = banks.data.find((bank: any) => bank.bin === ctx.http.me?.bankBin)
if (!bank) throw new Error('Bank not found')
if (!bank) {
throw new Error('Bank not found')
}
const refundTicket = await this.prisma.refundTicket.create({
data: {
orderId: order.id,

View File

@@ -118,8 +118,12 @@ export class ServiceSchema extends PothosSchema {
description: 'Whether the user has already provided feedback for the service.',
nullable: true,
resolve: async (service, _args, ctx) => {
if (ctx.isSubscription) return null
if (!ctx.http.me) return false
if (ctx.isSubscription) {
return null
}
if (!ctx.http.me) {
return false
}
const serviceFeedbacks = await this.prisma.serviceFeedback.findMany({
where: {
serviceId: service.id,

View File

@@ -90,10 +90,16 @@ export class ServiceFeedbackSchema extends PothosSchema {
},
description: 'Create a new service feedback.',
resolve: async (_, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http?.me) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http?.me) {
throw new Error('Unauthorized')
}
// allow only when user is CUSTOMER and order is completed
if (ctx.http?.me?.role !== Role.CUSTOMER) throw new Error('Unauthorized')
if (ctx.http?.me?.role !== Role.CUSTOMER) {
throw new Error('Unauthorized')
}
Logger.log(`args: ${JSON.stringify(args)}`)
const order = await this.prisma.order.findFirst({
where: {
@@ -109,13 +115,23 @@ export class ServiceFeedbackSchema extends PothosSchema {
},
},
})
if (!order) throw new Error('Order not found')
if (order.userId !== ctx.http?.me?.id) throw new Error('Unauthorized')
if (order.status !== OrderStatus.PAID) throw new Error('Order not completed')
if (!order) {
throw new Error('Order not found')
}
if (order.userId !== ctx.http?.me?.id) {
throw new Error('Unauthorized')
}
if (order.status !== OrderStatus.PAID) {
throw new Error('Order not completed')
}
// validate rating
if (args.rating < 0 || args.rating > 5) throw new Error('Invalid rating')
if (args.rating < 0 || args.rating > 5) {
throw new Error('Invalid rating')
}
// validate comments
if (args.comments && args.comments.length > 1024) throw new Error('Comments too long')
if (args.comments && args.comments.length > 1024) {
throw new Error('Comments too long')
}
return await this.prisma.serviceFeedback.create({
data: {
userId: ctx.http?.me?.id,

View File

@@ -185,9 +185,13 @@ export class UserSchema extends PothosSchema {
take: t.arg({ type: 'Int', required: false }),
},
resolve: async (_parent, args, ctx) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
const me = ctx.http.me
if (!me) throw new Error('User not found')
if (!me) {
throw new Error('User not found')
}
// get chat rooms that the user is a part of
const chatRooms = await this.prisma.chatRoom.findMany({
@@ -212,7 +216,9 @@ export class UserSchema extends PothosSchema {
},
})
if (!lastMessage) return null
if (!lastMessage) {
return null
}
const sender = lastMessage.senderId
? await this.prisma.user.findUnique({
@@ -257,7 +263,9 @@ export class UserSchema extends PothosSchema {
...query,
where: args.where,
})
if (!user) throw new Error('User not found')
if (!user) {
throw new Error('User not found')
}
return user
},
}),
@@ -540,7 +548,9 @@ export class UserSchema extends PothosSchema {
userScopedMessage: t.field({
type: this.messageSchema.message(),
subscribe: async (_, _args, ctx: SchemaContext) => {
if (!ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.isSubscription) {
throw new Error('Not allowed')
}
const {
websocket: { pubSub },
} = ctx

View File

@@ -134,15 +134,25 @@ export class WorkshopSchema extends PothosSchema {
},
description: 'Create a new workshop.',
resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Workshops cannot be created in subscription context')
if (!ctx.http.me) throw new Error('User is not authenticated to create a workshop')
if (ctx.http.me.role !== Role.CENTER_OWNER) throw new Error('Only center owners can create workshops')
if (!args.input.service.connect) throw new Error('Service is required to create a workshop')
if (ctx.isSubscription) {
throw new Error('Workshops cannot be created in subscription context')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated to create a workshop')
}
if (ctx.http.me.role !== Role.CENTER_OWNER) {
throw new Error('Only center owners can create workshops')
}
if (!args.input.service.connect) {
throw new Error('Service is required to create a workshop')
}
// check if service is active
const service = await this.prisma.service.findUnique({
where: { id: args.input.service.connect.id },
})
if (!service || !service.isActive) throw new Error('Service is not active')
if (!service || !service.isActive) {
throw new Error('Service is not active')
}
const workshop = await this.prisma.workshop.create({
...query,

View File

@@ -68,14 +68,20 @@ export class WorkshopMeetingRoomSchema extends PothosSchema {
}),
},
resolve: async (_, args, ctx) => {
if (ctx.isSubscription) throw new Error('Not allowed')
if (!ctx.http?.me) throw new Error('Unauthorized')
if (ctx.isSubscription) {
throw new Error('Not allowed')
}
if (!ctx.http?.me) {
throw new Error('Unauthorized')
}
const meetingRoom = await this.prisma.workshopMeetingRoom.findUnique({
where: {
workshopId: args.workshopId,
},
})
if (!meetingRoom) throw new Error('Meeting room not found')
if (!meetingRoom) {
throw new Error('Meeting room not found')
}
const serverUrl = this.livekitService.getServerUrl()
return {
id: meetingRoom.id,

View File

@@ -59,7 +59,9 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
args: this.builder.generator.findManyArgs('WorkshopSubscription'),
description: 'Retrieve a list of workshop subscriptions with optional filtering, ordering, and pagination.',
resolve: async (query, _root, args, ctx) => {
if (ctx.isSubscription) throw new Error('Workshops cannot be retrieved in subscription context')
if (ctx.isSubscription) {
throw new Error('Workshops cannot be retrieved in subscription context')
}
return await this.prisma.workshopSubscription.findMany({
...query,
skip: args.skip ?? undefined,
@@ -73,8 +75,12 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
type: [this.workshopSubscription()],
description: 'Retrieve a list of workshops that the current user is subscribed to.',
resolve: async (query, _root, _args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Workshops cannot be retrieved in subscription context')
if (!ctx.http.me) throw new Error('User is not authenticated')
if (ctx.isSubscription) {
throw new Error('Workshops cannot be retrieved in subscription context')
}
if (!ctx.http.me) {
throw new Error('User is not authenticated')
}
return await this.prisma.workshopSubscription.findMany({
...query,
where: {
@@ -94,21 +100,31 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
}),
},
resolve: async (_query, _root, args, ctx) => {
if (ctx.isSubscription) throw new Error('Not allowed in subscription')
if (ctx.isSubscription) {
throw new Error('Not allowed in subscription')
}
const userId = ctx.http.me?.id
// retrieve the workshop
const workshop = await this.prisma.workshop.findUnique({
where: { id: args.workshopId },
})
if (!workshop) throw new Error('Workshop not found')
if (!userId) throw new Error('User not authenticated')
if (!workshop) {
throw new Error('Workshop not found')
}
if (!userId) {
throw new Error('User not authenticated')
}
// check if workshop is in the future
if (workshop.date < DateTimeUtils.now().toJSDate()) throw new Error('Workshop has already started or is over')
if (workshop.date < DateTimeUtils.now().toJSDate()) {
throw new Error('Workshop has already started or is over')
}
// check if user is already subscribed to the workshop
const existingSubscription = await this.prisma.workshopSubscription.findFirst({
where: { userId, workshopId: args.workshopId },
})
if (existingSubscription) throw new Error('User already subscribed to workshop')
if (existingSubscription) {
throw new Error('User already subscribed to workshop')
}
// create the workshop subscription
return await this.prisma.workshopSubscription.create({
data: {