import { getUserEncryptionKey } from "../keyManager.js"; import System from "../System.js"; import SeriesLocationRepo, { SeriesLocationResult, SeriesLocationElementResult, SeriesLocationSubElementResult } from "../repositories/series-location.repo.js"; import RemovedItem from "./RemovedItem.js"; export interface SeriesLocationSubElementProps { id: string; name: string; description: string; } export interface SeriesLocationElementProps { id: string; name: string; description: string; subElements: SeriesLocationSubElementProps[]; } export interface SeriesLocationListProps { id: string; name: string; elements: SeriesLocationElementProps[]; } export default class SeriesLocation { /** * Retrieves all locations for a series with their elements and sub-elements. * @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 locations */ public static getLocationList(userId: string, seriesId: string, lang: 'fr' | 'en' = 'fr'): SeriesLocationListProps[] { const userKey: string = getUserEncryptionKey(userId); const locationsResult: SeriesLocationResult[] = SeriesLocationRepo.fetchLocations(userId, seriesId, lang); return locationsResult.map((loc): SeriesLocationListProps => { const elementsResult: SeriesLocationElementResult[] = SeriesLocationRepo.fetchElements(userId, loc.loc_id, lang); const elements: SeriesLocationElementProps[] = elementsResult.map((elem): SeriesLocationElementProps => { const subElementsResult: SeriesLocationSubElementResult[] = SeriesLocationRepo.fetchSubElements(userId, elem.element_id, lang); const subElements: SeriesLocationSubElementProps[] = subElementsResult.map((sub): SeriesLocationSubElementProps => ({ id: sub.sub_element_id, name: sub.sub_elem_name ? System.decryptDataWithUserKey(sub.sub_elem_name, userKey) : '', description: sub.sub_elem_description ? System.decryptDataWithUserKey(sub.sub_elem_description, userKey) : '' })); return { id: elem.element_id, name: elem.element_name ? System.decryptDataWithUserKey(elem.element_name, userKey) : '', description: elem.element_description ? System.decryptDataWithUserKey(elem.element_description, userKey) : '', subElements }; }); return { id: loc.loc_id, name: loc.loc_name ? System.decryptDataWithUserKey(loc.loc_name, userKey) : '', elements }; }); } /** * Adds a new location section 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 location * @param lang - The language for error messages ('fr' or 'en') * @returns The new location ID */ public static addLocationSection(userId: string, seriesId: string, name: string, lang: 'fr' | 'en' = 'fr'): string { const userKey: string = getUserEncryptionKey(userId); const locationId: string = System.createUniqueId(); const encryptedName: string = System.encryptDataWithUserKey(name, userKey); const originalName: string = System.hashElement(name); SeriesLocationRepo.insertLocation(locationId, seriesId, userId, encryptedName, originalName, lang); return locationId; } /** * Adds a new element to a location. * @param userId - The unique identifier of the user * @param locationId - The unique identifier of the location * @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, locationId: string, 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; SeriesLocationRepo.insertElement(elementId, locationId, userId, encryptedName, originalName, encryptedDescription, lang); return elementId; } /** * Adds a new sub-element to an element. * @param userId - The unique identifier of the user * @param elementId - The unique identifier of the element * @param name - The name of the sub-element * @param lang - The language for error messages ('fr' or 'en') * @param description - The description of the sub-element (optional) * @returns The new sub-element ID */ public static addSubElement(userId: string, elementId: string, name: string, lang: 'fr' | 'en' = 'fr', description?: string): string { const userKey: string = getUserEncryptionKey(userId); const subElementId: 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; SeriesLocationRepo.insertSubElement(subElementId, elementId, userId, encryptedName, originalName, encryptedDescription, lang); return subElementId; } /** * Deletes a location section. * @param userId - The unique identifier of the user * @param locationId - The unique identifier of the location * @param deletedAt - The timestamp of deletion * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static deleteLocation(userId: string, locationId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean { const deleted: boolean = SeriesLocationRepo.deleteLocation(userId, locationId, lang); if (deleted) { RemovedItem.deleteTracker(userId, null, 'series_locations', locationId, deletedAt, lang); } return deleted; } /** * Deletes an element. * @param userId - The unique identifier of the user * @param elementId - The unique identifier of the element * @param deletedAt - The timestamp of deletion * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static deleteElement(userId: string, elementId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean { const deleted: boolean = SeriesLocationRepo.deleteElement(userId, elementId, lang); if (deleted) { RemovedItem.deleteTracker(userId, null, 'series_location_elements', elementId, deletedAt, lang); } return deleted; } /** * Deletes a sub-element. * @param userId - The unique identifier of the user * @param subElementId - The unique identifier of the sub-element * @param deletedAt - The timestamp of deletion * @param lang - The language for error messages ('fr' or 'en') * @returns True if successful */ public static deleteSubElement(userId: string, subElementId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean { const deleted: boolean = SeriesLocationRepo.deleteSubElement(userId, subElementId, lang); if (deleted) { RemovedItem.deleteTracker(userId, null, 'series_location_sub_elements', subElementId, deletedAt, lang); } return deleted; } }