Skip to content

Commit

Permalink
[Resolver] Add mandala chart related resolver (#21)
Browse files Browse the repository at this point in the history
* ✨ Add mandala model

* ♻️ Change way to export

* ✨ Add default value

* ✨ Add mandala chart resolver

* ✨ Save title and description on mandala chart document, not cell

* ✨ Add dto for creating mandala chart

* ✨ Add dto for updating mandala chart

* ✨ Add dto for deleting mandala chart

* 🔥 Remove message field from success type

* ✨ Add dto for Getting mandala chart

* ✨ Add resolver for mandala chart

* ♻️ Fix type error

* ✨ Change goals to goal per one mandala cell

* ✨ Add getting user id decorator for resolver

* ✨ Add return type of failure

* ✨ Get userId from cookie on saving

* ✨ Add private field and fix wrong type

* ✨ Imbed mandala cell into mandala chart

* ✨ Add private fields on input

* ✨ Change update input

* 🐛 Remove true in for loop on validation function

* ✨ Replace impossible decorator to middleware

* 🔧 Fix eslintrc error

* ✨ Set temporary ignore

* 🐛 Fix error on type graphql

MichalLytek/type-graphql#1401

* ♻️ Change error without login

* ✨ Apply userId middleware

* ✨ Set proper error type
  • Loading branch information
lcpnine authored Jan 25, 2024
1 parent 4327740 commit 1951c46
Show file tree
Hide file tree
Showing 15 changed files with 662 additions and 12 deletions.
21 changes: 13 additions & 8 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
{
"plugins": ["unused-imports"],
"extends":["@typescript-eslint/no-unused-vars"],
"extends": ["plugin:@typescript-eslint/recommended"],
"rules": {
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{ "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
]
}
}
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
]
}
}
8 changes: 7 additions & 1 deletion packages/server/src/config/yoga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import type { YogaServerOptions } from 'graphql-yoga'
import { buildSchema } from 'type-graphql'
import { IS_DEV } from '../constant/common'
import renewJwt from '../middlewares/renewJwt.middleware'
import { extractUserId } from '../middlewares/userId.middleware'
import { MandalaChartResolver } from '../resolvers/mandalaChart.resolver'
import { RecommendationResolver } from '../resolvers/recommendation.resolver'
import { UserResolver } from '../resolvers/user.resolver'
import { MyContext } from '../types/common'

const createSchema = async () =>
await buildSchema({
resolvers: [UserResolver, RecommendationResolver],
resolvers: [UserResolver, MandalaChartResolver, RecommendationResolver],
emitSchemaFile: 'src/schema.gql',
validate: {
forbidUnknownValues: false,
},
})

const createYogaConfig = async () => {
Expand All @@ -20,6 +25,7 @@ const createYogaConfig = async () => {
graphiql: IS_DEV,
context: async ({ req, res }: MyContext) => {
await renewJwt(req, res)
extractUserId(req, res)
return { req, res }
},
} as YogaServerOptions<{}, {}>
Expand Down
29 changes: 29 additions & 0 deletions packages/server/src/middlewares/userId.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Request, Response } from 'express'
import * as jwt from 'jsonwebtoken'

export const extractUserId = (req: Request, res: Response) => {
const token = req.cookies?.token

if (!token) {
req.userId = null
return
}

try {
const decoded = jwt.verify(
token,
process.env.JWT_SECRET as string
) as jwt.JwtPayload
req.userId = decoded.userId
} catch (error) {
req.userId = null
}
}

declare global {
namespace Express {
interface Request {
userId: string | null
}
}
}
35 changes: 35 additions & 0 deletions packages/server/src/models/MandalaChart.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import mongoose, { Document, Schema } from 'mongoose'

// MandalaCell schema remains the same
const MandalaCellSchema: Schema = new Schema({
goal: { type: String },
tasks: [{ type: String }],
})

export interface IMandalaCell extends Document {
goal: string
tasks: string[]
}

const MandalaChartSchema: Schema = new Schema({
title: { type: String, required: true },
description: { type: String },
userId: { type: Schema.Types.ObjectId, ref: 'User' },
private: { type: Boolean, default: false },
centerCell: MandalaCellSchema,
surroundingCells: [MandalaCellSchema],
})

export interface IMandalaChart extends Document {
title: string
description?: string
userId: mongoose.Types.ObjectId
private: boolean
centerCell: IMandalaCell
surroundingCells: IMandalaCell[]
}

export const MandalaChartModel = mongoose.model<IMandalaChart>(
'MandalaChart',
MandalaChartSchema
)
7 changes: 6 additions & 1 deletion packages/server/src/models/User.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const UserSchema: Schema = new Schema({
},
default: () => ({}),
},
mandalaCharts: {
type: [{ type: Schema.Types.ObjectId, ref: 'MandalaChart' }],
default: [],
},
})

export interface IUser extends Document {
Expand All @@ -32,6 +36,7 @@ export interface IUser extends Document {
emailVerification: TokenInfo
resetPassword: TokenInfo
purchasedInfo: PurchasedInfo
mandalaCharts: mongoose.Types.ObjectId[]
}

export default mongoose.model<IUser>('User', UserSchema)
export const UserModel = mongoose.model<IUser>('User', UserSchema)
205 changes: 205 additions & 0 deletions packages/server/src/resolvers/dto/mandalaChart.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import {
Field,
ID,
InputType,
ObjectType,
createUnionType,
registerEnumType,
} from 'type-graphql'
import { MandalaChart } from '../../types/mandalaChart'
import { BaseError } from './common.dto'

@InputType()
export class MandalaCellInput {
@Field()
goal: string

@Field(() => [String])
tasks: string[]
}

@InputType()
export class GetMandalaChartInput {
@Field(() => ID)
mandalaChartId: string
}

@ObjectType()
export class GetMandalaChartSuccess {
@Field(() => MandalaChart)
mandalaChart: MandalaChart
}

export enum GetMandalaChartFailureType {
CHART_NOT_FOUND = 'CHART_NOT_FOUND',
UNAUTHORIZED_ACCESS = 'UNAUTHORIZED_ACCESS',
SERVER_ERROR = 'SERVER_ERROR',
}

registerEnumType(GetMandalaChartFailureType, {
name: 'GetMandalaChartFailureType',
})

@ObjectType()
export class GetMandalaChartFailure implements BaseError {
@Field(() => GetMandalaChartFailureType)
errorType: GetMandalaChartFailureType
}

export const GetMandalaChartResponse = createUnionType({
name: 'GetMandalaChartResponse',
types: () => [GetMandalaChartSuccess, GetMandalaChartFailure] as const,
resolveType: (value: any) => {
if ('mandalaChart' in value) {
return GetMandalaChartSuccess.name
}
return GetMandalaChartFailure.name
},
})

@InputType()
export class CreateMandalaChartInput {
@Field()
title: string

@Field({ nullable: true })
description?: string

@Field()
private: boolean

@Field(() => MandalaCellInput)
centerCell: MandalaCellInput

@Field(() => [MandalaCellInput])
surroundingCells: MandalaCellInput[]
}

@ObjectType()
export class CreateMandalaChartSuccess {
@Field(() => ID)
_id: string
}

export enum CreateMandalaChartFailureType {
NO_TITLE = 'NO_TITLE',
UNAUTHORIZED_ACCESS = 'UNAUTHORIZED_ACCESS',
INVALID_INPUT = 'INVALID_INPUT',
SERVER_ERROR = 'SERVER_ERROR',
}

registerEnumType(CreateMandalaChartFailureType, {
name: 'CreateMandalaChartFailureType',
})

@ObjectType()
export class CreateMandalaChartFailure implements BaseError {
@Field(() => CreateMandalaChartFailureType)
errorType: CreateMandalaChartFailureType
}

export const CreateMandalaChartResponse = createUnionType({
name: 'CreateMandalaChartResponse',
types: () => [CreateMandalaChartSuccess, CreateMandalaChartFailure] as const,
resolveType: (value: any) => {
if ('_id' in value) {
return CreateMandalaChartSuccess.name
}
return CreateMandalaChartFailure.name
},
})

@InputType()
export class UpdateMandalaChartInput {
@Field(() => ID)
mandalaChartId: string

@Field({ nullable: true })
title: string

@Field({ nullable: true })
description?: string

@Field({ nullable: true })
private: boolean

@Field(() => MandalaCellInput, { nullable: true })
centerCell: MandalaCellInput

@Field(() => [MandalaCellInput], { nullable: 'itemsAndList' })
surroundingCells: MandalaCellInput[]
}

@ObjectType()
export class UpdateMandalaChartSuccess {
@Field(() => ID)
_id: string
}

export enum UpdateMandalaChartFailureType {
CHART_NOT_FOUND = 'CHART_NOT_FOUND',
NO_TITLE = 'NO_TITLE',
UNAUTHORIZED_ACCESS = 'UNAUTHORIZED_ACCESS',
INVALID_INPUT = 'INVALID_INPUT',
SERVER_ERROR = 'SERVER_ERROR',
}

registerEnumType(UpdateMandalaChartFailureType, {
name: 'UpdateMandalaChartFailureType',
})

@ObjectType()
export class UpdateMandalaChartFailure implements BaseError {
@Field(() => UpdateMandalaChartFailureType)
errorType: UpdateMandalaChartFailureType
}

export const UpdateMandalaChartResponse = createUnionType({
name: 'UpdateMandalaChartResponse',
types: () => [UpdateMandalaChartSuccess, UpdateMandalaChartFailure] as const,
resolveType: (value: any) => {
if ('_id' in value) {
return UpdateMandalaChartSuccess.name
}
return UpdateMandalaChartFailure.name
},
})

@InputType()
export class DeleteMandalaChartInput {
@Field(() => ID)
mandalaChartId: string
}

@ObjectType()
export class DeleteMandalaChartSuccess {
@Field(() => ID)
_id: string
}

export enum DeleteMandalaChartFailureType {
CHART_NOT_FOUND = 'CHART_NOT_FOUND',
UNAUTHORIZED_ACCESS = 'UNAUTHORIZED_ACCESS',
SERVER_ERROR = 'SERVER_ERROR',
}

registerEnumType(DeleteMandalaChartFailureType, {
name: 'DeleteMandalaChartFailureType',
})

@ObjectType()
export class DeleteMandalaChartFailure implements BaseError {
@Field(() => DeleteMandalaChartFailureType)
errorType: DeleteMandalaChartFailureType
}

export const DeleteMandalaChartResponse = createUnionType({
name: 'DeleteMandalaChartResponse',
types: () => [DeleteMandalaChartSuccess, DeleteMandalaChartFailure] as const,
resolveType: (value: any) => {
if ('_id' in value) {
return DeleteMandalaChartSuccess.name
}
return DeleteMandalaChartFailure.name
},
})
Loading

0 comments on commit 1951c46

Please sign in to comment.