Skip to main content

stix_rs/sdos/
opinion.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::common::{CommonProperties, StixObject};
5
6/// Opinion SDO
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub struct Opinion {
10    #[serde(flatten)]
11    pub common: CommonProperties,
12
13    pub explanation: Option<String>,
14    pub authors: Option<Vec<String>>,
15    pub object_refs: Vec<String>,
16    pub opinion: String,
17}
18
19impl Opinion {
20    pub fn builder() -> OpinionBuilder {
21        OpinionBuilder::default()
22    }
23}
24
25#[derive(Debug, Default)]
26pub struct OpinionBuilder {
27    explanation: Option<String>,
28    authors: Option<Vec<String>>,
29    object_refs: Option<Vec<String>>,
30    opinion: Option<String>,
31    created_by_ref: Option<String>,
32}
33
34impl OpinionBuilder {
35    pub fn explanation(mut self, e: impl Into<String>) -> Self {
36        self.explanation = Some(e.into());
37        self
38    }
39    pub fn authors(mut self, a: Vec<String>) -> Self {
40        self.authors = Some(a);
41        self
42    }
43    pub fn object_refs(mut self, o: Vec<String>) -> Self {
44        self.object_refs = Some(o);
45        self
46    }
47    pub fn opinion(mut self, o: impl Into<String>) -> Self {
48        self.opinion = Some(o.into());
49        self
50    }
51    pub fn created_by_ref(mut self, r: impl Into<String>) -> Self {
52        self.created_by_ref = Some(r.into());
53        self
54    }
55
56    pub fn build(self) -> Result<Opinion, super::BuilderError> {
57        let object_refs = self
58            .object_refs
59            .ok_or(super::BuilderError::MissingField("object_refs"))?;
60        let opinion = self
61            .opinion
62            .ok_or(super::BuilderError::MissingField("opinion"))?;
63        let common = CommonProperties::new("opinion", self.created_by_ref);
64        Ok(Opinion {
65            common,
66            explanation: self.explanation,
67            authors: self.authors,
68            object_refs,
69            opinion,
70        })
71    }
72}
73
74impl StixObject for Opinion {
75    fn id(&self) -> &str {
76        &self.common.id
77    }
78    fn type_(&self) -> &str {
79        &self.common.r#type
80    }
81    fn created(&self) -> DateTime<Utc> {
82        self.common.created
83    }
84}
85
86impl From<Opinion> for crate::StixObjectEnum {
87    fn from(o: Opinion) -> Self {
88        crate::StixObjectEnum::Opinion(o)
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95    use serde_json::Value;
96
97    #[test]
98    fn opinion_builder_and_serialize() {
99        let op = Opinion::builder()
100            .opinion("agree")
101            .object_refs(vec!["report--1234".into()])
102            .build()
103            .unwrap();
104
105        let s = serde_json::to_string(&op).unwrap();
106        let v: Value = serde_json::from_str(&s).unwrap();
107        assert_eq!(v.get("type").and_then(Value::as_str).unwrap(), "opinion");
108        assert!(v.get("object_refs").is_some());
109    }
110}