feat(media): add public URL generation for media files and improve S3 integration

Introduce `getPublicUrl` in `S3Service` for generating public URLs. Replace custom file URL generation logic across services with the new method. Add media controller for file streaming and update related tests. Adjust frontend to display user roles instead of email in the sidebar. Update environment schema to include optional `API_URL`. Fix help page contact email.
This commit is contained in:
Mathis HERRIOT
2026-01-14 23:13:28 +01:00
parent 4ca15b578d
commit 38adbb6e77
12 changed files with 128 additions and 38 deletions

View File

@@ -6,7 +6,6 @@ import {
Injectable,
Logger,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import type { Cache } from "cache-manager";
import { v4 as uuidv4 } from "uuid";
import { RbacService } from "../auth/rbac.service";
@@ -28,7 +27,6 @@ export class UsersService {
private readonly rbacService: RbacService,
@Inject(MediaService) private readonly mediaService: IMediaService,
@Inject(S3Service) private readonly s3Service: IStorageService,
private readonly configService: ConfigService,
) {}
private async clearUserCache(username?: string) {
@@ -60,7 +58,9 @@ export class UsersService {
return {
...user,
avatarUrl: user.avatarUrl ? this.getFileUrl(user.avatarUrl) : null,
avatarUrl: user.avatarUrl
? this.s3Service.getPublicUrl(user.avatarUrl)
: null,
role: roles.includes("admin") ? "admin" : "user",
roles,
};
@@ -74,7 +74,9 @@ export class UsersService {
const processedData = data.map((user) => ({
...user,
avatarUrl: user.avatarUrl ? this.getFileUrl(user.avatarUrl) : null,
avatarUrl: user.avatarUrl
? this.s3Service.getPublicUrl(user.avatarUrl)
: null,
}));
return { data: processedData, totalCount };
@@ -86,7 +88,9 @@ export class UsersService {
return {
...user,
avatarUrl: user.avatarUrl ? this.getFileUrl(user.avatarUrl) : null,
avatarUrl: user.avatarUrl
? this.s3Service.getPublicUrl(user.avatarUrl)
: null,
};
}
@@ -193,17 +197,4 @@ export class UsersService {
async remove(uuid: string) {
return await this.usersRepository.softDeleteUserAndContents(uuid);
}
private getFileUrl(storageKey: string): string {
const endpoint = this.configService.get("S3_ENDPOINT");
const port = this.configService.get("S3_PORT");
const protocol =
this.configService.get("S3_USE_SSL") === true ? "https" : "http";
const bucket = this.configService.get("S3_BUCKET_NAME");
if (endpoint === "localhost" || endpoint === "127.0.0.1") {
return `${protocol}://${endpoint}:${port}/${bucket}/${storageKey}`;
}
return `${protocol}://${endpoint}/${bucket}/${storageKey}`;
}
}