rustauth-plugins 0.2.0

Official RustAuth plugin modules.
Documentation
use indexmap::IndexMap;
use rustauth_core::db::{DbField, DbFieldType, DbTable, ForeignKey, OnDelete};
use rustauth_core::plugin::PluginSchemaContribution;

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SiweSchemaOptions {
    table_name: Option<String>,
    field_names: IndexMap<String, String>,
}

impl SiweSchemaOptions {
    pub fn new() -> Self {
        Self::default()
    }

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

    #[must_use]
    pub fn field_name(
        mut self,
        logical_name: impl Into<String>,
        db_name: impl Into<String>,
    ) -> Self {
        self.field_names.insert(
            normalize_logical_field(&logical_name.into()),
            db_name.into(),
        );
        self
    }

    fn table_name_or_default(&self) -> String {
        self.table_name
            .clone()
            .unwrap_or_else(|| "wallet_addresses".to_owned())
    }

    fn field_name_or_default(&self, logical_name: &str) -> String {
        self.field_names
            .get(logical_name)
            .cloned()
            .unwrap_or_else(|| logical_name.to_owned())
    }

    pub(crate) fn metadata(&self) -> serde_json::Value {
        let mut fields = serde_json::Map::new();
        for logical_name in ["user_id", "address", "chain_id", "is_primary", "created_at"] {
            if let Some(db_name) = self.field_names.get(logical_name) {
                fields.insert(
                    metadata_field_key(logical_name),
                    serde_json::Value::String(db_name.clone()),
                );
            }
        }
        serde_json::json!({
            "walletAddress": {
                "modelName": self.table_name_or_default(),
                "fields": fields,
            }
        })
    }
}

fn normalize_logical_field(logical_name: &str) -> String {
    match logical_name {
        "userId" => "user_id".to_owned(),
        "chainId" => "chain_id".to_owned(),
        "isPrimary" => "is_primary".to_owned(),
        "createdAt" => "created_at".to_owned(),
        other => other.to_owned(),
    }
}

fn metadata_field_key(logical_name: &str) -> String {
    match logical_name {
        "user_id" => "userId".to_owned(),
        "chain_id" => "chainId".to_owned(),
        "is_primary" => "isPrimary".to_owned(),
        "created_at" => "createdAt".to_owned(),
        other => other.to_owned(),
    }
}

pub(crate) fn wallet_address_schema(options: &SiweSchemaOptions) -> PluginSchemaContribution {
    let mut fields = IndexMap::new();
    fields.insert(
        "id".to_owned(),
        DbField::new("id", DbFieldType::String).generated(),
    );
    fields.insert(
        "user_id".to_owned(),
        DbField::new(
            options.field_name_or_default("user_id"),
            DbFieldType::String,
        )
        .indexed()
        .references(ForeignKey::new("users", "id", OnDelete::Cascade)),
    );
    fields.insert(
        "address".to_owned(),
        DbField::new(
            options.field_name_or_default("address"),
            DbFieldType::String,
        ),
    );
    fields.insert(
        "chain_id".to_owned(),
        DbField::new(
            options.field_name_or_default("chain_id"),
            DbFieldType::Number,
        ),
    );
    fields.insert(
        "is_primary".to_owned(),
        DbField::new(
            options.field_name_or_default("is_primary"),
            DbFieldType::Boolean,
        ),
    );
    fields.insert(
        "created_at".to_owned(),
        DbField::new(
            options.field_name_or_default("created_at"),
            DbFieldType::Timestamp,
        )
        .generated(),
    );

    PluginSchemaContribution::table(
        "wallet_address",
        DbTable {
            name: options.table_name_or_default(),
            fields,
            order: Some(20),
        },
    )
}