diff --git a/frontend/src/stores/server.ts b/frontend/src/stores/server.ts index e08bbb0..e19adb6 100644 --- a/frontend/src/stores/server.ts +++ b/frontend/src/stores/server.ts @@ -168,3 +168,20 @@ onGatewayEvent("Category", (payload) => { void useServerStore().fetchServerTree(category.server_id); } }); + +onGatewayEvent("ServerTree", (payload) => { + if (payload.action !== "refresh") return; + const serverId = String(payload.content); + if (serverId) void useServerStore().fetchServerTree(serverId); +}); + +onGatewayEvent("Server", (payload) => { + if (payload.action !== "update") return; + const updated = payload.content as Server; + const store = useServerStore(); + const index = store.servers.findIndex(server => server.id === updated.id); + if (index >= 0) { + updated.unread_count ??= store.servers[index].unread_count ?? 0; + store.servers[index] = updated; + } +}); diff --git a/src/domain/events/mod.rs b/src/domain/events/mod.rs index 9df5974..96150c7 100644 --- a/src/domain/events/mod.rs +++ b/src/domain/events/mod.rs @@ -2,3 +2,4 @@ pub mod channel; pub mod emoji; pub mod message; pub mod server; +pub mod server_tree; diff --git a/src/domain/events/server_tree.rs b/src/domain/events/server_tree.rs new file mode 100644 index 0000000..9a365e8 --- /dev/null +++ b/src/domain/events/server_tree.rs @@ -0,0 +1,8 @@ +use uuid::Uuid; + +#[derive(Debug, Clone)] +pub struct ServerTreeInvalidatedEvent { + pub server_id: Uuid, + /// `None` means every current member of the server. + pub user_ids: Option>, +} diff --git a/src/routes/gateway/mod.rs b/src/routes/gateway/mod.rs index b1f0372..11ec38f 100644 --- a/src/routes/gateway/mod.rs +++ b/src/routes/gateway/mod.rs @@ -6,6 +6,7 @@ use crate::domain::events::message::{ MessageCreatedEvent, MessageDeletedEvent, MessageReactionAddedEvent, MessageReactionRemovedEvent, MessageUpdatedEvent, }; +use crate::domain::events::server_tree::ServerTreeInvalidatedEvent; use crate::models::{category, server, server_user, user}; use crate::repositories::Repositories; use crate::routes::category::mapper::category_model_to_category_response; @@ -369,6 +370,23 @@ impl RealtimeRouter { }, ); + let router = Arc::clone(self); + event_bus.on_async::( + "server_tree_invalidated", + move |event| { + let router = Arc::clone(&router); + async move { + let users = match event.user_ids { + Some(users) => users, + None => router.server_users(event.server_id).await, + }; + router + .gateway + .send_to_users(users, "ServerTree", "refresh", event.server_id); + } + }, + ); + let router = Arc::clone(self); event_bus.on_async::("emoji_created", move |event| { let router = Arc::clone(&router); diff --git a/src/routes/server/handlers.rs b/src/routes/server/handlers.rs index a69aa39..b3ff11b 100644 --- a/src/routes/server/handlers.rs +++ b/src/routes/server/handlers.rs @@ -299,6 +299,9 @@ pub async fn set_user_permission( .server .set_user_permission(server_id, user_id, payload.permissions) .await?; + state + .event_bus + .emit("server_user_permission_updated", (server_id, user_id)); let permission = state .repositories @@ -346,6 +349,9 @@ pub async fn remove_user_permission( .server .remove_user_permission(server_id, user_id) .await?; + state + .event_bus + .emit("server_user_permission_updated", (server_id, user_id)); Ok(StatusCode::NO_CONTENT) } @@ -406,6 +412,9 @@ pub async fn set_role_permission( .server .set_role_permission(server_id, role_id, payload.permissions) .await?; + state + .event_bus + .emit("server_role_permission_updated", (role_id, server_id)); let permission = state .repositories @@ -453,6 +462,9 @@ pub async fn remove_role_permission( .server .remove_role_permission(server_id, role_id) .await?; + state + .event_bus + .emit("server_role_permission_updated", (role_id, server_id)); Ok(StatusCode::NO_CONTENT) } diff --git a/src/services/channel.rs b/src/services/channel.rs index 2c89cf6..b4d1cca 100644 --- a/src/services/channel.rs +++ b/src/services/channel.rs @@ -255,6 +255,14 @@ impl ChannelService { ) -> Result<(), anyhow::Error> { let db = &self.service_context.repositories.server.context.db; let event_bus = &self.service_context.event_bus; + let server_id = self + .service_context + .repositories + .channel + .get_by_id(channel_id) + .await? + .and_then(|channel| channel.server_id) + .ok_or_else(|| anyhow::anyhow!("Server channel not found"))?; let txn = db.begin().await?; @@ -279,10 +287,7 @@ impl ChannelService { txn.commit().await?; - event_bus.emit( - "channel_role_permission_created", - (channel_id, role_id, permissions), - ); + event_bus.emit("channel_role_permission_updated", (role_id, server_id)); Ok(()) } @@ -294,6 +299,14 @@ impl ChannelService { ) -> Result<(), anyhow::Error> { let db = &self.service_context.repositories.server.context.db; let event_bus = &self.service_context.event_bus; + let server_id = self + .service_context + .repositories + .channel + .get_by_id(channel_id) + .await? + .and_then(|channel| channel.server_id) + .ok_or_else(|| anyhow::anyhow!("Server channel not found"))?; let txn = db.begin().await?; @@ -305,7 +318,7 @@ impl ChannelService { txn.commit().await?; - event_bus.emit("channel_role_permission_deleted", (channel_id, role_id)); + event_bus.emit("channel_role_permission_updated", (role_id, server_id)); Ok(()) } diff --git a/src/services/permission_sync.rs b/src/services/permission_sync.rs index 58e8247..dca3e13 100644 --- a/src/services/permission_sync.rs +++ b/src/services/permission_sync.rs @@ -1,7 +1,9 @@ use crate::domain::events::channel::{ChannelCreatedEvent, ChannelDeletedEvent}; +use crate::domain::events::server_tree::ServerTreeInvalidatedEvent; use crate::models::server; use crate::repositories::Repositories; use crate::services::ServicesContext; +use event_bus::EventBus; use std::sync::Arc; use uuid::Uuid; // list of all events : @@ -57,6 +59,16 @@ pub struct PermissionSyncService { } impl PermissionSyncService { + fn invalidate_tree(event_bus: &Arc, server_id: Uuid, user_ids: Option>) { + event_bus.emit( + "server_tree_invalidated", + ServerTreeInvalidatedEvent { + server_id, + user_ids, + }, + ); + } + pub fn new(service_context: Arc) -> Self { Self { service_context } } @@ -70,6 +82,7 @@ impl PermissionSyncService { // --------------------------------------------------------------------- // Événements Serveur & Membres Serveur // --------------------------------------------------------------------- + let notify = event_bus.clone(); event_bus.on_async_with( "server_created", repositories.clone(), @@ -81,16 +94,25 @@ impl PermissionSyncService { event_bus.on_async_with( "server_user_created", repositories.clone(), - move |repositories, (server_id, user_id): (Uuid, Uuid)| async move { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, (server_id, user_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } }, ); + let notify = event_bus.clone(); event_bus.on_async_with( "server_user_deleted", repositories.clone(), - move |repositories, (server_id, user_id): (Uuid, Uuid)| async move { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, (server_id, user_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } }, ); @@ -98,19 +120,29 @@ impl PermissionSyncService { // Événements Rôles & Membres de Rôle // --------------------------------------------------------------------- + let notify = event_bus.clone(); event_bus.on_async_with( "role_user_created", repositories.clone(), - move |repositories, (_role_id, user_id, server_id): (Uuid, Uuid, Uuid)| async move { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, (_role_id, user_id, server_id): (Uuid, Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } }, ); + let notify = event_bus.clone(); event_bus.on_async_with( "role_user_deleted", repositories.clone(), - move |repositories, (_role_id, user_id, server_id): (Uuid, Uuid, Uuid)| async move { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, (_role_id, user_id, server_id): (Uuid, Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } }, ); @@ -118,19 +150,29 @@ impl PermissionSyncService { // Overrides de Permissions Serveur // --------------------------------------------------------------------- + let notify = event_bus.clone(); event_bus.on_async_with( "server_role_permission_updated", repositories.clone(), - move |repositories, (role_id, server_id): (Uuid, Uuid)| async move { - Self::sync_role_members(repositories, role_id, server_id).await; + move |repositories, (role_id, server_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_role_members(repositories, role_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, None); + } }, ); + let notify = event_bus.clone(); event_bus.on_async_with( "server_user_permission_updated", repositories.clone(), - move |repositories, (server_id, user_id): (Uuid, Uuid)| async move { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, (server_id, user_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } }, ); @@ -138,73 +180,103 @@ impl PermissionSyncService { // Événements Canaux & Overrides de Permissions Canaux // --------------------------------------------------------------------- + let notify = event_bus.clone(); event_bus.on_async_with( "channel_created", repositories.clone(), - move |repositories, event: ChannelCreatedEvent| async move { - if let Some(server_id) = event.channel.server_id { - Self::sync_server(repositories, server_id).await; - } - }, - ); - - event_bus.on_async_with( - "channel_deleted", - repositories.clone(), - move |repositories, event: ChannelDeletedEvent| async move { - if let Some(server_id) = event.channel.server_id { - Self::sync_server(repositories, server_id).await; - } - }, - ); - - event_bus.on_async_with( - "channel_role_permission_updated", - repositories.clone(), - move |repositories, (role_id, server_id): (Uuid, Uuid)| async move { - Self::sync_role_members(repositories, role_id, server_id).await; - }, - ); - - event_bus.on_async_with( - "channel_user_permission_updated", - repositories.clone(), - move |repositories, (server_id, user_id): (Uuid, Uuid)| async move { - Self::sync_user(repositories, user_id, server_id).await; - }, - ); - - event_bus.on_async_with( - "channel_user_permission_created", - repositories.clone(), - move |repositories, (channel_id, user_id, _permissions): (Uuid, Uuid, u64)| async move { - if let Some(channel) = repositories - .channel - .get_by_id(channel_id) - .await - .ok() - .flatten() - { - if let Some(server_id) = channel.server_id { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, event: ChannelCreatedEvent| { + let notify = notify.clone(); + async move { + if let Some(server_id) = event.channel.server_id { + Self::sync_server(repositories, server_id).await; + Self::invalidate_tree(¬ify, server_id, None); } } }, ); + let notify = event_bus.clone(); + event_bus.on_async_with( + "channel_deleted", + repositories.clone(), + move |repositories, event: ChannelDeletedEvent| { + let notify = notify.clone(); + async move { + if let Some(server_id) = event.channel.server_id { + Self::sync_server(repositories, server_id).await; + Self::invalidate_tree(¬ify, server_id, None); + } + } + }, + ); + + let notify = event_bus.clone(); + event_bus.on_async_with( + "channel_role_permission_updated", + repositories.clone(), + move |repositories, (role_id, server_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_role_members(repositories, role_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, None); + } + }, + ); + + let notify = event_bus.clone(); + event_bus.on_async_with( + "channel_user_permission_updated", + repositories.clone(), + move |repositories, (server_id, user_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } + }, + ); + + let notify = event_bus.clone(); + event_bus.on_async_with( + "channel_user_permission_created", + repositories.clone(), + move |repositories, (channel_id, user_id, _permissions): (Uuid, Uuid, u64)| { + let notify = notify.clone(); + async move { + if let Some(channel) = repositories + .channel + .get_by_id(channel_id) + .await + .ok() + .flatten() + { + if let Some(server_id) = channel.server_id { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } + } + } + }, + ); + + let notify = event_bus.clone(); event_bus.on_async_with( "channel_user_permission_deleted", repositories, - move |repositories, (channel_id, user_id): (Uuid, Uuid)| async move { - if let Some(channel) = repositories - .channel - .get_by_id(channel_id) - .await - .ok() - .flatten() - { - if let Some(server_id) = channel.server_id { - Self::sync_user(repositories, user_id, server_id).await; + move |repositories, (channel_id, user_id): (Uuid, Uuid)| { + let notify = notify.clone(); + async move { + if let Some(channel) = repositories + .channel + .get_by_id(channel_id) + .await + .ok() + .flatten() + { + if let Some(server_id) = channel.server_id { + Self::sync_user(repositories, user_id, server_id).await; + Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); + } } } },