- Introduce new error messages for syncing and book deletion in `en.json`. - Update `DeleteBook` to support local-only deletion and synced book management. - Refine offline/online behavior with `deleteLocalToo` checkbox and update related state handling. - Extend repository and IPC methods to handle optional IDs for updates. - Add `SyncQueueContext` for queueing offline changes and improving synchronization workflows. - Enhance refined text generation logic in `DraftCompanion` and `GhostWriter` components. - Replace PUT with PATCH for world updates to align with API expectations. - Streamline `AlertBox` by integrating dynamic translation keys for deletion prompts.
235 lines
12 KiB
TypeScript
235 lines
12 KiB
TypeScript
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<string, number>();
|
|
data.forEach((record: LocationElementQueryResult): void => {
|
|
elementCounts.set(record.element_id, (elementCounts.get(record.element_id) || 0) + 1);
|
|
});
|
|
|
|
const subElements: SubElement[] = [];
|
|
const processedIds = new Set<string>();
|
|
|
|
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');
|
|
}
|
|
}
|