Skip to main content

systemprompt_content/
list_branding_provider.rs

1//! Page-data provider supplying branding values to content list pages.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use std::sync::Arc;
7
8use async_trait::async_trait;
9use serde_json::Value;
10use systemprompt_models::ContentConfigRaw;
11use systemprompt_provider_contracts::{
12    PageContext, PageDataProvider, ProviderError, ProviderResult,
13};
14
15#[derive(Debug, Clone, Copy, Default)]
16pub struct DefaultListBrandingProvider;
17
18fn resolve_content_raw<'a>(ctx: &'a PageContext<'_>) -> ProviderResult<&'a ContentConfigRaw> {
19    ctx.content_config::<ContentConfigRaw>().ok_or_else(|| {
20        ProviderError::Configuration("ContentConfig not available in PageContext".into())
21    })
22}
23
24#[async_trait]
25impl PageDataProvider for DefaultListBrandingProvider {
26    fn provider_id(&self) -> &'static str {
27        "default-list-branding"
28    }
29
30    async fn provide_page_data(&self, ctx: &PageContext<'_>) -> ProviderResult<Value> {
31        let Some(source_name) = ctx.page_type.strip_suffix("-list") else {
32            return Ok(serde_json::json!({}));
33        };
34
35        let content_config = resolve_content_raw(ctx)?;
36
37        let source = content_config.content_sources.get(source_name);
38        let org = &content_config.metadata.structured_data.organization;
39        let language = ctx.web_config.i18n.default_locale.as_str();
40        let branding = &ctx.web_config.branding;
41
42        let source_branding = source.and_then(|s| s.branding.as_ref());
43
44        let blog_name = source_branding
45            .and_then(|b| b.name.as_deref())
46            .unwrap_or(&branding.name);
47
48        let blog_description = source_branding
49            .and_then(|b| b.description.as_deref())
50            .unwrap_or(&branding.description);
51
52        let blog_image = source_branding
53            .and_then(|b| b.image.as_deref())
54            .map_or_else(String::new, |img| format!("{}{}", org.url, img));
55
56        let blog_keywords = source_branding
57            .and_then(|b| b.keywords.as_deref())
58            .unwrap_or("");
59
60        Ok(serde_json::json!({
61            "BLOG_NAME": blog_name,
62            "BLOG_DESCRIPTION": blog_description,
63            "BLOG_IMAGE": blog_image,
64            "BLOG_KEYWORDS": blog_keywords,
65            "BLOG_URL": format!("{}/{}", org.url, source_name),
66            "BLOG_LANGUAGE": language,
67        }))
68    }
69}
70
71pub fn default_list_branding_provider() -> Arc<dyn PageDataProvider> {
72    Arc::new(DefaultListBrandingProvider)
73}