import LocationRepo, { LocationByTagResult, LocationElementQueryResult, LocationQueryResult } from "../repositories/location.repository.js"; import System from "../System.js"; import {getUserEncryptionKey} from "../keyManager.js"; export interface SubElement { id: string; name: string; description: string; } export interface Element { id: string; name: string; description: string; subElements: SubElement[]; } export interface LocationProps { id: string; name: string; elements: Element[]; } export default class Location { /** * Récupère toutes les locations pour un utilisateur et un livre donnés. * @param {string} userId - L'ID de l'utilisateur. * @param {string} bookId - L'ID du livre. * @returns {LocationProps[]} - Un tableau de propriétés de location. * @throws {Error} - Lance une erreur si une exception se produit lors de la récupération des locations. */ static getAllLocations(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): LocationProps[] { const locations: LocationQueryResult[] = LocationRepo.getLocation(userId, bookId, lang); if (!locations || locations.length === 0) return []; const userKey: string = getUserEncryptionKey(userId); const locationArray: LocationProps[] = []; for (const record of locations) { let location = locationArray.find(loc => loc.id === record.loc_id); if (!location) { const decryptedName: string = System.decryptDataWithUserKey(record.loc_name, userKey); location = { id: record.loc_id, name: decryptedName, elements: [] }; locationArray.push(location); } if (record.element_id) { let element = location.elements.find(elem => elem.id === record.element_id); if (!element) { const decryptedName: string = System.decryptDataWithUserKey(record.element_name, userKey); const decryptedDesc: string = record.element_description ? System.decryptDataWithUserKey(record.element_description, userKey) : ''; element = { id: record.element_id, name: decryptedName, description: decryptedDesc, subElements: [] }; location.elements.push(element); } if (record.sub_element_id) { const subElementExists = element.subElements.some(sub => sub.id === record.sub_element_id); if (!subElementExists) { const decryptedName: string = System.decryptDataWithUserKey(record.sub_elem_name, userKey); const decryptedDesc: string = record.sub_elem_description ? System.decryptDataWithUserKey(record.sub_elem_description, userKey) : ''; element.subElements.push({ id: record.sub_element_id, name: decryptedName, description: decryptedDesc }); } } } } return locationArray; } static addLocationSection(userId: string, locationName: string, bookId: string, lang: 'fr' | 'en' = 'fr', existingLocationId?: string): string { const userKey: string = getUserEncryptionKey(userId); const originalName: string = System.hashElement(locationName); const encryptedName: string = System.encryptDataWithUserKey(locationName, userKey); const locationId: string = existingLocationId || System.createUniqueId(); return LocationRepo.insertLocation(userId, locationId, bookId, encryptedName, originalName, lang); } static addLocationElement(userId: string, locationId: string, elementName: string, lang: 'fr' | 'en' = 'fr', existingElementId?: string) { const userKey: string = getUserEncryptionKey(userId); const originalName: string = System.hashElement(elementName); const encryptedName: string = System.encryptDataWithUserKey(elementName, userKey); const elementId: string = existingElementId || System.createUniqueId(); return LocationRepo.insertLocationElement(userId, elementId, locationId, encryptedName, originalName, lang) } static addLocationSubElement(userId: string, elementId: string, subElementName: string, lang: 'fr' | 'en' = 'fr', existingSubElementId?: string) { const userKey: string = getUserEncryptionKey(userId); const originalName: string = System.hashElement(subElementName); const encryptedName: string = System.encryptDataWithUserKey(subElementName, userKey); const subElementId: string = existingSubElementId || System.createUniqueId(); return LocationRepo.insertLocationSubElement(userId, subElementId, elementId, encryptedName, originalName, lang) } static updateLocationSection(userId: string, locations: LocationProps[], lang: 'fr' | 'en' = 'fr') { const userKey: string = getUserEncryptionKey(userId); for (const location of locations) { const originalName: string = System.hashElement(location.name); const encryptedName: string = System.encryptDataWithUserKey(location.name, userKey); LocationRepo.updateLocationSection(userId, location.id, encryptedName, originalName, System.timeStampInSeconds(),lang) for (const element of location.elements) { const originalName: string = System.hashElement(element.name); const encryptedName: string = System.encryptDataWithUserKey(element.name, userKey); const encryptDescription: string = element.description ? System.encryptDataWithUserKey(element.description, userKey) : ''; LocationRepo.updateLocationElement(userId, element.id, encryptedName, originalName, encryptDescription, System.timeStampInSeconds(), lang) for (const subElement of element.subElements) { const originalName: string = System.hashElement(subElement.name); const encryptedName: string = System.encryptDataWithUserKey(subElement.name, userKey); const encryptDescription: string = subElement.description ? System.encryptDataWithUserKey(subElement.description, userKey) : ''; LocationRepo.updateLocationSubElement(userId, subElement.id, encryptedName, originalName, encryptDescription,System.timeStampInSeconds(),lang) } } } return { valid: true, message: lang === 'fr' ? 'Les sections ont été mis à jour.' : 'Sections have been updated.' } } static deleteLocationSection(userId: string, locationId: string, lang: 'fr' | 'en' = 'fr') { return LocationRepo.deleteLocationSection(userId, locationId, lang); } static deleteLocationElement(userId: string, elementId: string, lang: 'fr' | 'en' = 'fr') { return LocationRepo.deleteLocationElement(userId, elementId, lang); } static deleteLocationSubElement(userId: string, subElementId: string, lang: 'fr' | 'en' = 'fr') { return LocationRepo.deleteLocationSubElement(userId, subElementId, lang); } static getLocationTags(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): SubElement[] { const data: LocationElementQueryResult[] = LocationRepo.fetchLocationTags(userId, bookId, lang); if (!data || data.length === 0) return []; const userKey: string = getUserEncryptionKey(userId); const elementCounts = new Map(); data.forEach((record: LocationElementQueryResult): void => { elementCounts.set(record.element_id, (elementCounts.get(record.element_id) || 0) + 1); }); const subElements: SubElement[] = []; const processedIds = new Set(); for (const record of data) { const elementCount: number = elementCounts.get(record.element_id) || 0; if (elementCount > 1 && record.sub_element_id) { if (processedIds.has(record.sub_element_id)) continue; subElements.push({ id: record.sub_element_id, name: System.decryptDataWithUserKey(record.sub_elem_name, userKey), description: record.sub_elem_description ? System.decryptDataWithUserKey(record.sub_elem_description, userKey) : '' }); processedIds.add(record.sub_element_id); } else if (elementCount === 1 && !record.sub_element_id) { if (processedIds.has(record.element_id)) continue; subElements.push({ id: record.element_id, name: System.decryptDataWithUserKey(record.element_name, userKey), description: record.element_description ? System.decryptDataWithUserKey(record.element_description, userKey) : '' }); processedIds.add(record.element_id); } } return subElements; } static getLocationsByTags(userId: string, locations: string[], lang: 'fr' | 'en' = 'fr'): Element[] { const locationsTags: LocationByTagResult[] = LocationRepo.fetchLocationsByTags(userId, locations, lang); if (!locationsTags || locationsTags.length === 0) return []; const userKey: string = getUserEncryptionKey(userId); const locationTags: Element[] = []; for (const record of locationsTags) { let element: Element | undefined = locationTags.find((elem: Element): boolean => elem.name === record.element_name); if (!element) { const decryptedName: string = System.decryptDataWithUserKey(record.element_name, userKey); const decryptedDesc: string = record.element_description ? System.decryptDataWithUserKey(record.element_description, userKey) : ''; element = { id: '', name: decryptedName, description: decryptedDesc, subElements: [] }; locationTags.push(element); } if (record.sub_elem_name) { const subElementExists: boolean = element.subElements.some(sub => sub.name === record.sub_elem_name); if (!subElementExists) { const decryptedName: string = System.decryptDataWithUserKey(record.sub_elem_name, userKey); const decryptedDesc: string = record.sub_elem_description ? System.decryptDataWithUserKey(record.sub_elem_description, userKey) : ''; element.subElements.push({ id: '', name: decryptedName, description: decryptedDesc }); } } } return locationTags; } static locationsDescription(locations: Element[]): string { return locations.map((location: Element): string => { const fields: string[] = []; if (location.name) fields.push(`Nom : ${location.name}`); if (location.description) fields.push(`Description : ${location.description}`); return fields.join('\n'); }).join('\n\n'); } }