forked from Yara724/api
blame and claim refactored
This commit is contained in:
382
src/request-management/request-management.v2.controller.ts
Normal file
382
src/request-management/request-management.v2.controller.ts
Normal file
@@ -0,0 +1,382 @@
|
||||
import { extname } from "node:path";
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
Req,
|
||||
UploadedFile,
|
||||
UploadedFiles,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from "@nestjs/common";
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiBody,
|
||||
ApiConsumes,
|
||||
ApiParam,
|
||||
ApiTags,
|
||||
} from "@nestjs/swagger";
|
||||
import { FileFieldsInterceptor, FileInterceptor } from "@nestjs/platform-express";
|
||||
import { diskStorage } from "multer";
|
||||
import { Request } from "express";
|
||||
import { GlobalGuard } from "src/auth/guards/global.guard";
|
||||
import { RolesGuard } from "src/auth/guards/role.guard";
|
||||
import { Roles } from "src/decorators/roles.decorator";
|
||||
import { CurrentUser } from "src/decorators/user.decorator";
|
||||
import { RoleEnum } from "src/Types&Enums/role.enum";
|
||||
import { AddPlateDto } from "src/profile/dto/user/AddPlateDto";
|
||||
import {
|
||||
BlameConfessionDtoV2,
|
||||
CreateBlameRequestDtoV2,
|
||||
DescriptionDto,
|
||||
LocationDto,
|
||||
} from "./dto/create-request-management.dto";
|
||||
import { RequestManagementService } from "./request-management.service";
|
||||
|
||||
/**
|
||||
* V2 API surface for the redesigned `BlameRequest` model.
|
||||
*
|
||||
* Versioning strategy: prefix the controller route with `v2/` so
|
||||
* all endpoints under this controller are automatically V2.
|
||||
*/
|
||||
@Controller("v2/blame-request-management")
|
||||
@ApiTags("blame-request-management (v2)")
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(GlobalGuard, RolesGuard)
|
||||
@Roles(RoleEnum.USER)
|
||||
export class RequestManagementV2Controller {
|
||||
constructor(
|
||||
private readonly requestManagementService: RequestManagementService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
@UseGuards(GlobalGuard)
|
||||
async createRequestV2(
|
||||
@CurrentUser() user,
|
||||
@Body() createRequestDto: CreateBlameRequestDtoV2,
|
||||
) {
|
||||
return this.requestManagementService.createRequestV2(
|
||||
user,
|
||||
createRequestDto.type,
|
||||
);
|
||||
}
|
||||
|
||||
@Post("/blame-confession/:requestId")
|
||||
@ApiParam({ name: "requestId" })
|
||||
@ApiBody({ type: BlameConfessionDtoV2 })
|
||||
@UseGuards(GlobalGuard)
|
||||
async blameConfessionV2(
|
||||
@Param("requestId") requestId: string,
|
||||
@Body() body: BlameConfessionDtoV2,
|
||||
@CurrentUser() user,
|
||||
) {
|
||||
return this.requestManagementService.blameConfessionV2(requestId, body, user);
|
||||
}
|
||||
|
||||
@ApiBody({
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
file: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@UseInterceptors(
|
||||
FileInterceptor("file", {
|
||||
limits: {
|
||||
fileSize: 20 * 1024 * 1024,
|
||||
},
|
||||
storage: diskStorage({
|
||||
destination: "./files/video",
|
||||
filename: (req, file, callback) => {
|
||||
const unique = Date.now();
|
||||
const ex = extname(file.originalname);
|
||||
const filename = `${file.originalname}-${unique}${ex}`;
|
||||
callback(null, filename);
|
||||
},
|
||||
}),
|
||||
}),
|
||||
)
|
||||
@ApiParam({ name: "requestId" })
|
||||
@Post("upload-video/:requestId")
|
||||
@UseGuards(GlobalGuard)
|
||||
async uploadVideoV2(
|
||||
@Param("requestId") requestId: string,
|
||||
@CurrentUser() user,
|
||||
@UploadedFile() file?: Express.Multer.File,
|
||||
) {
|
||||
return this.requestManagementService.uploadFirstPartyVideoV2(
|
||||
requestId,
|
||||
file,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@Post("/initial-form/:requestId")
|
||||
@ApiParam({ name: "requestId" })
|
||||
@ApiBody({ type: AddPlateDto })
|
||||
@UseGuards(GlobalGuard)
|
||||
async initialFormV2(
|
||||
@Param("requestId") requestId: string,
|
||||
@Body() body: AddPlateDto,
|
||||
@CurrentUser() user,
|
||||
) {
|
||||
return this.requestManagementService.initialFormV2(requestId, body, user);
|
||||
}
|
||||
|
||||
@Post("/add-detail-location/:requestId")
|
||||
@ApiParam({ name: "requestId" })
|
||||
@ApiBody({ type: LocationDto })
|
||||
@UseGuards(GlobalGuard)
|
||||
async addLocationV2(
|
||||
@Param("requestId") requestId: string,
|
||||
@Body() body: LocationDto,
|
||||
@CurrentUser() user,
|
||||
) {
|
||||
return this.requestManagementService.addDetailLocationV2(requestId, body, user);
|
||||
}
|
||||
|
||||
@ApiBody({
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
file: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@UseInterceptors(
|
||||
FileInterceptor("file", {
|
||||
limits: {
|
||||
fileSize: 10 * 1024 * 1024,
|
||||
},
|
||||
storage: diskStorage({
|
||||
destination: "./files/voice",
|
||||
filename: (req, file, callback) => {
|
||||
const unique = Date.now();
|
||||
const ex = extname(file.originalname);
|
||||
const flname = file.originalname.split(".")[0];
|
||||
const filename = `${flname}-${unique}${ex}`;
|
||||
callback(null, filename);
|
||||
},
|
||||
}),
|
||||
}),
|
||||
)
|
||||
@ApiParam({ name: "requestId" })
|
||||
@Post("upload-voice/:requestId")
|
||||
@UseGuards(GlobalGuard)
|
||||
async uploadVoiceV2(
|
||||
@Param("requestId") requestId: string,
|
||||
@CurrentUser() user,
|
||||
@UploadedFile() voice?: Express.Multer.File,
|
||||
) {
|
||||
return this.requestManagementService.uploadVoiceV2(requestId, voice, user);
|
||||
}
|
||||
|
||||
@Post("/add-detail-description/:requestId")
|
||||
@ApiParam({ name: "requestId" })
|
||||
@ApiBody({ type: DescriptionDto })
|
||||
@UseGuards(GlobalGuard)
|
||||
async addDescriptionV2(
|
||||
@Param("requestId") requestId: string,
|
||||
@Body() body: DescriptionDto,
|
||||
@CurrentUser() user,
|
||||
) {
|
||||
return this.requestManagementService.addDescriptionV2(requestId, body, user);
|
||||
}
|
||||
|
||||
@Post("add-second-party/:phoneNumber/:requestId/:frontendRoute")
|
||||
@ApiParam({ name: "phoneNumber" })
|
||||
@ApiParam({ name: "requestId" })
|
||||
@ApiParam({ name: "frontendRoute" })
|
||||
@UseGuards(GlobalGuard)
|
||||
async addSecondPartyV2(
|
||||
@Param("phoneNumber") phoneNumber: string,
|
||||
@Param("requestId") requestId: string,
|
||||
@Param("frontendRoute") frontendRoute: string,
|
||||
@CurrentUser() user,
|
||||
) {
|
||||
return this.requestManagementService.addSecondPartyV2(
|
||||
requestId,
|
||||
phoneNumber,
|
||||
frontendRoute,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* V2: Get list of documents/items the current user needs to resend
|
||||
*/
|
||||
@Get("resend-requirements/:requestId")
|
||||
@ApiParam({ name: "requestId", description: "Blame request ID" })
|
||||
async getResendRequirements(
|
||||
@Param("requestId") requestId: string,
|
||||
@CurrentUser() user: any,
|
||||
) {
|
||||
return this.requestManagementService.getResendRequirementsV2(
|
||||
requestId,
|
||||
user.sub,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* V2: User signs/accepts or rejects expert decision
|
||||
*/
|
||||
@Put("sign/:requestId")
|
||||
@ApiParam({ name: "requestId", description: "Blame request ID" })
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@ApiBody({
|
||||
description: "Upload signature file and acceptance decision",
|
||||
schema: {
|
||||
type: "object",
|
||||
required: ["sign", "isAccept"],
|
||||
properties: {
|
||||
sign: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "Signature image file",
|
||||
},
|
||||
isAccept: {
|
||||
type: "boolean",
|
||||
description: "true to accept expert decision, false to reject",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@UseInterceptors(
|
||||
FileInterceptor("sign", {
|
||||
limits: {
|
||||
fileSize: 10 * 1024 * 1024, // 10MB
|
||||
},
|
||||
storage: diskStorage({
|
||||
destination: "./files/signs",
|
||||
filename: (req, file, callback) => {
|
||||
const unique = Date.now();
|
||||
const ext = extname(file.originalname);
|
||||
const filename = `${file.originalname.split(/[.,\s-]/)[0]}-${unique}${ext}`;
|
||||
callback(null, filename);
|
||||
},
|
||||
}),
|
||||
}),
|
||||
)
|
||||
async userSignDecision(
|
||||
@Param("requestId") requestId: string,
|
||||
@Body("isAccept") isAccept: string | boolean,
|
||||
@CurrentUser() user: any,
|
||||
@UploadedFile() sign: Express.Multer.File,
|
||||
) {
|
||||
// Convert string "true"/"false" to boolean
|
||||
const acceptDecision = typeof isAccept === "string"
|
||||
? isAccept === "true"
|
||||
: Boolean(isAccept);
|
||||
|
||||
return this.requestManagementService.userSignDecisionV2(
|
||||
requestId,
|
||||
user.sub,
|
||||
acceptDecision,
|
||||
sign,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* V2: Upload requested documents/evidence for resend
|
||||
* Field names must match ResendItemType enum values (e.g., drivingLicense, carCertificate, voice, video)
|
||||
*/
|
||||
@Put("resend/:requestId")
|
||||
@ApiParam({ name: "requestId", description: "Blame request ID" })
|
||||
@ApiConsumes("multipart/form-data")
|
||||
@ApiBody({
|
||||
description:
|
||||
"Upload files with field names matching requested items (e.g., drivingLicense, carCertificate, voice, video)",
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
drivingLicense: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "Driving license file (if requested)",
|
||||
},
|
||||
carCertificate: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "Car certificate file (if requested)",
|
||||
},
|
||||
nationalCertificate: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "National certificate file (if requested)",
|
||||
},
|
||||
carGreenCard: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "Car green card file (if requested)",
|
||||
},
|
||||
voice: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "Voice recording file (if requested)",
|
||||
},
|
||||
video: {
|
||||
type: "string",
|
||||
format: "binary",
|
||||
description: "Video file (if requested)",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@UseInterceptors(
|
||||
FileFieldsInterceptor(
|
||||
[
|
||||
{ name: "drivingLicense", maxCount: 1 },
|
||||
{ name: "carCertificate", maxCount: 1 },
|
||||
{ name: "nationalCertificate", maxCount: 1 },
|
||||
{ name: "carGreenCard", maxCount: 1 },
|
||||
{ name: "voice", maxCount: 1 },
|
||||
{ name: "video", maxCount: 1 },
|
||||
],
|
||||
{
|
||||
storage: diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, "./uploads");
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueSuffix =
|
||||
Date.now() + "-" + Math.round(Math.random() * 1e9);
|
||||
const ext = extname(file.originalname);
|
||||
cb(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
|
||||
},
|
||||
}),
|
||||
},
|
||||
),
|
||||
)
|
||||
async uploadResendDocuments(
|
||||
@Param("requestId") requestId: string,
|
||||
@CurrentUser() user: any,
|
||||
@UploadedFiles()
|
||||
files: {
|
||||
drivingLicense?: Express.Multer.File[];
|
||||
carCertificate?: Express.Multer.File[];
|
||||
nationalCertificate?: Express.Multer.File[];
|
||||
carGreenCard?: Express.Multer.File[];
|
||||
voice?: Express.Multer.File[];
|
||||
video?: Express.Multer.File[];
|
||||
},
|
||||
) {
|
||||
return this.requestManagementService.uploadResendDocumentsV2(
|
||||
requestId,
|
||||
user.sub,
|
||||
files,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user