import { getUserEncryptionKey } from "../keyManager.js"; import System from "../System.js"; import SeriesSpellRepo, { SeriesSpellResult, SeriesSpellTagResult } from "../repositories/series-spell.repo.js"; import RemovedItem from "./RemovedItem.js"; export interface SeriesSpellTagProps { id: string; name: string; color: string | null; } export interface SeriesSpellListProps { id: string; name: string; description: string; tags: string[]; } export interface SeriesSpellListResponse { spells: SeriesSpellListProps[]; tags: SeriesSpellTagProps[]; } export interface SeriesSpellDetailProps { id: string; name: string; description: string; appearance: string; tags: string[]; powerLevel: string | null; components: string | null; limitations: string | null; notes: string | null; } export default class SeriesSpell { /** * Retrieves all spells and tags 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 spells and tags */ public static getSpellList(userId: string, seriesId: string, lang: 'fr' | 'en' = 'fr'): SeriesSpellListResponse { const userKey: string = getUserEncryptionKey(userId); const spellsResult: SeriesSpellResult[] = SeriesSpellRepo.fetchSpells(userId, seriesId, lang); const tagsResult: SeriesSpellTagResult[] = SeriesSpellRepo.fetchTags(userId, seriesId, lang); const spells: SeriesSpellListProps[] = spellsResult.map((spell): SeriesSpellListProps => ({ id: spell.spell_id, name: spell.name ? System.decryptDataWithUserKey(spell.name, userKey) : '', description: spell.description ? System.decryptDataWithUserKey(spell.description, userKey) : '', tags: spell.tags ? JSON.parse(System.decryptDataWithUserKey(spell.tags, userKey)) : [] })); const tags: SeriesSpellTagProps[] = tagsResult.map((tag): SeriesSpellTagProps => ({ id: tag.tag_id, name: tag.name ? System.decryptDataWithUserKey(tag.name, userKey) : '', color: tag.color })); return { spells, tags }; } /** * Retrieves the details of a specific spell. * @param userId - The unique identifier of the user * @param spellId - The unique identifier of the spell * @param lang - The language for error messages ('fr' or 'en') * @returns The spell details */ public static getSpellDetail(userId: string, spellId: string, lang: 'fr' | 'en' = 'fr'): SeriesSpellDetailProps { const userKey: string = getUserEncryptionKey(userId); const spell: SeriesSpellResult | null = SeriesSpellRepo.fetchSpellById(userId, spellId, lang); if (!spell) { throw new Error(lang === 'fr' ? 'Sort non trouvé.' : 'Spell not found.'); } return { id: spell.spell_id, name: spell.name ? System.decryptDataWithUserKey(spell.name, userKey) : '', description: spell.description ? System.decryptDataWithUserKey(spell.description, userKey) : '', appearance: spell.appearance ? System.decryptDataWithUserKey(spell.appearance, userKey) : '', tags: spell.tags ? JSON.parse(System.decryptDataWithUserKey(spell.tags, userKey)) : [], powerLevel: spell.power_level ? System.decryptDataWithUserKey(spell.power_level, userKey) : null, components: spell.components ? System.decryptDataWithUserKey(spell.components, userKey) : null, limitations: spell.limitations ? System.decryptDataWithUserKey(spell.limitations, userKey) : null, notes: spell.notes ? System.decryptDataWithUserKey(spell.notes, userKey) : null }; } /** * Adds a new spell to a series. * @param userId - The unique identifier of the user * @param seriesId - The unique identifier of the series * @param name - The spell name * @param lang - The language for error messages ('fr' or 'en') * @param description - The spell description * @param appearance - The spell appearance * @param tags - The spell tags * @param powerLevel - The spell power level * @param components - The spell components * @param limitations - The spell limitations * @param notes - The spell notes * @returns The new spell ID */ public static addSpell(userId: string, seriesId: string, name: string, lang: 'fr' | 'en' = 'fr', description?: string | null, appearance?: string | null, tags?: string[], powerLevel?: string | null, components?: string | null, limitations?: string | null, notes?: string | null): string { const userKey: string = getUserEncryptionKey(userId); const spellId: string = System.createUniqueId(); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); const nameHash: string = System.hashElement(name); const encryptedDescription: string = description ? System.encryptDataWithUserKey(description, userKey) : ''; const encryptedAppearance: string = appearance ? System.encryptDataWithUserKey(appearance, userKey) : ''; const encryptedTags: string = System.encryptDataWithUserKey(JSON.stringify(tags || []), userKey); const encryptedPowerLevel: string | null = powerLevel ? System.encryptDataWithUserKey(powerLevel, userKey) : null; const encryptedComponents: string | null = components ? System.encryptDataWithUserKey(components, userKey) : null; const encryptedLimitations: string | null = limitations ? System.encryptDataWithUserKey(limitations, userKey) : null; const encryptedNotes: string | null = notes ? System.encryptDataWithUserKey(notes, userKey) : null; SeriesSpellRepo.insertSpell(spellId, seriesId, userId, encryptedName, nameHash, encryptedDescription, encryptedAppearance, encryptedTags, encryptedPowerLevel, encryptedComponents, encryptedLimitations, encryptedNotes, lang); return spellId; } /** * Updates an existing spell. * @param userId - The unique identifier of the user * @param spellId - The unique identifier of the spell * @param name - The spell name * @param lang - The language for error messages ('fr' or 'en') * @param description - The spell description * @param appearance - The spell appearance * @param tags - The spell tags * @param powerLevel - The spell power level * @param components - The spell components * @param limitations - The spell limitations * @param notes - The spell notes * @returns True if successful */ public static updateSpell(userId: string, spellId: string, name: string, lang: 'fr' | 'en' = 'fr', description?: string | null, appearance?: string | null, tags?: string[], powerLevel?: string | null, components?: string | null, limitations?: string | null, notes?: string | null): boolean { const userKey: string = getUserEncryptionKey(userId); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); const nameHash: string = System.hashElement(name); const encryptedDescription: string = description ? System.encryptDataWithUserKey(description, userKey) : ''; const encryptedAppearance: string = appearance ? System.encryptDataWithUserKey(appearance, userKey) : ''; const encryptedTags: string = System.encryptDataWithUserKey(JSON.stringify(tags || []), userKey); const encryptedPowerLevel: string | null = powerLevel ? System.encryptDataWithUserKey(powerLevel, userKey) : null; const encryptedComponents: string | null = components ? System.encryptDataWithUserKey(components, userKey) : null; const encryptedLimitations: string | null = limitations ? System.encryptDataWithUserKey(limitations, userKey) : null; const encryptedNotes: string | null = notes ? System.encryptDataWithUserKey(notes, userKey) : null; return SeriesSpellRepo.updateSpell(userId, spellId, encryptedName, nameHash, encryptedDescription, encryptedAppearance, encryptedTags, encryptedPowerLevel, encryptedComponents, encryptedLimitations, encryptedNotes, lang); } /** * Deletes a spell. * @param userId - The unique identifier of the user * @param spellId - The unique identifier of the spell * @param deletedAt - The timestamp of deletion * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static deleteSpell(userId: string, spellId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean { const deleted: boolean = SeriesSpellRepo.deleteSpell(userId, spellId, lang); if (deleted) { RemovedItem.deleteTracker(userId, null, 'series_spells', spellId, deletedAt, lang); } return deleted; } /** * Adds a new tag 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 tag * @param lang - The language for error messages ('fr' or 'en') * @param color - The color of the tag (optional) * @returns The new tag ID */ public static addTag(userId: string, seriesId: string, name: string, lang: 'fr' | 'en' = 'fr', color?: string | null): string { const userKey: string = getUserEncryptionKey(userId); const tagId: string = System.createUniqueId(); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); const hashedName: string = System.hashElement(name); SeriesSpellRepo.insertTag(tagId, seriesId, userId, encryptedName, hashedName, color || null, lang); return tagId; } /** * Updates an existing tag. * @param userId - The unique identifier of the user * @param tagId - The unique identifier of the tag * @param name - The new name of the tag * @param lang - The language for error messages ('fr' or 'en') * @param color - The new color of the tag (optional) * @returns True if successful */ public static updateTag(userId: string, tagId: string, name: string, lang: 'fr' | 'en' = 'fr', color?: string | null): boolean { const userKey: string = getUserEncryptionKey(userId); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); const hashedName: string = System.hashElement(name); return SeriesSpellRepo.updateTag(userId, tagId, encryptedName, hashedName, color || null, lang); } /** * Deletes a tag. * @param userId - The unique identifier of the user * @param tagId - The unique identifier of the tag * @param deletedAt - The timestamp of deletion * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static deleteTag(userId: string, tagId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean { const deleted: boolean = SeriesSpellRepo.deleteTag(userId, tagId, lang); if (deleted) { RemovedItem.deleteTracker(userId, null, 'series_spell_tags', tagId, deletedAt, lang); } return deleted; } }