1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::common::{CommonProperties, StixObject};
5use crate::sdos::BuilderError;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub struct Note {
11 #[serde(flatten)]
12 pub common: CommonProperties,
13 #[serde(rename = "abstract")]
14 pub abstract_: Option<String>,
15 pub content: Option<String>,
16}
17
18impl Note {
19 pub fn builder() -> NoteBuilder {
20 NoteBuilder::default()
21 }
22}
23
24#[derive(Debug, Default)]
25pub struct NoteBuilder {
26 abstract_: Option<String>,
27 content: Option<String>,
28 created_by_ref: Option<String>,
29}
30
31impl NoteBuilder {
32 pub fn abstract_(mut self, a: impl Into<String>) -> Self {
33 self.abstract_ = Some(a.into());
34 self
35 }
36
37 pub fn content(mut self, c: impl Into<String>) -> Self {
38 self.content = Some(c.into());
39 self
40 }
41
42 pub fn created_by_ref(mut self, r: impl Into<String>) -> Self {
43 self.created_by_ref = Some(r.into());
44 self
45 }
46
47 pub fn build(self) -> Result<Note, BuilderError> {
48 let common = CommonProperties::new("note", self.created_by_ref);
49 Ok(Note {
50 common,
51 abstract_: self.abstract_,
52 content: self.content,
53 })
54 }
55}
56
57impl StixObject for Note {
58 fn id(&self) -> &str {
59 &self.common.id
60 }
61
62 fn type_(&self) -> &str {
63 &self.common.r#type
64 }
65
66 fn created(&self) -> DateTime<Utc> {
67 self.common.created
68 }
69}
70
71impl From<Note> for crate::StixObjectEnum {
72 fn from(n: Note) -> Self {
73 crate::StixObjectEnum::Note(n)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn note_builder() {
83 let note = Note::builder()
84 .abstract_("Summary of findings")
85 .content("Detailed analysis of the threat actor's TTPs")
86 .build()
87 .unwrap();
88
89 assert_eq!(note.abstract_.as_deref(), Some("Summary of findings"));
90 assert_eq!(note.common.r#type, "note");
91 }
92
93 #[test]
94 fn note_serialize() {
95 let note = Note::builder()
96 .content("Important observation")
97 .build()
98 .unwrap();
99
100 let json = serde_json::to_string(¬e).unwrap();
101 assert!(json.contains("\"type\":\"note\""));
102 assert!(json.contains("\"content\":\"Important observation\""));
103 }
104}