From 866658343518f5d57528db41f89dbe32fac6efd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Mon, 20 Jul 2026 20:45:20 +0200 Subject: [PATCH] multidb --- docker-compose.yml | 2 +- src/api.rs | 20 ++++++++++++++++++-- src/db.rs | 24 ++++++++++++++++++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 80dcd09..6f697e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,7 +37,7 @@ services: retries: 20 mysql: - image: mysql:8.4 + image: mysql:8 profiles: ["mysql"] environment: MYSQL_DATABASE: ${MYSQL_DATABASE:-rustpad} diff --git a/src/api.rs b/src/api.rs index f444947..38620e2 100644 --- a/src/api.rs +++ b/src/api.rs @@ -205,7 +205,15 @@ pub async fn history( ) -> Result>, ApiError> { let (workspace, note) = authorized_note(&state, &workspace_slug, ¬e_slug, payload.password.as_deref()).await?; let _ = workspace; - Ok(Json(db::list_revisions(&state.db, note.id).await?)) + let revisions = db::list_revisions(&state.db, note.id) + .await? + .into_iter() + .map(|mut revision| { + revision.created_at = db::normalize_timestamp(&revision.created_at); + revision + }) + .collect(); + Ok(Json(revisions)) } pub async fn restore( @@ -434,7 +442,15 @@ pub async fn pad_history( Json(payload): Json, ) -> Result>, ApiError> { let pad = authorized_pad(&state, &slug, payload.password.as_deref()).await?; - Ok(Json(db::list_pad_revisions(&state.db, pad.id).await?)) + let revisions = db::list_pad_revisions(&state.db, pad.id) + .await? + .into_iter() + .map(|mut revision| { + revision.created_at = db::normalize_timestamp(&revision.created_at); + revision + }) + .collect(); + Ok(Json(revisions)) } pub async fn pad_restore( diff --git a/src/db.rs b/src/db.rs index 3e9bdb0..102a1d9 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,7 +1,7 @@ use argon2::{ password_hash::SaltString, Argon2, PasswordHash, PasswordHasher, PasswordVerifier, }; -use chrono::{DateTime, Utc}; +use chrono::{DateTime, NaiveDateTime, Utc}; use rand_core::{OsRng, RngCore}; use serde::Serialize; use sqlx::FromRow; @@ -198,9 +198,25 @@ fn hash_password(password: &str) -> String { } pub fn normalize_timestamp(value: &str) -> String { - DateTime::parse_from_rfc3339(value) - .map(|dt| dt.with_timezone(&Utc).to_rfc3339()) - .unwrap_or_else(|_| value.replace(' ', "T") + "Z") + let value = value.trim(); + + if let Ok(timestamp) = DateTime::parse_from_rfc3339(value) { + return timestamp.with_timezone(&Utc).to_rfc3339(); + } + + for format in ["%Y-%m-%d %H:%M:%S%.f%:z", "%Y-%m-%d %H:%M:%S%.f%#z"] { + if let Ok(timestamp) = DateTime::parse_from_str(value, format) { + return timestamp.with_timezone(&Utc).to_rfc3339(); + } + } + + for format in ["%Y-%m-%d %H:%M:%S%.f", "%Y-%m-%dT%H:%M:%S%.f"] { + if let Ok(timestamp) = NaiveDateTime::parse_from_str(value, format) { + return timestamp.and_utc().to_rfc3339(); + } + } + + value.to_string() } #[derive(Debug, Clone, FromRow)]