feat(s3): enhance logging and public URL generation
Some checks failed
Backend Tests / test (push) Successful in 1m11s
Lint / lint (backend) (push) Failing after 46s
Lint / lint (documentation) (push) Successful in 1m7s
Lint / lint (frontend) (push) Has been cancelled

Add detailed logging for S3 uploads in user and content services. Improve public URL generation logic in `S3Service` by providing better handling for `API_URL`, `DOMAIN_NAME`, and `PORT`. Update relevant tests to cover all scenarios.
This commit is contained in:
Mathis HERRIOT
2026-01-15 00:40:36 +01:00
parent f79507730e
commit 8d27532dc0
6 changed files with 50 additions and 42 deletions

View File

@@ -7,7 +7,7 @@ jest.mock("minio");
describe("S3Service", () => {
let service: S3Service;
let _configService: ConfigService;
let configService: ConfigService;
// biome-ignore lint/suspicious/noExplicitAny: Fine for testing purposes
let minioClient: any;
@@ -42,7 +42,7 @@ describe("S3Service", () => {
}).compile();
service = module.get<S3Service>(S3Service);
_configService = module.get<ConfigService>(ConfigService);
configService = module.get<ConfigService>(ConfigService);
});
it("should be defined", () => {
@@ -185,35 +185,35 @@ describe("S3Service", () => {
});
});
describe("moveFile", () => {
it("should move file within default bucket", async () => {
const source = "source.txt";
const dest = "dest.txt";
await service.moveFile(source, dest);
expect(minioClient.copyObject).toHaveBeenCalledWith(
"memegoat",
dest,
"/memegoat/source.txt",
expect.any(Minio.CopyConditions),
);
expect(minioClient.removeObject).toHaveBeenCalledWith("memegoat", source);
describe("getPublicUrl", () => {
it("should use API_URL if provided", () => {
(configService.get as jest.Mock).mockImplementation((key: string) => {
if (key === "API_URL") return "https://api.test.com";
return null;
});
const url = service.getPublicUrl("test.webp");
expect(url).toBe("https://api.test.com/media/test.webp");
});
it("should move file between different buckets", async () => {
const source = "source.txt";
const dest = "dest.txt";
const sBucket = "source-bucket";
const dBucket = "dest-bucket";
await service.moveFile(source, dest, sBucket, dBucket);
it("should use DOMAIN_NAME and PORT for localhost", () => {
(configService.get as jest.Mock).mockImplementation((key: string, def: any) => {
if (key === "API_URL") return null;
if (key === "DOMAIN_NAME") return "localhost";
if (key === "PORT") return 3000;
return def;
});
const url = service.getPublicUrl("test.webp");
expect(url).toBe("http://localhost:3000/media/test.webp");
});
expect(minioClient.copyObject).toHaveBeenCalledWith(
dBucket,
dest,
`/${sBucket}/${source}`,
expect.any(Minio.CopyConditions),
);
expect(minioClient.removeObject).toHaveBeenCalledWith(sBucket, source);
it("should use api.DOMAIN_NAME for production", () => {
(configService.get as jest.Mock).mockImplementation((key: string, def: any) => {
if (key === "API_URL") return null;
if (key === "DOMAIN_NAME") return "memegoat.fr";
return def;
});
const url = service.getPublicUrl("test.webp");
expect(url).toBe("https://api.memegoat.fr/media/test.webp");
});
});
});

View File

@@ -158,17 +158,19 @@ export class S3Service implements OnModuleInit, IStorageService {
getPublicUrl(storageKey: string): string {
const apiUrl = this.configService.get<string>("API_URL");
if (apiUrl) {
return `${apiUrl.replace(/\/$/, "")}/media/${storageKey}`;
}
const domain = this.configService.get<string>("DOMAIN_NAME", "localhost");
const port = this.configService.get<number>("PORT", 3000);
if (domain === "localhost" || domain === "127.0.0.1") {
return `http://${domain}:${port}/media/${storageKey}`;
let baseUrl: string;
if (apiUrl) {
baseUrl = apiUrl.replace(/\/$/, "");
} else if (domain === "localhost" || domain === "127.0.0.1") {
baseUrl = `http://${domain}:${port}`;
} else {
baseUrl = `https://api.${domain}`;
}
return `https://api.${domain}/media/${storageKey}`;
return `${baseUrl}/media/${storageKey}`;
}
}