Migrate from window.electron to tauri IPC functions across components
- Replaced `window.electron.invoke` calls with equivalent `tauri` function calls for all IPC interactions. - Removed `electron.d.ts` TypeScript definitions as they are no longer needed. - Updated related logic for offline/online state synchronization. - Added `types.rs` and `shared/mod.rs` modules to support Tauri IPC integration with Rust enums and shared logic. - Refactored IPC request queues to use updated handler names for consistency with Tauri.
This commit is contained in:
2
src-tauri/src/domains/guideline/mod.rs
Normal file
2
src-tauri/src/domains/guideline/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod repo;
|
||||
pub mod service;
|
||||
435
src-tauri/src/domains/guideline/repo.rs
Normal file
435
src-tauri/src/domains/guideline/repo.rs
Normal file
@@ -0,0 +1,435 @@
|
||||
use rusqlite::{params, Connection};
|
||||
|
||||
use crate::error::{AppError, AppResult};
|
||||
use crate::shared::types::Lang;
|
||||
|
||||
pub struct BookAIGuideLineTable {
|
||||
pub user_id: String,
|
||||
pub book_id: String,
|
||||
pub global_resume: Option<String>,
|
||||
pub themes: Option<String>,
|
||||
pub verbe_tense: Option<i64>,
|
||||
pub narrative_type: Option<i64>,
|
||||
pub langue: Option<i64>,
|
||||
pub dialogue_type: Option<i64>,
|
||||
pub tone: Option<String>,
|
||||
pub atmosphere: Option<String>,
|
||||
pub current_resume: Option<String>,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct BookGuideLineTable {
|
||||
pub user_id: String,
|
||||
pub book_id: String,
|
||||
pub tone: Option<String>,
|
||||
pub atmosphere: Option<String>,
|
||||
pub writing_style: Option<String>,
|
||||
pub themes: Option<String>,
|
||||
pub symbolism: Option<String>,
|
||||
pub motifs: Option<String>,
|
||||
pub narrative_voice: Option<String>,
|
||||
pub pacing: Option<String>,
|
||||
pub intended_audience: Option<String>,
|
||||
pub key_messages: Option<String>,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct SyncedGuideLineResult {
|
||||
pub book_id: String,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct SyncedAIGuideLineResult {
|
||||
pub book_id: String,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct GuideLineQuery {
|
||||
pub tone: String,
|
||||
pub atmosphere: String,
|
||||
pub writing_style: String,
|
||||
pub themes: String,
|
||||
pub symbolism: String,
|
||||
pub motifs: String,
|
||||
pub narrative_voice: String,
|
||||
pub pacing: String,
|
||||
pub intended_audience: String,
|
||||
pub key_messages: String,
|
||||
}
|
||||
|
||||
pub struct GuideLineAIQuery {
|
||||
pub user_id: String,
|
||||
pub book_id: String,
|
||||
pub global_resume: Option<String>,
|
||||
pub themes: Option<String>,
|
||||
pub verbe_tense: Option<i64>,
|
||||
pub narrative_type: Option<i64>,
|
||||
pub langue: Option<i64>,
|
||||
pub dialogue_type: Option<i64>,
|
||||
pub tone: Option<String>,
|
||||
pub atmosphere: Option<String>,
|
||||
pub current_resume: Option<String>,
|
||||
pub meta: String,
|
||||
}
|
||||
|
||||
/// Fetches the guideline for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of guideline query results.
|
||||
/// Errors if the guideline cannot be retrieved.
|
||||
pub fn fetch_guide_line(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<GuideLineQuery>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT tone, atmosphere, writing_style, themes, symbolism, motifs, narrative_voice, pacing, intended_audience, key_messages FROM book_guide_line WHERE book_id=?1 AND user_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice.".to_string() } else { "Unable to retrieve guideline.".to_string() }))?;
|
||||
|
||||
let guidelines = statement
|
||||
.query_map(params![book_id, user_id], |query_row| {
|
||||
Ok(GuideLineQuery {
|
||||
tone: query_row.get(0)?, atmosphere: query_row.get(1)?,
|
||||
writing_style: query_row.get(2)?, themes: query_row.get(3)?,
|
||||
symbolism: query_row.get(4)?, motifs: query_row.get(5)?,
|
||||
narrative_voice: query_row.get(6)?, pacing: query_row.get(7)?,
|
||||
intended_audience: query_row.get(8)?, key_messages: query_row.get(9)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice.".to_string() } else { "Unable to retrieve guideline.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice.".to_string() } else { "Unable to retrieve guideline.".to_string() }))?;
|
||||
|
||||
Ok(guidelines)
|
||||
}
|
||||
|
||||
/// Updates or inserts a guideline for a specific book.
|
||||
/// If the guideline exists, it updates it; otherwise, it inserts a new one.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `encrypted_tone` - The encrypted tone value
|
||||
/// * `encrypted_atmosphere` - The encrypted atmosphere value
|
||||
/// * `encrypted_writing_style` - The encrypted writing style value
|
||||
/// * `encrypted_themes` - The encrypted themes value
|
||||
/// * `encrypted_symbolism` - The encrypted symbolism value
|
||||
/// * `encrypted_motifs` - The encrypted motifs value
|
||||
/// * `encrypted_narrative_voice` - The encrypted narrative voice value
|
||||
/// * `encrypted_pacing` - The encrypted pacing value
|
||||
/// * `encrypted_key_messages` - The encrypted key messages value
|
||||
/// * `encrypted_intended_audience` - The encrypted intended audience value
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the operation was successful.
|
||||
/// Errors if the guideline cannot be updated or inserted.
|
||||
pub fn update_guide_line(
|
||||
conn: &Connection, user_id: &str, book_id: &str, encrypted_tone: Option<&str>,
|
||||
encrypted_atmosphere: Option<&str>, encrypted_writing_style: Option<&str>,
|
||||
encrypted_themes: Option<&str>, encrypted_symbolism: Option<&str>,
|
||||
encrypted_motifs: Option<&str>, encrypted_narrative_voice: Option<&str>,
|
||||
encrypted_pacing: Option<&str>, encrypted_key_messages: Option<&str>,
|
||||
encrypted_intended_audience: Option<&str>, last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let update_result = conn
|
||||
.execute(
|
||||
"UPDATE book_guide_line SET tone=?1, atmosphere=?2, writing_style=?3, themes=?4, symbolism=?5, motifs=?6, narrative_voice=?7, pacing=?8, intended_audience=?9, key_messages=?10, last_update=?11 WHERE user_id=?12 AND book_id=?13",
|
||||
params![encrypted_tone, encrypted_atmosphere, encrypted_writing_style, encrypted_themes, encrypted_symbolism, encrypted_motifs, encrypted_narrative_voice, encrypted_pacing, encrypted_intended_audience, encrypted_key_messages, last_update, user_id, book_id],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour la ligne directrice.".to_string() } else { "Unable to update guideline.".to_string() }))?;
|
||||
|
||||
if update_result > 0 {
|
||||
Ok(true)
|
||||
} else {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_guide_line (user_id, book_id, tone, atmosphere, writing_style, themes, symbolism, motifs, narrative_voice, pacing, intended_audience, key_messages, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13)",
|
||||
params![user_id, book_id, encrypted_tone, encrypted_atmosphere, encrypted_writing_style, encrypted_themes, encrypted_symbolism, encrypted_motifs, encrypted_narrative_voice, encrypted_pacing, encrypted_intended_audience, encrypted_key_messages, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour la ligne directrice.".to_string() } else { "Unable to update guideline.".to_string() }))?;
|
||||
|
||||
Ok(insert_result > 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts or updates an AI guideline for a specific book.
|
||||
/// If the AI guideline exists, it updates it; otherwise, it inserts a new one.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `narrative_type` - The narrative type identifier
|
||||
/// * `dialogue_type` - The dialogue type identifier
|
||||
/// * `encrypted_plot_summary` - The encrypted plot summary
|
||||
/// * `encrypted_tone_atmosphere` - The encrypted tone and atmosphere value
|
||||
/// * `verb_tense` - The verb tense identifier
|
||||
/// * `language` - The language identifier
|
||||
/// * `encrypted_themes` - The encrypted themes value
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the operation was successful.
|
||||
/// Errors if the AI guideline cannot be inserted or updated.
|
||||
pub fn insert_ai_guide_line(
|
||||
conn: &Connection, user_id: &str, book_id: &str, narrative_type: Option<i64>,
|
||||
dialogue_type: Option<i64>, encrypted_plot_summary: Option<&str>,
|
||||
encrypted_tone_atmosphere: Option<&str>, verb_tense: Option<i64>,
|
||||
language: Option<i64>, encrypted_themes: Option<&str>, last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let update_result = conn
|
||||
.execute(
|
||||
"UPDATE book_ai_guide_line SET narrative_type=?1, dialogue_type=?2, global_resume=?3, atmosphere=?4, verbe_tense=?5, langue=?6, themes=?7, last_update=?8 WHERE user_id=?9 AND book_id=?10",
|
||||
params![narrative_type, dialogue_type, encrypted_plot_summary, encrypted_tone_atmosphere, verb_tense, language, encrypted_themes, last_update, user_id, book_id],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer la ligne directrice IA.".to_string() } else { "Unable to insert AI guideline.".to_string() }))?;
|
||||
|
||||
if update_result > 0 {
|
||||
Ok(true)
|
||||
} else {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_ai_guide_line (user_id, book_id, global_resume, themes, verbe_tense, narrative_type, langue, dialogue_type, tone, atmosphere, current_resume, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12)",
|
||||
params![user_id, book_id, encrypted_plot_summary, encrypted_themes, verb_tense, narrative_type, language, dialogue_type, encrypted_tone_atmosphere, encrypted_tone_atmosphere, encrypted_plot_summary, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer la ligne directrice IA.".to_string() } else { "Unable to insert AI guideline.".to_string() }))?;
|
||||
|
||||
Ok(insert_result > 0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches the AI guideline for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns the AI guideline query result.
|
||||
/// Errors if the AI guideline cannot be retrieved or is not found.
|
||||
pub fn fetch_guide_line_ai(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<GuideLineAIQuery> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT narrative_type, dialogue_type, global_resume, atmosphere, verbe_tense, langue, themes, current_resume FROM book_ai_guide_line WHERE user_id=?1 AND book_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice IA.".to_string() } else { "Unable to retrieve AI guideline.".to_string() }))?;
|
||||
|
||||
let ai_guideline = statement
|
||||
.query_row(params![user_id, book_id], |query_row| {
|
||||
Ok(GuideLineAIQuery {
|
||||
narrative_type: query_row.get(0)?, dialogue_type: query_row.get(1)?,
|
||||
global_resume: query_row.get(2)?, atmosphere: query_row.get(3)?,
|
||||
verbe_tense: query_row.get(4)?, langue: query_row.get(5)?,
|
||||
themes: query_row.get(6)?, current_resume: query_row.get(7)?,
|
||||
user_id: user_id.to_string(), book_id: book_id.to_string(),
|
||||
tone: None, meta: String::new(),
|
||||
})
|
||||
})
|
||||
.map_err(|error| match error {
|
||||
rusqlite::Error::QueryReturnedNoRows => AppError::NotFound(if lang == Lang::Fr { "Ligne directrice IA non trouvée.".to_string() } else { "AI guideline not found.".to_string() }),
|
||||
_ => AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice IA.".to_string() } else { "Unable to retrieve AI guideline.".to_string() }),
|
||||
})?;
|
||||
|
||||
Ok(ai_guideline)
|
||||
}
|
||||
|
||||
/// Fetches the book AI guideline table data for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of book AI guideline table entries.
|
||||
/// Errors if the AI guideline cannot be retrieved.
|
||||
pub fn fetch_book_ai_guide_line(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookAIGuideLineTable>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT user_id, book_id, global_resume, themes, verbe_tense, narrative_type, langue, dialogue_type, tone, atmosphere, current_resume, last_update FROM book_ai_guide_line WHERE user_id=?1 AND book_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice IA.".to_string() } else { "Unable to retrieve AI guideline.".to_string() }))?;
|
||||
|
||||
let ai_guidelines = statement
|
||||
.query_map(params![user_id, book_id], |query_row| {
|
||||
Ok(BookAIGuideLineTable {
|
||||
user_id: query_row.get(0)?, book_id: query_row.get(1)?,
|
||||
global_resume: query_row.get(2)?, themes: query_row.get(3)?,
|
||||
verbe_tense: query_row.get(4)?, narrative_type: query_row.get(5)?,
|
||||
langue: query_row.get(6)?, dialogue_type: query_row.get(7)?,
|
||||
tone: query_row.get(8)?, atmosphere: query_row.get(9)?,
|
||||
current_resume: query_row.get(10)?, last_update: query_row.get(11)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice IA.".to_string() } else { "Unable to retrieve AI guideline.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice IA.".to_string() } else { "Unable to retrieve AI guideline.".to_string() }))?;
|
||||
|
||||
Ok(ai_guidelines)
|
||||
}
|
||||
|
||||
/// Fetches the book guideline table data for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of book guideline table entries.
|
||||
/// Errors if the guideline cannot be retrieved.
|
||||
pub fn fetch_book_guide_line_table(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookGuideLineTable>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT user_id, book_id, tone, atmosphere, writing_style, themes, symbolism, motifs, narrative_voice, pacing, intended_audience, key_messages, last_update FROM book_guide_line WHERE user_id=?1 AND book_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice.".to_string() } else { "Unable to retrieve guideline.".to_string() }))?;
|
||||
|
||||
let guidelines = statement
|
||||
.query_map(params![user_id, book_id], |query_row| {
|
||||
Ok(BookGuideLineTable {
|
||||
user_id: query_row.get(0)?, book_id: query_row.get(1)?,
|
||||
tone: query_row.get(2)?, atmosphere: query_row.get(3)?,
|
||||
writing_style: query_row.get(4)?, themes: query_row.get(5)?,
|
||||
symbolism: query_row.get(6)?, motifs: query_row.get(7)?,
|
||||
narrative_voice: query_row.get(8)?, pacing: query_row.get(9)?,
|
||||
intended_audience: query_row.get(10)?, key_messages: query_row.get(11)?,
|
||||
last_update: query_row.get(12)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice.".to_string() } else { "Unable to retrieve guideline.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer la ligne directrice.".to_string() } else { "Unable to retrieve guideline.".to_string() }))?;
|
||||
|
||||
Ok(guidelines)
|
||||
}
|
||||
|
||||
/// Fetches all synced guidelines for a specific user.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of synced guideline results containing book_id and last_update.
|
||||
/// Errors if the synced guidelines cannot be retrieved.
|
||||
pub fn fetch_synced_guide_line(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedGuideLineResult>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT book_id, last_update FROM book_guide_line WHERE user_id = ?1")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lignes directrices synchronisées.".to_string() } else { "Unable to retrieve synced guidelines.".to_string() }))?;
|
||||
|
||||
let synced_guidelines = statement
|
||||
.query_map(params![user_id], |query_row| {
|
||||
Ok(SyncedGuideLineResult { book_id: query_row.get(0)?, last_update: query_row.get(1)? })
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lignes directrices synchronisées.".to_string() } else { "Unable to retrieve synced guidelines.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lignes directrices synchronisées.".to_string() } else { "Unable to retrieve synced guidelines.".to_string() }))?;
|
||||
|
||||
Ok(synced_guidelines)
|
||||
}
|
||||
|
||||
/// Fetches all synced AI guidelines for a specific user.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of synced AI guideline results containing book_id and last_update.
|
||||
/// Errors if the synced AI guidelines cannot be retrieved.
|
||||
pub fn fetch_synced_ai_guide_line(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedAIGuideLineResult>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT book_id, last_update FROM book_ai_guide_line WHERE user_id = ?1")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lignes directrices IA synchronisées.".to_string() } else { "Unable to retrieve synced AI guidelines.".to_string() }))?;
|
||||
|
||||
let synced_ai_guidelines = statement
|
||||
.query_map(params![user_id], |query_row| {
|
||||
Ok(SyncedAIGuideLineResult { book_id: query_row.get(0)?, last_update: query_row.get(1)? })
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lignes directrices IA synchronisées.".to_string() } else { "Unable to retrieve synced AI guidelines.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les lignes directrices IA synchronisées.".to_string() } else { "Unable to retrieve synced AI guidelines.".to_string() }))?;
|
||||
|
||||
Ok(synced_ai_guidelines)
|
||||
}
|
||||
|
||||
/// Checks if a guideline exists for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the guideline exists, false otherwise.
|
||||
/// Errors if the existence check fails.
|
||||
pub fn guide_line_exist(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<bool> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT 1 FROM book_guide_line WHERE user_id=?1 AND book_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de la ligne directrice.".to_string() } else { "Unable to check guideline existence.".to_string() }))?;
|
||||
|
||||
let exists = statement
|
||||
.query_row(params![user_id, book_id], |_query_row| Ok(true))
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
/// Checks if an AI guideline exists for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the AI guideline exists, false otherwise.
|
||||
/// Errors if the existence check fails.
|
||||
pub fn ai_guide_line_exist(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<bool> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT 1 FROM book_ai_guide_line WHERE user_id=?1 AND book_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de la ligne directrice IA.".to_string() } else { "Unable to check AI guideline existence.".to_string() }))?;
|
||||
|
||||
let exists = statement
|
||||
.query_row(params![user_id, book_id], |_query_row| Ok(true))
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
/// Inserts a synced AI guideline for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `global_resume` - The global resume value (nullable)
|
||||
/// * `themes` - The themes value (nullable)
|
||||
/// * `verbe_tense` - The verb tense identifier (nullable)
|
||||
/// * `narrative_type` - The narrative type identifier (nullable)
|
||||
/// * `langue` - The language identifier (nullable)
|
||||
/// * `dialogue_type` - The dialogue type identifier (nullable)
|
||||
/// * `tone` - The tone value (nullable)
|
||||
/// * `atmosphere` - The atmosphere value (nullable)
|
||||
/// * `current_resume` - The current resume value (nullable)
|
||||
/// * `last_update` - The last update timestamp
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the insertion was successful.
|
||||
/// Errors if the AI guideline cannot be inserted.
|
||||
pub fn insert_sync_ai_guide_line(
|
||||
conn: &Connection, user_id: &str, book_id: &str, global_resume: Option<&str>,
|
||||
themes: Option<&str>, verbe_tense: Option<i64>, narrative_type: Option<i64>,
|
||||
langue: Option<i64>, dialogue_type: Option<i64>, tone: Option<&str>,
|
||||
atmosphere: Option<&str>, current_resume: Option<&str>, last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_ai_guide_line (user_id, book_id, global_resume, themes, verbe_tense, narrative_type, langue, dialogue_type, tone, atmosphere, current_resume, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)",
|
||||
params![user_id, book_id, global_resume, themes, verbe_tense, narrative_type, langue, dialogue_type, tone, atmosphere, current_resume, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer la ligne directrice IA.".to_string() } else { "Unable to insert AI guideline.".to_string() }))?;
|
||||
|
||||
Ok(insert_result > 0)
|
||||
}
|
||||
|
||||
/// Inserts a synced guideline for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The user identifier
|
||||
/// * `book_id` - The book identifier
|
||||
/// * `tone` - The tone value (nullable)
|
||||
/// * `atmosphere` - The atmosphere value (nullable)
|
||||
/// * `writing_style` - The writing style value (nullable)
|
||||
/// * `themes` - The themes value (nullable)
|
||||
/// * `symbolism` - The symbolism value (nullable)
|
||||
/// * `motifs` - The motifs value (nullable)
|
||||
/// * `narrative_voice` - The narrative voice value (nullable)
|
||||
/// * `pacing` - The pacing value (nullable)
|
||||
/// * `intended_audience` - The intended audience value (nullable)
|
||||
/// * `key_messages` - The key messages value (nullable)
|
||||
/// * `last_update` - The last update timestamp
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the insertion was successful.
|
||||
/// Errors if the guideline cannot be inserted.
|
||||
pub fn insert_sync_guide_line(
|
||||
conn: &Connection, user_id: &str, book_id: &str, tone: Option<&str>,
|
||||
atmosphere: Option<&str>, writing_style: Option<&str>, themes: Option<&str>,
|
||||
symbolism: Option<&str>, motifs: Option<&str>, narrative_voice: Option<&str>,
|
||||
pacing: Option<&str>, intended_audience: Option<&str>, key_messages: Option<&str>,
|
||||
last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_guide_line (user_id, book_id, tone, atmosphere, writing_style, themes, symbolism, motifs, narrative_voice, pacing, intended_audience, key_messages, last_update) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)",
|
||||
params![user_id, book_id, tone, atmosphere, writing_style, themes, symbolism, motifs, narrative_voice, pacing, intended_audience, key_messages, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer la ligne directrice.".to_string() } else { "Unable to insert guideline.".to_string() }))?;
|
||||
|
||||
Ok(insert_result > 0)
|
||||
}
|
||||
208
src-tauri/src/domains/guideline/service.rs
Normal file
208
src-tauri/src/domains/guideline/service.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
use rusqlite::Connection;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::crypto::encryption::{encrypt_data_with_user_key, decrypt_data_with_user_key};
|
||||
use crate::crypto::key_manager::get_user_encryption_key;
|
||||
use crate::domains::guideline::repo;
|
||||
use crate::error::{AppError, AppResult};
|
||||
use crate::helpers::timestamp_in_seconds;
|
||||
use crate::shared::types::Lang;
|
||||
|
||||
/// Represents the synced guideline data for a book.
|
||||
pub struct SyncedGuideLine {
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
/// Represents the synced AI guideline data for a book.
|
||||
pub struct SyncedAIGuideLine {
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
/// Represents the decrypted guideline properties for a book.
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GuideLineProps {
|
||||
pub tone: String,
|
||||
pub atmosphere: String,
|
||||
pub writing_style: String,
|
||||
pub themes: String,
|
||||
pub symbolism: String,
|
||||
pub motifs: String,
|
||||
pub narrative_voice: String,
|
||||
pub pacing: String,
|
||||
pub intended_audience: String,
|
||||
pub key_messages: String,
|
||||
}
|
||||
|
||||
/// Represents the decrypted AI guideline data for a book.
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GuideLineAI {
|
||||
pub narrative_type: Option<i64>,
|
||||
pub dialogue_type: Option<i64>,
|
||||
pub global_resume: Option<String>,
|
||||
pub atmosphere: Option<String>,
|
||||
pub verbe_tense: Option<i64>,
|
||||
pub langue: Option<i64>,
|
||||
pub current_resume: Option<String>,
|
||||
pub themes: Option<String>,
|
||||
}
|
||||
|
||||
/// Retrieves and decrypts the guideline for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns the decrypted guideline properties or None if not found.
|
||||
pub fn get_guide_line(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Option<GuideLineProps>> {
|
||||
let guide_line_results: Vec<repo::GuideLineQuery> = repo::fetch_guide_line(conn, user_id, book_id, lang)?;
|
||||
|
||||
if guide_line_results.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let guide_line_data: &repo::GuideLineQuery = &guide_line_results[0];
|
||||
let encryption_key: String = get_user_encryption_key(user_id)?;
|
||||
|
||||
Ok(Some(GuideLineProps {
|
||||
tone: if guide_line_data.tone.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.tone, &encryption_key)? },
|
||||
atmosphere: if guide_line_data.atmosphere.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.atmosphere, &encryption_key)? },
|
||||
writing_style: if guide_line_data.writing_style.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.writing_style, &encryption_key)? },
|
||||
themes: if guide_line_data.themes.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.themes, &encryption_key)? },
|
||||
symbolism: if guide_line_data.symbolism.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.symbolism, &encryption_key)? },
|
||||
motifs: if guide_line_data.motifs.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.motifs, &encryption_key)? },
|
||||
narrative_voice: if guide_line_data.narrative_voice.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.narrative_voice, &encryption_key)? },
|
||||
pacing: if guide_line_data.pacing.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.pacing, &encryption_key)? },
|
||||
intended_audience: if guide_line_data.intended_audience.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.intended_audience, &encryption_key)? },
|
||||
key_messages: if guide_line_data.key_messages.is_empty() { String::new() } else { decrypt_data_with_user_key(&guide_line_data.key_messages, &encryption_key)? },
|
||||
}))
|
||||
}
|
||||
|
||||
/// Updates or creates a guideline for a specific book with encrypted data.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `tone` - The tone setting for the book (nullable)
|
||||
/// * `atmosphere` - The atmosphere setting for the book (nullable)
|
||||
/// * `writing_style` - The writing style for the book (nullable)
|
||||
/// * `themes` - The themes for the book (nullable)
|
||||
/// * `symbolism` - The symbolism elements for the book (nullable)
|
||||
/// * `motifs` - The motifs for the book (nullable)
|
||||
/// * `narrative_voice` - The narrative voice for the book (nullable)
|
||||
/// * `pacing` - The pacing setting for the book (nullable)
|
||||
/// * `key_messages` - The key messages for the book (nullable)
|
||||
/// * `intended_audience` - The intended audience for the book (nullable)
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the update was successful, false otherwise.
|
||||
pub fn update_guide_line(
|
||||
conn: &Connection, user_id: &str, book_id: &str, tone: Option<&str>,
|
||||
atmosphere: Option<&str>, writing_style: Option<&str>, themes: Option<&str>,
|
||||
symbolism: Option<&str>, motifs: Option<&str>, narrative_voice: Option<&str>,
|
||||
pacing: Option<&str>, key_messages: Option<&str>, intended_audience: Option<&str>,
|
||||
lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let encryption_key: String = get_user_encryption_key(user_id)?;
|
||||
|
||||
let encrypted_tone: String = if let Some(tone_value) = tone { encrypt_data_with_user_key(tone_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_atmosphere: String = if let Some(atmosphere_value) = atmosphere { encrypt_data_with_user_key(atmosphere_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_writing_style: String = if let Some(writing_style_value) = writing_style { encrypt_data_with_user_key(writing_style_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_themes: String = if let Some(themes_value) = themes { encrypt_data_with_user_key(themes_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_symbolism: String = if let Some(symbolism_value) = symbolism { encrypt_data_with_user_key(symbolism_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_motifs: String = if let Some(motifs_value) = motifs { encrypt_data_with_user_key(motifs_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_narrative_voice: String = if let Some(narrative_voice_value) = narrative_voice { encrypt_data_with_user_key(narrative_voice_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_pacing: String = if let Some(pacing_value) = pacing { encrypt_data_with_user_key(pacing_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_key_messages: String = if let Some(key_messages_value) = key_messages { encrypt_data_with_user_key(key_messages_value, &encryption_key)? } else { String::new() };
|
||||
let encrypted_intended_audience: String = if let Some(intended_audience_value) = intended_audience { encrypt_data_with_user_key(intended_audience_value, &encryption_key)? } else { String::new() };
|
||||
|
||||
let last_update: i64 = timestamp_in_seconds();
|
||||
|
||||
repo::update_guide_line(
|
||||
conn, user_id, book_id,
|
||||
Some(&encrypted_tone), Some(&encrypted_atmosphere), Some(&encrypted_writing_style),
|
||||
Some(&encrypted_themes), Some(&encrypted_symbolism), Some(&encrypted_motifs),
|
||||
Some(&encrypted_narrative_voice), Some(&encrypted_pacing),
|
||||
Some(&encrypted_key_messages), Some(&encrypted_intended_audience),
|
||||
last_update, lang,
|
||||
)
|
||||
}
|
||||
|
||||
/// Retrieves and decrypts the AI guideline for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns the decrypted AI guideline data with default values if not found.
|
||||
/// Errors if an unexpected error occurs during retrieval.
|
||||
pub fn get_guide_line_ai(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<GuideLineAI> {
|
||||
let encryption_key: String = get_user_encryption_key(user_id)?;
|
||||
|
||||
match repo::fetch_guide_line_ai(conn, user_id, book_id, lang) {
|
||||
Ok(ai_guide_line_data) => {
|
||||
Ok(GuideLineAI {
|
||||
narrative_type: ai_guide_line_data.narrative_type,
|
||||
dialogue_type: ai_guide_line_data.dialogue_type,
|
||||
global_resume: Some(if let Some(ref global_resume) = ai_guide_line_data.global_resume { decrypt_data_with_user_key(global_resume, &encryption_key)? } else { String::new() }),
|
||||
atmosphere: Some(if let Some(ref atmosphere) = ai_guide_line_data.atmosphere { decrypt_data_with_user_key(atmosphere, &encryption_key)? } else { String::new() }),
|
||||
verbe_tense: ai_guide_line_data.verbe_tense,
|
||||
themes: Some(if let Some(ref themes) = ai_guide_line_data.themes { decrypt_data_with_user_key(themes, &encryption_key)? } else { String::new() }),
|
||||
current_resume: Some(if let Some(ref current_resume) = ai_guide_line_data.current_resume { decrypt_data_with_user_key(current_resume, &encryption_key)? } else { String::new() }),
|
||||
langue: ai_guide_line_data.langue,
|
||||
})
|
||||
}
|
||||
Err(error) => {
|
||||
if error.to_string().contains("not found") || error.to_string().contains("non trouvée") {
|
||||
Ok(GuideLineAI {
|
||||
narrative_type: Some(0),
|
||||
dialogue_type: Some(0),
|
||||
global_resume: Some(String::new()),
|
||||
atmosphere: Some(String::new()),
|
||||
verbe_tense: Some(0),
|
||||
themes: Some(String::new()),
|
||||
current_resume: Some(String::new()),
|
||||
langue: Some(0),
|
||||
})
|
||||
} else {
|
||||
Err(AppError::Internal(if lang == Lang::Fr {
|
||||
"Erreur inconnue lors de la recuperation de la ligne directrice de l'IA.".to_string()
|
||||
} else {
|
||||
"Unknown error while fetching AI guideline.".to_string()
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates or updates an AI guideline for a specific book with encrypted data.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `narrative_type` - The narrative type identifier
|
||||
/// * `dialogue_type` - The dialogue type identifier
|
||||
/// * `plot_summary` - The plot summary text to be encrypted
|
||||
/// * `tone_atmosphere` - The tone and atmosphere description to be encrypted
|
||||
/// * `verb_tense` - The verb tense identifier
|
||||
/// * `language` - The language identifier
|
||||
/// * `themes` - The themes description to be encrypted
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the operation was successful, false otherwise.
|
||||
pub fn set_ai_guide_line(
|
||||
conn: &Connection, user_id: &str, book_id: &str, narrative_type: i64,
|
||||
dialogue_type: i64, plot_summary: &str, tone_atmosphere: &str, verb_tense: i64,
|
||||
language: i64, themes: &str, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let encryption_key: String = get_user_encryption_key(user_id)?;
|
||||
|
||||
let encrypted_plot_summary: String = if plot_summary.is_empty() { String::new() } else { encrypt_data_with_user_key(plot_summary, &encryption_key)? };
|
||||
let encrypted_tone_atmosphere: String = if tone_atmosphere.is_empty() { String::new() } else { encrypt_data_with_user_key(tone_atmosphere, &encryption_key)? };
|
||||
let encrypted_themes: String = if themes.is_empty() { String::new() } else { encrypt_data_with_user_key(themes, &encryption_key)? };
|
||||
|
||||
let last_update: i64 = timestamp_in_seconds();
|
||||
|
||||
repo::insert_ai_guide_line(
|
||||
conn, user_id, book_id,
|
||||
Some(narrative_type), Some(dialogue_type),
|
||||
Some(&encrypted_plot_summary), Some(&encrypted_tone_atmosphere),
|
||||
Some(verb_tense), Some(language), Some(&encrypted_themes),
|
||||
last_update, lang,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user