]> Untitled Git - lemmy.git/commitdiff
Adding post delete, remove, lock, and sticky.
authorDessalines <tyhou13@gmx.com>
Tue, 21 Jul 2020 03:46:36 +0000 (23:46 -0400)
committerDessalines <tyhou13@gmx.com>
Tue, 21 Jul 2020 03:46:36 +0000 (23:46 -0400)
14 files changed:
docs/src/contributing_websocket_http_api.md
server/lemmy_db/src/post.rs
server/src/api/comment.rs
server/src/api/post.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/community.tsx
ui/src/components/post-form.tsx
ui/src/components/post-listing.tsx
ui/src/components/post.tsx
ui/src/interfaces.ts
ui/src/services/WebSocketService.ts

index 390fa9887d7e66f786d01afc9aa3600605f6b0dd..00e26b0d36597b97e3ea70f54a7385ef10907eee 100644 (file)
@@ -1271,8 +1271,9 @@ Only admins can remove a community.
     name: String,
     url: Option<String>,
     body: Option<String>,
+    nsfw: bool,
     community_id: i32,
-    auth: String
+    auth: String,
   }
 }
 ```
@@ -1378,25 +1379,17 @@ Post listing types are `All, Subscribed, Community`
 `POST /post/like`
 
 #### Edit Post
-
-Mods and admins can remove and lock a post, creators can delete it.
-
 ##### Request
 ```rust
 {
   op: "EditPost",
   data: {
     edit_id: i32,
-    creator_id: i32,
-    community_id: i32,
     name: String,
     url: Option<String>,
     body: Option<String>,
-    removed: Option<bool>,
-    deleted: Option<bool>,
-    locked: Option<bool>,
-    reason: Option<String>,
-    auth: String
+    nsfw: bool,
+    auth: String,
   }
 }
 ```
@@ -1414,6 +1407,120 @@ Mods and admins can remove and lock a post, creators can delete it.
 
 `PUT /post`
 
+#### Delete Post
+##### Request
+```rust
+{
+  op: "DeletePost",
+  data: {
+    edit_id: i32,
+    deleted: bool,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "DeletePost",
+  data: {
+    post: PostView
+  }
+}
+```
+
+##### HTTP
+
+`POST /post/delete`
+
+#### Remove Post
+
+Only admins and mods can remove a post.
+
+##### Request
+```rust
+{
+  op: "RemovePost",
+  data: {
+    edit_id: i32,
+    removed: bool,
+    reason: Option<String>,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "RemovePost",
+  data: {
+    post: PostView
+  }
+}
+```
+
+##### HTTP
+
+`POST /post/remove`
+
+#### Lock Post
+
+Only admins and mods can lock a post.
+
+##### Request
+```rust
+{
+  op: "LockPost",
+  data: {
+    edit_id: i32,
+    locked: bool,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "LockPost",
+  data: {
+    post: PostView
+  }
+}
+```
+
+##### HTTP
+
+`POST /post/lock`
+
+#### Sticky Post
+
+Only admins and mods can sticky a post.
+
+##### Request
+```rust
+{
+  op: "StickyPost",
+  data: {
+    edit_id: i32,
+    stickied: bool,
+    auth: String,
+  }
+}
+```
+##### Response
+```rust
+{
+  op: "StickyPost",
+  data: {
+    post: PostView
+  }
+}
+```
+
+##### HTTP
+
+`POST /post/sticky`
+
 #### Save Post
 ##### Request
 ```rust
index 66e24773a6e1adbb600da6dd15f0d489aff6c1a2..35b0feada20099e2a702a52f6a7327758f54ed96 100644 (file)
@@ -108,6 +108,46 @@ impl Post {
       ))
       .get_result::<Self>(conn)
   }
+
+  pub fn update_deleted(
+    conn: &PgConnection,
+    post_id: i32,
+    new_deleted: bool,
+  ) -> Result<Self, Error> {
+    use crate::schema::post::dsl::*;
+    diesel::update(post.find(post_id))
+      .set(deleted.eq(new_deleted))
+      .get_result::<Self>(conn)
+  }
+
+  pub fn update_removed(
+    conn: &PgConnection,
+    post_id: i32,
+    new_removed: bool,
+  ) -> Result<Self, Error> {
+    use crate::schema::post::dsl::*;
+    diesel::update(post.find(post_id))
+      .set(removed.eq(new_removed))
+      .get_result::<Self>(conn)
+  }
+
+  pub fn update_locked(conn: &PgConnection, post_id: i32, new_locked: bool) -> Result<Self, Error> {
+    use crate::schema::post::dsl::*;
+    diesel::update(post.find(post_id))
+      .set(locked.eq(new_locked))
+      .get_result::<Self>(conn)
+  }
+
+  pub fn update_stickied(
+    conn: &PgConnection,
+    post_id: i32,
+    new_stickied: bool,
+  ) -> Result<Self, Error> {
+    use crate::schema::post::dsl::*;
+    diesel::update(post.find(post_id))
+      .set(stickied.eq(new_stickied))
+      .get_result::<Self>(conn)
+  }
 }
 
 impl Crud<PostForm> for Post {
index 1a06032b27352b3a97b10f776b143fdb2c868632..79b7b2c7977cc277be7317341f80b96d1a78dab8 100644 (file)
@@ -162,6 +162,11 @@ impl Perform for Oper<CreateComment> {
       return Err(APIError::err("site_ban").into());
     }
 
+    // Check if post is locked, no new comments
+    if post.locked {
+      return Err(APIError::err("locked").into());
+    }
+
     // Create the comment
     let comment_form2 = comment_form.clone();
     let inserted_comment =
index 61f3513b68976b2428ef302f3fcb2ffc5e504e18..390d291cfa5c2b97b24a27ce88414309ae0b2671 100644 (file)
@@ -13,6 +13,7 @@ use crate::{
 };
 use lemmy_db::{
   comment_view::*,
+  community::*,
   community_view::*,
   moderator::*,
   naive_now,
@@ -96,20 +97,42 @@ pub struct CreatePostLike {
 #[derive(Serialize, Deserialize)]
 pub struct EditPost {
   pub edit_id: i32,
-  creator_id: i32,
-  community_id: i32,
   name: String,
   url: Option<String>,
   body: Option<String>,
-  removed: Option<bool>,
-  deleted: Option<bool>,
   nsfw: bool,
-  locked: Option<bool>,
-  stickied: Option<bool>,
+  auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct DeletePost {
+  pub edit_id: i32,
+  deleted: bool,
+  auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct RemovePost {
+  pub edit_id: i32,
+  removed: bool,
   reason: Option<String>,
   auth: String,
 }
 
+#[derive(Serialize, Deserialize)]
+pub struct LockPost {
+  pub edit_id: i32,
+  locked: bool,
+  auth: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct StickyPost {
+  pub edit_id: i32,
+  stickied: bool,
+  auth: String,
+}
+
 #[derive(Serialize, Deserialize)]
 pub struct SavePost {
   post_id: i32,
@@ -549,35 +572,10 @@ impl Perform for Oper<EditPost> {
     let user_id = claims.id;
 
     let edit_id = data.edit_id;
-    let read_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
-
-    // Verify its the creator or a mod or admin
-    let community_id = read_post.community_id;
-    let mut editors: Vec<i32> = vec![read_post.creator_id];
-    let mut moderators: Vec<i32> = vec![];
-
-    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);
-
-    if !editors.contains(&user_id) {
-      return Err(APIError::err("no_post_edit_allowed").into());
-    }
+    let orig_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
 
     // Check for a community ban
-    let community_id = read_post.community_id;
+    let community_id = orig_post.community_id;
     let is_banned =
       move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
     if blocking(pool, is_banned).await? {
@@ -590,55 +588,34 @@ impl Perform for Oper<EditPost> {
       return Err(APIError::err("site_ban").into());
     }
 
+    // Verify that only the creator can edit
+    if user_id != orig_post.creator_id {
+      return Err(APIError::err("no_post_edit_allowed").into());
+    }
+
     // Fetch Iframely and Pictrs cached image
     let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) =
       fetch_iframely_and_pictrs_data(&self.client, data.url.to_owned()).await;
 
-    let post_form = {
-      // only modify some properties if they are a moderator
-      if moderators.contains(&user_id) {
-        PostForm {
-          name: data.name.trim().to_owned(),
-          url: data.url.to_owned(),
-          body: data.body.to_owned(),
-          creator_id: read_post.creator_id.to_owned(),
-          community_id: read_post.community_id,
-          removed: data.removed.to_owned(),
-          deleted: data.deleted.to_owned(),
-          nsfw: data.nsfw,
-          locked: data.locked.to_owned(),
-          stickied: data.stickied.to_owned(),
-          updated: Some(naive_now()),
-          embed_title: iframely_title,
-          embed_description: iframely_description,
-          embed_html: iframely_html,
-          thumbnail_url: pictrs_thumbnail,
-          ap_id: read_post.ap_id,
-          local: read_post.local,
-          published: None,
-        }
-      } else {
-        PostForm {
-          name: read_post.name.trim().to_owned(),
-          url: data.url.to_owned(),
-          body: data.body.to_owned(),
-          creator_id: read_post.creator_id.to_owned(),
-          community_id: read_post.community_id,
-          removed: Some(read_post.removed),
-          deleted: data.deleted.to_owned(),
-          nsfw: data.nsfw,
-          locked: Some(read_post.locked),
-          stickied: Some(read_post.stickied),
-          updated: Some(naive_now()),
-          embed_title: iframely_title,
-          embed_description: iframely_description,
-          embed_html: iframely_html,
-          thumbnail_url: pictrs_thumbnail,
-          ap_id: read_post.ap_id,
-          local: read_post.local,
-          published: None,
-        }
-      }
+    let post_form = PostForm {
+      name: data.name.trim().to_owned(),
+      url: data.url.to_owned(),
+      body: data.body.to_owned(),
+      nsfw: data.nsfw,
+      creator_id: orig_post.creator_id.to_owned(),
+      community_id: orig_post.community_id,
+      removed: Some(orig_post.removed),
+      deleted: Some(orig_post.deleted),
+      locked: Some(orig_post.locked),
+      stickied: Some(orig_post.stickied),
+      updated: Some(naive_now()),
+      embed_title: iframely_title,
+      embed_description: iframely_description,
+      embed_html: iframely_html,
+      thumbnail_url: pictrs_thumbnail,
+      ap_id: orig_post.ap_id,
+      local: orig_post.local,
+      published: None,
     };
 
     let edit_id = data.edit_id;
@@ -656,59 +633,87 @@ impl Perform for Oper<EditPost> {
       }
     };
 
-    if moderators.contains(&user_id) {
-      // Mod tables
-      if let Some(removed) = data.removed.to_owned() {
-        let form = ModRemovePostForm {
-          mod_user_id: user_id,
-          post_id: data.edit_id,
-          removed: Some(removed),
-          reason: data.reason.to_owned(),
-        };
-        blocking(pool, move |conn| ModRemovePost::create(conn, &form)).await??;
-      }
+    // Send apub update
+    updated_post.send_update(&user, &self.client, pool).await?;
 
-      if let Some(locked) = data.locked.to_owned() {
-        let form = ModLockPostForm {
-          mod_user_id: user_id,
-          post_id: data.edit_id,
-          locked: Some(locked),
-        };
-        blocking(pool, move |conn| ModLockPost::create(conn, &form)).await??;
-      }
+    let edit_id = data.edit_id;
+    let post_view = blocking(pool, move |conn| {
+      PostView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
 
-      if let Some(stickied) = data.stickied.to_owned() {
-        let form = ModStickyPostForm {
-          mod_user_id: user_id,
-          post_id: data.edit_id,
-          stickied: Some(stickied),
-        };
-        blocking(pool, move |conn| ModStickyPost::create(conn, &form)).await??;
-      }
+    let res = PostResponse { post: post_view };
+
+    if let Some(ws) = websocket_info {
+      ws.chatserver.do_send(SendPost {
+        op: UserOperation::EditPost,
+        post: res.clone(),
+        my_id: ws.id,
+      });
     }
 
-    if let Some(deleted) = data.deleted.to_owned() {
-      if deleted {
-        updated_post.send_delete(&user, &self.client, pool).await?;
-      } else {
-        updated_post
-          .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_post.send_remove(&user, &self.client, pool).await?;
-        } else {
-          updated_post
-            .send_undo_remove(&user, &self.client, pool)
-            .await?;
-        }
-      }
+    Ok(res)
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<DeletePost> {
+  type Response = PostResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    websocket_info: Option<WebsocketInfo>,
+  ) -> Result<PostResponse, LemmyError> {
+    let data: &DeletePost = &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_post = blocking(pool, move |conn| Post::read(conn, edit_id)).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_post.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_post.creator_id {
+      return Err(APIError::err("no_post_edit_allowed").into());
+    }
+
+    // Update the post
+    let edit_id = data.edit_id;
+    let deleted = data.deleted;
+    let updated_post = blocking(pool, move |conn| {
+      Post::update_deleted(conn, edit_id, deleted)
+    })
+    .await??;
+
+    // apub updates
+    if deleted {
+      updated_post.send_delete(&user, &self.client, pool).await?;
     } else {
-      updated_post.send_update(&user, &self.client, pool).await?;
+      updated_post
+        .send_undo_delete(&user, &self.client, pool)
+        .await?;
     }
 
+    // Refetch the post
     let edit_id = data.edit_id;
     let post_view = blocking(pool, move |conn| {
       PostView::read(conn, edit_id, Some(user_id))
@@ -719,7 +724,265 @@ impl Perform for Oper<EditPost> {
 
     if let Some(ws) = websocket_info {
       ws.chatserver.do_send(SendPost {
-        op: UserOperation::EditPost,
+        op: UserOperation::DeletePost,
+        post: res.clone(),
+        my_id: ws.id,
+      });
+    }
+
+    Ok(res)
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<RemovePost> {
+  type Response = PostResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    websocket_info: Option<WebsocketInfo>,
+  ) -> Result<PostResponse, LemmyError> {
+    let data: &RemovePost = &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_post = blocking(pool, move |conn| Post::read(conn, edit_id)).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_post.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 mods 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());
+    }
+
+    // Update the post
+    let edit_id = data.edit_id;
+    let removed = data.removed;
+    let updated_post = blocking(pool, move |conn| {
+      Post::update_removed(conn, edit_id, removed)
+    })
+    .await??;
+
+    // Mod tables
+    let form = ModRemovePostForm {
+      mod_user_id: user_id,
+      post_id: data.edit_id,
+      removed: Some(removed),
+      reason: data.reason.to_owned(),
+    };
+    blocking(pool, move |conn| ModRemovePost::create(conn, &form)).await??;
+
+    // apub updates
+    if removed {
+      updated_post.send_remove(&user, &self.client, pool).await?;
+    } else {
+      updated_post
+        .send_undo_remove(&user, &self.client, pool)
+        .await?;
+    }
+
+    // Refetch the post
+    let edit_id = data.edit_id;
+    let post_view = blocking(pool, move |conn| {
+      PostView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
+
+    let res = PostResponse { post: post_view };
+
+    if let Some(ws) = websocket_info {
+      ws.chatserver.do_send(SendPost {
+        op: UserOperation::RemovePost,
+        post: res.clone(),
+        my_id: ws.id,
+      });
+    }
+
+    Ok(res)
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<LockPost> {
+  type Response = PostResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    websocket_info: Option<WebsocketInfo>,
+  ) -> Result<PostResponse, LemmyError> {
+    let data: &LockPost = &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_post = blocking(pool, move |conn| Post::read(conn, edit_id)).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_post.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 mods can lock
+    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());
+    }
+
+    // Update the post
+    let edit_id = data.edit_id;
+    let locked = data.locked;
+    let updated_post =
+      blocking(pool, move |conn| Post::update_locked(conn, edit_id, locked)).await??;
+
+    // Mod tables
+    let form = ModLockPostForm {
+      mod_user_id: user_id,
+      post_id: data.edit_id,
+      locked: Some(locked),
+    };
+    blocking(pool, move |conn| ModLockPost::create(conn, &form)).await??;
+
+    // apub updates
+    updated_post.send_update(&user, &self.client, pool).await?;
+
+    // Refetch the post
+    let edit_id = data.edit_id;
+    let post_view = blocking(pool, move |conn| {
+      PostView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
+
+    let res = PostResponse { post: post_view };
+
+    if let Some(ws) = websocket_info {
+      ws.chatserver.do_send(SendPost {
+        op: UserOperation::LockPost,
+        post: res.clone(),
+        my_id: ws.id,
+      });
+    }
+
+    Ok(res)
+  }
+}
+
+#[async_trait::async_trait(?Send)]
+impl Perform for Oper<StickyPost> {
+  type Response = PostResponse;
+
+  async fn perform(
+    &self,
+    pool: &DbPool,
+    websocket_info: Option<WebsocketInfo>,
+  ) -> Result<PostResponse, LemmyError> {
+    let data: &StickyPost = &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_post = blocking(pool, move |conn| Post::read(conn, edit_id)).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_post.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 mods can sticky
+    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());
+    }
+
+    // Update the post
+    let edit_id = data.edit_id;
+    let stickied = data.stickied;
+    let updated_post = blocking(pool, move |conn| {
+      Post::update_stickied(conn, edit_id, stickied)
+    })
+    .await??;
+
+    // Mod tables
+    let form = ModStickyPostForm {
+      mod_user_id: user_id,
+      post_id: data.edit_id,
+      stickied: Some(stickied),
+    };
+    blocking(pool, move |conn| ModStickyPost::create(conn, &form)).await??;
+
+    // Apub updates
+    // TODO stickied should pry work like locked for ease of use
+    updated_post.send_update(&user, &self.client, pool).await?;
+
+    // Refetch the post
+    let edit_id = data.edit_id;
+    let post_view = blocking(pool, move |conn| {
+      PostView::read(conn, edit_id, Some(user_id))
+    })
+    .await??;
+
+    let res = PostResponse { post: post_view };
+
+    if let Some(ws) = websocket_info {
+      ws.chatserver.do_send(SendPost {
+        op: UserOperation::StickyPost,
         post: res.clone(),
         my_id: ws.id,
       });
index 9fc84f4c349770ee23a6e1da653a27c70a39b4a2..31888156ea15af47ed9712f595571ce5f361f29f 100644 (file)
@@ -73,6 +73,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
           .wrap(rate_limit.message())
           .route("", web::get().to(route_get::<GetPost>))
           .route("", web::put().to(route_post::<EditPost>))
+          .route("/delete", web::post().to(route_post::<DeletePost>))
+          .route("/remove", web::post().to(route_post::<RemovePost>))
+          .route("/lock", web::post().to(route_post::<LockPost>))
+          .route("/sticky", web::post().to(route_post::<StickyPost>))
           .route("/list", web::get().to(route_get::<GetPosts>))
           .route("/like", web::post().to(route_post::<CreatePostLike>))
           .route("/save", web::put().to(route_post::<SavePost>)),
index ed8ee272a5acc43fb95504979ea3f2091604e984..5f3157b1bff1b058a6187767883e67c6f0726723 100644 (file)
@@ -36,6 +36,10 @@ pub enum UserOperation {
   GetPosts,
   CreatePostLike,
   EditPost,
+  DeletePost,
+  RemovePost,
+  LockPost,
+  StickyPost,
   SavePost,
   EditCommunity,
   DeleteCommunity,
index 6f0516ffd50a30dcc15aea7f2c86ed42c92a69ea..cc6de1150196ddf2c29654ee2d1e0850875b0b2e 100644 (file)
@@ -500,6 +500,10 @@ impl ChatServer {
         UserOperation::GetPost => do_user_operation::<GetPost>(args).await,
         UserOperation::GetPosts => do_user_operation::<GetPosts>(args).await,
         UserOperation::EditPost => do_user_operation::<EditPost>(args).await,
+        UserOperation::DeletePost => do_user_operation::<DeletePost>(args).await,
+        UserOperation::RemovePost => do_user_operation::<RemovePost>(args).await,
+        UserOperation::LockPost => do_user_operation::<LockPost>(args).await,
+        UserOperation::StickyPost => do_user_operation::<StickyPost>(args).await,
         UserOperation::CreatePostLike => do_user_operation::<CreatePostLike>(args).await,
         UserOperation::SavePost => do_user_operation::<SavePost>(args).await,
 
index f3cc867364891acee89bdb4cac16ffeb47ea8188..9ab9fc2ae89eddeec53237a1b6cf4ca872ac16a1 100644 (file)
@@ -4,6 +4,9 @@ import {
   LoginForm,
   LoginResponse,
   PostForm,
+  DeletePostForm,
+  RemovePostForm,
+  // TODO need to test LockPost and StickyPost federated
   PostResponse,
   SearchResponse,
   FollowCommunityForm,
@@ -100,7 +103,6 @@ describe('main', () => {
         name,
         auth: lemmyAlphaAuth,
         community_id: 2,
-        creator_id: 2,
         nsfw: false,
       };
 
@@ -269,7 +271,6 @@ describe('main', () => {
         name,
         auth: lemmyAlphaAuth,
         community_id: 3,
-        creator_id: 2,
         nsfw: false,
       };
 
@@ -326,7 +327,6 @@ describe('main', () => {
         edit_id: 2,
         auth: lemmyAlphaAuth,
         community_id: 3,
-        creator_id: 2,
         nsfw: false,
       };
 
@@ -587,7 +587,6 @@ describe('main', () => {
         name: postName,
         auth: lemmyBetaAuth,
         community_id: createCommunityRes.community.id,
-        creator_id: 2,
         nsfw: false,
       };
 
@@ -673,23 +672,22 @@ describe('main', () => {
       expect(getPostUndeleteRes.comments[0].deleted).toBe(false);
 
       // lemmy_beta deletes the post
-      let deletePostForm: PostForm = {
-        name: postName,
+      let deletePostForm: DeletePostForm = {
         edit_id: createPostRes.post.id,
-        auth: lemmyBetaAuth,
-        community_id: createPostRes.post.community_id,
-        creator_id: createPostRes.post.creator_id,
-        nsfw: false,
         deleted: true,
+        auth: lemmyBetaAuth,
       };
 
-      let deletePostRes: PostResponse = await fetch(`${lemmyBetaApiUrl}/post`, {
-        method: 'PUT',
-        headers: {
-          'Content-Type': 'application/json',
-        },
-        body: wrapper(deletePostForm),
-      }).then(d => d.json());
+      let deletePostRes: PostResponse = await fetch(
+        `${lemmyBetaApiUrl}/post/delete`,
+        {
+          method: 'POST',
+          headers: {
+            'Content-Type': 'application/json',
+          },
+          body: wrapper(deletePostForm),
+        }
+      ).then(d => d.json());
       expect(deletePostRes.post.deleted).toBe(true);
 
       // Make sure lemmy_alpha sees the post is deleted
@@ -699,20 +697,16 @@ describe('main', () => {
       expect(getPostResAgain.post.deleted).toBe(true);
 
       // lemmy_beta undeletes the post
-      let undeletePostForm: PostForm = {
-        name: postName,
+      let undeletePostForm: DeletePostForm = {
         edit_id: createPostRes.post.id,
-        auth: lemmyBetaAuth,
-        community_id: createPostRes.post.community_id,
-        creator_id: createPostRes.post.creator_id,
-        nsfw: false,
         deleted: false,
+        auth: lemmyBetaAuth,
       };
 
       let undeletePostRes: PostResponse = await fetch(
-        `${lemmyBetaApiUrl}/post`,
+        `${lemmyBetaApiUrl}/post/delete`,
         {
-          method: 'PUT',
+          method: 'POST',
           headers: {
             'Content-Type': 'application/json',
           },
@@ -849,7 +843,6 @@ describe('main', () => {
         name: postName,
         auth: lemmyBetaAuth,
         community_id: createCommunityRes.community.id,
-        creator_id: 2,
         nsfw: false,
       };
 
@@ -935,23 +928,22 @@ describe('main', () => {
       expect(getPostUnremoveRes.comments[0].removed).toBe(false);
 
       // lemmy_beta deletes the post
-      let removePostForm: PostForm = {
-        name: postName,
+      let removePostForm: RemovePostForm = {
         edit_id: createPostRes.post.id,
-        auth: lemmyBetaAuth,
-        community_id: createPostRes.post.community_id,
-        creator_id: createPostRes.post.creator_id,
-        nsfw: false,
         removed: true,
+        auth: lemmyBetaAuth,
       };
 
-      let removePostRes: PostResponse = await fetch(`${lemmyBetaApiUrl}/post`, {
-        method: 'PUT',
-        headers: {
-          'Content-Type': 'application/json',
-        },
-        body: wrapper(removePostForm),
-      }).then(d => d.json());
+      let removePostRes: PostResponse = await fetch(
+        `${lemmyBetaApiUrl}/post/remove`,
+        {
+          method: 'POST',
+          headers: {
+            'Content-Type': 'application/json',
+          },
+          body: wrapper(removePostForm),
+        }
+      ).then(d => d.json());
       expect(removePostRes.post.removed).toBe(true);
 
       // Make sure lemmy_alpha sees the post is deleted
@@ -961,20 +953,16 @@ describe('main', () => {
       expect(getPostResAgain.post.removed).toBe(true);
 
       // lemmy_beta unremoves the post
-      let unremovePostForm: PostForm = {
-        name: postName,
+      let unremovePostForm: RemovePostForm = {
         edit_id: createPostRes.post.id,
-        auth: lemmyBetaAuth,
-        community_id: createPostRes.post.community_id,
-        creator_id: createPostRes.post.creator_id,
-        nsfw: false,
         removed: false,
+        auth: lemmyBetaAuth,
       };
 
       let unremovePostRes: PostResponse = await fetch(
-        `${lemmyBetaApiUrl}/post`,
+        `${lemmyBetaApiUrl}/post/remove`,
         {
-          method: 'PUT',
+          method: 'POST',
           headers: {
             'Content-Type': 'application/json',
           },
@@ -1226,7 +1214,6 @@ describe('main', () => {
         name: postName,
         auth: lemmyAlphaAuth,
         community_id: 2,
-        creator_id: 2,
         nsfw: false,
       };
 
@@ -1337,7 +1324,6 @@ describe('main', () => {
         name: betaPostName,
         auth: lemmyBetaAuth,
         community_id: 2,
-        creator_id: 2,
         nsfw: false,
       };
 
index 66eaf96e681351ac66c4319c9f4bef660e42a564..f70fa4f7af7a701326d982cab581dc21b4813d75 100644 (file)
@@ -380,7 +380,13 @@ export class Community extends Component<any, State> {
       this.state.loading = false;
       this.setState(this.state);
       setupTippy();
-    } else if (res.op == UserOperation.EditPost) {
+    } else if (
+      res.op == UserOperation.EditPost ||
+      res.op == UserOperation.DeletePost ||
+      res.op == UserOperation.RemovePost ||
+      res.op == UserOperation.LockPost ||
+      res.op == UserOperation.StickyPost
+    ) {
       let data = res.data as PostResponse;
       editPostFindRes(data, this.state.posts);
       this.setState(this.state);
index 6656ef84242bdab6188cf78ef92ae2b8f5a65a56..854cff6e9a8d438ccd802cfd89dfc270c4b4bca7 100644 (file)
@@ -71,9 +71,6 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
       nsfw: false,
       auth: null,
       community_id: null,
-      creator_id: UserService.Instance.user
-        ? UserService.Instance.user.id
-        : null,
     },
     communities: [],
     loading: false,
@@ -99,7 +96,6 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
         name: this.props.post.name,
         community_id: this.props.post.community_id,
         edit_id: this.props.post.id,
-        creator_id: this.props.post.creator_id,
         url: this.props.post.url,
         nsfw: this.props.post.nsfw,
         auth: null,
index a47aba99205175b527233015b694cdce8a552e27..e117a282ea23488621bab73dc1467e83af15843c 100644 (file)
@@ -4,7 +4,10 @@ import { WebSocketService, UserService } from '../services';
 import {
   Post,
   CreatePostLikeForm,
-  PostForm as PostFormI,
+  DeletePostForm,
+  RemovePostForm,
+  LockPostForm,
+  StickyPostForm,
   SavePostForm,
   CommunityUser,
   UserView,
@@ -33,7 +36,6 @@ import {
   setupTippy,
   hostname,
   previewLines,
-  toast,
 } from '../utils';
 import { i18n } from '../i18next';
 
@@ -1114,18 +1116,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   handleDeleteClick(i: PostListing) {
-    let deleteForm: PostFormI = {
-      body: i.props.post.body,
-      community_id: i.props.post.community_id,
-      name: i.props.post.name,
-      url: i.props.post.url,
+    let deleteForm: DeletePostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
       deleted: !i.props.post.deleted,
-      nsfw: i.props.post.nsfw,
       auth: null,
     };
-    WebSocketService.Instance.editPost(deleteForm);
+    WebSocketService.Instance.deletePost(deleteForm);
   }
 
   handleSavePostClick(i: PostListing) {
@@ -1163,46 +1159,34 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
 
   handleModRemoveSubmit(i: PostListing) {
     event.preventDefault();
-    let form: PostFormI = {
-      name: i.props.post.name,
-      community_id: i.props.post.community_id,
+    let form: RemovePostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
       removed: !i.props.post.removed,
       reason: i.state.removeReason,
-      nsfw: i.props.post.nsfw,
       auth: null,
     };
-    WebSocketService.Instance.editPost(form);
+    WebSocketService.Instance.removePost(form);
 
     i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
 
   handleModLock(i: PostListing) {
-    let form: PostFormI = {
-      name: i.props.post.name,
-      community_id: i.props.post.community_id,
+    let form: LockPostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
-      nsfw: i.props.post.nsfw,
       locked: !i.props.post.locked,
       auth: null,
     };
-    WebSocketService.Instance.editPost(form);
+    WebSocketService.Instance.lockPost(form);
   }
 
   handleModSticky(i: PostListing) {
-    let form: PostFormI = {
-      name: i.props.post.name,
-      community_id: i.props.post.community_id,
+    let form: StickyPostForm = {
       edit_id: i.props.post.id,
-      creator_id: i.props.post.creator_id,
-      nsfw: i.props.post.nsfw,
       stickied: !i.props.post.stickied,
       auth: null,
     };
-    WebSocketService.Instance.editPost(form);
+    WebSocketService.Instance.stickyPost(form);
   }
 
   handleModBanFromCommunityShow(i: PostListing) {
index 91ffeb19f8093470b847eb6ec7f2f0bef9a4a993..c811062f5d167012ed727db98eb7fb378d166c5b 100644 (file)
@@ -452,7 +452,13 @@ export class Post extends Component<any, PostState> {
       let data = res.data as PostResponse;
       createPostLikeRes(data, this.state.post);
       this.setState(this.state);
-    } else if (res.op == UserOperation.EditPost) {
+    } else if (
+      res.op == UserOperation.EditPost ||
+      res.op == UserOperation.DeletePost ||
+      res.op == UserOperation.RemovePost ||
+      res.op == UserOperation.LockPost ||
+      res.op == UserOperation.StickyPost
+    ) {
       let data = res.data as PostResponse;
       this.state.post = data.post;
       this.setState(this.state);
index 6006f2ee491c2a90497c6c4fed7292a2fb6e6351..8dced1a61552775d4ef04a19357129efb48197f9 100644 (file)
@@ -17,6 +17,10 @@ export enum UserOperation {
   GetPosts,
   CreatePostLike,
   EditPost,
+  DeletePost,
+  RemovePost,
+  LockPost,
+  StickyPost,
   SavePost,
   EditCommunity,
   DeleteCommunity,
@@ -636,19 +640,37 @@ export interface PostForm {
   name: string;
   url?: string;
   body?: string;
-  community_id: number;
-  updated?: number;
+  community_id?: number;
   edit_id?: number;
-  creator_id: number;
-  removed?: boolean;
-  deleted?: boolean;
   nsfw: boolean;
-  locked?: boolean;
-  stickied?: boolean;
+  auth: string;
+}
+
+export interface DeletePostForm {
+  edit_id: number;
+  deleted: boolean;
+  auth: string;
+}
+
+export interface RemovePostForm {
+  edit_id: number;
+  removed: boolean;
   reason?: string;
   auth: string;
 }
 
+export interface LockPostForm {
+  edit_id: number;
+  locked: boolean;
+  auth: string;
+}
+
+export interface StickyPostForm {
+  edit_id: number;
+  stickied: boolean;
+  auth: string;
+}
+
 export interface PostFormParams {
   name: string;
   url?: string;
@@ -914,6 +936,10 @@ export type MessageType =
   | ListCommunitiesForm
   | GetFollowedCommunitiesForm
   | PostForm
+  | DeletePostForm
+  | RemovePostForm
+  | LockPostForm
+  | StickyPostForm
   | GetPostForm
   | GetPostsForm
   | GetCommunityForm
index 2c85425d844a337753e5bd2f0a9675f670a535d9..aabfc4dd5d35ba298531a874e96c4fbe5d4a02c8 100644 (file)
@@ -7,6 +7,10 @@ import {
   DeleteCommunityForm,
   RemoveCommunityForm,
   PostForm,
+  DeletePostForm,
+  RemovePostForm,
+  LockPostForm,
+  StickyPostForm,
   SavePostForm,
   CommentForm,
   DeleteCommentForm,
@@ -153,9 +157,9 @@ export class WebSocketService {
     this.ws.send(this.wsSendWrapper(UserOperation.ListCategories, {}));
   }
 
-  public createPost(postForm: PostForm) {
-    this.setAuth(postForm);
-    this.ws.send(this.wsSendWrapper(UserOperation.CreatePost, postForm));
+  public createPost(form: PostForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.CreatePost, form));
   }
 
   public getPost(form: GetPostForm) {
@@ -218,9 +222,29 @@ export class WebSocketService {
     this.ws.send(this.wsSendWrapper(UserOperation.CreatePostLike, form));
   }
 
-  public editPost(postForm: PostForm) {
-    this.setAuth(postForm);
-    this.ws.send(this.wsSendWrapper(UserOperation.EditPost, postForm));
+  public editPost(form: PostForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.EditPost, form));
+  }
+
+  public deletePost(form: DeletePostForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.DeletePost, form));
+  }
+
+  public removePost(form: RemovePostForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.RemovePost, form));
+  }
+
+  public lockPost(form: LockPostForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.LockPost, form));
+  }
+
+  public stickyPost(form: StickyPostForm) {
+    this.setAuth(form);
+    this.ws.send(this.wsSendWrapper(UserOperation.StickyPost, form));
   }
 
   public savePost(form: SavePostForm) {