feat(api): expose object created_at/updated_at in AdminObjectView (#44)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-06 23:17:50 +02:00
parent e7ff817c63
commit 5efa7b8a16
2 changed files with 46 additions and 0 deletions
+12
View File
@@ -45,6 +45,10 @@ pub(crate) struct AdminObjectView {
/// Flexible field values (key -> value). /// Flexible field values (key -> value).
#[schema(value_type = std::collections::HashMap<String, serde_json::Value>)] #[schema(value_type = std::collections::HashMap<String, serde_json::Value>)]
pub fields: serde_json::Value, pub fields: serde_json::Value,
/// RFC3339 UTC timestamp.
pub created_at: String,
/// RFC3339 UTC timestamp.
pub updated_at: String,
} }
impl AdminObjectView { impl AdminObjectView {
@@ -61,6 +65,14 @@ impl AdminObjectView {
recording_date: o.recording_date.map(format_date), recording_date: o.recording_date.map(format_date),
visibility: o.visibility.as_str().to_owned(), visibility: o.visibility.as_str().to_owned(),
fields: o.fields.clone(), 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(),
} }
} }
} }
+34
View File
@@ -843,6 +843,40 @@ async fn delete_field_definition_referenced_is_409(pool: PgPool) {
assert_eq!(body["count"], 1); 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")] #[sqlx::test(migrations = "../db/migrations")]
async fn field_definition_edit_delete_requires_auth(pool: PgPool) { async fn field_definition_edit_delete_requires_auth(pool: PgPool) {
migrate_sessions(&db::Db::from_pool(pool.clone())) migrate_sessions(&db::Db::from_pool(pool.clone()))