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}