288 lines
8.3 KiB
Rust
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)
|
|
}
|
|
}
|