fix(admin): use instance branding on self-hosted (#3401)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-11 15:57:12 +02:00
1 parent af7724dbf6
commit 50c28aa8fa
9 files changed
+206 -49

No files matched your search

+9
View File
@@ -49,6 +49,15 @@ impl AdminApiClient {
Self { generated }
}
pub fn anonymous(http_client: &reqwest::Client, config: &AdminConfig) -> Self {
let generated = GeneratedClient::new_with_client(
&config.api_endpoint,
http_client.clone(),
build_proxy_client_ip_headers(config),
);
Self { generated }
}
fn build_url(&self, path: &str, query_params: Option<&[(&str, &str)]>) -> String {
let mut url = format!("{}{}", self.generated.baseurl(), path);
let query = query_params
+76 -17
View File
@@ -119,6 +119,9 @@ pub struct InstancePremiumDiscoveryAppPublic {
#[derive(Clone, Debug, Default, Deserialize)]
pub struct InstancePremiumDiscoveryBranding {
pub product_name: Option<String>,
pub icon_url: Option<String>,
pub favicon_url: Option<String>,
pub premium_product_name: Option<String>,
}
@@ -130,46 +133,67 @@ pub struct InstancePremiumDiscoveryFeatures {
impl InstancePremiumDiscovery {
pub fn premium_product_name(&self) -> Option<&str> {
self.app_public
.branding
.premium_product_name
.as_deref()
.map(str::trim)
.filter(|name| !name.is_empty())
non_blank(self.app_public.branding.premium_product_name.as_deref())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct PremiumBranding {
pub name: Option<String>,
pub premium_enabled: bool,
pub product_name: Option<String>,
pub favicon_url: Option<String>,
}
impl PremiumBranding {
pub fn from_discovery(discovery: &InstancePremiumDiscovery) -> Self {
let branding = &discovery.app_public.branding;
Self {
name: discovery.premium_product_name().map(str::to_owned),
premium_enabled: discovery.features.premium_enabled,
product_name: non_blank(branding.product_name.as_deref()).map(str::to_owned),
favicon_url: favicon_url(
branding.favicon_url.as_deref(),
branding.icon_url.as_deref(),
),
}
}
pub fn from_instance_config(config: &InstanceConfigResponse) -> Self {
Self::from_config_parts(
config.self_hosted,
&config.app_public.branding.premium_product_name,
config.policy.premium_mode,
)
let branding = &config.app_public.branding;
Self {
product_name: non_blank(Some(&branding.product_name)).map(str::to_owned),
favicon_url: favicon_url(
branding.favicon_url.as_deref(),
branding.icon_url.as_deref(),
),
..Self::from_config_parts(
config.self_hosted,
&branding.premium_product_name,
config.policy.premium_mode,
)
}
}
fn from_config_parts(self_hosted: bool, name: &str, premium_mode: PremiumMode) -> Self {
let name = name.trim();
Self {
name: (!name.is_empty()).then(|| name.to_owned()),
name: non_blank(Some(name)).map(str::to_owned),
premium_enabled: !self_hosted || matches!(premium_mode, PremiumMode::Mirror),
..Self::default()
}
}
}
fn non_blank(value: Option<&str>) -> Option<&str> {
value.map(str::trim).filter(|value| !value.is_empty())
}
fn favicon_url(favicon_url: Option<&str>, icon_url: Option<&str>) -> Option<String> {
non_blank(favicon_url)
.or_else(|| non_blank(icon_url))
.map(str::to_owned)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -304,18 +328,52 @@ mod tests {
PremiumBranding::from_discovery(&discovery),
PremiumBranding {
name: Some("Gold".to_owned()),
premium_enabled: true
premium_enabled: true,
product_name: Some("Example".to_owned()),
favicon_url: None,
}
);
}
#[test]
fn instance_branding_prefers_the_favicon_and_falls_back_to_the_icon() {
let discovery = |branding| -> InstancePremiumDiscovery {
serde_json::from_value(json!({"app_public": {"branding": branding}}))
.expect("discovery")
};
let both = discovery(json!({
"favicon_url": "https://media.example/favicon.png",
"icon_url": "https://media.example/icon.png"
}));
assert_eq!(
PremiumBranding::from_discovery(&both)
.favicon_url
.as_deref(),
Some("https://media.example/favicon.png")
);
let icon_only =
discovery(json!({"favicon_url": " ", "icon_url": "https://media.example/icon.png"}));
assert_eq!(
PremiumBranding::from_discovery(&icon_only)
.favicon_url
.as_deref(),
Some("https://media.example/icon.png")
);
let neither = discovery(json!({"product_name": " "}));
assert_eq!(
PremiumBranding::from_discovery(&neither),
PremiumBranding::default()
);
}
#[test]
fn premium_branding_from_instance_config_matches_discovery_rules() {
assert_eq!(
PremiumBranding::from_config_parts(true, " Gold ", PremiumMode::Everyone),
PremiumBranding {
name: Some("Gold".to_owned()),
premium_enabled: false
premium_enabled: false,
..PremiumBranding::default()
}
);
assert!(
@@ -325,7 +383,8 @@ mod tests {
PremiumBranding::from_config_parts(false, " ", PremiumMode::Everyone),
PremiumBranding {
name: None,
premium_enabled: true
premium_enabled: true,
..PremiumBranding::default()
}
);
}