forked from Yara724/api
Merge pull request 'Fixing link for some documents' (#120) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#120
This commit is contained in:
14
README.md
14
README.md
@@ -1 +1,15 @@
|
|||||||
# api
|
# api
|
||||||
|
|
||||||
|
Current JWT payload:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "saman_insurer@gmail.com",
|
||||||
|
"sub": "6a144979799f3c63aa63f67c",
|
||||||
|
"fullName": "بیمه گر سامان",
|
||||||
|
"role": "company",
|
||||||
|
"userType": "UserType",
|
||||||
|
"clientKey": "67f0fd0e53868dc1ff8a2738",
|
||||||
|
"iat": 1781339791,
|
||||||
|
"exp": 1781343391
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { isAxiosError } from "axios";
|
|||||||
import { unlink } from "node:fs/promises";
|
import { unlink } from "node:fs/promises";
|
||||||
import { existsSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
import { AiService } from "src/ai/ai.service";
|
import { AiService } from "src/ai/ai.service";
|
||||||
import { buildFileLink } from "src/helpers/urlCreator";
|
import { buildFileLink, resolveStoredFileUrl } from "src/helpers/urlCreator";
|
||||||
import { RequestManagementDbService } from "src/request-management/entities/db-service/request-management.db.service";
|
import { RequestManagementDbService } from "src/request-management/entities/db-service/request-management.db.service";
|
||||||
import { ReqBlameStatus } from "src/Types&Enums/blame-request-management/status.enum";
|
import { ReqBlameStatus } from "src/Types&Enums/blame-request-management/status.enum";
|
||||||
import { ReqClaimStatus } from "src/Types&Enums/claim-request-management/status.enum";
|
import { ReqClaimStatus } from "src/Types&Enums/claim-request-management/status.enum";
|
||||||
@@ -6644,7 +6644,7 @@ export class ClaimRequestManagementService {
|
|||||||
) as { url?: string; path?: string } | undefined;
|
) as { url?: string; path?: string } | undefined;
|
||||||
carAngles[k] = {
|
carAngles[k] = {
|
||||||
captured: !!cap,
|
captured: !!cap,
|
||||||
url: cap?.url || (cap?.path ? buildFileLink(cap.path) : undefined),
|
url: resolveStoredFileUrl(cap),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ export class EnvironmentVariables {
|
|||||||
message: "NODE_ENV should be development or production",
|
message: "NODE_ENV should be development or production",
|
||||||
})
|
})
|
||||||
NODE_ENV: Environment;
|
NODE_ENV: Environment;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
@IsNumber(
|
@IsNumber(
|
||||||
{
|
{
|
||||||
allowNaN: false,
|
allowNaN: false,
|
||||||
@@ -36,7 +38,9 @@ export class EnvironmentVariables {
|
|||||||
@Min(0, { message: "PORT must be between 0 and 65535" })
|
@Min(0, { message: "PORT must be between 0 and 65535" })
|
||||||
@Max(65535, { message: "PORT must be between 0 and 65535" })
|
@Max(65535, { message: "PORT must be between 0 and 65535" })
|
||||||
PORT: number;
|
PORT: number;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
@IsString({ message: "MONGO_URI must be string" })
|
@IsString({ message: "MONGO_URI must be string" })
|
||||||
@IsUrl(
|
@IsUrl(
|
||||||
{
|
{
|
||||||
@@ -48,23 +52,32 @@ export class EnvironmentVariables {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
MONGO_URI: string;
|
MONGO_URI: string;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
@IsBooleanString({ message: "MONGO_TLS must be boolean" })
|
@IsBooleanString({ message: "MONGO_TLS must be boolean" })
|
||||||
MONGO_TLS: string;
|
MONGO_TLS: string;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
@IsBooleanString({ message: "MONGO_TLS_ALLOW_INVALID_CERTS must be boolean" })
|
@IsBooleanString({ message: "MONGO_TLS_ALLOW_INVALID_CERTS must be boolean" })
|
||||||
MONGO_TLS_ALLOW_INVALID_CERTS: string;
|
MONGO_TLS_ALLOW_INVALID_CERTS: string;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
@IsString({ message: "JWT_SECRET must be string" })
|
@IsString({ message: "JWT_SECRET must be string" })
|
||||||
@MinLength(32, {
|
@MinLength(32, {
|
||||||
message: "JWT_SECRET must be at least 32 characters",
|
message: "JWT_SECRET must be at least 32 characters",
|
||||||
})
|
})
|
||||||
JWT_SECRET: string;
|
JWT_SECRET: string;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
|
||||||
@Matches(/^\d+(ms|s|m|h|d|w|y)$/, {
|
@Matches(/^\d+(ms|s|m|h|d|w|y)$/, {
|
||||||
message: "JWT_EXPIRY must be in the correct format",
|
message: "JWT_EXPIRY must be in the correct format",
|
||||||
})
|
})
|
||||||
JWT_EXPIRY: StringValue;
|
JWT_EXPIRY: StringValue;
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
// @IsString({ message: "HASH_PEPPER must be string" })
|
// @IsString({ message: "HASH_PEPPER must be string" })
|
||||||
// @MinLength(32, {
|
// @MinLength(32, {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// claim-damaged-part.enricher.ts
|
// claim-damaged-part.enricher.ts
|
||||||
|
|
||||||
|
import { resolveStoredFileUrl } from "src/helpers/urlCreator";
|
||||||
import {
|
import {
|
||||||
DamagedPartCaptureStatus,
|
DamagedPartCaptureStatus,
|
||||||
EnrichedDamagedPart,
|
EnrichedDamagedPart,
|
||||||
@@ -14,6 +15,9 @@ export function buildEnrichedDamagedParts(params: {
|
|||||||
hasDamagedPartCapture: (data: any, key: string, parts: any[]) => boolean;
|
hasDamagedPartCapture: (data: any, key: string, parts: any[]) => boolean;
|
||||||
catalogLikeKeyFromPart: (part: any) => string;
|
catalogLikeKeyFromPart: (part: any) => string;
|
||||||
buildFileLink: (path: string) => string;
|
buildFileLink: (path: string) => string;
|
||||||
|
resolveStoredFileUrl?: (
|
||||||
|
stored?: { url?: string; path?: string } | null,
|
||||||
|
) => string | undefined;
|
||||||
}): EnrichedDamagedPart[] {
|
}): EnrichedDamagedPart[] {
|
||||||
const {
|
const {
|
||||||
selectedParts,
|
selectedParts,
|
||||||
@@ -24,6 +28,7 @@ export function buildEnrichedDamagedParts(params: {
|
|||||||
hasDamagedPartCapture,
|
hasDamagedPartCapture,
|
||||||
catalogLikeKeyFromPart,
|
catalogLikeKeyFromPart,
|
||||||
buildFileLink,
|
buildFileLink,
|
||||||
|
resolveStoredFileUrl: resolveUrl = resolveStoredFileUrl,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
const priceDropLines: any[] = evaluationBlock?.priceDrop?.partLines ?? [];
|
const priceDropLines: any[] = evaluationBlock?.priceDrop?.partLines ?? [];
|
||||||
@@ -109,17 +114,13 @@ export function buildEnrichedDamagedParts(params: {
|
|||||||
: false);
|
: false);
|
||||||
|
|
||||||
const capUrl =
|
const capUrl =
|
||||||
cap?.url ||
|
resolveUrl(cap) ||
|
||||||
(cap?.path ? buildFileLink(cap.path) : undefined) ||
|
|
||||||
(sp.id == null && Array.isArray(damagedPartsData)
|
(sp.id == null && Array.isArray(damagedPartsData)
|
||||||
? (() => {
|
? (() => {
|
||||||
const match = (damagedPartsData as any[]).find(
|
const match = (damagedPartsData as any[]).find(
|
||||||
(d) => d.name === sp.name && d.side === sp.side && d.path,
|
(d) => d.name === sp.name && d.side === sp.side && d.path,
|
||||||
);
|
);
|
||||||
return (
|
return resolveUrl(match);
|
||||||
match?.url ||
|
|
||||||
(match?.path ? buildFileLink(match.path) : undefined)
|
|
||||||
);
|
|
||||||
})()
|
})()
|
||||||
: undefined);
|
: undefined);
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { ClaimSignDbService } from "src/claim-request-management/entites/db-serv
|
|||||||
import { DamageImageDbService } from "src/claim-request-management/entites/db-service/damage-image.db.service";
|
import { DamageImageDbService } from "src/claim-request-management/entites/db-service/damage-image.db.service";
|
||||||
import { VideoCaptureDbService } from "src/claim-request-management/entites/db-service/video-capture.db.service";
|
import { VideoCaptureDbService } from "src/claim-request-management/entites/db-service/video-capture.db.service";
|
||||||
import { ClientDbService } from "src/client/entities/db-service/client.db.service";
|
import { ClientDbService } from "src/client/entities/db-service/client.db.service";
|
||||||
import { buildFileLink } from "src/helpers/urlCreator";
|
import { buildFileLink, resolveStoredFileUrl } from "src/helpers/urlCreator";
|
||||||
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
||||||
import { BlameDocumentDbService } from "src/request-management/entities/db-service/blame-document.db.service";
|
import { BlameDocumentDbService } from "src/request-management/entities/db-service/blame-document.db.service";
|
||||||
import { BlameVideoDbService } from "src/request-management/entities/db-service/blame-video.db.service";
|
import { BlameVideoDbService } from "src/request-management/entities/db-service/blame-video.db.service";
|
||||||
@@ -3941,7 +3941,7 @@ export class ExpertClaimService {
|
|||||||
) as { url?: string; path?: string } | undefined;
|
) as { url?: string; path?: string } | undefined;
|
||||||
carAngles[k] = {
|
carAngles[k] = {
|
||||||
captured: !!cap,
|
captured: !!cap,
|
||||||
url: cap?.url || (cap?.path ? buildFileLink(cap.path) : undefined),
|
url: resolveStoredFileUrl(cap),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3965,6 +3965,7 @@ export class ExpertClaimService {
|
|||||||
hasDamagedPartCapture,
|
hasDamagedPartCapture,
|
||||||
catalogLikeKeyFromPart,
|
catalogLikeKeyFromPart,
|
||||||
buildFileLink,
|
buildFileLink,
|
||||||
|
resolveStoredFileUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Vehicle payload — fall back to blame inquiry if claim vehicle is sparse
|
// Vehicle payload — fall back to blame inquiry if claim vehicle is sparse
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { BlameVideoDbService } from "src/request-management/entities/db-service/
|
|||||||
import { BlameVoiceDbService } from "src/request-management/entities/db-service/blame.voice.db.service";
|
import { BlameVoiceDbService } from "src/request-management/entities/db-service/blame.voice.db.service";
|
||||||
import { VideoCaptureDbService } from "src/claim-request-management/entites/db-service/video-capture.db.service";
|
import { VideoCaptureDbService } from "src/claim-request-management/entites/db-service/video-capture.db.service";
|
||||||
import { ClientDbService } from "src/client/entities/db-service/client.db.service";
|
import { ClientDbService } from "src/client/entities/db-service/client.db.service";
|
||||||
import { buildFileLink } from "src/helpers/urlCreator";
|
import { buildFileLink, resolveStoredFileUrl } from "src/helpers/urlCreator";
|
||||||
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
||||||
import { enrichBlamePartiesForAgreementView } from "src/helpers/blame-party-agreement-decision";
|
import { enrichBlamePartiesForAgreementView } from "src/helpers/blame-party-agreement-decision";
|
||||||
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum";
|
||||||
@@ -422,7 +422,7 @@ export class ExpertInsurerService {
|
|||||||
ck,
|
ck,
|
||||||
selectedNormExpert,
|
selectedNormExpert,
|
||||||
) as { url?: string; path?: string; fileName?: string } | undefined;
|
) as { url?: string; path?: string; fileName?: string } | undefined;
|
||||||
const url = cap?.url || (cap?.path ? buildFileLink(cap.path) : undefined);
|
const url = resolveStoredFileUrl(cap);
|
||||||
const link = url;
|
const link = url;
|
||||||
return {
|
return {
|
||||||
index,
|
index,
|
||||||
@@ -633,7 +633,7 @@ export class ExpertInsurerService {
|
|||||||
) as { url?: string; path?: string } | undefined;
|
) as { url?: string; path?: string } | undefined;
|
||||||
carAngles[k] = {
|
carAngles[k] = {
|
||||||
captured: !!cap,
|
captured: !!cap,
|
||||||
url: cap?.url || (cap?.path ? buildFileLink(cap.path) : undefined),
|
url: resolveStoredFileUrl(cap),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
} from "./outer-damage-parts";
|
} from "./outer-damage-parts";
|
||||||
import { ClaimVehicleTypeV2 } from "src/static/outer-car-parts-catalog";
|
import { ClaimVehicleTypeV2 } from "src/static/outer-car-parts-catalog";
|
||||||
import { canonicalizeResendDocumentKey } from "./claim-resend-document-keys";
|
import { canonicalizeResendDocumentKey } from "./claim-resend-document-keys";
|
||||||
|
import { resolveStoredFileUrl } from "./urlCreator";
|
||||||
|
|
||||||
export type ExpertResendCarPartV2 = {
|
export type ExpertResendCarPartV2 = {
|
||||||
id?: number | null;
|
id?: number | null;
|
||||||
@@ -161,8 +162,7 @@ export function mapExpertResendCarPartsForClient(
|
|||||||
const capturedFromStore =
|
const capturedFromStore =
|
||||||
typeof stored.captured === "boolean" ? stored.captured : undefined;
|
typeof stored.captured === "boolean" ? stored.captured : undefined;
|
||||||
const url =
|
const url =
|
||||||
cap?.url ||
|
resolveStoredFileUrl(cap);
|
||||||
(cap?.path && options.buildUrl ? options.buildUrl(cap.path) : undefined);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: sp.id,
|
id: sp.id,
|
||||||
|
|||||||
@@ -1,9 +1,38 @@
|
|||||||
|
type StoredFileCapture = {
|
||||||
|
url?: string;
|
||||||
|
path?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a public file URL from a relative storage path (e.g. `files/...`).
|
||||||
|
* Uses the current `URL` env so deployments with custom routing stay correct.
|
||||||
|
*/
|
||||||
export function buildFileLink(path: string): string {
|
export function buildFileLink(path: string): string {
|
||||||
const baseUrl = process.env.URL;
|
const normalized = String(path ?? "").trim();
|
||||||
if(process.env.NODE_ENV === 'local'){
|
if (!normalized) return normalized;
|
||||||
return baseUrl + "/" + path;
|
if (/^https?:\/\//i.test(normalized)) {
|
||||||
}else{
|
return normalized;
|
||||||
return baseUrl + "/api/" + path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const baseUrl = (process.env.URL ?? "").replace(/\/+$/, "");
|
||||||
|
const relativePath = normalized.replace(/^\/+/, "");
|
||||||
|
if (process.env.NODE_ENV === "local") {
|
||||||
|
return `${baseUrl}/${relativePath}`;
|
||||||
|
}
|
||||||
|
return `${baseUrl}/api/${relativePath}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a file URL from persisted capture metadata.
|
||||||
|
* Prefer rebuilding from `path` so stale baked-in URLs (e.g. user-portal prefix)
|
||||||
|
* do not leak into expert/other API responses.
|
||||||
|
*/
|
||||||
|
export function resolveStoredFileUrl(
|
||||||
|
stored?: StoredFileCapture | null,
|
||||||
|
): string | undefined {
|
||||||
|
const path = stored?.path?.trim();
|
||||||
|
if (path) {
|
||||||
|
return buildFileLink(path);
|
||||||
|
}
|
||||||
|
return stored?.url;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user