- 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.
2264 lines
118 KiB
TypeScript
2264 lines
118 KiB
TypeScript
import type {
|
|
ActQuery,
|
|
BookActSummariesTable, BookAIGuideLineTable, BookChapterContentTable, BookChapterInfosTable, BookChaptersTable,
|
|
BookCharactersAttributesTable,
|
|
BookCharactersTable, BookGuideLineTable, BookIncidentsTable, BookIssuesTable, BookLocationTable,
|
|
BookPlotPointsTable, BookWorldElementsTable, BookWorldTable,
|
|
EritBooksTable,
|
|
IncidentQuery,
|
|
IssueQuery, LocationElementTable, LocationSubElementTable,
|
|
PlotPointQuery,
|
|
SyncedActSummaryResult,
|
|
SyncedAIGuideLineResult,
|
|
SyncedBookResult,
|
|
SyncedChapterContentResult,
|
|
SyncedChapterInfoResult,
|
|
SyncedChapterResult,
|
|
SyncedCharacterAttributeResult,
|
|
SyncedCharacterResult,
|
|
SyncedGuideLineResult,
|
|
SyncedIncidentResult,
|
|
SyncedIssueResult,
|
|
SyncedLocationElementResult,
|
|
SyncedLocationResult,
|
|
SyncedLocationSubElementResult,
|
|
SyncedPlotPointResult,
|
|
SyncedWorldElementResult,
|
|
SyncedWorldResult,
|
|
WorldQuery
|
|
} from '../repositories/book.repository.js';
|
|
import BookRepository from '../repositories/book.repository.js';
|
|
import BookRepo, {
|
|
BookCoverQuery,
|
|
BookQuery,
|
|
ChapterBookResult,
|
|
GuideLineAIQuery,
|
|
GuideLineQuery,
|
|
WorldElementValue
|
|
} from '../repositories/book.repository.js';
|
|
import System from '../System.js';
|
|
import {getUserEncryptionKey} from '../keyManager.js';
|
|
import path from "path";
|
|
import fs from "fs";
|
|
import Chapter, {ActChapter, ChapterContentData, ChapterProps} from "./Chapter.js";
|
|
import UserRepo from "../repositories/user.repository.js";
|
|
import ChapterRepo from "../repositories/chapter.repository.js";
|
|
import CharacterRepo from "../repositories/character.repository.js";
|
|
import LocationRepo from "../repositories/location.repository.js";
|
|
|
|
export interface BookProps{
|
|
id:string;
|
|
type:string;
|
|
authorId:string;
|
|
title:string;
|
|
subTitle?:string;
|
|
summary?:string;
|
|
serieId?:number;
|
|
desiredReleaseDate?:string;
|
|
desiredWordCount?:number;
|
|
wordCount?:number;
|
|
coverImage?:string;
|
|
bookMeta?:string;
|
|
}
|
|
|
|
export interface CompleteBook {
|
|
eritBooks: EritBooksTable[];
|
|
actSummaries: BookActSummariesTable[];
|
|
aiGuideLine: BookAIGuideLineTable[];
|
|
chapters: BookChaptersTable[];
|
|
chapterContents: BookChapterContentTable[];
|
|
chapterInfos: BookChapterInfosTable[];
|
|
characters: BookCharactersTable[];
|
|
characterAttributes: BookCharactersAttributesTable[];
|
|
guideLine: BookGuideLineTable[];
|
|
incidents: BookIncidentsTable[];
|
|
issues: BookIssuesTable[];
|
|
locations: BookLocationTable[];
|
|
plotPoints: BookPlotPointsTable[];
|
|
worlds: BookWorldTable[];
|
|
worldElements: BookWorldElementsTable[];
|
|
locationElements: LocationElementTable[];
|
|
locationSubElements: LocationSubElementTable[];
|
|
}
|
|
|
|
export interface SyncedBook {
|
|
id: string;
|
|
type: string;
|
|
title: string;
|
|
subTitle: string | null;
|
|
lastUpdate: number;
|
|
chapters: SyncedChapter[];
|
|
characters: SyncedCharacter[];
|
|
locations: SyncedLocation[];
|
|
worlds: SyncedWorld[];
|
|
incidents: SyncedIncident[];
|
|
plotPoints: SyncedPlotPoint[];
|
|
issues: SyncedIssue[];
|
|
actSummaries: SyncedActSummary[];
|
|
guideLine: SyncedGuideLine | null;
|
|
aiGuideLine: SyncedAIGuideLine | null;
|
|
}
|
|
|
|
export interface BookSyncCompare {
|
|
id: string;
|
|
chapters: string[];
|
|
chapterContents: string[];
|
|
chapterInfos: string[];
|
|
characters: string[];
|
|
characterAttributes: string[];
|
|
locations: string[];
|
|
locationElements: string[];
|
|
locationSubElements: string[];
|
|
worlds: string[];
|
|
worldElements: string[];
|
|
incidents: string[];
|
|
plotPoints: string[];
|
|
issues: string[];
|
|
actSummaries: string[];
|
|
guideLine: boolean;
|
|
aiGuideLine: boolean;
|
|
}
|
|
|
|
export interface SyncedChapter {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
contents: SyncedChapterContent[];
|
|
info: SyncedChapterInfo | null;
|
|
}
|
|
|
|
export interface SyncedChapterContent {
|
|
id: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedChapterInfo {
|
|
id: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedCharacter {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
attributes: SyncedCharacterAttribute[];
|
|
}
|
|
|
|
export interface SyncedCharacterAttribute {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedLocation {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
elements: SyncedLocationElement[];
|
|
}
|
|
|
|
export interface SyncedLocationElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
subElements: SyncedLocationSubElement[];
|
|
}
|
|
|
|
export interface SyncedLocationSubElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedWorld {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
elements: SyncedWorldElement[];
|
|
}
|
|
|
|
export interface SyncedWorldElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedIncident {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedPlotPoint {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedIssue {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedActSummary {
|
|
id: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedGuideLine {
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedAIGuideLine {
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface GuideLine{
|
|
tone:string;
|
|
atmosphere:string;
|
|
writingStyle:string;
|
|
themes:string;
|
|
symbolism: string;
|
|
motifs: string;
|
|
narrativeVoice: string;
|
|
pacing: string;
|
|
intendedAudience: string;
|
|
keyMessages: string;
|
|
}
|
|
|
|
interface PlotPoint {
|
|
plotPointId: string,
|
|
title:string,
|
|
summary:string,
|
|
linkedIncidentId: string | null,
|
|
chapters?:ActChapter[]
|
|
}
|
|
|
|
interface Incident {
|
|
incidentId: string,
|
|
title:string,
|
|
summary:string,
|
|
chapters?:ActChapter[]
|
|
}
|
|
|
|
export interface ExportData {
|
|
buffer: Buffer;
|
|
fileName: string;
|
|
}
|
|
|
|
export interface Act {
|
|
id: number;
|
|
summary: string | null;
|
|
incidents?:Incident[];
|
|
plotPoints?:PlotPoint[],
|
|
chapters?:ActChapter[]
|
|
}
|
|
|
|
export interface Issue {
|
|
id: string,
|
|
name: string
|
|
}
|
|
|
|
export interface WorldElement {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
type?:number;
|
|
}
|
|
|
|
export interface WorldProps {
|
|
id: string;
|
|
name: string;
|
|
history: string;
|
|
politics: string;
|
|
economy: string;
|
|
religion: string;
|
|
languages: string;
|
|
laws: WorldElement[];
|
|
biomes: WorldElement[];
|
|
issues: WorldElement[];
|
|
customs: WorldElement[];
|
|
kingdoms: WorldElement[];
|
|
climate: WorldElement[];
|
|
resources: WorldElement[];
|
|
wildlife: WorldElement[];
|
|
arts: WorldElement[];
|
|
ethnicGroups: WorldElement[];
|
|
socialClasses: WorldElement[];
|
|
importantCharacters: WorldElement[];
|
|
}
|
|
|
|
export interface GuideLineAI {
|
|
narrativeType: number|null;
|
|
dialogueType: number|null;
|
|
globalResume: string|null;
|
|
atmosphere: string|null;
|
|
verbeTense: number|null;
|
|
langue: number|null;
|
|
currentResume: string|null;
|
|
themes: string|null;
|
|
}
|
|
|
|
export interface CompleteBookData {
|
|
bookId: string;
|
|
title: string;
|
|
subTitle: string;
|
|
summary: string;
|
|
coverImage: string;
|
|
userInfos: {
|
|
firstName: string;
|
|
lastName: string;
|
|
authorName: string;
|
|
},
|
|
chapters: CompleteChapterContent[];
|
|
}
|
|
|
|
export interface CompleteChapterContent {
|
|
id: string;
|
|
title: string;
|
|
content: string;
|
|
order: number;
|
|
version?: number;
|
|
}
|
|
|
|
export default class Book {
|
|
private readonly id: string;
|
|
private type:string;
|
|
private authorId: string;
|
|
private title: string;
|
|
private subTitle: string;
|
|
private summary: string;
|
|
private serieId: number;
|
|
private desiredReleaseDate: string;
|
|
private desiredWordCount:number;
|
|
private wordCount: number;
|
|
private cover: string;
|
|
|
|
constructor(id:string,authorId?:string) {
|
|
this.id = id;
|
|
if (authorId){
|
|
this.authorId = authorId;
|
|
} else {
|
|
this.authorId = '';
|
|
}
|
|
this.title = '';
|
|
this.subTitle = '';
|
|
this.summary = '';
|
|
this.serieId = 0;
|
|
this.desiredReleaseDate = '';
|
|
this.desiredWordCount = 0;
|
|
this.wordCount = 0;
|
|
this.cover = '';
|
|
this.type = '';
|
|
}
|
|
public static async getBooks(userId: string, lang: 'fr' | 'en' = 'fr'): Promise<BookProps[]> {
|
|
const userKey: string | null = getUserEncryptionKey(userId);
|
|
if (!userKey) {
|
|
throw new Error(
|
|
lang === 'fr' ? "Clé d'encryption utilisateur non trouvée." : 'User encryption key not found.'
|
|
);
|
|
}
|
|
|
|
const books:BookQuery[] = BookRepository.fetchBooks(userId, lang);
|
|
if (!books || books.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
return await Promise.all(
|
|
books.map(async (book: BookQuery):Promise<BookProps> => {
|
|
return {
|
|
id: book.book_id,
|
|
type: book.type,
|
|
authorId: book.author_id,
|
|
title: System.decryptDataWithUserKey(book.title, userKey),
|
|
subTitle: book.sub_title ? System.decryptDataWithUserKey(book.sub_title, userKey) : '',
|
|
summary: book.summary ? System.decryptDataWithUserKey(book.summary, userKey) : '',
|
|
serieId: book.serie_id || 0,
|
|
desiredReleaseDate: book.desired_release_date || '',
|
|
desiredWordCount: book.desired_word_count || 0,
|
|
wordCount: book.words_count || 0,
|
|
coverImage: book.cover_image ? await this.getPicture(userId, userKey, book.cover_image) : '',
|
|
};
|
|
}) ?? []
|
|
);
|
|
}
|
|
|
|
public static async getCoverPicture(userId:string,bookId:string, lang: 'fr' | 'en' = 'fr'):Promise<string>{
|
|
const query:BookCoverQuery = BookRepo.fetchBookCover(userId,bookId,lang);
|
|
if (query){
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
return System.decryptDataWithUserKey(query.cover_image,userKey);
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
public static async deleteCoverPicture(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): Promise<boolean> {
|
|
const coverName:string = await Book.getCoverPicture(userId,bookId,lang);
|
|
return BookRepo.updateBookCover(bookId, '', userId, lang);
|
|
}
|
|
public static getPicture(userId: string, userKey: string, image: string, lang: 'fr' | 'en' = 'fr'): string {
|
|
if (!image) return '';
|
|
try {
|
|
const decryptedFileName: string = System.decryptDataWithUserKey(image, userKey);
|
|
const userDirectory: string = path.join('');
|
|
fs.accessSync(userDirectory, fs.constants.R_OK);
|
|
const data = fs.readFileSync(userDirectory);
|
|
return data.toString('base64');
|
|
} catch (err) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
public static async addBook(bookId: string | null, userId: string, title: string, subTitle: string, summary: string, type: string, serie: number, publicationDate: string, desiredWordCount: number, lang: 'fr' | 'en' = 'fr'): Promise<string> {
|
|
let id:string = '';
|
|
const userKey:string|null = getUserEncryptionKey(userId);
|
|
|
|
const encryptedTitle:string = System.encryptDataWithUserKey(title, userKey);
|
|
const encryptedSubTitle:string = subTitle ? System.encryptDataWithUserKey(subTitle, userKey) : '';
|
|
const encryptedSummary:string = summary ? System.encryptDataWithUserKey(summary, userKey) : '';
|
|
const hashedTitle:string = System.hashElement(title);
|
|
const hashedSubTitle:string = subTitle ? System.hashElement(subTitle) : '';
|
|
|
|
if (BookRepo.verifyBookExist(hashedTitle,hashedSubTitle,userId,lang)){
|
|
throw new Error(lang === "fr" ? `Tu as déjà un livre intitulé ${title} - ${subTitle}.` : `You already have a book named ${title} - ${subTitle}.`);
|
|
}
|
|
if (bookId){
|
|
id = bookId;
|
|
} else {
|
|
id = System.createUniqueId();
|
|
}
|
|
return BookRepo.insertBook(id,userId,encryptedTitle,hashedTitle,encryptedSubTitle,hashedSubTitle,encryptedSummary,type,serie,publicationDate,desiredWordCount,lang);
|
|
}
|
|
|
|
public static async getBook(userId:string,bookId: string, lang: 'fr' | 'en'): Promise<BookProps> {
|
|
const book:Book = new Book(bookId);
|
|
await book.getBookInfos(userId);
|
|
return {
|
|
id: book.getId(),
|
|
type: book.getType(),
|
|
authorId: book.getAuthorId(),
|
|
title: book.getTitle(),
|
|
subTitle: book.getSubTitle(),
|
|
summary: book.getSummary(),
|
|
serieId: book.getSerieId(),
|
|
desiredReleaseDate: book.getDesiredReleaseDate(),
|
|
desiredWordCount: book.getDesiredWordCount(),
|
|
wordCount: book.getWordCount(),
|
|
coverImage: book.getCover()
|
|
};
|
|
}
|
|
|
|
public static async getGuideLine(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): Promise<GuideLine | null> {
|
|
const guideLineResponse: GuideLineQuery[] = BookRepo.fetchGuideLine(userId, bookId,lang);
|
|
if (guideLineResponse.length === 0) {
|
|
return null;
|
|
}
|
|
const guideLine: GuideLineQuery = guideLineResponse[0];
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
return {
|
|
tone: guideLine.tone ? System.decryptDataWithUserKey(guideLine.tone, userKey) : '',
|
|
atmosphere: guideLine.atmosphere ? System.decryptDataWithUserKey(guideLine.atmosphere, userKey) : '',
|
|
writingStyle: guideLine.writing_style ? System.decryptDataWithUserKey(guideLine.writing_style, userKey) : '',
|
|
themes: guideLine.themes ? System.decryptDataWithUserKey(guideLine.themes, userKey) : '',
|
|
symbolism: guideLine.symbolism ? System.decryptDataWithUserKey(guideLine.symbolism, userKey) : '',
|
|
motifs: guideLine.motifs ? System.decryptDataWithUserKey(guideLine.motifs, userKey) : '',
|
|
narrativeVoice: guideLine['narrative-voice'] ? System.decryptDataWithUserKey(guideLine['narrative-voice'] as string, userKey) : '',
|
|
pacing: guideLine.pacing ? System.decryptDataWithUserKey(guideLine.pacing, userKey) : '',
|
|
intendedAudience: guideLine.intended_audience ? System.decryptDataWithUserKey(guideLine.intended_audience, userKey) : '',
|
|
keyMessages: guideLine.key_messages ? System.decryptDataWithUserKey(guideLine.key_messages, userKey) : '',
|
|
};
|
|
}
|
|
|
|
public static async updateGuideLine(userId: string, bookId: string, tone: string | null, atmosphere: string | null, writingStyle: string | null, themes: string | null, symbolism: string | null, motifs: string | null, narrativeVoice: string | null, pacing: string | null, keyMessages: string | null, intendedAudience: string | null, lang: 'fr' | 'en' = 'fr'): Promise<boolean> {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const encryptedTone: string = tone ? System.encryptDataWithUserKey(tone, userKey) : '';
|
|
const encryptedAtmosphere: string = atmosphere ? System.encryptDataWithUserKey(atmosphere, userKey) : '';
|
|
const encryptedWritingStyle: string = writingStyle ? System.encryptDataWithUserKey(writingStyle, userKey) : '';
|
|
const encryptedThemes: string = themes ? System.encryptDataWithUserKey(themes, userKey) : '';
|
|
const encryptedSymbolism: string = symbolism ? System.encryptDataWithUserKey(symbolism, userKey) : '';
|
|
const encryptedMotifs: string = motifs ? System.encryptDataWithUserKey(motifs, userKey) : '';
|
|
const encryptedNarrativeVoice: string = narrativeVoice ? System.encryptDataWithUserKey(narrativeVoice, userKey) : '';
|
|
const encryptedPacing: string = pacing ? System.encryptDataWithUserKey(pacing, userKey) : '';
|
|
const encryptedKeyMessages: string = keyMessages ? System.encryptDataWithUserKey(keyMessages, userKey) : '';
|
|
const encryptedIntendedAudience: string = intendedAudience ? System.encryptDataWithUserKey(intendedAudience, userKey) : '';
|
|
|
|
return BookRepo.updateGuideLine(userId, bookId, encryptedTone, encryptedAtmosphere, encryptedWritingStyle, encryptedThemes, encryptedSymbolism, encryptedMotifs, encryptedNarrativeVoice, encryptedPacing, encryptedKeyMessages, encryptedIntendedAudience, lang);
|
|
}
|
|
|
|
public static addNewIncident(userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr', existingIncidentId?: string): string {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const encryptedName:string = System.encryptDataWithUserKey(name,userKey);
|
|
const hashedName:string = System.hashElement(name);
|
|
const incidentId: string = existingIncidentId || System.createUniqueId();
|
|
return BookRepo.insertNewIncident(incidentId, userId, bookId, encryptedName, hashedName, lang);
|
|
}
|
|
public static async getPlotPoints(userId:string, bookId: string,actChapters:ActChapter[], lang: 'fr' | 'en' = 'fr'):Promise<PlotPoint[]>{
|
|
const query:PlotPointQuery[] = BookRepo.fetchAllPlotPoints(userId,bookId,lang);
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
let plotPoints:PlotPoint[] = [];
|
|
if (query.length>0){
|
|
for (const plot of query) {
|
|
let chapters:ActChapter[] = [];
|
|
for (const chapter of actChapters) {
|
|
if (chapter.plotPointId === plot.plot_point_id){
|
|
chapters.push(chapter);
|
|
}
|
|
}
|
|
plotPoints.push({
|
|
plotPointId: plot.plot_point_id,
|
|
title: plot.title ? System.decryptDataWithUserKey(plot.title,userKey) : '',
|
|
summary : plot.summary ? System.decryptDataWithUserKey(plot.summary,userKey) : '',
|
|
linkedIncidentId: plot.linked_incident_id,
|
|
chapters:chapters
|
|
})
|
|
}
|
|
}
|
|
return plotPoints;
|
|
}
|
|
public static async getIncitentsIncidents(userId:string,bookId: string,actChapters:ActChapter[], lang: 'fr' | 'en' = 'fr'):Promise<Incident[]>{
|
|
const query:IncidentQuery[] = BookRepo.fetchAllIncitentIncidents(userId,bookId,lang);
|
|
let incidents:Incident[] = [];
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
if (query.length>0){
|
|
for (const incident of query) {
|
|
let chapters:ActChapter[] = [];
|
|
for (const chapter of actChapters) {
|
|
if (chapter.incidentId === incident.incident_id){
|
|
chapters.push(chapter);
|
|
}
|
|
}
|
|
incidents.push({
|
|
incidentId: incident.incident_id,
|
|
title: incident.title ? System.decryptDataWithUserKey(incident.title,userKey) : '',
|
|
summary : incident.summary ? System.decryptDataWithUserKey(incident.summary,userKey) : '',
|
|
chapters:chapters
|
|
})
|
|
}
|
|
}
|
|
return incidents;
|
|
}
|
|
|
|
public static removeIncident(userId: string, bookId: string, incidentId: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
return BookRepo.deleteIncident(userId, bookId, incidentId, lang);
|
|
}
|
|
|
|
public static async getActsData(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): Promise<Act[]> {
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
const actChapters:ActChapter[] = Chapter.getAllChapterFromActs(userId, bookId, lang);
|
|
const query: ActQuery[] = BookRepo.fetchAllActs(userId, bookId, lang);
|
|
const incidents: Incident[] = await Book.getIncitentsIncidents(userId, bookId, actChapters);
|
|
const plotsPoint: PlotPoint[] = await Book.getPlotPoints(userId, bookId, actChapters);
|
|
let acts: Act[] = [];
|
|
acts.push({
|
|
id: 1,
|
|
summary: '',
|
|
chapters: actChapters.filter((chapter: ActChapter) => chapter.actId === 1)
|
|
})
|
|
acts.push({
|
|
id: 2,
|
|
summary: '',
|
|
incidents: incidents ? incidents : [],
|
|
})
|
|
acts.push({
|
|
id: 3,
|
|
summary: '',
|
|
plotPoints: plotsPoint ? plotsPoint : [],
|
|
})
|
|
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 (query.length > 0) {
|
|
for (const act of query) {
|
|
acts[act.act_index - 1].summary = act.summary && userKey ? System.decryptDataWithUserKey(act.summary, userKey) : '';
|
|
}
|
|
}
|
|
return acts;
|
|
}
|
|
public static async getIssuesFromBook(userId:string,bookId:string, lang: 'fr' | 'en' = 'fr'):Promise<Issue[]>{
|
|
const query:IssueQuery[] = BookRepo.fetchIssuesFromBook(userId,bookId,lang);
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
let issues:Issue[] = [];
|
|
if (query.length>0){
|
|
for (const issue of query) {
|
|
issues.push({
|
|
id:issue.issue_id,
|
|
name: System.decryptDataWithUserKey(issue.name,userKey)
|
|
})
|
|
}
|
|
}
|
|
return issues;
|
|
}
|
|
|
|
static updateBookBasicInformation(userId: string, title: string, subTitle: string, summary: string, publicationDate: string, wordCount: number, bookId: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
const encryptedTitle:string = System.encryptDataWithUserKey(title, userKey);
|
|
const encryptedSubTitle:string = subTitle ? System.encryptDataWithUserKey(subTitle, userKey) : '';
|
|
const encryptedSummary:string = summary ? System.encryptDataWithUserKey(summary, userKey) : '';
|
|
const hashedTitle:string = System.hashElement(title);
|
|
const hashedSubTitle:string = subTitle ? System.hashElement(subTitle) : '';
|
|
return BookRepo.updateBookBasicInformation(userId, encryptedTitle, hashedTitle, encryptedSubTitle, hashedSubTitle, encryptedSummary, publicationDate, wordCount, bookId, lang);
|
|
}
|
|
|
|
static addNewPlotPoint(userId: string, bookId: string, incidentId: string, name: string, lang: 'fr' | 'en' = 'fr', existingPlotPointId?: string): string {
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
const encryptedName:string = System.encryptDataWithUserKey(name, userKey);
|
|
const hashedName:string = System.hashElement(name);
|
|
const plotPointId: string = existingPlotPointId || System.createUniqueId();
|
|
return BookRepo.insertNewPlotPoint(plotPointId, userId, bookId, encryptedName, hashedName, incidentId, lang);
|
|
}
|
|
|
|
static removePlotPoint(userId: string, plotId: string, lang: 'fr' | 'en' = 'fr'): boolean{
|
|
return BookRepo.deletePlotPoint(userId, plotId, lang);
|
|
}
|
|
|
|
public static addNewIssue(userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr', existingIssueId?: string): string {
|
|
const userKey:string = getUserEncryptionKey(userId);
|
|
const encryptedName:string = System.encryptDataWithUserKey(name,userKey);
|
|
const hashedName:string = System.hashElement(name);
|
|
const issueId: string = existingIssueId || System.createUniqueId();
|
|
return BookRepo.insertNewIssue(issueId, userId, bookId, encryptedName, hashedName,lang);
|
|
}
|
|
|
|
public static removeIssue(userId: string, issueId: string, lang: 'fr' | 'en' = 'fr'): boolean{
|
|
return BookRepo.deleteIssue(userId, issueId,lang);
|
|
}
|
|
|
|
public static async updateAct(acts: Act[], userId: string, bookId: string, userKey: string, lang: 'fr' | 'en' = 'fr'): Promise<boolean> {
|
|
for (const act of acts) {
|
|
const incidents: Incident[] = act.incidents ? act.incidents : [];
|
|
const actId: number = act.id;
|
|
if (actId === 1 || actId === 4 || actId === 5) {
|
|
const actSummary: string = act.summary ? System.encryptDataWithUserKey(act.summary, userKey) : '';
|
|
try {
|
|
BookRepo.updateActSummary(userId, bookId, actId, actSummary,System.timeStampInSeconds(),lang);
|
|
} catch (e: unknown) {
|
|
const actSummaryId: string = System.createUniqueId();
|
|
BookRepo.insertActSummary(actSummaryId, userId, bookId, actId, actSummary,lang);
|
|
}
|
|
if (act.chapters) {
|
|
Chapter.updateChapterInfos(act.chapters, userId, actId, bookId, null, null, lang);
|
|
}
|
|
} else if (actId === 2) {
|
|
for (const incident of incidents) {
|
|
const incidentSummary: string = incident.summary ? System.encryptDataWithUserKey(incident.summary, userKey) : '';
|
|
const incidentId: string = incident.incidentId;
|
|
const incidentName: string = incident.title;
|
|
const incidentHashedName: string = System.hashElement(incidentName);
|
|
const encryptedIncidentName: string = System.encryptDataWithUserKey(incidentName, userKey);
|
|
BookRepo.updateIncident(userId, bookId, incidentId, encryptedIncidentName, incidentHashedName, incidentSummary, System.timeStampInSeconds(), lang);
|
|
if (incident.chapters) {
|
|
Chapter.updateChapterInfos(incident.chapters, userId, actId, bookId, incidentId, null, lang);
|
|
}
|
|
}
|
|
} else {
|
|
const plotPoints: PlotPoint[] = act.plotPoints ? act.plotPoints : [];
|
|
for (const plotPoint of plotPoints) {
|
|
const plotPointSummary: string = plotPoint.summary ? System.encryptDataWithUserKey(plotPoint.summary, userKey) : '';
|
|
const plotPointId: string = plotPoint.plotPointId;
|
|
const plotPointName: string = plotPoint.title;
|
|
const plotPointHashedName: string = System.hashElement(plotPointName);
|
|
const encryptedPlotPointName: string = System.encryptDataWithUserKey(plotPointName, userKey);
|
|
BookRepo.updatePlotPoint(userId, bookId, plotPointId, encryptedPlotPointName, plotPointHashedName, plotPointSummary, System.timeStampInSeconds(), lang);
|
|
if (plotPoint.chapters) {
|
|
Chapter.updateChapterInfos(plotPoint.chapters, userId, actId, bookId, null, plotPointId, lang);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static updateStory(userId: string, bookId: string, acts: Act[], mainChapters: ChapterProps[], lang: 'fr' | 'en' = 'fr'): boolean {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
Book.updateAct(acts, userId, bookId, userKey, lang);
|
|
for (const chapter of mainChapters) {
|
|
const chapterId: string = chapter.chapterId;
|
|
const chapterTitle: string = chapter.title;
|
|
const chapterHashedTitle: string = System.hashElement(chapterTitle);
|
|
const encryptedTitle: string = System.encryptDataWithUserKey(chapterTitle, userKey);
|
|
const chapterOrder: number = chapter.chapterOrder;
|
|
ChapterRepo.updateChapter(userId, chapterId, encryptedTitle, chapterHashedTitle, chapterOrder, System.timeStampInSeconds(), lang);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static addNewWorld(userId: string, bookId: string, worldName: string, lang: 'fr' | 'en' = 'fr', existingWorldId?: string): string {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const hashedName: string = System.hashElement(worldName);
|
|
if (!existingWorldId && BookRepo.checkWorldExist(userId, bookId, hashedName, lang)) {
|
|
throw new Error(lang === "fr" ? `Tu as déjà un monde ${worldName}.` : `You already have a world named ${worldName}.`);
|
|
}
|
|
const encryptedName: string = System.encryptDataWithUserKey(worldName, userKey);
|
|
const worldId: string = existingWorldId || System.createUniqueId();
|
|
return BookRepo.insertNewWorld(worldId, userId, bookId, encryptedName, hashedName, lang);
|
|
}
|
|
|
|
public static getWorlds(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): WorldProps[] {
|
|
const worldElements: WorldQuery[] = BookRepo.fetchWorlds(userId, bookId, lang);
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
let worlds: WorldProps[] = []
|
|
for (const element of worldElements) {
|
|
const existWorld: WorldProps | undefined = worlds.find((world: WorldProps) => world.id === element.world_id);
|
|
|
|
if (!existWorld) {
|
|
const newWorld: WorldProps = {
|
|
id: element.world_id,
|
|
name: System.decryptDataWithUserKey(element.world_name, userKey),
|
|
history: element.history ? System.decryptDataWithUserKey(element.history, userKey) : '',
|
|
politics: element.politics ? System.decryptDataWithUserKey(element.politics, userKey) : '',
|
|
economy: element.economy ? System.decryptDataWithUserKey(element.economy, userKey) : '',
|
|
religion: element.religion ? System.decryptDataWithUserKey(element.religion, userKey) : '',
|
|
languages: element.languages ? System.decryptDataWithUserKey(element.languages, userKey) : '',
|
|
laws: [],
|
|
biomes: [],
|
|
issues: [],
|
|
customs: [],
|
|
kingdoms: [],
|
|
climate: [],
|
|
resources: [],
|
|
wildlife: [],
|
|
arts: [],
|
|
ethnicGroups: [],
|
|
socialClasses: [],
|
|
importantCharacters: [],
|
|
};
|
|
|
|
worlds.push(newWorld);
|
|
|
|
if (element.element_type) {
|
|
const newElement = {
|
|
id: element.element_id as string,
|
|
name: element.element_name ? System.decryptDataWithUserKey(element.element_name, userKey) : '',
|
|
description: element.element_description ? System.decryptDataWithUserKey(element.element_description, userKey) : ''
|
|
};
|
|
|
|
switch (element.element_type) {
|
|
case 1:
|
|
worlds[worlds.length - 1].laws.push(newElement);
|
|
break;
|
|
case 2:
|
|
worlds[worlds.length - 1].biomes.push(newElement);
|
|
break;
|
|
case 3:
|
|
worlds[worlds.length - 1].issues.push(newElement);
|
|
break;
|
|
case 4:
|
|
worlds[worlds.length - 1].customs.push(newElement);
|
|
break;
|
|
case 5:
|
|
worlds[worlds.length - 1].kingdoms.push(newElement);
|
|
break;
|
|
case 6:
|
|
worlds[worlds.length - 1].climate.push(newElement);
|
|
break;
|
|
case 7:
|
|
worlds[worlds.length - 1].resources.push(newElement);
|
|
break;
|
|
case 8:
|
|
worlds[worlds.length - 1].wildlife.push(newElement);
|
|
break;
|
|
case 9:
|
|
worlds[worlds.length - 1].arts.push(newElement);
|
|
break;
|
|
case 10:
|
|
worlds[worlds.length - 1].ethnicGroups.push(newElement);
|
|
break;
|
|
case 11:
|
|
worlds[worlds.length - 1].socialClasses.push(newElement);
|
|
break;
|
|
case 12:
|
|
worlds[worlds.length - 1].importantCharacters.push(newElement);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
const existingElement = {
|
|
id: element.element_id as string,
|
|
name: element.element_name ? System.decryptDataWithUserKey(element.element_name, userKey) : '',
|
|
description: element.element_description ? System.decryptDataWithUserKey(element.element_description, userKey) : ''
|
|
};
|
|
|
|
switch (element.element_type) {
|
|
case 1:
|
|
existWorld.laws.push(existingElement);
|
|
break;
|
|
case 2:
|
|
existWorld.biomes.push(existingElement);
|
|
break;
|
|
case 3:
|
|
existWorld.issues.push(existingElement);
|
|
break;
|
|
case 4:
|
|
existWorld.customs.push(existingElement);
|
|
break;
|
|
case 5:
|
|
existWorld.kingdoms.push(existingElement);
|
|
break;
|
|
case 6:
|
|
existWorld.climate.push(existingElement);
|
|
break;
|
|
case 7:
|
|
existWorld.resources.push(existingElement);
|
|
break;
|
|
case 8:
|
|
existWorld.wildlife.push(existingElement);
|
|
break;
|
|
case 9:
|
|
existWorld.arts.push(existingElement);
|
|
break;
|
|
case 10:
|
|
existWorld.ethnicGroups.push(existingElement);
|
|
break;
|
|
case 11:
|
|
existWorld.socialClasses.push(existingElement);
|
|
break;
|
|
case 12:
|
|
existWorld.importantCharacters.push(existingElement);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return worlds;
|
|
}
|
|
|
|
public static updateWorld(userId: string, world: WorldProps, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const encryptName: string = world.name ? System.encryptDataWithUserKey(world.name, userKey) : '';
|
|
const encryptHistory: string = world.history ? System.encryptDataWithUserKey(world.history, userKey) : '';
|
|
const encryptPolitics: string = world.politics ? System.encryptDataWithUserKey(world.politics, userKey) : '';
|
|
const encryptEconomy: string = world.economy ? System.encryptDataWithUserKey(world.economy, userKey) : '';
|
|
const encryptReligion: string = world.religion ? System.encryptDataWithUserKey(world.religion, userKey) : '';
|
|
const encryptLanguages: string = world.languages ? System.encryptDataWithUserKey(world.languages, userKey) : '';
|
|
let elements: WorldElementValue[] = [];
|
|
const elementTypes: { key: keyof WorldProps, elements: WorldElement[] }[] = [
|
|
{key: 'laws', elements: world.laws},
|
|
{key: 'biomes', elements: world.biomes},
|
|
{key: 'issues', elements: world.issues},
|
|
{key: 'customs', elements: world.customs},
|
|
{key: 'kingdoms', elements: world.kingdoms},
|
|
{key: 'climate', elements: world.climate},
|
|
{key: 'resources', elements: world.resources},
|
|
{key: 'wildlife', elements: world.wildlife},
|
|
{key: 'arts', elements: world.arts},
|
|
{key: 'ethnicGroups', elements: world.ethnicGroups},
|
|
{key: 'socialClasses', elements: world.socialClasses},
|
|
{key: 'importantCharacters', elements: world.importantCharacters}
|
|
];
|
|
|
|
elementTypes.forEach(({key, elements: elementsList}) => {
|
|
elements = elements.concat(elementsList.map((element: WorldElement) => {
|
|
const encryptedName: string = System.encryptDataWithUserKey(element.name, userKey);
|
|
const hashedName: string = System.hashElement(element.name);
|
|
const encryptedDescription: string = element.description ? System.encryptDataWithUserKey(element.description, userKey) : '';
|
|
const elementType: number = Book.getElementTypes(key);
|
|
|
|
return {
|
|
id: element.id,
|
|
name: encryptedName,
|
|
hashedName: hashedName,
|
|
description: encryptedDescription,
|
|
type: elementType
|
|
};
|
|
}));
|
|
});
|
|
|
|
BookRepo.updateWorld(userId, world.id, encryptName, System.hashElement(world.name), encryptHistory, encryptPolitics, encryptEconomy, encryptReligion, encryptLanguages, System.timeStampInSeconds(), lang);
|
|
return BookRepo.updateWorldElements(userId, elements, lang);
|
|
}
|
|
|
|
public static addNewElementToWorld(userId: string, worldId: string, elementName: string, elementType: string, lang: 'fr' | 'en' = 'fr', existingElementId?: string): string {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const hashedName: string = System.hashElement(elementName);
|
|
if (!existingElementId && BookRepo.checkElementExist(worldId, hashedName, lang)) {
|
|
throw new Error(lang === "fr" ? `Vous avez déjà un élément avec ce nom ${elementName}.` : `You already have an element named ${elementName}.`);
|
|
}
|
|
const elementTypeId: number = Book.getElementTypes(elementType);
|
|
const encryptedName: string = System.encryptDataWithUserKey(elementName, userKey);
|
|
const elementId: string = existingElementId || System.createUniqueId();
|
|
return BookRepo.insertNewElement(userId, elementId, elementTypeId, worldId, encryptedName, hashedName, lang);
|
|
}
|
|
public static getElementTypes(elementType:string):number{
|
|
switch (elementType){
|
|
case 'laws':
|
|
return 1;
|
|
case 'biomes':
|
|
return 2;
|
|
case 'issues':
|
|
return 3;
|
|
case 'customs':
|
|
return 4;
|
|
case 'kingdoms':
|
|
return 5;
|
|
case 'climate':
|
|
return 6;
|
|
case 'resources':
|
|
return 7;
|
|
case 'wildlife':
|
|
return 8;
|
|
case 'arts':
|
|
return 9;
|
|
case 'ethnicGroups':
|
|
return 10;
|
|
case 'socialClasses':
|
|
return 11;
|
|
case 'importantCharacters':
|
|
return 12;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public static removeElementFromWorld(userId: string, elementId: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
return BookRepo.deleteElement(userId, elementId, lang);
|
|
}
|
|
|
|
public static removeBook(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
return BookRepo.deleteBook(userId, bookId, lang);
|
|
}
|
|
|
|
static getGuideLineAI(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): GuideLineAI {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
try {
|
|
const guideLine: GuideLineAIQuery = BookRepo.fetchGuideLineAI(userId, bookId, lang);
|
|
return {
|
|
narrativeType: guideLine.narrative_type,
|
|
dialogueType: guideLine.dialogue_type,
|
|
globalResume: guideLine.global_resume ? System.decryptDataWithUserKey(guideLine.global_resume, userKey) : '',
|
|
atmosphere: guideLine.atmosphere ? System.decryptDataWithUserKey(guideLine.atmosphere, userKey) : '',
|
|
verbeTense: guideLine.verbe_tense,
|
|
themes: guideLine.themes ? System.decryptDataWithUserKey(guideLine.themes, userKey) : '',
|
|
currentResume: guideLine.current_resume ? System.decryptDataWithUserKey(guideLine.current_resume, userKey) : '',
|
|
langue: guideLine.langue
|
|
}
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error && e.message.includes('not found')) {
|
|
return {
|
|
narrativeType: 0,
|
|
dialogueType: 0,
|
|
globalResume: '',
|
|
atmosphere: '',
|
|
verbeTense: 0,
|
|
themes: '',
|
|
currentResume: '',
|
|
langue: 0
|
|
}
|
|
}
|
|
if (e instanceof Error) {
|
|
throw new Error(e.message);
|
|
} else {
|
|
console.error(lang === 'fr' ? "Erreur inconnue lors de la récupération de la ligne directrice de l'IA." : "Unknown error while fetching AI guideline.");
|
|
throw new Error(lang === 'fr' ? "Erreur inconnue lors de la récupération de la ligne directrice de l'IA." : "Unknown error while fetching AI guideline.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static setAIGuideLine(userId: string, bookId: string, narrativeType: number, dialogueType: number, plotSummary: string, toneAtmosphere: string, verbTense: number, language: number, themes: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const encryptedPlotSummary: string = plotSummary ? System.encryptDataWithUserKey(plotSummary, userKey) : '';
|
|
const encryptedToneAtmosphere: string = toneAtmosphere ? System.encryptDataWithUserKey(toneAtmosphere, userKey) : '';
|
|
const encryptedThemes: string = themes ? System.encryptDataWithUserKey(themes, userKey) : '';
|
|
return BookRepo.insertAIGuideLine(userId, bookId, narrativeType, dialogueType, encryptedPlotSummary, encryptedToneAtmosphere, verbTense, language, encryptedThemes, lang);
|
|
}
|
|
|
|
public getId(): string {
|
|
return this.id;
|
|
}
|
|
|
|
public getAuthorId(): string {
|
|
return this.authorId;
|
|
}
|
|
|
|
public getTitle(): string {
|
|
return this.title;
|
|
}
|
|
|
|
public getSubTitle(): string {
|
|
return this.subTitle;
|
|
}
|
|
|
|
public getSummary(): string {
|
|
return this.summary;
|
|
}
|
|
|
|
public getSerieId(): number {
|
|
return this.serieId;
|
|
}
|
|
|
|
public getDesiredReleaseDate(): string {
|
|
return this.desiredReleaseDate;
|
|
}
|
|
|
|
public getDesiredWordCount(): number {
|
|
return this.desiredWordCount;
|
|
}
|
|
|
|
public getWordCount(): number {
|
|
return this.wordCount;
|
|
}
|
|
|
|
public getCover(): string {
|
|
return this.cover;
|
|
}
|
|
|
|
public getType(): string {
|
|
return this.type;
|
|
}
|
|
|
|
static completeBookData(userId: string, id: string, lang: 'fr' | 'en' = 'fr'): CompleteBookData {
|
|
const data = BookRepo.fetchBook(id, userId, lang);
|
|
const chapters: ChapterBookResult[] = BookRepo.fetchCompleteBookChapters(id, lang);
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const userInfos = UserRepo.fetchAccountInformation(userId, lang);
|
|
|
|
const bookTitle: string = data.title ? System.decryptDataWithUserKey(data.title, userKey) : '';
|
|
const decryptedChapters: any[] = [];
|
|
|
|
for (const chapter of chapters) {
|
|
decryptedChapters.push({
|
|
id: '',
|
|
title: chapter.title ? System.decryptDataWithUserKey(chapter.title, userKey) : '',
|
|
content: chapter.content ? System.decryptDataWithUserKey(chapter.content, userKey) : '',
|
|
order: chapter.chapter_order
|
|
})
|
|
}
|
|
const coverImage: string = data.cover_image ? Book.getPicture(userId, userKey, data.cover_image, lang) : '';
|
|
return {
|
|
bookId: id,
|
|
title: bookTitle,
|
|
subTitle: data.sub_title ? System.decryptDataWithUserKey(data.sub_title, userKey) : '',
|
|
summary: data.summary ? System.decryptDataWithUserKey(data.summary, userKey) : '',
|
|
coverImage: coverImage,
|
|
userInfos: {
|
|
firstName: userInfos.first_name ? System.decryptDataWithUserKey(userInfos.first_name, userKey) : '',
|
|
lastName: userInfos.last_name ? System.decryptDataWithUserKey(userInfos.last_name, userKey) : '',
|
|
authorName: userInfos.author_name ? System.decryptDataWithUserKey(userInfos.author_name, userKey) : '',
|
|
},
|
|
chapters: decryptedChapters
|
|
};
|
|
}
|
|
|
|
static getChaptersOrSheet(bookChapters: CompleteChapterContent[]): ChapterContentData[] {
|
|
const chapters: ChapterContentData[] = [];
|
|
const haveSheet: CompleteChapterContent | undefined = bookChapters.find((chapter: CompleteChapterContent): boolean => chapter.order === -1);
|
|
const haveChapter: CompleteChapterContent | undefined = bookChapters.find((chapter: CompleteChapterContent): boolean => chapter.order > 0);
|
|
if (haveSheet && !haveChapter) {
|
|
chapters.push({
|
|
title: haveSheet.title,
|
|
chapterOrder: haveSheet.order,
|
|
content: System.htmlToText(Chapter.tipTapToHtml(JSON.parse(haveSheet.content))),
|
|
wordsCount: 0,
|
|
version: haveSheet.version || 0
|
|
});
|
|
} else if (haveChapter) {
|
|
for (const chapter of bookChapters) {
|
|
if (chapter.order < 0) continue;
|
|
chapters.push({
|
|
title: chapter.title,
|
|
chapterOrder: chapter.order,
|
|
content: System.htmlToText(Chapter.tipTapToHtml(JSON.parse(chapter.content))),
|
|
wordsCount: 0,
|
|
version: chapter.version || 0
|
|
});
|
|
}
|
|
}
|
|
return chapters;
|
|
}
|
|
|
|
static getAllChapters(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): ChapterContentData[] {
|
|
try {
|
|
const book: CompleteBookData = Book.completeBookData(userId, bookId, lang);
|
|
return Book.getChaptersOrSheet(book.chapters);
|
|
} catch (e: unknown) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public getBookInfos(userId: string, lang: 'fr' | 'en' = 'fr'): void {
|
|
const book: BookQuery = BookRepo.fetchBook(this.id, userId, lang);
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
if (book) {
|
|
this.authorId = book.author_id;
|
|
this.type = book.type;
|
|
this.title = book.title ? System.decryptDataWithUserKey(book.title, userKey) : '';
|
|
this.subTitle = book.sub_title ? System.decryptDataWithUserKey(book.sub_title, userKey) : '';
|
|
this.summary = book.summary ? System.decryptDataWithUserKey(book.summary, userKey) : '';
|
|
this.serieId = book.serie_id ?? 0;
|
|
this.desiredReleaseDate = book.desired_release_date ?? '';
|
|
this.desiredWordCount = book.desired_word_count ?? 0;
|
|
this.wordCount = book.words_count ?? 0;
|
|
this.cover = book.cover_image ? Book.getPicture(userId, userKey, book.cover_image, lang) : '';
|
|
} else {
|
|
this.authorId = '';
|
|
this.title = '';
|
|
this.subTitle = '';
|
|
this.summary = '';
|
|
this.serieId = 0;
|
|
this.desiredReleaseDate = '';
|
|
this.wordCount = 0;
|
|
this.cover = '';
|
|
}
|
|
}
|
|
|
|
static async getSyncedBooks(userId: string, lang: 'fr' | 'en'):Promise<SyncedBook[]> {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
|
|
const [
|
|
allBooks,
|
|
allChapters,
|
|
allChapterContents,
|
|
allChapterInfos,
|
|
allCharacters,
|
|
allCharacterAttributes,
|
|
allLocations,
|
|
allLocationElements,
|
|
allLocationSubElements,
|
|
allWorlds,
|
|
allWorldElements,
|
|
allIncidents,
|
|
allPlotPoints,
|
|
allIssues,
|
|
allActSummaries,
|
|
allGuidelines,
|
|
allAIGuidelines
|
|
]: [
|
|
SyncedBookResult[],
|
|
SyncedChapterResult[],
|
|
SyncedChapterContentResult[],
|
|
SyncedChapterInfoResult[],
|
|
SyncedCharacterResult[],
|
|
SyncedCharacterAttributeResult[],
|
|
SyncedLocationResult[],
|
|
SyncedLocationElementResult[],
|
|
SyncedLocationSubElementResult[],
|
|
SyncedWorldResult[],
|
|
SyncedWorldElementResult[],
|
|
SyncedIncidentResult[],
|
|
SyncedPlotPointResult[],
|
|
SyncedIssueResult[],
|
|
SyncedActSummaryResult[],
|
|
SyncedGuideLineResult[],
|
|
SyncedAIGuideLineResult[]
|
|
] = await Promise.all([
|
|
BookRepo.fetchSyncedBooks(userId,lang),
|
|
BookRepo.fetchSyncedChapters(userId,lang),
|
|
BookRepo.fetchSyncedChapterContents(userId,lang),
|
|
BookRepo.fetchSyncedChapterInfos(userId,lang),
|
|
BookRepo.fetchSyncedCharacters(userId,lang),
|
|
BookRepo.fetchSyncedCharacterAttributes(userId,lang),
|
|
BookRepo.fetchSyncedLocations(userId,lang),
|
|
BookRepo.fetchSyncedLocationElements(userId,lang),
|
|
BookRepo.fetchSyncedLocationSubElements(userId,lang),
|
|
BookRepo.fetchSyncedWorlds(userId,lang),
|
|
BookRepo.fetchSyncedWorldElements(userId,lang),
|
|
BookRepo.fetchSyncedIncidents(userId,lang),
|
|
BookRepo.fetchSyncedPlotPoints(userId,lang),
|
|
BookRepo.fetchSyncedIssues(userId,lang),
|
|
BookRepo.fetchSyncedActSummaries(userId,lang),
|
|
BookRepo.fetchSyncedGuideLine(userId,lang),
|
|
BookRepo.fetchSyncedAIGuideLine(userId,lang)
|
|
]);
|
|
|
|
return allBooks.map((book: SyncedBookResult): SyncedBook => {
|
|
const bookId: string = book.book_id;
|
|
|
|
const chapters: SyncedChapter[] = allChapters
|
|
.filter((chapter: SyncedChapterResult): boolean => chapter.book_id === bookId)
|
|
.map((chapter: SyncedChapterResult): SyncedChapter => {
|
|
const chapterId: string = chapter.chapter_id;
|
|
|
|
const contents: SyncedChapterContent[] = allChapterContents
|
|
.filter((content: SyncedChapterContentResult): boolean => content.chapter_id === chapterId)
|
|
.map((content: SyncedChapterContentResult): SyncedChapterContent => ({
|
|
id: content.content_id,
|
|
lastUpdate: content.last_update
|
|
}));
|
|
|
|
const infoData: SyncedChapterInfoResult | undefined = allChapterInfos.find((info: SyncedChapterInfoResult): boolean => info.chapter_id === chapterId);
|
|
const info: SyncedChapterInfo | null = infoData ? {
|
|
id: infoData.chapter_info_id,
|
|
lastUpdate: infoData.last_update
|
|
} : null;
|
|
|
|
return {
|
|
id: chapterId,
|
|
name: System.decryptDataWithUserKey(chapter.title, userKey),
|
|
lastUpdate: chapter.last_update,
|
|
contents,
|
|
info
|
|
};
|
|
});
|
|
|
|
const characters: SyncedCharacter[] = allCharacters
|
|
.filter((character: SyncedCharacterResult): boolean => character.book_id === bookId)
|
|
.map((character: SyncedCharacterResult): SyncedCharacter => {
|
|
const characterId: string = character.character_id;
|
|
|
|
const attributes: SyncedCharacterAttribute[] = allCharacterAttributes
|
|
.filter((attribute: SyncedCharacterAttributeResult): boolean => attribute.character_id === characterId)
|
|
.map((attribute: SyncedCharacterAttributeResult): SyncedCharacterAttribute => ({
|
|
id: attribute.attr_id,
|
|
name: System.decryptDataWithUserKey(attribute.attribute_name, userKey),
|
|
lastUpdate: attribute.last_update
|
|
}));
|
|
|
|
return {
|
|
id: characterId,
|
|
name: System.decryptDataWithUserKey(character.first_name, userKey),
|
|
lastUpdate: character.last_update,
|
|
attributes
|
|
};
|
|
});
|
|
|
|
const locations: SyncedLocation[] = allLocations
|
|
.filter((location: SyncedLocationResult): boolean => location.book_id === bookId)
|
|
.map((location: SyncedLocationResult): SyncedLocation => {
|
|
const locationId: string = location.loc_id;
|
|
|
|
const elements: SyncedLocationElement[] = allLocationElements
|
|
.filter((element: SyncedLocationElementResult): boolean => element.location === locationId)
|
|
.map((element: SyncedLocationElementResult): SyncedLocationElement => {
|
|
const elementId: string = element.element_id;
|
|
|
|
const subElements: SyncedLocationSubElement[] = allLocationSubElements
|
|
.filter((subElement: SyncedLocationSubElementResult): boolean => subElement.element_id === elementId)
|
|
.map((subElement: SyncedLocationSubElementResult): SyncedLocationSubElement => ({
|
|
id: subElement.sub_element_id,
|
|
name: System.decryptDataWithUserKey(subElement.sub_elem_name, userKey),
|
|
lastUpdate: subElement.last_update
|
|
}));
|
|
|
|
return {
|
|
id: elementId,
|
|
name: System.decryptDataWithUserKey(element.element_name, userKey),
|
|
lastUpdate: element.last_update,
|
|
subElements
|
|
};
|
|
});
|
|
|
|
return {
|
|
id: locationId,
|
|
name: System.decryptDataWithUserKey(location.loc_name, userKey),
|
|
lastUpdate: location.last_update,
|
|
elements
|
|
};
|
|
});
|
|
|
|
const worlds: SyncedWorld[] = allWorlds
|
|
.filter((world: SyncedWorldResult): boolean => world.book_id === bookId)
|
|
.map((world: SyncedWorldResult): SyncedWorld => {
|
|
const worldId: string = world.world_id;
|
|
|
|
const elements: SyncedWorldElement[] = allWorldElements
|
|
.filter((worldElement: SyncedWorldElementResult): boolean => worldElement.world_id === worldId)
|
|
.map((worldElement: SyncedWorldElementResult): SyncedWorldElement => ({
|
|
id: worldElement.element_id,
|
|
name: System.decryptDataWithUserKey(worldElement.name, userKey),
|
|
lastUpdate: worldElement.last_update
|
|
}));
|
|
|
|
return {
|
|
id: worldId,
|
|
name: System.decryptDataWithUserKey(world.name, userKey),
|
|
lastUpdate: world.last_update,
|
|
elements
|
|
};
|
|
});
|
|
|
|
const incidents: SyncedIncident[] = allIncidents
|
|
.filter((incident: SyncedIncidentResult): boolean => incident.book_id === bookId)
|
|
.map((incident: SyncedIncidentResult): SyncedIncident => ({
|
|
id: incident.incident_id,
|
|
name: System.decryptDataWithUserKey(incident.title, userKey),
|
|
lastUpdate: incident.last_update
|
|
}));
|
|
|
|
const plotPoints: SyncedPlotPoint[] = allPlotPoints
|
|
.filter((plotPoint: SyncedPlotPointResult): boolean => plotPoint.book_id === bookId)
|
|
.map((plotPoint: SyncedPlotPointResult): SyncedPlotPoint => ({
|
|
id: plotPoint.plot_point_id,
|
|
name: System.decryptDataWithUserKey(plotPoint.title, userKey),
|
|
lastUpdate: plotPoint.last_update
|
|
}));
|
|
|
|
const issues: SyncedIssue[] = allIssues
|
|
.filter((issue: SyncedIssueResult): boolean => issue.book_id === bookId)
|
|
.map((issue: SyncedIssueResult): SyncedIssue => ({
|
|
id: issue.issue_id,
|
|
name: System.decryptDataWithUserKey(issue.name, userKey),
|
|
lastUpdate: issue.last_update
|
|
}));
|
|
|
|
const actSummaries: SyncedActSummary[] = allActSummaries
|
|
.filter((actSummary: SyncedActSummaryResult): boolean => actSummary.book_id === bookId)
|
|
.map((actSummary: SyncedActSummaryResult): SyncedActSummary => ({
|
|
id: actSummary.act_sum_id,
|
|
lastUpdate: actSummary.last_update
|
|
}));
|
|
|
|
const guidelineData: SyncedGuideLineResult | undefined = allGuidelines.find((guideline: SyncedGuideLineResult): boolean => guideline.book_id === bookId);
|
|
const guideLine: SyncedGuideLine | null = guidelineData ? {
|
|
lastUpdate: guidelineData.last_update
|
|
} : null;
|
|
|
|
const aiGuidelineData: SyncedAIGuideLineResult | undefined = allAIGuidelines.find((aiGuideline: SyncedAIGuideLineResult): boolean => aiGuideline.book_id === bookId);
|
|
const aiGuideLine: SyncedAIGuideLine | null = aiGuidelineData ? {
|
|
lastUpdate: aiGuidelineData.last_update
|
|
} : null;
|
|
|
|
return {
|
|
id: bookId,
|
|
type: book.type,
|
|
title: System.decryptDataWithUserKey(book.title, userKey),
|
|
subTitle: book.sub_title ? System.decryptDataWithUserKey(book.sub_title, userKey) : null,
|
|
lastUpdate: book.last_update,
|
|
chapters,
|
|
characters,
|
|
locations,
|
|
worlds,
|
|
incidents,
|
|
plotPoints,
|
|
issues,
|
|
actSummaries,
|
|
guideLine,
|
|
aiGuideLine
|
|
};
|
|
});
|
|
}
|
|
|
|
static async uploadBookForSync(userId:string,bookId: string,lang: "fr" | "en"): Promise<CompleteBook> {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const [
|
|
eritBooksRaw,
|
|
actSummariesRaw,
|
|
aiGuideLineRaw,
|
|
chaptersRaw,
|
|
charactersRaw,
|
|
guideLineRaw,
|
|
incidentsRaw,
|
|
issuesRaw,
|
|
locationsRaw,
|
|
plotPointsRaw,
|
|
worldsRaw
|
|
]: [
|
|
EritBooksTable[],
|
|
BookActSummariesTable[],
|
|
BookAIGuideLineTable[],
|
|
BookChaptersTable[],
|
|
BookCharactersTable[],
|
|
BookGuideLineTable[],
|
|
BookIncidentsTable[],
|
|
BookIssuesTable[],
|
|
BookLocationTable[],
|
|
BookPlotPointsTable[],
|
|
BookWorldTable[]
|
|
] = await Promise.all([
|
|
BookRepo.fetchEritBooksTable(userId, bookId,lang),
|
|
BookRepo.fetchBookActSummaries(userId, bookId,lang),
|
|
BookRepo.fetchBookAIGuideLine(userId, bookId,lang),
|
|
BookRepo.fetchBookChapters(userId, bookId,lang),
|
|
BookRepo.fetchBookCharacters(userId, bookId,lang),
|
|
BookRepo.fetchBookGuideLineTable(userId, bookId,lang),
|
|
BookRepo.fetchBookIncidents(userId, bookId,lang),
|
|
BookRepo.fetchBookIssues(userId, bookId,lang),
|
|
BookRepo.fetchBookLocations(userId, bookId,lang),
|
|
BookRepo.fetchBookPlotPoints(userId, bookId,lang),
|
|
BookRepo.fetchBookWorlds(userId, bookId,lang)
|
|
]);
|
|
|
|
const [
|
|
chapterContentsNested,
|
|
chapterInfosNested,
|
|
characterAttributesNested,
|
|
worldElementsNested,
|
|
locationElementsNested
|
|
]: [
|
|
BookChapterContentTable[][],
|
|
BookChapterInfosTable[][],
|
|
BookCharactersAttributesTable[][],
|
|
BookWorldElementsTable[][],
|
|
LocationElementTable[][]
|
|
] = await Promise.all([
|
|
Promise.all(chaptersRaw.map((chapter: BookChaptersTable): Promise<BookChapterContentTable[]> => BookRepo.fetchBookChapterContents(userId, chapter.chapter_id,lang))),
|
|
Promise.all(chaptersRaw.map((chapter: BookChaptersTable): Promise<BookChapterInfosTable[]> => BookRepo.fetchBookChapterInfos(userId, chapter.chapter_id,lang))),
|
|
Promise.all(charactersRaw.map((character: BookCharactersTable): Promise<BookCharactersAttributesTable[]> => BookRepo.fetchBookCharactersAttributes(userId, character.character_id,lang))),
|
|
Promise.all(worldsRaw.map((world: BookWorldTable): Promise<BookWorldElementsTable[]> => BookRepo.fetchBookWorldElements(userId, world.world_id,lang))),
|
|
Promise.all(locationsRaw.map((location: BookLocationTable): Promise<LocationElementTable[]> => BookRepo.fetchLocationElements(userId, location.loc_id,lang)))
|
|
]);
|
|
|
|
const chapterContentsRaw: BookChapterContentTable[] = chapterContentsNested.flat();
|
|
const chapterInfosRaw: BookChapterInfosTable[] = chapterInfosNested.flat();
|
|
const characterAttributesRaw: BookCharactersAttributesTable[] = characterAttributesNested.flat();
|
|
const worldElementsRaw: BookWorldElementsTable[] = worldElementsNested.flat();
|
|
const locationElementsRaw: LocationElementTable[] = locationElementsNested.flat();
|
|
|
|
const locationSubElementsNested: LocationSubElementTable[][] = await Promise.all(
|
|
locationElementsRaw.map((element: LocationElementTable): Promise<LocationSubElementTable[]> => BookRepo.fetchLocationSubElements(userId, element.element_id,lang))
|
|
);
|
|
const locationSubElementsRaw: LocationSubElementTable[] = locationSubElementsNested.flat();
|
|
|
|
const eritBooks: EritBooksTable[] = eritBooksRaw.map((book: EritBooksTable): EritBooksTable => ({
|
|
...book,
|
|
title: System.decryptDataWithUserKey(book.title, userKey),
|
|
sub_title: book.sub_title ? System.decryptDataWithUserKey(book.sub_title, userKey) : null,
|
|
summary: book.summary ? System.decryptDataWithUserKey(book.summary, userKey) : null,
|
|
cover_image: book.cover_image ? System.decryptDataWithUserKey(book.cover_image, userKey) : null
|
|
}));
|
|
|
|
const actSummaries: BookActSummariesTable[] = actSummariesRaw.map((actSummary: BookActSummariesTable): BookActSummariesTable => ({
|
|
...actSummary,
|
|
summary: actSummary.summary ? System.decryptDataWithUserKey(actSummary.summary, userKey) : null
|
|
}));
|
|
|
|
const aiGuideLine: BookAIGuideLineTable[] = aiGuideLineRaw.map((guideLine: BookAIGuideLineTable): BookAIGuideLineTable => ({
|
|
...guideLine,
|
|
global_resume: guideLine.global_resume ? System.decryptDataWithUserKey(guideLine.global_resume, userKey) : null,
|
|
themes: guideLine.themes ? System.decryptDataWithUserKey(guideLine.themes, userKey) : null,
|
|
tone: guideLine.tone ? System.decryptDataWithUserKey(guideLine.tone, userKey) : null,
|
|
atmosphere: guideLine.atmosphere ? System.decryptDataWithUserKey(guideLine.atmosphere, userKey) : null,
|
|
current_resume: guideLine.current_resume ? System.decryptDataWithUserKey(guideLine.current_resume, userKey) : null
|
|
}));
|
|
|
|
const chapters: BookChaptersTable[] = chaptersRaw.map((chapter: BookChaptersTable): BookChaptersTable => ({
|
|
...chapter,
|
|
title: System.decryptDataWithUserKey(chapter.title, userKey)
|
|
}));
|
|
|
|
const chapterContents: BookChapterContentTable[] = chapterContentsRaw.map((chapterContent: BookChapterContentTable): BookChapterContentTable => ({
|
|
...chapterContent,
|
|
content: chapterContent.content ? JSON.parse(System.decryptDataWithUserKey(chapterContent.content, userKey)) : null
|
|
}));
|
|
|
|
const chapterInfos: BookChapterInfosTable[] = chapterInfosRaw.map((chapterInfo: BookChapterInfosTable): BookChapterInfosTable => ({
|
|
...chapterInfo,
|
|
summary: chapterInfo.summary ? System.decryptDataWithUserKey(chapterInfo.summary, userKey) : null,
|
|
goal: chapterInfo.goal ? System.decryptDataWithUserKey(chapterInfo.goal, userKey) : null
|
|
}));
|
|
|
|
const characters: BookCharactersTable[] = charactersRaw.map((character: BookCharactersTable): BookCharactersTable => ({
|
|
...character,
|
|
first_name: System.decryptDataWithUserKey(character.first_name, userKey),
|
|
last_name: character.last_name ? System.decryptDataWithUserKey(character.last_name, userKey) : null,
|
|
category: System.decryptDataWithUserKey(character.category, userKey),
|
|
title: character.title ? System.decryptDataWithUserKey(character.title, userKey) : null,
|
|
role: character.role ? System.decryptDataWithUserKey(character.role, userKey) : null,
|
|
biography: character.biography ? System.decryptDataWithUserKey(character.biography, userKey) : null,
|
|
history: character.history ? System.decryptDataWithUserKey(character.history, userKey) : null
|
|
}));
|
|
|
|
const characterAttributes: BookCharactersAttributesTable[] = characterAttributesRaw.map((attribute: BookCharactersAttributesTable): BookCharactersAttributesTable => ({
|
|
...attribute,
|
|
attribute_name: System.decryptDataWithUserKey(attribute.attribute_name, userKey),
|
|
attribute_value: System.decryptDataWithUserKey(attribute.attribute_value, userKey)
|
|
}));
|
|
|
|
const guideLine: BookGuideLineTable[] = guideLineRaw.map((guide: BookGuideLineTable): BookGuideLineTable => ({
|
|
...guide,
|
|
tone: guide.tone ? System.decryptDataWithUserKey(guide.tone, userKey) : null,
|
|
atmosphere: guide.atmosphere ? System.decryptDataWithUserKey(guide.atmosphere, userKey) : null,
|
|
writing_style: guide.writing_style ? System.decryptDataWithUserKey(guide.writing_style, userKey) : null,
|
|
themes: guide.themes ? System.decryptDataWithUserKey(guide.themes, userKey) : null,
|
|
symbolism: guide.symbolism ? System.decryptDataWithUserKey(guide.symbolism, userKey) : null,
|
|
motifs: guide.motifs ? System.decryptDataWithUserKey(guide.motifs, userKey) : null,
|
|
narrative_voice: guide.narrative_voice ? System.decryptDataWithUserKey(guide.narrative_voice, userKey) : null,
|
|
pacing: guide.pacing ? System.decryptDataWithUserKey(guide.pacing, userKey) : null,
|
|
intended_audience: guide.intended_audience ? System.decryptDataWithUserKey(guide.intended_audience, userKey) : null,
|
|
key_messages: guide.key_messages ? System.decryptDataWithUserKey(guide.key_messages, userKey) : null
|
|
}));
|
|
|
|
const incidents: BookIncidentsTable[] = incidentsRaw.map((incident: BookIncidentsTable): BookIncidentsTable => ({
|
|
...incident,
|
|
title: System.decryptDataWithUserKey(incident.title, userKey),
|
|
summary: incident.summary ? System.decryptDataWithUserKey(incident.summary, userKey) : null
|
|
}));
|
|
|
|
const issues: BookIssuesTable[] = issuesRaw.map((issue: BookIssuesTable): BookIssuesTable => ({
|
|
...issue,
|
|
name: System.decryptDataWithUserKey(issue.name, userKey)
|
|
}));
|
|
|
|
const locations: BookLocationTable[] = locationsRaw.map((location: BookLocationTable): BookLocationTable => ({
|
|
...location,
|
|
loc_name: System.decryptDataWithUserKey(location.loc_name, userKey)
|
|
}));
|
|
|
|
const plotPoints: BookPlotPointsTable[] = plotPointsRaw.map((plotPoint: BookPlotPointsTable): BookPlotPointsTable => ({
|
|
...plotPoint,
|
|
title: System.decryptDataWithUserKey(plotPoint.title, userKey),
|
|
summary: plotPoint.summary ? System.decryptDataWithUserKey(plotPoint.summary, userKey) : null
|
|
}));
|
|
|
|
const worlds: BookWorldTable[] = worldsRaw.map((world: BookWorldTable): BookWorldTable => ({
|
|
...world,
|
|
name: System.decryptDataWithUserKey(world.name, userKey),
|
|
history: world.history ? System.decryptDataWithUserKey(world.history, userKey) : null,
|
|
politics: world.politics ? System.decryptDataWithUserKey(world.politics, userKey) : null,
|
|
economy: world.economy ? System.decryptDataWithUserKey(world.economy, userKey) : null,
|
|
religion: world.religion ? System.decryptDataWithUserKey(world.religion, userKey) : null,
|
|
languages: world.languages ? System.decryptDataWithUserKey(world.languages, userKey) : null
|
|
}));
|
|
|
|
const worldElements: BookWorldElementsTable[] = worldElementsRaw.map((worldElement: BookWorldElementsTable): BookWorldElementsTable => ({
|
|
...worldElement,
|
|
name: System.decryptDataWithUserKey(worldElement.name, userKey),
|
|
description: worldElement.description ? System.decryptDataWithUserKey(worldElement.description, userKey) : null
|
|
}));
|
|
|
|
const locationElements: LocationElementTable[] = locationElementsRaw.map((locationElement: LocationElementTable): LocationElementTable => ({
|
|
...locationElement,
|
|
element_name: System.decryptDataWithUserKey(locationElement.element_name, userKey),
|
|
element_description: locationElement.element_description ? System.decryptDataWithUserKey(locationElement.element_description, userKey) : null
|
|
}));
|
|
|
|
const locationSubElements: LocationSubElementTable[] = locationSubElementsRaw.map((locationSubElement: LocationSubElementTable): LocationSubElementTable => ({
|
|
...locationSubElement,
|
|
sub_elem_name: System.decryptDataWithUserKey(locationSubElement.sub_elem_name, userKey),
|
|
sub_elem_description: locationSubElement.sub_elem_description ? System.decryptDataWithUserKey(locationSubElement.sub_elem_description, userKey) : null
|
|
}));
|
|
|
|
return {
|
|
eritBooks,
|
|
actSummaries,
|
|
aiGuideLine,
|
|
chapters,
|
|
chapterContents,
|
|
chapterInfos,
|
|
characters,
|
|
characterAttributes,
|
|
guideLine,
|
|
incidents,
|
|
issues,
|
|
locations,
|
|
plotPoints,
|
|
worlds,
|
|
worldElements,
|
|
locationElements,
|
|
locationSubElements
|
|
};
|
|
}
|
|
|
|
static async saveCompleteBook(userId: string, data: CompleteBook, lang: "fr" | "en"):Promise<boolean> {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
|
|
const book: EritBooksTable = data.eritBooks[0];
|
|
const encryptedBookTitle: string = System.encryptDataWithUserKey(book.title, userKey);
|
|
const encryptedBookSubTitle: string | null = book.sub_title ? System.encryptDataWithUserKey(book.sub_title, userKey) : null;
|
|
const encryptedBookSummary: string | null = book.summary ? System.encryptDataWithUserKey(book.summary, userKey) : null;
|
|
const encryptedBookCoverImage: string | null = book.cover_image ? System.encryptDataWithUserKey(book.cover_image, userKey) : null;
|
|
|
|
const bookInserted: boolean = BookRepo.insertSyncBook(
|
|
book.book_id,
|
|
userId,
|
|
book.type,
|
|
encryptedBookTitle,
|
|
book.hashed_title,
|
|
encryptedBookSubTitle,
|
|
book.hashed_sub_title,
|
|
encryptedBookSummary,
|
|
book.serie_id,
|
|
book.desired_release_date,
|
|
book.desired_word_count,
|
|
book.words_count,
|
|
encryptedBookCoverImage,
|
|
book.last_update,
|
|
lang
|
|
);
|
|
if (!bookInserted) return false;
|
|
|
|
const chaptersInserted: boolean = data.chapters.every((chapter: BookChaptersTable): boolean => {
|
|
const encryptedTitle: string = System.encryptDataWithUserKey(chapter.title, userKey);
|
|
return BookRepo.insertSyncChapter(chapter.chapter_id, chapter.book_id, userId, encryptedTitle, chapter.hashed_title, chapter.words_count, chapter.chapter_order, chapter.last_update, lang);
|
|
});
|
|
if (!chaptersInserted) return false;
|
|
|
|
const incidentsInserted: boolean = data.incidents.every((incident: BookIncidentsTable): boolean => {
|
|
const encryptedIncidentTitle: string = System.encryptDataWithUserKey(incident.title, userKey);
|
|
const encryptedIncidentSummary: string | null = incident.summary ? System.encryptDataWithUserKey(incident.summary, userKey) : null;
|
|
return BookRepo.insertSyncIncident(incident.incident_id, userId, incident.book_id, encryptedIncidentTitle, incident.hashed_title, encryptedIncidentSummary, incident.last_update, lang);
|
|
});
|
|
if (!incidentsInserted) return false;
|
|
|
|
const plotPointsInserted: boolean = data.plotPoints.every((plotPoint: BookPlotPointsTable): boolean => {
|
|
const encryptedPlotTitle: string = System.encryptDataWithUserKey(plotPoint.title, userKey);
|
|
const encryptedPlotSummary: string | null = plotPoint.summary ? System.encryptDataWithUserKey(plotPoint.summary, userKey) : null;
|
|
return BookRepo.insertSyncPlotPoint(plotPoint.plot_point_id, encryptedPlotTitle, plotPoint.hashed_title, encryptedPlotSummary, plotPoint.linked_incident_id, userId, plotPoint.book_id, plotPoint.last_update, lang);
|
|
});
|
|
if (!plotPointsInserted) return false;
|
|
|
|
const chapterContentsInserted: boolean = data.chapterContents.every((content: BookChapterContentTable): boolean => {
|
|
const encryptedContent: string | null = content.content ? System.encryptDataWithUserKey(JSON.stringify(content.content), userKey) : null;
|
|
return BookRepo.insertSyncChapterContent(content.content_id, content.chapter_id, userId, content.version, encryptedContent, content.words_count, content.time_on_it, content.last_update, lang);
|
|
});
|
|
if (!chapterContentsInserted) return false;
|
|
|
|
const chapterInfosInserted: boolean = data.chapterInfos.every((info: BookChapterInfosTable): boolean => {
|
|
const encryptedSummary: string | null = info.summary ? System.encryptDataWithUserKey(info.summary, userKey) : null;
|
|
const encryptedGoal: string | null = info.goal ? System.encryptDataWithUserKey(info.goal, userKey) : null;
|
|
return BookRepo.insertSyncChapterInfo(info.chapter_info_id, info.chapter_id, info.act_id, info.incident_id, info.plot_point_id, info.book_id, userId, encryptedSummary, encryptedGoal, info.last_update, lang);
|
|
});
|
|
if (!chapterInfosInserted) return false;
|
|
|
|
const charactersInserted: boolean = data.characters.every((character: BookCharactersTable): boolean => {
|
|
const encryptedFirstName: string = System.encryptDataWithUserKey(character.first_name, userKey);
|
|
const encryptedLastName: string | null = character.last_name ? System.encryptDataWithUserKey(character.last_name, userKey) : null;
|
|
const encryptedCategory: string = System.encryptDataWithUserKey(character.category, userKey);
|
|
const encryptedCharTitle: string | null = character.title ? System.encryptDataWithUserKey(character.title, userKey) : null;
|
|
const encryptedImage: string | null = character.image ? System.encryptDataWithUserKey(character.image, userKey) : null;
|
|
const encryptedRole: string | null = character.role ? System.encryptDataWithUserKey(character.role, userKey) : null;
|
|
const encryptedBiography: string | null = character.biography ? System.encryptDataWithUserKey(character.biography, userKey) : null;
|
|
const encryptedCharHistory: string | null = character.history ? System.encryptDataWithUserKey(character.history, userKey) : null;
|
|
return BookRepo.insertSyncCharacter(character.character_id, character.book_id, userId, encryptedFirstName, encryptedLastName, encryptedCategory, encryptedCharTitle, encryptedImage, encryptedRole, encryptedBiography, encryptedCharHistory, character.last_update, lang);
|
|
});
|
|
if (!charactersInserted) return false;
|
|
|
|
const characterAttributesInserted: boolean = data.characterAttributes.every((attr: BookCharactersAttributesTable): boolean => {
|
|
const encryptedAttrName: string = System.encryptDataWithUserKey(attr.attribute_name, userKey);
|
|
const encryptedAttrValue: string = System.encryptDataWithUserKey(attr.attribute_value, userKey);
|
|
return BookRepo.insertSyncCharacterAttribute(attr.attr_id, attr.character_id, userId, encryptedAttrName, encryptedAttrValue, attr.last_update, lang);
|
|
});
|
|
if (!characterAttributesInserted) return false;
|
|
|
|
const locationsInserted: boolean = data.locations.every((location: BookLocationTable): boolean => {
|
|
const encryptedLocName: string = System.encryptDataWithUserKey(location.loc_name, userKey);
|
|
return BookRepo.insertSyncLocation(location.loc_id, location.book_id, userId, encryptedLocName, location.loc_original_name, location.last_update, lang);
|
|
});
|
|
if (!locationsInserted) return false;
|
|
|
|
const locationElementsInserted: boolean = data.locationElements.every((element: LocationElementTable): boolean => {
|
|
const encryptedLocElemName: string = System.encryptDataWithUserKey(element.element_name, userKey);
|
|
const encryptedLocElemDesc: string | null = element.element_description ? System.encryptDataWithUserKey(element.element_description, userKey) : null;
|
|
return BookRepo.insertSyncLocationElement(element.element_id, element.location, userId, encryptedLocElemName, element.original_name, encryptedLocElemDesc, element.last_update, lang);
|
|
});
|
|
if (!locationElementsInserted) return false;
|
|
|
|
const locationSubElementsInserted: boolean = data.locationSubElements.every((subElement: LocationSubElementTable): boolean => {
|
|
const encryptedSubElemName: string = System.encryptDataWithUserKey(subElement.sub_elem_name, userKey);
|
|
const encryptedSubElemDesc: string | null = subElement.sub_elem_description ? System.encryptDataWithUserKey(subElement.sub_elem_description, userKey) : null;
|
|
return BookRepo.insertSyncLocationSubElement(subElement.sub_element_id, subElement.element_id, userId, encryptedSubElemName, subElement.original_name, encryptedSubElemDesc, subElement.last_update, lang);
|
|
});
|
|
if (!locationSubElementsInserted) return false;
|
|
|
|
const worldsInserted: boolean = data.worlds.every((world: BookWorldTable): boolean => {
|
|
const encryptedWorldName: string = System.encryptDataWithUserKey(world.name, userKey);
|
|
const encryptedWorldHistory: string | null = world.history ? System.encryptDataWithUserKey(world.history, userKey) : null;
|
|
const encryptedPolitics: string | null = world.politics ? System.encryptDataWithUserKey(world.politics, userKey) : null;
|
|
const encryptedEconomy: string | null = world.economy ? System.encryptDataWithUserKey(world.economy, userKey) : null;
|
|
const encryptedReligion: string | null = world.religion ? System.encryptDataWithUserKey(world.religion, userKey) : null;
|
|
const encryptedLanguages: string | null = world.languages ? System.encryptDataWithUserKey(world.languages, userKey) : null;
|
|
return BookRepo.insertSyncWorld(world.world_id, encryptedWorldName, world.hashed_name, userId, world.book_id, encryptedWorldHistory, encryptedPolitics, encryptedEconomy, encryptedReligion, encryptedLanguages, world.last_update, lang);
|
|
});
|
|
if (!worldsInserted) return false;
|
|
|
|
const worldElementsInserted: boolean = data.worldElements.every((element: BookWorldElementsTable): boolean => {
|
|
const encryptedElemName: string = System.encryptDataWithUserKey(element.name, userKey);
|
|
const encryptedElemDesc: string | null = element.description ? System.encryptDataWithUserKey(element.description, userKey) : null;
|
|
return BookRepo.insertSyncWorldElement(element.element_id, element.world_id, userId, element.element_type, encryptedElemName, element.original_name, encryptedElemDesc, element.last_update, lang);
|
|
});
|
|
if (!worldElementsInserted) return false;
|
|
|
|
const actSummariesInserted: boolean = data.actSummaries.every((actSummary: BookActSummariesTable): boolean => {
|
|
const encryptedSummary: string | null = actSummary.summary ? System.encryptDataWithUserKey(actSummary.summary, userKey) : null;
|
|
return BookRepo.insertSyncActSummary(actSummary.act_sum_id, actSummary.book_id, userId, actSummary.act_index, encryptedSummary, actSummary.last_update, lang);
|
|
});
|
|
if (!actSummariesInserted) return false;
|
|
|
|
const aiGuidelinesInserted: boolean = data.aiGuideLine.every((aiGuide: BookAIGuideLineTable): boolean => {
|
|
const encryptedGlobalResume: string | null = aiGuide.global_resume ? System.encryptDataWithUserKey(aiGuide.global_resume, userKey) : null;
|
|
const encryptedAIThemes: string | null = aiGuide.themes ? System.encryptDataWithUserKey(aiGuide.themes, userKey) : null;
|
|
const encryptedAITone: string | null = aiGuide.tone ? System.encryptDataWithUserKey(aiGuide.tone, userKey) : null;
|
|
const encryptedAIAtmosphere: string | null = aiGuide.atmosphere ? System.encryptDataWithUserKey(aiGuide.atmosphere, userKey) : null;
|
|
const encryptedCurrentResume: string | null = aiGuide.current_resume ? System.encryptDataWithUserKey(aiGuide.current_resume, userKey) : null;
|
|
return BookRepo.insertSyncAIGuideLine(userId, aiGuide.book_id, encryptedGlobalResume, encryptedAIThemes, aiGuide.verbe_tense, aiGuide.narrative_type, aiGuide.langue, aiGuide.dialogue_type, encryptedAITone, encryptedAIAtmosphere, encryptedCurrentResume, aiGuide.last_update, lang);
|
|
});
|
|
if (!aiGuidelinesInserted) return false;
|
|
|
|
const guidelinesInserted: boolean = data.guideLine.every((guide: BookGuideLineTable): boolean => {
|
|
const encryptedGuideTone: string | null = guide.tone ? System.encryptDataWithUserKey(guide.tone, userKey) : null;
|
|
const encryptedGuideAtmosphere: string | null = guide.atmosphere ? System.encryptDataWithUserKey(guide.atmosphere, userKey) : null;
|
|
const encryptedWritingStyle: string | null = guide.writing_style ? System.encryptDataWithUserKey(guide.writing_style, userKey) : null;
|
|
const encryptedGuideThemes: string | null = guide.themes ? System.encryptDataWithUserKey(guide.themes, userKey) : null;
|
|
const encryptedSymbolism: string | null = guide.symbolism ? System.encryptDataWithUserKey(guide.symbolism, userKey) : null;
|
|
const encryptedMotifs: string | null = guide.motifs ? System.encryptDataWithUserKey(guide.motifs, userKey) : null;
|
|
const encryptedNarrativeVoice: string | null = guide.narrative_voice ? System.encryptDataWithUserKey(guide.narrative_voice, userKey) : null;
|
|
const encryptedPacing: string | null = guide.pacing ? System.encryptDataWithUserKey(guide.pacing, userKey) : null;
|
|
const encryptedIntendedAudience: string | null = guide.intended_audience ? System.encryptDataWithUserKey(guide.intended_audience, userKey) : null;
|
|
const encryptedKeyMessages: string | null = guide.key_messages ? System.encryptDataWithUserKey(guide.key_messages, userKey) : null;
|
|
return BookRepo.insertSyncGuideLine(userId, guide.book_id, encryptedGuideTone, encryptedGuideAtmosphere, encryptedWritingStyle, encryptedGuideThemes, encryptedSymbolism, encryptedMotifs, encryptedNarrativeVoice, encryptedPacing, encryptedIntendedAudience, encryptedKeyMessages, guide.last_update, lang);
|
|
});
|
|
if (!guidelinesInserted) return false;
|
|
|
|
return data.issues.every((issue: BookIssuesTable): boolean => {
|
|
const encryptedIssueName: string = System.encryptDataWithUserKey(issue.name, userKey);
|
|
return BookRepo.insertSyncIssue(issue.issue_id, userId, issue.book_id, encryptedIssueName, issue.hashed_issue_name, issue.last_update, lang);
|
|
});
|
|
}
|
|
|
|
static async getCompleteSyncBook(userId: string, data: BookSyncCompare, lang: "fr" | "en"):Promise<CompleteBook> {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const bookData: EritBooksTable[] = [];
|
|
const chaptersData: BookChaptersTable[] = [];
|
|
const plotPointsData: BookPlotPointsTable[] = [];
|
|
const incidentsData: BookIncidentsTable[] = [];
|
|
const chapterContentsData: BookChapterContentTable[] = [];
|
|
const chapterInfosData: BookChapterInfosTable[] = [];
|
|
const charactersData: BookCharactersTable[] = [];
|
|
const characterAttributesData: BookCharactersAttributesTable[] = [];
|
|
const locationsData: BookLocationTable[] = [];
|
|
const locationElementsData: LocationElementTable[] = [];
|
|
const locationSubElementsData: LocationSubElementTable[] = [];
|
|
const worldsData: BookWorldTable[] = [];
|
|
const worldElementsData: BookWorldElementsTable[] = [];
|
|
const actSummariesData: BookActSummariesTable[] = [];
|
|
const guideLineData: BookGuideLineTable[] = [];
|
|
const aiGuideLineData: BookAIGuideLineTable[] = [];
|
|
const issuesData: BookIssuesTable[] = [];
|
|
|
|
const actSummaries: string[] = data.actSummaries;
|
|
const chapters: string[] = data.chapters;
|
|
const plotPoints: string[] = data.plotPoints;
|
|
const incidents: string[] = data.incidents;
|
|
const chapterContents: string[] = data.chapterContents;
|
|
const chapterInfos: string[] = data.chapterInfos;
|
|
const characters: string[] = data.characters;
|
|
const characterAttributes: string[] = data.characterAttributes;
|
|
const locations: string[] = data.locations;
|
|
const locationElements: string[] = data.locationElements;
|
|
const locationSubElements: string[] = data.locationSubElements;
|
|
const worlds: string[] = data.worlds;
|
|
const worldElements: string[] = data.worldElements;
|
|
const issues: string[] = data.issues;
|
|
|
|
if (actSummaries && actSummaries.length > 0) {
|
|
for (const id of actSummaries) {
|
|
const actSummary: BookActSummariesTable[] = await BookRepo.fetchCompleteActSummaryById(id, lang);
|
|
if (actSummary.length>0) {
|
|
const actSummaryData: BookActSummariesTable = actSummary[0];
|
|
actSummariesData.push({
|
|
...actSummaryData,
|
|
summary: actSummaryData.summary ? System.decryptDataWithUserKey(actSummaryData.summary, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chapters && chapters.length > 0) {
|
|
for (const id of chapters) {
|
|
const chapter: BookChaptersTable[] = await BookRepo.fetchCompleteChapterById(id, lang);
|
|
if (chapter.length>0) {
|
|
const chapterData: BookChaptersTable = chapter[0];
|
|
chaptersData.push({
|
|
...chapterData,
|
|
title: System.decryptDataWithUserKey(chapterData.title, userKey)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plotPoints && plotPoints.length > 0) {
|
|
for (const id of plotPoints) {
|
|
const plotPoint: BookPlotPointsTable[] = await BookRepo.fetchCompletePlotPointById(id, lang);
|
|
if (plotPoint.length>0) {
|
|
const plotPointData: BookPlotPointsTable = plotPoint[0];
|
|
plotPointsData.push({
|
|
...plotPointData,
|
|
title: System.decryptDataWithUserKey(plotPointData.title, userKey),
|
|
summary: plotPointData.summary ? System.decryptDataWithUserKey(plotPointData.summary, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (incidents && incidents.length > 0) {
|
|
for (const id of incidents) {
|
|
const incident: BookIncidentsTable[] = await BookRepo.fetchCompleteIncidentById(id, lang);
|
|
if (incident.length>0) {
|
|
const incidentData: BookIncidentsTable = incident[0];
|
|
incidentsData.push({
|
|
...incidentData,
|
|
title: System.decryptDataWithUserKey(incidentData.title, userKey),
|
|
summary: incidentData.summary ? System.decryptDataWithUserKey(incidentData.summary, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chapterContents && chapterContents.length > 0) {
|
|
for (const id of chapterContents) {
|
|
const chapterContent: BookChapterContentTable[] = await BookRepo.fetchCompleteChapterContentById(id, lang);
|
|
if (chapterContent.length>0) {
|
|
const chapterContentData: BookChapterContentTable = chapterContent[0];
|
|
chapterContentsData.push({
|
|
...chapterContentData,
|
|
content: chapterContentData.content ? JSON.parse(System.decryptDataWithUserKey(chapterContentData.content, userKey)) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chapterInfos && chapterInfos.length > 0) {
|
|
for (const id of chapterInfos) {
|
|
const chapterInfo: BookChapterInfosTable[] = await BookRepo.fetchCompleteChapterInfoById(id, lang);
|
|
if (chapterInfo.length>0) {
|
|
const chapterInfoData: BookChapterInfosTable = chapterInfo[0];
|
|
chapterInfosData.push({
|
|
...chapterInfoData,
|
|
summary: chapterInfoData.summary ? System.decryptDataWithUserKey(chapterInfoData.summary, userKey) : null,
|
|
goal: chapterInfoData.goal ? System.decryptDataWithUserKey(chapterInfoData.goal, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (characters && characters.length > 0) {
|
|
for (const id of characters) {
|
|
const character: BookCharactersTable[] = await BookRepo.fetchCompleteCharacterById(id, lang);
|
|
if (character.length>0) {
|
|
const characterData: BookCharactersTable = character[0];
|
|
charactersData.push({
|
|
...characterData,
|
|
first_name: System.decryptDataWithUserKey(characterData.first_name, userKey),
|
|
last_name: characterData.last_name ? System.decryptDataWithUserKey(characterData.last_name, userKey) : null,
|
|
category: System.decryptDataWithUserKey(characterData.category, userKey),
|
|
title: characterData.title ? System.decryptDataWithUserKey(characterData.title, userKey) : null,
|
|
role: characterData.role ? System.decryptDataWithUserKey(characterData.role, userKey) : null,
|
|
biography: characterData.biography ? System.decryptDataWithUserKey(characterData.biography, userKey) : null,
|
|
history: characterData.history ? System.decryptDataWithUserKey(characterData.history, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (characterAttributes && characterAttributes.length > 0) {
|
|
for (const id of characterAttributes) {
|
|
const characterAttribute: BookCharactersAttributesTable[] = await BookRepo.fetchCompleteCharacterAttributeById(id, lang);
|
|
if (characterAttribute.length>0) {
|
|
const characterAttributeData: BookCharactersAttributesTable = characterAttribute[0];
|
|
characterAttributesData.push({
|
|
...characterAttributeData,
|
|
attribute_name: System.decryptDataWithUserKey(characterAttributeData.attribute_name, userKey),
|
|
attribute_value: System.decryptDataWithUserKey(characterAttributeData.attribute_value, userKey)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locations && locations.length > 0) {
|
|
for (const id of locations) {
|
|
const location: BookLocationTable[] = await BookRepo.fetchCompleteLocationById(id, lang);
|
|
if (location.length>0) {
|
|
const locationData: BookLocationTable = location[0];
|
|
locationsData.push({
|
|
...locationData,
|
|
loc_name: System.decryptDataWithUserKey(locationData.loc_name, userKey)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locationElements && locationElements.length > 0) {
|
|
for (const id of locationElements) {
|
|
const locationElement: LocationElementTable[] = await BookRepo.fetchCompleteLocationElementById(id, lang);
|
|
if (locationElement.length>0) {
|
|
const locationElementData: LocationElementTable = locationElement[0];
|
|
locationElementsData.push({
|
|
...locationElementData,
|
|
element_name: System.decryptDataWithUserKey(locationElementData.element_name, userKey),
|
|
element_description: locationElementData.element_description ? System.decryptDataWithUserKey(locationElementData.element_description, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locationSubElements && locationSubElements.length > 0) {
|
|
for (const id of locationSubElements) {
|
|
const locationSubElement: LocationSubElementTable[] = await BookRepo.fetchCompleteLocationSubElementById(id, lang);
|
|
if (locationSubElement.length>0) {
|
|
const locationSubElementData: LocationSubElementTable = locationSubElement[0];
|
|
locationSubElementsData.push({
|
|
...locationSubElementData,
|
|
sub_elem_name: System.decryptDataWithUserKey(locationSubElementData.sub_elem_name, userKey),
|
|
sub_elem_description: locationSubElementData.sub_elem_description ? System.decryptDataWithUserKey(locationSubElementData.sub_elem_description, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (worlds && worlds.length > 0) {
|
|
for (const id of worlds) {
|
|
const world: BookWorldTable[] = await BookRepo.fetchCompleteWorldById(id, lang);
|
|
if (world.length>0) {
|
|
const worldData: BookWorldTable = world[0];
|
|
worldsData.push({
|
|
...worldData,
|
|
name: System.decryptDataWithUserKey(worldData.name, userKey),
|
|
history: worldData.history ? System.decryptDataWithUserKey(worldData.history, userKey) : null,
|
|
politics: worldData.politics ? System.decryptDataWithUserKey(worldData.politics, userKey) : null,
|
|
economy: worldData.economy ? System.decryptDataWithUserKey(worldData.economy, userKey) : null,
|
|
religion: worldData.religion ? System.decryptDataWithUserKey(worldData.religion, userKey) : null,
|
|
languages: worldData.languages ? System.decryptDataWithUserKey(worldData.languages, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (worldElements && worldElements.length > 0) {
|
|
for (const id of worldElements) {
|
|
const worldElement: BookWorldElementsTable[] = await BookRepo.fetchCompleteWorldElementById(id, lang);
|
|
if (worldElement.length>0) {
|
|
const worldElementData: BookWorldElementsTable = worldElement[0];
|
|
worldElementsData.push({
|
|
...worldElementData,
|
|
name: System.decryptDataWithUserKey(worldElementData.name, userKey),
|
|
description: worldElementData.description ? System.decryptDataWithUserKey(worldElementData.description, userKey) : null
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (issues && issues.length > 0) {
|
|
for (const id of issues) {
|
|
const issue: BookIssuesTable[] = await BookRepo.fetchCompleteIssueById(id, lang);
|
|
if (issue.length>0) {
|
|
const issueData: BookIssuesTable = issue[0];
|
|
issuesData.push({
|
|
...issueData,
|
|
name: System.decryptDataWithUserKey(issueData.name, userKey)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
const book: EritBooksTable[] = await BookRepo.fetchCompleteBookById(data.id, lang);
|
|
if (book.length>0) {
|
|
const bookDataItem: EritBooksTable = book[0];
|
|
bookData.push({
|
|
...bookDataItem,
|
|
title: System.decryptDataWithUserKey(bookDataItem.title, userKey),
|
|
sub_title: bookDataItem.sub_title ? System.decryptDataWithUserKey(bookDataItem.sub_title, userKey) : null,
|
|
summary: bookDataItem.summary ? System.decryptDataWithUserKey(bookDataItem.summary, userKey) : null,
|
|
cover_image: bookDataItem.cover_image ? System.decryptDataWithUserKey(bookDataItem.cover_image, userKey) : null
|
|
});
|
|
}
|
|
return {
|
|
eritBooks: bookData,
|
|
chapters: chaptersData,
|
|
plotPoints: plotPointsData,
|
|
incidents: incidentsData,
|
|
chapterContents: chapterContentsData,
|
|
chapterInfos: chapterInfosData,
|
|
characters: charactersData,
|
|
characterAttributes: characterAttributesData,
|
|
locations: locationsData,
|
|
locationElements: locationElementsData,
|
|
locationSubElements: locationSubElementsData,
|
|
worlds: worldsData,
|
|
worldElements: worldElementsData,
|
|
actSummaries: actSummariesData,
|
|
guideLine: guideLineData,
|
|
aiGuideLine: aiGuideLineData,
|
|
issues: issuesData
|
|
};
|
|
}
|
|
|
|
static async syncBookFromServerToClient(userId:string,completeBook: CompleteBook,lang:"fr"|"en"):Promise<boolean> {
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
|
|
const actSummaries: BookActSummariesTable[] = completeBook.actSummaries;
|
|
const chapters: BookChaptersTable[] = completeBook.chapters;
|
|
const plotPoints: BookPlotPointsTable[] = completeBook.plotPoints;
|
|
const incidents: BookIncidentsTable[] = completeBook.incidents;
|
|
const chapterContents: BookChapterContentTable[] = completeBook.chapterContents;
|
|
const chapterInfos: BookChapterInfosTable[] = completeBook.chapterInfos;
|
|
const characters: BookCharactersTable[] = completeBook.characters;
|
|
const characterAttributes: BookCharactersAttributesTable[] = completeBook.characterAttributes;
|
|
const locations: BookLocationTable[] = completeBook.locations;
|
|
const locationElements: LocationElementTable[] = completeBook.locationElements;
|
|
const locationSubElements: LocationSubElementTable[] = completeBook.locationSubElements;
|
|
const worlds: BookWorldTable[] = completeBook.worlds;
|
|
const worldElements: BookWorldElementsTable[] = completeBook.worldElements;
|
|
const issues: BookIssuesTable[] = completeBook.issues;
|
|
|
|
const bookId: string = completeBook.eritBooks.length > 0 ? completeBook.eritBooks[0].book_id : '';
|
|
if (chapters && chapters.length > 0) {
|
|
for (const chapter of chapters) {
|
|
const isExist: boolean = ChapterRepo.isChapterExist(userId, chapter.chapter_id,lang);
|
|
const title: string = System.encryptDataWithUserKey(chapter.title, userKey)
|
|
if (isExist) {
|
|
const updated: boolean = ChapterRepo.updateChapter(userId, chapter.chapter_id, title, chapter.hashed_title, chapter.chapter_order, chapter.last_update, lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncChapter(chapter.chapter_id, chapter.book_id, userId, title, chapter.hashed_title, chapter.words_count || 0, chapter.chapter_order, chapter.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (actSummaries && actSummaries.length > 0) {
|
|
for (const act of actSummaries) {
|
|
const isExist: boolean = BookRepo.actSummarizeExist(userId, bookId, act.act_index,lang);
|
|
const summary: string = System.encryptDataWithUserKey(act.summary ? act.summary : '', userKey)
|
|
if (isExist) {
|
|
const updated: boolean = BookRepo.updateActSummary(userId, bookId, act.act_index, summary, act.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncActSummary(act.act_sum_id, userId, bookId, act.act_index, summary, act.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (plotPoints && plotPoints.length > 0) {
|
|
for (const plotPoint of plotPoints) {
|
|
const title: string = System.encryptDataWithUserKey(plotPoint.title, userKey);
|
|
const summary: string = System.encryptDataWithUserKey(plotPoint.summary ? plotPoint.summary : '', userKey);
|
|
const ifExist: boolean = BookRepo.plotPointExist(userId, bookId, plotPoint.plot_point_id,lang);
|
|
if (ifExist) {
|
|
const updated: boolean = BookRepo.updatePlotPoint(userId, bookId, plotPoint.plot_point_id, title, plotPoint.hashed_title, summary, plotPoint.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
if (!plotPoint.linked_incident_id) {
|
|
return false;
|
|
}
|
|
const created: boolean = BookRepo.insertSyncPlotPoint(plotPoint.plot_point_id, title, plotPoint.hashed_title, summary, plotPoint.linked_incident_id, plotPoint.author_id, bookId, plotPoint.last_update,lang);
|
|
if (!created) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (incidents && incidents.length > 0) {
|
|
for (const incident of incidents) {
|
|
const title: string = System.encryptDataWithUserKey(incident.title, userKey);
|
|
const summary: string = System.encryptDataWithUserKey(incident.summary ? incident.summary : '', userKey);
|
|
const isExist: boolean = BookRepo.incidentExist(userId, bookId, incident.incident_id,lang);
|
|
if (isExist) {
|
|
const updated: boolean = BookRepo.updateIncident(userId, bookId, incident.incident_id, title, incident.hashed_title, summary, incident.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const created: boolean = BookRepo.insertSyncIncident(incident.incident_id, userId, bookId, title, incident.hashed_title, summary, incident.last_update,lang);
|
|
if (!created) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chapterContents && chapterContents.length > 0) {
|
|
for (const chapterContent of chapterContents) {
|
|
const isExist: boolean = ChapterRepo.isChapterContentExist(userId, chapterContent.content_id, lang);
|
|
const content: string = System.encryptDataWithUserKey(chapterContent.content ? JSON.stringify(chapterContent.content) : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = ChapterRepo.updateChapterContent(userId, chapterContent.chapter_id, chapterContent.version, content, chapterContent.words_count, chapterContent.last_update);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncChapterContent(chapterContent.content_id, chapterContent.chapter_id, userId, chapterContent.version, content, chapterContent.words_count, chapterContent.time_on_it, chapterContent.last_update, lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chapterInfos && chapterInfos.length > 0) {
|
|
for (const chapterInfo of chapterInfos) {
|
|
const isExist: boolean = ChapterRepo.isChapterInfoExist(userId, chapterInfo.chapter_id,lang);
|
|
const summary: string = System.encryptDataWithUserKey(chapterInfo.summary ? chapterInfo.summary : '', userKey);
|
|
const goal: string = System.encryptDataWithUserKey(chapterInfo.goal ? chapterInfo.goal : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = ChapterRepo.updateChapterInfos(userId, chapterInfo.chapter_id, chapterInfo.act_id, bookId, chapterInfo.incident_id, chapterInfo.plot_point_id, summary, goal, chapterInfo.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncChapterInfo(chapterInfo.chapter_info_id, chapterInfo.chapter_id, chapterInfo.act_id, chapterInfo.incident_id, chapterInfo.plot_point_id, bookId, chapterInfo.author_id, summary, goal, chapterInfo.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (characters && characters.length > 0) {
|
|
for (const character of characters) {
|
|
const isExist: boolean = CharacterRepo.isCharacterExist(userId, character.character_id,lang);
|
|
const firstName: string = System.encryptDataWithUserKey(character.first_name, userKey);
|
|
const lastName: string = System.encryptDataWithUserKey(character.last_name ? character.last_name : '', userKey);
|
|
const category: string = System.encryptDataWithUserKey(character.category, userKey);
|
|
const title: string = System.encryptDataWithUserKey(character.title ? character.title : '', userKey);
|
|
const role: string = System.encryptDataWithUserKey(character.role ? character.role : '', userKey);
|
|
const image: string = System.encryptDataWithUserKey(character.image ? character.image : '', userKey);
|
|
const biography: string = System.encryptDataWithUserKey(character.biography ? character.biography : '', userKey);
|
|
const history: string = System.encryptDataWithUserKey(character.history ? character.history : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = CharacterRepo.updateCharacter(userId, character.character_id, firstName, lastName, title, category, image, role, biography, history, character.last_update);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncCharacter(character.character_id, bookId, userId, firstName, lastName, category, title, image, role, biography, history, character.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (characterAttributes && characterAttributes.length > 0) {
|
|
for (const characterAttribute of characterAttributes) {
|
|
const isExist: boolean = CharacterRepo.isCharacterAttributeExist(userId, characterAttribute.attr_id,lang);
|
|
const attributeName: string = System.encryptDataWithUserKey(characterAttribute.attribute_name, userKey);
|
|
const attributeValue: string = System.encryptDataWithUserKey(characterAttribute.attribute_value, userKey);
|
|
if (isExist) {
|
|
const updated: boolean = CharacterRepo.updateCharacterAttribute(userId, characterAttribute.attr_id, attributeName, attributeValue, characterAttribute.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncCharacterAttribute(characterAttribute.attr_id, characterAttribute.character_id, userId, attributeName, attributeValue, characterAttribute.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locations && locations.length > 0) {
|
|
for (const location of locations) {
|
|
const isExist: boolean = LocationRepo.isLocationExist(userId, location.loc_id,lang);
|
|
const locName: string = System.encryptDataWithUserKey(location.loc_name, userKey);
|
|
if (isExist) {
|
|
const updated: boolean = LocationRepo.updateLocationSection(userId, location.loc_id, locName, location.loc_original_name, location.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncLocation(location.loc_id, bookId, userId, locName, location.loc_original_name, location.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locationElements && locationElements.length > 0) {
|
|
for (const locationElement of locationElements) {
|
|
const isExist: boolean = LocationRepo.isLocationElementExist(userId, locationElement.element_id,lang);
|
|
const elementName: string = System.encryptDataWithUserKey(locationElement.element_name, userKey);
|
|
const elementDescription: string = System.encryptDataWithUserKey(locationElement.element_description ? locationElement.element_description : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = LocationRepo.updateLocationElement(userId, locationElement.element_id, elementName, locationElement.original_name, elementDescription, locationElement.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncLocationElement(locationElement.element_id, locationElement.location, userId, elementName, locationElement.original_name, elementDescription, locationElement.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locationSubElements && locationSubElements.length > 0) {
|
|
for (const locationSubElement of locationSubElements) {
|
|
const isExist: boolean = LocationRepo.isLocationSubElementExist(userId, locationSubElement.sub_element_id,lang);
|
|
const subElemName: string = System.encryptDataWithUserKey(locationSubElement.sub_elem_name, userKey);
|
|
const subElemDescription: string = System.encryptDataWithUserKey(locationSubElement.sub_elem_description ? locationSubElement.sub_elem_description : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = LocationRepo.updateLocationSubElement(userId, locationSubElement.sub_element_id, subElemName, locationSubElement.original_name, subElemDescription, locationSubElement.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncLocationSubElement(locationSubElement.sub_element_id, locationSubElement.element_id, userId, subElemName, locationSubElement.original_name, subElemDescription, locationSubElement.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (worlds && worlds.length > 0) {
|
|
for (const world of worlds) {
|
|
const isExist: boolean = BookRepo.worldExist(userId, bookId, world.world_id,lang);
|
|
const name: string = System.encryptDataWithUserKey(world.name, userKey);
|
|
const history: string = System.encryptDataWithUserKey(world.history ? world.history : '', userKey);
|
|
const politics: string = System.encryptDataWithUserKey(world.politics ? world.politics : '', userKey);
|
|
const economy: string = System.encryptDataWithUserKey(world.economy ? world.economy : '', userKey);
|
|
const religion: string = System.encryptDataWithUserKey(world.religion ? world.religion : '', userKey);
|
|
const languages: string = System.encryptDataWithUserKey(world.languages ? world.languages : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = BookRepo.updateWorld(userId, world.world_id, name, world.hashed_name, history, politics, economy, religion, languages, world.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncWorld(world.world_id, name, world.hashed_name, userId, bookId, history, politics, economy, religion, languages, world.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (worldElements && worldElements.length > 0) {
|
|
for (const worldElement of worldElements) {
|
|
const isExist: boolean = BookRepo.worldElementExist(userId, worldElement.world_id, worldElement.element_id,lang);
|
|
const name: string = System.encryptDataWithUserKey(worldElement.name, userKey);
|
|
const description: string = System.encryptDataWithUserKey(worldElement.description ? worldElement.description : '', userKey);
|
|
if (isExist) {
|
|
const updated: boolean = BookRepo.updateWorldElement(userId, worldElement.element_id, name, description, worldElement.last_update,lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncWorldElement(worldElement.element_id, worldElement.world_id, userId, worldElement.element_type, name, worldElement.original_name, description, worldElement.last_update,lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (issues && issues.length > 0) {
|
|
for (const issue of issues) {
|
|
const isExist: boolean = BookRepo.issueExist(userId, bookId, issue.issue_id,lang);
|
|
const name: string = System.encryptDataWithUserKey(issue.name, userKey);
|
|
if (isExist) {
|
|
const updated: boolean = BookRepo.updateIssue(userId, bookId, issue.issue_id, name, issue.hashed_issue_name, issue.last_update, lang);
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const insert: boolean = BookRepo.insertSyncIssue(issue.issue_id, userId, bookId, name, issue.hashed_issue_name, issue.last_update, lang);
|
|
if (!insert) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
} |