1use crate::Widget;
4use crate::field::{FieldError, FieldResult, FormField};
5use serde_json::{self, Value};
6
7const DEFAULT_MAX_DEPTH: usize = 64;
34
35#[derive(Debug, Clone)]
36pub struct JSONField {
37 pub name: String,
38 pub required: bool,
39 pub error_messages: std::collections::HashMap<String, String>,
40 pub widget: Widget,
41 pub help_text: String,
42 pub initial: Option<Value>,
43 pub require_object: bool,
45 pub require_array: bool,
47 pub required_keys: Vec<String>,
49 pub max_depth: usize,
51}
52
53impl JSONField {
54 pub fn new(name: impl Into<String>) -> Self {
66 let mut error_messages = std::collections::HashMap::new();
67 error_messages.insert(
68 "required".to_string(),
69 "This field is required.".to_string(),
70 );
71 error_messages.insert("invalid".to_string(), "Enter valid JSON.".to_string());
72 error_messages.insert("invalid_type".to_string(), "Invalid JSON type.".to_string());
73 error_messages.insert(
74 "missing_keys".to_string(),
75 "Missing required keys.".to_string(),
76 );
77
78 Self {
79 name: name.into(),
80 required: true,
81 error_messages,
82 widget: Widget::TextArea,
83 help_text: String::new(),
84 initial: None,
85 require_object: false,
86 require_array: false,
87 required_keys: Vec::new(),
88 max_depth: DEFAULT_MAX_DEPTH,
89 }
90 }
91 pub fn required(mut self, required: bool) -> Self {
92 self.required = required;
93 self
94 }
95 pub fn help_text(mut self, text: impl Into<String>) -> Self {
96 self.help_text = text.into();
97 self
98 }
99 pub fn initial(mut self, value: Value) -> Self {
100 self.initial = Some(value);
101 self
102 }
103 pub fn require_object(mut self) -> Self {
104 self.require_object = true;
105 self
106 }
107 pub fn require_array(mut self) -> Self {
108 self.require_array = true;
109 self
110 }
111 pub fn required_keys(mut self, keys: Vec<String>) -> Self {
112 self.required_keys = keys;
113 self
114 }
115 pub fn max_depth(mut self, depth: usize) -> Self {
120 self.max_depth = depth;
121 self
122 }
123 pub fn error_message(
124 mut self,
125 error_type: impl Into<String>,
126 message: impl Into<String>,
127 ) -> Self {
128 self.error_messages
129 .insert(error_type.into(), message.into());
130 self
131 }
132
133 fn check_depth(value: &Value, max_depth: usize) -> bool {
135 Self::depth_check_recursive(value, 0, max_depth)
136 }
137
138 fn depth_check_recursive(value: &Value, current: usize, max: usize) -> bool {
139 if current > max {
140 return false;
141 }
142 match value {
143 Value::Array(arr) => arr
144 .iter()
145 .all(|v| Self::depth_check_recursive(v, current + 1, max)),
146 Value::Object(map) => map
147 .values()
148 .all(|v| Self::depth_check_recursive(v, current + 1, max)),
149 _ => true,
150 }
151 }
152
153 fn validate_required_keys(&self, obj: &serde_json::Map<String, Value>) -> FieldResult<()> {
155 if self.required_keys.is_empty() {
156 return Ok(());
157 }
158
159 let missing_keys: Vec<&String> = self
160 .required_keys
161 .iter()
162 .filter(|key| !obj.contains_key(*key))
163 .collect();
164
165 if !missing_keys.is_empty() {
166 let error_msg = self
167 .error_messages
168 .get("missing_keys")
169 .cloned()
170 .unwrap_or_else(|| "Missing required keys.".to_string());
171 return Err(FieldError::validation(None, &error_msg));
172 }
173
174 Ok(())
175 }
176}
177
178impl FormField for JSONField {
179 fn name(&self) -> &str {
180 &self.name
181 }
182
183 fn label(&self) -> Option<&str> {
184 None
185 }
186
187 fn widget(&self) -> &Widget {
188 &self.widget
189 }
190
191 fn required(&self) -> bool {
192 self.required
193 }
194
195 fn initial(&self) -> Option<&Value> {
196 self.initial.as_ref()
197 }
198
199 fn help_text(&self) -> Option<&str> {
200 if self.help_text.is_empty() {
201 None
202 } else {
203 Some(&self.help_text)
204 }
205 }
206
207 fn clean(&self, value: Option<&Value>) -> FieldResult<Value> {
208 if value.is_none() || value == Some(&Value::Null) {
210 if self.required {
211 let error_msg = self
212 .error_messages
213 .get("required")
214 .cloned()
215 .unwrap_or_else(|| "This field is required.".to_string());
216 return Err(FieldError::validation(None, &error_msg));
217 }
218 return Ok(Value::Null);
219 }
220
221 let json_str = match value.unwrap() {
222 Value::String(s) => s.as_str(),
223 _ => {
224 let error_msg = self
225 .error_messages
226 .get("invalid")
227 .cloned()
228 .unwrap_or_else(|| "Enter valid JSON.".to_string());
229 return Err(FieldError::validation(None, &error_msg));
230 }
231 };
232
233 if json_str.trim().is_empty() {
235 if self.required {
236 let error_msg = self
237 .error_messages
238 .get("required")
239 .cloned()
240 .unwrap_or_else(|| "This field is required.".to_string());
241 return Err(FieldError::validation(None, &error_msg));
242 }
243 return Ok(Value::Null);
244 }
245
246 let parsed: Value = match serde_json::from_str(json_str) {
248 Ok(v) => v,
249 Err(_) => {
250 let error_msg = self
251 .error_messages
252 .get("invalid")
253 .cloned()
254 .unwrap_or_else(|| "Enter valid JSON.".to_string());
255 return Err(FieldError::validation(None, &error_msg));
256 }
257 };
258
259 if !Self::check_depth(&parsed, self.max_depth) {
261 return Err(FieldError::validation(
262 None,
263 "JSON structure is too deeply nested.",
264 ));
265 }
266
267 if self.require_object && !parsed.is_object() {
269 let error_msg = self
270 .error_messages
271 .get("invalid_type")
272 .cloned()
273 .unwrap_or_else(|| "JSON must be an object.".to_string());
274 return Err(FieldError::validation(None, &error_msg));
275 }
276
277 if self.require_array && !parsed.is_array() {
278 let error_msg = self
279 .error_messages
280 .get("invalid_type")
281 .cloned()
282 .unwrap_or_else(|| "JSON must be an array.".to_string());
283 return Err(FieldError::validation(None, &error_msg));
284 }
285
286 if let Value::Object(ref obj) = parsed {
288 self.validate_required_keys(obj)?;
289 }
290
291 Ok(parsed)
292 }
293
294 fn has_changed(&self, initial: Option<&Value>, data: Option<&Value>) -> bool {
295 match (initial, data) {
296 (None, None) => false,
297 (Some(_), None) | (None, Some(_)) => true,
298 (Some(a), Some(b)) => {
299 let a_normalized = serde_json::to_string(a).unwrap_or_default();
302 let b_normalized = serde_json::to_string(b).unwrap_or_default();
303 a_normalized != b_normalized
304 }
305 }
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312 use serde_json::json;
313
314 #[test]
315 fn test_json_field_valid_object() {
316 let field = JSONField::new("data");
317 let result = field.clean(Some(&json!(r#"{"name": "John", "age": 30}"#)));
318 let value = result.unwrap();
319 assert!(value.is_object());
320 }
321
322 #[test]
323 fn test_json_field_valid_array() {
324 let field = JSONField::new("data");
325 let result = field.clean(Some(&json!(r#"[1, 2, 3, 4, 5]"#)));
326 let value = result.unwrap();
327 assert!(value.is_array());
328 }
329
330 #[test]
331 fn test_json_field_invalid() {
332 let field = JSONField::new("data");
333 let result = field.clean(Some(&json!(r#"{invalid json}"#)));
334 assert!(result.is_err());
335 }
336
337 #[test]
338 fn test_json_field_required() {
339 let field = JSONField::new("data").required(true);
340 let result = field.clean(None);
341 assert!(result.is_err());
342 }
343
344 #[test]
345 fn test_json_field_not_required() {
346 let field = JSONField::new("data").required(false);
347 let result = field.clean(None);
348 assert!(result.is_ok());
349 assert_eq!(result.unwrap(), Value::Null);
350 }
351
352 #[test]
353 fn test_json_field_require_object() {
354 let field = JSONField::new("data").require_object();
355
356 let result = field.clean(Some(&json!(r#"{"key": "value"}"#)));
358 assert!(result.is_ok());
359
360 let result = field.clean(Some(&json!(r#"[1, 2, 3]"#)));
362 assert!(result.is_err());
363 }
364
365 #[test]
366 fn test_json_field_require_array() {
367 let field = JSONField::new("data").require_array();
368
369 let result = field.clean(Some(&json!(r#"[1, 2, 3]"#)));
371 assert!(result.is_ok());
372
373 let result = field.clean(Some(&json!(r#"{"key": "value"}"#)));
375 assert!(result.is_err());
376 }
377
378 #[test]
379 fn test_json_field_required_keys() {
380 let field = JSONField::new("data")
381 .require_object()
382 .required_keys(vec!["name".to_string(), "age".to_string()]);
383
384 let result = field.clean(Some(&json!(
386 r#"{"name": "John", "age": 30, "city": "NYC"}"#
387 )));
388 assert!(result.is_ok());
389
390 let result = field.clean(Some(&json!(r#"{"name": "John"}"#)));
392 assert!(result.is_err());
393 }
394
395 #[test]
396 fn test_json_field_has_changed() {
397 let field = JSONField::new("data");
398
399 assert!(!field.has_changed(
401 Some(&json!({"name": "John"})),
402 Some(&json!({"name": "John"}))
403 ));
404
405 assert!(field.has_changed(
407 Some(&json!({"name": "John"})),
408 Some(&json!({"name": "Jane"}))
409 ));
410
411 assert!(field.has_changed(None, Some(&json!({"name": "John"}))));
413 }
414}