From 83b453c3b89328abfea7e8196f391797afc91ae2 Mon Sep 17 00:00:00 2001 From: Ly Tuan Kiet Date: Sun, 6 Oct 2024 20:42:02 +0700 Subject: [PATCH] thang an bi ngu --- .eslintrc.js | 2 - package-lock.json | 64 +++++++++++++++++++++++++- package.json | 2 + src/app.module.ts | 2 + src/graphql/graphql.builder.ts | 5 +- src/graphql/schema.ts | 83 ++++++++++++++++++++++++++++------ src/main.ts | 28 +++++++++++- src/restful/restful.module.ts | 8 +++- src/restful/restful.service.ts | 31 +++++++++++++ 9 files changed, 202 insertions(+), 23 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3a8c5c7..4df8089 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,3 @@ -const { environments } = require('eslint-plugin-prettier'); - module.exports = { parser: '@typescript-eslint/parser', parserOptions: { diff --git a/package-lock.json b/package-lock.json index c0de823..7fb68e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@nestjs/graphql": "^12.2.0", "@nestjs/jwt": "^10.2.0", "@nestjs/platform-express": "^10.0.0", + "@nestjs/swagger": "^7.4.2", "@pothos/core": "^4.2.0", "@pothos/plugin-add-graphql": "^4.1.0", "@pothos/plugin-prisma": "^4.2.1", @@ -40,6 +41,7 @@ "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", + "swagger-ui-express": "^5.0.1", "type-graphql": "^2.0.0-rc.2" }, "devDependencies": { @@ -4910,6 +4912,12 @@ "node": ">=8" } }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", + "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", + "license": "MIT" + }, "node_modules/@nestjs/apollo": { "version": "12.2.0", "resolved": "https://registry.npmjs.org/@nestjs/apollo/-/apollo-12.2.0.tgz", @@ -5303,6 +5311,39 @@ "dev": true, "license": "MIT" }, + "node_modules/@nestjs/swagger": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.4.2.tgz", + "integrity": "sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==", + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "^0.15.0", + "@nestjs/mapped-types": "2.0.5", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "3.3.0", + "swagger-ui-dist": "5.17.14" + }, + "peerDependencies": { + "@fastify/static": "^6.0.0 || ^7.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/testing": { "version": "10.4.4", "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.4.4.tgz", @@ -7212,7 +7253,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/array-flatten": { @@ -11602,7 +11642,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -14247,6 +14286,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.17.14", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz", + "integrity": "sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==", + "license": "Apache-2.0" + }, + "node_modules/swagger-ui-express": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", + "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", + "license": "MIT", + "dependencies": { + "swagger-ui-dist": ">=5.0.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0 || >=5.0.0-beta" + } + }, "node_modules/swap-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-2.0.2.tgz", diff --git a/package.json b/package.json index a50591e..4a5361d 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@nestjs/graphql": "^12.2.0", "@nestjs/jwt": "^10.2.0", "@nestjs/platform-express": "^10.0.0", + "@nestjs/swagger": "^7.4.2", "@pothos/core": "^4.2.0", "@pothos/plugin-add-graphql": "^4.1.0", "@pothos/plugin-prisma": "^4.2.1", @@ -54,6 +55,7 @@ "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", + "swagger-ui-express": "^5.0.1", "type-graphql": "^2.0.0-rc.2" }, "devDependencies": { diff --git a/src/app.module.ts b/src/app.module.ts index 58f355a..1ebf343 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,11 +1,13 @@ import { Module } from '@nestjs/common'; import { GraphqlModule } from './graphql/graphql.module'; import { ClerkModule } from './clerk/clerk.module'; +import { RestfulModule } from './restful/restful.module'; @Module({ imports: [ GraphqlModule, // GraphQL setup ClerkModule, // Clerk setup + RestfulModule, // RESTful API module ], }) export class AppModule {} diff --git a/src/graphql/graphql.builder.ts b/src/graphql/graphql.builder.ts index b794fc4..dbd6b1d 100644 --- a/src/graphql/graphql.builder.ts +++ b/src/graphql/graphql.builder.ts @@ -2,6 +2,7 @@ import SchemaBuilder from '@pothos/core'; import PrismaPlugin from '@pothos/plugin-prisma'; import PrismaUtils from '@pothos/plugin-prisma-utils'; import { DateTimeResolver } from 'graphql-scalars'; +import { GraphQLInt } from 'graphql'; import { PrismaService } from '../prisma/prisma.service'; import type PrismaTypes from '../types/pothos.generated'; import { getDatamodel } from '../types/pothos.generated'; @@ -32,6 +33,4 @@ export const builder = new SchemaBuilder<{ export const SortOrder = builder.enumType('SortOrder', { values: ['asc', 'desc'], }); - - -builder.addScalarType('DateTime', DateTimeResolver, {}); \ No newline at end of file +builder.addScalarType('DateTime', DateTimeResolver, {}); diff --git a/src/graphql/schema.ts b/src/graphql/schema.ts index 664b046..ab93d7f 100644 --- a/src/graphql/schema.ts +++ b/src/graphql/schema.ts @@ -32,7 +32,25 @@ builder.prismaObject('User', { builder.prismaObject('Order', { fields: (t) => ({ id: t.exposeID('id'), + paymentId: t.exposeString('paymentId'), userId: t.exposeID('userId'), + serviceId: t.exposeID('serviceId'), + status: t.exposeString('status'), + total: t.expose('total', { + type: 'Int', + }), + createdAt: t.expose('createdAt', { + type: 'DateTime', + nullable: true, + }), + updatedAt: t.expose('updatedAt', { + type: 'DateTime', + nullable: true, + }), + user: t.relation('user'), + payment: t.relation('payment'), + service: t.relation('service'), + refundTicket: t.relation('refundTicket'), }), }); @@ -59,6 +77,45 @@ builder.prismaObject('Message', { }), }); +builder.prismaObject('Payment', { + fields: (t) => ({ + id: t.exposeID('id'), + amount: t.expose('amount', { + type: 'Float', + }), + status: t.exposeString('status'), + createdAt: t.expose('createdAt', { + type: 'DateTime', + nullable: true, + }), + updatedAt: t.expose('updatedAt', { + type: 'DateTime', + nullable: true, + }), + order: t.relation('Order'), + }), +}); + +builder.prismaObject('RefundTicket', { + fields: (t) => ({ + id: t.exposeID('id'), + orderId: t.exposeID('orderId'), + amount: t.expose('amount', { + type: 'Float', + }), + status: t.exposeString('status'), + createdAt: t.expose('createdAt', { + type: 'DateTime', + nullable: true, + }), + updatedAt: t.expose('updatedAt', { + type: 'DateTime', + nullable: true, + }), + order: t.relation('order'), + }), +}); + builder.prismaObject('Service', { fields: (t) => ({ id: t.exposeID('id'), @@ -146,6 +203,7 @@ builder.prismaObject('ChatRoom', { builder.prismaObject('CenterStaff', { fields: (t) => ({ staffId: t.exposeID('staffId'), + staff: t.relation('staff'), centerId: t.exposeID('centerId'), serviceId: t.exposeID('serviceId'), }), @@ -261,28 +319,27 @@ builder.queryType({ take: t.arg.int(), skip: t.arg.int(), }, - resolve: (query, root, args, ctx, info) => { + resolve: async (query, root, args, ctx, info) => { return prisma.service.findMany({ - // process filters + // handle where condition where: { name: { - contains: args.where?.nameContain as string, - startsWith: args.where?.nameStartsWith as string, - endsWith: args.where?.nameEndsWith as string, + contains: args.where?.nameContain as string | undefined, + startsWith: args.where?.nameStartsWith as string | undefined, + endsWith: args.where?.nameEndsWith as string | undefined, }, }, - // process order by + // handle orderBy condition orderBy: { rating: args.orderBy?.rating as Prisma.SortOrder, price: args.orderBy?.price as Prisma.SortOrder, }, - // process pagination - cursor: args.cursor as Prisma.ServiceWhereUniqueInput, - take: args.take as number, - skip: args.skip as number, - ...query, + // handle pagination + cursor: args.cursor as Prisma.ServiceWhereUniqueInput | undefined, + take: args.take as number | undefined, + skip: args.skip as number | undefined, }); - }, + }, }), service: t.prismaField({ type: 'Service', @@ -361,7 +418,7 @@ builder.queryType({ // if (!args.data) { // throw new Error('Data input is required'); // } - + // return prisma.user.create({ // ...query, // data: args.data as Prisma.UserCreateInput, // Explicit type casting to match Prisma's expectation diff --git a/src/main.ts b/src/main.ts index 4d8df81..1f0f43b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,10 +1,36 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { cors } from './common/utils/cors.utils'; +import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; +// Import DateTime scalar if necessary +require('./common/utils/datetime.utils'); async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(cors); - await app.listen(3069); + + const config = new DocumentBuilder() + .setTitle('EPESS API') + .setDescription('API documentation for EPESS application') + .setVersion('1.0') + .addBearerAuth() + .build(); + + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api', app, document); + + document.paths['/graphql'] = { + get: { + summary: 'GraphQL Playground', + description: 'Access the GraphQL Playground to interact with the GraphQL API.', + responses: { + '200': { + description: 'GraphQL Playground', + }, + }, + }, + }; + + await app.listen(3000); } bootstrap(); diff --git a/src/restful/restful.module.ts b/src/restful/restful.module.ts index 6d20dc8..dbe92f1 100644 --- a/src/restful/restful.module.ts +++ b/src/restful/restful.module.ts @@ -1,5 +1,9 @@ import { Module } from '@nestjs/common'; +import { RestfulController } from './restful.controller'; +import { RestfulService } from './restful.service'; + @Module({ - imports: [], + controllers: [RestfulController], + providers: [RestfulService], }) -export class RestfulModule {} +export class RestfulModule {} \ No newline at end of file diff --git a/src/restful/restful.service.ts b/src/restful/restful.service.ts index e69de29..f8fd0f2 100644 --- a/src/restful/restful.service.ts +++ b/src/restful/restful.service.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class RestfulService { + getAllItems() { + // Implementation to get all items + return []; // Replace with actual logic + } + + getItem(id: string) { + // Implementation to get a single item by id + return {}; // Replace with actual logic + } + + createItem(createDto: any) { + // Implementation to create a new item + return {}; // Replace with actual logic + } + + updateItem(id: string, updateDto: any) { + // Implementation to update an item by id + return {}; // Replace with actual logic + } + + deleteItem(id: string) { + // Implementation to delete an item by id + return {}; // Replace with actual logic + } +} + +export default RestfulService;