diff --git a/crates/api/src/admin_objects.rs b/crates/api/src/admin_objects.rs index ef32f2d..6664dbf 100644 --- a/crates/api/src/admin_objects.rs +++ b/crates/api/src/admin_objects.rs @@ -45,6 +45,10 @@ pub(crate) struct AdminObjectView { /// Flexible field values (key -> value). #[schema(value_type = std::collections::HashMap)] pub fields: serde_json::Value, + /// RFC3339 UTC timestamp. + pub created_at: String, + /// RFC3339 UTC timestamp. + pub updated_at: String, } impl AdminObjectView { @@ -61,6 +65,14 @@ impl AdminObjectView { recording_date: o.recording_date.map(format_date), visibility: o.visibility.as_str().to_owned(), fields: o.fields.clone(), + created_at: o + .created_at + .format(&time::format_description::well_known::Rfc3339) + .unwrap_or_default(), + updated_at: o + .updated_at + .format(&time::format_description::well_known::Rfc3339) + .unwrap_or_default(), } } } diff --git a/crates/api/tests/admin_catalog.rs b/crates/api/tests/admin_catalog.rs index a8d957c..0c998ae 100644 --- a/crates/api/tests/admin_catalog.rs +++ b/crates/api/tests/admin_catalog.rs @@ -843,6 +843,40 @@ async fn delete_field_definition_referenced_is_409(pool: PgPool) { assert_eq!(body["count"], 1); } +#[sqlx::test(migrations = "../db/migrations")] +async fn listed_object_carries_timestamps(pool: PgPool) { + migrate_sessions(&db::Db::from_pool(pool.clone())) + .await + .unwrap(); + + seed_user(&pool, "ed@example.com", "pw-editor-123", Role::Editor).await; + + let app = build_app(state(pool)); + let cookie = login(&app, "ed@example.com", "pw-editor-123").await; + + let created = send( + &app, + &cookie, + "POST", + "/api/admin/objects", + Some(r#"{"object_number":"TS-1","object_name":"clock","number_of_objects":1,"visibility":"draft"}"#), + ) + .await; + assert_eq!(created.status(), StatusCode::CREATED); + + let list = send(&app, &cookie, "GET", "/api/admin/objects", None).await; + assert_eq!(list.status(), StatusCode::OK); + + let body: serde_json::Value = + serde_json::from_slice(&list.into_body().collect().await.unwrap().to_bytes()).unwrap(); + + let item = &body["items"][0]; + let created_at = item["created_at"].as_str().unwrap(); + let updated_at = item["updated_at"].as_str().unwrap(); + assert!(!created_at.is_empty(), "created_at must be non-empty"); + assert!(!updated_at.is_empty(), "updated_at must be non-empty"); +} + #[sqlx::test(migrations = "../db/migrations")] async fn field_definition_edit_delete_requires_auth(pool: PgPool) { migrate_sessions(&db::Db::from_pool(pool.clone()))