- 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.
240 lines
11 KiB
Rust
240 lines
11 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use tauri::State;
|
|
|
|
use crate::db::connection::DbManager;
|
|
use crate::domains::chapter::service;
|
|
use crate::error::AppError;
|
|
use crate::helpers::timestamp_in_seconds;
|
|
use crate::shared::session::SessionState;
|
|
use crate::shared::types::Lang;
|
|
|
|
fn get_session(session: &State<SessionState>) -> Result<(String, Lang), AppError> {
|
|
let session_guard = session.lock().map_err(|e| AppError::Internal(format!("Session lock failed: {}", e)))?;
|
|
let user_id = session_guard.get_user_id().map_err(|e| AppError::Auth(e))?.to_string();
|
|
let lang = session_guard.lang;
|
|
Ok((user_id, lang))
|
|
}
|
|
|
|
// ─── Queries ──────────────────────────────────────────
|
|
|
|
#[tauri::command]
|
|
pub fn get_chapters(book_id: String, db: State<DbManager>, session: State<SessionState>) -> Result<Vec<service::ChapterProps>, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::get_all_chapters_from_a_book(conn, &user_id, &book_id, lang)
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct GetWholeChapterData {
|
|
pub id: String,
|
|
pub version: i64,
|
|
pub book_id: String,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_whole_chapter(data: GetWholeChapterData, db: State<DbManager>, session: State<SessionState>) -> Result<service::ChapterProps, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::get_whole_chapter(conn, &user_id, &data.id, data.version, Some(&data.book_id), lang)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_chapter_story(chapter_id: String, db: State<DbManager>, session: State<SessionState>) -> Result<Vec<service::ActStory>, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::get_chapter_story(conn, &user_id, &chapter_id, lang)
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct GetCompanionData {
|
|
pub chapter_id: String,
|
|
pub version: i64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_companion_content(data: GetCompanionData, db: State<DbManager>, session: State<SessionState>) -> Result<service::CompanionContent, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::get_companion_content(conn, &user_id, &data.chapter_id, data.version, lang)
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct GetChapterContentData {
|
|
pub chapter_id: String,
|
|
pub version: i64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_chapter_content(data: GetChapterContentData, db: State<DbManager>, session: State<SessionState>) -> Result<String, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::get_chapter_content_by_version(conn, &user_id, &data.chapter_id, data.version, lang)
|
|
}
|
|
|
|
// ─── Mutations ────────────────────────────────────────
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SaveChapterContentData {
|
|
pub chapter_id: String,
|
|
pub version: i64,
|
|
pub content: Value,
|
|
pub total_word_count: i64,
|
|
pub content_id: String,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn save_chapter_content(data: SaveChapterContentData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
let content_str = serde_json::to_string(&data.content).map_err(|e| AppError::Internal(format!("JSON serialize failed: {}", e)))?;
|
|
service::save_chapter_content(conn, &user_id, &data.chapter_id, data.version, &content_str, data.total_word_count, timestamp_in_seconds(), lang)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_last_chapter(book_id: String, db: State<DbManager>, session: State<SessionState>) -> Result<Option<service::ChapterProps>, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::get_last_chapter(conn, &user_id, &book_id, lang)
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct AddChapterData {
|
|
pub book_id: String,
|
|
pub title: String,
|
|
pub chapter_order: i64,
|
|
pub chapter_id: Option<String>,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn add_chapter(data: AddChapterData, db: State<DbManager>, session: State<SessionState>) -> Result<String, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::add_chapter(conn, &user_id, &data.book_id, &data.title, 0, data.chapter_order, lang, data.chapter_id.as_deref())
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct RemoveChapterData {
|
|
pub chapter_id: String,
|
|
pub book_id: String,
|
|
pub deleted_at: i64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn remove_chapter(data: RemoveChapterData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::remove_chapter(conn, &user_id, &data.book_id, &data.chapter_id, data.deleted_at, lang)
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct UpdateChapterData {
|
|
pub chapter_id: String,
|
|
pub title: String,
|
|
pub chapter_order: i64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn update_chapter(data: UpdateChapterData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::update_chapter(conn, &user_id, &data.chapter_id, &data.title, data.chapter_order, lang)
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct AddChapterInfoData {
|
|
pub chapter_id: String,
|
|
pub act_id: i64,
|
|
pub book_id: String,
|
|
pub plot_id: Option<String>,
|
|
pub incident_id: Option<String>,
|
|
pub chapter_info_id: Option<String>,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn add_chapter_information(data: AddChapterInfoData, db: State<DbManager>, session: State<SessionState>) -> Result<String, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::add_chapter_information(conn, &user_id, &data.chapter_id, data.act_id, &data.book_id, data.plot_id.as_deref(), data.incident_id.as_deref(), lang, data.chapter_info_id.as_deref())
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct RemoveChapterInfoData {
|
|
pub chapter_info_id: String,
|
|
pub book_id: String,
|
|
pub deleted_at: i64,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn remove_chapter_information(data: RemoveChapterInfoData, db: State<DbManager>, session: State<SessionState>) -> Result<bool, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
service::remove_chapter_information(conn, &user_id, &data.book_id, &data.chapter_info_id, data.deleted_at, lang)
|
|
}
|
|
|
|
// ─── Book Tags (aggregate) ───────────────────────────
|
|
|
|
#[derive(Serialize)]
|
|
pub struct Tag {
|
|
pub label: String,
|
|
pub value: String,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct BookTags {
|
|
pub characters: Vec<Tag>,
|
|
pub locations: Vec<Tag>,
|
|
pub objects: Vec<Tag>,
|
|
pub world_elements: Vec<Tag>,
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn get_book_tags(book_id: String, db: State<DbManager>, session: State<SessionState>) -> Result<BookTags, AppError> {
|
|
let (user_id, lang) = get_session(&session)?;
|
|
let db_manager = db.lock().map_err(|e| AppError::Internal(format!("DB lock failed: {}", e)))?;
|
|
let conn = db_manager.get_connection(&user_id)?;
|
|
|
|
let character_response = crate::domains::character::service::get_character_list(conn, &user_id, &book_id, lang)?;
|
|
let character_tags: Vec<Tag> = character_response.characters.into_iter().map(|character| Tag { label: character.name, value: character.id }).collect();
|
|
|
|
let location_elements = crate::domains::location::service::get_location_tags(conn, &user_id, &book_id, lang)?;
|
|
let location_tags: Vec<Tag> = location_elements.into_iter().map(|element| Tag { label: element.name, value: element.id }).collect();
|
|
|
|
let spell_response = crate::domains::spell::service::get_spell_list(conn, &user_id, &book_id, lang)?;
|
|
let object_tags: Vec<Tag> = spell_response.spells.into_iter().map(|spell| Tag { label: spell.name, value: spell.id }).collect();
|
|
|
|
let world_response = crate::domains::world::service::get_worlds(conn, &user_id, &book_id, lang)?;
|
|
let mut world_tags: Vec<Tag> = Vec::new();
|
|
for world in &world_response.worlds {
|
|
for element_list in [&world.laws, &world.biomes, &world.issues, &world.customs, &world.kingdoms, &world.climate, &world.resources, &world.wildlife, &world.arts, &world.ethnic_groups, &world.social_classes, &world.important_characters] {
|
|
for element in element_list {
|
|
world_tags.push(Tag { label: element.name.clone(), value: element.id.clone() });
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(BookTags { characters: character_tags, locations: location_tags, objects: object_tags, world_elements: world_tags })
|
|
}
|