1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::common::{CommonProperties, StixObject};
5
6#[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}