mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 08:20:58 +00:00
Enhance contract clearance features with review timestamps and staff identifiers; improve file handling in controllers and views for better user experience.
This commit is contained in:
@@ -18,6 +18,10 @@ export interface ContractClearanceDocument {
|
||||
file: { id: string; name: string; url: string } | null;
|
||||
reviewStatus: ContractDocReviewStatus | null;
|
||||
note: string | null;
|
||||
/** When the review decision (approve/query) was recorded. */
|
||||
reviewedAt: string | null;
|
||||
/** Staff id that recorded the decision (no user directory to resolve names). */
|
||||
reviewedByStaffId: string | null;
|
||||
}
|
||||
|
||||
export interface ContractClearanceView {
|
||||
@@ -77,6 +81,8 @@ export class ContractClearanceService {
|
||||
file: file ? { id: file.id, name: file.name, url: file.url } : null,
|
||||
reviewStatus: review?.status ?? null,
|
||||
note: review?.note ?? null,
|
||||
reviewedAt: review?.reviewedAt ? review.reviewedAt.toISOString() : null,
|
||||
reviewedByStaffId: review?.reviewedByStaffId ?? null,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -97,6 +103,8 @@ export class ContractClearanceService {
|
||||
file: { id: f.id, name: f.name, url: f.url },
|
||||
reviewStatus: review?.status ?? null,
|
||||
note: review?.note ?? null,
|
||||
reviewedAt: review?.reviewedAt ? review.reviewedAt.toISOString() : null,
|
||||
reviewedByStaffId: review?.reviewedByStaffId ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { Controller, Get, Param, ParseUUIDPipe, Res } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
ParseUUIDPipe,
|
||||
Query,
|
||||
Res,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiQuery, ApiTags } from "@nestjs/swagger";
|
||||
import { Response } from "express";
|
||||
|
||||
import { FilesService } from "./files.service";
|
||||
@@ -11,18 +18,34 @@ export class FilesController {
|
||||
|
||||
@Get(":fileId")
|
||||
@ApiOperation({
|
||||
summary: "Download a file by ID",
|
||||
summary: "Stream a file by ID",
|
||||
description:
|
||||
"Global endpoint — streams any uploaded file directly from MinIO by its UUID. " +
|
||||
"No resource context (e.g. booking ID) required.",
|
||||
"No resource context (e.g. booking ID) required. Serves inline by default so " +
|
||||
"the browser can preview it; pass ?download=1 to force a download.",
|
||||
})
|
||||
@ApiQuery({
|
||||
name: "download",
|
||||
required: false,
|
||||
description: "Set to 1/true to force a download instead of inline preview.",
|
||||
})
|
||||
async download(
|
||||
@Param("fileId", ParseUUIDPipe) fileId: string,
|
||||
@Query("download") download: string | undefined,
|
||||
@Res() res: Response,
|
||||
) {
|
||||
const { stream, record } = await this.filesService.streamById(fileId);
|
||||
const forceDownload = download === "1" || download === "true";
|
||||
const disposition = forceDownload ? "attachment" : "inline";
|
||||
|
||||
res.setHeader("Content-Type", record.mimeType);
|
||||
res.setHeader("Content-Disposition", `attachment; filename="${record.name}"`);
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`${disposition}; filename="${record.name}"`,
|
||||
);
|
||||
// Allow the browser to cache the streamed bytes briefly for smoother
|
||||
// in-page previews (re-opening the viewer shouldn't re-hit MinIO).
|
||||
res.setHeader("Cache-Control", "private, max-age=300");
|
||||
stream.pipe(res);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user