Add models for guidelines, incidents, plot points, issues, acts, and world data
- Introduced new models: `GuideLine`, `Incident`, `PlotPoint`, `Issue`, `Act`, and `World` for managing book-related entities. - Integrated encryption/decryption for sensitive properties in all models using user-specific keys. - Added methods for CRUD operations and synchronization workflows with error handling and multilingual support. - Improved maintainability with JSDoc comments and streamlined queries.
This commit is contained in:
185
electron/database/models/Act.ts
Normal file
185
electron/database/models/Act.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { getUserEncryptionKey } from "../keyManager.js";
|
||||
import System from "../System.js";
|
||||
import PlotPoint, { PlotPointProps, PlotPointStory } from "./PlotPoint.js";
|
||||
import Incident, { IncidentProps, IncidentStory } from "./Incident.js";
|
||||
import ActRepository, { ActQuery } from "../repositories/act.repository.js";
|
||||
import Chapter, { ChapterProps } from "./Chapter.js";
|
||||
import IncidentRepository from "../repositories/incident.repository.js";
|
||||
import PlotPointRepository from "../repositories/plotpoint.repository.js";
|
||||
import ChapterRepo from "../repositories/chapter.repository.js";
|
||||
|
||||
export interface ActProps {
|
||||
id: number;
|
||||
summary: string | null;
|
||||
incidents?: IncidentProps[];
|
||||
plotPoints?: PlotPointProps[];
|
||||
chapters?: ActChapter[];
|
||||
}
|
||||
|
||||
export interface ActStory {
|
||||
actId: number;
|
||||
summary: string;
|
||||
chapterSummary: string;
|
||||
chapterGoal: string;
|
||||
incidents: IncidentStory[];
|
||||
plotPoints: PlotPointStory[];
|
||||
}
|
||||
|
||||
export interface ActChapter {
|
||||
chapterInfoId: number;
|
||||
chapterId: string;
|
||||
title: string;
|
||||
chapterOrder: number;
|
||||
actId: number;
|
||||
incidentId: string | null;
|
||||
plotPointId: string | null;
|
||||
summary: string;
|
||||
goal: string;
|
||||
}
|
||||
|
||||
export interface SyncedActSummary {
|
||||
id: string;
|
||||
lastUpdate: number;
|
||||
}
|
||||
|
||||
export default class Act {
|
||||
/**
|
||||
* Retrieves all acts data for a specific book, including chapters, incidents, and plot points.
|
||||
* Decrypts summaries using the user's encryption key.
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param bookId - The unique identifier of the book
|
||||
* @param lang - The language for localization ('fr' or 'en'), defaults to 'fr'
|
||||
* @returns A promise resolving to an array of Act objects with their associated data
|
||||
*/
|
||||
public static async getActsData(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): Promise<ActProps[]> {
|
||||
const userEncryptionKey: string = getUserEncryptionKey(userId);
|
||||
const actChapters: ActChapter[] = Chapter.getAllChapterFromActs(userId, bookId, lang);
|
||||
const actQueries: ActQuery[] = ActRepository.fetchAllActs(userId, bookId, lang);
|
||||
const bookIncidents: IncidentProps[] = await Incident.getIncitentsIncidents(userId, bookId, actChapters);
|
||||
const bookPlotPoints: PlotPointProps[] = await PlotPoint.getPlotPoints(userId, bookId, actChapters);
|
||||
|
||||
const acts: ActProps[] = [];
|
||||
|
||||
acts.push({
|
||||
id: 1,
|
||||
summary: '',
|
||||
chapters: actChapters.filter((chapter: ActChapter) => chapter.actId === 1)
|
||||
});
|
||||
|
||||
acts.push({
|
||||
id: 2,
|
||||
summary: '',
|
||||
incidents: bookIncidents ? bookIncidents : [],
|
||||
});
|
||||
|
||||
acts.push({
|
||||
id: 3,
|
||||
summary: '',
|
||||
plotPoints: bookPlotPoints ? bookPlotPoints : [],
|
||||
});
|
||||
|
||||
acts.push({
|
||||
id: 4,
|
||||
summary: '',
|
||||
chapters: actChapters.filter((chapter: ActChapter) => chapter.actId === 4)
|
||||
});
|
||||
|
||||
acts.push({
|
||||
id: 5,
|
||||
summary: '',
|
||||
chapters: actChapters.filter((chapter: ActChapter) => chapter.actId === 5)
|
||||
});
|
||||
|
||||
if (actQueries.length > 0) {
|
||||
for (const actQuery of actQueries) {
|
||||
acts[actQuery.act_index - 1].summary = actQuery.summary && userEncryptionKey
|
||||
? System.decryptDataWithUserKey(actQuery.summary, userEncryptionKey)
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
||||
return acts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates multiple acts including their summaries, incidents, plot points, and chapter information.
|
||||
* Encrypts all sensitive data before storing in the database.
|
||||
* @param acts - Array of act properties to update
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param bookId - The unique identifier of the book
|
||||
* @param userKey - The user's encryption key for data encryption
|
||||
* @param lang - The language for localization ('fr' or 'en'), defaults to 'fr'
|
||||
* @returns A promise resolving to true when all updates are complete
|
||||
*/
|
||||
public static async updateAct(acts: ActProps[], userId: string, bookId: string, userKey: string, lang: 'fr' | 'en' = 'fr'): Promise<boolean> {
|
||||
for (const act of acts) {
|
||||
const actIncidents: IncidentProps[] = act.incidents ? act.incidents : [];
|
||||
const actId: number = act.id;
|
||||
|
||||
if (actId === 1 || actId === 4 || actId === 5) {
|
||||
const encryptedActSummary: string = act.summary ? System.encryptDataWithUserKey(act.summary, userKey) : '';
|
||||
try {
|
||||
ActRepository.updateActSummary(userId, bookId, actId, encryptedActSummary, System.timeStampInSeconds(), lang);
|
||||
} catch (error: unknown) {
|
||||
const newActSummaryId: string = System.createUniqueId();
|
||||
ActRepository.insertActSummary(newActSummaryId, userId, bookId, actId, encryptedActSummary, lang);
|
||||
}
|
||||
if (act.chapters) {
|
||||
Chapter.updateChapterInfos(act.chapters, userId, actId, bookId, null, null, lang);
|
||||
}
|
||||
} else if (actId === 2) {
|
||||
for (const incident of actIncidents) {
|
||||
const encryptedIncidentSummary: string = incident.summary ? System.encryptDataWithUserKey(incident.summary, userKey) : '';
|
||||
const incidentId: string = incident.incidentId;
|
||||
const incidentTitle: string = incident.title;
|
||||
const hashedIncidentTitle: string = System.hashElement(incidentTitle);
|
||||
const encryptedIncidentTitle: string = System.encryptDataWithUserKey(incidentTitle, userKey);
|
||||
IncidentRepository.updateIncident(userId, bookId, incidentId, encryptedIncidentTitle, hashedIncidentTitle, encryptedIncidentSummary, System.timeStampInSeconds(), lang);
|
||||
if (incident.chapters) {
|
||||
Chapter.updateChapterInfos(incident.chapters, userId, actId, bookId, incidentId, null, lang);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const actPlotPoints: PlotPointProps[] = act.plotPoints ? act.plotPoints : [];
|
||||
for (const plotPoint of actPlotPoints) {
|
||||
const encryptedPlotPointSummary: string = plotPoint.summary ? System.encryptDataWithUserKey(plotPoint.summary, userKey) : '';
|
||||
const plotPointId: string = plotPoint.plotPointId;
|
||||
const plotPointTitle: string = plotPoint.title;
|
||||
const hashedPlotPointTitle: string = System.hashElement(plotPointTitle);
|
||||
const encryptedPlotPointTitle: string = System.encryptDataWithUserKey(plotPointTitle, userKey);
|
||||
PlotPointRepository.updatePlotPoint(userId, bookId, plotPointId, encryptedPlotPointTitle, hashedPlotPointTitle, encryptedPlotPointSummary, System.timeStampInSeconds(), lang);
|
||||
if (plotPoint.chapters) {
|
||||
Chapter.updateChapterInfos(plotPoint.chapters, userId, actId, bookId, null, plotPointId, lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the story structure including acts and main chapters.
|
||||
* Encrypts chapter titles and updates their order in the database.
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param bookId - The unique identifier of the book
|
||||
* @param acts - Array of act properties to update
|
||||
* @param mainChapters - Array of main chapter properties to update
|
||||
* @param lang - The language for localization ('fr' or 'en'), defaults to 'fr'
|
||||
* @returns True when all updates are complete
|
||||
*/
|
||||
public static updateStory(userId: string, bookId: string, acts: ActProps[], mainChapters: ChapterProps[], lang: 'fr' | 'en' = 'fr'): boolean {
|
||||
const userEncryptionKey: string = getUserEncryptionKey(userId);
|
||||
Act.updateAct(acts, userId, bookId, userEncryptionKey, lang).then();
|
||||
|
||||
for (const chapter of mainChapters) {
|
||||
const chapterId: string = chapter.chapterId;
|
||||
const chapterTitle: string = chapter.title;
|
||||
const hashedChapterTitle: string = System.hashElement(chapterTitle);
|
||||
const encryptedChapterTitle: string = System.encryptDataWithUserKey(chapterTitle, userEncryptionKey);
|
||||
const chapterOrder: number = chapter.chapterOrder;
|
||||
ChapterRepo.updateChapter(userId, chapterId, encryptedChapterTitle, hashedChapterTitle, chapterOrder, System.timeStampInSeconds(), lang);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user