diff --git a/lemmy_api/src/comment.rs b/lemmy_api/src/comment.rs index e9ed0a445..2b0ee0544 100644 --- a/lemmy_api/src/comment.rs +++ b/lemmy_api/src/comment.rs @@ -34,6 +34,7 @@ use lemmy_utils::{ }; use lemmy_websocket::{messages::{SendComment, SendUserRoomMessage}, LemmyContext, UserOperation}; use std::str::FromStr; +use lemmy_websocket::messages::SendModRoomMessage; #[async_trait::async_trait(?Send)] impl Perform for CreateComment { @@ -693,7 +694,7 @@ impl Perform for CreateCommentReport { async fn perform( &self, context: &Data, - _websocket_id: Option, + websocket_id: Option, ) -> Result { let data: &CreateCommentReport = &self; let user = get_user_from_jwt(&data.auth, context.pool()).await?; @@ -722,24 +723,28 @@ impl Perform for CreateCommentReport { reason: data.reason.to_owned(), }; - let _report = match blocking(context.pool(), move |conn| { + let report = match blocking(context.pool(), move |conn| { CommentReport::report(conn, &report_form) }).await? { Ok(report) => report, Err(_e) => return Err(APIError::err("couldnt_create_report").into()) }; - // to build on this, the user should get a success response, however - // mods should get a different response with more details let res = CreateCommentReportResponse { success: true }; - // TODO this needs to use a SendModRoomMessage - // context.chat_server().do_send(SendUserRoomMessage { - // op: UserOperation::CreateReport, - // response: res.clone(), - // recipient_id: user.id, - // websocket_id, - // }); + context.chat_server().do_send(SendUserRoomMessage { + op: UserOperation::CreateCommentReport, + response: res.clone(), + recipient_id: user.id, + websocket_id, + }); + + context.chat_server().do_send(SendModRoomMessage { + op: UserOperation::CreateCommentReport, + response: report, + community_id: comment.community_id, + websocket_id, + }); Ok(res) } @@ -752,7 +757,7 @@ impl Perform for ResolveCommentReport { async fn perform( &self, context: &Data, - _websocket_id: Option, + websocket_id: Option, ) -> Result { let data: &ResolveCommentReport = &self; let user = get_user_from_jwt(&data.auth, context.pool()).await?; @@ -784,13 +789,12 @@ impl Perform for ResolveCommentReport { resolved, }; - // TODO this needs to use a SendModRoomMessage - // context.chat_server().do_send(SendUserRoomMessage { - // op: UserOperation::ResolveCommentReport, - // response: res.clone(), - // recipient_id: user.id, - // websocket_id, - // }); + context.chat_server().do_send(SendModRoomMessage { + op: UserOperation::ResolveCommentReport, + response: res.clone(), + community_id: report.community_id, + websocket_id, + }); Ok(res) } diff --git a/lemmy_api/src/community.rs b/lemmy_api/src/community.rs index a9e130b9b..ae19c5f8f 100644 --- a/lemmy_api/src/community.rs +++ b/lemmy_api/src/community.rs @@ -41,6 +41,7 @@ use lemmy_websocket::{ UserOperation, }; use std::str::FromStr; +use lemmy_websocket::messages::JoinModRoom; #[async_trait::async_trait(?Send)] impl Perform for GetCommunity { @@ -883,3 +884,26 @@ impl Perform for CommunityJoin { Ok(CommunityJoinResponse { joined: true }) } } + +// is this the right place for this? +#[async_trait::async_trait(?Send)] +impl Perform for ModJoin { + type Response = ModJoinResponse; + + async fn perform( + &self, + context: &Data, + websocket_id: Option, + ) -> Result { + let data: &ModJoin = &self; + + if let Some(ws_id) = websocket_id { + context.chat_server().do_send(JoinModRoom { + community_id: data.community_id, + id: ws_id, + }); + } + + Ok(ModJoinResponse { joined: true }) + } +} diff --git a/lemmy_api/src/lib.rs b/lemmy_api/src/lib.rs index 38cf80435..96f2b0612 100644 --- a/lemmy_api/src/lib.rs +++ b/lemmy_api/src/lib.rs @@ -195,6 +195,9 @@ pub async fn match_websocket_operation( UserOperation::CommunityJoin => { do_websocket_operation::(context, id, op, data).await } + UserOperation::ModJoin => { + do_websocket_operation::(context, id, op, data).await + } UserOperation::SaveUserSettings => { do_websocket_operation::(context, id, op, data).await } diff --git a/lemmy_api/src/post.rs b/lemmy_api/src/post.rs index 0bf76b4d4..0abb879cf 100644 --- a/lemmy_api/src/post.rs +++ b/lemmy_api/src/post.rs @@ -35,7 +35,13 @@ use lemmy_utils::{ LemmyError, }; use lemmy_websocket::{ - messages::{GetPostUsersOnline, JoinPostRoom, SendPost, SendUserRoomMessage}, + messages::{ + GetPostUsersOnline, + JoinPostRoom, + SendModRoomMessage, + SendPost, + SendUserRoomMessage + }, LemmyContext, UserOperation, }; @@ -752,7 +758,7 @@ impl Perform for CreatePostReport { async fn perform( &self, context: &Data, - _websocket_id: Option, + websocket_id: Option, ) -> Result { let data: &CreatePostReport = &self; let user = get_user_from_jwt(&data.auth, context.pool()).await?; @@ -783,24 +789,28 @@ impl Perform for CreatePostReport { reason: data.reason.to_owned(), }; - let _report = match blocking(context.pool(), move |conn| { + let report = match blocking(context.pool(), move |conn| { PostReport::report(conn, &report_form) }).await? { Ok(report) => report, Err(_e) => return Err(APIError::err("couldnt_create_report").into()) }; - // to build on this, the user should get a success response, however - // mods should get a different response with more details let res = CreatePostReportResponse { success: true }; - // TODO this needs to use a SendModRoomMessage - // context.chat_server().do_send(SendUserRoomMessage { - // op: UserOperation::CreateReport, - // response: res.clone(), - // recipient_id: user.id, - // websocket_id, - // }); + context.chat_server().do_send(SendUserRoomMessage { + op: UserOperation::CreatePostReport, + response: res.clone(), + recipient_id: user.id, + websocket_id, + }); + + context.chat_server().do_send(SendModRoomMessage { + op: UserOperation::CreatePostReport, + response: report, + community_id: post.community_id, + websocket_id, + }); Ok(res) } @@ -813,7 +823,7 @@ impl Perform for ResolvePostReport { async fn perform( &self, context: &Data, - _websocket_id: Option, + websocket_id: Option, ) -> Result { let data: &ResolvePostReport = &self; let user = get_user_from_jwt(&data.auth, context.pool()).await?; @@ -844,13 +854,12 @@ impl Perform for ResolvePostReport { return Err(APIError::err("couldnt_resolve_report").into()) }; - // TODO this needs to use a SendModRoomMessage - // context.chat_server().do_send(SendUserRoomMessage { - // op: UserOperation::ResolvePostReport, - // response: res.clone(), - // recipient_id: user.id, - // websocket_id, - // }); + context.chat_server().do_send(SendModRoomMessage { + op: UserOperation::ResolvePostReport, + response: res.clone(), + community_id: report.community_id, + websocket_id, + }); Ok(res) } diff --git a/lemmy_db/src/comment_report.rs b/lemmy_db/src/comment_report.rs index a2b4e1d30..a5ac701c1 100644 --- a/lemmy_db/src/comment_report.rs +++ b/lemmy_db/src/comment_report.rs @@ -23,7 +23,7 @@ table! { } } -#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] +#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Serialize)] #[belongs_to(Comment)] #[table_name = "comment_report"] pub struct CommentReport { diff --git a/lemmy_structs/src/community.rs b/lemmy_structs/src/community.rs index 6c543eac2..3535c05a9 100644 --- a/lemmy_structs/src/community.rs +++ b/lemmy_structs/src/community.rs @@ -139,3 +139,13 @@ pub struct CommunityJoin { pub struct CommunityJoinResponse { pub joined: bool, } + +#[derive(Deserialize, Debug)] +pub struct ModJoin { + pub community_id: i32, +} + +#[derive(Serialize, Clone)] +pub struct ModJoinResponse { + pub joined: bool, +} diff --git a/lemmy_websocket/src/chat_server.rs b/lemmy_websocket/src/chat_server.rs index 8346a32f6..0a524e3db 100644 --- a/lemmy_websocket/src/chat_server.rs +++ b/lemmy_websocket/src/chat_server.rs @@ -47,6 +47,8 @@ pub struct ChatServer { /// A map from community to set of connectionIDs pub community_rooms: HashMap>, + pub mod_rooms: HashMap>, + /// A map from user id to its connection ID for joined users. Remember a user can have multiple /// sessions (IE clients) pub(super) user_rooms: HashMap>, @@ -90,6 +92,7 @@ impl ChatServer { sessions: HashMap::new(), post_rooms: HashMap::new(), community_rooms: HashMap::new(), + mod_rooms: HashMap::new(), user_rooms: HashMap::new(), rng: rand::thread_rng(), pool, @@ -130,6 +133,29 @@ impl ChatServer { Ok(()) } + pub fn join_mod_room( + &mut self, + community_id: CommunityId, + id: ConnectionId, + ) -> Result<(), LemmyError> { + // remove session from all rooms + for sessions in self.mod_rooms.values_mut() { + sessions.remove(&id); + } + + // If the room doesn't exist yet + if self.mod_rooms.get_mut(&community_id).is_none() { + self.mod_rooms.insert(community_id, HashSet::new()); + } + + self + .mod_rooms + .get_mut(&community_id) + .context(location_info!())? + .insert(id); + Ok(()) + } + pub fn join_post_room(&mut self, post_id: PostId, id: ConnectionId) -> Result<(), LemmyError> { // remove session from all rooms for sessions in self.post_rooms.values_mut() { @@ -227,6 +253,30 @@ impl ChatServer { Ok(()) } + pub fn send_mod_room_message( + &self, + op: &UserOperation, + response: &Response, + community_id: CommunityId, + websocket_id: Option, + ) -> Result<(), LemmyError> + where + Response: Serialize, + { + let res_str = &serialize_websocket_message(op, response)?; + if let Some(sessions) = self.mod_rooms.get(&community_id) { + for id in sessions { + if let Some(my_id) = websocket_id { + if *id == my_id { + continue; + } + } + self.sendit(res_str, *id); + } + } + Ok(()) + } + pub fn send_all_message( &self, op: &UserOperation, diff --git a/lemmy_websocket/src/handlers.rs b/lemmy_websocket/src/handlers.rs index 258098d62..0b5703ab1 100644 --- a/lemmy_websocket/src/handlers.rs +++ b/lemmy_websocket/src/handlers.rs @@ -120,6 +120,19 @@ where } } +impl Handler> for ChatServer + where + Response: Serialize, +{ + type Result = (); + + fn handle(&mut self, msg: SendModRoomMessage, _: &mut Context) { + self + .send_mod_room_message(&msg.op, &msg.response, msg.community_id, msg.websocket_id) + .ok(); + } +} + impl Handler for ChatServer { type Result = (); @@ -154,6 +167,14 @@ impl Handler for ChatServer { } } +impl Handler for ChatServer { + type Result = (); + + fn handle(&mut self, msg: JoinModRoom, _: &mut Context) { + self.join_mod_room(msg.community_id, msg.id).ok(); + } +} + impl Handler for ChatServer { type Result = (); diff --git a/lemmy_websocket/src/lib.rs b/lemmy_websocket/src/lib.rs index 7673510cd..d789efdd1 100644 --- a/lemmy_websocket/src/lib.rs +++ b/lemmy_websocket/src/lib.rs @@ -148,4 +148,5 @@ pub enum UserOperation { SaveSiteConfig, PostJoin, CommunityJoin, + ModJoin, } diff --git a/lemmy_websocket/src/messages.rs b/lemmy_websocket/src/messages.rs index d9f8320a8..c678a96ef 100644 --- a/lemmy_websocket/src/messages.rs +++ b/lemmy_websocket/src/messages.rs @@ -63,6 +63,15 @@ pub struct SendCommunityRoomMessage { pub websocket_id: Option, } +#[derive(Message)] +#[rtype(result = "()")] +pub struct SendModRoomMessage { + pub op: UserOperation, + pub response: Response, + pub community_id: CommunityId, + pub websocket_id: Option, +} + #[derive(Message)] #[rtype(result = "()")] pub struct SendPost { @@ -93,6 +102,13 @@ pub struct JoinCommunityRoom { pub id: ConnectionId, } +#[derive(Message)] +#[rtype(result = "()")] +pub struct JoinModRoom { + pub community_id: CommunityId, + pub id: ConnectionId, +} + #[derive(Message)] #[rtype(result = "()")] pub struct JoinPostRoom { diff --git a/src/routes/api.rs b/src/routes/api.rs index e6d6b31a9..7b95b4ee4 100644 --- a/src/routes/api.rs +++ b/src/routes/api.rs @@ -57,7 +57,8 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { .route("/transfer", web::post().to(route_post::)) .route("/ban_user", web::post().to(route_post::)) .route("/mod", web::post().to(route_post::)) - .route("/join", web::post().to(route_post::)), + .route("/join", web::post().to(route_post::)) + .route("/mod/join", web::post().to(route_post::)), ) // Post .service(