From 86b2901e8cf56dd776b58424d3df1b24d1e680f8 Mon Sep 17 00:00:00 2001
From: Dessalines <dessalines@users.noreply.github.com>
Date: Tue, 23 Nov 2021 09:15:43 -0500
Subject: [PATCH] Adding MarkPostAsRead to API. Fixes #1784 (#1946)

* Adding MarkPostAsRead to API. Fixes #1784

* Adding error
---
 crates/api/src/lib.rs         |  3 +++
 crates/api/src/post.rs        | 36 +++++++++++++++++++++++++++++++++++
 crates/api_common/src/lib.rs  | 16 +++++++++++++++-
 crates/api_common/src/post.rs |  7 +++++++
 crates/websocket/src/lib.rs   |  1 +
 src/api_routes.rs             |  4 ++++
 6 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs
index 74a3d303..d535c467 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::<CreatePostLike>(context, id, op, data).await
     }
+    UserOperation::MarkPostAsRead => {
+      do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
+    }
     UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
     UserOperation::CreatePostReport => {
       do_websocket_operation::<CreatePostReport>(context, id, op, data).await
diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs
index c7acb08f..60a580b8 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<LemmyContext>,
+    _websocket_id: Option<ConnectionId>,
+  ) -> Result<Self::Response, LemmyError> {
+    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 bf6246a0..f5b6ebad 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<usize, LemmyError> {
+  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 d4a8c3f5..6e2c3179 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 b7ab5bf2..251c7072 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 0349f518..a6a84039 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::<EditPost>))
           .route("/delete", web::post().to(route_post_crud::<DeletePost>))
           .route("/remove", web::post().to(route_post_crud::<RemovePost>))
+          .route(
+            "/mark_as_read",
+            web::post().to(route_post::<MarkPostAsRead>),
+          )
           .route("/lock", web::post().to(route_post::<LockPost>))
           .route("/sticky", web::post().to(route_post::<StickyPost>))
           .route("/list", web::get().to(route_get_crud::<GetPosts>))
-- 
2.44.1