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

View File

@@ -19,8 +19,10 @@
"prisma:seed": "npx prisma db seed --schema=./epess-database/prisma/schema.prisma", "prisma:seed": "npx prisma db seed --schema=./epess-database/prisma/schema.prisma",
"prisma:format": "npx prisma format --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", "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:format": "biome format --write",
"biome:lint": "biome lint",
"biome:check:unsafe": "biome check --write --unsafe",
"test": "jest", "test": "jest",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:cov": "jest --coverage", "test:cov": "jest --coverage",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -117,8 +117,12 @@ export class OrderSchema extends PothosSchema {
description: 'Retrieve a list of completed orders', description: 'Retrieve a list of completed orders',
args: this.builder.generator.findManyArgs('Order'), args: this.builder.generator.findManyArgs('Order'),
resolve: async (query, _root, args, ctx, _info) => { resolve: async (query, _root, args, ctx, _info) => {
if (ctx.isSubscription) throw new Error('Orders cannot be retrieved in subscription context') if (ctx.isSubscription) {
if (!ctx.http.me) throw new Error('Unauthorized') 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 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({ return await this.prisma.order.findMany({
...query, ...query,

View File

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

View File

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

View File

@@ -156,14 +156,21 @@ export class RefundTicketSchema extends PothosSchema {
const diffTime = Math.abs(now.diff(orderDate).toMillis()) const diffTime = Math.abs(now.diff(orderDate).toMillis())
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
let refundAmount = 0 let refundAmount = 0
if (diffDays < 1) refundAmount = order.total if (diffDays < 1) {
else if (diffDays < 3) refundAmount = order.total * 0.5 refundAmount = order.total
if (refundAmount === 0) throw new Error('Cannot refund after 3 days') } else if (diffDays < 3) {
refundAmount = order.total * 0.5
}
if (refundAmount === 0) {
throw new Error('Cannot refund after 3 days')
}
// create refund ticket // create refund ticket
// get bank name from bank bin from banks.json // get bank name from bank bin from banks.json
// biome-ignore lint/suspicious/noExplicitAny: <explanation> // biome-ignore lint/suspicious/noExplicitAny: <explanation>
const bank = banks.data.find((bank: any) => bank.bin === ctx.http.me?.bankBin) 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({ const refundTicket = await this.prisma.refundTicket.create({
data: { data: {
orderId: order.id, 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.', description: 'Whether the user has already provided feedback for the service.',
nullable: true, nullable: true,
resolve: async (service, _args, ctx) => { resolve: async (service, _args, ctx) => {
if (ctx.isSubscription) return null if (ctx.isSubscription) {
if (!ctx.http.me) return false return null
}
if (!ctx.http.me) {
return false
}
const serviceFeedbacks = await this.prisma.serviceFeedback.findMany({ const serviceFeedbacks = await this.prisma.serviceFeedback.findMany({
where: { where: {
serviceId: service.id, serviceId: service.id,

View File

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

View File

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

View File

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

View File

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

View File

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