From eb646505941f07f688c0aa2e9cea160edca0d016 Mon Sep 17 00:00:00 2001 From: qaz741wsd856 Date: Sun, 30 Nov 2025 17:20:26 +0000 Subject: [PATCH] fix: update user timestamp after data modifications --- src/db.rs | 19 ++++++++++++++++++- src/handlers/ciphers.rs | 18 ++++++++++++++++++ src/handlers/folders.rs | 8 +++++++- src/handlers/import.rs | 4 +++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/db.rs b/src/db.rs index 603ec99..570d3f5 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,11 +1,28 @@ use crate::error::AppError; +use chrono::Utc; use std::sync::Arc; -use worker::{D1Database, D1PreparedStatement, Env}; +use worker::{query, D1Database, D1PreparedStatement, Env}; pub fn get_db(env: &Arc) -> Result { env.d1("vault1").map_err(AppError::Worker) } +/// Update the user's `updated_at` field to the current timestamp. +/// This should be called after any operation that modifies user data (ciphers, folders, etc.) +pub async fn touch_user_updated_at(db: &D1Database, user_id: &str) -> Result<(), AppError> { + let now = Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string(); + query!( + db, + "UPDATE users SET updated_at = ?1 WHERE id = ?2", + now, + user_id + ) + .map_err(|_| AppError::Database)? + .run() + .await?; + Ok(()) +} + /// Execute D1 statements in batches, allowing batch_size 0 to run everything at once. pub async fn execute_in_batches( db: &D1Database, diff --git a/src/handlers/ciphers.rs b/src/handlers/ciphers.rs index 60b9e86..ee33a81 100644 --- a/src/handlers/ciphers.rs +++ b/src/handlers/ciphers.rs @@ -79,6 +79,8 @@ pub async fn create_cipher( .run() .await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(cipher)) } @@ -155,6 +157,8 @@ pub async fn update_cipher( .run() .await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(cipher)) } @@ -187,6 +191,8 @@ pub async fn soft_delete_cipher( .run() .await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(())) } @@ -217,6 +223,8 @@ pub async fn soft_delete_ciphers_bulk( db::execute_in_batches(&db, statements, batch_size).await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(())) } @@ -240,6 +248,8 @@ pub async fn hard_delete_cipher( .run() .await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(())) } @@ -268,6 +278,8 @@ pub async fn hard_delete_ciphers_bulk( db::execute_in_batches(&db, statements, batch_size).await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(())) } @@ -306,6 +318,8 @@ pub async fn restore_cipher( .await? .ok_or(AppError::NotFound("Cipher not found".to_string()))?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(cipher_db.into())) } @@ -364,6 +378,8 @@ pub async fn restore_ciphers_bulk( } } + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(BulkRestoreResponse { data: restored_ciphers, object: "list".to_string(), @@ -435,5 +451,7 @@ pub async fn create_cipher_simple( .run() .await?; + db::touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(cipher)) } diff --git a/src/handlers/folders.rs b/src/handlers/folders.rs index d7e82c8..15dc035 100644 --- a/src/handlers/folders.rs +++ b/src/handlers/folders.rs @@ -5,7 +5,7 @@ use uuid::Uuid; use worker::{query, Env}; use crate::auth::Claims; -use crate::db; +use crate::db::{self, touch_user_updated_at}; use crate::error::AppError; use crate::models::folder::{CreateFolderRequest, Folder, FolderResponse}; use axum::extract::Path; @@ -41,6 +41,8 @@ pub async fn create_folder( .run() .await?; + touch_user_updated_at(&db, &claims.sub).await?; + let response = FolderResponse { id: folder.id, name: folder.name, @@ -69,6 +71,8 @@ pub async fn delete_folder( .run() .await?; + touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(())) } #[worker::send] @@ -113,6 +117,8 @@ pub async fn update_folder( .run() .await?; + touch_user_updated_at(&db, &claims.sub).await?; + let response = FolderResponse { id: folder.id, name: folder.name, diff --git a/src/handlers/import.rs b/src/handlers/import.rs index a15d6db..b88bb41 100644 --- a/src/handlers/import.rs +++ b/src/handlers/import.rs @@ -5,7 +5,7 @@ use uuid::Uuid; use worker::{query, D1PreparedStatement, Env}; use crate::auth::Claims; -use crate::db; +use crate::db::{self, touch_user_updated_at}; use crate::error::AppError; use crate::models::cipher::{Cipher, CipherData}; use crate::models::folder::Folder; @@ -125,5 +125,7 @@ pub async fn import_data( // Execute cipher inserts in batches db::execute_in_batches(&db, cipher_statements, batch_size).await?; + touch_user_updated_at(&db, &claims.sub).await?; + Ok(Json(())) } \ No newline at end of file