use super::*;
pub(crate) fn bucket_lifecycle_configuration_xml(result: &BucketLifecycleConfiguration) -> String {
let rules = result
.rules
.iter()
.map(|rule| {
let prefix = rule
.prefix
.as_ref()
.map(|prefix| format!("<Prefix>{}</Prefix>", xml_escape(prefix)))
.unwrap_or_default();
let tag_filter = rule_filter_xml(&rule.tag_filter);
let size_filter = lifecycle_size_filter_xml(rule);
let filter = if !prefix.is_empty() || !tag_filter.is_empty() || !size_filter.is_empty()
{
format!("<Filter>{prefix}{tag_filter}{size_filter}</Filter>")
} else {
String::new()
};
let expiration = rule
.expiration_days
.map(|days| format!("<Expiration><Days>{days}</Days></Expiration>"))
.unwrap_or_default();
let noncurrent = rule
.noncurrent_expiration_days
.map(|days| {
format!(
"<NoncurrentVersionExpiration><NoncurrentDays>{days}</NoncurrentDays></NoncurrentVersionExpiration>"
)
})
.unwrap_or_default();
let abort = rule
.abort_incomplete_multipart_upload_days
.map(|days| AbortIncompleteMultipartUpload {
days_after_initiation: days,
})
.map(|abort| {
format!(
"<AbortIncompleteMultipartUpload><DaysAfterInitiation>{days}</DaysAfterInitiation></AbortIncompleteMultipartUpload>"
, days = abort.days_after_initiation)
})
.unwrap_or_default();
format!(
"<Rule><ID>{}</ID>{filter}<Status>{}</Status>{expiration}{noncurrent}{abort}</Rule>",
xml_escape(&rule.id),
xml_escape(&rule.status)
)
})
.collect::<String>();
format!("<LifecycleConfiguration>{rules}</LifecycleConfiguration>")
}
fn lifecycle_size_filter_xml(rule: &LifecycleRule) -> String {
let greater_than = rule
.object_size_greater_than
.map(|value| format!("<ObjectSizeGreaterThan>{value}</ObjectSizeGreaterThan>"))
.unwrap_or_default();
let less_than = rule
.object_size_less_than
.map(|value| format!("<ObjectSizeLessThan>{value}</ObjectSizeLessThan>"))
.unwrap_or_default();
format!("{greater_than}{less_than}")
}
pub(crate) fn bucket_notification_configuration_xml(
result: &BucketNotificationConfiguration,
) -> String {
let rules = result
.rules
.iter()
.map(|rule| {
if rule.target_kind == "eventbridge" {
let config = EventBridgeConfiguration {
event_bridge_enabled: true,
};
return format!(
"<EventBridgeConfiguration><EventBridgeEnabled>{}</EventBridgeEnabled></EventBridgeConfiguration>",
config.event_bridge_enabled
);
}
let (block_tag, target_tag) = match rule.target_kind.as_str() {
"topic" => ("TopicConfiguration", "Topic"),
"lambda" => ("CloudFunctionConfiguration", "CloudFunction"),
_ => ("QueueConfiguration", "Queue"),
};
let events = rule
.events
.iter()
.map(|event| format!("<Event>{}</Event>", xml_escape(event)))
.collect::<String>();
let filters = notification_filter_xml(rule);
if rule.target_kind == "lambda" {
let config = CloudFunctionConfiguration {
id: rule.id.clone(),
cloud_function: rule.target_arn.clone(),
events: rule.events.clone(),
filter_prefix: rule.filter_prefix.clone(),
filter_suffix: rule.filter_suffix.clone(),
};
format!(
"<{block_tag}><Id>{}</Id><{target_tag}>{}</{target_tag}>{events}{filters}</{block_tag}>",
xml_escape(&config.id),
xml_escape(&config.cloud_function)
)
} else {
format!(
"<{block_tag}><Id>{}</Id><{target_tag}>{}</{target_tag}>{events}{filters}</{block_tag}>",
xml_escape(&rule.id),
xml_escape(&rule.target_arn)
)
}
})
.collect::<String>();
format!("<NotificationConfiguration>{rules}</NotificationConfiguration>")
}
pub(crate) fn bucket_replication_configuration_xml(
result: &BucketReplicationConfiguration,
) -> String {
let role = result
.role
.as_ref()
.map(|role| format!("<Role>{}</Role>", xml_escape(role)))
.unwrap_or_default();
let rules = result
.rules
.iter()
.map(|rule| {
let prefix = rule
.prefix
.as_ref()
.map(|prefix| format!("<Prefix>{}</Prefix>", xml_escape(prefix)))
.unwrap_or_default();
let tag_filter = rule_filter_xml(&rule.tag_filter);
let filter = if !prefix.is_empty() || !tag_filter.is_empty() {
format!("<Filter>{prefix}{tag_filter}</Filter>")
} else {
String::new()
};
let delete_marker_status = if rule.delete_marker_replication {
"Enabled"
} else {
"Disabled"
};
let existing_object_status = if rule.existing_object_replication {
"Enabled"
} else {
"Disabled"
};
let encryption_status = if rule.replicate_encrypted_objects {
"Enabled"
} else {
"Disabled"
};
let destination = Destination {
bucket: rule.destination_bucket.clone(),
};
let delete_marker_replication = DeleteMarkerReplication {
status: delete_marker_status.to_string(),
};
let existing_object_replication = ExistingObjectReplication {
status: existing_object_status.to_string(),
};
format!(
"<Rule><ID>{}</ID><Status>{}</Status>{filter}<Destination><Bucket>{}</Bucket></Destination><DeleteMarkerReplication><Status>{}</Status></DeleteMarkerReplication><ExistingObjectReplication><Status>{}</Status></ExistingObjectReplication><SourceSelectionCriteria><SseKmsEncryptedObjects><Status>{encryption_status}</Status></SseKmsEncryptedObjects></SourceSelectionCriteria></Rule>",
xml_escape(&rule.id),
xml_escape(&rule.status),
xml_escape(&destination.bucket),
xml_escape(&delete_marker_replication.status),
xml_escape(&existing_object_replication.status)
)
})
.collect::<String>();
format!("<ReplicationConfiguration>{role}{rules}</ReplicationConfiguration>")
}
pub(crate) fn replication_run_result_xml(result: &ReplicationRunResult) -> String {
format!(
"<ReplicationRunResult><SourceBucket>{}</SourceBucket><ReplicatedObjectVersions>{}</ReplicatedObjectVersions><ReplicatedDeleteMarkers>{}</ReplicatedDeleteMarkers><ReplicatedDeletedVersions>{}</ReplicatedDeletedVersions><SkippedExistingVersions>{}</SkippedExistingVersions><SkippedEncryptedObjects>{}</SkippedEncryptedObjects><SkippedMissingDestinations>{}</SkippedMissingDestinations></ReplicationRunResult>",
xml_escape(&result.source_bucket),
result.replicated_object_versions,
result.replicated_delete_markers,
result.replicated_deleted_versions,
result.skipped_existing_versions,
result.skipped_encrypted_objects,
result.skipped_missing_destinations
)
}
pub(crate) fn rule_filter_xml(tags: &BTreeMap<String, String>) -> String {
tags.iter()
.map(|(key, value)| {
format!(
"<Tag><Key>{}</Key><Value>{}</Value></Tag>",
xml_escape(key),
xml_escape(value)
)
})
.collect::<String>()
}
pub(crate) fn notification_filter_xml(rule: &NotificationRule) -> String {
let mut filter_rules = Vec::new();
if let Some(prefix) = &rule.filter_prefix {
filter_rules.push(FilterRule {
name: "prefix".to_string(),
value: prefix.clone(),
});
}
if let Some(suffix) = &rule.filter_suffix {
filter_rules.push(FilterRule {
name: "suffix".to_string(),
value: suffix.clone(),
});
}
let filter_rules = filter_rules
.iter()
.map(|filter_rule| {
format!(
"<FilterRule><Name>{}</Name><Value>{}</Value></FilterRule>",
xml_escape(&filter_rule.name),
xml_escape(&filter_rule.value)
)
})
.collect::<String>();
if filter_rules.is_empty() {
String::new()
} else {
format!("<Filter><S3Key>{filter_rules}</S3Key></Filter>")
}
}