import { getUserEncryptionKey } from "../keyManager.js"; import System from "../System.js"; import IssueRepository, { IssueQuery } from "../repositories/issue.repository.js"; import RemovedItem from "./RemovedItem.js"; /** * Represents a synced issue with its metadata. */ export interface SyncedIssue { id: string; name: string; lastUpdate: number; } /** * Represents the basic properties of an issue. */ export interface IssueProps { id: string; name: string; } /** * Model class for managing issues associated with books. * Provides methods for CRUD operations on issues with encryption support. */ export default class Issue { /** * Retrieves all issues associated with a specific book. * Decrypts issue names using the user's encryption key. * * @param userId - The unique identifier of the user. * @param bookId - The unique identifier of the book. * @param lang - The language for error messages ('fr' or 'en'). Defaults to 'fr'. * @returns A promise resolving to an array of decrypted issues. */ public static async getIssuesFromBook( userId: string, bookId: string, lang: 'fr' | 'en' = 'fr' ): Promise { const issueQueryResults: IssueQuery[] = IssueRepository.fetchIssuesFromBook(userId, bookId, lang); const userEncryptionKey: string = getUserEncryptionKey(userId); const decryptedIssues: IssueProps[] = []; if (issueQueryResults.length > 0) { for (const issueRecord of issueQueryResults) { decryptedIssues.push({ id: issueRecord.issue_id, name: System.decryptDataWithUserKey(issueRecord.name, userEncryptionKey) }); } } return decryptedIssues; } /** * Creates a new issue for a book. * Encrypts and hashes the issue name before storage. * * @param userId - The unique identifier of the user. * @param bookId - The unique identifier of the book. * @param name - The plain text name of the issue. * @param lang - The language for error messages ('fr' or 'en'). Defaults to 'fr'. * @param existingIssueId - Optional existing issue ID for syncing purposes. * @returns The unique identifier of the created issue. */ public static addNewIssue( userId: string, bookId: string, name: string, lang: 'fr' | 'en' = 'fr', existingIssueId?: string ): string { const userEncryptionKey: string = getUserEncryptionKey(userId); const encryptedName: string = System.encryptDataWithUserKey(name, userEncryptionKey); const hashedName: string = System.hashElement(name); const issueId: string = existingIssueId || System.createUniqueId(); return IssueRepository.insertNewIssue(issueId, userId, bookId, encryptedName, hashedName, lang); } /** * Removes an issue from the database. * * @param userId - The unique identifier of the user. * @param bookId - The unique identifier of the book. * @param issueId - The unique identifier of the issue to remove. * @param deletedAt - The timestamp of deletion. * @param lang - The language for error messages ('fr' or 'en'). Defaults to 'fr'. * @returns True if the issue was successfully removed, false otherwise. */ public static removeIssue( userId: string, bookId: string, issueId: string, deletedAt: number = System.timeStampInSeconds(), lang: 'fr' | 'en' = 'fr' ): boolean { const deleted: boolean = IssueRepository.deleteIssue(userId, issueId, lang); if (deleted) { RemovedItem.deleteTracker(userId, bookId, 'book_issues', issueId, deletedAt, lang); } return deleted; } }