bucketwarden-server 0.1.0

BucketWarden storage server runtime.
Documentation
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>")
    }
}