]> Untitled Git - lemmy.git/commitdiff
Added comment delete, remove, read.
authorDessalines <tyhou13@gmx.com>
Tue, 21 Jul 2020 01:37:44 +0000 (21:37 -0400)
committerDessalines <tyhou13@gmx.com>
Tue, 21 Jul 2020 01:37:44 +0000 (21:37 -0400)
20 files changed:
docs/src/contributing_websocket_http_api.md
server/lemmy_db/src/comment.rs
server/lemmy_db/src/community.rs
server/lemmy_db/src/private_message.rs
server/src/api/comment.rs
server/src/api/community.rs
server/src/api/user.rs
server/src/apub/shared_inbox.rs
server/src/routes/api.rs
server/src/websocket/mod.rs
server/src/websocket/server.rs
ui/src/api_tests/api.spec.ts
ui/src/components/comment-node.tsx
ui/src/components/community.tsx
ui/src/components/inbox.tsx
ui/src/components/main.tsx
ui/src/components/post.tsx
ui/src/components/user-details.tsx
ui/src/interfaces.ts
ui/src/services/WebSocketService.ts

index 4931ed583d3c281680c35bf87ca6e921df9bd29b..390fa9887d7e66f786d01afc9aa3600605f6b0dd 100644 (file)
@@ -1448,7 +1448,6 @@ Mods and admins can remove and lock a post, creators can delete it.
   data: {
     content: String,
     parent_id: Option<i32>,
-    edit_id: Option<i32>,
     post_id: i32,
     auth: String
   }
@@ -1470,7 +1469,7 @@ Mods and admins can remove and lock a post, creators can delete it.
 
 #### Edit Comment
 
-Mods and admins can remove a comment, creators can delete it.
+Only the creator can edit the comment.
 
 ##### Request
 ```rust
@@ -1478,15 +1477,8 @@ Mods and admins can remove a comment, creators can delete it.
   op: "EditComment",
   data: {
     content: String,
-    parent_id: Option<i32>,
     edit_id: i32,
-    creator_id: i32,
-    post_id: i32,
-    removed: Option<bool>,
-    deleted: Option<bool>,
-    reason: Option<String>,
-    read: Option<bool>,
-    auth: String
+    auth: String,
   }
 }
 ```
@@ -1503,6 +1495,89 @@ Mods and admins can remove a comment, creators can delete it.
 
 `PUT /comment`
 
+#### Delete Comment
+
+Only the creator can delete the comment.
+
+##### Request
+```rust
+{
+  op: "DeleteComment",
+  data: {
+    edit_id: i32,
+    deleted: bool,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "DeleteComment",
+  data: {
+    comment: CommentView
+  }
+}
+```
+##### HTTP
+
+`POST /comment/delete`
+
+
+#### Remove Comment
+
+Only a mod or admin can remove the comment.
+
+##### Request
+```rust
+{
+  op: "RemoveComment",
+  data: {
+    edit_id: i32,
+    removed: bool,
+    reason: Option<String>,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "RemoveComment",
+  data: {
+    comment: CommentView
+  }
+}
+```
+##### HTTP
+
+`POST /comment/remove`
+
+#### Mark Comment as Read
+##### Request
+```rust
+{
+  op: "MarkCommentAsRead",
+  data: {
+    edit_id: i32,
+    read: bool,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "MarkCommentAsRead",
+  data: {
+    comment: CommentView
+  }
+}
+```
+##### HTTP
+
+`POST /comment/mark_as_read`
+
 #### Save Comment
 ##### Request
 ```rust
@@ -1538,7 +1613,6 @@ Mods and admins can remove a comment, creators can delete it.
   op: "CreateCommentLike",
   data: {
     comment_id: i32,
-    post_id: i32,
     score: i16,
     auth: String
   }
index dc369c8bc7d939884a229f48142a62ad6ddd0dc3..de6904133a7a597d893760818dcefb096b2e9793 100644 (file)
@@ -97,14 +97,6 @@ impl Comment {
     comment.filter(ap_id.eq(object_id)).first::<Self>(conn)
   }
 
-  pub fn mark_as_read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
-    use crate::schema::comment::dsl::*;
-
-    diesel::update(comment.find(comment_id))
-      .set(read.eq(true))
-      .get_result::<Self>(conn)
-  }
-
   pub fn permadelete(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
     use crate::schema::comment::dsl::*;
 
@@ -116,6 +108,46 @@ impl Comment {
       ))
       .get_result::<Self>(conn)
   }
+
+  pub fn update_deleted(
+    conn: &PgConnection,
+    comment_id: i32,
+    new_deleted: bool,
+  ) -> Result<Self, Error> {
+    use crate::schema::comment::dsl::*;
+    diesel::update(comment.find(comment_id))
+      .set(deleted.eq(new_deleted))
+      .get_result::<Self>(conn)
+  }
+
+  pub fn update_removed(
+    conn: &PgConnection,
+    comment_id: i32,
+    new_removed: bool,
+  ) -> Result<Self, Error> {
+    use crate::schema::comment::dsl::*;
+    diesel::update(comment.find(comment_id))
+      .set(removed.eq(new_removed))
+      .get_result::<Self>(conn)
+  }
+
+  pub fn update_read(conn: &PgConnection, comment_id: i32, new_read: bool) -> Result<Self, Error> {
+    use crate::schema::comment::dsl::*;
+    diesel::update(comment.find(comment_id))
+      .set(read.eq(new_read))
+      .get_result::<Self>(conn)
+  }
+
+  pub fn update_content(
+    conn: &PgConnection,
+    comment_id: i32,
+    new_content: &str,
+  ) -> Result<Self, Error> {
+    use crate::schema::comment::dsl::*;
+    diesel::update(comment.find(comment_id))
+      .set((content.eq(new_content), updated.eq(naive_now())))
+      .get_result::<Self>(conn)
+  }
 }
 
 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
index 4fe507f72cc5c92bb19776d608b4a9ec04c99da0..03c47e463513b4eadc41a380d6e7872f66780033 100644 (file)
@@ -1,4 +1,5 @@
 use crate::{
+  naive_now,
   schema::{community, community_follower, community_moderator, community_user_ban},
   Bannable,
   Crud,
@@ -29,7 +30,6 @@ pub struct Community {
   pub last_refreshed_at: chrono::NaiveDateTime,
 }
 
-// TODO add better delete, remove, lock actions here.
 #[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize, Debug)]
 #[table_name = "community"]
 pub struct CommunityForm {
@@ -129,9 +129,24 @@ impl Community {
   ) -> Result<Self, Error> {
     use crate::schema::community::dsl::*;
     diesel::update(community.find(community_id))
-      .set(creator_id.eq(new_creator_id))
+      .set((creator_id.eq(new_creator_id), updated.eq(naive_now())))
       .get_result::<Self>(conn)
   }
+
+  pub fn community_mods_and_admins(
+    conn: &PgConnection,
+    community_id: i32,
+  ) -> Result<Vec<i32>, Error> {
+    use crate::{community_view::CommunityModeratorView, user_view::UserView};
+    let mut mods_and_admins: Vec<i32> = Vec::new();
+    mods_and_admins.append(
+      &mut CommunityModeratorView::for_community(conn, community_id)
+        .map(|v| v.into_iter().map(|m| m.user_id).collect())?,
+    );
+    mods_and_admins
+      .append(&mut UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())?);
+    Ok(mods_and_admins)
+  }
 }
 
 #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
index 30f40e6b8e48fc8cacc5d234894857406c4a8298..3486cf545e4d327b406735f8df3cfd91153eedf5 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{schema::private_message, Crud};
+use crate::{naive_now, schema::private_message, Crud};
 use diesel::{dsl::*, result::Error, *};
 use serde::{Deserialize, Serialize};
 
@@ -88,7 +88,7 @@ impl PrivateMessage {
   ) -> Result<Self, Error> {
     use crate::schema::private_message::dsl::*;
     diesel::update(private_message.find(private_message_id))
-      .set(content.eq(new_content))
+      .set((content.eq(new_content), updated.eq(naive_now())))
       .get_result::<Self>(conn)
   }
 
index f8bdf5d5b17f3f708de2b72a05373ea5cdf8036b..1a06032b27352b3a97b10f776b143fdb2c868632 100644 (file)
@@ -13,14 +13,13 @@ use crate::{
 use lemmy_db::{
   comment::*,
   comment_view::*,
+  community::Community,
   community_view::*,
   moderator::*,
-  naive_now,
   post::*,
   site_view::*,
   user::*,
   user_mention::*,
-  user_view::*,
   Crud,
   Likeable,
   ListingType,
@@ -44,7 +43,6 @@ use std::str::FromStr;
 pub struct CreateComment {
   content: String,
   parent_id: Option<i32>,
-  edit_id: Option<i32>, // TODO this isn't used
   pub post_id: i32,
   auth: String,
 }
@@ -52,14 +50,29 @@ pub struct CreateComment {
 #[derive(Serialize, Deserialize)]
 pub struct EditComment {
   content: String,
-  parent_id: Option<i32>, // TODO why are the parent_id, creator_id, post_id, etc fields required? They aren't going to change
   edit_id: i32,
-  creator_id: i32,
-  pub post_id: i32,
-  removed: Option<bool>,
-  deleted: Option<bool>,
+  auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct DeleteComment {
+  edit_id: i32,
+  deleted: bool,
+  auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct RemoveComment {
+  edit_id: i32,
+  removed: bool,
   reason: Option<String>,
-  read: Option<bool>,
+  auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct MarkCommentAsRead {
+  edit_id: i32,
+  read: bool,
   auth: String,
 }
 
@@ -79,7 +92,6 @@ pub struct CommentResponse {
 #[derive(Serialize, Deserialize)]
 pub struct CreateCommentLike {
   comment_id: i32,
-  pub post_id: i32,
   score: i16,
   auth: String,
 }
@@ -150,6 +162,7 @@ impl Perform for Oper<CreateComment> {
       return Err(APIError::err("site_ban").into());
     }
 
+    // Create the comment
     let comment_form2 = comment_form.clone();
     let inserted_comment =
       match blocking(pool, move |conn| Comment::create(&conn, &comment_form2)).await? {
@@ -157,6 +170,7 @@ impl Perform for Oper<CreateComment> {
         Err(_e) => return Err(APIError::err("couldnt_create_comment").into()),
       };
 
+    // Necessary to update the ap_id
     let inserted_comment_id = inserted_comment.id;
     let updated_comment: Comment = match blocking(pool, move |conn| {
       let apub_id =
@@ -175,8 +189,15 @@ impl Perform for Oper<CreateComment> {
 
     // Scan the comment for user mentions, add those rows
     let mentions = scrape_text_for_mentions(&comment_form.content);
-    let recipient_ids =
-      send_local_notifs(mentions, updated_comment.clone(), user.clone(), post, pool).await?;
+    let recipient_ids = send_local_notifs(
+      mentions,
+      updated_comment.clone(),
+      user.clone(),
+      post,
+      pool,
+      true,
+    )
+    .await?;
 
     // You like your own comment by default
     let like_form = CommentLikeForm {
@@ -237,122 +258,127 @@ impl Perform for Oper<EditComment> {
 
     let user_id = claims.id;
 
-    let user = blocking(pool, move |conn| User_::read(&conn, user_id)).await??;
-
     let edit_id = data.edit_id;
     let orig_comment =
       blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
 
-    let mut editors: Vec<i32> = vec![orig_comment.creator_id];
-    let mut moderators: Vec<i32> = vec![];
+    // Check for a site ban
+    let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
+    if user.banned {
+      return Err(APIError::err("site_ban").into());
+    }
 
+    // Check for a community ban
     let community_id = orig_comment.community_id;
-    moderators.append(
-      &mut blocking(pool, move |conn| {
-        CommunityModeratorView::for_community(&conn, community_id)
-          .map(|v| v.into_iter().map(|m| m.user_id).collect())
-      })
-      .await??,
-    );
-    moderators.append(
-      &mut blocking(pool, move |conn| {
-        UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())
-      })
-      .await??,
-    );
-
-    editors.extend(&moderators);
-    // You are allowed to mark the comment as read even if you're banned.
-    if data.read.is_none() {
-      // Verify its the creator or a mod, or an admin
-
-      if !editors.contains(&user_id) {
-        return Err(APIError::err("no_comment_edit_allowed").into());
-      }
-
-      // Check for a community ban
-      let community_id = orig_comment.community_id;
-      let is_banned =
-        move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
-      if blocking(pool, is_banned).await? {
-        return Err(APIError::err("community_ban").into());
-      }
+    let is_banned =
+      move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
+    if blocking(pool, is_banned).await? {
+      return Err(APIError::err("community_ban").into());
+    }
 
-      // Check for a site ban
-      if user.banned {
-        return Err(APIError::err("site_ban").into());
-      }
-    } else {
-      // check that user can mark as read
-      let parent_id = orig_comment.parent_id;
-      match parent_id {
-        Some(pid) => {
-          let parent_comment =
-            blocking(pool, move |conn| CommentView::read(&conn, pid, None)).await??;
-          if user_id != parent_comment.creator_id {
-            return Err(APIError::err("no_comment_edit_allowed").into());
-          }
-        }
-        None => {
-          let parent_post_id = orig_comment.post_id;
-          let parent_post = blocking(pool, move |conn| Post::read(conn, parent_post_id)).await??;
-          if user_id != parent_post.creator_id {
-            return Err(APIError::err("no_comment_edit_allowed").into());
-          }
-        }
-      }
+    // Verify that only the creator can edit
+    if user_id != orig_comment.creator_id {
+      return Err(APIError::err("no_comment_edit_allowed").into());
     }
 
+    // Do the update
     let content_slurs_removed = remove_slurs(&data.content.to_owned());
+    let edit_id = data.edit_id;
+    let updated_comment = match blocking(pool, move |conn| {
+      Comment::update_content(conn, edit_id, &content_slurs_removed)
+    })
+    .await?
+    {
+      Ok(comment) => comment,
+      Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
+    };
+
+    // Send the apub update
+    updated_comment
+      .send_update(&user, &self.client, pool)
+      .await?;
+
+    // Do the mentions / recipients
+    let post_id = orig_comment.post_id;
+    let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
+
+    let updated_comment_content = updated_comment.content.to_owned();
+    let mentions = scrape_text_for_mentions(&updated_comment_content);
+    let recipient_ids =
+      send_local_notifs(mentions, updated_comment, user, post, pool, false).await?;
 
     let edit_id = data.edit_id;
-    let read_comment = blocking(pool, move |conn| Comment::read(conn, edit_id)).await??;
-
-    let comment_form = {
-      if data.read.is_none() {
-        // the ban etc checks should been made and have passed
-        // the comment can be properly edited
-        let post_removed = if moderators.contains(&user_id) {
-          data.removed
-        } else {
-          Some(read_comment.removed)
-        };
-
-        CommentForm {
-          content: content_slurs_removed,
-          parent_id: read_comment.parent_id,
-          post_id: read_comment.post_id,
-          creator_id: read_comment.creator_id,
-          removed: post_removed.to_owned(),
-          deleted: data.deleted.to_owned(),
-          read: Some(read_comment.read),
-          published: None,
-          updated: Some(naive_now()),
-          ap_id: read_comment.ap_id,
-          local: read_comment.local,
-        }
-      } else {
-        // the only field that can be updated it the read field
-        CommentForm {
-          content: read_comment.content,
-          parent_id: read_comment.parent_id,
-          post_id: read_comment.post_id,
-          creator_id: read_comment.creator_id,
-          removed: Some(read_comment.removed).to_owned(),
-          deleted: Some(read_comment.deleted).to_owned(),
-          read: data.read.to_owned(),
-          published: None,
-          updated: orig_comment.updated,
-          ap_id: read_comment.ap_id,
-          local: read_comment.local,
-        }
-      }
+    let comment_view = blocking(pool, move |conn| {
+      CommentView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
+
+    let mut res = CommentResponse {
+      comment: comment_view,
+      recipient_ids,
+    };
+
+    if let Some(ws) = websocket_info {
+      ws.chatserver.do_send(SendComment {
+        op: UserOperation::EditComment,
+        comment: res.clone(),
+        my_id: ws.id,
+      });
+
+      // strip out the recipient_ids, so that
+      // users don't get double notifs
+      res.recipient_ids = Vec::new();
+    }
+
+    Ok(res)
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<DeleteComment> {
+  type Response = CommentResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    websocket_info: Option<WebsocketInfo>,
+  ) -> Result<CommentResponse, LemmyError> {
+    let data: &DeleteComment = &self.data;
+
+    let claims = match Claims::decode(&data.auth) {
+      Ok(claims) => claims.claims,
+      Err(_e) => return Err(APIError::err("not_logged_in").into()),
     };
 
+    let user_id = claims.id;
+
     let edit_id = data.edit_id;
-    let comment_form2 = comment_form.clone();
+    let orig_comment =
+      blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
+
+    // Check for a site ban
+    let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
+    if user.banned {
+      return Err(APIError::err("site_ban").into());
+    }
+
+    // Check for a community ban
+    let community_id = orig_comment.community_id;
+    let is_banned =
+      move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
+    if blocking(pool, is_banned).await? {
+      return Err(APIError::err("community_ban").into());
+    }
+
+    // Verify that only the creator can delete
+    if user_id != orig_comment.creator_id {
+      return Err(APIError::err("no_comment_edit_allowed").into());
+    }
+
+    // Do the delete
+    let deleted = data.deleted;
     let updated_comment = match blocking(pool, move |conn| {
-      Comment::update(conn, edit_id, &comment_form2)
+      Comment::update_deleted(conn, edit_id, deleted)
     })
     .await?
     {
@@ -360,61 +386,142 @@ impl Perform for Oper<EditComment> {
       Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
     };
 
-    if data.read.is_none() {
-      if let Some(deleted) = data.deleted.to_owned() {
-        if deleted {
-          updated_comment
-            .send_delete(&user, &self.client, pool)
-            .await?;
-        } else {
-          updated_comment
-            .send_undo_delete(&user, &self.client, pool)
-            .await?;
-        }
-      } else if let Some(removed) = data.removed.to_owned() {
-        if moderators.contains(&user_id) {
-          if removed {
-            updated_comment
-              .send_remove(&user, &self.client, pool)
-              .await?;
-          } else {
-            updated_comment
-              .send_undo_remove(&user, &self.client, pool)
-              .await?;
-          }
-        }
-      } else {
-        updated_comment
-          .send_update(&user, &self.client, pool)
-          .await?;
-      }
-
-      // Mod tables
-      if moderators.contains(&user_id) {
-        if let Some(removed) = data.removed.to_owned() {
-          let form = ModRemoveCommentForm {
-            mod_user_id: user_id,
-            comment_id: data.edit_id,
-            removed: Some(removed),
-            reason: data.reason.to_owned(),
-          };
-          blocking(pool, move |conn| ModRemoveComment::create(conn, &form)).await??;
-        }
-      }
+    // Send the apub message
+    if deleted {
+      updated_comment
+        .send_delete(&user, &self.client, pool)
+        .await?;
+    } else {
+      updated_comment
+        .send_undo_delete(&user, &self.client, pool)
+        .await?;
     }
 
-    let post_id = data.post_id;
+    // Refetch it
+    let edit_id = data.edit_id;
+    let comment_view = blocking(pool, move |conn| {
+      CommentView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
+
+    // Build the recipients
+    let post_id = comment_view.post_id;
     let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
+    let mentions = vec![];
+    let recipient_ids =
+      send_local_notifs(mentions, updated_comment, user, post, pool, false).await?;
 
-    let mentions = scrape_text_for_mentions(&comment_form.content);
-    let recipient_ids = send_local_notifs(mentions, updated_comment, user, post, pool).await?;
+    let mut res = CommentResponse {
+      comment: comment_view,
+      recipient_ids,
+    };
+
+    if let Some(ws) = websocket_info {
+      ws.chatserver.do_send(SendComment {
+        op: UserOperation::DeleteComment,
+        comment: res.clone(),
+        my_id: ws.id,
+      });
+
+      // strip out the recipient_ids, so that
+      // users don't get double notifs
+      res.recipient_ids = Vec::new();
+    }
+
+    Ok(res)
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<RemoveComment> {
+  type Response = CommentResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    websocket_info: Option<WebsocketInfo>,
+  ) -> Result<CommentResponse, LemmyError> {
+    let data: &RemoveComment = &self.data;
+
+    let claims = match Claims::decode(&data.auth) {
+      Ok(claims) => claims.claims,
+      Err(_e) => return Err(APIError::err("not_logged_in").into()),
+    };
+
+    let user_id = claims.id;
+
+    let edit_id = data.edit_id;
+    let orig_comment =
+      blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
+
+    // Check for a site ban
+    let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
+    if user.banned {
+      return Err(APIError::err("site_ban").into());
+    }
+
+    // Check for a community ban
+    let community_id = orig_comment.community_id;
+    let is_banned =
+      move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
+    if blocking(pool, is_banned).await? {
+      return Err(APIError::err("community_ban").into());
+    }
+
+    // Verify that only a mod or admin can remove
+    let mods_and_admins = blocking(pool, move |conn| {
+      Community::community_mods_and_admins(conn, community_id)
+    })
+    .await??;
+    if !mods_and_admins.contains(&user_id) {
+      return Err(APIError::err("not_an_admin").into());
+    }
+
+    // Do the remove
+    let removed = data.removed;
+    let updated_comment = match blocking(pool, move |conn| {
+      Comment::update_removed(conn, edit_id, removed)
+    })
+    .await?
+    {
+      Ok(comment) => comment,
+      Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
+    };
+
+    // Mod tables
+    let form = ModRemoveCommentForm {
+      mod_user_id: user_id,
+      comment_id: data.edit_id,
+      removed: Some(removed),
+      reason: data.reason.to_owned(),
+    };
+    blocking(pool, move |conn| ModRemoveComment::create(conn, &form)).await??;
+
+    // Send the apub message
+    if removed {
+      updated_comment
+        .send_remove(&user, &self.client, pool)
+        .await?;
+    } else {
+      updated_comment
+        .send_undo_remove(&user, &self.client, pool)
+        .await?;
+    }
 
+    // Refetch it
     let edit_id = data.edit_id;
     let comment_view = blocking(pool, move |conn| {
       CommentView::read(conn, edit_id, Some(user_id))
     })
     .await??;
 
+    // Build the recipients
+    let post_id = comment_view.post_id;
+    let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
+    let mentions = vec![];
+    let recipient_ids =
+      send_local_notifs(mentions, updated_comment, user, post, pool, false).await?;
+
     let mut res = CommentResponse {
       comment: comment_view,
       recipient_ids,
@@ -422,7 +529,7 @@ impl Perform for Oper<EditComment> {
 
     if let Some(ws) = websocket_info {
       ws.chatserver.do_send(SendComment {
-        op: UserOperation::EditComment,
+        op: UserOperation::RemoveComment,
         comment: res.clone(),
         my_id: ws.id,
       });
@@ -436,6 +543,85 @@ impl Perform for Oper<EditComment> {
   }
 }
 
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<MarkCommentAsRead> {
+  type Response = CommentResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    _websocket_info: Option<WebsocketInfo>,
+  ) -> Result<CommentResponse, LemmyError> {
+    let data: &MarkCommentAsRead = &self.data;
+
+    let claims = match Claims::decode(&data.auth) {
+      Ok(claims) => claims.claims,
+      Err(_e) => return Err(APIError::err("not_logged_in").into()),
+    };
+
+    let user_id = claims.id;
+
+    let edit_id = data.edit_id;
+    let orig_comment =
+      blocking(pool, move |conn| CommentView::read(&conn, edit_id, None)).await??;
+
+    // Check for a site ban
+    let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??;
+    if user.banned {
+      return Err(APIError::err("site_ban").into());
+    }
+
+    // Check for a community ban
+    let community_id = orig_comment.community_id;
+    let is_banned =
+      move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
+    if blocking(pool, is_banned).await? {
+      return Err(APIError::err("community_ban").into());
+    }
+
+    // Verify that only the recipient can mark as read
+    // Needs to fetch the parent comment / post to get the recipient
+    let parent_id = orig_comment.parent_id;
+    match parent_id {
+      Some(pid) => {
+        let parent_comment =
+          blocking(pool, move |conn| CommentView::read(&conn, pid, None)).await??;
+        if user_id != parent_comment.creator_id {
+          return Err(APIError::err("no_comment_edit_allowed").into());
+        }
+      }
+      None => {
+        let parent_post_id = orig_comment.post_id;
+        let parent_post = blocking(pool, move |conn| Post::read(conn, parent_post_id)).await??;
+        if user_id != parent_post.creator_id {
+          return Err(APIError::err("no_comment_edit_allowed").into());
+        }
+      }
+    }
+
+    // Do the mark as read
+    let read = data.read;
+    match blocking(pool, move |conn| Comment::update_read(conn, edit_id, read)).await? {
+      Ok(comment) => comment,
+      Err(_e) => return Err(APIError::err("couldnt_update_comment").into()),
+    };
+
+    // Refetch it
+    let edit_id = data.edit_id;
+    let comment_view = blocking(pool, move |conn| {
+      CommentView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
+
+    let res = CommentResponse {
+      comment: comment_view,
+      recipient_ids: Vec::new(),
+    };
+
+    Ok(res)
+  }
+}
+
 #[async_trait::async_trait(?Send)]
 impl Perform for Oper<SaveComment> {
   type Response = CommentResponse;
@@ -512,8 +698,12 @@ impl Perform for Oper<CreateCommentLike> {
       }
     }
 
+    let comment_id = data.comment_id;
+    let orig_comment =
+      blocking(pool, move |conn| CommentView::read(&conn, comment_id, None)).await??;
+
     // Check for a community ban
-    let post_id = data.post_id;
+    let post_id = orig_comment.post_id;
     let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
     let community_id = post.community_id;
     let is_banned =
@@ -550,7 +740,7 @@ impl Perform for Oper<CreateCommentLike> {
 
     let like_form = CommentLikeForm {
       comment_id: data.comment_id,
-      post_id: data.post_id,
+      post_id,
       user_id,
       score: data.score,
     };
@@ -675,9 +865,10 @@ pub async fn send_local_notifs(
   user: User_,
   post: Post,
   pool: &DbPool,
+  do_send_email: bool,
 ) -> Result<Vec<i32>, LemmyError> {
   let ids = blocking(pool, move |conn| {
-    do_send_local_notifs(conn, &mentions, &comment, &user, &post)
+    do_send_local_notifs(conn, &mentions, &comment, &user, &post, do_send_email)
   })
   .await?;
 
@@ -690,6 +881,7 @@ fn do_send_local_notifs(
   comment: &Comment,
   user: &User_,
   post: &Post,
+  do_send_email: bool,
 ) -> Vec<i32> {
   let mut recipient_ids = Vec::new();
   let hostname = &format!("https://{}", Settings::get().hostname);
@@ -720,7 +912,7 @@ fn do_send_local_notifs(
       };
 
       // Send an email to those users that have notifications on
-      if mention_user.send_notifications_to_email {
+      if do_send_email && mention_user.send_notifications_to_email {
         if let Some(mention_email) = mention_user.email {
           let subject = &format!("{} - Mentioned by {}", Settings::get().hostname, user.name,);
           let html = &format!(
@@ -744,7 +936,7 @@ fn do_send_local_notifs(
           if let Ok(parent_user) = User_::read(&conn, parent_comment.creator_id) {
             recipient_ids.push(parent_user.id);
 
-            if parent_user.send_notifications_to_email {
+            if do_send_email && parent_user.send_notifications_to_email {
               if let Some(comment_reply_email) = parent_user.email {
                 let subject = &format!("{} - Reply from {}", Settings::get().hostname, user.name,);
                 let html = &format!(
@@ -767,7 +959,7 @@ fn do_send_local_notifs(
         if let Ok(parent_user) = User_::read(&conn, post.creator_id) {
           recipient_ids.push(parent_user.id);
 
-          if parent_user.send_notifications_to_email {
+          if do_send_email && parent_user.send_notifications_to_email {
             if let Some(post_reply_email) = parent_user.email {
               let subject = &format!("{} - Reply from {}", Settings::get().hostname, user.name,);
               let html = &format!(
index 1f46c596e211e543c1fff7a40eb92b61015e8154..5e84bc6c61d7100f3237c21f65bed633add2d684 100644 (file)
@@ -10,7 +10,6 @@ use crate::{
   },
   DbPool,
 };
-use diesel::PgConnection;
 use lemmy_db::{naive_now, Bannable, Crud, Followable, Joinable, SortType};
 use lemmy_utils::{
   generate_actor_keypair,
@@ -1078,16 +1077,3 @@ impl Perform for Oper<TransferCommunity> {
     })
   }
 }
-
-pub fn community_mods_and_admins(
-  conn: &PgConnection,
-  community_id: i32,
-) -> Result<Vec<i32>, LemmyError> {
-  let mut editors: Vec<i32> = Vec::new();
-  editors.append(
-    &mut CommunityModeratorView::for_community(conn, community_id)
-      .map(|v| v.into_iter().map(|m| m.user_id).collect())?,
-  );
-  editors.append(&mut UserView::admins(conn).map(|v| v.into_iter().map(|a| a.id).collect())?);
-  Ok(editors)
-}
index 71fecea78a5bd9ce96c90e6219cf9becd38ee8c5..ec61c658eb86b840b6ed1c798c7ae88c39971c81 100644 (file)
@@ -936,9 +936,11 @@ impl Perform for Oper<MarkAllAsRead> {
     .await??;
 
     // TODO: this should probably be a bulk operation
+    // Not easy to do as a bulk operation,
+    // because recipient_id isn't in the comment table
     for reply in &replies {
       let reply_id = reply.id;
-      let mark_as_read = move |conn: &'_ _| Comment::mark_as_read(conn, reply_id);
+      let mark_as_read = move |conn: &'_ _| Comment::update_read(conn, reply_id, true);
       if blocking(pool, mark_as_read).await?.is_err() {
         return Err(APIError::err("couldnt_update_comment").into());
       }
index 8d6b255d30f627de208847bfe4fec6cdad957677..41d1a80e88164c31558ee69476c60b847eefb390 100644 (file)
@@ -393,7 +393,7 @@ async fn receive_create_comment(
   // anyway.
   let mentions = scrape_text_for_mentions(&inserted_comment.content);
   let recipient_ids =
-    send_local_notifs(mentions, inserted_comment.clone(), user, post, pool).await?;
+    send_local_notifs(mentions, inserted_comment.clone(), user, post, pool, true).await?;
 
   // Refetch the view
   let comment_view = blocking(pool, move |conn| {
@@ -558,7 +558,7 @@ async fn receive_update_comment(
   let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??;
 
   let mentions = scrape_text_for_mentions(&updated_comment.content);
-  let recipient_ids = send_local_notifs(mentions, updated_comment, user, post, pool).await?;
+  let recipient_ids = send_local_notifs(mentions, updated_comment, user, post, pool, false).await?;
 
   // Refetch the view
   let comment_view =
index 4722fb81f1ee149788713d7726fdffd6eef7e463..9fc84f4c349770ee23a6e1da653a27c70a39b4a2 100644 (file)
@@ -83,6 +83,12 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
           .wrap(rate_limit.message())
           .route("", web::post().to(route_post::<CreateComment>))
           .route("", web::put().to(route_post::<EditComment>))
+          .route("/delete", web::post().to(route_post::<DeleteComment>))
+          .route("/remove", web::post().to(route_post::<RemoveComment>))
+          .route(
+            "/mark_as_read",
+            web::post().to(route_post::<MarkCommentAsRead>),
+          )
           .route("/like", web::post().to(route_post::<CreateCommentLike>))
           .route("/save", web::put().to(route_post::<SaveComment>)),
       )
index c4c0214632267fca3cfa6e867510d6cc6973f5b5..ed8ee272a5acc43fb95504979ea3f2091604e984 100644 (file)
@@ -28,6 +28,9 @@ pub enum UserOperation {
   GetCommunity,
   CreateComment,
   EditComment,
+  DeleteComment,
+  RemoveComment,
+  MarkCommentAsRead,
   SaveComment,
   CreateCommentLike,
   GetPosts,
index 0344e1b99315fe0eb08a53b39dd63fe9043a1453..6f0516ffd50a30dcc15aea7f2c86ed42c92a69ea 100644 (file)
@@ -506,6 +506,9 @@ impl ChatServer {
         // Comment ops
         UserOperation::CreateComment => do_user_operation::<CreateComment>(args).await,
         UserOperation::EditComment => do_user_operation::<EditComment>(args).await,
+        UserOperation::DeleteComment => do_user_operation::<DeleteComment>(args).await,
+        UserOperation::RemoveComment => do_user_operation::<RemoveComment>(args).await,
+        UserOperation::MarkCommentAsRead => do_user_operation::<MarkCommentAsRead>(args).await,
         UserOperation::SaveComment => do_user_operation::<SaveComment>(args).await,
         UserOperation::GetComments => do_user_operation::<GetComments>(args).await,
         UserOperation::CreateCommentLike => do_user_operation::<CreateCommentLike>(args).await,
index 891654b28a0cd86bb0cae945b3eb6e1255c9be30..f3cc867364891acee89bdb4cac16ffeb47ea8188 100644 (file)
@@ -11,6 +11,8 @@ import {
   GetFollowedCommunitiesResponse,
   GetPostResponse,
   CommentForm,
+  DeleteCommentForm,
+  RemoveCommentForm,
   CommentResponse,
   CommunityForm,
   DeleteCommunityForm,
@@ -383,7 +385,6 @@ describe('main', () => {
       let unlikeCommentForm: CommentLikeForm = {
         comment_id: createResponse.comment.id,
         score: 0,
-        post_id: 2,
         auth: lemmyAlphaAuth,
       };
 
@@ -621,19 +622,16 @@ describe('main', () => {
       expect(createCommentRes.comment.content).toBe(commentContent);
 
       // lemmy_beta deletes the comment
-      let deleteCommentForm: CommentForm = {
-        content: commentContent,
+      let deleteCommentForm: DeleteCommentForm = {
         edit_id: createCommentRes.comment.id,
-        post_id: createPostRes.post.id,
         deleted: true,
         auth: lemmyBetaAuth,
-        creator_id: createCommentRes.comment.creator_id,
       };
 
       let deleteCommentRes: CommentResponse = await fetch(
-        `${lemmyBetaApiUrl}/comment`,
+        `${lemmyBetaApiUrl}/comment/delete`,
         {
-          method: 'PUT',
+          method: 'POST',
           headers: {
             'Content-Type': 'application/json',
           },
@@ -650,19 +648,16 @@ describe('main', () => {
       expect(getPostRes.comments[0].deleted).toBe(true);
 
       // lemmy_beta undeletes the comment
-      let undeleteCommentForm: CommentForm = {
-        content: commentContent,
+      let undeleteCommentForm: DeleteCommentForm = {
         edit_id: createCommentRes.comment.id,
-        post_id: createPostRes.post.id,
         deleted: false,
         auth: lemmyBetaAuth,
-        creator_id: createCommentRes.comment.creator_id,
       };
 
       let undeleteCommentRes: CommentResponse = await fetch(
-        `${lemmyBetaApiUrl}/comment`,
+        `${lemmyBetaApiUrl}/comment/delete`,
         {
-          method: 'PUT',
+          method: 'POST',
           headers: {
             'Content-Type': 'application/json',
           },
@@ -889,19 +884,16 @@ describe('main', () => {
       expect(createCommentRes.comment.content).toBe(commentContent);
 
       // lemmy_beta removes the comment
-      let removeCommentForm: CommentForm = {
-        content: commentContent,
+      let removeCommentForm: RemoveCommentForm = {
         edit_id: createCommentRes.comment.id,
-        post_id: createPostRes.post.id,
         removed: true,
         auth: lemmyBetaAuth,
-        creator_id: createCommentRes.comment.creator_id,
       };
 
       let removeCommentRes: CommentResponse = await fetch(
-        `${lemmyBetaApiUrl}/comment`,
+        `${lemmyBetaApiUrl}/comment/remove`,
         {
-          method: 'PUT',
+          method: 'POST',
           headers: {
             'Content-Type': 'application/json',
           },
@@ -918,19 +910,16 @@ describe('main', () => {
       expect(getPostRes.comments[0].removed).toBe(true);
 
       // lemmy_beta undeletes the comment
-      let unremoveCommentForm: CommentForm = {
-        content: commentContent,
+      let unremoveCommentForm: RemoveCommentForm = {
         edit_id: createCommentRes.comment.id,
-        post_id: createPostRes.post.id,
         removed: false,
         auth: lemmyBetaAuth,
-        creator_id: createCommentRes.comment.creator_id,
       };
 
       let unremoveCommentRes: CommentResponse = await fetch(
-        `${lemmyBetaApiUrl}/comment`,
+        `${lemmyBetaApiUrl}/comment/remove`,
         {
-          method: 'PUT',
+          method: 'POST',
           headers: {
             'Content-Type': 'application/json',
           },
index dfe52ec1cc64cc8298c47a6029335c4eb6c92385..527cad895d33ed2109d18b249fc2e60d5d55c538 100644 (file)
@@ -3,7 +3,9 @@ import { Link } from 'inferno-router';
 import {
   CommentNode as CommentNodeI,
   CommentLikeForm,
-  CommentForm as CommentFormI,
+  DeleteCommentForm,
+  RemoveCommentForm,
+  MarkCommentAsReadForm,
   MarkUserMentionAsReadForm,
   SaveCommentForm,
   BanFromCommunityForm,
@@ -848,16 +850,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   }
 
   handleDeleteClick(i: CommentNode) {
-    let deleteForm: CommentFormI = {
-      content: i.props.node.comment.content,
+    let deleteForm: DeleteCommentForm = {
       edit_id: i.props.node.comment.id,
-      creator_id: i.props.node.comment.creator_id,
-      post_id: i.props.node.comment.post_id,
-      parent_id: i.props.node.comment.parent_id,
       deleted: !i.props.node.comment.deleted,
       auth: null,
     };
-    WebSocketService.Instance.editComment(deleteForm);
+    WebSocketService.Instance.deleteComment(deleteForm);
   }
 
   handleSaveCommentClick(i: CommentNode) {
@@ -901,7 +899,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
     let form: CommentLikeForm = {
       comment_id: i.comment.id,
-      post_id: i.comment.post_id,
       score: this.state.my_vote,
     };
 
@@ -929,7 +926,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
     let form: CommentLikeForm = {
       comment_id: i.comment.id,
-      post_id: i.comment.post_id,
       score: this.state.my_vote,
     };
 
@@ -950,17 +946,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
   handleModRemoveSubmit(i: CommentNode) {
     event.preventDefault();
-    let form: CommentFormI = {
-      content: i.props.node.comment.content,
+    let form: RemoveCommentForm = {
       edit_id: i.props.node.comment.id,
-      creator_id: i.props.node.comment.creator_id,
-      post_id: i.props.node.comment.post_id,
-      parent_id: i.props.node.comment.parent_id,
       removed: !i.props.node.comment.removed,
       reason: i.state.removeReason,
       auth: null,
     };
-    WebSocketService.Instance.editComment(form);
+    WebSocketService.Instance.removeComment(form);
 
     i.state.showRemoveDialog = false;
     i.setState(i.state);
@@ -975,16 +967,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
       };
       WebSocketService.Instance.markUserMentionAsRead(form);
     } else {
-      let form: CommentFormI = {
-        content: i.props.node.comment.content,
+      let form: MarkCommentAsReadForm = {
         edit_id: i.props.node.comment.id,
-        creator_id: i.props.node.comment.creator_id,
-        post_id: i.props.node.comment.post_id,
-        parent_id: i.props.node.comment.parent_id,
         read: !i.props.node.comment.read,
         auth: null,
       };
-      WebSocketService.Instance.editComment(form);
+      WebSocketService.Instance.markCommentAsRead(form);
     }
 
     i.state.readLoading = true;
index 2899c2cb67e8aac8e3bd86ea6824126db7b0c6b3..66eaf96e681351ac66c4319c9f4bef660e42a564 100644 (file)
@@ -409,7 +409,11 @@ export class Community extends Component<any, State> {
       this.state.comments = data.comments;
       this.state.loading = false;
       this.setState(this.state);
-    } else if (res.op == UserOperation.EditComment) {
+    } else if (
+      res.op == UserOperation.EditComment ||
+      res.op == UserOperation.DeleteComment ||
+      res.op == UserOperation.RemoveComment
+    ) {
       let data = res.data as CommentResponse;
       editCommentRes(data, this.state.comments);
       this.setState(this.state);
index 5609879cc0348a1d77c5a58c5e176a050ebc1b95..66a3d6767c72a96d0d4ce7fb0c809e7d362526fa 100644 (file)
@@ -484,9 +484,16 @@ export class Inbox extends Component<any, InboxState> {
       this.setState(this.state);
     } else if (res.op == UserOperation.MarkAllAsRead) {
       // Moved to be instant
-    } else if (res.op == UserOperation.EditComment) {
+    } else if (
+      res.op == UserOperation.EditComment ||
+      res.op == UserOperation.DeleteComment ||
+      res.op == UserOperation.RemoveComment
+    ) {
       let data = res.data as CommentResponse;
       editCommentRes(data, this.state.replies);
+      this.setState(this.state);
+    } else if (res.op == UserOperation.MarkCommentAsRead) {
+      let data = res.data as CommentResponse;
 
       // If youre in the unread view, just remove it from the list
       if (this.state.unreadOrAll == UnreadOrAll.Unread && data.comment.read) {
index 0392090a5f3f26bc601a9470db0a7a644aba4d84..d203cd081f944e9cad6be3e02d1791580de97805 100644 (file)
@@ -701,7 +701,11 @@ export class Main extends Component<any, MainState> {
       this.state.comments = data.comments;
       this.state.loading = false;
       this.setState(this.state);
-    } else if (res.op == UserOperation.EditComment) {
+    } else if (
+      res.op == UserOperation.EditComment ||
+      res.op == UserOperation.DeleteComment ||
+      res.op == UserOperation.RemoveComment
+    ) {
       let data = res.data as CommentResponse;
       editCommentRes(data, this.state.comments);
       this.setState(this.state);
index 97f80b6e680540adc83e4c878a53b130b4cc9a33..91ffeb19f8093470b847eb6ec7f2f0bef9a4a993 100644 (file)
@@ -8,7 +8,7 @@ import {
   GetPostResponse,
   PostResponse,
   Comment,
-  CommentForm as CommentFormI,
+  MarkCommentAsReadForm,
   CommentResponse,
   CommentSortType,
   CommentViewType,
@@ -167,16 +167,12 @@ export class Post extends Component<any, PostState> {
       UserService.Instance.user &&
       UserService.Instance.user.id == parent_user_id
     ) {
-      let form: CommentFormI = {
-        content: found.content,
+      let form: MarkCommentAsReadForm = {
         edit_id: found.id,
-        creator_id: found.creator_id,
-        post_id: found.post_id,
-        parent_id: found.parent_id,
         read: true,
         auth: null,
       };
-      WebSocketService.Instance.editComment(form);
+      WebSocketService.Instance.markCommentAsRead(form);
       UserService.Instance.user.unreadCount--;
       UserService.Instance.sub.next({
         user: UserService.Instance.user,
@@ -435,7 +431,11 @@ export class Post extends Component<any, PostState> {
         this.state.comments.unshift(data.comment);
         this.setState(this.state);
       }
-    } else if (res.op == UserOperation.EditComment) {
+    } else if (
+      res.op == UserOperation.EditComment ||
+      res.op == UserOperation.DeleteComment ||
+      res.op == UserOperation.RemoveComment
+    ) {
       let data = res.data as CommentResponse;
       editCommentRes(data, this.state.comments);
       this.setState(this.state);
index 5f2346a240f3baf11fa4a12e34de8795e8062be1..339dc5e4a499c98b137c37d83b25eafbc761bf5f 100644 (file)
@@ -257,7 +257,11 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
       this.setState({
         comments: this.state.comments,
       });
-    } else if (res.op == UserOperation.EditComment) {
+    } else if (
+      res.op == UserOperation.EditComment ||
+      res.op == UserOperation.DeleteComment ||
+      res.op == UserOperation.RemoveComment
+    ) {
       const data = res.data as CommentResponse;
       editCommentRes(data, this.state.comments);
       this.setState({
index 7f650f1b147ee479b820c2f2e999d4122312f41b..6006f2ee491c2a90497c6c4fed7292a2fb6e6351 100644 (file)
@@ -9,6 +9,9 @@ export enum UserOperation {
   GetCommunity,
   CreateComment,
   EditComment,
+  DeleteComment,
+  RemoveComment,
+  MarkCommentAsRead,
   SaveComment,
   CreateCommentLike,
   GetPosts,
@@ -679,14 +682,29 @@ export interface PostResponse {
 
 export interface CommentForm {
   content: string;
-  post_id: number;
+  post_id?: number;
   parent_id?: number;
   edit_id?: number;
   creator_id?: number;
-  removed?: boolean;
-  deleted?: boolean;
+  auth: string;
+}
+
+export interface DeleteCommentForm {
+  edit_id: number;
+  deleted: boolean;
+  auth: string;
+}
+
+export interface RemoveCommentForm {
+  edit_id: number;
+  removed: boolean;
   reason?: string;
-  read?: boolean;
+  auth: string;
+}
+
+export interface MarkCommentAsReadForm {
+  edit_id: number;
+  read: boolean;
   auth: string;
 }
 
@@ -703,7 +721,6 @@ export interface CommentResponse {
 
 export interface CommentLikeForm {
   comment_id: number;
-  post_id: number;
   score: number;
   auth?: string;
 }
@@ -901,6 +918,9 @@ export type MessageType =
   | GetPostsForm
   | GetCommunityForm
   | CommentForm
+  | DeleteCommentForm
+  | RemoveCommentForm
+  | MarkCommentAsReadForm
   | CommentLikeForm
   | SaveCommentForm
   | CreatePostLikeForm
index 26e58135d0a0f5da0f75d4ec6eb98bac83aaf428..2c85425d844a337753e5bd2f0a9675f670a535d9 100644 (file)
@@ -9,6 +9,9 @@ import {
   PostForm,
   SavePostForm,
   CommentForm,
+  DeleteCommentForm,
+  RemoveCommentForm,
+  MarkCommentAsReadForm,
   SaveCommentForm,
   CommentLikeForm,
   GetPostForm,
@@ -165,14 +168,29 @@ export class WebSocketService {
     this.ws.send(this.wsSendWrapper(UserOperation.GetCommunity, form));
   }
 
-  public createComment(commentForm: CommentForm) {
-    this.setAuth(commentForm);
-    this.ws.send(this.wsSendWrapper(UserOperation.CreateComment, commentForm));
+  public createComment(form: CommentForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.CreateComment, form));
+  }
+
+  public editComment(form: CommentForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.EditComment, form));
   }
 
-  public editComment(commentForm: CommentForm) {
-    this.setAuth(commentForm);
-    this.ws.send(this.wsSendWrapper(UserOperation.EditComment, commentForm));
+  public deleteComment(form: DeleteCommentForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.DeleteComment, form));
+  }
+
+  public removeComment(form: RemoveCommentForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.RemoveComment, form));
+  }
+
+  public markCommentAsRead(form: MarkCommentAsReadForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.MarkCommentAsRead, form));
   }
 
   public likeComment(form: CommentLikeForm) {