feat: enhance quiz schema with JsonList type and add quiz attempt fields
- Introduced a new 'JsonList' scalar type in the GraphQL schema to handle lists of JSON values, improving data structure flexibility. - Updated the Quiz schema to replace 'Json' type with 'JsonList' for user input and questions, ensuring consistent data handling. - Added new fields for retrieving quiz attempts, including individual and multiple attempts, with appropriate authorization checks for user roles. - Enhanced error handling for quiz attempt retrieval to ensure proper access control and user feedback. These changes improve the overall functionality and maintainability of the quiz feature, providing a more robust data model and user experience.
This commit is contained in:
Submodule epess-database updated: 54cb097acd...ad75f8f4b4
@@ -78,6 +78,10 @@ export interface SchemaBuilderOption {
|
|||||||
Input: Delta
|
Input: Delta
|
||||||
Output: Delta
|
Output: Delta
|
||||||
}
|
}
|
||||||
|
JsonList: {
|
||||||
|
Input: JsonValue[]
|
||||||
|
Output: JsonValue[]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +164,12 @@ export class Builder extends SchemaBuilder<SchemaBuilderOption> {
|
|||||||
parseLiteral: (ast: ValueNode) => ast as unknown as Delta,
|
parseLiteral: (ast: ValueNode) => ast as unknown as Delta,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.scalarType('JsonList', {
|
||||||
|
serialize: (value) => JSON.stringify(value),
|
||||||
|
parseValue: (value: unknown) => JSON.parse(value as string) as JsonValue[],
|
||||||
|
parseLiteral: (ast: ValueNode) => ast as unknown as JsonValue[],
|
||||||
|
})
|
||||||
|
|
||||||
this.addScalarType('Json', JSONObjectResolver)
|
this.addScalarType('Json', JSONObjectResolver)
|
||||||
this.addScalarType('Upload', GraphQLUpload)
|
this.addScalarType('Upload', GraphQLUpload)
|
||||||
|
|
||||||
|
|||||||
@@ -86,10 +86,10 @@ export class QuizSchema extends PothosSchema {
|
|||||||
correctPoints: t.exposeInt('correctPoints'),
|
correctPoints: t.exposeInt('correctPoints'),
|
||||||
totalPoints: t.exposeInt('totalPoints'),
|
totalPoints: t.exposeInt('totalPoints'),
|
||||||
userInput: t.expose('userInput', {
|
userInput: t.expose('userInput', {
|
||||||
type: 'Json',
|
type: 'JsonList',
|
||||||
}),
|
}),
|
||||||
questions: t.expose('questions', {
|
questions: t.expose('questions', {
|
||||||
type: 'Json',
|
type: 'JsonList',
|
||||||
}),
|
}),
|
||||||
createdAt: t.expose('createdAt', {
|
createdAt: t.expose('createdAt', {
|
||||||
type: 'DateTime',
|
type: 'DateTime',
|
||||||
@@ -227,6 +227,90 @@ export class QuizSchema extends PothosSchema {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
quizAttempt: t.prismaField({
|
||||||
|
type: this.quizAttempt(),
|
||||||
|
args: {
|
||||||
|
id: t.arg({
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
resolve: async (query, _root, args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) {
|
||||||
|
throw new Error('Not allowed')
|
||||||
|
}
|
||||||
|
if (!ctx.http.me) {
|
||||||
|
throw new Error('Unauthorized')
|
||||||
|
}
|
||||||
|
if (!args.id) {
|
||||||
|
throw new Error('Id is required')
|
||||||
|
}
|
||||||
|
const result = await this.prisma.quizAttempt.findUnique({
|
||||||
|
...query,
|
||||||
|
where: {
|
||||||
|
id: args.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Quiz attempt not found')
|
||||||
|
}
|
||||||
|
// check if user is the owner of the quiz attempt
|
||||||
|
if (
|
||||||
|
result.userId !== ctx.http.me.id &&
|
||||||
|
ctx.http.me.role !== Role.CENTER_OWNER &&
|
||||||
|
ctx.http.me.role !== Role.CENTER_MENTOR &&
|
||||||
|
ctx.http.me.role !== Role.CUSTOMER
|
||||||
|
) {
|
||||||
|
throw new Error('Unauthorized')
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
quizAttempts: t.prismaField({
|
||||||
|
type: [this.quizAttempt()],
|
||||||
|
args: {
|
||||||
|
quizId: t.arg({
|
||||||
|
type: 'String',
|
||||||
|
required: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
resolve: async (query, _root, args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) {
|
||||||
|
throw new Error('Not allowed')
|
||||||
|
}
|
||||||
|
if (!ctx.http.me) {
|
||||||
|
throw new Error('Unauthorized')
|
||||||
|
}
|
||||||
|
// use case 1: center mentor or center owner
|
||||||
|
if (ctx.http.me.role === Role.CENTER_MENTOR || ctx.http.me.role === Role.CENTER_OWNER) {
|
||||||
|
const centerMentor = await this.prisma.centerMentor.findUnique({
|
||||||
|
where: { mentorId: ctx.http.me.id },
|
||||||
|
})
|
||||||
|
if (!centerMentor) {
|
||||||
|
throw new Error('Center mentor not found')
|
||||||
|
}
|
||||||
|
return await this.prisma.quizAttempt.findMany({
|
||||||
|
...query,
|
||||||
|
where: {
|
||||||
|
quiz: {
|
||||||
|
centerMentorId: centerMentor.mentorId,
|
||||||
|
},
|
||||||
|
...(args.quizId ? [{ quizId: args.quizId }] : []),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// use case 2: customer
|
||||||
|
if (ctx.http.me.role === Role.CUSTOMER) {
|
||||||
|
return await this.prisma.quizAttempt.findMany({
|
||||||
|
...query,
|
||||||
|
where: {
|
||||||
|
userId: ctx.http.me.id,
|
||||||
|
...(args.quizId ? [{ quizId: args.quizId }] : []),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
}))
|
}))
|
||||||
this.builder.mutationFields((t) => ({
|
this.builder.mutationFields((t) => ({
|
||||||
createQuiz: t.prismaField({
|
createQuiz: t.prismaField({
|
||||||
@@ -298,7 +382,6 @@ export class QuizSchema extends PothosSchema {
|
|||||||
'id',
|
'id',
|
||||||
'createdAt',
|
'createdAt',
|
||||||
'updatedAt',
|
'updatedAt',
|
||||||
'quiz',
|
|
||||||
'user',
|
'user',
|
||||||
'userId',
|
'userId',
|
||||||
]),
|
]),
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user