diff --git a/components/book/settings/quillsense/QuillSenseSetting.tsx b/components/book/settings/quillsense/QuillSenseSetting.tsx
index 2412813..607bcf0 100644
--- a/components/book/settings/quillsense/QuillSenseSetting.tsx
+++ b/components/book/settings/quillsense/QuillSenseSetting.tsx
@@ -66,13 +66,13 @@ const QuillSenseSetting = forwardRef(function QuillSenseSetting(props, ref) {
lang
);
if (updateResult) {
- successMessage(t('quillsenseSetting.saveSuccess'));
+ successMessage(t('quillSenseSetting.successSave'));
// Mettre a jour le contexte du livre
if (setBook && book) {
setBook({...book, quillsenseEnabled: quillsenseEnabled});
}
} else {
- errorMessage(t('quillsenseSetting.saveError'));
+ errorMessage(t('quillSenseSetting.errorSave'));
}
} catch (e: unknown) {
if (e instanceof Error) {
@@ -94,7 +94,7 @@ const QuillSenseSetting = forwardRef(function QuillSenseSetting(props, ref) {
- {t('quillsenseSetting.enableDescription')}
+ {t('quillSenseSetting.enableDescription')}
): void => setAdvancedPrompt(e.target.value)}
- placeholder={t('quillsenseSetting.advancedPromptPlaceholder')}
+ placeholder={t('quillSenseSetting.advancedPromptPlaceholder')}
/>
}
/>
- {t('quillsenseSetting.advancedPromptDescription')}
+ {t('quillSenseSetting.advancedPromptHint')}
diff --git a/electron/database/models/Act.ts b/electron/database/models/Act.ts
index dd9cdb6..07fb590 100644
--- a/electron/database/models/Act.ts
+++ b/electron/database/models/Act.ts
@@ -174,10 +174,8 @@ export default class Act {
for (const chapter of mainChapters) {
const chapterId: string = chapter.chapterId;
const chapterTitle: string = chapter.title;
- const hashedChapterTitle: string = System.hashElement(chapterTitle);
- const encryptedChapterTitle: string = System.encryptDataWithUserKey(chapterTitle, userEncryptionKey);
const chapterOrder: number = chapter.chapterOrder;
- ChapterRepo.updateChapter(userId, chapterId, encryptedChapterTitle, hashedChapterTitle, chapterOrder, System.timeStampInSeconds(), lang);
+ Chapter.updateChapter(userId, chapterId, chapterTitle, chapterOrder, lang);
}
return true;
diff --git a/electron/database/models/GuideLine.ts b/electron/database/models/GuideLine.ts
index 9fe01c2..84eb4a1 100644
--- a/electron/database/models/GuideLine.ts
+++ b/electron/database/models/GuideLine.ts
@@ -120,6 +120,7 @@ export default class GuideLine {
encryptedPacing,
encryptedKeyMessages,
encryptedIntendedAudience,
+ System.timeStampInSeconds(),
lang
);
}
@@ -210,6 +211,7 @@ export default class GuideLine {
verbTense,
language,
encryptedThemes,
+ System.timeStampInSeconds(),
lang
);
}
diff --git a/electron/database/models/Sync.ts b/electron/database/models/Sync.ts
index fc0f0e2..88625dc 100644
--- a/electron/database/models/Sync.ts
+++ b/electron/database/models/Sync.ts
@@ -303,6 +303,41 @@ export default class Sync {
}
}
+ if (syncCompareData.guideLine) {
+ const guidelineResults: BookGuideLineTable[] = await GuidelineRepo.fetchBookGuideLineTable(userId, syncCompareData.id, lang);
+ if (guidelineResults.length > 0) {
+ const guidelineRecord: BookGuideLineTable = guidelineResults[0];
+ decryptedGuideLines.push({
+ ...guidelineRecord,
+ tone: guidelineRecord.tone ? System.decryptDataWithUserKey(guidelineRecord.tone, userEncryptionKey) : null,
+ atmosphere: guidelineRecord.atmosphere ? System.decryptDataWithUserKey(guidelineRecord.atmosphere, userEncryptionKey) : null,
+ writing_style: guidelineRecord.writing_style ? System.decryptDataWithUserKey(guidelineRecord.writing_style, userEncryptionKey) : null,
+ themes: guidelineRecord.themes ? System.decryptDataWithUserKey(guidelineRecord.themes, userEncryptionKey) : null,
+ symbolism: guidelineRecord.symbolism ? System.decryptDataWithUserKey(guidelineRecord.symbolism, userEncryptionKey) : null,
+ motifs: guidelineRecord.motifs ? System.decryptDataWithUserKey(guidelineRecord.motifs, userEncryptionKey) : null,
+ narrative_voice: guidelineRecord.narrative_voice ? System.decryptDataWithUserKey(guidelineRecord.narrative_voice, userEncryptionKey) : null,
+ pacing: guidelineRecord.pacing ? System.decryptDataWithUserKey(guidelineRecord.pacing, userEncryptionKey) : null,
+ intended_audience: guidelineRecord.intended_audience ? System.decryptDataWithUserKey(guidelineRecord.intended_audience, userEncryptionKey) : null,
+ key_messages: guidelineRecord.key_messages ? System.decryptDataWithUserKey(guidelineRecord.key_messages, userEncryptionKey) : null
+ });
+ }
+ }
+
+ if (syncCompareData.aiGuideLine) {
+ const aiGuidelineResults: BookAIGuideLineTable[] = await GuidelineRepo.fetchBookAIGuideLine(userId, syncCompareData.id, lang);
+ if (aiGuidelineResults.length > 0) {
+ const aiGuidelineRecord: BookAIGuideLineTable = aiGuidelineResults[0];
+ decryptedAIGuideLines.push({
+ ...aiGuidelineRecord,
+ global_resume: aiGuidelineRecord.global_resume ? System.decryptDataWithUserKey(aiGuidelineRecord.global_resume, userEncryptionKey) : null,
+ themes: aiGuidelineRecord.themes ? System.decryptDataWithUserKey(aiGuidelineRecord.themes, userEncryptionKey) : null,
+ tone: aiGuidelineRecord.tone ? System.decryptDataWithUserKey(aiGuidelineRecord.tone, userEncryptionKey) : null,
+ atmosphere: aiGuidelineRecord.atmosphere ? System.decryptDataWithUserKey(aiGuidelineRecord.atmosphere, userEncryptionKey) : null,
+ current_resume: aiGuidelineRecord.current_resume ? System.decryptDataWithUserKey(aiGuidelineRecord.current_resume, userEncryptionKey) : null
+ });
+ }
+ }
+
const bookResults: EritBooksTable[] = await BookRepo.fetchCompleteBookById(syncCompareData.id, lang);
if (bookResults.length > 0) {
const bookRecord: EritBooksTable = bookResults[0];
@@ -361,6 +396,8 @@ export default class Sync {
const serverWorlds: BookWorldTable[] = completeBook.worlds;
const serverWorldElements: BookWorldElementsTable[] = completeBook.worldElements;
const serverIssues: BookIssuesTable[] = completeBook.issues;
+ const serverGuideLines: BookGuideLineTable[] = completeBook.guideLine;
+ const serverAIGuideLines: BookAIGuideLineTable[] = completeBook.aiGuideLine;
const bookId: string = completeBook.eritBooks.length > 0 ? completeBook.eritBooks[0].book_id : '';
@@ -638,6 +675,55 @@ export default class Sync {
}
}
+ if (serverGuideLines && serverGuideLines.length > 0) {
+ for (const serverGuideLine of serverGuideLines) {
+ const guideLineExists: boolean = GuidelineRepo.guideLineExist(userId, bookId, lang);
+ const encryptedTone: string | null = serverGuideLine.tone ? System.encryptDataWithUserKey(serverGuideLine.tone, userEncryptionKey) : null;
+ const encryptedAtmosphere: string | null = serverGuideLine.atmosphere ? System.encryptDataWithUserKey(serverGuideLine.atmosphere, userEncryptionKey) : null;
+ const encryptedWritingStyle: string | null = serverGuideLine.writing_style ? System.encryptDataWithUserKey(serverGuideLine.writing_style, userEncryptionKey) : null;
+ const encryptedThemes: string | null = serverGuideLine.themes ? System.encryptDataWithUserKey(serverGuideLine.themes, userEncryptionKey) : null;
+ const encryptedSymbolism: string | null = serverGuideLine.symbolism ? System.encryptDataWithUserKey(serverGuideLine.symbolism, userEncryptionKey) : null;
+ const encryptedMotifs: string | null = serverGuideLine.motifs ? System.encryptDataWithUserKey(serverGuideLine.motifs, userEncryptionKey) : null;
+ const encryptedNarrativeVoice: string | null = serverGuideLine.narrative_voice ? System.encryptDataWithUserKey(serverGuideLine.narrative_voice, userEncryptionKey) : null;
+ const encryptedPacing: string | null = serverGuideLine.pacing ? System.encryptDataWithUserKey(serverGuideLine.pacing, userEncryptionKey) : null;
+ const encryptedKeyMessages: string | null = serverGuideLine.key_messages ? System.encryptDataWithUserKey(serverGuideLine.key_messages, userEncryptionKey) : null;
+ const encryptedIntendedAudience: string | null = serverGuideLine.intended_audience ? System.encryptDataWithUserKey(serverGuideLine.intended_audience, userEncryptionKey) : null;
+ if (guideLineExists) {
+ const updateSuccessful: boolean = GuidelineRepo.updateGuideLine(userId, bookId, encryptedTone, encryptedAtmosphere, encryptedWritingStyle, encryptedThemes, encryptedSymbolism, encryptedMotifs, encryptedNarrativeVoice, encryptedPacing, encryptedKeyMessages, encryptedIntendedAudience, serverGuideLine.last_update, lang);
+ if (!updateSuccessful) {
+ return false;
+ }
+ } else {
+ const insertSuccessful: boolean = GuidelineRepo.insertSyncGuideLine(userId, bookId, encryptedTone, encryptedAtmosphere, encryptedWritingStyle, encryptedThemes, encryptedSymbolism, encryptedMotifs, encryptedNarrativeVoice, encryptedPacing, encryptedIntendedAudience, encryptedKeyMessages, serverGuideLine.last_update, lang);
+ if (!insertSuccessful) {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (serverAIGuideLines && serverAIGuideLines.length > 0) {
+ for (const serverAIGuideLine of serverAIGuideLines) {
+ const aiGuideLineExists: boolean = GuidelineRepo.aiGuideLineExist(userId, bookId, lang);
+ const encryptedGlobalResume: string | null = serverAIGuideLine.global_resume ? System.encryptDataWithUserKey(serverAIGuideLine.global_resume, userEncryptionKey) : null;
+ const encryptedThemes: string | null = serverAIGuideLine.themes ? System.encryptDataWithUserKey(serverAIGuideLine.themes, userEncryptionKey) : null;
+ const encryptedTone: string | null = serverAIGuideLine.tone ? System.encryptDataWithUserKey(serverAIGuideLine.tone, userEncryptionKey) : null;
+ const encryptedAtmosphere: string | null = serverAIGuideLine.atmosphere ? System.encryptDataWithUserKey(serverAIGuideLine.atmosphere, userEncryptionKey) : null;
+ const encryptedCurrentResume: string | null = serverAIGuideLine.current_resume ? System.encryptDataWithUserKey(serverAIGuideLine.current_resume, userEncryptionKey) : null;
+ if (aiGuideLineExists) {
+ const updateSuccessful: boolean = GuidelineRepo.insertAIGuideLine(userId, bookId, serverAIGuideLine.narrative_type, serverAIGuideLine.dialogue_type, encryptedGlobalResume, encryptedAtmosphere, serverAIGuideLine.verbe_tense, serverAIGuideLine.langue, encryptedThemes, serverAIGuideLine.last_update, lang);
+ if (!updateSuccessful) {
+ return false;
+ }
+ } else {
+ const insertSuccessful: boolean = GuidelineRepo.insertSyncAIGuideLine(userId, bookId, encryptedGlobalResume, encryptedThemes, serverAIGuideLine.verbe_tense, serverAIGuideLine.narrative_type, serverAIGuideLine.langue, serverAIGuideLine.dialogue_type, encryptedTone, encryptedAtmosphere, encryptedCurrentResume, serverAIGuideLine.last_update, lang);
+ if (!insertSuccessful) {
+ return false;
+ }
+ }
+ }
+ }
+
return true;
}
@@ -703,8 +789,8 @@ export default class Sync {
PlotPointRepository.fetchSyncedPlotPoints(userId, lang),
IssueRepository.fetchSyncedIssues(userId, lang),
ActRepository.fetchSyncedActSummaries(userId, lang),
- GuidelineRepo.fetchSyncedAIGuideLine(userId, lang),
- GuidelineRepo.fetchSyncedGuideLine(userId, lang)
+ GuidelineRepo.fetchSyncedGuideLine(userId, lang),
+ GuidelineRepo.fetchSyncedAIGuideLine(userId, lang)
]);
return allBooks.map((bookRecord: SyncedBookResult): SyncedBook => {
diff --git a/electron/database/repositories/guideline.repository.ts b/electron/database/repositories/guideline.repository.ts
index 35bf516..cb8694b 100644
--- a/electron/database/repositories/guideline.repository.ts
+++ b/electron/database/repositories/guideline.repository.ts
@@ -117,24 +117,30 @@ export default class GuidelineRepo {
* @returns True if the operation was successful
* @throws Error if the guideline cannot be updated or inserted
*/
- static updateGuideLine(
- userId: string,
- bookId: string,
- encryptedTone: string,
- encryptedAtmosphere: string,
- encryptedWritingStyle: string,
- encryptedThemes: string,
- encryptedSymbolism: string,
- encryptedMotifs: string,
- encryptedNarrativeVoice: string,
- encryptedPacing: string,
- encryptedKeyMessages: string,
- encryptedIntendedAudience: string,
- lang: 'fr' | 'en'
- ): boolean {
+ /**
+ * Updates or inserts a guideline for a specific book.
+ * If the guideline exists, it updates it; otherwise, it inserts a new one.
+ * @param userId - The user identifier
+ * @param bookId - The book identifier
+ * @param encryptedTone - The encrypted tone value
+ * @param encryptedAtmosphere - The encrypted atmosphere value
+ * @param encryptedWritingStyle - The encrypted writing style value
+ * @param encryptedThemes - The encrypted themes value
+ * @param encryptedSymbolism - The encrypted symbolism value
+ * @param encryptedMotifs - The encrypted motifs value
+ * @param encryptedNarrativeVoice - The encrypted narrative voice value
+ * @param encryptedPacing - The encrypted pacing value
+ * @param encryptedKeyMessages - The encrypted key messages value
+ * @param encryptedIntendedAudience - The encrypted intended audience value
+ * @param lastUpdate - The timestamp of the last update
+ * @param lang - The language for error messages ('fr' or 'en')
+ * @returns True if the operation was successful
+ * @throws Error if the guideline cannot be updated or inserted
+ */
+ static updateGuideLine(userId: string, bookId: string, encryptedTone: string | null, encryptedAtmosphere: string | null, encryptedWritingStyle: string | null, encryptedThemes: string | null, encryptedSymbolism: string | null, encryptedMotifs: string | null, encryptedNarrativeVoice: string | null, encryptedPacing: string | null, encryptedKeyMessages: string | null, encryptedIntendedAudience: string | null, lastUpdate: number, lang: 'fr' | 'en'): boolean {
try {
const db: Database = System.getDb();
- const updateQuery: string = 'UPDATE book_guide_line SET tone=?, atmosphere=?, writing_style=?, themes=?, symbolism=?, motifs=?, narrative_voice=?, pacing=?, key_messages=?, last_update=? WHERE user_id=? AND book_id=?';
+ const updateQuery: string = 'UPDATE book_guide_line SET tone=?, atmosphere=?, writing_style=?, themes=?, symbolism=?, motifs=?, narrative_voice=?, pacing=?, intended_audience=?, key_messages=?, last_update=? WHERE user_id=? AND book_id=?';
const updateParams: SQLiteValue[] = [
encryptedTone,
encryptedAtmosphere,
@@ -144,8 +150,9 @@ export default class GuidelineRepo {
encryptedMotifs,
encryptedNarrativeVoice,
encryptedPacing,
+ encryptedIntendedAudience,
encryptedKeyMessages,
- System.timeStampInSeconds(),
+ lastUpdate,
userId,
bookId
];
@@ -168,7 +175,7 @@ export default class GuidelineRepo {
encryptedPacing,
encryptedIntendedAudience,
encryptedKeyMessages,
- System.timeStampInSeconds()
+ lastUpdate
];
const insertResult: RunResult = db.run(insertQuery, insertParams);
return insertResult.changes > 0;
@@ -196,34 +203,24 @@ export default class GuidelineRepo {
* @param verbTense - The verb tense identifier
* @param language - The language identifier
* @param encryptedThemes - The encrypted themes value
+ * @param lastUpdate - The timestamp of the last update
* @param lang - The language for error messages ('fr' or 'en')
* @returns True if the operation was successful
* @throws Error if the AI guideline cannot be inserted or updated
*/
- static insertAIGuideLine(
- userId: string,
- bookId: string,
- narrativeType: number,
- dialogueType: number,
- encryptedPlotSummary: string,
- encryptedToneAtmosphere: string,
- verbTense: number,
- language: number,
- encryptedThemes: string,
- lang: 'fr' | 'en'
- ): boolean {
+ static insertAIGuideLine(userId: string, bookId: string, narrativeType: number | null, dialogueType: number | null, encryptedPlotSummary: string | null, encryptedToneAtmosphere: string | null, verbTense: number | null, language: number | null, encryptedThemes: string | null, lastUpdate: number, lang: 'fr' | 'en'): boolean {
try {
const db: Database = System.getDb();
const updateQuery: string = 'UPDATE book_ai_guide_line SET narrative_type=?, dialogue_type=?, global_resume=?, atmosphere=?, verbe_tense=?, langue=?, themes=?, last_update=? WHERE user_id=? AND book_id=?';
const updateParams: SQLiteValue[] = [
- narrativeType ? narrativeType : null,
- dialogueType ? dialogueType : null,
+ narrativeType,
+ dialogueType,
encryptedPlotSummary,
encryptedToneAtmosphere,
- verbTense ? verbTense : null,
- language ? language : null,
+ verbTense,
+ language,
encryptedThemes,
- System.timeStampInSeconds(),
+ lastUpdate,
userId,
bookId
];
@@ -238,14 +235,14 @@ export default class GuidelineRepo {
bookId,
encryptedPlotSummary,
encryptedThemes,
- verbTense ? verbTense : null,
- narrativeType ? narrativeType : null,
- language ? language : null,
- dialogueType ? dialogueType : null,
+ verbTense,
+ narrativeType,
+ language,
+ dialogueType,
encryptedToneAtmosphere,
encryptedToneAtmosphere,
encryptedPlotSummary,
- System.timeStampInSeconds()
+ lastUpdate
];
const insertResult: RunResult = db.run(insertQuery, insertParams);
return insertResult.changes > 0;
@@ -391,6 +388,54 @@ export default class GuidelineRepo {
}
}
+ /**
+ * Checks if a guideline exists for a specific book.
+ * @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 True if the guideline exists, false otherwise.
+ */
+ static guideLineExist(userId: string, bookId: string, lang: 'fr' | 'en'): boolean {
+ try {
+ const db: Database = System.getDb();
+ const query: string = 'SELECT 1 FROM book_guide_line WHERE user_id=? AND book_id=?';
+ const params: SQLiteValue[] = [userId, bookId];
+ const result: Record | undefined = db.get(query, params) as Record | undefined;
+ return result !== undefined;
+ } catch (error: unknown) {
+ if (error instanceof Error) {
+ console.error(`DB Error: ${error.message}`);
+ throw new Error(lang === 'fr' ? `Impossible de vérifier l'existence de la ligne directrice.` : `Unable to check guideline existence.`);
+ } else {
+ throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
+ }
+ }
+ }
+
+ /**
+ * Checks if an AI guideline exists for a specific book.
+ * @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 True if the AI guideline exists, false otherwise.
+ */
+ static aiGuideLineExist(userId: string, bookId: string, lang: 'fr' | 'en'): boolean {
+ try {
+ const db: Database = System.getDb();
+ const query: string = 'SELECT 1 FROM book_ai_guide_line WHERE user_id=? AND book_id=?';
+ const params: SQLiteValue[] = [userId, bookId];
+ const result: Record | undefined = db.get(query, params) as Record | undefined;
+ return result !== undefined;
+ } catch (error: unknown) {
+ if (error instanceof Error) {
+ console.error(`DB Error: ${error.message}`);
+ throw new Error(lang === 'fr' ? `Impossible de vérifier l'existence de la ligne directrice IA.` : `Unable to check AI guideline existence.`);
+ } else {
+ throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
+ }
+ }
+ }
+
/**
* Inserts a synced AI guideline for a specific book.
* @param userId - The user identifier