import { getUserEncryptionKey } from "../keyManager.js"; import System from "../System.js"; import SeriesWorldRepo, { SeriesWorldResult } from "../repositories/series-world.repo.js"; export interface SeriesWorldElementProps { id: string; name: string; description: string; } export interface SeriesWorldListProps { id: string; name: string; history: string; politics: string; economy: string; religion: string; languages: string; laws: SeriesWorldElementProps[]; biomes: SeriesWorldElementProps[]; issues: SeriesWorldElementProps[]; customs: SeriesWorldElementProps[]; kingdoms: SeriesWorldElementProps[]; climate: SeriesWorldElementProps[]; resources: SeriesWorldElementProps[]; wildlife: SeriesWorldElementProps[]; arts: SeriesWorldElementProps[]; ethnicGroups: SeriesWorldElementProps[]; socialClasses: SeriesWorldElementProps[]; importantCharacters: SeriesWorldElementProps[]; } export interface SeriesWorldUpdateProps { name: string; history?: string; politics?: string; economy?: string; religion?: string; languages?: string; } const ELEMENT_TYPE_MAP: Record = { 0: 'laws', 1: 'biomes', 2: 'issues', 3: 'customs', 4: 'kingdoms', 5: 'climate', 6: 'resources', 7: 'wildlife', 8: 'arts', 9: 'ethnicGroups', 10: 'socialClasses', 11: 'importantCharacters' }; export default class SeriesWorld { /** * Retrieves all worlds and their elements for a series. * @param userId - The unique identifier of the user * @param seriesId - The unique identifier of the series * @param lang - The language for error messages ('fr' or 'en') * @returns The list of worlds */ public static getWorldList(userId: string, seriesId: string, lang: 'fr' | 'en' = 'fr'): SeriesWorldListProps[] { const userKey: string = getUserEncryptionKey(userId); const worldsResult: SeriesWorldResult[] = SeriesWorldRepo.fetchWorlds(userId, seriesId, lang); const worldsMap: Map = new Map(); for (const row of worldsResult) { if (!worldsMap.has(row.world_id)) { worldsMap.set(row.world_id, { id: row.world_id, name: row.world_name ? System.decryptDataWithUserKey(row.world_name, userKey) : '', history: row.history ? System.decryptDataWithUserKey(row.history, userKey) : '', politics: row.politics ? System.decryptDataWithUserKey(row.politics, userKey) : '', economy: row.economy ? System.decryptDataWithUserKey(row.economy, userKey) : '', religion: row.religion ? System.decryptDataWithUserKey(row.religion, userKey) : '', languages: row.languages ? System.decryptDataWithUserKey(row.languages, userKey) : '', laws: [], biomes: [], issues: [], customs: [], kingdoms: [], climate: [], resources: [], wildlife: [], arts: [], ethnicGroups: [], socialClasses: [], importantCharacters: [] }); } if (row.element_id) { const world = worldsMap.get(row.world_id)!; const element: SeriesWorldElementProps = { id: row.element_id, name: row.element_name ? System.decryptDataWithUserKey(row.element_name, userKey) : '', description: row.element_description ? System.decryptDataWithUserKey(row.element_description, userKey) : '' }; const key = ELEMENT_TYPE_MAP[row.element_type]; if (key && Array.isArray(world[key])) { (world[key] as SeriesWorldElementProps[]).push(element); } } } return Array.from(worldsMap.values()); } /** * Adds a new world to a series. * @param userId - The unique identifier of the user * @param seriesId - The unique identifier of the series * @param name - The name of the world * @param lang - The language for error messages ('fr' or 'en') * @returns The new world ID */ public static addWorld(userId: string, seriesId: string, name: string, lang: 'fr' | 'en' = 'fr'): string { const hashedName: string = System.hashElement(name); const exists: boolean = SeriesWorldRepo.checkWorldExist(userId, seriesId, hashedName, lang); if (exists) { throw new Error(lang === 'fr' ? 'Un monde avec ce nom existe déjà.' : 'A world with this name already exists.'); } const userKey: string = getUserEncryptionKey(userId); const worldId: string = System.createUniqueId(); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); SeriesWorldRepo.insertNewWorld(worldId, userId, seriesId, encryptedName, hashedName, lang); return worldId; } /** * Updates a world's information. * @param userId - The unique identifier of the user * @param worldId - The unique identifier of the world * @param world - The updated world data * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static updateWorld(userId: string, worldId: string, world: SeriesWorldUpdateProps, lang: 'fr' | 'en' = 'fr'): boolean { const userKey: string = getUserEncryptionKey(userId); const encryptedName: string = System.encryptDataWithUserKey(world.name, userKey); const hashedName: string = System.hashElement(world.name); const encryptedHistory: string | null = world.history ? System.encryptDataWithUserKey(world.history, userKey) : null; const encryptedPolitics: string | null = world.politics ? System.encryptDataWithUserKey(world.politics, userKey) : null; const encryptedEconomy: string | null = world.economy ? System.encryptDataWithUserKey(world.economy, userKey) : null; const encryptedReligion: string | null = world.religion ? System.encryptDataWithUserKey(world.religion, userKey) : null; const encryptedLanguages: string | null = world.languages ? System.encryptDataWithUserKey(world.languages, userKey) : null; return SeriesWorldRepo.updateWorld(userId, worldId, encryptedName, hashedName, encryptedHistory, encryptedPolitics, encryptedEconomy, encryptedReligion, encryptedLanguages, lang); } /** * Adds a new element to a world. * @param userId - The unique identifier of the user * @param worldId - The unique identifier of the world * @param elementType - The type of element (0-11) * @param name - The name of the element * @param lang - The language for error messages ('fr' or 'en') * @param description - The description of the element (optional) * @returns The new element ID */ public static addElement(userId: string, worldId: string, elementType: number, name: string, lang: 'fr' | 'en' = 'fr', description?: string): string { const userKey: string = getUserEncryptionKey(userId); const elementId: string = System.createUniqueId(); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); const originalName: string = System.hashElement(name); const encryptedDescription: string | null = description ? System.encryptDataWithUserKey(description, userKey) : null; SeriesWorldRepo.insertElement(elementId, worldId, userId, elementType, encryptedName, originalName, encryptedDescription, lang); return elementId; } /** * Deletes an element from a world. * @param userId - The unique identifier of the user * @param elementId - The unique identifier of the element * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static deleteElement(userId: string, elementId: string, lang: 'fr' | 'en' = 'fr'): boolean { return SeriesWorldRepo.deleteElement(userId, elementId, lang); } }