import { getUserEncryptionKey } from "../keyManager.js"; import System from "../System.js"; import { ActChapter } from "./Act.js"; import PlotPointRepository, { PlotPointQuery } from "../repositories/plotpoint.repository.js"; import RemovedItem from "./RemovedItem.js"; export interface PlotPointStory { plotTitle: string; plotSummary: string; chapterSummary: string; chapterGoal: string; } export interface PlotPointProps { plotPointId: string, title: string, summary: string, linkedIncidentId: string | null, chapters?: ActChapter[] } export interface SyncedPlotPoint { id: string; name: string; lastUpdate: number; } export default class PlotPoint { /** * Retrieves all plot points for a specific book with their associated chapters. * Decrypts plot point titles and summaries using the user's encryption key. * @param userId - The unique identifier of the user * @param bookId - The unique identifier of the book * @param actChapters - Array of act chapters to associate with plot points * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr' * @returns A promise resolving to an array of plot point properties with their associated chapters */ public static async getPlotPoints( userId: string, bookId: string, actChapters: ActChapter[], lang: 'fr' | 'en' = 'fr' ): Promise { const plotPointQueryResults: PlotPointQuery[] = PlotPointRepository.fetchAllPlotPoints(userId, bookId, lang); const userEncryptionKey: string = getUserEncryptionKey(userId); const plotPoints: PlotPointProps[] = []; if (plotPointQueryResults.length > 0) { for (const plotPointRow of plotPointQueryResults) { const associatedChapters: ActChapter[] = []; for (const chapter of actChapters) { if (chapter.plotPointId === plotPointRow.plot_point_id) { associatedChapters.push(chapter); } } plotPoints.push({ plotPointId: plotPointRow.plot_point_id, title: plotPointRow.title ? System.decryptDataWithUserKey(plotPointRow.title, userEncryptionKey) : '', summary: plotPointRow.summary ? System.decryptDataWithUserKey(plotPointRow.summary, userEncryptionKey) : '', linkedIncidentId: plotPointRow.linked_incident_id, chapters: associatedChapters }); } } return plotPoints; } /** * Creates a new plot point for a book, encrypting the name before storage. * @param userId - The unique identifier of the user * @param bookId - The unique identifier of the book * @param incidentId - The identifier of the linked incident * @param name - The name/title of the plot point * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr' * @param existingPlotPointId - Optional existing plot point ID to use instead of generating a new one * @returns The unique identifier of the created plot point */ static addNewPlotPoint( userId: string, bookId: string, incidentId: string, name: string, lang: 'fr' | 'en' = 'fr', existingPlotPointId?: string ): string { const userEncryptionKey: string = getUserEncryptionKey(userId); const encryptedName: string = System.encryptDataWithUserKey(name, userEncryptionKey); const hashedName: string = System.hashElement(name); const plotPointId: string = existingPlotPointId || System.createUniqueId(); return PlotPointRepository.insertNewPlotPoint(plotPointId, userId, bookId, encryptedName, hashedName, incidentId, lang); } /** * Removes a plot point from the database. * @param userId - The unique identifier of the user * @param bookId - The unique identifier of the book * @param plotId - The unique identifier of the plot point to remove * @param deletedAt - The timestamp of deletion * @param lang - The language for error messages ('fr' or 'en'), defaults to 'fr' * @returns True if the plot point was successfully deleted, false otherwise */ static removePlotPoint(userId: string, bookId: string, plotId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean { const deleted: boolean = PlotPointRepository.deletePlotPoint(userId, plotId, lang); if (deleted) { RemovedItem.deleteTracker(userId, bookId, 'book_plot_points', plotId, deletedAt, lang); } return deleted; } }