1use super::{tag::Tag, Status, StorageClass};
2use serde::{Deserialize, Serialize};
3
4pub mod builder {
5 use crate::oss::entities::{Status, StorageClass};
6
7 use super::{
8 AbortMultipartUpload, Expiration, Filter, LifecycleConfiguration,
9 NoncurrentVersionExpiration, Rule, Transition,
10 };
11
12 #[derive(Default, Clone, Debug)]
13 pub struct FilterBuilder {}
14
15 impl FilterBuilder {
16 pub fn new() -> Self {
17 Self::default()
18 }
19
20 pub fn build() -> Filter {
21 Filter::default()
22 }
23 }
24
25 #[derive(Default, Clone, Debug)]
26 pub struct ExpirationBuilder {
27 days: Option<i32>,
28 created_before_date: Option<String>,
29 expired_object_delete_marker: Option<bool>,
30 }
31
32 impl ExpirationBuilder {
33 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn with_days(mut self, value: i32) -> Self {
38 self.days = Some(value);
39 self
40 }
41
42 pub fn with_created_before_date(mut self, value: String) -> Self {
43 self.created_before_date = Some(value);
44 self
45 }
46
47 pub fn with_expired_object_delete_marker(mut self, value: bool) -> Self {
48 self.expired_object_delete_marker = Some(value);
49 self
50 }
51
52 pub fn build(&self) -> Expiration {
53 Expiration {
54 days: self.days,
55 created_before_date: self.created_before_date.clone(),
56 expired_object_delete_marker: self.expired_object_delete_marker,
57 }
58 }
59 }
60
61 #[derive(Default, Debug, Clone)]
62 pub struct TransitionBuilder {
63 days: Option<i32>,
64 storage_class: StorageClass,
65 is_access_time: Option<bool>,
66 return_to_std_when_visit: Option<bool>,
67 allow_small_file: Option<bool>,
68 }
69
70 impl TransitionBuilder {
71 pub fn new() -> Self {
72 Self::default()
73 }
74
75 pub fn with_days(mut self, value: i32) -> Self {
76 self.days = Some(value);
77 self
78 }
79
80 pub fn with_torage_class(mut self, value: StorageClass) -> Self {
81 self.storage_class = value;
82 self
83 }
84
85 pub fn with_is_access_time(mut self, value: bool) -> Self {
86 self.is_access_time = Some(value);
87 self
88 }
89
90 pub fn with_return_to_std_when_visit(mut self, value: bool) -> Self {
91 self.return_to_std_when_visit = Some(value);
92 self
93 }
94
95 pub fn with_allow_small_file(mut self, value: bool) -> Self {
96 self.allow_small_file = Some(value);
97 self
98 }
99
100 pub fn build(&self) -> Transition {
101 Transition {
102 days: self.days,
103 storage_class: self.storage_class.clone(),
104 is_access_time: self.is_access_time,
105 return_to_std_when_visit: self.return_to_std_when_visit,
106 allow_small_file: self.allow_small_file,
107 }
108 }
109 }
110
111 #[derive(Default, Debug, Clone)]
112 pub struct RuleBuilder<'a> {
113 id: &'a str,
114 prefix: &'a str,
115 status: Status,
116 transition: Option<Vec<Transition>>,
117 filter: Option<Filter>,
118 expiration: Option<Expiration>,
119 noncurrent_version_expiration: Option<NoncurrentVersionExpiration>,
120 abort_multipart_upload: Option<AbortMultipartUpload>,
121 }
122
123 impl<'a> RuleBuilder<'a> {
124 pub fn new() -> Self {
125 Self::default()
126 }
127
128 pub fn with_id(mut self, value: &'a str) -> Self {
129 self.id = value;
130 self
131 }
132
133 pub fn with_prefix(mut self, value: &'a str) -> Self {
134 self.prefix = value;
135 self
136 }
137
138 pub fn with_status(mut self, value: Status) -> Self {
139 self.status = value;
140 self
141 }
142
143 pub fn with_transition(mut self, value: Transition) -> Self {
144 let transitions = if let Some(mut transitions) = self.transition {
145 transitions.push(value);
146 transitions
147 } else {
148 vec![value]
149 };
150 self.transition = Some(transitions);
151 self
152 }
153
154 pub fn with_filter(mut self, value: Filter) -> Self {
155 self.filter = Some(value);
156 self
157 }
158
159 pub fn with_expiration(mut self, value: Expiration) -> Self {
160 self.expiration = Some(value);
161 self
162 }
163
164 pub fn with_noncurrent_version_expiration(mut self, days: i32) -> Self {
165 self.noncurrent_version_expiration = Some(NoncurrentVersionExpiration {
166 noncurrent_days: days,
167 });
168 self
169 }
170
171 pub fn with_abort_multipart_upload(mut self, days: i32) -> Self {
172 self.abort_multipart_upload = Some(AbortMultipartUpload { days });
173 self
174 }
175
176 pub fn build(&self) -> Rule {
177 Rule {
178 id: self.id.into(),
180 prefix: self.prefix.into(),
181 status: self.status.clone(),
182 transition: self.transition.clone(),
183 filter: self.filter.clone(),
184 expiration: self.expiration.clone(),
185 noncurrent_version_expiration: self.noncurrent_version_expiration.clone(),
186 abort_multipart_upload: self.abort_multipart_upload.clone(),
187 }
188 }
189 }
190
191 #[derive(Default, Debug, Clone)]
192 pub struct LifecycleConfigurationBuilder {
193 rules: Vec<Rule>,
194 }
195
196 impl LifecycleConfigurationBuilder {
197 pub fn new() -> Self {
198 Self::default()
199 }
200
201 pub fn with_rule(mut self, value: Rule) -> Self {
202 self.rules.push(value);
203 self
204 }
205
206 pub fn build(&self) -> LifecycleConfiguration {
207 LifecycleConfiguration {
208 rule: self.rules.clone(),
209 }
210 }
211 }
212}
213
214#[derive(Debug, Serialize, Deserialize, Clone, Default)]
215pub struct Not {
216 #[serde(rename = "Prefix")]
217 pub prefix: String,
218 #[serde(rename = "Tag")]
219 pub tag: Tag,
220}
221
222#[derive(Debug, Serialize, Deserialize, Clone, Default)]
223pub struct Filter {
224 #[serde(rename = "Not", skip_serializing_if = "Option::is_none")]
225 pub not: Option<Not>,
226 #[serde(
227 rename = "ObjectSizeGreaterThan",
228 skip_serializing_if = "Option::is_none"
229 )]
230 pub object_size_greater_than: Option<i32>,
231 #[serde(rename = "ObjectSizeLessThan", skip_serializing_if = "Option::is_none")]
232 pub object_size_less_than: Option<i32>,
233}
234
235#[derive(Debug, Serialize, Deserialize, Clone, Default)]
236pub struct AbortMultipartUpload {
237 #[serde(rename = "Days")]
238 pub days: i32,
239}
240
241#[derive(Debug, Serialize, Deserialize, Clone, Default)]
242pub struct NoncurrentVersionTransition {
243 #[serde(rename = "NoncurrentDays", skip_serializing_if = "Option::is_none")]
244 pub noncurrent_days: Option<bool>,
245 #[serde(rename = "StorageClass")]
246 pub storage_class: StorageClass,
247}
248
249#[derive(Debug, Serialize, Deserialize, Default, Clone)]
250pub struct Transition {
251 #[serde(rename = "Days")]
252 pub days: Option<i32>,
253 #[serde(rename = "StorageClass")]
254 pub storage_class: StorageClass,
255 #[serde(rename = "IsAccessTime", skip_serializing_if = "Option::is_none")]
256 pub is_access_time: Option<bool>,
257 #[serde(
258 rename = "ReturnToStdWhenVisit",
259 skip_serializing_if = "Option::is_none"
260 )]
261 pub return_to_std_when_visit: Option<bool>,
262 #[serde(rename = "AllowSmallFile", skip_serializing_if = "Option::is_none")]
263 pub allow_small_file: Option<bool>,
264}
265
266#[derive(Debug, Serialize, Deserialize, Default, Clone)]
267pub struct Expiration {
268 #[serde(rename = "Days", skip_serializing_if = "Option::is_none")]
269 pub days: Option<i32>,
270 #[serde(rename = "CreatedBeforeDate", skip_serializing_if = "Option::is_none")]
271 pub created_before_date: Option<String>,
272 #[serde(
273 rename = "ExpiredObjectDeleteMarker",
274 skip_serializing_if = "Option::is_none"
275 )]
276 pub expired_object_delete_marker: Option<bool>,
277}
278
279#[derive(Debug, Serialize, Deserialize, Default, Clone)]
280pub struct NoncurrentVersionExpiration {
281 #[serde(rename = "NoncurrentDays")]
282 pub noncurrent_days: i32,
283}
284
285#[derive(Debug, Serialize, Deserialize, Default, Clone)]
286pub struct Rule {
287 #[serde(rename = "ID")]
288 pub id: String,
289 #[serde(rename = "Prefix")]
290 pub prefix: String,
291 #[serde(rename = "Status")]
292 pub status: Status,
293 #[serde(rename = "Transition", skip_serializing_if = "Option::is_none")]
294 pub transition: Option<Vec<Transition>>,
295 #[serde(rename = "Filter", skip_serializing_if = "Option::is_none")]
296 pub filter: Option<Filter>,
297 #[serde(rename = "Expiration", skip_serializing_if = "Option::is_none")]
298 pub expiration: Option<Expiration>,
299 #[serde(
300 rename = "NoncurrentVersionExpiration",
301 skip_serializing_if = "Option::is_none"
302 )]
303 pub noncurrent_version_expiration: Option<NoncurrentVersionExpiration>,
304 #[serde(
305 rename = "AbortMultipartUpload",
306 skip_serializing_if = "Option::is_none"
307 )]
308 pub abort_multipart_upload: Option<AbortMultipartUpload>,
309}
310
311#[derive(Debug, Serialize, Deserialize, Default, Clone)]
312pub struct LifecycleConfiguration {
313 #[serde(rename = "Rule")]
314 pub rule: Vec<Rule>,
315}
316
317#[cfg(test)]
318mod tests {
319 use crate::oss::entities::Status;
320
321 use super::builder::*;
322 use super::*;
323
324 #[test]
325 fn lifecycle_configuration_return_parse_1() {
327 let xml_content = r#"<?xml version="1.0" encoding="UTF-8"?>
328<LifecycleConfiguration>
329 <Rule>
330 <ID>delete after one day</ID>
331 <Prefix>logs1/</Prefix>
332 <Status>Enabled</Status>
333 <Expiration>
334 <Days>1</Days>
335 </Expiration>
336 </Rule>
337 <Rule>
338 <ID>mtime transition1</ID>
339 <Prefix>logs2/</Prefix>
340 <Status>Enabled</Status>
341 <Transition>
342 <Days>30</Days>
343 <StorageClass>IA</StorageClass>
344 </Transition>
345 </Rule>
346 <Rule>
347 <ID>mtime transition2</ID>
348 <Prefix>logs3/</Prefix>
349 <Status>Enabled</Status>
350 <Transition>
351 <Days>30</Days>
352 <StorageClass>IA</StorageClass>
353 <IsAccessTime>false</IsAccessTime>
354 </Transition>
355 </Rule>
356</LifecycleConfiguration>"#;
357 let object: LifecycleConfiguration = quick_xml::de::from_str(xml_content).unwrap();
358
359 let left = "mtime transition1";
362 let right = &object.rule[1].id;
363 assert_eq!(left, right);
364 }
365
366 #[test]
367 fn lifecycle_configuration_return_parse_2() {
369 let xml_content = r#"<?xml version="1.0" encoding="UTF-8"?>
370<LifecycleConfiguration>
371 <Rule>
372 <ID>atime transition1</ID>
373 <Prefix>logs1/</Prefix>
374 <Status>Enabled</Status>
375 <Transition>
376 <Days>30</Days>
377 <StorageClass>IA</StorageClass>
378 <IsAccessTime>true</IsAccessTime>
379 <ReturnToStdWhenVisit>false</ReturnToStdWhenVisit>
380 </Transition>
381 <AtimeBase>1631698332</AtimeBase>
382 </Rule>
383 <Rule>
384 <ID>atime transition2</ID>
385 <Prefix>logs2/</Prefix>
386 <Status>Enabled</Status>
387 <NoncurrentVersionTransition>
388 <NoncurrentDays>10</NoncurrentDays>
389 <StorageClass>IA</StorageClass>
390 <IsAccessTime>true</IsAccessTime>
391 <ReturnToStdWhenVisit>false</ReturnToStdWhenVisit>
392 </NoncurrentVersionTransition>
393 <AtimeBase>1631698332</AtimeBase>
394 </Rule>
395</LifecycleConfiguration>"#;
396 let object: LifecycleConfiguration = quick_xml::de::from_str(xml_content).unwrap();
397
398 let left = "atime transition2";
399 let right = &object.rule[1].id;
400 assert_eq!(left, right);
401 }
402
403 #[test]
405 fn lifecycle_configuration_builder_1() {
407 let config = LifecycleConfigurationBuilder::new()
408 .with_rule(
409 RuleBuilder::new()
410 .with_id("rule")
411 .with_prefix("log")
412 .with_status(Status::Enabled)
413 .with_transition(
414 TransitionBuilder::new()
415 .with_days(30)
416 .with_torage_class(StorageClass::IA)
417 .build(),
418 )
419 .build(),
420 )
421 .build();
422
423 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix>log</Prefix><Status>Enabled</Status><Transition><Days>30</Days><StorageClass>IA</StorageClass></Transition></Rule></LifecycleConfiguration>";
424 let right = quick_xml::se::to_string(&config).unwrap();
425
426 assert_eq!(left, right);
427 }
428
429 #[test]
431 fn lifecycle_configuration_builder_2() {
433 let config = LifecycleConfigurationBuilder::new()
434 .with_rule(
435 RuleBuilder::new()
436 .with_id("rule")
437 .with_prefix("log")
438 .with_status(Status::Enabled)
439 .with_expiration(ExpirationBuilder::new().with_days(90).build())
440 .build(),
441 )
442 .build();
443
444 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix>log</Prefix><Status>Enabled</Status><Expiration><Days>90</Days></Expiration></Rule></LifecycleConfiguration>";
445 let right = quick_xml::se::to_string(&config).unwrap();
446
447 assert_eq!(left, right);
448 }
449
450 #[test]
452 fn lifecycle_configuration_builder_3() {
454 let config = LifecycleConfigurationBuilder::new()
455 .with_rule(
456 RuleBuilder::new()
457 .with_id("rule")
458 .with_prefix("log")
459 .with_status(Status::Enabled)
460 .with_transition(
461 TransitionBuilder::new()
462 .with_days(30)
463 .with_torage_class(StorageClass::IA)
464 .build(),
465 )
466 .with_transition(
467 TransitionBuilder::new()
468 .with_days(60)
469 .with_torage_class(StorageClass::Archive)
470 .build(),
471 )
472 .with_expiration(ExpirationBuilder::new().with_days(60).build())
473 .build(),
474 )
475 .build();
476 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix>log</Prefix><Status>Enabled</Status><Transition><Days>30</Days><StorageClass>IA</StorageClass></Transition><Transition><Days>60</Days><StorageClass>Archive</StorageClass></Transition><Expiration><Days>60</Days></Expiration></Rule></LifecycleConfiguration>";
477 let right = quick_xml::se::to_string(&config).unwrap();
478
479 assert_eq!(left, right);
480 }
481
482 #[test]
483 fn lifecycle_configuration_builder_4() {
485 let config = LifecycleConfigurationBuilder::new()
486 .with_rule(
487 RuleBuilder::new()
488 .with_id("rule")
489 .with_prefix("")
490 .with_status(Status::Enabled)
491 .with_expiration(
492 ExpirationBuilder::new()
493 .with_expired_object_delete_marker(true)
494 .build(),
495 )
496 .with_noncurrent_version_expiration(5)
497 .build(),
498 )
499 .build();
500
501 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix/><Status>Enabled</Status><Expiration><ExpiredObjectDeleteMarker>true</ExpiredObjectDeleteMarker></Expiration><NoncurrentVersionExpiration><NoncurrentDays>5</NoncurrentDays></NoncurrentVersionExpiration></Rule></LifecycleConfiguration>";
502 let right = quick_xml::se::to_string(&config).unwrap();
503
504 assert_eq!(left, right);
505 }
506
507 #[test]
508 fn lifecycle_configuration_builder_5() {
510 let config = LifecycleConfigurationBuilder::new()
511 .with_rule(
512 RuleBuilder::new()
513 .with_id("rule")
514 .with_prefix("log")
515 .with_status(Status::Enabled)
516 .with_transition(
517 TransitionBuilder::new()
518 .with_days(30)
519 .with_torage_class(StorageClass::IA)
520 .with_is_access_time(true)
521 .with_return_to_std_when_visit(true)
522 .build(),
523 )
524 .build(),
525 )
526 .build();
527
528 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix>log</Prefix><Status>Enabled</Status><Transition><Days>30</Days><StorageClass>IA</StorageClass><IsAccessTime>true</IsAccessTime><ReturnToStdWhenVisit>true</ReturnToStdWhenVisit></Transition></Rule></LifecycleConfiguration>";
529 let right = quick_xml::se::to_string(&config).unwrap();
530
531 assert_eq!(left, right);
532 }
533 #[test]
534 fn lifecycle_configuration_builder_6() {
536 let config = LifecycleConfigurationBuilder::new()
537 .with_rule(
538 RuleBuilder::new()
539 .with_id("rule")
540 .with_prefix("/")
541 .with_status(Status::Enabled)
542 .with_abort_multipart_upload(30)
543 .build(),
544 )
545 .build();
546
547 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix>/</Prefix><Status>Enabled</Status><AbortMultipartUpload><Days>30</Days></AbortMultipartUpload></Rule></LifecycleConfiguration>";
548 let right = quick_xml::se::to_string(&config).unwrap();
549
550 assert_eq!(left, right);
551 }
552
553 #[test]
554 fn lifecycle_configuration_builder_7() {
556 let config = LifecycleConfigurationBuilder::new()
557 .with_rule(
558 RuleBuilder::new()
559 .with_id("rule")
560 .with_prefix("/")
561 .with_status(Status::Enabled)
562 .with_abort_multipart_upload(30)
563 .build(),
564 )
565 .build();
566 let left = "<LifecycleConfiguration><Rule><ID>rule</ID><Prefix>/</Prefix><Status>Enabled</Status><AbortMultipartUpload><Days>30</Days></AbortMultipartUpload></Rule></LifecycleConfiguration>";
567 let right = quick_xml::se::to_string(&config).unwrap();
568 assert_eq!(left, right);
569 }
570
571 #[test]
572 fn lifecycle_configuration_builder_8() {
574 let config = LifecycleConfigurationBuilder::new()
575 .with_rule(
576 RuleBuilder::new()
577 .with_id("Rule1")
578 .with_prefix("dir1")
579 .with_expiration(ExpirationBuilder::new().with_days(180).build())
580 .build(),
581 )
582 .with_rule(
583 RuleBuilder::new()
584 .with_id("Rule2")
585 .with_prefix("dir1/dir2")
586 .with_status(Status::Enabled)
587 .with_expiration(ExpirationBuilder::new().with_days(30).build())
588 .build(),
589 )
590 .build();
591
592 let right = quick_xml::se::to_string(&config).unwrap();
593 let left = r#"<LifecycleConfiguration><Rule><ID>Rule1</ID><Prefix>dir1</Prefix><Status>Disabled</Status><Expiration><Days>180</Days></Expiration></Rule><Rule><ID>Rule2</ID><Prefix>dir1/dir2</Prefix><Status>Enabled</Status><Expiration><Days>30</Days></Expiration></Rule></LifecycleConfiguration>"#;
594
595 assert_eq!(left, right);
596 }
597}