rustauth-plugins 0.2.0

Official RustAuth plugin modules.
Documentation
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use rustauth_core::error::RustAuthError;

use super::hooks::AnonymousLinkAccount;

pub type AnonymousOptionFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
pub type GenerateRandomEmail = Arc<dyn Fn() -> AnonymousOptionFuture<String> + Send + Sync>;
pub type GenerateName = Arc<dyn Fn() -> AnonymousOptionFuture<String> + Send + Sync>;
pub type OnLinkAccount = Arc<
    dyn Fn(AnonymousLinkAccount) -> AnonymousOptionFuture<Result<(), RustAuthError>> + Send + Sync,
>;

#[derive(Clone, Default)]
pub struct AnonymousOptions {
    pub email_domain_name: Option<String>,
    pub generate_random_email: Option<GenerateRandomEmail>,
    pub generate_name: Option<GenerateName>,
    pub disable_delete_anonymous_user: bool,
    pub on_link_account: Option<OnLinkAccount>,
    pub field_name: Option<String>,
}

impl AnonymousOptions {
    #[must_use]
    pub fn builder() -> AnonymousOptionsBuilder {
        AnonymousOptionsBuilder::default()
    }

    pub(crate) fn storage_field_name(&self) -> &str {
        self.field_name.as_deref().unwrap_or("is_anonymous")
    }

    #[must_use]
    pub fn email_domain_name(mut self, domain: impl Into<String>) -> Self {
        self.email_domain_name = Some(domain.into());
        self
    }

    #[must_use]
    pub fn generate_random_email<F>(mut self, generator: F) -> Self
    where
        F: Fn() -> String + Send + Sync + 'static,
    {
        self.generate_random_email = Some(Arc::new(move || {
            let value = generator();
            Box::pin(std::future::ready(value))
        }));
        self
    }

    #[must_use]
    pub fn generate_random_email_async<F, Fut>(mut self, generator: F) -> Self
    where
        F: Fn() -> Fut + Send + Sync + 'static,
        Fut: Future<Output = String> + Send + 'static,
    {
        self.generate_random_email = Some(Arc::new(move || Box::pin(generator())));
        self
    }

    #[must_use]
    pub fn generate_name<F>(mut self, generator: F) -> Self
    where
        F: Fn() -> String + Send + Sync + 'static,
    {
        self.generate_name = Some(Arc::new(move || {
            let value = generator();
            Box::pin(std::future::ready(value))
        }));
        self
    }

    #[must_use]
    pub fn generate_name_async<F, Fut>(mut self, generator: F) -> Self
    where
        F: Fn() -> Fut + Send + Sync + 'static,
        Fut: Future<Output = String> + Send + 'static,
    {
        self.generate_name = Some(Arc::new(move || Box::pin(generator())));
        self
    }

    #[must_use]
    pub fn disable_delete_anonymous_user(mut self, disabled: bool) -> Self {
        self.disable_delete_anonymous_user = disabled;
        self
    }

    #[must_use]
    pub fn on_link_account<F>(mut self, callback: F) -> Self
    where
        F: Fn(AnonymousLinkAccount) -> Result<(), RustAuthError> + Send + Sync + 'static,
    {
        self.on_link_account = Some(Arc::new(move |data| {
            let result = callback(data);
            Box::pin(std::future::ready(result))
        }));
        self
    }

    #[must_use]
    pub fn on_link_account_async<F, Fut>(mut self, callback: F) -> Self
    where
        F: Fn(AnonymousLinkAccount) -> Fut + Send + Sync + 'static,
        Fut: Future<Output = Result<(), RustAuthError>> + Send + 'static,
    {
        self.on_link_account = Some(Arc::new(move |data| Box::pin(callback(data))));
        self
    }

    #[must_use]
    pub fn field_name(mut self, field_name: impl Into<String>) -> Self {
        self.field_name = Some(field_name.into());
        self
    }
}

#[derive(Clone, Default)]
pub struct AnonymousOptionsBuilder {
    email_domain_name: Option<String>,
    generate_random_email: Option<GenerateRandomEmail>,
    generate_name: Option<GenerateName>,
    disable_delete_anonymous_user: Option<bool>,
    on_link_account: Option<OnLinkAccount>,
    field_name: Option<String>,
}

impl AnonymousOptionsBuilder {
    #[must_use]
    pub fn email_domain_name(mut self, domain: impl Into<String>) -> Self {
        self.email_domain_name = Some(domain.into());
        self
    }

    #[must_use]
    pub fn generate_random_email(mut self, generator: GenerateRandomEmail) -> Self {
        self.generate_random_email = Some(generator);
        self
    }

    #[must_use]
    pub fn generate_name(mut self, generator: GenerateName) -> Self {
        self.generate_name = Some(generator);
        self
    }

    #[must_use]
    pub fn disable_delete_anonymous_user(mut self, disabled: bool) -> Self {
        self.disable_delete_anonymous_user = Some(disabled);
        self
    }

    #[must_use]
    pub fn on_link_account(mut self, callback: OnLinkAccount) -> Self {
        self.on_link_account = Some(callback);
        self
    }

    #[must_use]
    pub fn field_name(mut self, field_name: impl Into<String>) -> Self {
        self.field_name = Some(field_name.into());
        self
    }

    #[must_use]
    pub fn build(self) -> AnonymousOptions {
        let defaults = AnonymousOptions::default();
        AnonymousOptions {
            email_domain_name: self.email_domain_name.or(defaults.email_domain_name),
            generate_random_email: self
                .generate_random_email
                .or(defaults.generate_random_email),
            generate_name: self.generate_name.or(defaults.generate_name),
            disable_delete_anonymous_user: self
                .disable_delete_anonymous_user
                .unwrap_or(defaults.disable_delete_anonymous_user),
            on_link_account: self.on_link_account.or(defaults.on_link_account),
            field_name: self.field_name.or(defaults.field_name),
        }
    }
}