greentic_bundle/answers/
document.rs1use std::collections::BTreeMap;
2
3use anyhow::{Result, bail};
4use semver::Version;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct AnswerDocument {
10 pub wizard_id: String,
11 pub schema_id: String,
12 pub schema_version: Version,
13 pub locale: String,
14 #[serde(default, skip_serializing_if = "Option::is_none")]
19 pub env_id: Option<String>,
20 #[serde(default)]
21 pub answers: BTreeMap<String, Value>,
22 #[serde(default)]
23 pub locks: BTreeMap<String, Value>,
24}
25
26impl AnswerDocument {
27 pub fn new(locale: &str) -> Self {
28 Self {
29 wizard_id: crate::wizard::WIZARD_ID.to_string(),
30 schema_id: crate::wizard::ANSWER_SCHEMA_ID.to_string(),
31 schema_version: Version::new(1, 0, 0),
32 locale: crate::i18n::normalize_locale(locale).unwrap_or_else(|| "en".to_string()),
33 env_id: None,
34 answers: BTreeMap::new(),
35 locks: BTreeMap::new(),
36 }
37 }
38
39 pub fn from_json_str(raw: &str) -> Result<Self> {
40 let document: Self = serde_json::from_str(raw)?;
41 document.validate()?;
42 Ok(document)
43 }
44
45 pub fn validate(&self) -> Result<()> {
46 if self.wizard_id.trim().is_empty() {
47 bail!("{}", crate::i18n::tr("errors.answer_document.wizard_id"));
48 }
49 if self.schema_id.trim().is_empty() {
50 bail!("{}", crate::i18n::tr("errors.answer_document.schema_id"));
51 }
52 if self.locale.trim().is_empty() {
53 bail!("{}", crate::i18n::tr("errors.answer_document.locale"));
54 }
55 Ok(())
56 }
57
58 pub fn to_pretty_json_string(&self) -> Result<String> {
59 self.validate()?;
60 let mut rendered = serde_json::to_string_pretty(self)?;
61 rendered.push('\n');
62 Ok(rendered)
63 }
64}