mirror of
https://github.com/telemt/telemt.git
synced 2026-05-22 19:51:43 +03:00
feat(api): support null-removal in PATCH /v1/users/{user}
PatchUserRequest now uses Patch<T> for the five removable fields (user_ad_tag, max_tcp_conns, expiration_rfc3339, data_quota_bytes, max_unique_ips). Sending JSON null drops the entry from the corresponding access HashMap; sending 0 is preserved as a literal limit; omitted fields stay untouched. The handler synchronises the in-memory ip_tracker on both set and remove of max_unique_ips. A helper parse_patch_expiration mirrors parse_optional_expiration for the new three-state field. Runtime semantics are unchanged.
This commit is contained in:
@@ -41,6 +41,8 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::api::model::{PatchUserRequest, parse_patch_expiration};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -76,4 +78,53 @@ mod tests {
|
||||
let h = parse(r#"{"value": 0}"#);
|
||||
assert!(matches!(h.value, Patch::Set(0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_patch_expiration_passes_unchanged_and_remove_through() {
|
||||
assert!(matches!(
|
||||
parse_patch_expiration(&Patch::Unchanged),
|
||||
Ok(Patch::Unchanged)
|
||||
));
|
||||
assert!(matches!(
|
||||
parse_patch_expiration(&Patch::Remove),
|
||||
Ok(Patch::Remove)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_patch_expiration_parses_set_value() {
|
||||
let parsed =
|
||||
parse_patch_expiration(&Patch::Set("2030-01-02T03:04:05Z".into())).expect("valid");
|
||||
match parsed {
|
||||
Patch::Set(dt) => {
|
||||
assert_eq!(dt, Utc.with_ymd_and_hms(2030, 1, 2, 3, 4, 5).unwrap());
|
||||
}
|
||||
other => panic!("expected Patch::Set, got {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_patch_expiration_rejects_invalid_set_value() {
|
||||
assert!(parse_patch_expiration(&Patch::Set("not-a-date".into())).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn patch_user_request_deserializes_mixed_states() {
|
||||
let raw = r#"{
|
||||
"secret": "00112233445566778899aabbccddeeff",
|
||||
"max_tcp_conns": 0,
|
||||
"max_unique_ips": null,
|
||||
"data_quota_bytes": 1024
|
||||
}"#;
|
||||
let req: PatchUserRequest = serde_json::from_str(raw).expect("valid json");
|
||||
assert_eq!(
|
||||
req.secret.as_deref(),
|
||||
Some("00112233445566778899aabbccddeeff")
|
||||
);
|
||||
assert!(matches!(req.max_tcp_conns, Patch::Set(0)));
|
||||
assert!(matches!(req.max_unique_ips, Patch::Remove));
|
||||
assert!(matches!(req.data_quota_bytes, Patch::Set(1024)));
|
||||
assert!(matches!(req.expiration_rfc3339, Patch::Unchanged));
|
||||
assert!(matches!(req.user_ad_tag, Patch::Unchanged));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user