Files
ERitors-Scribe-Desktop/electron/database/models/SeriesCharacter.ts
natreex 209dc6f85a Remove CharacterComponent and CharacterDetail components
- Deleted `CharacterComponent` and `CharacterDetail` files from the project.
- Refactored related logic to improve code maintainability and reduce redundancy.
2026-02-05 14:12:08 -05:00

288 lines
17 KiB
TypeScript

import { getUserEncryptionKey } from "../keyManager.js";
import System from "../System.js";
import SeriesCharacterRepo, { SeriesCharacterAttributeResult, SeriesCharacterResult } from "../repositories/series-character.repo.js";
import RemovedItem from "./RemovedItem.js";
export type CharacterCategory = 'Main' | 'Secondary' | 'Recurring';
export interface SeriesCharacterPropsPost {
id: string | null;
name: string;
lastName: string;
nickname: string;
age: number | null;
gender: string;
species: string;
nationality: string;
status: string;
category: CharacterCategory;
title: string;
image: string;
physical: { name: string }[];
psychological: { name: string }[];
relations: { name: string }[];
skills: { name: string }[];
weaknesses: { name: string }[];
strengths: { name: string }[];
goals: { name: string }[];
motivations: { name: string }[];
arc: { name: string }[];
secrets: { name: string }[];
fears: { name: string }[];
flaws: { name: string }[];
beliefs: { name: string }[];
conflicts: { name: string }[];
quotes: { name: string }[];
distinguishingMarks: { name: string }[];
items: { name: string }[];
affiliations: { name: string }[];
role: string;
biography?: string;
history?: string;
speechPattern?: string;
catchphrase?: string;
residence?: string;
notes?: string;
color?: string;
}
export interface SeriesCharacterListProps {
id: string;
name: string;
lastName: string;
nickname: string;
age: number | null;
gender: string;
species: string;
nationality: string;
status: string;
title: string;
category: string;
image: string;
role: string;
biography: string;
history: string;
speechPattern: string;
catchphrase: string;
residence: string;
notes: string;
color: string;
}
export interface SeriesAttribute {
id: string;
name: string;
}
export interface CharacterAttributesResponse {
attributes: SeriesAttribute[];
}
export default class SeriesCharacter {
/**
* Retrieves a list of characters for a specific series owned by a user.
* @param userId - The unique identifier of the user
* @param seriesId - The unique identifier of the series
* @param lang - The language for error messages ('fr' or 'en')
* @returns Characters list
*/
public static getCharacterList(userId: string, seriesId: string, lang: 'fr' | 'en' = 'fr'): SeriesCharacterListProps[] {
const characters: SeriesCharacterResult[] = SeriesCharacterRepo.fetchCharacters(userId, seriesId, lang);
if (!characters || characters.length === 0) {
return [];
}
const userKey: string = getUserEncryptionKey(userId);
return characters.map((character: SeriesCharacterResult): SeriesCharacterListProps => ({
id: character.character_id,
name: character.first_name ? System.decryptDataWithUserKey(character.first_name, userKey) : '',
lastName: character.last_name ? System.decryptDataWithUserKey(character.last_name, userKey) : '',
nickname: character.nickname ? System.decryptDataWithUserKey(character.nickname, userKey) : '',
age: character.age ? parseInt(System.decryptDataWithUserKey(character.age, userKey), 10) : null,
gender: character.gender ? System.decryptDataWithUserKey(character.gender, userKey) : '',
species: character.species ? System.decryptDataWithUserKey(character.species, userKey) : '',
nationality: character.nationality ? System.decryptDataWithUserKey(character.nationality, userKey) : '',
status: character.status ? System.decryptDataWithUserKey(character.status, userKey) : 'alive',
title: character.title ? System.decryptDataWithUserKey(character.title, userKey) : '',
category: character.category ? System.decryptDataWithUserKey(character.category, userKey) : '',
image: character.image ? System.decryptDataWithUserKey(character.image, userKey) : '',
role: character.role ? System.decryptDataWithUserKey(character.role, userKey) : '',
biography: character.biography ? System.decryptDataWithUserKey(character.biography, userKey) : '',
history: character.history ? System.decryptDataWithUserKey(character.history, userKey) : '',
speechPattern: character.speech_pattern ? System.decryptDataWithUserKey(character.speech_pattern, userKey) : '',
catchphrase: character.catchphrase ? System.decryptDataWithUserKey(character.catchphrase, userKey) : '',
residence: character.residence ? System.decryptDataWithUserKey(character.residence, userKey) : '',
notes: character.notes ? System.decryptDataWithUserKey(character.notes, userKey) : '',
color: character.color ? System.decryptDataWithUserKey(character.color, userKey) : '',
}));
}
/**
* Adds a new character to a series with all its attributes.
* @param userId - The unique identifier of the user
* @param character - The character data to create
* @param seriesId - The unique identifier of the series
* @param lang - The language for error messages ('fr' or 'en')
* @returns The newly created character's ID
*/
public static addNewCharacter(userId: string, character: SeriesCharacterPropsPost, seriesId: string, lang: 'fr' | 'en' = 'fr'): string {
const userKey: string = getUserEncryptionKey(userId);
const characterId: string = System.createUniqueId();
const encryptedName: string = System.encryptDataWithUserKey(character.name, userKey);
const encryptedLastName: string | null = character.lastName ? System.encryptDataWithUserKey(character.lastName, userKey) : null;
const encryptedNickname: string | null = character.nickname ? System.encryptDataWithUserKey(character.nickname, userKey) : null;
const encryptedAge: string | null = character.age !== null ? System.encryptDataWithUserKey(String(character.age), userKey) : null;
const encryptedGender: string | null = character.gender ? System.encryptDataWithUserKey(character.gender, userKey) : null;
const encryptedSpecies: string | null = character.species ? System.encryptDataWithUserKey(character.species, userKey) : null;
const encryptedNationality: string | null = character.nationality ? System.encryptDataWithUserKey(character.nationality, userKey) : null;
const encryptedStatus: string | null = character.status ? System.encryptDataWithUserKey(character.status, userKey) : null;
const encryptedTitle: string | null = character.title ? System.encryptDataWithUserKey(character.title, userKey) : null;
const encryptedCategory: string | null = character.category ? System.encryptDataWithUserKey(character.category, 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 encryptedHistory: string | null = character.history ? System.encryptDataWithUserKey(character.history, userKey) : null;
const encryptedSpeechPattern: string | null = character.speechPattern ? System.encryptDataWithUserKey(character.speechPattern, userKey) : null;
const encryptedCatchphrase: string | null = character.catchphrase ? System.encryptDataWithUserKey(character.catchphrase, userKey) : null;
const encryptedResidence: string | null = character.residence ? System.encryptDataWithUserKey(character.residence, userKey) : null;
const encryptedNotes: string | null = character.notes ? System.encryptDataWithUserKey(character.notes, userKey) : null;
const encryptedColor: string | null = character.color ? System.encryptDataWithUserKey(character.color, userKey) : null;
SeriesCharacterRepo.addNewCharacter(userId, characterId, encryptedName, encryptedLastName, encryptedNickname, encryptedAge, encryptedGender, encryptedSpecies, encryptedNationality, encryptedStatus, encryptedTitle, encryptedCategory, encryptedImage, encryptedRole, encryptedBiography, encryptedHistory, encryptedSpeechPattern, encryptedCatchphrase, encryptedResidence, encryptedNotes, encryptedColor, seriesId, lang);
const attributeKeys: string[] = Object.keys(character);
for (const attributeKey of attributeKeys) {
const attributeValue = character[attributeKey as keyof SeriesCharacterPropsPost];
if (Array.isArray(attributeValue)) {
const attributeArray: { name: string }[] = attributeValue;
if (attributeArray.length > 0) {
for (const attributeItem of attributeArray) {
const attributeType: string = attributeKey;
const attributeName: string = attributeItem.name;
this.addNewAttribute(characterId, userId, attributeType, attributeName, lang);
}
}
}
}
return characterId;
}
/**
* Updates an existing character's information and attributes.
* @param userId - The unique identifier of the user
* @param character - The updated character data
* @param lang - The language for error messages ('fr' or 'en')
* @returns True if the update was successful
*/
public static updateCharacter(userId: string, character: SeriesCharacterPropsPost, lang: 'fr' | 'en' = 'fr'): boolean {
if (!character.id) {
throw new Error(lang === 'fr' ? 'ID du personnage requis.' : 'Character ID required.');
}
const exists: boolean = SeriesCharacterRepo.isCharacterExist(userId, character.id, lang);
if (!exists) {
throw new Error(lang === 'fr' ? 'Personnage non trouvé.' : 'Character not found.');
}
const userKey: string = getUserEncryptionKey(userId);
const encryptedName: string = System.encryptDataWithUserKey(character.name, userKey);
const encryptedLastName: string | null = character.lastName ? System.encryptDataWithUserKey(character.lastName, userKey) : null;
const encryptedNickname: string | null = character.nickname ? System.encryptDataWithUserKey(character.nickname, userKey) : null;
const encryptedAge: string | null = character.age !== null ? System.encryptDataWithUserKey(String(character.age), userKey) : null;
const encryptedGender: string | null = character.gender ? System.encryptDataWithUserKey(character.gender, userKey) : null;
const encryptedSpecies: string | null = character.species ? System.encryptDataWithUserKey(character.species, userKey) : null;
const encryptedNationality: string | null = character.nationality ? System.encryptDataWithUserKey(character.nationality, userKey) : null;
const encryptedStatus: string | null = character.status ? System.encryptDataWithUserKey(character.status, userKey) : null;
const encryptedTitle: string | null = character.title ? System.encryptDataWithUserKey(character.title, userKey) : null;
const encryptedCategory: string | null = character.category ? System.encryptDataWithUserKey(character.category, 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 encryptedHistory: string | null = character.history ? System.encryptDataWithUserKey(character.history, userKey) : null;
const encryptedSpeechPattern: string | null = character.speechPattern ? System.encryptDataWithUserKey(character.speechPattern, userKey) : null;
const encryptedCatchphrase: string | null = character.catchphrase ? System.encryptDataWithUserKey(character.catchphrase, userKey) : null;
const encryptedResidence: string | null = character.residence ? System.encryptDataWithUserKey(character.residence, userKey) : null;
const encryptedNotes: string | null = character.notes ? System.encryptDataWithUserKey(character.notes, userKey) : null;
const encryptedColor: string | null = character.color ? System.encryptDataWithUserKey(character.color, userKey) : null;
return SeriesCharacterRepo.updateCharacter(userId, character.id, encryptedName, encryptedLastName, encryptedNickname, encryptedAge, encryptedGender, encryptedSpecies, encryptedNationality, encryptedStatus, encryptedTitle, encryptedCategory, encryptedImage, encryptedRole, encryptedBiography, encryptedHistory, encryptedSpeechPattern, encryptedCatchphrase, encryptedResidence, encryptedNotes, encryptedColor, lang);
}
/**
* Deletes a character from a series.
* @param userId - The unique identifier of the user
* @param characterId - The unique identifier of the character
* @param deletedAt - The timestamp of deletion
* @param lang - The language for error messages ('fr' or 'en')
* @returns True if the deletion was successful
*/
public static deleteCharacter(userId: string, characterId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean {
const exists: boolean = SeriesCharacterRepo.isCharacterExist(userId, characterId, lang);
if (!exists) {
throw new Error(lang === 'fr' ? 'Personnage non trouvé.' : 'Character not found.');
}
const deleted: boolean = SeriesCharacterRepo.deleteCharacter(userId, characterId, lang);
if (deleted) {
RemovedItem.deleteTracker(userId, null, 'series_characters', characterId, deletedAt, lang);
}
return deleted;
}
/**
* Adds a new attribute to a character.
* @param characterId - The unique identifier of the character
* @param userId - The unique identifier of the user
* @param type - The attribute type
* @param name - The attribute value
* @param lang - The language for error messages ('fr' or 'en')
* @returns The attribute ID
*/
public static addNewAttribute(characterId: string, userId: string, type: string, name: string, lang: 'fr' | 'en' = 'fr'): string {
const userKey: string = getUserEncryptionKey(userId);
const attributeId: string = System.createUniqueId();
const encryptedType: string = System.encryptDataWithUserKey(type, userKey);
const encryptedName: string = System.encryptDataWithUserKey(name, userKey);
SeriesCharacterRepo.insertAttribute(attributeId, characterId, userId, encryptedType, encryptedName, lang);
return attributeId;
}
/**
* Deletes an attribute from a character.
* @param userId - The unique identifier of the user
* @param attributeId - The unique identifier of the attribute
* @param deletedAt - The timestamp of deletion
* @param lang - The language for error messages ('fr' or 'en')
* @returns True if the deletion was successful
*/
public static deleteAttribute(userId: string, attributeId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr'): boolean {
const deleted: boolean = SeriesCharacterRepo.deleteAttribute(userId, attributeId, lang);
if (deleted) {
RemovedItem.deleteTracker(userId, null, 'series_characters_attributes', attributeId, deletedAt, lang);
}
return deleted;
}
/**
* Gets all attributes for a character.
* @param userId - The unique identifier of the user
* @param characterId - The unique identifier of the character
* @param lang - The language for error messages ('fr' or 'en')
* @returns The character's attributes
*/
public static getCharacterAttributes(userId: string, characterId: string, lang: 'fr' | 'en' = 'fr'): CharacterAttributesResponse {
const userKey: string = getUserEncryptionKey(userId);
const attributesResult: SeriesCharacterAttributeResult[] = SeriesCharacterRepo.fetchAttributes(characterId, userId, lang);
const attributes: SeriesAttribute[] = attributesResult.map((attr) => ({
id: attr.attr_id,
name: System.decryptDataWithUserKey(attr.attribute_value, userKey)
}));
return { attributes };
}
}