azure_storage/
stored_access_policy.rs

1use azure_core::{date, xml::read_xml};
2use time::OffsetDateTime;
3
4#[derive(Debug, Clone, Default, PartialEq, Eq)]
5pub struct StoredAccessPolicyList {
6    pub stored_access: Vec<StoredAccessPolicy>,
7}
8
9impl StoredAccessPolicyList {
10    pub fn new(list: Vec<StoredAccessPolicy>) -> Self {
11        Self {
12            stored_access: list,
13        }
14    }
15
16    pub fn from_xml(bytes: &[u8]) -> azure_core::Result<Self> {
17        let sis: SignedIdentifiers = read_xml(bytes)?;
18        Ok(sis.into())
19    }
20
21    pub fn to_xml(&self) -> String {
22        let mut s = String::new();
23        s.push_str("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<SignedIdentifiers>\n");
24        for sa in &self.stored_access {
25            s.push_str("\t<SignedIdentifier>\n");
26
27            s.push_str("\t\t<Id>");
28            s.push_str(&sa.id);
29            s.push_str("\n\t\t</Id>\n");
30
31            s.push_str("<AccessPolicy>\n");
32
33            s.push_str("\t\t\t<Start>");
34            s.push_str(&date::to_rfc3339(&sa.start));
35            s.push_str("</Start>\n");
36
37            s.push_str("\t\t\t<Expiry>");
38            s.push_str(&date::to_rfc3339(&sa.expiry));
39            s.push_str("</Expiry>\n");
40
41            s.push_str("\t\t\t<Permission>");
42            s.push_str(&sa.permission);
43            s.push_str("</Permission>\n");
44            s.push_str("\t\t</AccessPolicy>\n\t</SignedIdentifier>\n");
45        }
46
47        s.push_str("</SignedIdentifiers>");
48        s
49    }
50}
51
52impl From<SignedIdentifiers> for StoredAccessPolicyList {
53    fn from(si: SignedIdentifiers) -> Self {
54        let list = si
55            .signed_identifiers
56            .into_iter()
57            .map(|si| StoredAccessPolicy {
58                id: si.id,
59                start: si.access_policy.start,
60                expiry: si.access_policy.expiry,
61                permission: si.access_policy.permission,
62            })
63            .collect();
64        Self {
65            stored_access: list,
66        }
67    }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct StoredAccessPolicy {
72    pub id: String,
73    pub start: OffsetDateTime,
74    pub expiry: OffsetDateTime,
75    pub permission: String,
76}
77
78impl StoredAccessPolicy {
79    pub fn new<A, B>(id: A, start: OffsetDateTime, expiry: OffsetDateTime, permission: B) -> Self
80    where
81        A: Into<String>,
82        B: Into<String>,
83    {
84        Self {
85            id: id.into(),
86            start,
87            expiry,
88            permission: permission.into(),
89        }
90    }
91}
92
93#[derive(Debug, Deserialize)]
94struct SignedIdentifiers {
95    #[serde(rename = "SignedIdentifier", default)]
96    signed_identifiers: Vec<SignedIdentifier>,
97}
98
99#[derive(Debug, Deserialize)]
100#[serde(rename_all = "PascalCase")]
101struct SignedIdentifier {
102    id: String,
103    access_policy: AccessPolicy,
104}
105
106#[derive(Debug, Deserialize)]
107#[serde(rename_all = "PascalCase")]
108struct AccessPolicy {
109    #[serde(with = "azure_core::date::rfc3339")]
110    start: OffsetDateTime,
111    #[serde(with = "azure_core::date::rfc3339")]
112    expiry: OffsetDateTime,
113    permission: String,
114}
115
116#[cfg(test)]
117mod test {
118    use super::*;
119
120    #[test]
121    fn parse_from_xml() {
122        let resp = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
123    <SignedIdentifiers>
124      <SignedIdentifier>
125          <Id>MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=</Id>
126          <AccessPolicy>
127            <Start>2009-09-28T08:49:37Z</Start>
128            <Expiry>2009-09-29T08:49:37Z</Expiry>
129            <Permission>rwd</Permission>
130          </AccessPolicy>
131      </SignedIdentifier>
132      <SignedIdentifier>
133          <Id>000zNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=</Id>
134          <AccessPolicy>
135            <Start>2018-09-28T08:49:37Z</Start>
136            <Expiry>2020-09-29T08:49:37Z</Expiry>
137            <Permission>rd</Permission>
138          </AccessPolicy>
139      </SignedIdentifier>
140    </SignedIdentifiers>";
141
142        let sis: SignedIdentifiers = read_xml(resp.as_bytes()).unwrap();
143        assert_eq!(sis.signed_identifiers.len(), 2);
144        let sap: StoredAccessPolicyList = sis.into();
145        let sxml = sap.to_xml();
146
147        fn remove_whitespace(mut s: String) -> String {
148            s.retain(|c| !c.is_whitespace());
149            s
150        }
151        assert_eq!(remove_whitespace(sxml), remove_whitespace(resp.to_owned()));
152    }
153}