init
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
use crate::domain::events::message::{
|
||||
MessageCreatedEvent, MessageDeletedEvent, MessageUpdatedEvent,
|
||||
MessageCreatedEvent, MessageDeletedEvent, MessageReactionAddedEvent,
|
||||
MessageReactionRemovedEvent, MessageUpdatedEvent,
|
||||
};
|
||||
use crate::models::user::Model as User;
|
||||
use crate::routes::category::mapper::category_model_to_category_response;
|
||||
use crate::routes::channel::mapper::channel_model_to_channel_response;
|
||||
use crate::routes::message::mapper::message_model_to_message_response_with_server_id;
|
||||
use crate::routes::message::mapper::{
|
||||
message_model_to_message_response_with_reactions,
|
||||
message_model_to_message_response_with_server_id, reaction_model_to_response,
|
||||
};
|
||||
use crate::routes::server::mapper::server_model_to_server_response;
|
||||
use crate::services::Services;
|
||||
use axum::extract::ws::Message;
|
||||
@@ -70,12 +74,22 @@ impl GatewayManager {
|
||||
event_bus.on_async::<MessageUpdatedEvent, _, _>("message_updated", move |event| {
|
||||
let manager = Arc::clone(&manager);
|
||||
async move {
|
||||
let message_id = event.message.id;
|
||||
let reactions = manager
|
||||
.services
|
||||
.message_reaction
|
||||
.grouped_for_messages(&[message_id])
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|mut groups| groups.remove(&message_id))
|
||||
.unwrap_or_default();
|
||||
manager.broadcast_message(
|
||||
event.channel_id,
|
||||
"update",
|
||||
message_model_to_message_response_with_server_id(
|
||||
message_model_to_message_response_with_reactions(
|
||||
event.message,
|
||||
event.server_id,
|
||||
reactions,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -88,6 +102,36 @@ impl GatewayManager {
|
||||
manager.broadcast_message(event.channel_id, "remove", event.message.id);
|
||||
}
|
||||
});
|
||||
|
||||
let manager = Arc::clone(self);
|
||||
event_bus.on_async::<MessageReactionAddedEvent, _, _>(
|
||||
"message_reaction_added",
|
||||
move |event| {
|
||||
let manager = Arc::clone(&manager);
|
||||
async move {
|
||||
manager.broadcast_reaction(
|
||||
event.channel_id,
|
||||
"add",
|
||||
reaction_model_to_response(event.reaction),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let manager = Arc::clone(self);
|
||||
event_bus.on_async::<MessageReactionRemovedEvent, _, _>(
|
||||
"message_reaction_removed",
|
||||
move |event| {
|
||||
let manager = Arc::clone(&manager);
|
||||
async move {
|
||||
manager.broadcast_reaction(
|
||||
event.channel_id,
|
||||
"remove",
|
||||
reaction_model_to_response(event.reaction),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn add_client(&self, gateway_client: GatewayClient) {
|
||||
@@ -126,6 +170,33 @@ impl GatewayManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn broadcast_reaction<T: serde::Serialize>(
|
||||
&self,
|
||||
channel_id: Uuid,
|
||||
action: &'static str,
|
||||
content: T,
|
||||
) {
|
||||
let event = GatewayEvent {
|
||||
namespace: "Reaction",
|
||||
action,
|
||||
content,
|
||||
};
|
||||
let Ok(json) = serde_json::to_string(&event) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let users = self
|
||||
.services
|
||||
.realtime_registry
|
||||
.users_for_channel(channel_id);
|
||||
let clients = self.clients.read();
|
||||
for (key, client) in clients.iter() {
|
||||
if users.contains(&key.user_id) {
|
||||
let _ = client.sender.send(Message::Text(json.clone().into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GatewayClient {
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::domain::dto::message::{
|
||||
CreateMessageRequest, MessagePageResponse, MessageQueryParams, MessageResponse,
|
||||
UpdateMessageRequest,
|
||||
};
|
||||
use crate::domain::dto::reaction::{CreateReactionRequest, DeleteReactionQuery, ReactionResponse};
|
||||
use crate::http::context::CurrentUser;
|
||||
use crate::http::error::HTTPError;
|
||||
use crate::routes::message::mapper;
|
||||
@@ -39,6 +40,12 @@ pub async fn get_all(
|
||||
|
||||
let params = mapper::query_params_to_message_filter(filters);
|
||||
let page = state.repositories.message.filter(params).await?;
|
||||
let message_ids: Vec<_> = page.messages.iter().map(|message| message.id).collect();
|
||||
let mut reactions = state
|
||||
.services
|
||||
.message_reaction
|
||||
.grouped_for_messages(&message_ids)
|
||||
.await?;
|
||||
let oldest_id = page.messages.first().map(|message| message.id);
|
||||
let newest_id = page.messages.last().map(|message| message.id);
|
||||
|
||||
@@ -46,7 +53,10 @@ pub async fn get_all(
|
||||
messages: page
|
||||
.messages
|
||||
.into_iter()
|
||||
.map(mapper::message_model_to_message_response)
|
||||
.map(|message| {
|
||||
let groups = reactions.remove(&message.id).unwrap_or_default();
|
||||
mapper::message_model_to_message_response_with_reactions(message, None, groups)
|
||||
})
|
||||
.collect(),
|
||||
oldest_id,
|
||||
newest_id,
|
||||
@@ -80,7 +90,17 @@ pub async fn get_by_id(
|
||||
.await?
|
||||
.ok_or(HTTPError::NotFound)?;
|
||||
|
||||
Ok(Json(mapper::message_model_to_message_response(message)))
|
||||
let reactions = state
|
||||
.services
|
||||
.message_reaction
|
||||
.grouped_for_messages(&[id])
|
||||
.await?
|
||||
.remove(&id)
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(Json(
|
||||
mapper::message_model_to_message_response_with_reactions(message, None, reactions),
|
||||
))
|
||||
}
|
||||
|
||||
/// Crée un nouveau message
|
||||
@@ -181,7 +201,81 @@ pub async fn update(
|
||||
.update_message(id, payload.content)
|
||||
.await?;
|
||||
|
||||
Ok(Json(mapper::message_model_to_message_response(message)))
|
||||
let reactions = state
|
||||
.services
|
||||
.message_reaction
|
||||
.grouped_for_messages(&[id])
|
||||
.await?
|
||||
.remove(&id)
|
||||
.unwrap_or_default();
|
||||
Ok(Json(
|
||||
mapper::message_model_to_message_response_with_reactions(message, None, reactions),
|
||||
))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/messages/{message_id}/reactions",
|
||||
request_body = CreateReactionRequest,
|
||||
responses(
|
||||
(status = 201, description = "Réaction ajoutée", body = ReactionResponse),
|
||||
(status = 200, description = "Réaction déjà présente", body = ReactionResponse),
|
||||
(status = 400, description = "Emoji ou ton invalide"),
|
||||
(status = 404, description = "Message non trouvé")
|
||||
),
|
||||
params(("message_id" = Uuid, Path)),
|
||||
tag = "Messages",
|
||||
security(("bearerAuth" = []))
|
||||
)]
|
||||
pub async fn add_reaction(
|
||||
user: CurrentUser,
|
||||
State(state): State<AppState>,
|
||||
Path(message_id): Path<Uuid>,
|
||||
Json(payload): Json<CreateReactionRequest>,
|
||||
) -> Result<(StatusCode, Json<ReactionResponse>), HTTPError> {
|
||||
let (reaction, created) = state
|
||||
.services
|
||||
.message_reaction
|
||||
.add(message_id, user.id, payload.emoji_id, payload.skin_tone)
|
||||
.await?;
|
||||
Ok((
|
||||
if created {
|
||||
StatusCode::CREATED
|
||||
} else {
|
||||
StatusCode::OK
|
||||
},
|
||||
Json(mapper::reaction_model_to_response(reaction)),
|
||||
))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/messages/{message_id}/reactions/{emoji_id}",
|
||||
responses(
|
||||
(status = 204, description = "Réaction supprimée"),
|
||||
(status = 400, description = "Emoji ou ton invalide"),
|
||||
(status = 404, description = "Réaction non trouvée")
|
||||
),
|
||||
params(
|
||||
("message_id" = Uuid, Path),
|
||||
("emoji_id" = Uuid, Path),
|
||||
DeleteReactionQuery
|
||||
),
|
||||
tag = "Messages",
|
||||
security(("bearerAuth" = []))
|
||||
)]
|
||||
pub async fn remove_reaction(
|
||||
user: CurrentUser,
|
||||
State(state): State<AppState>,
|
||||
Path((message_id, emoji_id)): Path<(Uuid, Uuid)>,
|
||||
Query(query): Query<DeleteReactionQuery>,
|
||||
) -> Result<StatusCode, HTTPError> {
|
||||
state
|
||||
.services
|
||||
.message_reaction
|
||||
.remove(message_id, user.id, emoji_id, query.skin_tone)
|
||||
.await?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
/// Supprime un message
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use crate::domain::dto::message::{
|
||||
CreateMessageRequest, MessageQueryParams, MessageResponse, UpdateMessageRequest,
|
||||
};
|
||||
use crate::domain::dto::reaction::ReactionGroupResponse;
|
||||
use crate::domain::dto::reaction::ReactionResponse;
|
||||
use crate::models::message;
|
||||
use crate::models::message_reaction;
|
||||
use crate::repositories::types::MessageFilter;
|
||||
use chrono::Utc;
|
||||
use sea_orm::Set;
|
||||
@@ -14,6 +17,14 @@ pub fn message_model_to_message_response(model: message::Model) -> MessageRespon
|
||||
pub fn message_model_to_message_response_with_server_id(
|
||||
model: message::Model,
|
||||
server_id: Option<Uuid>,
|
||||
) -> MessageResponse {
|
||||
message_model_to_message_response_with_reactions(model, server_id, Vec::new())
|
||||
}
|
||||
|
||||
pub fn message_model_to_message_response_with_reactions(
|
||||
model: message::Model,
|
||||
server_id: Option<Uuid>,
|
||||
reactions: Vec<ReactionGroupResponse>,
|
||||
) -> MessageResponse {
|
||||
MessageResponse {
|
||||
id: model.id,
|
||||
@@ -24,6 +35,7 @@ pub fn message_model_to_message_response_with_server_id(
|
||||
created_at: model.created_at,
|
||||
updated_at: model.updated_at,
|
||||
reply_to_id: model.reply_to_id,
|
||||
reactions,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,3 +74,14 @@ pub fn query_params_to_message_filter(params: MessageQueryParams) -> MessageFilt
|
||||
limit: params.limit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reaction_model_to_response(model: message_reaction::Model) -> ReactionResponse {
|
||||
ReactionResponse {
|
||||
id: model.id,
|
||||
message_id: model.message_id,
|
||||
user_id: model.user_id,
|
||||
emoji_id: model.emoji_id,
|
||||
skin_tone: (model.skin_tone != 0).then_some(model.skin_tone as u8),
|
||||
created_at: model.created_at,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,12 @@ pub fn router() -> Router<AppState> {
|
||||
.put(handlers::update)
|
||||
.delete(handlers::delete),
|
||||
)
|
||||
.route(
|
||||
"/messages/{message_id}/reactions",
|
||||
axum::routing::post(handlers::add_reaction),
|
||||
)
|
||||
.route(
|
||||
"/messages/{message_id}/reactions/{emoji_id}",
|
||||
axum::routing::delete(handlers::remove_reaction),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ use utoipa::{Modify, OpenApi};
|
||||
message::handlers::create,
|
||||
message::handlers::update,
|
||||
message::handlers::delete,
|
||||
message::handlers::add_reaction,
|
||||
message::handlers::remove_reaction,
|
||||
core::handlers::join,
|
||||
emoji::handlers::get_all,
|
||||
emoji::handlers::get_by_id,
|
||||
@@ -73,6 +75,9 @@ use utoipa::{Modify, OpenApi};
|
||||
crate::domain::dto::message::MessageResponse,
|
||||
crate::domain::dto::message::CreateMessageRequest,
|
||||
crate::domain::dto::message::UpdateMessageRequest,
|
||||
crate::domain::dto::reaction::CreateReactionRequest,
|
||||
crate::domain::dto::reaction::ReactionResponse,
|
||||
crate::domain::dto::reaction::ReactionGroupResponse,
|
||||
crate::domain::dto::core::JoinRequest,
|
||||
ChannelType,
|
||||
crate::domain::dto::emoji::EmojiResponse,
|
||||
|
||||
Reference in New Issue
Block a user