chio_openapi/
extensions.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "lowercase")]
12pub enum Sensitivity {
13 Public,
15 #[default]
17 Internal,
18 Sensitive,
20 Restricted,
22}
23
24#[derive(Debug, Clone, Default)]
26pub struct ChioExtensions {
27 pub sensitivity: Option<Sensitivity>,
29 pub side_effects: Option<bool>,
32 pub approval_required: Option<bool>,
34 pub budget_limit: Option<u64>,
37 pub publish: Option<bool>,
40}
41
42impl ChioExtensions {
43 pub fn from_operation(obj: &serde_json::Value) -> Self {
46 let map = match obj.as_object() {
47 Some(m) => m,
48 None => return Self::default(),
49 };
50
51 Self {
52 sensitivity: map
53 .get("x-chio-sensitivity")
54 .and_then(|v| v.as_str())
55 .and_then(|s| match s {
56 "public" => Some(Sensitivity::Public),
57 "internal" => Some(Sensitivity::Internal),
58 "sensitive" => Some(Sensitivity::Sensitive),
59 "restricted" => Some(Sensitivity::Restricted),
60 _ => None,
61 }),
62 side_effects: map.get("x-chio-side-effects").and_then(|v| v.as_bool()),
63 approval_required: map
64 .get("x-chio-approval-required")
65 .and_then(|v| v.as_bool()),
66 budget_limit: map.get("x-chio-budget-limit").and_then(|v| v.as_u64()),
67 publish: map.get("x-chio-publish").and_then(|v| v.as_bool()),
68 }
69 }
70
71 pub fn should_publish(&self) -> bool {
74 self.publish.unwrap_or(true)
75 }
76}
77
78#[cfg(test)]
79#[allow(clippy::unwrap_used, clippy::expect_used)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn empty_object() {
85 let val = serde_json::json!({});
86 let ext = ChioExtensions::from_operation(&val);
87 assert!(ext.sensitivity.is_none());
88 assert!(ext.side_effects.is_none());
89 assert!(ext.approval_required.is_none());
90 assert!(ext.budget_limit.is_none());
91 assert!(ext.publish.is_none());
92 assert!(ext.should_publish());
93 }
94
95 #[test]
96 fn all_fields_present() {
97 let val = serde_json::json!({
98 "x-chio-sensitivity": "restricted",
99 "x-chio-side-effects": true,
100 "x-chio-approval-required": true,
101 "x-chio-budget-limit": 5000,
102 "x-chio-publish": false
103 });
104 let ext = ChioExtensions::from_operation(&val);
105 assert_eq!(ext.sensitivity, Some(Sensitivity::Restricted));
106 assert_eq!(ext.side_effects, Some(true));
107 assert_eq!(ext.approval_required, Some(true));
108 assert_eq!(ext.budget_limit, Some(5000));
109 assert_eq!(ext.publish, Some(false));
110 assert!(!ext.should_publish());
111 }
112
113 #[test]
114 fn unknown_sensitivity_ignored() {
115 let val = serde_json::json!({ "x-chio-sensitivity": "unknown" });
116 let ext = ChioExtensions::from_operation(&val);
117 assert!(ext.sensitivity.is_none());
118 }
119
120 #[test]
121 fn non_object_returns_default() {
122 let val = serde_json::json!("not an object");
123 let ext = ChioExtensions::from_operation(&val);
124 assert!(ext.sensitivity.is_none());
125 }
126
127 #[test]
128 fn sensitivity_serde_roundtrip() {
129 let s = Sensitivity::Sensitive;
130 let json = serde_json::to_string(&s).unwrap();
131 assert_eq!(json, "\"sensitive\"");
132 let back: Sensitivity = serde_json::from_str(&json).unwrap();
133 assert_eq!(back, s);
134 }
135}