aster_forge_config/
avatar.rs

1//! Gravatar configuration helpers.
2//!
3//! This module owns the configuration-facing parts of Gravatar handling:
4//! normalization of the stored base URL and runtime fallback to the conventional
5//! default base URL. Product crates still own avatar source policy, upload
6//! routes, cache headers, and which sizes they expose.
7
8use crate::{ConfigCoreError, Result};
9
10use aster_forge_utils::url::{HttpBaseUrlOptions, normalize_http_base_url};
11
12/// Default Gravatar base URL used by Aster services.
13pub const DEFAULT_GRAVATAR_BASE_URL: &str = "https://www.gravatar.com/avatar";
14
15/// Normalizes a Gravatar base URL configuration value.
16///
17/// Empty values fall back to [`DEFAULT_GRAVATAR_BASE_URL`]. Non-empty values
18/// must be absolute HTTP(S) base URLs without query or fragment components.
19///
20/// # Errors
21///
22/// Returns [`ConfigError`] when the Gravatar base URL is empty, malformed, or unsupported.
23pub fn normalize_gravatar_base_url_config_value(value: &str) -> Result<String> {
24    normalize_http_base_url(
25        value,
26        "gravatar_base_url",
27        HttpBaseUrlOptions::optional_without_query_fragment(),
28    )
29    .map_err(|error| ConfigCoreError::invalid_value(error.to_string()))
30    .map(|normalized| normalized.unwrap_or_else(|| DEFAULT_GRAVATAR_BASE_URL.to_string()))
31}
32
33/// Returns a normalized Gravatar base URL or [`DEFAULT_GRAVATAR_BASE_URL`].
34#[must_use]
35pub fn gravatar_base_url_or_default(value: Option<&str>) -> String {
36    let normalized = value
37        .unwrap_or(DEFAULT_GRAVATAR_BASE_URL)
38        .trim()
39        .trim_end_matches('/')
40        .to_string();
41    if normalized.is_empty() {
42        DEFAULT_GRAVATAR_BASE_URL.to_string()
43    } else {
44        normalized
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::{
51        DEFAULT_GRAVATAR_BASE_URL, gravatar_base_url_or_default,
52        normalize_gravatar_base_url_config_value,
53    };
54
55    #[test]
56    fn gravatar_base_url_normalization_accepts_empty_and_http_base_urls() {
57        assert_eq!(
58            normalize_gravatar_base_url_config_value("  ").unwrap(),
59            DEFAULT_GRAVATAR_BASE_URL
60        );
61        assert_eq!(
62            normalize_gravatar_base_url_config_value(" https://mirror.example/avatar/ ").unwrap(),
63            "https://mirror.example/avatar"
64        );
65        assert!(normalize_gravatar_base_url_config_value("ftp://example.com/avatar").is_err());
66        assert!(
67            normalize_gravatar_base_url_config_value("https://example.com/avatar?x=1").is_err()
68        );
69        assert!(
70            normalize_gravatar_base_url_config_value("https://example.com/avatar#frag").is_err()
71        );
72    }
73
74    #[test]
75    fn gravatar_base_url_reader_defaults_blank_values() {
76        assert_eq!(
77            gravatar_base_url_or_default(None),
78            DEFAULT_GRAVATAR_BASE_URL
79        );
80        assert_eq!(
81            gravatar_base_url_or_default(Some("   ")),
82            DEFAULT_GRAVATAR_BASE_URL
83        );
84        assert_eq!(
85            gravatar_base_url_or_default(Some("https://mirror.example/avatar/")),
86            "https://mirror.example/avatar"
87        );
88    }
89}