graphile_worker_admin_ui 0.2.1

Embedded Leptos admin UI for graphile_worker
Documentation
use std::net::SocketAddr;

use graphile_worker::{Schema, WorkerUtils};
use sqlx::PgPool;

use super::auth::{generate_secret, AdminAuthConfig};
use super::error::AdminUiError;

#[derive(Clone)]
pub struct AdminServerConfig {
    pub pool: PgPool,
    pub utils: WorkerUtils,
    pub schema: Schema,
    pub schema_name: String,
    pub listen_addr: SocketAddr,
    pub auth: AdminAuthConfig,
    pub read_only: bool,
}

pub struct AdminServerConfigBuilder {
    pool: PgPool,
    utils: WorkerUtils,
    schema: Schema,
    schema_name: String,
    listen_addr: SocketAddr,
    auth: AdminAuthConfig,
    read_only: bool,
}

impl AdminServerConfig {
    pub fn builder(pool: PgPool, utils: WorkerUtils) -> AdminServerConfigBuilder {
        AdminServerConfigBuilder {
            pool,
            utils,
            schema: Schema::default(),
            schema_name: "graphile_worker".to_string(),
            listen_addr: SocketAddr::from(([127, 0, 0, 1], 4000)),
            auth: AdminAuthConfig::basic_with_random_password("admin"),
            read_only: false,
        }
    }

    pub fn validate(&self) -> Result<(), AdminUiError> {
        if matches!(self.auth, AdminAuthConfig::None) && !self.listen_addr.ip().is_loopback() {
            return Err(AdminUiError::InsecureNoAuth);
        }
        Ok(())
    }
}

impl AdminServerConfigBuilder {
    pub fn schema(mut self, schema: impl Into<Schema>) -> Self {
        self.schema = schema.into();
        self
    }

    pub fn schema_name(mut self, schema_name: impl Into<String>) -> Self {
        self.schema_name = schema_name.into();
        self
    }

    pub fn listen_addr(mut self, listen_addr: SocketAddr) -> Self {
        self.listen_addr = listen_addr;
        self
    }

    pub fn auth(mut self, auth: AdminAuthConfig) -> Self {
        self.auth = auth;
        self
    }

    pub fn read_only(mut self, read_only: bool) -> Self {
        self.read_only = read_only;
        self
    }

    pub fn build(self) -> Result<AdminServerConfig, AdminUiError> {
        let config = AdminServerConfig {
            pool: self.pool,
            utils: self.utils,
            schema: self.schema,
            schema_name: self.schema_name,
            listen_addr: self.listen_addr,
            auth: self.auth,
            read_only: self.read_only,
        };
        config.validate()?;
        Ok(config)
    }
}

#[derive(Clone)]
pub(crate) struct AppState {
    pub(crate) pool: PgPool,
    pub(crate) utils: WorkerUtils,
    pub(crate) schema: Schema,
    pub(crate) schema_name: String,
    pub(crate) auth: AdminAuthConfig,
    pub(crate) csrf_token: String,
    pub(crate) read_only: bool,
}

impl AppState {
    pub(crate) fn from_config(config: AdminServerConfig) -> Result<Self, AdminUiError> {
        config.validate()?;

        Ok(Self {
            pool: config.pool,
            utils: config.utils,
            schema: config.schema,
            schema_name: config.schema_name,
            auth: config.auth,
            csrf_token: generate_secret(),
            read_only: config.read_only,
        })
    }
}