remove graph

This commit is contained in:
2025-11-22 10:49:31 +03:30
parent 2c0ab601f3
commit ee1e6049c5
42 changed files with 364 additions and 875 deletions
+4 -275
View File
@@ -20,14 +20,12 @@
"@mikro-orm/nestjs": "^6.1.1",
"@mikro-orm/postgresql": "^6.5.8",
"@nest-lab/fastify-multer": "^1.3.0",
"@nestjs/apollo": "^13.2.1",
"@nestjs/axios": "^4.0.1",
"@nestjs/bullmq": "^11.0.4",
"@nestjs/cache-manager": "^3.0.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1",
"@nestjs/graphql": "^13.2.0",
"@nestjs/jwt": "^11.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^11.0.1",
@@ -40,7 +38,6 @@
"class-validator": "^0.14.2",
"dayjs": "^1.11.19",
"fastify": "^5.6.1",
"graphql": "^16.12.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"ulid": "^3.0.1"
@@ -299,22 +296,6 @@
"graphql": "14.x || 15.x || 16.x"
}
},
"node_modules/@apollo/server-plugin-landing-page-graphql-playground": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@apollo/server-plugin-landing-page-graphql-playground/-/server-plugin-landing-page-graphql-playground-4.0.1.tgz",
"integrity": "sha512-tWhQzD7DtiTO/wfbGvasryz7eJSuEh9XJHgRTMZI7+Wu/omylG5gH6K6ksg1Vccg8/Xuglfi2f1M5Nm/IlBBGw==",
"deprecated": "The use of GraphQL Playground in Apollo Server was supported in previous versions, but this is no longer the case as of December 31, 2022. This package exists for v4 migration purposes only. We do not intend to resolve security issues or other bugs with this package if they arise, so please migrate away from this to [Apollo Server's default Explorer](https://www.apollographql.com/docs/apollo-server/api/plugin/landing-pages) as soon as possible.",
"license": "MIT",
"dependencies": {
"@apollographql/graphql-playground-html": "1.6.29"
},
"engines": {
"node": ">=14.0"
},
"peerDependencies": {
"@apollo/server": "^4.0.0"
}
},
"node_modules/@apollo/server/node_modules/lru-cache": {
"version": "11.2.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
@@ -487,15 +468,6 @@
"node": ">=16"
}
},
"node_modules/@apollographql/graphql-playground-html": {
"version": "1.6.29",
"resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.29.tgz",
"integrity": "sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA==",
"license": "MIT",
"dependencies": {
"xss": "^1.0.8"
}
},
"node_modules/@as-integrations/fastify": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@as-integrations/fastify/-/fastify-3.1.0.tgz",
@@ -4051,42 +4023,6 @@
}
}
},
"node_modules/@nestjs/apollo": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@nestjs/apollo/-/apollo-13.2.1.tgz",
"integrity": "sha512-BJPNw8xqs4DfdEEmjaAbI6cIJsHouWjcZN70BKTPl8rZcw4Tf61RonqFRn0F/rr/aiccWGAuXJuWY4dPsgah4Q==",
"license": "MIT",
"dependencies": {
"@apollo/server-plugin-landing-page-graphql-playground": "4.0.1",
"iterall": "1.3.0",
"lodash.omit": "4.5.0",
"tslib": "2.8.1"
},
"peerDependencies": {
"@apollo/gateway": "^2.0.0",
"@apollo/server": "^5.0.0",
"@apollo/subgraph": "^2.0.0",
"@as-integrations/fastify": "^2.1.1 || ^3.0.0",
"@nestjs/common": "^11.0.1",
"@nestjs/core": "^11.0.1",
"@nestjs/graphql": "^13.0.0",
"graphql": "^16.10.0"
},
"peerDependenciesMeta": {
"@apollo/gateway": {
"optional": true
},
"@apollo/subgraph": {
"optional": true
},
"@as-integrations/express5": {
"optional": true
},
"@as-integrations/fastify": {
"optional": true
}
}
},
"node_modules/@nestjs/axios": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-4.0.1.tgz",
@@ -4469,51 +4405,6 @@
}
}
},
"node_modules/@nestjs/graphql": {
"version": "13.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/graphql/-/graphql-13.2.0.tgz",
"integrity": "sha512-ehgd4pp9e6PQJWjkjV/jGF4934LLzH7C/efe9a9yKJeTZi+x7AL6p+00Q5fhgG75E2CgUZOrmKa90LhcCwqMfA==",
"license": "MIT",
"dependencies": {
"@graphql-tools/merge": "9.1.1",
"@graphql-tools/schema": "10.0.25",
"@graphql-tools/utils": "10.9.1",
"@nestjs/mapped-types": "2.1.0",
"chokidar": "4.0.3",
"fast-glob": "3.3.3",
"graphql-tag": "2.12.6",
"graphql-ws": "6.0.6",
"lodash": "4.17.21",
"normalize-path": "3.0.0",
"subscriptions-transport-ws": "0.11.0",
"tslib": "2.8.1",
"ws": "8.18.3"
},
"peerDependencies": {
"@apollo/subgraph": "^2.9.3",
"@nestjs/common": "^11.0.1",
"@nestjs/core": "^11.0.1",
"class-transformer": "*",
"class-validator": "*",
"graphql": "^16.11.0",
"reflect-metadata": "^0.1.13 || ^0.2.0",
"ts-morph": "^20.0.0 || ^21.0.0 || ^24.0.0 || ^25.0.0"
},
"peerDependenciesMeta": {
"@apollo/subgraph": {
"optional": true
},
"class-transformer": {
"optional": true
},
"class-validator": {
"optional": true
},
"ts-morph": {
"optional": true
}
}
},
"node_modules/@nestjs/jwt": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.1.tgz",
@@ -7252,12 +7143,6 @@
"@babel/core": "^7.11.0 || ^8.0.0-beta.1"
}
},
"node_modules/backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==",
"license": "MIT"
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -7635,6 +7520,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
@@ -8089,12 +7975,6 @@
"node": ">= 8"
}
},
"node_modules/cssfilter": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
"integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==",
"license": "MIT"
},
"node_modules/dataloader": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz",
@@ -8731,12 +8611,6 @@
"node": ">= 0.6"
}
},
"node_modules/eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"license": "MIT"
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
@@ -9720,55 +9594,11 @@
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz",
"integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
}
},
"node_modules/graphql-tag": {
"version": "2.12.6",
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
"integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.1.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
}
},
"node_modules/graphql-ws": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.6.tgz",
"integrity": "sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw==",
"license": "MIT",
"engines": {
"node": ">=20"
},
"peerDependencies": {
"@fastify/websocket": "^10 || ^11",
"crossws": "~0.3",
"graphql": "^15.10.1 || ^16",
"uWebSockets.js": "^20",
"ws": "^8"
},
"peerDependenciesMeta": {
"@fastify/websocket": {
"optional": true
},
"crossws": {
"optional": true
},
"uWebSockets.js": {
"optional": true
},
"ws": {
"optional": true
}
}
},
"node_modules/handlebars": {
"version": "4.7.8",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
@@ -10286,12 +10116,6 @@
"node": ">=8"
}
},
"node_modules/iterall": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
"integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==",
"license": "MIT"
},
"node_modules/iterare": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
@@ -11548,13 +11372,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/lodash.omit": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
"integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==",
"deprecated": "This package is deprecated. Use destructuring assignment syntax instead.",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -12055,6 +11872,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -12927,6 +12745,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
@@ -13799,53 +13618,6 @@
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/subscriptions-transport-ws": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz",
"integrity": "sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==",
"deprecated": "The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md",
"license": "MIT",
"dependencies": {
"backo2": "^1.0.2",
"eventemitter3": "^3.1.0",
"iterall": "^1.2.1",
"symbol-observable": "^1.0.4",
"ws": "^5.2.0 || ^6.0.0 || ^7.0.0"
},
"peerDependencies": {
"graphql": "^15.7.2 || ^16.0.0"
}
},
"node_modules/subscriptions-transport-ws/node_modules/symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/subscriptions-transport-ws/node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/superagent": {
"version": "10.2.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz",
@@ -15170,49 +14942,6 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xss": {
"version": "1.0.15",
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz",
"integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==",
"license": "MIT",
"dependencies": {
"commander": "^2.20.3",
"cssfilter": "0.0.10"
},
"bin": {
"xss": "bin/xss"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/xss/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"license": "MIT"
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
-3
View File
@@ -35,14 +35,12 @@
"@mikro-orm/nestjs": "^6.1.1",
"@mikro-orm/postgresql": "^6.5.8",
"@nest-lab/fastify-multer": "^1.3.0",
"@nestjs/apollo": "^13.2.1",
"@nestjs/axios": "^4.0.1",
"@nestjs/bullmq": "^11.0.4",
"@nestjs/cache-manager": "^3.0.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1",
"@nestjs/graphql": "^13.2.0",
"@nestjs/jwt": "^11.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^11.0.1",
@@ -55,7 +53,6 @@
"class-validator": "^0.14.2",
"dayjs": "^1.11.19",
"fastify": "^5.6.1",
"graphql": "^16.12.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"ulid": "^3.0.1"
-9
View File
@@ -18,20 +18,11 @@ import { RestaurantsModule } from './modules/restaurants/restaurants.module';
import { FoodModule } from './modules/foods/food.module';
import { CartModule } from './modules/cart/cart.module';
import { RolesModule } from './modules/roles/roles.module';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { PaymentsModule } from './modules/payments/payments.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, cache: true }),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true,
playground: true,
introspection: true,
context: ({ req, reply }) => ({ request: req, reply }),
}),
MikroOrmModule.forRootAsync(dataBaseConfig),
// CacheModule.registerAsync(cacheConfig()),
JwtModule.registerAsync({
+1 -17
View File
@@ -1,25 +1,9 @@
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common';
import { FastifyReply } from 'fastify';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
// Check if this is a GraphQL context
if (host.getType<'graphql' | 'http'>() === 'graphql') {
try {
// In GraphQL context, host is actually an ExecutionContext
const gqlContext = GqlExecutionContext.create(host as ExecutionContext);
if (gqlContext && gqlContext.getInfo()) {
// For GraphQL, let the exception propagate - GraphQL will handle it automatically
// We can't use HTTP response methods in GraphQL context
return;
}
} catch {
// Not a GraphQL context, continue with HTTP handling
}
}
// Handle HTTP/REST context
try {
const ctx = host.switchToHttp();
+3 -50
View File
@@ -1,6 +1,5 @@
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { FastifyReply, FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -8,59 +7,13 @@ import { map } from 'rxjs/operators';
export class ResponseInterceptor implements NestInterceptor {
constructor() {}
private isGraphQLBody(body: unknown): boolean {
if (!body || typeof body !== 'object') {
return false;
}
const bodyObj = body as Record<string, unknown>;
return !!(bodyObj.query || bodyObj.mutation || bodyObj.operationName);
}
intercept(context: ExecutionContext, next: CallHandler<Record<string, unknown>>): Observable<unknown> {
// Check if this is a GraphQL request
// GraphQL requests should bypass this interceptor as they handle their own response format
// Method 1: Try to create GraphQL context - if it doesn't throw, it's GraphQL
try {
const gqlContext = GqlExecutionContext.create(context);
// If we can create it and it has GraphQL-specific properties, it's GraphQL
if (gqlContext && gqlContext.getInfo()) {
return next.handle();
}
} catch {
// Not a GraphQL context, continue
}
// Method 2: Check request URL and body for GraphQL endpoint
try {
const request = context.switchToHttp().getRequest<FastifyRequest>();
// Check URL path
if (request.url?.includes('/graphql')) {
return next.handle();
}
// Check if request body contains GraphQL query/mutation
if (this.isGraphQLBody(request.body)) {
return next.handle();
}
} catch {
// Not an HTTP context, might be GraphQL - skip wrapping
return next.handle();
}
// Method 3: Check if handler is a GraphQL resolver by checking the class name
const handler = context.getHandler();
const className = context.getClass()?.name || '';
const handlerName = handler?.name || '';
if (className.includes('Resolver') || handlerName.includes('Resolver')) {
return next.handle();
}
// For REST endpoints, wrap the response
try {
const ctx = context.switchToHttp().getResponse<FastifyReply>();
const statusCode = ctx.statusCode;
// If statusCode is undefined, it might be a GraphQL request - skip wrapping
// If statusCode is undefined, skip wrapping
if (statusCode === undefined) {
return next.handle();
}
@@ -87,7 +40,7 @@ export class ResponseInterceptor implements NestInterceptor {
}),
);
} catch {
// If we can't get HTTP context either, return data as-is (likely GraphQL)
// If we can't get HTTP context, return data as-is
return next.handle();
}
}
+1 -3
View File
@@ -12,8 +12,6 @@ import { MikroOrmModule } from '@mikro-orm/nestjs';
import { User } from '../users/entities/user.entity';
import { AdminAuthController } from './controllers/admin-auth.controller';
import { AdminAuthGuard } from './guards/adminAuth.guard';
import { AuthResolver } from './graphql/resolvers/auth.resolver';
import { AdminAuthResolver } from './graphql/resolvers/admin-auth.resolver';
@Module({
imports: [
@@ -34,7 +32,7 @@ import { AdminAuthResolver } from './graphql/resolvers/admin-auth.resolver';
MikroOrmModule.forFeature([User]),
],
controllers: [AuthController, AdminAuthController],
providers: [AuthService, TokensService, AdminAuthGuard, AuthResolver, AdminAuthResolver],
providers: [AuthService, TokensService, AdminAuthGuard],
exports: [AdminAuthGuard],
})
export class AuthModule {}
-16
View File
@@ -1,16 +0,0 @@
// Inputs
export * from './inputs/request-otp.input';
export * from './inputs/verify-otp.input';
export * from './inputs/refresh-token.input';
// Objects
export * from './objects/token-response.object';
export * from './objects/restaurant-info.object';
export * from './objects/admin-auth-response.object';
export * from './objects/auth-response.object';
export * from './objects/otp-response.object';
// Resolvers
export * from './resolvers/auth.resolver';
export * from './resolvers/admin-auth.resolver';
@@ -1,11 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsNotEmpty, IsString } from 'class-validator';
@InputType()
export class RefreshTokenInput {
@Field(() => String, { description: 'Refresh token' })
@IsString({ message: 'Refresh token must be a string' })
@IsNotEmpty({ message: 'Refresh token is required' })
refreshToken: string;
}
@@ -1,17 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsNotEmpty, IsString, IsMobilePhone } from 'class-validator';
@InputType()
export class RequestOtpInput {
@Field(() => String, { description: 'Mobile number' })
@IsNotEmpty()
@IsString()
@IsMobilePhone('fa-IR')
phone: string;
@Field(() => String, { description: 'Restaurant slug' })
@IsNotEmpty()
@IsString()
slug: string;
}
@@ -1,25 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsNotEmpty, IsString, Length, Matches } from 'class-validator';
@InputType()
export class VerifyOtpInput {
@Field(() => String, { description: 'Mobile number' })
@IsNotEmpty()
@IsString()
@Matches(/^09\d{9}$/, {
message: 'Mobile number must be a valid Iranian phone number (e.g., 09123456789)',
})
phone: string;
@Field(() => String, { description: 'OTP code' })
@IsNotEmpty()
@IsString()
@Length(5)
otp: string;
@Field(() => String, { description: 'Restaurant slug' })
@IsNotEmpty()
@IsString()
slug: string;
}
@@ -1,37 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { TokenResponse } from './token-response.object';
import { RestaurantInfo } from './restaurant-info.object';
@ObjectType()
export class AdminInfo {
@Field(() => String)
id: string;
@Field(() => String, { nullable: true })
firstName?: string;
@Field(() => String, { nullable: true })
lastName?: string;
@Field(() => String)
phone: string;
@Field(() => String)
role: string;
@Field(() => [String])
permissions: string[];
@Field(() => RestaurantInfo, { nullable: true })
restaurant?: RestaurantInfo;
}
@ObjectType()
export class AdminAuthResponse {
@Field(() => TokenResponse)
tokens: TokenResponse;
@Field(() => AdminInfo)
admin: AdminInfo;
}
@@ -1,40 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
import { TokenResponse } from './token-response.object';
import { RestaurantInfo } from './restaurant-info.object';
@ObjectType()
export class UserInfo {
@Field(() => String)
id: string;
@Field(() => String)
firstName: string;
@Field(() => String, { nullable: true })
lastName?: string;
@Field(() => String)
phone: string;
@Field(() => Number)
wallet: number;
@Field(() => Number)
points: number;
@Field(() => Boolean, { nullable: true })
isActive?: boolean;
@Field(() => RestaurantInfo)
restaurant: RestaurantInfo;
}
@ObjectType()
export class AuthResponse {
@Field(() => TokenResponse)
tokens: TokenResponse;
@Field(() => UserInfo)
user: UserInfo;
}
@@ -1,8 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class OtpResponse {
@Field(() => String, { description: 'OTP code (for development/testing purposes)' })
code: string;
}
@@ -1,14 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class RestaurantInfo {
@Field(() => String)
id: string;
@Field(() => String)
name: string;
@Field(() => String)
slug: string;
}
@@ -1,20 +0,0 @@
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class TokenInfo {
@Field(() => String)
token: string;
@Field(() => Number)
expire: number;
}
@ObjectType()
export class TokenResponse {
@Field(() => TokenInfo)
accessToken: TokenInfo;
@Field(() => TokenInfo)
refreshToken: TokenInfo;
}
@@ -1,40 +0,0 @@
import { Resolver, Mutation, Args } from '@nestjs/graphql';
import { AuthService } from '../../services/auth.service';
import { RequestOtpInput } from '../inputs/request-otp.input';
import { VerifyOtpInput } from '../inputs/verify-otp.input';
import { RefreshTokenInput } from '../inputs/refresh-token.input';
import { OtpResponse } from '../objects/otp-response.object';
import { AdminAuthResponse } from '../objects/admin-auth-response.object';
import { TokenResponse } from '../objects/token-response.object';
import { Throttle } from '@nestjs/throttler';
import { RefreshTokenRateLimit } from 'src/common/decorators/rate-limit.decorator';
@Resolver()
export class AdminAuthResolver {
constructor(private readonly authService: AuthService) {}
@Throttle({ default: { limit: 3, ttl: 180_000 } })
@Mutation(() => OtpResponse, {
description: 'Request OTP for admin login',
})
async adminRequestOtp(@Args('input') input: RequestOtpInput): Promise<OtpResponse> {
const code = await this.authService.requestOtpAdmin(input);
return { code };
}
@Mutation(() => AdminAuthResponse, {
description: 'Verify OTP code for admin login',
})
async adminVerifyOtp(@Args('input') input: VerifyOtpInput): Promise<AdminAuthResponse> {
return this.authService.verifyOtpAdmin(input.phone, input.slug, input.otp);
}
@RefreshTokenRateLimit()
@Mutation(() => TokenResponse, {
description: 'Refresh the admin access token and refresh token',
})
async adminRefreshToken(@Args('input') input: RefreshTokenInput): Promise<TokenResponse> {
return this.authService.refreshTokenAdmin(input.refreshToken);
}
}
@@ -1,45 +0,0 @@
import { Resolver, Mutation, Query, Args } from '@nestjs/graphql';
import { AuthService } from '../../services/auth.service';
import { RequestOtpInput } from '../inputs/request-otp.input';
import { VerifyOtpInput } from '../inputs/verify-otp.input';
import { RefreshTokenInput } from '../inputs/refresh-token.input';
import { OtpResponse } from '../objects/otp-response.object';
import { AuthResponse } from '../objects/auth-response.object';
import { TokenResponse } from '../objects/token-response.object';
import { Throttle } from '@nestjs/throttler';
import { RefreshTokenRateLimit } from 'src/common/decorators/rate-limit.decorator';
@Resolver()
export class AuthResolver {
constructor(private readonly authService: AuthService) {}
@Query(() => String, {
description: 'Health check query',
})
async health(): Promise<string> {
return 'OK';
}
@Throttle({ default: { limit: 3, ttl: 180_000 } })
@Mutation(() => OtpResponse, {
description: 'Request OTP for login or signup',
})
async requestOtp(@Args('input') input: RequestOtpInput): Promise<OtpResponse> {
return this.authService.requestOtp(input);
}
@Mutation(() => AuthResponse, {
description: 'Verify OTP code',
})
async verifyOtp(@Args('input') input: VerifyOtpInput): Promise<AuthResponse> {
return this.authService.verifyOtp(input.phone, input.slug, input.otp);
}
@RefreshTokenRateLimit()
@Mutation(() => TokenResponse, {
description: 'Refresh the user access token and refresh token',
})
async refreshToken(@Args('input') input: RefreshTokenInput): Promise<TokenResponse> {
return this.authService.refreshToken(input.refreshToken);
}
}
@@ -0,0 +1,68 @@
import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common';
import { PaymentMethodService } from '../services/payment-method.service';
import { CreatePaymentMethodDto } from '../dto/create-payment-method.dto';
import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiCreatedResponse,
ApiOkResponse,
ApiNotFoundResponse,
ApiBody,
ApiParam,
ApiBearerAuth,
} from '@nestjs/swagger';
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@ApiTags('admin/payment-methods')
@Controller('admin/payment-methods')
export class PaymentMethodController {
constructor(private readonly paymentMethodService: PaymentMethodService) {}
@Post()
@ApiOperation({ summary: 'Create a new payment method' })
@ApiBody({ type: CreatePaymentMethodDto })
@ApiCreatedResponse({ description: 'Payment method created successfully' })
create(@Body() createPaymentMethodDto: CreatePaymentMethodDto) {
return this.paymentMethodService.create(createPaymentMethodDto);
}
@Get()
@ApiOperation({ summary: 'Get all payment methods' })
@ApiOkResponse({ description: 'List of all payment methods' })
findAll() {
return this.paymentMethodService.findAll();
}
@Get(':id')
@ApiOperation({ summary: 'Get a payment method by ID' })
@ApiParam({ name: 'id', type: 'string', description: 'Payment method ID' })
@ApiOkResponse({ description: 'Payment method found' })
@ApiNotFoundResponse({ description: 'Payment method not found' })
findOne(@Param('id') id: string) {
return this.paymentMethodService.findOne(id);
}
@Patch(':id')
@ApiOperation({ summary: 'Update a payment method' })
@ApiParam({ name: 'id', type: 'string', description: 'Payment method ID' })
@ApiBody({ type: UpdatePaymentMethodDto })
@ApiOkResponse({ description: 'Payment method updated successfully' })
@ApiNotFoundResponse({ description: 'Payment method not found' })
update(@Param('id') id: string, @Body() updatePaymentMethodDto: UpdatePaymentMethodDto) {
return this.paymentMethodService.update(id, updatePaymentMethodDto);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a payment method' })
@ApiParam({ name: 'id', type: 'string', description: 'Payment method ID' })
@ApiOkResponse({ description: 'Payment method deleted successfully' })
@ApiNotFoundResponse({ description: 'Payment method not found' })
remove(@Param('id') id: string) {
return this.paymentMethodService.remove(id);
}
}
@@ -0,0 +1,68 @@
import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common';
import { PaymentsService } from '../services/payments.service';
import { CreatePaymentDto } from '../dto/create-payment.dto';
import { UpdatePaymentDto } from '../dto/update-payment.dto';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiCreatedResponse,
ApiOkResponse,
ApiNotFoundResponse,
ApiBody,
ApiParam,
ApiBearerAuth,
} from '@nestjs/swagger';
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@ApiTags('admin/payments')
@Controller('admin/payments')
export class PaymentsController {
constructor(private readonly paymentsService: PaymentsService) {}
@Post()
@ApiOperation({ summary: 'Create a new payment' })
@ApiBody({ type: CreatePaymentDto })
@ApiCreatedResponse({ description: 'Payment created successfully' })
create(@Body() createPaymentDto: CreatePaymentDto) {
return this.paymentsService.create(createPaymentDto);
}
@Get()
@ApiOperation({ summary: 'Get all payments' })
@ApiOkResponse({ description: 'List of all payments' })
findAll() {
return this.paymentsService.findAll();
}
@Get(':id')
@ApiOperation({ summary: 'Get a payment by ID' })
@ApiParam({ name: 'id', type: 'number', description: 'Payment ID' })
@ApiOkResponse({ description: 'Payment found' })
@ApiNotFoundResponse({ description: 'Payment not found' })
findOne(@Param('id') id: string) {
return this.paymentsService.findOne(+id);
}
@Patch(':id')
@ApiOperation({ summary: 'Update a payment' })
@ApiParam({ name: 'id', type: 'number', description: 'Payment ID' })
@ApiBody({ type: UpdatePaymentDto })
@ApiOkResponse({ description: 'Payment updated successfully' })
@ApiNotFoundResponse({ description: 'Payment not found' })
update(@Param('id') id: string, @Body() updatePaymentDto: UpdatePaymentDto) {
return this.paymentsService.update(+id, updatePaymentDto);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a payment' })
@ApiParam({ name: 'id', type: 'number', description: 'Payment ID' })
@ApiOkResponse({ description: 'Payment deleted successfully' })
@ApiNotFoundResponse({ description: 'Payment not found' })
remove(@Param('id') id: string) {
return this.paymentsService.remove(+id);
}
}
@@ -0,0 +1,85 @@
import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common';
import { RestaurantPaymentMethodService } from '../services/restaurant-payment-method.service';
import { CreateRestaurantPaymentMethodDto } from '../dto/create-restaurant-payment-method.dto';
import { UpdateRestaurantPaymentMethodDto } from '../dto/update-restaurant-payment-method.dto';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiCreatedResponse,
ApiOkResponse,
ApiNotFoundResponse,
ApiBody,
ApiParam,
ApiQuery,
ApiBearerAuth,
} from '@nestjs/swagger';
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
@UseGuards(AdminAuthGuard)
@ApiBearerAuth()
@ApiTags('admin/restaurant-payment-methods')
@Controller('admin/restaurant-payment-methods')
export class RestaurantPaymentMethodController {
constructor(private readonly restaurantPaymentMethodService: RestaurantPaymentMethodService) {}
@Post()
@ApiOperation({ summary: 'Create a new restaurant payment method' })
@ApiBody({ type: CreateRestaurantPaymentMethodDto })
@ApiCreatedResponse({ description: 'Restaurant payment method created successfully' })
create(@Body() createRestaurantPaymentMethodDto: CreateRestaurantPaymentMethodDto) {
return this.restaurantPaymentMethodService.create(createRestaurantPaymentMethodDto);
}
@Get()
@ApiOperation({ summary: 'Get all restaurant payment methods' })
@ApiOkResponse({ description: 'List of all restaurant payment methods' })
findAll() {
return this.restaurantPaymentMethodService.findAll();
}
@Get('by-restaurant/:restaurantId')
@ApiOperation({ summary: 'Get restaurant payment methods by restaurant ID' })
@ApiParam({ name: 'restaurantId', type: 'string', description: 'Restaurant ID' })
@ApiOkResponse({ description: 'List of restaurant payment methods for the restaurant' })
findByRestaurant(@Param('restaurantId') restaurantId: string) {
return this.restaurantPaymentMethodService.findByRestaurant(restaurantId);
}
@Get('by-payment-method/:paymentMethodId')
@ApiOperation({ summary: 'Get restaurant payment methods by payment method ID' })
@ApiParam({ name: 'paymentMethodId', type: 'string', description: 'Payment method ID' })
@ApiOkResponse({ description: 'List of restaurant payment methods for the payment method' })
findByPaymentMethod(@Param('paymentMethodId') paymentMethodId: string) {
return this.restaurantPaymentMethodService.findByPaymentMethod(paymentMethodId);
}
@Get(':id')
@ApiOperation({ summary: 'Get a restaurant payment method by ID' })
@ApiParam({ name: 'id', type: 'string', description: 'Restaurant payment method ID' })
@ApiOkResponse({ description: 'Restaurant payment method found' })
@ApiNotFoundResponse({ description: 'Restaurant payment method not found' })
findOne(@Param('id') id: string) {
return this.restaurantPaymentMethodService.findOne(id);
}
@Patch(':id')
@ApiOperation({ summary: 'Update a restaurant payment method' })
@ApiParam({ name: 'id', type: 'string', description: 'Restaurant payment method ID' })
@ApiBody({ type: UpdateRestaurantPaymentMethodDto })
@ApiOkResponse({ description: 'Restaurant payment method updated successfully' })
@ApiNotFoundResponse({ description: 'Restaurant payment method not found' })
update(@Param('id') id: string, @Body() updateRestaurantPaymentMethodDto: UpdateRestaurantPaymentMethodDto) {
return this.restaurantPaymentMethodService.update(id, updateRestaurantPaymentMethodDto);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a restaurant payment method' })
@ApiParam({ name: 'id', type: 'string', description: 'Restaurant payment method ID' })
@ApiOkResponse({ description: 'Restaurant payment method deleted successfully' })
@ApiNotFoundResponse({ description: 'Restaurant payment method not found' })
remove(@Param('id') id: string) {
return this.restaurantPaymentMethodService.remove(id);
}
}
@@ -0,0 +1,29 @@
import { IsString, IsOptional, IsBoolean, IsNumber } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreatePaymentMethodDto {
@ApiProperty({ description: 'Payment method name' })
@IsString()
name!: string;
@ApiProperty({ description: 'Payment method description', required: false })
@IsOptional()
@IsString()
description?: string;
@ApiProperty({ description: 'Payment method icon', required: false })
@IsOptional()
@IsString()
icon?: string;
@ApiProperty({ description: 'Is payment method active', required: false, default: true })
@IsOptional()
@IsBoolean()
isActive?: boolean;
@ApiProperty({ description: 'Display order', required: false })
@IsOptional()
@IsNumber()
order?: number;
}
@@ -1,19 +0,0 @@
import { InputType, Field, Int } from '@nestjs/graphql';
@InputType()
export class CreatePaymentMethodInput {
@Field()
name!: string;
@Field({ nullable: true })
description?: string;
@Field({ nullable: true })
icon?: string;
@Field(() => Boolean, { nullable: true, defaultValue: true })
isActive?: boolean;
@Field(() => Int, { nullable: true })
order?: number;
}
@@ -0,0 +1,9 @@
import { IsNumber } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreatePaymentDto {
@ApiProperty({ description: 'Example field (placeholder)' })
@IsNumber()
exampleField: number;
}
@@ -1,7 +0,0 @@
import { InputType, Int, Field } from '@nestjs/graphql';
@InputType()
export class CreatePaymentInput {
@Field(() => Int, { description: 'Example field (placeholder)' })
exampleField: number;
}
@@ -0,0 +1,23 @@
import { IsString, IsOptional, IsBoolean } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateRestaurantPaymentMethodDto {
@ApiProperty({ description: 'Restaurant ID' })
@IsString()
restaurantId!: string;
@ApiProperty({ description: 'Payment method ID' })
@IsString()
paymentMethodId!: string;
@ApiProperty({ description: 'Merchant ID', required: false })
@IsOptional()
@IsString()
merchantId?: string;
@ApiProperty({ description: 'Is active', required: false, default: true })
@IsOptional()
@IsBoolean()
isActive?: boolean;
}
@@ -1,16 +0,0 @@
import { InputType, Field } from '@nestjs/graphql';
@InputType()
export class CreateRestaurantPaymentMethodInput {
@Field()
restaurantId!: string;
@Field()
paymentMethodId!: string;
@Field({ nullable: true })
merchantId?: string;
@Field({ nullable: true })
isActive?: boolean;
}
@@ -0,0 +1,11 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreatePaymentMethodDto } from './create-payment-method.dto';
import { IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class UpdatePaymentMethodDto extends PartialType(CreatePaymentMethodDto) {
@ApiProperty({ description: 'Payment method ID' })
@IsString()
id!: string;
}
@@ -1,8 +0,0 @@
import { CreatePaymentMethodInput } from './create-payment-method.input';
import { InputType, Field, PartialType } from '@nestjs/graphql';
@InputType()
export class UpdatePaymentMethodInput extends PartialType(CreatePaymentMethodInput) {
@Field()
id!: string;
}
@@ -0,0 +1,11 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreatePaymentDto } from './create-payment.dto';
import { IsNumber } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class UpdatePaymentDto extends PartialType(CreatePaymentDto) {
@ApiProperty({ description: 'Payment ID' })
@IsNumber()
id: number;
}
@@ -1,8 +0,0 @@
import { CreatePaymentInput } from './create-payment.input';
import { InputType, Field, Int, PartialType } from '@nestjs/graphql';
@InputType()
export class UpdatePaymentInput extends PartialType(CreatePaymentInput) {
@Field(() => Int)
id: number;
}
@@ -0,0 +1,11 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateRestaurantPaymentMethodDto } from './create-restaurant-payment-method.dto';
import { IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class UpdateRestaurantPaymentMethodDto extends PartialType(CreateRestaurantPaymentMethodDto) {
@ApiProperty({ description: 'Restaurant payment method ID' })
@IsString()
id!: string;
}
@@ -1,8 +0,0 @@
import { CreateRestaurantPaymentMethodInput } from './create-restaurant-payment-method.input';
import { InputType, Field, PartialType } from '@nestjs/graphql';
@InputType()
export class UpdateRestaurantPaymentMethodInput extends PartialType(CreateRestaurantPaymentMethodInput) {
@Field()
id!: string;
}
@@ -1,31 +1,23 @@
import { Entity, Property } from '@mikro-orm/core';
import { BaseEntity } from '../../../common/entities/base.entity';
import { ObjectType, Field, Int } from '@nestjs/graphql';
@ObjectType()
@Entity({ tableName: 'payment_methods' })
export class PaymentMethod extends BaseEntity {
@Field()
@Property()
name!: string;
@Field()
@Property()
keyName!: string;
@Field({ nullable: true })
@Property({ nullable: true })
description?: string;
@Field({ nullable: true })
@Property({ nullable: true })
icon?: string;
@Field(() => Boolean)
@Property({ default: true })
isActive: boolean = true;
@Field(() => Int, { nullable: true })
@Property({ type: 'int', nullable: true })
order?: number;
}
@@ -1,7 +1,3 @@
import { ObjectType, Field, Int } from '@nestjs/graphql';
@ObjectType()
export class Payment {
@Field(() => Int, { description: 'Example field (placeholder)' })
exampleField: number;
}
@@ -2,25 +2,20 @@ import { Entity, ManyToOne, Unique, Property } from '@mikro-orm/core';
import { BaseEntity } from '../../../common/entities/base.entity';
import { Restaurant } from '../../restaurants/entities/restaurant.entity';
import { PaymentMethod } from './payment-method.entity';
import { ObjectType, Field } from '@nestjs/graphql';
@ObjectType()
@Entity({ tableName: 'restaurant_payment_methods' })
@Unique({ properties: ['restaurant', 'paymentMethod'] })
export class RestaurantPaymentMethod extends BaseEntity {
@ManyToOne(() => Restaurant)
restaurant!: Restaurant;
@Field(() => PaymentMethod, { nullable: true })
@ManyToOne(() => PaymentMethod)
paymentMethod!: PaymentMethod;
// Add merchant ID for payment gateway providers (e.g., ZarinPal)
@Field({ nullable: true })
@Property({ nullable: true })
merchantId?: string;
@Field({ nullable: true })
@Property({ type: 'boolean', default: true })
isActive: boolean = true;
}
+7 -7
View File
@@ -1,26 +1,26 @@
import { Module } from '@nestjs/common';
import { PaymentsService } from './services/payments.service';
import { PaymentsResolver } from './resolvers/payments.resolver';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { PaymentMethod } from './entities/payment-method.entity';
import { PaymentMethodRepository } from './repositories/payment-method.repository';
import { PaymentMethodService } from './services/payment-method.service';
import { PaymentMethodResolver } from './resolvers/payment-method.resolver';
import { RestaurantPaymentMethod } from './entities/restaurant-payment-method.entity';
import { RestaurantPaymentMethodRepository } from './repositories/restaurant-payment-method.repository';
import { RestaurantPaymentMethodService } from './services/restaurant-payment-method.service';
import { RestaurantPaymentMethodResolver } from './resolvers/restaurant-payment-method.resolver';
import { Restaurant } from '../restaurants/entities/restaurant.entity';
import { PaymentsController } from './controllers/payments.controller';
import { PaymentMethodController } from './controllers/payment-method.controller';
import { RestaurantPaymentMethodController } from './controllers/restaurant-payment-method.controller';
import { AuthModule } from '../auth/auth.module';
import { JwtModule } from '@nestjs/jwt';
@Module({
imports: [MikroOrmModule.forFeature([PaymentMethod, RestaurantPaymentMethod, Restaurant])],
imports: [MikroOrmModule.forFeature([PaymentMethod, RestaurantPaymentMethod, Restaurant]), AuthModule, JwtModule],
controllers: [PaymentsController, PaymentMethodController, RestaurantPaymentMethodController],
providers: [
PaymentsResolver,
PaymentsService,
PaymentMethodResolver,
PaymentMethodService,
PaymentMethodRepository,
RestaurantPaymentMethodResolver,
RestaurantPaymentMethodService,
RestaurantPaymentMethodRepository,
],
@@ -1,35 +0,0 @@
import { Resolver, Query, Mutation, Args, ID } from '@nestjs/graphql';
import { PaymentMethodService } from '../services/payment-method.service';
import { PaymentMethod } from '../entities/payment-method.entity';
import { CreatePaymentMethodInput } from '../dto/create-payment-method.input';
import { UpdatePaymentMethodInput } from '../dto/update-payment-method.input';
@Resolver(() => PaymentMethod)
export class PaymentMethodResolver {
constructor(private readonly paymentMethodService: PaymentMethodService) {}
@Mutation(() => PaymentMethod)
createPaymentMethod(@Args('createPaymentMethodInput') createPaymentMethodInput: CreatePaymentMethodInput) {
return this.paymentMethodService.create(createPaymentMethodInput);
}
@Query(() => [PaymentMethod], { name: 'paymentMethods' })
findAll() {
return this.paymentMethodService.findAll();
}
@Query(() => PaymentMethod, { name: 'paymentMethod' })
findOne(@Args('id', { type: () => ID }) id: string) {
return this.paymentMethodService.findOne(id);
}
@Mutation(() => PaymentMethod)
updatePaymentMethod(@Args('updatePaymentMethodInput') updatePaymentMethodInput: UpdatePaymentMethodInput) {
return this.paymentMethodService.update(updatePaymentMethodInput.id, updatePaymentMethodInput);
}
@Mutation(() => PaymentMethod)
removePaymentMethod(@Args('id', { type: () => ID }) id: string) {
return this.paymentMethodService.remove(id);
}
}
@@ -1,35 +0,0 @@
import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql';
import { PaymentsService } from '../services/payments.service';
import { Payment } from '../entities/payment.entity';
import { CreatePaymentInput } from '../dto/create-payment.input';
import { UpdatePaymentInput } from '../dto/update-payment.input';
@Resolver(() => Payment)
export class PaymentsResolver {
constructor(private readonly paymentsService: PaymentsService) {}
@Mutation(() => Payment)
createPayment(@Args('createPaymentInput') createPaymentInput: CreatePaymentInput) {
return this.paymentsService.create(createPaymentInput);
}
@Query(() => [Payment], { name: 'payments' })
findAll() {
return this.paymentsService.findAll();
}
@Query(() => Payment, { name: 'payment' })
findOne(@Args('id', { type: () => Int }) id: number) {
return this.paymentsService.findOne(id);
}
@Mutation(() => Payment)
updatePayment(@Args('updatePaymentInput') updatePaymentInput: UpdatePaymentInput) {
return this.paymentsService.update(updatePaymentInput.id, updatePaymentInput);
}
@Mutation(() => Payment)
removePayment(@Args('id', { type: () => Int }) id: number) {
return this.paymentsService.remove(id);
}
}
@@ -1,52 +0,0 @@
import { Resolver, Query, Mutation, Args, ID } from '@nestjs/graphql';
import { RestaurantPaymentMethodService } from '../services/restaurant-payment-method.service';
import { RestaurantPaymentMethod } from '../entities/restaurant-payment-method.entity';
import { CreateRestaurantPaymentMethodInput } from '../dto/create-restaurant-payment-method.input';
import { UpdateRestaurantPaymentMethodInput } from '../dto/update-restaurant-payment-method.input';
@Resolver(() => RestaurantPaymentMethod)
export class RestaurantPaymentMethodResolver {
constructor(private readonly restaurantPaymentMethodService: RestaurantPaymentMethodService) {}
@Mutation(() => RestaurantPaymentMethod)
createRestaurantPaymentMethod(
@Args('createRestaurantPaymentMethodInput') createRestaurantPaymentMethodInput: CreateRestaurantPaymentMethodInput,
) {
return this.restaurantPaymentMethodService.create(createRestaurantPaymentMethodInput);
}
@Query(() => [RestaurantPaymentMethod], { name: 'restaurantPaymentMethods' })
findAll() {
return this.restaurantPaymentMethodService.findAll();
}
@Query(() => [RestaurantPaymentMethod], { name: 'restaurantPaymentMethodsByRestaurant' })
findByRestaurant(@Args('restaurantId', { type: () => ID }) restaurantId: string) {
return this.restaurantPaymentMethodService.findByRestaurant(restaurantId);
}
@Query(() => [RestaurantPaymentMethod], { name: 'restaurantPaymentMethodsByPaymentMethod' })
findByPaymentMethod(@Args('paymentMethodId', { type: () => ID }) paymentMethodId: string) {
return this.restaurantPaymentMethodService.findByPaymentMethod(paymentMethodId);
}
@Query(() => RestaurantPaymentMethod, { name: 'restaurantPaymentMethod' })
findOne(@Args('id', { type: () => ID }) id: string) {
return this.restaurantPaymentMethodService.findOne(id);
}
@Mutation(() => RestaurantPaymentMethod)
updateRestaurantPaymentMethod(
@Args('updateRestaurantPaymentMethodInput') updateRestaurantPaymentMethodInput: UpdateRestaurantPaymentMethodInput,
) {
return this.restaurantPaymentMethodService.update(
updateRestaurantPaymentMethodInput.id,
updateRestaurantPaymentMethodInput,
);
}
@Mutation(() => RestaurantPaymentMethod)
removeRestaurantPaymentMethod(@Args('id', { type: () => ID }) id: string) {
return this.restaurantPaymentMethodService.remove(id);
}
}
@@ -2,8 +2,8 @@ import { Injectable, NotFoundException } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql';
import { PaymentMethod } from '../entities/payment-method.entity';
import { PaymentMethodRepository } from '../repositories/payment-method.repository';
import { CreatePaymentMethodInput } from '../dto/create-payment-method.input';
import { UpdatePaymentMethodInput } from '../dto/update-payment-method.input';
import { CreatePaymentMethodDto } from '../dto/create-payment-method.dto';
import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto';
import { RequiredEntityData } from '@mikro-orm/core';
@Injectable()
@@ -13,9 +13,9 @@ export class PaymentMethodService {
private readonly em: EntityManager,
) {}
async create(createPaymentMethodInput: CreatePaymentMethodInput): Promise<PaymentMethod> {
async create(createPaymentMethodDto: CreatePaymentMethodDto): Promise<PaymentMethod> {
const paymentMethod = this.paymentMethodRepository.create(
createPaymentMethodInput as unknown as RequiredEntityData<PaymentMethod>,
createPaymentMethodDto as unknown as RequiredEntityData<PaymentMethod>,
);
await this.em.persistAndFlush(paymentMethod);
return paymentMethod;
@@ -33,9 +33,9 @@ export class PaymentMethodService {
return paymentMethod;
}
async update(id: string, updatePaymentMethodInput: UpdatePaymentMethodInput): Promise<PaymentMethod> {
async update(id: string, updatePaymentMethodDto: UpdatePaymentMethodDto): Promise<PaymentMethod> {
const paymentMethod = await this.findOne(id);
this.em.assign(paymentMethod, updatePaymentMethodInput);
this.em.assign(paymentMethod, updatePaymentMethodDto);
await this.em.flush();
return paymentMethod;
}
@@ -1,10 +1,10 @@
import { Injectable } from '@nestjs/common';
import { CreatePaymentInput } from '../dto/create-payment.input';
import { UpdatePaymentInput } from '../dto/update-payment.input';
import { CreatePaymentDto } from '../dto/create-payment.dto';
import { UpdatePaymentDto } from '../dto/update-payment.dto';
@Injectable()
export class PaymentsService {
create(createPaymentInput: CreatePaymentInput) {
create(createPaymentDto: CreatePaymentDto) {
return 'This action adds a new payment';
}
@@ -16,7 +16,7 @@ export class PaymentsService {
return `This action returns a #${id} payment`;
}
update(id: number, updatePaymentInput: UpdatePaymentInput) {
update(id: number, updatePaymentDto: UpdatePaymentDto) {
return `This action updates a #${id} payment`;
}
@@ -4,8 +4,8 @@ import { RestaurantPaymentMethod } from '../entities/restaurant-payment-method.e
import { RestaurantPaymentMethodRepository } from '../repositories/restaurant-payment-method.repository';
import { Restaurant } from '../../restaurants/entities/restaurant.entity';
import { PaymentMethod } from '../entities/payment-method.entity';
import { CreateRestaurantPaymentMethodInput } from '../dto/create-restaurant-payment-method.input';
import { UpdateRestaurantPaymentMethodInput } from '../dto/update-restaurant-payment-method.input';
import { CreateRestaurantPaymentMethodDto } from '../dto/create-restaurant-payment-method.dto';
import { UpdateRestaurantPaymentMethodDto } from '../dto/update-restaurant-payment-method.dto';
import { RequiredEntityData } from '@mikro-orm/core';
@Injectable()
@@ -16,24 +16,24 @@ export class RestaurantPaymentMethodService {
) {}
async create(
createRestaurantPaymentMethodInput: CreateRestaurantPaymentMethodInput,
createRestaurantPaymentMethodDto: CreateRestaurantPaymentMethodDto,
): Promise<RestaurantPaymentMethod> {
// Check if restaurant exists
const restaurant = await this.em.findOne(Restaurant, { id: createRestaurantPaymentMethodInput.restaurantId });
const restaurant = await this.em.findOne(Restaurant, { id: createRestaurantPaymentMethodDto.restaurantId });
if (!restaurant) {
throw new NotFoundException(`Restaurant with ID ${createRestaurantPaymentMethodInput.restaurantId} not found`);
throw new NotFoundException(`Restaurant with ID ${createRestaurantPaymentMethodDto.restaurantId} not found`);
}
// Check if payment method exists
const paymentMethod = await this.em.findOne(PaymentMethod, { id: createRestaurantPaymentMethodInput.paymentMethodId });
const paymentMethod = await this.em.findOne(PaymentMethod, { id: createRestaurantPaymentMethodDto.paymentMethodId });
if (!paymentMethod) {
throw new NotFoundException(`PaymentMethod with ID ${createRestaurantPaymentMethodInput.paymentMethodId} not found`);
throw new NotFoundException(`PaymentMethod with ID ${createRestaurantPaymentMethodDto.paymentMethodId} not found`);
}
// Check if the relationship already exists
const existing = await this.restaurantPaymentMethodRepository.findOne({
restaurant: { id: createRestaurantPaymentMethodInput.restaurantId },
paymentMethod: { id: createRestaurantPaymentMethodInput.paymentMethodId },
restaurant: { id: createRestaurantPaymentMethodDto.restaurantId },
paymentMethod: { id: createRestaurantPaymentMethodDto.paymentMethodId },
});
if (existing) {
@@ -43,8 +43,8 @@ export class RestaurantPaymentMethodService {
const restaurantPaymentMethod = this.restaurantPaymentMethodRepository.create({
restaurant,
paymentMethod,
merchantId: createRestaurantPaymentMethodInput.merchantId,
isActive: createRestaurantPaymentMethodInput.isActive ?? true,
merchantId: createRestaurantPaymentMethodDto.merchantId,
isActive: createRestaurantPaymentMethodDto.isActive ?? true,
} as unknown as RequiredEntityData<RestaurantPaymentMethod>);
await this.em.persistAndFlush(restaurantPaymentMethod);
@@ -82,28 +82,28 @@ export class RestaurantPaymentMethodService {
async update(
id: string,
updateRestaurantPaymentMethodInput: UpdateRestaurantPaymentMethodInput,
updateRestaurantPaymentMethodDto: UpdateRestaurantPaymentMethodDto,
): Promise<RestaurantPaymentMethod> {
const restaurantPaymentMethod = await this.findOne(id);
if (updateRestaurantPaymentMethodInput.restaurantId) {
const restaurant = await this.em.findOne(Restaurant, { id: updateRestaurantPaymentMethodInput.restaurantId });
if (updateRestaurantPaymentMethodDto.restaurantId) {
const restaurant = await this.em.findOne(Restaurant, { id: updateRestaurantPaymentMethodDto.restaurantId });
if (!restaurant) {
throw new NotFoundException(`Restaurant with ID ${updateRestaurantPaymentMethodInput.restaurantId} not found`);
throw new NotFoundException(`Restaurant with ID ${updateRestaurantPaymentMethodDto.restaurantId} not found`);
}
restaurantPaymentMethod.restaurant = restaurant;
}
if (updateRestaurantPaymentMethodInput.paymentMethodId) {
const paymentMethod = await this.em.findOne(PaymentMethod, { id: updateRestaurantPaymentMethodInput.paymentMethodId });
if (updateRestaurantPaymentMethodDto.paymentMethodId) {
const paymentMethod = await this.em.findOne(PaymentMethod, { id: updateRestaurantPaymentMethodDto.paymentMethodId });
if (!paymentMethod) {
throw new NotFoundException(`PaymentMethod with ID ${updateRestaurantPaymentMethodInput.paymentMethodId} not found`);
throw new NotFoundException(`PaymentMethod with ID ${updateRestaurantPaymentMethodDto.paymentMethodId} not found`);
}
// Check if the new relationship already exists
const existing = await this.restaurantPaymentMethodRepository.findOne({
restaurant: { id: restaurantPaymentMethod.restaurant.id },
paymentMethod: { id: updateRestaurantPaymentMethodInput.paymentMethodId },
paymentMethod: { id: updateRestaurantPaymentMethodDto.paymentMethodId },
});
if (existing && existing.id !== id) {
@@ -114,12 +114,12 @@ export class RestaurantPaymentMethodService {
}
// Update merchantId and isActive if provided
if (updateRestaurantPaymentMethodInput.merchantId !== undefined) {
restaurantPaymentMethod.merchantId = updateRestaurantPaymentMethodInput.merchantId;
if (updateRestaurantPaymentMethodDto.merchantId !== undefined) {
restaurantPaymentMethod.merchantId = updateRestaurantPaymentMethodDto.merchantId;
}
if (updateRestaurantPaymentMethodInput.isActive !== undefined) {
restaurantPaymentMethod.isActive = updateRestaurantPaymentMethodInput.isActive;
if (updateRestaurantPaymentMethodDto.isActive !== undefined) {
restaurantPaymentMethod.isActive = updateRestaurantPaymentMethodDto.isActive;
}
await this.em.flush();