199 lines
12 KiB
Rust
199 lines
12 KiB
Rust
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 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,
|
|
)
|
|
}
|