- 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.
285 lines
14 KiB
Rust
285 lines
14 KiB
Rust
use rusqlite::Connection;
|
|
use serde::Serialize;
|
|
|
|
use crate::crypto::encryption::{encrypt_data_with_user_key, decrypt_data_with_user_key, hash_element};
|
|
use crate::crypto::key_manager::get_user_encryption_key;
|
|
use crate::domains::series_spell::repo;
|
|
use crate::domains::tombstone::repo as tombstone_repo;
|
|
use crate::error::{AppError, AppResult};
|
|
use crate::helpers::{create_unique_id, timestamp_in_seconds};
|
|
use crate::shared::types::Lang;
|
|
|
|
#[derive(Serialize)]
|
|
pub struct SeriesSpellTagProps {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub color: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct SeriesSpellListProps {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub tags: Vec<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct SeriesSpellListResponse {
|
|
pub spells: Vec<SeriesSpellListProps>,
|
|
pub tags: Vec<SeriesSpellTagProps>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SeriesSpellDetailProps {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub appearance: String,
|
|
pub tags: Vec<String>,
|
|
pub power_level: Option<String>,
|
|
pub components: Option<String>,
|
|
pub limitations: Option<String>,
|
|
pub notes: Option<String>,
|
|
}
|
|
|
|
/// Retrieves all spells and tags for a series.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `series_id` - The unique identifier of the series
|
|
/// * `lang` - The language for error messages
|
|
/// Returns the list of spells and tags.
|
|
pub fn get_spell_list(conn: &Connection, user_id: &str, series_id: &str, lang: Lang) -> AppResult<SeriesSpellListResponse> {
|
|
let user_key: String = get_user_encryption_key(user_id)?;
|
|
let spells_result: Vec<repo::SeriesSpellResult> = repo::fetch_spells(conn, user_id, series_id, lang)?;
|
|
let tags_result: Vec<repo::SeriesSpellTagResult> = repo::fetch_tags(conn, user_id, series_id, lang)?;
|
|
|
|
let mut spells: Vec<SeriesSpellListProps> = Vec::with_capacity(spells_result.len());
|
|
for spell in spells_result {
|
|
let decrypted_name: String = if spell.name.is_empty() { String::new() } else { decrypt_data_with_user_key(&spell.name, &user_key)? };
|
|
let decrypted_description: String = if spell.description.is_empty() { String::new() } else { decrypt_data_with_user_key(&spell.description, &user_key)? };
|
|
let decrypted_tags: Vec<String> = if spell.tags.is_empty() {
|
|
vec![]
|
|
} else {
|
|
let decrypted_tags_string: String = decrypt_data_with_user_key(&spell.tags, &user_key)?;
|
|
serde_json::from_str(&decrypted_tags_string).unwrap_or_default()
|
|
};
|
|
|
|
spells.push(SeriesSpellListProps {
|
|
id: spell.spell_id,
|
|
name: decrypted_name,
|
|
description: decrypted_description,
|
|
tags: decrypted_tags,
|
|
});
|
|
}
|
|
|
|
let mut tags: Vec<SeriesSpellTagProps> = Vec::with_capacity(tags_result.len());
|
|
for tag in tags_result {
|
|
let decrypted_name: String = if tag.name.is_empty() { String::new() } else { decrypt_data_with_user_key(&tag.name, &user_key)? };
|
|
|
|
tags.push(SeriesSpellTagProps {
|
|
id: tag.tag_id,
|
|
name: decrypted_name,
|
|
color: tag.color,
|
|
});
|
|
}
|
|
|
|
Ok(SeriesSpellListResponse { spells, tags })
|
|
}
|
|
|
|
/// Retrieves the details of a specific spell.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `spell_id` - The unique identifier of the spell
|
|
/// * `lang` - The language for error messages
|
|
/// Returns the spell details.
|
|
pub fn get_spell_detail(conn: &Connection, user_id: &str, spell_id: &str, lang: Lang) -> AppResult<SeriesSpellDetailProps> {
|
|
let user_key: String = get_user_encryption_key(user_id)?;
|
|
let spell: Option<repo::SeriesSpellResult> = repo::fetch_spell_by_id(conn, user_id, spell_id, lang)?;
|
|
|
|
let spell: repo::SeriesSpellResult = spell.ok_or_else(|| {
|
|
AppError::Internal(if lang == Lang::Fr { "Sort non trouvé.".to_string() } else { "Spell not found.".to_string() })
|
|
})?;
|
|
|
|
let decrypted_name: String = if spell.name.is_empty() { String::new() } else { decrypt_data_with_user_key(&spell.name, &user_key)? };
|
|
let decrypted_description: String = if spell.description.is_empty() { String::new() } else { decrypt_data_with_user_key(&spell.description, &user_key)? };
|
|
let decrypted_appearance: String = if spell.appearance.is_empty() { String::new() } else { decrypt_data_with_user_key(&spell.appearance, &user_key)? };
|
|
let decrypted_tags: Vec<String> = if spell.tags.is_empty() {
|
|
vec![]
|
|
} else {
|
|
let decrypted_tags_string: String = decrypt_data_with_user_key(&spell.tags, &user_key)?;
|
|
serde_json::from_str(&decrypted_tags_string).unwrap_or_default()
|
|
};
|
|
let decrypted_power_level: Option<String> = if let Some(ref power_level) = spell.power_level { Some(decrypt_data_with_user_key(power_level, &user_key)?) } else { None };
|
|
let decrypted_components: Option<String> = if let Some(ref components) = spell.components { Some(decrypt_data_with_user_key(components, &user_key)?) } else { None };
|
|
let decrypted_limitations: Option<String> = if let Some(ref limitations) = spell.limitations { Some(decrypt_data_with_user_key(limitations, &user_key)?) } else { None };
|
|
let decrypted_notes: Option<String> = if let Some(ref notes) = spell.notes { Some(decrypt_data_with_user_key(notes, &user_key)?) } else { None };
|
|
|
|
Ok(SeriesSpellDetailProps {
|
|
id: spell.spell_id,
|
|
name: decrypted_name,
|
|
description: decrypted_description,
|
|
appearance: decrypted_appearance,
|
|
tags: decrypted_tags,
|
|
power_level: decrypted_power_level,
|
|
components: decrypted_components,
|
|
limitations: decrypted_limitations,
|
|
notes: decrypted_notes,
|
|
})
|
|
}
|
|
|
|
/// Adds a new spell to a series.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `series_id` - The unique identifier of the series
|
|
/// * `name` - The spell name
|
|
/// * `lang` - The language for error messages
|
|
/// * `description` - The spell description
|
|
/// * `appearance` - The spell appearance
|
|
/// * `tags` - The spell tags
|
|
/// * `power_level` - The spell power level
|
|
/// * `components` - The spell components
|
|
/// * `limitations` - The spell limitations
|
|
/// * `notes` - The spell notes
|
|
/// Returns the new spell ID.
|
|
pub fn add_spell(
|
|
conn: &Connection, user_id: &str, series_id: &str, name: &str, lang: Lang,
|
|
description: Option<&str>, appearance: Option<&str>, tags: Option<Vec<String>>,
|
|
power_level: Option<&str>, components: Option<&str>, limitations: Option<&str>, notes: Option<&str>,
|
|
) -> AppResult<String> {
|
|
let user_key: String = get_user_encryption_key(user_id)?;
|
|
let spell_id: String = create_unique_id(None);
|
|
let encrypted_name: String = encrypt_data_with_user_key(name, &user_key)?;
|
|
let name_hash: String = hash_element(name);
|
|
let encrypted_description: String = if let Some(description) = description { encrypt_data_with_user_key(description, &user_key)? } else { String::new() };
|
|
let encrypted_appearance: String = if let Some(appearance) = appearance { encrypt_data_with_user_key(appearance, &user_key)? } else { String::new() };
|
|
let tags_json: String = serde_json::to_string(&tags.unwrap_or_default()).unwrap_or_else(|_| "[]".to_string());
|
|
let encrypted_tags: String = encrypt_data_with_user_key(&tags_json, &user_key)?;
|
|
let encrypted_power_level: Option<String> = if let Some(power_level) = power_level { Some(encrypt_data_with_user_key(power_level, &user_key)?) } else { None };
|
|
let encrypted_components: Option<String> = if let Some(components) = components { Some(encrypt_data_with_user_key(components, &user_key)?) } else { None };
|
|
let encrypted_limitations: Option<String> = if let Some(limitations) = limitations { Some(encrypt_data_with_user_key(limitations, &user_key)?) } else { None };
|
|
let encrypted_notes: Option<String> = if let Some(notes) = notes { Some(encrypt_data_with_user_key(notes, &user_key)?) } else { None };
|
|
let last_update: i64 = timestamp_in_seconds();
|
|
|
|
repo::insert_spell(
|
|
conn, &spell_id, series_id, user_id, &encrypted_name, &name_hash,
|
|
&encrypted_description, &encrypted_appearance, &encrypted_tags,
|
|
encrypted_power_level.as_deref(), encrypted_components.as_deref(),
|
|
encrypted_limitations.as_deref(), encrypted_notes.as_deref(), last_update, lang,
|
|
)?;
|
|
|
|
Ok(spell_id)
|
|
}
|
|
|
|
/// Updates an existing spell.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `spell_id` - The unique identifier of the spell
|
|
/// * `name` - The spell name
|
|
/// * `lang` - The language for error messages
|
|
/// * `description` - The spell description
|
|
/// * `appearance` - The spell appearance
|
|
/// * `tags` - The spell tags
|
|
/// * `power_level` - The spell power level
|
|
/// * `components` - The spell components
|
|
/// * `limitations` - The spell limitations
|
|
/// * `notes` - The spell notes
|
|
/// Returns true if successful.
|
|
pub fn update_spell(
|
|
conn: &Connection, user_id: &str, spell_id: &str, name: &str, lang: Lang,
|
|
description: Option<&str>, appearance: Option<&str>, tags: Option<Vec<String>>,
|
|
power_level: Option<&str>, components: Option<&str>, limitations: Option<&str>, notes: Option<&str>,
|
|
) -> AppResult<bool> {
|
|
let user_key: String = get_user_encryption_key(user_id)?;
|
|
let encrypted_name: String = encrypt_data_with_user_key(name, &user_key)?;
|
|
let name_hash: String = hash_element(name);
|
|
let encrypted_description: String = if let Some(description) = description { encrypt_data_with_user_key(description, &user_key)? } else { String::new() };
|
|
let encrypted_appearance: String = if let Some(appearance) = appearance { encrypt_data_with_user_key(appearance, &user_key)? } else { String::new() };
|
|
let tags_json: String = serde_json::to_string(&tags.unwrap_or_default()).unwrap_or_else(|_| "[]".to_string());
|
|
let encrypted_tags: String = encrypt_data_with_user_key(&tags_json, &user_key)?;
|
|
let encrypted_power_level: Option<String> = if let Some(power_level) = power_level { Some(encrypt_data_with_user_key(power_level, &user_key)?) } else { None };
|
|
let encrypted_components: Option<String> = if let Some(components) = components { Some(encrypt_data_with_user_key(components, &user_key)?) } else { None };
|
|
let encrypted_limitations: Option<String> = if let Some(limitations) = limitations { Some(encrypt_data_with_user_key(limitations, &user_key)?) } else { None };
|
|
let encrypted_notes: Option<String> = if let Some(notes) = notes { Some(encrypt_data_with_user_key(notes, &user_key)?) } else { None };
|
|
let last_update: i64 = timestamp_in_seconds();
|
|
|
|
repo::update_spell(
|
|
conn, user_id, spell_id, &encrypted_name, &name_hash,
|
|
&encrypted_description, &encrypted_appearance, &encrypted_tags,
|
|
encrypted_power_level.as_deref(), encrypted_components.as_deref(),
|
|
encrypted_limitations.as_deref(), encrypted_notes.as_deref(), last_update, lang,
|
|
)
|
|
}
|
|
|
|
/// Deletes a spell.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `spell_id` - The unique identifier of the spell
|
|
/// * `deleted_at` - The timestamp of deletion
|
|
/// * `lang` - The language for error messages
|
|
/// Returns true if successful.
|
|
pub fn delete_spell(conn: &Connection, user_id: &str, spell_id: &str, deleted_at: i64, lang: Lang) -> AppResult<bool> {
|
|
let deleted: bool = repo::delete_spell(conn, user_id, spell_id, lang)?;
|
|
if deleted {
|
|
tombstone_repo::insert(conn, spell_id, "series_spells", spell_id, None, user_id, deleted_at, lang)?;
|
|
}
|
|
Ok(deleted)
|
|
}
|
|
|
|
/// Adds a new tag to a series.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `series_id` - The unique identifier of the series
|
|
/// * `name` - The name of the tag
|
|
/// * `lang` - The language for error messages
|
|
/// * `color` - The color of the tag (optional)
|
|
/// Returns the new tag ID.
|
|
pub fn add_tag(
|
|
conn: &Connection, user_id: &str, series_id: &str, name: &str, lang: Lang, color: Option<&str>,
|
|
) -> AppResult<String> {
|
|
let user_key: String = get_user_encryption_key(user_id)?;
|
|
let tag_id: String = create_unique_id(None);
|
|
let encrypted_name: String = encrypt_data_with_user_key(name, &user_key)?;
|
|
let hashed_name: String = hash_element(name);
|
|
let last_update: i64 = timestamp_in_seconds();
|
|
|
|
repo::insert_tag(conn, &tag_id, series_id, user_id, &encrypted_name, &hashed_name, color, last_update, lang)?;
|
|
|
|
Ok(tag_id)
|
|
}
|
|
|
|
/// Updates an existing tag.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `tag_id` - The unique identifier of the tag
|
|
/// * `name` - The new name of the tag
|
|
/// * `lang` - The language for error messages
|
|
/// * `color` - The new color of the tag (optional)
|
|
/// Returns true if successful.
|
|
pub fn update_tag(
|
|
conn: &Connection, user_id: &str, tag_id: &str, name: &str, lang: Lang, color: Option<&str>,
|
|
) -> AppResult<bool> {
|
|
let user_key: String = get_user_encryption_key(user_id)?;
|
|
let encrypted_name: String = encrypt_data_with_user_key(name, &user_key)?;
|
|
let hashed_name: String = hash_element(name);
|
|
let last_update: i64 = timestamp_in_seconds();
|
|
|
|
repo::update_tag(conn, user_id, tag_id, &encrypted_name, &hashed_name, color, last_update, lang)
|
|
}
|
|
|
|
/// Deletes a tag.
|
|
/// * `conn` - Database connection
|
|
/// * `user_id` - The unique identifier of the user
|
|
/// * `tag_id` - The unique identifier of the tag
|
|
/// * `deleted_at` - The timestamp of deletion
|
|
/// * `lang` - The language for error messages
|
|
/// Returns true if successful.
|
|
pub fn delete_tag(conn: &Connection, user_id: &str, tag_id: &str, deleted_at: i64, lang: Lang) -> AppResult<bool> {
|
|
let deleted: bool = repo::delete_tag(conn, user_id, tag_id, lang)?;
|
|
if deleted {
|
|
tombstone_repo::insert(conn, tag_id, "series_spell_tags", tag_id, None, user_id, deleted_at, lang)?;
|
|
}
|
|
Ok(deleted)
|
|
}
|