scim_server/resource/value_objects/
name.rs1use crate::error::{ValidationError, ValidationResult};
7use crate::resource::value_objects::value_object_trait::{SchemaConstructible, ValueObject};
8use crate::schema::types::{AttributeDefinition, AttributeType};
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use std::any::Any;
12use std::fmt;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct Name {
53 pub formatted: Option<String>,
54 #[serde(rename = "familyName")]
55 pub family_name: Option<String>,
56 #[serde(rename = "givenName")]
57 pub given_name: Option<String>,
58 #[serde(rename = "middleName")]
59 pub middle_name: Option<String>,
60 #[serde(rename = "honorificPrefix")]
61 pub honorific_prefix: Option<String>,
62 #[serde(rename = "honorificSuffix")]
63 pub honorific_suffix: Option<String>,
64}
65
66impl Name {
67 pub fn new(
86 formatted: Option<String>,
87 family_name: Option<String>,
88 given_name: Option<String>,
89 middle_name: Option<String>,
90 honorific_prefix: Option<String>,
91 honorific_suffix: Option<String>,
92 ) -> ValidationResult<Self> {
93 if let Some(ref f) = formatted {
95 Self::validate_name_component(f, "formatted")?;
96 }
97 if let Some(ref fn_val) = family_name {
98 Self::validate_name_component(fn_val, "familyName")?;
99 }
100 if let Some(ref gn) = given_name {
101 Self::validate_name_component(gn, "givenName")?;
102 }
103 if let Some(ref mn) = middle_name {
104 Self::validate_name_component(mn, "middleName")?;
105 }
106 if let Some(ref hp) = honorific_prefix {
107 Self::validate_name_component(hp, "honorificPrefix")?;
108 }
109 if let Some(ref hs) = honorific_suffix {
110 Self::validate_name_component(hs, "honorificSuffix")?;
111 }
112
113 if formatted.is_none()
115 && family_name.is_none()
116 && given_name.is_none()
117 && middle_name.is_none()
118 && honorific_prefix.is_none()
119 && honorific_suffix.is_none()
120 {
121 return Err(ValidationError::custom(
122 "At least one name component must be provided",
123 ));
124 }
125
126 Ok(Self {
127 formatted,
128 family_name,
129 given_name,
130 middle_name,
131 honorific_prefix,
132 honorific_suffix,
133 })
134 }
135
136 pub fn new_simple(given_name: String, family_name: String) -> ValidationResult<Self> {
150 Self::new(None, Some(family_name), Some(given_name), None, None, None)
151 }
152
153 pub fn new_formatted(formatted: String) -> ValidationResult<Self> {
166 Self::new(Some(formatted), None, None, None, None, None)
167 }
168
169 pub fn formatted(&self) -> Option<&str> {
173 self.formatted.as_deref()
174 }
175
176 pub fn family_name(&self) -> Option<&str> {
178 self.family_name.as_deref()
179 }
180
181 pub fn given_name(&self) -> Option<&str> {
183 self.given_name.as_deref()
184 }
185
186 pub fn middle_name(&self) -> Option<&str> {
188 self.middle_name.as_deref()
189 }
190
191 pub fn honorific_prefix(&self) -> Option<&str> {
193 self.honorific_prefix.as_deref()
194 }
195
196 pub fn honorific_suffix(&self) -> Option<&str> {
198 self.honorific_suffix.as_deref()
199 }
200
201 pub fn display_name(&self) -> Option<String> {
211 if let Some(ref formatted) = self.formatted {
212 return Some(formatted.clone());
213 }
214
215 let mut parts = Vec::new();
216
217 if let Some(ref prefix) = self.honorific_prefix {
218 parts.push(prefix.as_str());
219 }
220 if let Some(ref given) = self.given_name {
221 parts.push(given.as_str());
222 }
223 if let Some(ref middle) = self.middle_name {
224 parts.push(middle.as_str());
225 }
226 if let Some(ref family) = self.family_name {
227 parts.push(family.as_str());
228 }
229 if let Some(ref suffix) = self.honorific_suffix {
230 parts.push(suffix.as_str());
231 }
232
233 if parts.is_empty() {
234 None
235 } else {
236 Some(parts.join(" "))
237 }
238 }
239
240 pub fn is_empty(&self) -> bool {
242 self.formatted.is_none()
243 && self.family_name.is_none()
244 && self.given_name.is_none()
245 && self.middle_name.is_none()
246 && self.honorific_prefix.is_none()
247 && self.honorific_suffix.is_none()
248 }
249
250 fn validate_name_component(value: &str, field_name: &str) -> ValidationResult<()> {
252 if value.trim().is_empty() {
253 return Err(ValidationError::custom(format!(
254 "{}: Name component cannot be empty or contain only whitespace",
255 field_name
256 )));
257 }
258
259 if value.len() > 256 {
261 return Err(ValidationError::custom(format!(
262 "{}: Name component exceeds maximum length of 256 characters",
263 field_name
264 )));
265 }
266
267 if value
269 .chars()
270 .any(|c| c.is_control() && c != '\n' && c != '\r' && c != '\t')
271 {
272 return Err(ValidationError::custom(format!(
273 "{}: Name component contains invalid control characters",
274 field_name
275 )));
276 }
277
278 Ok(())
279 }
280
281 pub fn from_json(value: &Value) -> ValidationResult<Self> {
283 if let Value::Object(obj) = value {
284 let formatted = obj
285 .get("formatted")
286 .and_then(|v| v.as_str())
287 .map(|s| s.to_string());
288
289 let family_name = obj
290 .get("familyName")
291 .and_then(|v| v.as_str())
292 .map(|s| s.to_string());
293
294 let given_name = obj
295 .get("givenName")
296 .and_then(|v| v.as_str())
297 .map(|s| s.to_string());
298
299 let middle_name = obj
300 .get("middleName")
301 .and_then(|v| v.as_str())
302 .map(|s| s.to_string());
303
304 let honorific_prefix = obj
305 .get("honorificPrefix")
306 .and_then(|v| v.as_str())
307 .map(|s| s.to_string());
308
309 let honorific_suffix = obj
310 .get("honorificSuffix")
311 .and_then(|v| v.as_str())
312 .map(|s| s.to_string());
313
314 Self::new(
315 formatted,
316 family_name,
317 given_name,
318 middle_name,
319 honorific_prefix,
320 honorific_suffix,
321 )
322 } else {
323 Err(ValidationError::InvalidAttributeType {
324 attribute: "name".to_string(),
325 expected: "object".to_string(),
326 actual: "non-object".to_string(),
327 })
328 }
329 }
330}
331
332impl ValueObject for Name {
333 fn attribute_type(&self) -> AttributeType {
334 AttributeType::Complex
335 }
336
337 fn attribute_name(&self) -> &str {
338 "name"
339 }
340
341 fn to_json(&self) -> ValidationResult<Value> {
342 Ok(serde_json::to_value(self)?)
343 }
344
345 fn validate_against_schema(&self, definition: &AttributeDefinition) -> ValidationResult<()> {
346 if definition.data_type != AttributeType::Complex {
347 return Err(ValidationError::InvalidAttributeType {
348 attribute: definition.name.clone(),
349 expected: "complex".to_string(),
350 actual: format!("{:?}", definition.data_type),
351 });
352 }
353
354 if definition.name != "name" {
355 return Err(ValidationError::InvalidAttributeName {
356 actual: definition.name.clone(),
357 expected: "name".to_string(),
358 });
359 }
360
361 Ok(())
362 }
363
364 fn as_json_value(&self) -> Value {
365 serde_json::to_value(self).unwrap_or(Value::Null)
366 }
367
368 fn supports_definition(&self, definition: &AttributeDefinition) -> bool {
369 definition.data_type == AttributeType::Complex && definition.name == "name"
370 }
371
372 fn clone_boxed(&self) -> Box<dyn ValueObject> {
373 Box::new(self.clone())
374 }
375
376 fn as_any(&self) -> &dyn Any {
377 self
378 }
379}
380
381impl SchemaConstructible for Name {
382 fn from_schema_and_value(
383 definition: &AttributeDefinition,
384 value: &Value,
385 ) -> ValidationResult<Self> {
386 if definition.name != "name" || definition.data_type != AttributeType::Complex {
387 return Err(ValidationError::UnsupportedAttributeType {
388 attribute: definition.name.clone(),
389 type_name: format!("{:?}", definition.data_type),
390 });
391 }
392
393 Self::from_json(value)
394 }
395
396 fn can_construct_from(definition: &AttributeDefinition) -> bool {
397 definition.name == "name" && definition.data_type == AttributeType::Complex
398 }
399
400 fn constructor_priority() -> u8 {
401 100 }
403}
404
405impl fmt::Display for Name {
406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407 match self.display_name() {
408 Some(name) => write!(f, "{}", name),
409 None => write!(f, "[Empty Name]"),
410 }
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417
418 #[test]
419 fn test_valid_name_full() {
420 let name = Name::new(
421 Some("Ms. Barbara J Jensen, III".to_string()),
422 Some("Jensen".to_string()),
423 Some("Barbara".to_string()),
424 Some("Jane".to_string()),
425 Some("Ms.".to_string()),
426 Some("III".to_string()),
427 );
428
429 assert!(name.is_ok());
430 let name = name.unwrap();
431 assert_eq!(name.formatted(), Some("Ms. Barbara J Jensen, III"));
432 assert_eq!(name.family_name(), Some("Jensen"));
433 assert_eq!(name.given_name(), Some("Barbara"));
434 assert_eq!(name.middle_name(), Some("Jane"));
435 assert_eq!(name.honorific_prefix(), Some("Ms."));
436 assert_eq!(name.honorific_suffix(), Some("III"));
437 }
438
439 #[test]
440 fn test_valid_name_simple() {
441 let name = Name::new_simple("John".to_string(), "Doe".to_string());
442
443 assert!(name.is_ok());
444 let name = name.unwrap();
445 assert_eq!(name.given_name(), Some("John"));
446 assert_eq!(name.family_name(), Some("Doe"));
447 assert_eq!(name.formatted(), None);
448 }
449
450 #[test]
451 fn test_valid_name_formatted_only() {
452 let name = Name::new_formatted("John Doe".to_string());
453
454 assert!(name.is_ok());
455 let name = name.unwrap();
456 assert_eq!(name.formatted(), Some("John Doe"));
457 assert_eq!(name.given_name(), None);
458 assert_eq!(name.family_name(), None);
459 }
460
461 #[test]
462 fn test_empty_name_components() {
463 let result = Name::new(Some("".to_string()), None, None, None, None, None);
464 assert!(result.is_err());
465 }
466
467 #[test]
468 fn test_whitespace_only_components() {
469 let result = Name::new(None, Some(" ".to_string()), None, None, None, None);
470 assert!(result.is_err());
471 }
472
473 #[test]
474 fn test_all_none_components() {
475 let result = Name::new(None, None, None, None, None, None);
476 assert!(result.is_err());
477 assert!(
478 result
479 .unwrap_err()
480 .to_string()
481 .contains("At least one name component")
482 );
483 }
484
485 #[test]
486 fn test_too_long_component() {
487 let long_name = "a".repeat(300);
488 let result = Name::new_formatted(long_name);
489 assert!(result.is_err());
490 assert!(
491 result
492 .unwrap_err()
493 .to_string()
494 .contains("exceeds maximum length")
495 );
496 }
497
498 #[test]
499 fn test_control_characters() {
500 let result = Name::new_formatted("John\x00Doe".to_string());
501 assert!(result.is_err());
502 assert!(
503 result
504 .unwrap_err()
505 .to_string()
506 .contains("invalid control characters")
507 );
508 }
509
510 #[test]
511 fn test_display_name_with_formatted() {
512 let name = Name::new_formatted("Dr. John Smith Jr.".to_string()).unwrap();
513 assert_eq!(name.display_name(), Some("Dr. John Smith Jr.".to_string()));
514 }
515
516 #[test]
517 fn test_display_name_from_components() {
518 let name = Name::new(
519 None,
520 Some("Smith".to_string()),
521 Some("John".to_string()),
522 Some("Michael".to_string()),
523 Some("Dr.".to_string()),
524 Some("Jr.".to_string()),
525 )
526 .unwrap();
527
528 assert_eq!(
529 name.display_name(),
530 Some("Dr. John Michael Smith Jr.".to_string())
531 );
532 }
533
534 #[test]
535 fn test_display_name_partial_components() {
536 let name = Name::new(
537 None,
538 Some("Doe".to_string()),
539 Some("Jane".to_string()),
540 None,
541 None,
542 None,
543 )
544 .unwrap();
545
546 assert_eq!(name.display_name(), Some("Jane Doe".to_string()));
547 }
548
549 #[test]
550 fn test_display() {
551 let name = Name::new_simple("John".to_string(), "Doe".to_string()).unwrap();
552 assert_eq!(format!("{}", name), "John Doe");
553
554 let formatted_name = Name::new_formatted("Dr. John Smith Doe Jr.".to_string()).unwrap();
556 let display_str = format!("{}", formatted_name);
557 assert_eq!(display_str, "Dr. John Smith Doe Jr.");
558 }
559
560 #[test]
561 fn test_serialization() {
562 let name = Name::new(
563 Some("Ms. Barbara J Jensen, III".to_string()),
564 Some("Jensen".to_string()),
565 Some("Barbara".to_string()),
566 Some("Jane".to_string()),
567 Some("Ms.".to_string()),
568 Some("III".to_string()),
569 )
570 .unwrap();
571
572 let json = serde_json::to_string(&name).unwrap();
573 assert!(json.contains("\"formatted\":\"Ms. Barbara J Jensen, III\""));
574 assert!(json.contains("\"familyName\":\"Jensen\""));
575 assert!(json.contains("\"givenName\":\"Barbara\""));
576 }
577
578 #[test]
579 fn test_deserialization() {
580 let json = r#"{
581 "formatted": "Ms. Barbara J Jensen, III",
582 "familyName": "Jensen",
583 "givenName": "Barbara",
584 "middleName": "Jane",
585 "honorificPrefix": "Ms.",
586 "honorificSuffix": "III"
587 }"#;
588
589 let name: Name = serde_json::from_str(json).unwrap();
590 assert_eq!(name.formatted(), Some("Ms. Barbara J Jensen, III"));
591 assert_eq!(name.family_name(), Some("Jensen"));
592 assert_eq!(name.given_name(), Some("Barbara"));
593 }
594
595 #[test]
596 fn test_equality() {
597 let name1 = Name::new_simple("John".to_string(), "Doe".to_string()).unwrap();
598 let name2 = Name::new_simple("John".to_string(), "Doe".to_string()).unwrap();
599 let name3 = Name::new_simple("Jane".to_string(), "Doe".to_string()).unwrap();
600
601 assert_eq!(name1, name2);
602 assert_ne!(name1, name3);
603 }
604
605 #[test]
606 fn test_clone() {
607 let original = Name::new(
608 Some("Dr. John Smith".to_string()),
609 Some("Smith".to_string()),
610 Some("John".to_string()),
611 None,
612 Some("Dr.".to_string()),
613 None,
614 )
615 .unwrap();
616
617 let cloned = original.clone();
618 assert_eq!(original, cloned);
619 assert_eq!(cloned.formatted(), Some("Dr. John Smith"));
620 assert_eq!(cloned.family_name(), Some("Smith"));
621 }
622
623 #[test]
624 fn test_allows_newlines_in_formatted() {
625 let name = Name::new_formatted("John\nDoe".to_string());
626 assert!(name.is_ok());
627 }
628
629 #[test]
630 fn test_allows_tabs_in_formatted() {
631 let name = Name::new_formatted("John\tDoe".to_string());
632 assert!(name.is_ok());
633 }
634}