Initial commit: LACA parking management system
This commit is contained in:
34
backend/src/common/auth/decorators.ts
Normal file
34
backend/src/common/auth/decorators.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
createParamDecorator,
|
||||
ExecutionContext,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { JwtAccessTokenPayload } from './type';
|
||||
|
||||
export type AuthUserPayloadType = JwtAccessTokenPayload;
|
||||
|
||||
export const AuthUser = createParamDecorator(
|
||||
async (_: unknown, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
const user = request.user;
|
||||
return user;
|
||||
},
|
||||
);
|
||||
|
||||
export const AuthTenant = createParamDecorator(
|
||||
async (_: unknown, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
const user = request.user;
|
||||
if (user.type !== 'tenant') throw new UnauthorizedException();
|
||||
return user;
|
||||
},
|
||||
);
|
||||
|
||||
export const AuthAdmin = createParamDecorator(
|
||||
async (_: unknown, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
const user = request.user;
|
||||
if (user.type !== 'admin') throw new UnauthorizedException();
|
||||
return user;
|
||||
},
|
||||
);
|
||||
20
backend/src/common/auth/type.ts
Normal file
20
backend/src/common/auth/type.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export enum eUserType {
|
||||
USER,
|
||||
TENANT,
|
||||
ADMIN,
|
||||
}
|
||||
|
||||
export type TokenUserType = eUserType.ADMIN | eUserType.TENANT | eUserType.USER;
|
||||
|
||||
export type JwtAccessTokenPayload = {
|
||||
id: number;
|
||||
roleId: number;
|
||||
tokenId: string;
|
||||
type: TokenUserType;
|
||||
};
|
||||
|
||||
export type JwtRefreshTokenPayload = {
|
||||
id: number;
|
||||
tokenId: string;
|
||||
type: TokenUserType;
|
||||
};
|
||||
57
backend/src/common/dto/search.ts
Normal file
57
backend/src/common/dto/search.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { ApiExtraModels, ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsNumber, IsOptional, IsString, Max, Min } from 'class-validator';
|
||||
|
||||
export enum Order {
|
||||
Desc = 'DESC',
|
||||
Asc = 'ASC',
|
||||
}
|
||||
|
||||
@ApiExtraModels()
|
||||
export class PagingReqDto {
|
||||
@ApiProperty({ example: 'abc', required: false, type: String })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
search? = '';
|
||||
|
||||
@ApiProperty({ example: 20, required: false, type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@Max(100)
|
||||
@Type(() => Number)
|
||||
pageSize = 10;
|
||||
|
||||
@ApiProperty({ example: 20, required: false, type: Number })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@Min(1)
|
||||
pageNumber = 1;
|
||||
|
||||
@ApiProperty({
|
||||
name: 'sort',
|
||||
type: 'object',
|
||||
additionalProperties: { type: 'string' },
|
||||
description: 'Data object with key-value pairs',
|
||||
required: false,
|
||||
example: {
|
||||
created_at: 'asc',
|
||||
},
|
||||
})
|
||||
@IsOptional()
|
||||
sort: Record<string, string> = {
|
||||
created_at: 'asc',
|
||||
};
|
||||
}
|
||||
|
||||
export class PagingRes {
|
||||
@ApiProperty({ example: 100 })
|
||||
pages: number;
|
||||
|
||||
@ApiProperty({ example: 1000 })
|
||||
count: number;
|
||||
|
||||
@ApiProperty({ example: 5 })
|
||||
pageNumber: number;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
ExecutionContext,
|
||||
CallHandler,
|
||||
Logger,
|
||||
HttpException,
|
||||
} from '@nestjs/common';
|
||||
import { Observable, catchError } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class TransformErrorInterceptor implements NestInterceptor {
|
||||
private readonly logger = new Logger(TransformErrorInterceptor.name);
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
||||
// next.handle() is an Observable of the controller's result value
|
||||
return next.handle().pipe(
|
||||
catchError((error) => {
|
||||
const response = error.response || {};
|
||||
const { statusCode, message } = response;
|
||||
throw new HttpException(
|
||||
{
|
||||
status: statusCode,
|
||||
code: error['code'],
|
||||
details: {
|
||||
type: 'error',
|
||||
message: message,
|
||||
},
|
||||
},
|
||||
statusCode,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
ExecutionContext,
|
||||
CallHandler,
|
||||
StreamableFile,
|
||||
} from '@nestjs/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { DEFAULT_SUCCESS_MSG } from 'src/share/constans';
|
||||
|
||||
export interface Response<T> {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class TransformResponseInterceptor<T>
|
||||
implements NestInterceptor<T, Response<T> | StreamableFile>
|
||||
{
|
||||
intercept(
|
||||
context: ExecutionContext,
|
||||
next: CallHandler,
|
||||
): Observable<Response<any> | StreamableFile> {
|
||||
return next.handle().pipe(
|
||||
map((data) => {
|
||||
if (data instanceof StreamableFile) {
|
||||
return data;
|
||||
}
|
||||
return {
|
||||
statusCode:
|
||||
<number>data?.statusCode ||
|
||||
<number>context.switchToHttp().getResponse().statusCode,
|
||||
message: <string>data?.message || DEFAULT_SUCCESS_MSG,
|
||||
data: data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
28
backend/src/common/interceptor/uid.interceptor.ts
Normal file
28
backend/src/common/interceptor/uid.interceptor.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import {
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
ExecutionContext,
|
||||
CallHandler,
|
||||
StreamableFile,
|
||||
} from '@nestjs/common';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface Response<T> {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UUIDRequestInterceptor<T>
|
||||
implements NestInterceptor<T, Response<T> | StreamableFile>
|
||||
{
|
||||
intercept(
|
||||
context: ExecutionContext,
|
||||
next: CallHandler,
|
||||
): Observable<Response<any> | StreamableFile> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
request.headers['x-request-id'] = 'asf';
|
||||
return next.handle();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user