Files
oxspeak_server/src/services/server.rs
T
2026-10-18 18:46:52 +02:00

288 lines
8.3 KiB
Rust

use crate::domain::events::server::{
ServerCreatedEvent, ServerDeletedEvent, ServerUpdatedEvent, ServerUserCreatedEvent,
ServerUserDeletedEvent,
};
use crate::models::{role, role_user, server, server_user};
use crate::services::ServicesContext;
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, Set,
TransactionTrait,
};
use std::sync::Arc;
use uuid::Uuid;
#[derive(Debug, Clone)]
pub struct ServerService {
service_context: Arc<ServicesContext>,
}
impl ServerService {
pub fn new(service_context: Arc<ServicesContext>) -> Self {
Self { service_context }
}
pub async fn create_server(
&self,
name: String,
password: Option<String>,
is_default: bool,
owner_id: Uuid,
) -> Result<server::Model, anyhow::Error> {
let db = &self.service_context.repositories.server.context.db;
let event_bus = &self.service_context.event_bus;
let txn = db.begin().await?;
let active = server::ActiveModel {
name: Set(name),
password: Set(password),
is_default: Set(is_default),
owner_id: Set(Some(owner_id)),
..Default::default()
};
let srv = active.insert(&txn).await?;
let default_group = role::ActiveModel {
server_id: Set(srv.id),
name: Set("Member".to_string()),
is_default: Set(true),
..Default::default()
};
let default_group = default_group.insert(&txn).await?;
server_user::ActiveModel {
server_id: Set(srv.id),
user_id: Set(owner_id),
..Default::default()
}
.insert(&txn)
.await?;
role_user::ActiveModel {
role_id: Set(default_group.id),
user_id: Set(owner_id),
}
.insert(&txn)
.await?;
txn.commit().await?;
event_bus.emit(ServerCreatedEvent {
server: srv.clone(),
});
Ok(srv)
}
pub async fn join_server(
&self,
server_id: Uuid,
user_id: Uuid,
password: Option<String>,
) -> Result<server::Model, anyhow::Error> {
let db = &self.service_context.repositories.server.context.db;
let event_bus = &self.service_context.event_bus;
let txn = db.begin().await?;
let srv = server::Entity::find_by_id(server_id)
.one(&txn)
.await?
.ok_or_else(|| anyhow::anyhow!("Server not found"))?;
if srv.password != password {
return Err(anyhow::anyhow!("Invalid server password"));
}
if server_user::Entity::find()
.filter(server_user::Column::ServerId.eq(server_id))
.filter(server_user::Column::UserId.eq(user_id))
.one(&txn)
.await?
.is_some()
{
txn.commit().await?;
return Ok(srv);
}
let membership = server_user::ActiveModel {
server_id: Set(server_id),
user_id: Set(user_id),
..Default::default()
}
.insert(&txn)
.await?;
let default_role = role::Entity::find()
.filter(role::Column::ServerId.eq(server_id))
.filter(role::Column::IsDefault.eq(true))
.one(&txn)
.await?
.ok_or_else(|| anyhow::anyhow!("Default role not found"))?;
role_user::ActiveModel {
role_id: Set(default_role.id),
user_id: Set(user_id),
}
.insert(&txn)
.await?;
txn.commit().await?;
let services = self
.service_context
.services
.get()
.expect("services initialized");
if let Err(error) = self
.service_context
.repositories
.computed_permission
.full_sync_user(user_id, server_id)
.await
{
tracing::error!(%user_id, %server_id, ?error, "Unable to sync permissions on join");
}
if let Err(error) = services
.realtime_registry
.refresh_user(&self.service_context.repositories, user_id)
.await
{
tracing::error!(%user_id, ?error, "Unable to refresh realtime registry on join");
}
event_bus.emit(ServerUserCreatedEvent {
server_user: membership,
});
self.service_context
.repositories
.read_state
.mark_server_read(server_id, user_id)
.await?;
Ok(srv)
}
pub async fn update_server(
&self,
id: Uuid,
name: String,
is_default: bool,
) -> Result<server::Model, anyhow::Error> {
let db = &self.service_context.repositories.server.context.db;
let event_bus = &self.service_context.event_bus;
let txn = db.begin().await?;
let existing = server::Entity::find_by_id(id)
.one(&txn)
.await?
.ok_or_else(|| anyhow::anyhow!("Server not found"))?;
let mut active: server::ActiveModel = existing.into();
active.name = Set(name);
active.is_default = Set(is_default);
let srv = active.update(&txn).await?;
txn.commit().await?;
event_bus.emit(ServerUpdatedEvent {
server: srv.clone(),
});
Ok(srv)
}
pub async fn delete_server(&self, id: Uuid) -> Result<bool, anyhow::Error> {
let db = &self.service_context.repositories.server.context.db;
let event_bus = &self.service_context.event_bus;
let txn = db.begin().await?;
let existing = server::Entity::find_by_id(id)
.one(&txn)
.await?
.ok_or_else(|| anyhow::anyhow!("Server not found"))?;
let audience = server_user::Entity::find()
.filter(server_user::Column::ServerId.eq(id))
.all(&txn)
.await?
.into_iter()
.map(|member| member.user_id)
.collect::<Vec<_>>();
let res = server::Entity::delete_by_id(id).exec(&txn).await?;
let deleted = res.rows_affected > 0;
txn.commit().await?;
if deleted {
event_bus.emit(ServerDeletedEvent {
server: existing,
audience,
});
}
Ok(deleted)
}
pub async fn add_user(&self, server_id: Uuid, user_id: Uuid) -> Result<bool, anyhow::Error> {
let db = &self.service_context.repositories.server.context.db;
let event_bus = &self.service_context.event_bus;
let txn = db.begin().await?;
let membership = crate::models::server_user::ActiveModel {
server_id: Set(server_id),
user_id: Set(user_id),
..Default::default()
}
.insert(&txn)
.await?;
let role_id: Uuid = role::Entity::find()
.filter(role::Column::ServerId.eq(server_id))
.filter(role::Column::IsDefault.eq(true))
.select_only()
.column(role::Column::Id)
.into_tuple::<Uuid>()
.one(&txn)
.await?
.ok_or_else(|| anyhow::anyhow!("Rôle par défaut introuvable"))?;
txn.commit().await?;
event_bus.emit(ServerUserCreatedEvent {
server_user: membership,
});
Ok(true)
}
pub async fn remove_user(&self, server_id: Uuid, user_id: Uuid) -> Result<bool, anyhow::Error> {
let db = &self.service_context.repositories.server.context.db;
let event_bus = &self.service_context.event_bus;
let txn = db.begin().await?;
let membership = server_user::Entity::find()
.filter(server_user::Column::ServerId.eq(server_id))
.filter(server_user::Column::UserId.eq(user_id))
.one(&txn)
.await?;
let res = crate::models::server_user::Entity::delete_many()
.filter(crate::models::server_user::Column::ServerId.eq(server_id))
.filter(crate::models::server_user::Column::UserId.eq(user_id))
.exec(&txn)
.await?;
let deleted = res.rows_affected > 0;
txn.commit().await?;
if let Some(server_user) = membership.filter(|_| deleted) {
event_bus.emit(ServerUserDeletedEvent { server_user });
}
Ok(deleted)
}
}