From 0c045e8d3cd34368a357e5c9372f00c7785d1d55 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:51:32 +0100 Subject: [PATCH] refactor: remove unused tests, mocks, and outdated e2e configurations Deleted unused e2e tests, mocks (`cuid2`, `jose`, `ml-kem`, `sha3`), and their associated jest configurations. Simplified services by ensuring proper dependency imports, resolving circular references, and improving TypeScript type usage for enhanced maintainability and testability. Upgraded Dockerfile base image to match new development standards. --- backend/.migrations/meta/_journal.json | 45 +++++++++++-------- backend/Dockerfile | 3 +- backend/src/auth/auth.module.ts | 9 +++- backend/src/auth/auth.service.ts | 3 ++ backend/src/auth/rbac.service.spec.ts | 4 +- .../src/categories/categories.controller.ts | 2 +- .../src/categories/categories.service.spec.ts | 12 +++-- backend/src/categories/categories.service.ts | 6 +-- .../repositories/categories.repository.ts | 5 ++- .../common/interfaces/storage.interface.ts | 7 +-- .../src/common/services/purge.service.spec.ts | 12 +++-- backend/src/common/services/purge.service.ts | 5 +-- backend/src/contents/contents.service.spec.ts | 11 +++-- backend/src/contents/contents.service.ts | 36 +++++++-------- .../repositories/contents.repository.ts | 29 +++++------- backend/src/crypto/crypto.module.ts | 2 +- backend/src/crypto/crypto.service.spec.ts | 2 +- backend/src/database/schemas/index.ts | 2 +- backend/src/database/schemas/pgp.ts | 5 ++- backend/src/database/schemas/users.ts | 1 - .../src/favorites/favorites.service.spec.ts | 12 +++-- backend/src/favorites/favorites.service.ts | 2 +- .../strategies/media-processor.strategy.ts | 5 ++- backend/src/reports/reports.service.spec.ts | 10 ++++- backend/src/reports/reports.service.ts | 2 +- .../repositories/reports.repository.ts | 2 +- .../repositories/sessions.repository.ts | 2 +- backend/src/sessions/sessions.module.ts | 2 +- backend/src/sessions/sessions.service.spec.ts | 7 ++- backend/src/sessions/sessions.service.ts | 3 +- backend/src/tags/tags.controller.ts | 2 +- backend/src/tags/tags.module.ts | 2 +- backend/src/tags/tags.service.spec.ts | 2 +- .../users/repositories/users.repository.ts | 5 +-- backend/src/users/users.controller.ts | 5 ++- backend/src/users/users.module.ts | 6 +-- backend/src/users/users.service.spec.ts | 8 ++-- backend/src/users/users.service.ts | 6 +-- backend/test/__mocks__/cuid2.js | 3 -- backend/test/__mocks__/jose.js | 13 ------ backend/test/__mocks__/ml-kem.js | 7 --- backend/test/__mocks__/sha3.js | 5 --- backend/test/app.e2e-spec.ts | 25 ----------- backend/test/jest-e2e.json | 9 ---- 44 files changed, 163 insertions(+), 183 deletions(-) delete mode 100644 backend/test/__mocks__/cuid2.js delete mode 100644 backend/test/__mocks__/jose.js delete mode 100644 backend/test/__mocks__/ml-kem.js delete mode 100644 backend/test/__mocks__/sha3.js delete mode 100644 backend/test/app.e2e-spec.ts delete mode 100644 backend/test/jest-e2e.json diff --git a/backend/.migrations/meta/_journal.json b/backend/.migrations/meta/_journal.json index c5d94fe..309ca08 100644 --- a/backend/.migrations/meta/_journal.json +++ b/backend/.migrations/meta/_journal.json @@ -1,20 +1,27 @@ { - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1767618753676, - "tag": "0000_right_sally_floyd", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1768392191169, - "tag": "0001_purple_goliath", - "breakpoints": true - } - ] -} \ No newline at end of file + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1767618753676, + "tag": "0000_right_sally_floyd", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1768392191169, + "tag": "0001_purple_goliath", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1768393637823, + "tag": "0002_redundant_skin", + "breakpoints": true + } + ] +} diff --git a/backend/Dockerfile b/backend/Dockerfile index b0fd3a0..bf25c92 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,7 +1,6 @@ -FROM node:22-slim AS base +FROM pnpm/pnpm:22 AS base ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable FROM base AS build WORKDIR /usr/src/app diff --git a/backend/src/auth/auth.module.ts b/backend/src/auth/auth.module.ts index 32b235c..5d44d45 100644 --- a/backend/src/auth/auth.module.ts +++ b/backend/src/auth/auth.module.ts @@ -1,4 +1,4 @@ -import { Module } from "@nestjs/common"; +import { forwardRef, Module } from "@nestjs/common"; import { CryptoModule } from "../crypto/crypto.module"; import { DatabaseModule } from "../database/database.module"; import { SessionsModule } from "../sessions/sessions.module"; @@ -9,7 +9,12 @@ import { RbacService } from "./rbac.service"; import { RbacRepository } from "./repositories/rbac.repository"; @Module({ - imports: [UsersModule, CryptoModule, SessionsModule, DatabaseModule], + imports: [ + forwardRef(() => UsersModule), + CryptoModule, + SessionsModule, + DatabaseModule, + ], controllers: [AuthController], providers: [AuthService, RbacService, RbacRepository], exports: [AuthService, RbacService], diff --git a/backend/src/auth/auth.service.ts b/backend/src/auth/auth.service.ts index 8e293c4..2133afb 100644 --- a/backend/src/auth/auth.service.ts +++ b/backend/src/auth/auth.service.ts @@ -1,5 +1,7 @@ import { BadRequestException, + forwardRef, + Inject, Injectable, Logger, UnauthorizedException, @@ -19,6 +21,7 @@ export class AuthService { private readonly logger = new Logger(AuthService.name); constructor( + @Inject(forwardRef(() => UsersService)) private readonly usersService: UsersService, private readonly hashingService: HashingService, private readonly jwtService: JwtService, diff --git a/backend/src/auth/rbac.service.spec.ts b/backend/src/auth/rbac.service.spec.ts index e638acc..a9d767b 100644 --- a/backend/src/auth/rbac.service.spec.ts +++ b/backend/src/auth/rbac.service.spec.ts @@ -48,7 +48,9 @@ describe("RbacService", () => { it("should return user permissions", async () => { const userId = "user-id"; const mockPermissions = ["read", "write"]; - mockRbacRepository.findPermissionsByUserId.mockResolvedValue(mockPermissions); + mockRbacRepository.findPermissionsByUserId.mockResolvedValue( + mockPermissions, + ); const result = await service.getUserPermissions(userId); diff --git a/backend/src/categories/categories.controller.ts b/backend/src/categories/categories.controller.ts index 5cad8c3..dfc2e74 100644 --- a/backend/src/categories/categories.controller.ts +++ b/backend/src/categories/categories.controller.ts @@ -1,3 +1,4 @@ +import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager"; import { Body, Controller, @@ -9,7 +10,6 @@ import { UseGuards, UseInterceptors, } from "@nestjs/common"; -import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager"; import { Roles } from "../auth/decorators/roles.decorator"; import { AuthGuard } from "../auth/guards/auth.guard"; import { RolesGuard } from "../auth/guards/roles.guard"; diff --git a/backend/src/categories/categories.service.spec.ts b/backend/src/categories/categories.service.spec.ts index f0f43ab..a8cb747 100644 --- a/backend/src/categories/categories.service.spec.ts +++ b/backend/src/categories/categories.service.spec.ts @@ -1,9 +1,9 @@ -import { Test, TestingModule } from "@nestjs/testing"; import { CACHE_MANAGER } from "@nestjs/cache-manager"; +import { Test, TestingModule } from "@nestjs/testing"; import { CategoriesService } from "./categories.service"; -import { CategoriesRepository } from "./repositories/categories.repository"; import { CreateCategoryDto } from "./dto/create-category.dto"; import { UpdateCategoryDto } from "./dto/update-category.dto"; +import { CategoriesRepository } from "./repositories/categories.repository"; describe("CategoriesService", () => { let service: CategoriesService; @@ -75,7 +75,9 @@ describe("CategoriesService", () => { describe("create", () => { it("should create a category and generate slug", async () => { const dto: CreateCategoryDto = { name: "Test Category" }; - mockCategoriesRepository.create.mockResolvedValue([{ ...dto, slug: "test-category" }]); + mockCategoriesRepository.create.mockResolvedValue([ + { ...dto, slug: "test-category" }, + ]); const result = await service.create(dto); @@ -91,7 +93,9 @@ describe("CategoriesService", () => { it("should update a category and regenerate slug", async () => { const id = "1"; const dto: UpdateCategoryDto = { name: "New Name" }; - mockCategoriesRepository.update.mockResolvedValue([{ id, ...dto, slug: "new-name" }]); + mockCategoriesRepository.update.mockResolvedValue([ + { id, ...dto, slug: "new-name" }, + ]); const result = await service.update(id, dto); diff --git a/backend/src/categories/categories.service.ts b/backend/src/categories/categories.service.ts index 5a41bea..ddfbba0 100644 --- a/backend/src/categories/categories.service.ts +++ b/backend/src/categories/categories.service.ts @@ -1,9 +1,9 @@ -import { Injectable, Logger, Inject } from "@nestjs/common"; import { CACHE_MANAGER } from "@nestjs/cache-manager"; -import { Cache } from "cache-manager"; -import { CategoriesRepository } from "./repositories/categories.repository"; +import { Inject, Injectable, Logger } from "@nestjs/common"; +import type { Cache } from "cache-manager"; import { CreateCategoryDto } from "./dto/create-category.dto"; import { UpdateCategoryDto } from "./dto/update-category.dto"; +import { CategoriesRepository } from "./repositories/categories.repository"; @Injectable() export class CategoriesService { diff --git a/backend/src/categories/repositories/categories.repository.ts b/backend/src/categories/repositories/categories.repository.ts index 3ef00c6..a15b7c8 100644 --- a/backend/src/categories/repositories/categories.repository.ts +++ b/backend/src/categories/repositories/categories.repository.ts @@ -33,7 +33,10 @@ export class CategoriesRepository { .returning(); } - async update(id: string, data: UpdateCategoryDto & { slug?: string; updatedAt: Date }) { + async update( + id: string, + data: UpdateCategoryDto & { slug?: string; updatedAt: Date }, + ) { return await this.databaseService.db .update(categories) .set(data) diff --git a/backend/src/common/interfaces/storage.interface.ts b/backend/src/common/interfaces/storage.interface.ts index c65062a..f0d7f0a 100644 --- a/backend/src/common/interfaces/storage.interface.ts +++ b/backend/src/common/interfaces/storage.interface.ts @@ -9,10 +9,7 @@ export interface IStorageService { bucketName?: string, ): Promise; - getFile( - fileName: string, - bucketName?: string, - ): Promise; + getFile(fileName: string, bucketName?: string): Promise; getFileUrl( fileName: string, @@ -28,7 +25,7 @@ export interface IStorageService { deleteFile(fileName: string, bucketName?: string): Promise; - getFileInfo(fileName: string, bucketName?: string): Promise; + getFileInfo(fileName: string, bucketName?: string): Promise; moveFile( sourceFileName: string, diff --git a/backend/src/common/services/purge.service.spec.ts b/backend/src/common/services/purge.service.spec.ts index 4768400..5a5d320 100644 --- a/backend/src/common/services/purge.service.spec.ts +++ b/backend/src/common/services/purge.service.spec.ts @@ -9,10 +9,16 @@ import { PurgeService } from "./purge.service"; describe("PurgeService", () => { let service: PurgeService; - const mockSessionsRepository = { purgeExpired: jest.fn().mockResolvedValue([]) }; - const mockReportsRepository = { purgeObsolete: jest.fn().mockResolvedValue([]) }; + const mockSessionsRepository = { + purgeExpired: jest.fn().mockResolvedValue([]), + }; + const mockReportsRepository = { + purgeObsolete: jest.fn().mockResolvedValue([]), + }; const mockUsersRepository = { purgeDeleted: jest.fn().mockResolvedValue([]) }; - const mockContentsRepository = { purgeSoftDeleted: jest.fn().mockResolvedValue([]) }; + const mockContentsRepository = { + purgeSoftDeleted: jest.fn().mockResolvedValue([]), + }; beforeEach(async () => { jest.clearAllMocks(); diff --git a/backend/src/common/services/purge.service.ts b/backend/src/common/services/purge.service.ts index 106fd3d..0ddfad6 100644 --- a/backend/src/common/services/purge.service.ts +++ b/backend/src/common/services/purge.service.ts @@ -42,9 +42,8 @@ export class PurgeService { ); // 4. Purge des contenus supprimés (Soft Delete > 30 jours) - const deletedContents = await this.contentsRepository.purgeSoftDeleted( - thirtyDaysAgo, - ); + const deletedContents = + await this.contentsRepository.purgeSoftDeleted(thirtyDaysAgo); this.logger.log( `Purged ${deletedContents.length} contents marked for deletion more than 30 days ago.`, ); diff --git a/backend/src/contents/contents.service.spec.ts b/backend/src/contents/contents.service.spec.ts index 2f4fff8..cc6059f 100644 --- a/backend/src/contents/contents.service.spec.ts +++ b/backend/src/contents/contents.service.spec.ts @@ -2,11 +2,10 @@ jest.mock("uuid", () => ({ v4: jest.fn(() => "mocked-uuid"), })); +import { CACHE_MANAGER } from "@nestjs/cache-manager"; import { BadRequestException } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; -import { CACHE_MANAGER } from "@nestjs/cache-manager"; import { Test, TestingModule } from "@nestjs/testing"; -import { DatabaseService } from "../database/database.service"; import { MediaService } from "../media/media.service"; import { S3Service } from "../s3/s3.service"; import { ContentsService } from "./contents.service"; @@ -44,9 +43,7 @@ describe("ContentsService", () => { }; const mockCacheManager = { - store: { - keys: jest.fn().mockResolvedValue([]), - }, + clear: jest.fn(), del: jest.fn(), }; @@ -141,7 +138,9 @@ describe("ContentsService", () => { describe("incrementViews", () => { it("should increment views", async () => { - mockContentsRepository.incrementViews.mockResolvedValue([{ id: "1", views: 1 }]); + mockContentsRepository.incrementViews.mockResolvedValue([ + { id: "1", views: 1 }, + ]); const result = await service.incrementViews("1"); expect(mockContentsRepository.incrementViews).toHaveBeenCalledWith("1"); expect(result[0].views).toBe(1); diff --git a/backend/src/contents/contents.service.ts b/backend/src/contents/contents.service.ts index 695384a..c0f58ec 100644 --- a/backend/src/contents/contents.service.ts +++ b/backend/src/contents/contents.service.ts @@ -1,13 +1,22 @@ -import { BadRequestException, Injectable, Logger } from "@nestjs/common"; import { CACHE_MANAGER } from "@nestjs/cache-manager"; -import { Cache } from "cache-manager"; -import { Inject } from "@nestjs/common"; +import { + BadRequestException, + Inject, + Injectable, + Logger, +} from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; +import type { Cache } from "cache-manager"; import { v4 as uuidv4 } from "uuid"; -import type { IMediaService } from "../common/interfaces/media.interface"; +import type { + IMediaService, + MediaProcessingResult, +} from "../common/interfaces/media.interface"; import type { IStorageService } from "../common/interfaces/storage.interface"; import { MediaService } from "../media/media.service"; import { S3Service } from "../s3/s3.service"; +import { CreateContentDto } from "./dto/create-content.dto"; +import { UploadContentDto } from "./dto/upload-content.dto"; import { ContentsRepository } from "./repositories/contents.repository"; @Injectable() @@ -24,11 +33,7 @@ export class ContentsService { private async clearContentsCache() { this.logger.log("Clearing contents cache"); - const keys = await this.cacheManager.store.keys(); - const contentsKeys = keys.filter((key) => key.startsWith("contents/")); - for (const key of contentsKeys) { - await this.cacheManager.del(key); - } + await this.cacheManager.clear(); } async getUploadUrl(userId: string, fileName: string) { @@ -40,12 +45,7 @@ export class ContentsService { async uploadAndProcess( userId: string, file: Express.Multer.File, - data: { - title: string; - type: "meme" | "gif"; - categoryId?: string; - tags?: string[]; - }, + data: UploadContentDto, ) { this.logger.log(`Uploading and processing file for user ${userId}`); // 0. Validation du format et de la taille @@ -86,7 +86,7 @@ export class ContentsService { } // 2. Transcodage - let processed; + let processed: MediaProcessingResult; if (file.mimetype.startsWith("image/")) { // Image ou GIF -> WebP (format moderne, bien supporté) processed = await this.mediaService.processImage(file.buffer, "webp"); @@ -129,7 +129,7 @@ export class ContentsService { return { data, totalCount }; } - async create(userId: string, data: any) { + async create(userId: string, data: CreateContentDto) { this.logger.log(`Creating content for user ${userId}: ${data.title}`); const { tags: tagNames, ...contentData } = data; @@ -166,7 +166,7 @@ export class ContentsService { return this.contentsRepository.findOne(idOrSlug); } - generateBotHtml(content: any): string { + generateBotHtml(content: { title: string; storageKey: string }): string { const imageUrl = this.getFileUrl(content.storageKey); return ` diff --git a/backend/src/contents/repositories/contents.repository.ts b/backend/src/contents/repositories/contents.repository.ts index d044c51..8fbc2d0 100644 --- a/backend/src/contents/repositories/contents.repository.ts +++ b/backend/src/contents/repositories/contents.repository.ts @@ -6,9 +6,9 @@ import { exists, ilike, isNull, - sql, lte, type SQL, + sql, } from "drizzle-orm"; import { DatabaseService } from "../../database/database.service"; import { @@ -113,10 +113,7 @@ export class ContentsRepository { .select() .from(favorites) .where( - and( - eq(favorites.contentId, contents.id), - eq(favorites.userId, userId), - ), + and(eq(favorites.contentId, contents.id), eq(favorites.userId, userId)), ), ), ); @@ -143,7 +140,6 @@ export class ContentsRepository { author: { id: users.uuid, username: users.username, - avatarUrl: users.avatarUrl, }, category: { id: categories.id, @@ -173,18 +169,13 @@ export class ContentsRepository { return results.map((r) => ({ ...r, - tags: tagsForContents - .filter((t) => t.contentId === r.id) - .map((t) => t.name), + tags: tagsForContents.filter((t) => t.contentId === r.id).map((t) => t.name), })); } async create(data: NewContentInDb & { userId: string }, tagNames?: string[]) { return await this.databaseService.db.transaction(async (tx) => { - const [newContent] = await tx - .insert(contents) - .values(data) - .returning(); + const [newContent] = await tx.insert(contents).values(data).returning(); if (tagNames && tagNames.length > 0) { for (const tagName of tagNames) { @@ -325,10 +316,7 @@ export class ContentsRepository { .select() .from(favorites) .where( - and( - eq(favorites.contentId, contents.id), - eq(favorites.userId, userId), - ), + and(eq(favorites.contentId, contents.id), eq(favorites.userId, userId)), ), ), ); @@ -377,7 +365,12 @@ export class ContentsRepository { async purgeSoftDeleted(before: Date) { return await this.databaseService.db .delete(contents) - .where(and(sql`${contents.deletedAt} IS NOT NULL`, lte(contents.deletedAt, before))) + .where( + and( + sql`${contents.deletedAt} IS NOT NULL`, + lte(contents.deletedAt, before), + ), + ) .returning(); } } diff --git a/backend/src/crypto/crypto.module.ts b/backend/src/crypto/crypto.module.ts index 75836b1..d85f7cf 100644 --- a/backend/src/crypto/crypto.module.ts +++ b/backend/src/crypto/crypto.module.ts @@ -1,8 +1,8 @@ import { Module } from "@nestjs/common"; import { CryptoService } from "./crypto.service"; +import { EncryptionService } from "./services/encryption.service"; import { HashingService } from "./services/hashing.service"; import { JwtService } from "./services/jwt.service"; -import { EncryptionService } from "./services/encryption.service"; import { PostQuantumService } from "./services/post-quantum.service"; @Module({ diff --git a/backend/src/crypto/crypto.service.spec.ts b/backend/src/crypto/crypto.service.spec.ts index e46fe9b..82a4081 100644 --- a/backend/src/crypto/crypto.service.spec.ts +++ b/backend/src/crypto/crypto.service.spec.ts @@ -64,9 +64,9 @@ jest.mock("jose", () => ({ })); import { CryptoService } from "./crypto.service"; +import { EncryptionService } from "./services/encryption.service"; import { HashingService } from "./services/hashing.service"; import { JwtService } from "./services/jwt.service"; -import { EncryptionService } from "./services/encryption.service"; import { PostQuantumService } from "./services/post-quantum.service"; describe("CryptoService", () => { diff --git a/backend/src/database/schemas/index.ts b/backend/src/database/schemas/index.ts index e54a30a..e271c71 100644 --- a/backend/src/database/schemas/index.ts +++ b/backend/src/database/schemas/index.ts @@ -3,9 +3,9 @@ export * from "./audit_logs"; export * from "./categories"; export * from "./content"; export * from "./favorites"; +export * from "./pgp"; export * from "./rbac"; export * from "./reports"; export * from "./sessions"; export * from "./tags"; export * from "./users"; -export * from "./pgp"; diff --git a/backend/src/database/schemas/pgp.ts b/backend/src/database/schemas/pgp.ts index cc514e8..f872b26 100644 --- a/backend/src/database/schemas/pgp.ts +++ b/backend/src/database/schemas/pgp.ts @@ -55,6 +55,9 @@ export function pgpSymEncrypt(value: string | SQL, key: string | SQL) { /** * @deprecated Utiliser directement les colonnes de type pgpEncrypted qui gèrent maintenant le déchiffrement automatiquement. */ -export function pgpSymDecrypt(column: AnyPgColumn, key: string | SQL): SQL { +export function pgpSymDecrypt( + column: AnyPgColumn, + key: string | SQL, +): SQL { return sql`pgp_sym_decrypt(${column}, ${key})`.mapWith(column) as SQL; } diff --git a/backend/src/database/schemas/users.ts b/backend/src/database/schemas/users.ts index 9190acd..bdc1b7f 100644 --- a/backend/src/database/schemas/users.ts +++ b/backend/src/database/schemas/users.ts @@ -1,4 +1,3 @@ -import { SQL, sql } from "drizzle-orm"; import { boolean, index, diff --git a/backend/src/favorites/favorites.service.spec.ts b/backend/src/favorites/favorites.service.spec.ts index a2b636b..20c9497 100644 --- a/backend/src/favorites/favorites.service.spec.ts +++ b/backend/src/favorites/favorites.service.spec.ts @@ -34,7 +34,9 @@ describe("FavoritesService", () => { describe("addFavorite", () => { it("should add a favorite", async () => { - mockFavoritesRepository.findContentById.mockResolvedValue({ id: "content1" }); + mockFavoritesRepository.findContentById.mockResolvedValue({ + id: "content1", + }); mockFavoritesRepository.add.mockResolvedValue([ { userId: "u1", contentId: "content1" }, ]); @@ -53,7 +55,9 @@ describe("FavoritesService", () => { }); it("should throw ConflictException on duplicate favorite", async () => { - mockFavoritesRepository.findContentById.mockResolvedValue({ id: "content1" }); + mockFavoritesRepository.findContentById.mockResolvedValue({ + id: "content1", + }); mockFavoritesRepository.add.mockRejectedValue(new Error("Duplicate")); await expect(service.addFavorite("u1", "content1")).rejects.toThrow( ConflictException, @@ -63,7 +67,9 @@ describe("FavoritesService", () => { describe("removeFavorite", () => { it("should remove a favorite", async () => { - mockFavoritesRepository.remove.mockResolvedValue([{ userId: "u1", contentId: "c1" }]); + mockFavoritesRepository.remove.mockResolvedValue([ + { userId: "u1", contentId: "c1" }, + ]); const result = await service.removeFavorite("u1", "c1"); expect(result).toEqual({ userId: "u1", contentId: "c1" }); expect(repository.remove).toHaveBeenCalledWith("u1", "c1"); diff --git a/backend/src/favorites/favorites.service.ts b/backend/src/favorites/favorites.service.ts index b001b16..4b2f638 100644 --- a/backend/src/favorites/favorites.service.ts +++ b/backend/src/favorites/favorites.service.ts @@ -14,7 +14,7 @@ export class FavoritesService { async addFavorite(userId: string, contentId: string) { this.logger.log(`Adding favorite: user ${userId}, content ${contentId}`); - + const content = await this.favoritesRepository.findContentById(contentId); if (!content) { throw new NotFoundException("Content not found"); diff --git a/backend/src/media/strategies/media-processor.strategy.ts b/backend/src/media/strategies/media-processor.strategy.ts index 330ca77..94a4893 100644 --- a/backend/src/media/strategies/media-processor.strategy.ts +++ b/backend/src/media/strategies/media-processor.strategy.ts @@ -2,5 +2,8 @@ import type { MediaProcessingResult } from "../../common/interfaces/media.interf export interface IMediaProcessorStrategy { canHandle(mimeType: string): boolean; - process(buffer: Buffer, options?: any): Promise; + process( + buffer: Buffer, + options?: Record, + ): Promise; } diff --git a/backend/src/reports/reports.service.spec.ts b/backend/src/reports/reports.service.spec.ts index 9564996..a741493 100644 --- a/backend/src/reports/reports.service.spec.ts +++ b/backend/src/reports/reports.service.spec.ts @@ -34,7 +34,11 @@ describe("ReportsService", () => { it("should create a report", async () => { const reporterId = "u1"; const data = { contentId: "c1", reason: "spam" }; - mockReportsRepository.create.mockResolvedValue({ id: "r1", ...data, reporterId }); + mockReportsRepository.create.mockResolvedValue({ + id: "r1", + ...data, + reporterId, + }); const result = await service.create(reporterId, data); @@ -54,7 +58,9 @@ describe("ReportsService", () => { describe("updateStatus", () => { it("should update report status", async () => { - mockReportsRepository.updateStatus.mockResolvedValue([{ id: "r1", status: "resolved" }]); + mockReportsRepository.updateStatus.mockResolvedValue([ + { id: "r1", status: "resolved" }, + ]); const result = await service.updateStatus("r1", "resolved"); expect(result[0].status).toBe("resolved"); expect(repository.updateStatus).toHaveBeenCalledWith("r1", "resolved"); diff --git a/backend/src/reports/reports.service.ts b/backend/src/reports/reports.service.ts index b014831..aa58adb 100644 --- a/backend/src/reports/reports.service.ts +++ b/backend/src/reports/reports.service.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from "@nestjs/common"; -import { ReportsRepository } from "./repositories/reports.repository"; import { CreateReportDto } from "./dto/create-report.dto"; +import { ReportsRepository } from "./repositories/reports.repository"; @Injectable() export class ReportsService { diff --git a/backend/src/reports/repositories/reports.repository.ts b/backend/src/reports/repositories/reports.repository.ts index 7404d46..9f113fe 100644 --- a/backend/src/reports/repositories/reports.repository.ts +++ b/backend/src/reports/repositories/reports.repository.ts @@ -11,7 +11,7 @@ export class ReportsRepository { reporterId: string; contentId?: string; tagId?: string; - reason: string; + reason: "inappropriate" | "spam" | "copyright" | "other"; description?: string; }) { const [newReport] = await this.databaseService.db diff --git a/backend/src/sessions/repositories/sessions.repository.ts b/backend/src/sessions/repositories/sessions.repository.ts index 050f368..59619e4 100644 --- a/backend/src/sessions/repositories/sessions.repository.ts +++ b/backend/src/sessions/repositories/sessions.repository.ts @@ -32,7 +32,7 @@ export class SessionsRepository { return result[0] || null; } - async update(sessionId: string, data: any) { + async update(sessionId: string, data: Record) { const [updatedSession] = await this.databaseService.db .update(sessions) .set({ ...data, updatedAt: new Date() }) diff --git a/backend/src/sessions/sessions.module.ts b/backend/src/sessions/sessions.module.ts index c69d49b..a5c4367 100644 --- a/backend/src/sessions/sessions.module.ts +++ b/backend/src/sessions/sessions.module.ts @@ -1,8 +1,8 @@ import { Module } from "@nestjs/common"; import { CryptoModule } from "../crypto/crypto.module"; import { DatabaseModule } from "../database/database.module"; -import { SessionsService } from "./sessions.service"; import { SessionsRepository } from "./repositories/sessions.repository"; +import { SessionsService } from "./sessions.service"; @Module({ imports: [DatabaseModule, CryptoModule], diff --git a/backend/src/sessions/sessions.service.spec.ts b/backend/src/sessions/sessions.service.spec.ts index 37343cc..0f2afe3 100644 --- a/backend/src/sessions/sessions.service.spec.ts +++ b/backend/src/sessions/sessions.service.spec.ts @@ -15,8 +15,8 @@ import { UnauthorizedException } from "@nestjs/common"; import { Test, TestingModule } from "@nestjs/testing"; import { HashingService } from "../crypto/services/hashing.service"; import { JwtService } from "../crypto/services/jwt.service"; -import { SessionsService } from "./sessions.service"; import { SessionsRepository } from "./repositories/sessions.repository"; +import { SessionsService } from "./sessions.service"; describe("SessionsService", () => { let service: SessionsService; @@ -76,7 +76,10 @@ describe("SessionsService", () => { userId: "u1", expiresAt, }); - mockSessionsRepository.update.mockResolvedValue({ id: "s1", refreshToken: "new-token" }); + mockSessionsRepository.update.mockResolvedValue({ + id: "s1", + refreshToken: "new-token", + }); const result = await service.refreshSession("old-token"); diff --git a/backend/src/sessions/sessions.service.ts b/backend/src/sessions/sessions.service.ts index 8659765..fa11205 100644 --- a/backend/src/sessions/sessions.service.ts +++ b/backend/src/sessions/sessions.service.ts @@ -30,7 +30,8 @@ export class SessionsService { } async refreshSession(oldRefreshToken: string) { - const session = await this.sessionsRepository.findValidByRefreshToken(oldRefreshToken); + const session = + await this.sessionsRepository.findValidByRefreshToken(oldRefreshToken); if (!session || session.expiresAt < new Date()) { if (session) { diff --git a/backend/src/tags/tags.controller.ts b/backend/src/tags/tags.controller.ts index ae08024..ae11e2c 100644 --- a/backend/src/tags/tags.controller.ts +++ b/backend/src/tags/tags.controller.ts @@ -1,3 +1,4 @@ +import { CacheInterceptor, CacheTTL } from "@nestjs/cache-manager"; import { Controller, DefaultValuePipe, @@ -6,7 +7,6 @@ import { Query, UseInterceptors, } from "@nestjs/common"; -import { CacheInterceptor, CacheTTL } from "@nestjs/cache-manager"; import { TagsService } from "./tags.service"; @Controller("tags") diff --git a/backend/src/tags/tags.module.ts b/backend/src/tags/tags.module.ts index f3fba4a..456c36a 100644 --- a/backend/src/tags/tags.module.ts +++ b/backend/src/tags/tags.module.ts @@ -1,8 +1,8 @@ import { Module } from "@nestjs/common"; import { DatabaseModule } from "../database/database.module"; +import { TagsRepository } from "./repositories/tags.repository"; import { TagsController } from "./tags.controller"; import { TagsService } from "./tags.service"; -import { TagsRepository } from "./repositories/tags.repository"; @Module({ imports: [DatabaseModule], diff --git a/backend/src/tags/tags.service.spec.ts b/backend/src/tags/tags.service.spec.ts index 8eddf61..4b02a4e 100644 --- a/backend/src/tags/tags.service.spec.ts +++ b/backend/src/tags/tags.service.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from "@nestjs/testing"; -import { TagsService } from "./tags.service"; import { TagsRepository } from "./repositories/tags.repository"; +import { TagsService } from "./tags.service"; describe("TagsService", () => { let service: TagsService; diff --git a/backend/src/users/repositories/users.repository.ts b/backend/src/users/repositories/users.repository.ts index c56ccf2..7a3f538 100644 --- a/backend/src/users/repositories/users.repository.ts +++ b/backend/src/users/repositories/users.repository.ts @@ -1,8 +1,7 @@ import { Injectable } from "@nestjs/common"; import { and, eq, lte, sql } from "drizzle-orm"; import { DatabaseService } from "../../database/database.service"; -import { users, contents, favorites } from "../../database/schemas"; -import type { UpdateUserDto } from "../dto/update-user.dto"; +import { contents, favorites, users } from "../../database/schemas"; @Injectable() export class UsersRepository { @@ -99,7 +98,7 @@ export class UsersRepository { return result[0] || null; } - async update(uuid: string, data: any) { + async update(uuid: string, data: Partial) { return await this.databaseService.db .update(users) .set({ ...data, updatedAt: new Date() }) diff --git a/backend/src/users/users.controller.ts b/backend/src/users/users.controller.ts index 673f9a5..c036337 100644 --- a/backend/src/users/users.controller.ts +++ b/backend/src/users/users.controller.ts @@ -1,9 +1,12 @@ +import { CacheInterceptor, CacheTTL } from "@nestjs/cache-manager"; import { Body, Controller, DefaultValuePipe, Delete, + forwardRef, Get, + Inject, Param, ParseIntPipe, Patch, @@ -13,7 +16,6 @@ import { UseGuards, UseInterceptors, } from "@nestjs/common"; -import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager"; import { AuthService } from "../auth/auth.service"; import { Roles } from "../auth/decorators/roles.decorator"; import { AuthGuard } from "../auth/guards/auth.guard"; @@ -27,6 +29,7 @@ import { UsersService } from "./users.service"; export class UsersController { constructor( private readonly usersService: UsersService, + @Inject(forwardRef(() => AuthService)) private readonly authService: AuthService, ) {} diff --git a/backend/src/users/users.module.ts b/backend/src/users/users.module.ts index 317a7a7..a15fae5 100644 --- a/backend/src/users/users.module.ts +++ b/backend/src/users/users.module.ts @@ -1,13 +1,13 @@ -import { Module } from "@nestjs/common"; +import { forwardRef, Module } from "@nestjs/common"; import { AuthModule } from "../auth/auth.module"; import { CryptoModule } from "../crypto/crypto.module"; import { DatabaseModule } from "../database/database.module"; +import { UsersRepository } from "./repositories/users.repository"; import { UsersController } from "./users.controller"; import { UsersService } from "./users.service"; -import { UsersRepository } from "./repositories/users.repository"; @Module({ - imports: [DatabaseModule, CryptoModule, AuthModule], + imports: [DatabaseModule, CryptoModule, forwardRef(() => AuthModule)], controllers: [UsersController], providers: [UsersService, UsersRepository], exports: [UsersService], diff --git a/backend/src/users/users.service.spec.ts b/backend/src/users/users.service.spec.ts index 637017f..2bc21f5 100644 --- a/backend/src/users/users.service.spec.ts +++ b/backend/src/users/users.service.spec.ts @@ -11,10 +11,10 @@ jest.mock("jose", () => ({ jwtVerify: jest.fn(), })); -import { Test, TestingModule } from "@nestjs/testing"; import { CACHE_MANAGER } from "@nestjs/cache-manager"; -import { UsersService } from "./users.service"; +import { Test, TestingModule } from "@nestjs/testing"; import { UsersRepository } from "./repositories/users.repository"; +import { UsersService } from "./users.service"; describe("UsersService", () => { let service: UsersService; @@ -91,7 +91,9 @@ describe("UsersService", () => { describe("update", () => { it("should update a user", async () => { - mockUsersRepository.update.mockResolvedValue([{ uuid: "uuid1", displayName: "New" }]); + mockUsersRepository.update.mockResolvedValue([ + { uuid: "uuid1", displayName: "New" }, + ]); const result = await service.update("uuid1", { displayName: "New" }); expect(result[0].displayName).toBe("New"); }); diff --git a/backend/src/users/users.service.ts b/backend/src/users/users.service.ts index 59e68bd..8c7a97e 100644 --- a/backend/src/users/users.service.ts +++ b/backend/src/users/users.service.ts @@ -1,8 +1,8 @@ -import { Injectable, Logger, Inject } from "@nestjs/common"; import { CACHE_MANAGER } from "@nestjs/cache-manager"; -import { Cache } from "cache-manager"; -import { UsersRepository } from "./repositories/users.repository"; +import { Inject, Injectable, Logger } from "@nestjs/common"; +import type { Cache } from "cache-manager"; import { UpdateUserDto } from "./dto/update-user.dto"; +import { UsersRepository } from "./repositories/users.repository"; @Injectable() export class UsersService { diff --git a/backend/test/__mocks__/cuid2.js b/backend/test/__mocks__/cuid2.js deleted file mode 100644 index e95da3d..0000000 --- a/backend/test/__mocks__/cuid2.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - createCuid: () => () => 'mocked-cuid', -}; \ No newline at end of file diff --git a/backend/test/__mocks__/jose.js b/backend/test/__mocks__/jose.js deleted file mode 100644 index 006ccab..0000000 --- a/backend/test/__mocks__/jose.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - SignJWT: class { - constructor() { return this; } - setProtectedHeader() { return this; } - setIssuedAt() { return this; } - setExpirationTime() { return this; } - sign() { return Promise.resolve('mocked-token'); } - }, - jwtVerify: () => Promise.resolve({ payload: { sub: 'mocked-user' } }), - importJWK: () => Promise.resolve({}), - exportJWK: () => Promise.resolve({}), - generateKeyPair: () => Promise.resolve({ publicKey: {}, privateKey: {} }), -}; \ No newline at end of file diff --git a/backend/test/__mocks__/ml-kem.js b/backend/test/__mocks__/ml-kem.js deleted file mode 100644 index 2ef4c06..0000000 --- a/backend/test/__mocks__/ml-kem.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - ml_kem768: { - keygen: () => ({ publicKey: Buffer.alloc(1184), secretKey: Buffer.alloc(2400) }), - encapsulate: () => ({ cipherText: Buffer.alloc(1088), sharedSecret: Buffer.alloc(32) }), - decapsulate: () => Buffer.alloc(32), - } -}; \ No newline at end of file diff --git a/backend/test/__mocks__/sha3.js b/backend/test/__mocks__/sha3.js deleted file mode 100644 index b1a25f2..0000000 --- a/backend/test/__mocks__/sha3.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - sha3_256: () => ({ update: () => ({ digest: () => Buffer.alloc(32) }) }), - sha3_512: () => ({ update: () => ({ digest: () => Buffer.alloc(64) }) }), - shake256: () => ({ update: () => ({ digest: () => Buffer.alloc(32) }) }), -}; \ No newline at end of file diff --git a/backend/test/app.e2e-spec.ts b/backend/test/app.e2e-spec.ts deleted file mode 100644 index 8e18dd4..0000000 --- a/backend/test/app.e2e-spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { INestApplication } from "@nestjs/common"; -import { Test, TestingModule } from "@nestjs/testing"; -import request from "supertest"; -import { App } from "supertest/types"; -import { AppModule } from "../src/app.module"; - -describe("AppController (e2e)", () => { - let app: INestApplication; - - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); - - app = moduleFixture.createNestApplication(); - await app.init(); - }); - - it("/ (GET)", () => { - return request(app.getHttpServer()) - .get("/") - .expect(200) - .expect("Hello World!"); - }); -}); diff --git a/backend/test/jest-e2e.json b/backend/test/jest-e2e.json deleted file mode 100644 index f43e8a6..0000000 --- a/backend/test/jest-e2e.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "moduleFileExtensions": ["js", "json", "ts"], - "rootDir": ".", - "testEnvironment": "node", - "testRegex": ".e2e-spec.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - } -}