- Added `series-world.repo.ts` to handle database operations related to series worlds and their elements. - Implemented `series-sync.repo.ts` for managing synchronization between books and series. - Expanded `spell.ipc.ts` data models to include `seriesSpellId` for spell synchronization. - Refactored `insertSpellTag` method in `spelltag.repo.ts` for improved error handling and logic clarity.
721 lines
25 KiB
TypeScript
721 lines
25 KiB
TypeScript
import System from '../System.js';
|
|
import { getUserEncryptionKey } from '../keyManager.js';
|
|
import BookRepo, { BookQuery, BookToolsTable, EritBooksTable } from "../repositories/book.repository.js";
|
|
import { BookActSummariesTable } from "../repositories/act.repository.js";
|
|
import { BookAIGuideLineTable, BookGuideLineTable } from "../repositories/guideline.repository.js";
|
|
import ChapterRepo, {
|
|
BookChapterInfosTable,
|
|
BookChaptersTable,
|
|
ChapterBookResult
|
|
} from "../repositories/chapter.repository.js";
|
|
import { BookChapterContentTable } from "../repositories/chaptercontent.repository.js";
|
|
import {
|
|
BookCharactersAttributesTable,
|
|
BookCharactersTable
|
|
} from "../repositories/character.repository.js";
|
|
import { BookIncidentsTable } from "../repositories/incident.repository.js";
|
|
import { BookIssuesTable } from "../repositories/issue.repository.js";
|
|
import {
|
|
BookLocationTable,
|
|
LocationElementTable,
|
|
LocationSubElementTable
|
|
} from "../repositories/location.repository.js";
|
|
import { BookPlotPointsTable } from "../repositories/plotpoint.repository.js";
|
|
import { BookWorldElementsTable, BookWorldTable } from "../repositories/world.repository.js";
|
|
import { BookSpellsTable } from "../repositories/spell.repo.js";
|
|
import { BookSpellTagsTable } from "../repositories/spelltag.repo.js";
|
|
import { SyncedSpell, SyncedSpellTag } from "./Spell.js";
|
|
import { CompleteChapterContent, SyncedChapter } from "./Chapter.js";
|
|
import { SyncedCharacter } from "./Character.js";
|
|
import { SyncedLocation } from "./Location.js";
|
|
import { SyncedWorld } from "./World.js";
|
|
import { SyncedIncident } from "./Incident.js";
|
|
import { SyncedPlotPoint } from "./PlotPoint.js";
|
|
import { SyncedIssue } from "./Issue.js";
|
|
import { SyncedActSummary } from "./Act.js";
|
|
import { SyncedAIGuideLine, SyncedGuideLine } from "./GuideLine.js";
|
|
import Cover from "./Cover.js";
|
|
import UserRepo from "../repositories/user.repository.js";
|
|
|
|
export interface SyncedBookTools {
|
|
lastUpdate: number;
|
|
charactersEnabled: boolean;
|
|
worldsEnabled: boolean;
|
|
locationsEnabled: boolean;
|
|
spellsEnabled: boolean;
|
|
}
|
|
|
|
export interface BookToolsSettings {
|
|
characters: boolean;
|
|
worlds: boolean;
|
|
locations: boolean;
|
|
spells: boolean;
|
|
}
|
|
|
|
export interface BookProps {
|
|
bookId: string;
|
|
type: string;
|
|
authorId: string;
|
|
title: string;
|
|
subTitle?: string;
|
|
summary?: string;
|
|
serieId?: number | null;
|
|
seriesId?: string | null;
|
|
desiredReleaseDate?: string | null;
|
|
desiredWordCount?: number | null;
|
|
wordCount?: number;
|
|
coverImage?: string | null;
|
|
bookMeta?: string;
|
|
tools?: BookToolsSettings;
|
|
}
|
|
|
|
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[];
|
|
bookTools: BookToolsTable[];
|
|
spells: BookSpellsTable[];
|
|
spellTags: BookSpellTagsTable[];
|
|
}
|
|
|
|
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;
|
|
bookTools: SyncedBookTools | null;
|
|
spells: SyncedSpell[];
|
|
spellTags: SyncedSpellTag[];
|
|
}
|
|
|
|
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;
|
|
bookTools: boolean;
|
|
spells: string[];
|
|
spellTags: string[];
|
|
}
|
|
|
|
export interface CompleteBookData {
|
|
bookId: string;
|
|
title: string;
|
|
subTitle: string;
|
|
summary: string;
|
|
coverImage: string;
|
|
userInfos: {
|
|
firstName: string;
|
|
lastName: string;
|
|
authorName: string;
|
|
},
|
|
chapters: CompleteChapterContent[];
|
|
}
|
|
|
|
// ===== SERIES TABLE INTERFACES (for sync) =====
|
|
|
|
export interface SeriesTable {
|
|
series_id: string;
|
|
user_id: string;
|
|
name: string;
|
|
hashed_name: string;
|
|
description: string | null;
|
|
cover_image: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesBooksTable {
|
|
series_id: string;
|
|
book_id: string;
|
|
book_order: number;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesCharactersTable {
|
|
character_id: string;
|
|
series_id: string;
|
|
user_id: string;
|
|
first_name: string;
|
|
last_name: string | null;
|
|
nickname: string | null;
|
|
age: number | null;
|
|
gender: string | null;
|
|
species: string | null;
|
|
nationality: string | null;
|
|
status: string | null;
|
|
title: string | null;
|
|
category: string;
|
|
image: string | null;
|
|
role: string | null;
|
|
biography: string | null;
|
|
history: string | null;
|
|
speech_pattern: string | null;
|
|
catchphrase: string | null;
|
|
residence: string | null;
|
|
notes: string | null;
|
|
color: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesCharacterAttributesTable {
|
|
attr_id: string;
|
|
character_id: string;
|
|
user_id: string;
|
|
attribute_name: string;
|
|
attribute_value: string;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesWorldsTable {
|
|
world_id: string;
|
|
series_id: string;
|
|
user_id: string;
|
|
name: string;
|
|
hashed_name: string;
|
|
history: string | null;
|
|
politics: string | null;
|
|
economy: string | null;
|
|
religion: string | null;
|
|
languages: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesWorldElementsTable {
|
|
element_id: string;
|
|
world_id: string;
|
|
user_id: string;
|
|
element_type: number;
|
|
name: string;
|
|
original_name: string;
|
|
description: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesLocationsTable {
|
|
loc_id: string;
|
|
series_id: string;
|
|
user_id: string;
|
|
loc_name: string;
|
|
loc_original_name: string;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesLocationElementsTable {
|
|
element_id: string;
|
|
location_id: string;
|
|
user_id: string;
|
|
element_name: string;
|
|
original_name: string;
|
|
element_description: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesLocationSubElementsTable {
|
|
sub_element_id: string;
|
|
element_id: string;
|
|
user_id: string;
|
|
sub_elem_name: string;
|
|
original_name: string;
|
|
sub_elem_description: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesSpellsTable {
|
|
spell_id: string;
|
|
series_id: string;
|
|
user_id: string;
|
|
name: string;
|
|
name_hash: string;
|
|
description: string;
|
|
appearance: string;
|
|
tags: string;
|
|
power_level: string | null;
|
|
components: string | null;
|
|
limitations: string | null;
|
|
notes: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface SeriesSpellTagsTable {
|
|
tag_id: string;
|
|
series_id: string;
|
|
user_id: string;
|
|
name: string;
|
|
hashed_name: string;
|
|
color: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
// ===== COMPLETE SERIES INTERFACE (for full sync) =====
|
|
|
|
export interface CompleteSeries {
|
|
series: SeriesTable[];
|
|
seriesBooks: SeriesBooksTable[];
|
|
seriesCharacters: SeriesCharactersTable[];
|
|
seriesCharacterAttributes: SeriesCharacterAttributesTable[];
|
|
seriesWorlds: SeriesWorldsTable[];
|
|
seriesWorldElements: SeriesWorldElementsTable[];
|
|
seriesLocations: SeriesLocationsTable[];
|
|
seriesLocationElements: SeriesLocationElementsTable[];
|
|
seriesLocationSubElements: SeriesLocationSubElementsTable[];
|
|
seriesSpells: SeriesSpellsTable[];
|
|
seriesSpellTags: SeriesSpellTagsTable[];
|
|
}
|
|
|
|
// ===== SYNCED SERIES INTERFACES (lightweight, for comparison) =====
|
|
|
|
export interface SyncedSeriesBook {
|
|
bookId: string;
|
|
order: number;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedSeriesCharacterAttribute {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedSeriesCharacter {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
attributes: SyncedSeriesCharacterAttribute[];
|
|
}
|
|
|
|
export interface SyncedSeriesWorldElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedSeriesWorld {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
elements: SyncedSeriesWorldElement[];
|
|
}
|
|
|
|
export interface SyncedSeriesLocationSubElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedSeriesLocationElement {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
subElements: SyncedSeriesLocationSubElement[];
|
|
}
|
|
|
|
export interface SyncedSeriesLocation {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
elements: SyncedSeriesLocationElement[];
|
|
}
|
|
|
|
export interface SyncedSeriesSpell {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedSeriesSpellTag {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
}
|
|
|
|
export interface SyncedSeries {
|
|
id: string;
|
|
name: string;
|
|
lastUpdate: number;
|
|
books: SyncedSeriesBook[];
|
|
characters: SyncedSeriesCharacter[];
|
|
worlds: SyncedSeriesWorld[];
|
|
locations: SyncedSeriesLocation[];
|
|
spells: SyncedSeriesSpell[];
|
|
spellTags: SyncedSeriesSpellTag[];
|
|
}
|
|
|
|
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;
|
|
|
|
/**
|
|
* Creates a new Book instance.
|
|
* @param id - The unique identifier of the book
|
|
* @param authorId - The unique identifier of the author (optional)
|
|
*/
|
|
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 = '';
|
|
}
|
|
|
|
/**
|
|
* Retrieves all books for a specific user.
|
|
* @param userId - The unique identifier of the user
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
* @returns A promise resolving to an array of book properties
|
|
* @throws Error if the user encryption key is not found
|
|
*/
|
|
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[] = BookRepo.fetchBooks(userId, lang);
|
|
if (!books || books.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
return await Promise.all(
|
|
books.map(async (book: BookQuery): Promise<BookProps> => {
|
|
return {
|
|
bookId: 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 ? Cover.getPicture(userId, userKey, book.cover_image) : '',
|
|
};
|
|
}) ?? []
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Adds a new book to the database.
|
|
* @param bookId - The unique identifier for the book (optional, will be generated if null)
|
|
* @param userId - The unique identifier of the user
|
|
* @param title - The title of the book
|
|
* @param subTitle - The subtitle of the book
|
|
* @param summary - The summary of the book
|
|
* @param type - The type/genre of the book
|
|
* @param serie - The series identifier
|
|
* @param publicationDate - The desired publication date
|
|
* @param desiredWordCount - The target word count
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
* @returns A promise resolving to the book ID
|
|
* @throws Error if a book with the same title already exists
|
|
*/
|
|
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 newBookId: 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) {
|
|
newBookId = bookId;
|
|
} else {
|
|
newBookId = System.createUniqueId();
|
|
}
|
|
return BookRepo.insertBook(newBookId, userId, encryptedTitle, hashedTitle, encryptedSubTitle, hashedSubTitle, encryptedSummary, type, serie, publicationDate, desiredWordCount, lang);
|
|
}
|
|
|
|
/**
|
|
* Retrieves a single book by its ID.
|
|
* @param userId - The unique identifier of the user
|
|
* @param bookId - The unique identifier of the book
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
* @returns A promise resolving to the book properties
|
|
*/
|
|
public static async getBook(userId: string, bookId: string, lang: 'fr' | 'en'): Promise<BookProps> {
|
|
const book: Book = new Book(bookId);
|
|
book.getBookInfos(userId);
|
|
const bookTools: BookToolsTable | null = BookRepo.fetchBookTools(userId, bookId, lang);
|
|
return {
|
|
bookId: 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(),
|
|
tools: {
|
|
characters: bookTools ? bookTools.characters_enabled === 1 : false,
|
|
worlds: bookTools ? bookTools.worlds_enabled === 1 : false,
|
|
locations: bookTools ? bookTools.locations_enabled === 1 : false,
|
|
spells: bookTools ? bookTools.spells_enabled === 1 : false
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Updates basic information for a book.
|
|
* @param userId - The unique identifier of the user
|
|
* @param title - The new title
|
|
* @param subTitle - The new subtitle
|
|
* @param summary - The new summary
|
|
* @param publicationDate - The new publication date
|
|
* @param wordCount - The new word count
|
|
* @param bookId - The unique identifier of the book
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
* @returns True if the update was successful, false otherwise
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* Removes a book from the database.
|
|
* @param userId - The unique identifier of the user
|
|
* @param bookId - The unique identifier of the book to remove
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
* @returns True if the book was removed, false otherwise
|
|
*/
|
|
public static removeBook(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
return BookRepo.deleteBook(userId, bookId, lang);
|
|
}
|
|
|
|
public static updateBookToolSetting(userId: string, bookId: string, toolName: 'characters' | 'worlds' | 'locations' | 'spells', enabled: boolean, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
const columnName: 'characters_enabled' | 'worlds_enabled' | 'locations_enabled' | 'spells_enabled' = `${toolName}_enabled` as 'characters_enabled' | 'worlds_enabled' | 'locations_enabled' | 'spells_enabled';
|
|
return BookRepo.updateBookToolSetting(userId, bookId, columnName, enabled, System.timeStampInSeconds(), lang);
|
|
}
|
|
|
|
/**
|
|
* Gets the book ID.
|
|
* @returns The book's unique identifier
|
|
*/
|
|
public getId(): string {
|
|
return this.id;
|
|
}
|
|
|
|
/**
|
|
* Gets the author ID.
|
|
* @returns The author's unique identifier
|
|
*/
|
|
public getAuthorId(): string {
|
|
return this.authorId;
|
|
}
|
|
|
|
/**
|
|
* Gets the book title.
|
|
* @returns The decrypted book title
|
|
*/
|
|
public getTitle(): string {
|
|
return this.title;
|
|
}
|
|
|
|
/**
|
|
* Gets the book subtitle.
|
|
* @returns The decrypted book subtitle
|
|
*/
|
|
public getSubTitle(): string {
|
|
return this.subTitle;
|
|
}
|
|
|
|
/**
|
|
* Gets the book summary.
|
|
* @returns The decrypted book summary
|
|
*/
|
|
public getSummary(): string {
|
|
return this.summary;
|
|
}
|
|
|
|
/**
|
|
* Gets the series ID.
|
|
* @returns The series identifier
|
|
*/
|
|
public getSerieId(): number {
|
|
return this.serieId;
|
|
}
|
|
|
|
/**
|
|
* Gets the desired release date.
|
|
* @returns The desired release date string
|
|
*/
|
|
public getDesiredReleaseDate(): string {
|
|
return this.desiredReleaseDate;
|
|
}
|
|
|
|
/**
|
|
* Gets the desired word count.
|
|
* @returns The target word count
|
|
*/
|
|
public getDesiredWordCount(): number {
|
|
return this.desiredWordCount;
|
|
}
|
|
|
|
/**
|
|
* Gets the current word count.
|
|
* @returns The current word count
|
|
*/
|
|
public getWordCount(): number {
|
|
return this.wordCount;
|
|
}
|
|
|
|
/**
|
|
* Gets the cover image.
|
|
* @returns The cover image data
|
|
*/
|
|
public getCover(): string {
|
|
return this.cover;
|
|
}
|
|
|
|
/**
|
|
* Gets the book type.
|
|
* @returns The book type/genre
|
|
*/
|
|
public getType(): string {
|
|
return this.type;
|
|
}
|
|
|
|
/**
|
|
* Retrieves complete book data including chapters and user information.
|
|
* @param userId - The unique identifier of the user
|
|
* @param id - The unique identifier of the book
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
* @returns The complete book data with decrypted content
|
|
*/
|
|
static completeBookData(userId: string, id: string, lang: 'fr' | 'en' = 'fr'): CompleteBookData {
|
|
const bookData: BookQuery = BookRepo.fetchBook(id, userId, lang);
|
|
const chapters: ChapterBookResult[] = ChapterRepo.fetchCompleteBookChapters(id, lang);
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
const userInfos = UserRepo.fetchAccountInformation(userId, lang);
|
|
|
|
const bookTitle: string = bookData.title ? System.decryptDataWithUserKey(bookData.title, userKey) : '';
|
|
const decryptedChapters: CompleteChapterContent[] = [];
|
|
|
|
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 = bookData.cover_image ? Cover.getPicture(userId, userKey, bookData.cover_image, lang) : '';
|
|
return {
|
|
bookId: id,
|
|
title: bookTitle,
|
|
subTitle: bookData.sub_title ? System.decryptDataWithUserKey(bookData.sub_title, userKey) : '',
|
|
summary: bookData.summary ? System.decryptDataWithUserKey(bookData.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
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Loads book information from the database into the instance.
|
|
* @param userId - The unique identifier of the user
|
|
* @param lang - The language for error messages ('fr' or 'en')
|
|
*/
|
|
public getBookInfos(userId: string, lang: 'fr' | 'en' = 'fr'): void {
|
|
const bookData: BookQuery = BookRepo.fetchBook(this.id, userId, lang);
|
|
const userKey: string = getUserEncryptionKey(userId);
|
|
if (bookData) {
|
|
this.authorId = bookData.author_id;
|
|
this.type = bookData.type;
|
|
this.title = bookData.title ? System.decryptDataWithUserKey(bookData.title, userKey) : '';
|
|
this.subTitle = bookData.sub_title ? System.decryptDataWithUserKey(bookData.sub_title, userKey) : '';
|
|
this.summary = bookData.summary ? System.decryptDataWithUserKey(bookData.summary, userKey) : '';
|
|
this.serieId = bookData.serie_id ?? 0;
|
|
this.desiredReleaseDate = bookData.desired_release_date ?? '';
|
|
this.desiredWordCount = bookData.desired_word_count ?? 0;
|
|
this.wordCount = bookData.words_count ?? 0;
|
|
this.cover = bookData.cover_image ? Cover.getPicture(userId, userKey, bookData.cover_image, lang) : '';
|
|
} else {
|
|
this.authorId = '';
|
|
this.title = '';
|
|
this.subTitle = '';
|
|
this.summary = '';
|
|
this.serieId = 0;
|
|
this.desiredReleaseDate = '';
|
|
this.wordCount = 0;
|
|
this.cover = '';
|
|
}
|
|
}
|
|
}
|