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