feat: add is_admin to User, count_users, ProviderConfigRepository trait, admin migration

This commit is contained in:
2026-03-16 03:22:00 +01:00
parent b35054f23e
commit d80d4e9741
6 changed files with 65 additions and 14 deletions

View File

@@ -22,6 +22,7 @@ pub struct User {
pub subject: String,
pub email: Email,
pub password_hash: Option<String>,
pub is_admin: bool,
pub created_at: DateTime<Utc>,
}
@@ -32,6 +33,7 @@ impl User {
subject: subject.into(),
email,
password_hash: None,
is_admin: false,
created_at: Utc::now(),
}
}
@@ -41,6 +43,7 @@ impl User {
subject: impl Into<String>,
email: Email,
password_hash: Option<String>,
is_admin: bool,
created_at: DateTime<Utc>,
) -> Self {
Self {
@@ -48,6 +51,7 @@ impl User {
subject: subject.into(),
email,
password_hash,
is_admin,
created_at,
}
}
@@ -58,6 +62,7 @@ impl User {
subject: format!("local|{}", Uuid::new_v4()),
email,
password_hash: Some(password_hash.into()),
is_admin: false,
created_at: Utc::now(),
}
}

View File

@@ -39,6 +39,24 @@ pub trait UserRepository: Send + Sync {
/// Delete a user by their ID
async fn delete(&self, id: Uuid) -> DomainResult<()>;
/// Count total number of users (used for first-user admin promotion)
async fn count_users(&self) -> DomainResult<u64>;
}
#[derive(Debug, Clone)]
pub struct ProviderConfigRow {
pub provider_type: String,
pub config_json: String,
pub enabled: bool,
pub updated_at: String,
}
#[async_trait]
pub trait ProviderConfigRepository: Send + Sync {
async fn get_all(&self) -> DomainResult<Vec<ProviderConfigRow>>;
async fn upsert(&self, row: &ProviderConfigRow) -> DomainResult<()>;
async fn delete(&self, provider_type: &str) -> DomainResult<()>;
}
/// Repository port for `Channel` persistence.

View File

@@ -31,7 +31,10 @@ impl UserService {
}
let email = Email::try_from(email)?;
let user = User::new(subject, email);
let mut user = User::new(subject, email);
if self.user_repository.count_users().await? == 0 {
user.is_admin = true;
}
self.user_repository.save(&user).await?;
Ok(user)
}
@@ -53,7 +56,10 @@ impl UserService {
password_hash: &str,
) -> DomainResult<User> {
let email = Email::try_from(email)?;
let user = User::new_local(email, password_hash);
let mut user = User::new_local(email, password_hash);
if self.user_repository.count_users().await? == 0 {
user.is_admin = true;
}
self.user_repository.save(&user).await?;
Ok(user)
}