portfu_admin 1.3.2

Library of Admin tools build on toip of Portfu
Documentation
use crate::themes::default::DEFAULT_THEME;
use crate::themes::token::Token;
use crate::themes::Theme;
use portfu::pfcore::editable::EditResult;
use portfu::pfcore::service::{Service, ServiceBuilder};
use portfu::pfcore::{ServiceData, ServiceHandler, ServiceRegister, ServiceRegistry, ServiceType};
use portfu::prelude::async_trait::async_trait;
use portfu::prelude::http::Extensions;
use std::collections::HashMap;
use std::io::Error;
use std::sync::Arc;
use tokio::sync::RwLock;

#[derive(Clone)]
pub struct ThemeSelector {
    pub themes: Arc<RwLock<HashMap<String, Arc<Theme>>>>,
    pub tokens: Arc<RwLock<Vec<Token>>>,
    pub selected_theme: Arc<RwLock<Arc<Theme>>>,
}
impl Default for ThemeSelector {
    fn default() -> Self {
        Self {
            themes: Arc::new(RwLock::new(HashMap::from([(
                String::from("default"),
                DEFAULT_THEME.clone(),
            )]))),
            tokens: Default::default(),
            selected_theme: Arc::new(RwLock::new(DEFAULT_THEME.clone())),
        }
    }
}
#[async_trait]
impl ServiceHandler for ThemeSelector {
    fn name(&self) -> &str {
        "ThemeSelector"
    }

    async fn handle(&self, data: ServiceData) -> Result<ServiceData, (ServiceData, Error)> {
        let theme = self.selected_theme.read().await.clone();
        let tokens = self.tokens.clone();
        theme.render(data, tokens).await
    }
    fn is_editable(&self) -> bool {
        true
    }

    fn service_type(&self) -> ServiceType {
        ServiceType::API
    }

    async fn current_value(&self) -> EditResult {
        EditResult::Success(self.selected_theme.read().await.name.as_bytes().to_vec())
    }
    async fn update_value(&self, new_value: Vec<u8>, _: Option<Vec<u8>>) -> EditResult {
        let theme_as_string = String::from_utf8_lossy(&new_value);
        if let Some(theme) = self
            .themes
            .read()
            .await
            .get(theme_as_string.as_ref())
            .cloned()
        {
            *self.selected_theme.write().await = theme;
            EditResult::Success(new_value)
        } else {
            EditResult::Failed(format!("Failed to find theme with name: {theme_as_string}"))
        }
    }
}
impl ServiceRegister for ThemeSelector {
    fn register(self, service_registry: &mut ServiceRegistry, _: Extensions) {
        service_registry.register(self.into())
    }
}
impl From<ThemeSelector> for Service {
    fn from(value: ThemeSelector) -> Self {
        ServiceBuilder::new("/*")
            .name(value.name())
            .handler(Arc::new(value))
            .build()
    }
}