diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 74a3d3037..d535c4678 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -120,6 +120,9 @@ pub async fn match_websocket_operation( UserOperation::CreatePostLike => { do_websocket_operation::(context, id, op, data).await } + UserOperation::MarkPostAsRead => { + do_websocket_operation::(context, id, op, data).await + } UserOperation::SavePost => do_websocket_operation::(context, id, op, data).await, UserOperation::CreatePostReport => { do_websocket_operation::(context, id, op, data).await diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs index c7acb08fb..60a580b84 100644 --- a/crates/api/src/post.rs +++ b/crates/api/src/post.rs @@ -9,6 +9,7 @@ use lemmy_api_common::{ get_local_user_view_from_jwt, is_mod_or_admin, mark_post_as_read, + mark_post_as_unread, post::*, }; use lemmy_apub::{ @@ -118,6 +119,41 @@ impl Perform for CreatePostLike { } } +#[async_trait::async_trait(?Send)] +impl Perform for MarkPostAsRead { + type Response = PostResponse; + + async fn perform( + &self, + context: &Data, + _websocket_id: Option, + ) -> Result { + let data = self; + let local_user_view = + get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; + + let post_id = data.post_id; + let person_id = local_user_view.person.id; + + // Mark the post as read / unread + if data.read { + mark_post_as_read(person_id, post_id, context.pool()).await?; + } else { + mark_post_as_unread(person_id, post_id, context.pool()).await?; + } + + // Fetch it + let post_view = blocking(context.pool(), move |conn| { + PostView::read(conn, post_id, Some(person_id)) + }) + .await??; + + let res = Self::Response { post_view }; + + Ok(res) + } +} + #[async_trait::async_trait(?Send)] impl Perform for LockPost { type Response = PostResponse; diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index bf6246a0d..f5b6ebad2 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -81,7 +81,21 @@ pub async fn mark_post_as_read( PostRead::mark_as_read(conn, &post_read_form) }) .await? - .map_err(|_| ApiError::err_plain("couldnt_mark_post_as_read").into()) + .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into()) +} + +pub async fn mark_post_as_unread( + person_id: PersonId, + post_id: PostId, + pool: &DbPool, +) -> Result { + let post_read_form = PostReadForm { post_id, person_id }; + + blocking(pool, move |conn| { + PostRead::mark_as_unread(conn, &post_read_form) + }) + .await? + .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into()) } pub async fn get_local_user_view_from_jwt( diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index d4a8c3f52..6e2c31797 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -92,6 +92,13 @@ pub struct RemovePost { pub auth: String, } +#[derive(Serialize, Deserialize)] +pub struct MarkPostAsRead { + pub post_id: PostId, + pub read: bool, + pub auth: String, +} + #[derive(Serialize, Deserialize)] pub struct LockPost { pub post_id: PostId, diff --git a/crates/websocket/src/lib.rs b/crates/websocket/src/lib.rs index b7ab5bf28..251c7072a 100644 --- a/crates/websocket/src/lib.rs +++ b/crates/websocket/src/lib.rs @@ -110,6 +110,7 @@ pub enum UserOperation { CreatePostLike, LockPost, StickyPost, + MarkPostAsRead, SavePost, CreatePostReport, ResolvePostReport, diff --git a/src/api_routes.rs b/src/api_routes.rs index 0349f518c..a6a840395 100644 --- a/src/api_routes.rs +++ b/src/api_routes.rs @@ -83,6 +83,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { .route("", web::put().to(route_post_crud::)) .route("/delete", web::post().to(route_post_crud::)) .route("/remove", web::post().to(route_post_crud::)) + .route( + "/mark_as_read", + web::post().to(route_post::), + ) .route("/lock", web::post().to(route_post::)) .route("/sticky", web::post().to(route_post::)) .route("/list", web::get().to(route_get_crud::))