transform core api codes into this project, update modules as admin/pos context modules

This commit is contained in:
2026-03-07 11:25:11 +03:30
parent b949500482
commit 8c5f1d4d49
167 changed files with 26975 additions and 1837 deletions
+11
View File
@@ -0,0 +1,11 @@
export default {
COUNT: 'تعداد',
GRAM: 'گرم',
KILO_GRAM: 'کیلوگرم',
LITER: 'لیتر',
MILLILITER: 'میلی‌لیتر',
STANDARD: 'استاندارد',
GOLD: 'طلا',
ACTIVE: 'فعال',
SUSPENDED: 'غیرفعال',
}
@@ -0,0 +1,5 @@
import enums from './enums'
export default {
enums,
}
+1 -1
View File
@@ -1,5 +1,5 @@
// src/common/database/transaction.helper.ts
import { PrismaService } from '../../prisma/prisma.service'
import { PrismaService } from '@/prisma/prisma.service'
export async function withTransaction<T>(
prisma: PrismaService,
+10 -10
View File
@@ -1,18 +1,18 @@
export enum TokenType {
ACCESS,
REFRESH,
ACCESS = 'ACCESS',
REFRESH = 'REFRESH',
}
export enum AccountType {
PARTNER,
BUSINESS,
ADMIN,
PROVIDER,
POS,
PARTNER = 'PARTNER',
BUSINESS = 'BUSINESS',
ADMIN = 'ADMIN',
PROVIDER = 'PROVIDER',
POS = 'POS',
}
export enum GoldKarat {
KARAT_18 = 18,
KARAT_21 = 21,
KARAT_24 = 24,
KARAT_18 = '18',
KARAT_21 = '21',
KARAT_24 = '24',
}
@@ -6,7 +6,7 @@ import {
HttpStatus,
} from '@nestjs/common'
import type { Request, Response } from 'express'
import { Prisma } from '../../generated/prisma/client'
import { Prisma } from 'generated/prisma/client'
@Catch()
export class PrismaExceptionFilter implements ExceptionFilter {
+57
View File
@@ -0,0 +1,57 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common'
import { Reflector } from '@nestjs/core'
import { JwtService } from '@nestjs/jwt'
import { IS_PUBLIC_KEY } from '../decorators/public.decorator'
import { IWithJWTPayloadRequest } from '../models/token-model'
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(
private jwt: JwtService,
private reflector: Reflector,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
])
if (isPublic) return true
const req = context.switchToHttp().getRequest<IWithJWTPayloadRequest>()
let token: string | undefined = req.cookies?.accessToken
if (!token) {
const authHeader = (req.headers.authorization || req.headers.Authorization) as
| string
| undefined
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.slice(7)
}
}
if (!token) throw new UnauthorizedException('Missing access token')
try {
const payload = this.jwt.verify(token, {
secret: process.env.JWT_SECRET || 'secret',
})
if (payload.type !== 'POS')
throw new UnauthorizedException('Invalid or expired token')
// Set the typed dataPayload to the request
req.dataPayload = payload
return true
} catch (err) {
console.log(err)
throw new UnauthorizedException('Invalid or expired token')
}
}
}
+59
View File
@@ -0,0 +1,59 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common'
import { Reflector } from '@nestjs/core'
import { JwtService } from '@nestjs/jwt'
import { IS_PUBLIC_KEY } from '../decorators/public.decorator'
import { IWithJWTPayloadRequest } from '../models/token-model'
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(
private jwt: JwtService,
private reflector: Reflector,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
console.log('asd')
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
])
if (isPublic) return true
const req = context.switchToHttp().getRequest<IWithJWTPayloadRequest>()
let token: string | undefined = req.cookies?.accessToken
if (!token) {
const authHeader = (req.headers.authorization || req.headers.Authorization) as
| string
| undefined
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.slice(7)
}
}
if (!token) throw new UnauthorizedException('Missing access token')
try {
const payload = this.jwt.verify(token, {
secret: process.env.JWT_SECRET || 'secret',
})
// if (payload.type !== 'POS')
// throw new UnauthorizedException('Invalid or expired token')
// Set the typed dataPayload to the request
req.dataPayload = payload
return true
} catch (err) {
console.log(err)
throw new UnauthorizedException('Invalid or expired token')
}
}
}
@@ -76,12 +76,12 @@ export class ResponseMappingInterceptor implements NestInterceptor {
break
case 'list':
payload = Array.isArray(wrapped.items) ? wrapped.items : []
meta = {
totalRecords: payload.length,
totalPages: 1,
page: 1,
perPage: payload.length,
}
// meta = {
// totalRecords: payload.length,
// totalPages: 1,
// page: 1,
// perPage: payload.length,
// }
break
case 'paginate': {
const items = Array.isArray(wrapped.items) ? wrapped.items : []
@@ -193,7 +193,7 @@ export class ResponseMappingInterceptor implements NestInterceptor {
}
}
if (meta)
if (meta || ['list', 'paginate'].includes((data as any).__mapped))
return {
data: data.items,
meta,
+15 -8
View File
@@ -5,10 +5,17 @@
* the global `ResponseMappingInterceptor` understands and normalizes.
*/
export type MapperWrapper<T> =
| { __mapped: 'create' | 'update' | 'single' | 'delete'; data: T }
| { __mapped: 'create' | 'update' | 'single'; data: T }
| { __mapped: 'list'; items: T[] }
| { __mapped: 'paginate'; items: T[]; total: number; page?: number; perPage?: number }
| { __mapped: 'paginate'; items: T[]; count: number; page?: number; pageSize?: number }
| { __mapped: 'sequelize'; rows: T[]; count: number; page?: number; perPage?: number }
| { __mapped: 'delete' }
interface IPaginateMeta {
count: number
page?: number
pageSize?: number
}
export const ResponseMapper = {
create<T>(item: T): MapperWrapper<T> {
@@ -23,20 +30,20 @@ export const ResponseMapper = {
return { __mapped: 'single', data: item }
},
delete<T>(item: T): MapperWrapper<T> {
return { __mapped: 'delete', data: item }
delete(): MapperWrapper<boolean> {
return { __mapped: 'delete' }
},
list<T>(items: T[]): MapperWrapper<T> {
return { __mapped: 'list', items }
},
paginate<T>(items: T[], total: number, page = 1, perPage = items.length) {
return { __mapped: 'paginate', items, total, page, perPage }
paginate<T>(items: T[], { count, page = 1, pageSize: perPage }: IPaginateMeta) {
return { __mapped: 'paginate', items, count, page, perPage }
},
sequelizePaginate<T>(rows: T[], count: number, page = 1, perPage = rows.length) {
return { __mapped: 'sequelize', rows, count, page, perPage }
sequelizePaginate<T>(rows: T[], count: number, page = 1, pageSize = rows.length) {
return { __mapped: 'sequelize', rows, count, page, pageSize }
},
}
+30
View File
@@ -0,0 +1,30 @@
import { UnauthorizedException } from '@nestjs/common'
import { JwtService } from '@nestjs/jwt'
import { Request } from 'express'
import { AccessTokenPayload } from 'modules/auth/models'
export function getAccountIdFromJwt(req: Request, jwtService: JwtService): string | null {
// Try to get token from Authorization header
let token = req.cookies?.accessToken
if (!token) {
const authHeader = (req.headers.authorization || req.headers.Authorization) as
| string
| undefined
if (authHeader && authHeader.startsWith('Bearer ')) {
token = authHeader.slice(7)
}
}
if (!token) throw new UnauthorizedException('Missing accessToken cookie')
// const token = authHeader.replace('Bearer ', '')
try {
const payload = jwtService.decode(token) as AccessTokenPayload
console.log(payload)
return payload?.account_id || null
} catch {
return null
}
}
+11
View File
@@ -0,0 +1,11 @@
import * as bcrypt from 'bcrypt'
export class PasswordUtil {
static async hash(password: string, saltRounds = 10): Promise<string> {
return bcrypt.hash(password, saltRounds)
}
static async compare(password: string, hashedPassword: string): Promise<boolean> {
return bcrypt.compare(password, hashedPassword)
}
}