Compare commits

..

4 Commits

Author SHA1 Message Date
spinline
09a4c69282 fix(auth): fix MsgPack serialization by adding missing feature in backend and reverting to individual arguments
All checks were successful
Build MIPS Binary / build (push) Successful in 5m15s
2026-02-11 22:03:46 +03:00
spinline
a877e0c393 chore: remove db files from git and update gitignore
All checks were successful
Build MIPS Binary / build (push) Successful in 5m13s
2026-02-11 21:54:15 +03:00
spinline
fd65df2962 fix(setup): add logging and error details for setup debugging
Some checks failed
Build MIPS Binary / build (push) Has been cancelled
2026-02-11 21:53:53 +03:00
spinline
9d160a7ef5 fix(ui): use thread_local for toast signal to fix context issue
All checks were successful
Build MIPS Binary / build (push) Successful in 5m12s
2026-02-11 21:43:06 +03:00
9 changed files with 65 additions and 15 deletions

6
.gitignore vendored
View File

@@ -8,3 +8,9 @@ backend.log
.runner
.env
backend/.env
*.db
*.db-shm
*.db-wal
*.sqlite
*.sqlite-shm
*.sqlite-wal

1
Cargo.lock generated
View File

@@ -3761,6 +3761,7 @@ dependencies = [
"struct-patch",
"thiserror 2.0.18",
"tokio",
"tracing",
"utoipa",
]

View File

@@ -44,6 +44,6 @@ tower_governor = "0.8.0"
governor = "0.10.4"
# Leptos
leptos = { version = "0.8.15", features = ["nightly"] }
leptos = { version = "0.8.15", features = ["nightly", "msgpack"] }
leptos_axum = { version = "0.8.7" }
jsonwebtoken = "9"

View File

@@ -41,7 +41,8 @@ pub fn Setup() -> impl IntoView {
}
Err(e) => {
log::error!("Setup failed: {:?}", e);
error.1.set(Some("Kurulum sırasında bir hata oluştu".to_string()));
// Hatanın sadece mesaj kısmını almaya çalışalım, yoksa full struct basılabilir
error.1.set(Some(format!("Hata: {}", e)));
loading.1.set(false);
}
}

View File

@@ -138,8 +138,18 @@ pub fn SonnerList(
}
}
// Thread local storage for global access without Context
thread_local! {
static TOASTS: std::cell::RefCell<Option<RwSignal<Vec<ToastData>>>> = std::cell::RefCell::new(None);
}
pub fn provide_toaster() {
let toasts = RwSignal::new(Vec::<ToastData>::new());
// Set global thread_local
TOASTS.with(|t| *t.borrow_mut() = Some(toasts));
// Also provide context for components
provide_context(ToasterStore { toasts });
}
@@ -191,7 +201,9 @@ pub fn Toaster(#[prop(default = SonnerPosition::default())] position: SonnerPosi
// Global Helper Functions
pub fn toast(title: impl Into<String>, variant: ToastType) {
if let Some(store) = use_context::<ToasterStore>() {
let signal_opt = TOASTS.with(|t| *t.borrow());
if let Some(toasts) = signal_opt {
let id = js_sys::Math::random().to_bits();
let new_toast = ToastData {
id,
@@ -201,18 +213,16 @@ pub fn toast(title: impl Into<String>, variant: ToastType) {
duration: 4000,
};
store.toasts.update(|t| t.push(new_toast.clone()));
toasts.update(|t| t.push(new_toast.clone()));
// Auto remove after duration
let duration = new_toast.duration;
leptos::task::spawn_local(async move {
gloo_timers::future::TimeoutFuture::new(duration as u32).await;
if let Some(store) = use_context::<ToasterStore>() {
store.toasts.update(|vec| vec.retain(|t| t.id != id));
}
toasts.update(|vec| vec.retain(|t| t.id != id));
});
} else {
gloo_console::warn!("ToasterStore not found. Make sure <Toaster /> is mounted.");
gloo_console::warn!("ToasterStore not found (global static). Make sure provide_toaster() is called.");
}
}

View File

@@ -10,6 +10,7 @@ struct-patch = "0.5"
rmp-serde = "1.3"
bytes = "1"
http = "1"
tracing = "0.1"
# Leptos 0.8.7
leptos = { version = "0.8.15", features = ["nightly", "msgpack"] }

View File

@@ -28,8 +28,17 @@ impl Db {
}
async fn run_migrations(&self) -> Result<()> {
sqlx::migrate!("./migrations").run(&self.pool).await?;
Ok(())
tracing::info!("Starting database migrations...");
match sqlx::migrate!("./migrations").run(&self.pool).await {
Ok(_) => {
tracing::info!("Database migrations completed successfully.");
Ok(())
}
Err(e) => {
tracing::error!("Database migration failed: {}", e);
Err(e.into())
}
}
}
// --- User Operations ---

View File

@@ -24,9 +24,19 @@ pub struct SetupStatus {
pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
use crate::DbContext;
let db_context = use_context::<DbContext>().ok_or_else(|| ServerFnError::new("DB Context missing"))?;
tracing::info!("Checking setup status...");
let db_context = use_context::<DbContext>().ok_or_else(|| {
tracing::error!("DB Context missing in GetSetupStatus");
ServerFnError::new("DB Context missing")
})?;
let has_users = db_context.db.has_users().await
.map_err(|e| ServerFnError::new(format!("DB error: {}", e)))?;
.map_err(|e| {
tracing::error!("DB error in GetSetupStatus: {}", e);
ServerFnError::new(format!("DB error: {}", e))
})?;
tracing::info!("Setup status: completed={}", has_users);
Ok(SetupStatus {
completed: has_users,
@@ -37,21 +47,33 @@ pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
pub async fn setup(username: String, password: String) -> Result<(), ServerFnError> {
use crate::DbContext;
let db_context = use_context::<DbContext>().ok_or_else(|| ServerFnError::new("DB Context missing"))?;
tracing::info!("Attempting setup for user: {}", username);
let db_context = use_context::<DbContext>().ok_or_else(|| {
tracing::error!("DB Context missing in Setup");
ServerFnError::new("DB Context missing")
})?;
// Check if setup is already done
let has_users = db_context.db.has_users().await.unwrap_or(false);
if has_users {
tracing::warn!("Setup attempt blocked: Setup already completed");
return Err(ServerFnError::new("Setup already completed"));
}
// Hash password (low cost for MIPS)
let password_hash = bcrypt::hash(&password, 6)
.map_err(|_| ServerFnError::new("Hashing error"))?;
.map_err(|e| {
tracing::error!("Hashing error: {}", e);
ServerFnError::new("Hashing error")
})?;
db_context.db.create_user(&username, &password_hash).await
.map_err(|e| ServerFnError::new(format!("DB error: {}", e)))?;
.map_err(|e| {
tracing::error!("Failed to create user: {}", e);
ServerFnError::new(format!("DB error: {}", e))
})?;
tracing::info!("Setup completed successfully for user: {}", username);
Ok(())
}

Binary file not shown.