Adding post delete, remove, lock, and sticky.
This commit is contained in:
parent
fd96dfdb5e
commit
2eac037408
14 changed files with 692 additions and 237 deletions
129
docs/src/contributing_websocket_http_api.md
vendored
129
docs/src/contributing_websocket_http_api.md
vendored
|
@ -1271,8 +1271,9 @@ Only admins can remove a community.
|
||||||
name: String,
|
name: String,
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
body: Option<String>,
|
body: Option<String>,
|
||||||
|
nsfw: bool,
|
||||||
community_id: i32,
|
community_id: i32,
|
||||||
auth: String
|
auth: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1378,25 +1379,17 @@ Post listing types are `All, Subscribed, Community`
|
||||||
`POST /post/like`
|
`POST /post/like`
|
||||||
|
|
||||||
#### Edit Post
|
#### Edit Post
|
||||||
|
|
||||||
Mods and admins can remove and lock a post, creators can delete it.
|
|
||||||
|
|
||||||
##### Request
|
##### Request
|
||||||
```rust
|
```rust
|
||||||
{
|
{
|
||||||
op: "EditPost",
|
op: "EditPost",
|
||||||
data: {
|
data: {
|
||||||
edit_id: i32,
|
edit_id: i32,
|
||||||
creator_id: i32,
|
|
||||||
community_id: i32,
|
|
||||||
name: String,
|
name: String,
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
body: Option<String>,
|
body: Option<String>,
|
||||||
removed: Option<bool>,
|
nsfw: bool,
|
||||||
deleted: Option<bool>,
|
auth: String,
|
||||||
locked: Option<bool>,
|
|
||||||
reason: Option<String>,
|
|
||||||
auth: String
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1414,6 +1407,120 @@ Mods and admins can remove and lock a post, creators can delete it.
|
||||||
|
|
||||||
`PUT /post`
|
`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
|
#### Save Post
|
||||||
##### Request
|
##### Request
|
||||||
```rust
|
```rust
|
||||||
|
|
|
@ -108,6 +108,46 @@ impl Post {
|
||||||
))
|
))
|
||||||
.get_result::<Self>(conn)
|
.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 {
|
impl Crud<PostForm> for Post {
|
||||||
|
|
|
@ -162,6 +162,11 @@ impl Perform for Oper<CreateComment> {
|
||||||
return Err(APIError::err("site_ban").into());
|
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
|
// Create the comment
|
||||||
let comment_form2 = comment_form.clone();
|
let comment_form2 = comment_form.clone();
|
||||||
let inserted_comment =
|
let inserted_comment =
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
|
community::*,
|
||||||
community_view::*,
|
community_view::*,
|
||||||
moderator::*,
|
moderator::*,
|
||||||
naive_now,
|
naive_now,
|
||||||
|
@ -96,20 +97,42 @@ pub struct CreatePostLike {
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct EditPost {
|
pub struct EditPost {
|
||||||
pub edit_id: i32,
|
pub edit_id: i32,
|
||||||
creator_id: i32,
|
|
||||||
community_id: i32,
|
|
||||||
name: String,
|
name: String,
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
body: Option<String>,
|
body: Option<String>,
|
||||||
removed: Option<bool>,
|
|
||||||
deleted: Option<bool>,
|
|
||||||
nsfw: bool,
|
nsfw: bool,
|
||||||
locked: Option<bool>,
|
auth: String,
|
||||||
stickied: Option<bool>,
|
}
|
||||||
|
|
||||||
|
#[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>,
|
reason: Option<String>,
|
||||||
auth: 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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SavePost {
|
pub struct SavePost {
|
||||||
post_id: i32,
|
post_id: i32,
|
||||||
|
@ -549,35 +572,10 @@ impl Perform for Oper<EditPost> {
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
|
|
||||||
let edit_id = data.edit_id;
|
let edit_id = data.edit_id;
|
||||||
let read_post = blocking(pool, move |conn| Post::read(conn, edit_id)).await??;
|
let orig_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());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a community ban
|
// Check for a community ban
|
||||||
let community_id = read_post.community_id;
|
let community_id = orig_post.community_id;
|
||||||
let is_banned =
|
let is_banned =
|
||||||
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
|
move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok();
|
||||||
if blocking(pool, is_banned).await? {
|
if blocking(pool, is_banned).await? {
|
||||||
|
@ -590,55 +588,34 @@ impl Perform for Oper<EditPost> {
|
||||||
return Err(APIError::err("site_ban").into());
|
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
|
// Fetch Iframely and Pictrs cached image
|
||||||
let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) =
|
let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) =
|
||||||
fetch_iframely_and_pictrs_data(&self.client, data.url.to_owned()).await;
|
fetch_iframely_and_pictrs_data(&self.client, data.url.to_owned()).await;
|
||||||
|
|
||||||
let post_form = {
|
let post_form = PostForm {
|
||||||
// only modify some properties if they are a moderator
|
|
||||||
if moderators.contains(&user_id) {
|
|
||||||
PostForm {
|
|
||||||
name: data.name.trim().to_owned(),
|
name: data.name.trim().to_owned(),
|
||||||
url: data.url.to_owned(),
|
url: data.url.to_owned(),
|
||||||
body: data.body.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,
|
nsfw: data.nsfw,
|
||||||
locked: data.locked.to_owned(),
|
creator_id: orig_post.creator_id.to_owned(),
|
||||||
stickied: data.stickied.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()),
|
updated: Some(naive_now()),
|
||||||
embed_title: iframely_title,
|
embed_title: iframely_title,
|
||||||
embed_description: iframely_description,
|
embed_description: iframely_description,
|
||||||
embed_html: iframely_html,
|
embed_html: iframely_html,
|
||||||
thumbnail_url: pictrs_thumbnail,
|
thumbnail_url: pictrs_thumbnail,
|
||||||
ap_id: read_post.ap_id,
|
ap_id: orig_post.ap_id,
|
||||||
local: read_post.local,
|
local: orig_post.local,
|
||||||
published: None,
|
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 edit_id = data.edit_id;
|
let edit_id = data.edit_id;
|
||||||
|
@ -656,58 +633,8 @@ impl Perform for Oper<EditPost> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if moderators.contains(&user_id) {
|
// Send apub update
|
||||||
// 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??;
|
|
||||||
}
|
|
||||||
|
|
||||||
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??;
|
|
||||||
}
|
|
||||||
|
|
||||||
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??;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
updated_post.send_update(&user, &self.client, pool).await?;
|
updated_post.send_update(&user, &self.client, pool).await?;
|
||||||
}
|
|
||||||
|
|
||||||
let edit_id = data.edit_id;
|
let edit_id = data.edit_id;
|
||||||
let post_view = blocking(pool, move |conn| {
|
let post_view = blocking(pool, move |conn| {
|
||||||
|
@ -729,6 +656,342 @@ impl Perform for Oper<EditPost> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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_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))
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
let res = PostResponse { post: post_view };
|
||||||
|
|
||||||
|
if let Some(ws) = websocket_info {
|
||||||
|
ws.chatserver.do_send(SendPost {
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for Oper<SavePost> {
|
impl Perform for Oper<SavePost> {
|
||||||
type Response = PostResponse;
|
type Response = PostResponse;
|
||||||
|
|
|
@ -73,6 +73,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
.wrap(rate_limit.message())
|
.wrap(rate_limit.message())
|
||||||
.route("", web::get().to(route_get::<GetPost>))
|
.route("", web::get().to(route_get::<GetPost>))
|
||||||
.route("", web::put().to(route_post::<EditPost>))
|
.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("/list", web::get().to(route_get::<GetPosts>))
|
||||||
.route("/like", web::post().to(route_post::<CreatePostLike>))
|
.route("/like", web::post().to(route_post::<CreatePostLike>))
|
||||||
.route("/save", web::put().to(route_post::<SavePost>)),
|
.route("/save", web::put().to(route_post::<SavePost>)),
|
||||||
|
|
|
@ -36,6 +36,10 @@ pub enum UserOperation {
|
||||||
GetPosts,
|
GetPosts,
|
||||||
CreatePostLike,
|
CreatePostLike,
|
||||||
EditPost,
|
EditPost,
|
||||||
|
DeletePost,
|
||||||
|
RemovePost,
|
||||||
|
LockPost,
|
||||||
|
StickyPost,
|
||||||
SavePost,
|
SavePost,
|
||||||
EditCommunity,
|
EditCommunity,
|
||||||
DeleteCommunity,
|
DeleteCommunity,
|
||||||
|
|
|
@ -500,6 +500,10 @@ impl ChatServer {
|
||||||
UserOperation::GetPost => do_user_operation::<GetPost>(args).await,
|
UserOperation::GetPost => do_user_operation::<GetPost>(args).await,
|
||||||
UserOperation::GetPosts => do_user_operation::<GetPosts>(args).await,
|
UserOperation::GetPosts => do_user_operation::<GetPosts>(args).await,
|
||||||
UserOperation::EditPost => do_user_operation::<EditPost>(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::CreatePostLike => do_user_operation::<CreatePostLike>(args).await,
|
||||||
UserOperation::SavePost => do_user_operation::<SavePost>(args).await,
|
UserOperation::SavePost => do_user_operation::<SavePost>(args).await,
|
||||||
|
|
||||||
|
|
68
ui/src/api_tests/api.spec.ts
vendored
68
ui/src/api_tests/api.spec.ts
vendored
|
@ -4,6 +4,9 @@ import {
|
||||||
LoginForm,
|
LoginForm,
|
||||||
LoginResponse,
|
LoginResponse,
|
||||||
PostForm,
|
PostForm,
|
||||||
|
DeletePostForm,
|
||||||
|
RemovePostForm,
|
||||||
|
// TODO need to test LockPost and StickyPost federated
|
||||||
PostResponse,
|
PostResponse,
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
FollowCommunityForm,
|
FollowCommunityForm,
|
||||||
|
@ -100,7 +103,6 @@ describe('main', () => {
|
||||||
name,
|
name,
|
||||||
auth: lemmyAlphaAuth,
|
auth: lemmyAlphaAuth,
|
||||||
community_id: 2,
|
community_id: 2,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,7 +271,6 @@ describe('main', () => {
|
||||||
name,
|
name,
|
||||||
auth: lemmyAlphaAuth,
|
auth: lemmyAlphaAuth,
|
||||||
community_id: 3,
|
community_id: 3,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,7 +327,6 @@ describe('main', () => {
|
||||||
edit_id: 2,
|
edit_id: 2,
|
||||||
auth: lemmyAlphaAuth,
|
auth: lemmyAlphaAuth,
|
||||||
community_id: 3,
|
community_id: 3,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -587,7 +587,6 @@ describe('main', () => {
|
||||||
name: postName,
|
name: postName,
|
||||||
auth: lemmyBetaAuth,
|
auth: lemmyBetaAuth,
|
||||||
community_id: createCommunityRes.community.id,
|
community_id: createCommunityRes.community.id,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -673,23 +672,22 @@ describe('main', () => {
|
||||||
expect(getPostUndeleteRes.comments[0].deleted).toBe(false);
|
expect(getPostUndeleteRes.comments[0].deleted).toBe(false);
|
||||||
|
|
||||||
// lemmy_beta deletes the post
|
// lemmy_beta deletes the post
|
||||||
let deletePostForm: PostForm = {
|
let deletePostForm: DeletePostForm = {
|
||||||
name: postName,
|
|
||||||
edit_id: createPostRes.post.id,
|
edit_id: createPostRes.post.id,
|
||||||
auth: lemmyBetaAuth,
|
|
||||||
community_id: createPostRes.post.community_id,
|
|
||||||
creator_id: createPostRes.post.creator_id,
|
|
||||||
nsfw: false,
|
|
||||||
deleted: true,
|
deleted: true,
|
||||||
|
auth: lemmyBetaAuth,
|
||||||
};
|
};
|
||||||
|
|
||||||
let deletePostRes: PostResponse = await fetch(`${lemmyBetaApiUrl}/post`, {
|
let deletePostRes: PostResponse = await fetch(
|
||||||
method: 'PUT',
|
`${lemmyBetaApiUrl}/post/delete`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: wrapper(deletePostForm),
|
body: wrapper(deletePostForm),
|
||||||
}).then(d => d.json());
|
}
|
||||||
|
).then(d => d.json());
|
||||||
expect(deletePostRes.post.deleted).toBe(true);
|
expect(deletePostRes.post.deleted).toBe(true);
|
||||||
|
|
||||||
// Make sure lemmy_alpha sees the post is deleted
|
// Make sure lemmy_alpha sees the post is deleted
|
||||||
|
@ -699,20 +697,16 @@ describe('main', () => {
|
||||||
expect(getPostResAgain.post.deleted).toBe(true);
|
expect(getPostResAgain.post.deleted).toBe(true);
|
||||||
|
|
||||||
// lemmy_beta undeletes the post
|
// lemmy_beta undeletes the post
|
||||||
let undeletePostForm: PostForm = {
|
let undeletePostForm: DeletePostForm = {
|
||||||
name: postName,
|
|
||||||
edit_id: createPostRes.post.id,
|
edit_id: createPostRes.post.id,
|
||||||
auth: lemmyBetaAuth,
|
|
||||||
community_id: createPostRes.post.community_id,
|
|
||||||
creator_id: createPostRes.post.creator_id,
|
|
||||||
nsfw: false,
|
|
||||||
deleted: false,
|
deleted: false,
|
||||||
|
auth: lemmyBetaAuth,
|
||||||
};
|
};
|
||||||
|
|
||||||
let undeletePostRes: PostResponse = await fetch(
|
let undeletePostRes: PostResponse = await fetch(
|
||||||
`${lemmyBetaApiUrl}/post`,
|
`${lemmyBetaApiUrl}/post/delete`,
|
||||||
{
|
{
|
||||||
method: 'PUT',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
|
@ -849,7 +843,6 @@ describe('main', () => {
|
||||||
name: postName,
|
name: postName,
|
||||||
auth: lemmyBetaAuth,
|
auth: lemmyBetaAuth,
|
||||||
community_id: createCommunityRes.community.id,
|
community_id: createCommunityRes.community.id,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -935,23 +928,22 @@ describe('main', () => {
|
||||||
expect(getPostUnremoveRes.comments[0].removed).toBe(false);
|
expect(getPostUnremoveRes.comments[0].removed).toBe(false);
|
||||||
|
|
||||||
// lemmy_beta deletes the post
|
// lemmy_beta deletes the post
|
||||||
let removePostForm: PostForm = {
|
let removePostForm: RemovePostForm = {
|
||||||
name: postName,
|
|
||||||
edit_id: createPostRes.post.id,
|
edit_id: createPostRes.post.id,
|
||||||
auth: lemmyBetaAuth,
|
|
||||||
community_id: createPostRes.post.community_id,
|
|
||||||
creator_id: createPostRes.post.creator_id,
|
|
||||||
nsfw: false,
|
|
||||||
removed: true,
|
removed: true,
|
||||||
|
auth: lemmyBetaAuth,
|
||||||
};
|
};
|
||||||
|
|
||||||
let removePostRes: PostResponse = await fetch(`${lemmyBetaApiUrl}/post`, {
|
let removePostRes: PostResponse = await fetch(
|
||||||
method: 'PUT',
|
`${lemmyBetaApiUrl}/post/remove`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: wrapper(removePostForm),
|
body: wrapper(removePostForm),
|
||||||
}).then(d => d.json());
|
}
|
||||||
|
).then(d => d.json());
|
||||||
expect(removePostRes.post.removed).toBe(true);
|
expect(removePostRes.post.removed).toBe(true);
|
||||||
|
|
||||||
// Make sure lemmy_alpha sees the post is deleted
|
// Make sure lemmy_alpha sees the post is deleted
|
||||||
|
@ -961,20 +953,16 @@ describe('main', () => {
|
||||||
expect(getPostResAgain.post.removed).toBe(true);
|
expect(getPostResAgain.post.removed).toBe(true);
|
||||||
|
|
||||||
// lemmy_beta unremoves the post
|
// lemmy_beta unremoves the post
|
||||||
let unremovePostForm: PostForm = {
|
let unremovePostForm: RemovePostForm = {
|
||||||
name: postName,
|
|
||||||
edit_id: createPostRes.post.id,
|
edit_id: createPostRes.post.id,
|
||||||
auth: lemmyBetaAuth,
|
|
||||||
community_id: createPostRes.post.community_id,
|
|
||||||
creator_id: createPostRes.post.creator_id,
|
|
||||||
nsfw: false,
|
|
||||||
removed: false,
|
removed: false,
|
||||||
|
auth: lemmyBetaAuth,
|
||||||
};
|
};
|
||||||
|
|
||||||
let unremovePostRes: PostResponse = await fetch(
|
let unremovePostRes: PostResponse = await fetch(
|
||||||
`${lemmyBetaApiUrl}/post`,
|
`${lemmyBetaApiUrl}/post/remove`,
|
||||||
{
|
{
|
||||||
method: 'PUT',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
|
@ -1226,7 +1214,6 @@ describe('main', () => {
|
||||||
name: postName,
|
name: postName,
|
||||||
auth: lemmyAlphaAuth,
|
auth: lemmyAlphaAuth,
|
||||||
community_id: 2,
|
community_id: 2,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1337,7 +1324,6 @@ describe('main', () => {
|
||||||
name: betaPostName,
|
name: betaPostName,
|
||||||
auth: lemmyBetaAuth,
|
auth: lemmyBetaAuth,
|
||||||
community_id: 2,
|
community_id: 2,
|
||||||
creator_id: 2,
|
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
8
ui/src/components/community.tsx
vendored
8
ui/src/components/community.tsx
vendored
|
@ -380,7 +380,13 @@ export class Community extends Component<any, State> {
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
setupTippy();
|
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;
|
let data = res.data as PostResponse;
|
||||||
editPostFindRes(data, this.state.posts);
|
editPostFindRes(data, this.state.posts);
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
4
ui/src/components/post-form.tsx
vendored
4
ui/src/components/post-form.tsx
vendored
|
@ -71,9 +71,6 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
auth: null,
|
auth: null,
|
||||||
community_id: null,
|
community_id: null,
|
||||||
creator_id: UserService.Instance.user
|
|
||||||
? UserService.Instance.user.id
|
|
||||||
: null,
|
|
||||||
},
|
},
|
||||||
communities: [],
|
communities: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -99,7 +96,6 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
name: this.props.post.name,
|
name: this.props.post.name,
|
||||||
community_id: this.props.post.community_id,
|
community_id: this.props.post.community_id,
|
||||||
edit_id: this.props.post.id,
|
edit_id: this.props.post.id,
|
||||||
creator_id: this.props.post.creator_id,
|
|
||||||
url: this.props.post.url,
|
url: this.props.post.url,
|
||||||
nsfw: this.props.post.nsfw,
|
nsfw: this.props.post.nsfw,
|
||||||
auth: null,
|
auth: null,
|
||||||
|
|
40
ui/src/components/post-listing.tsx
vendored
40
ui/src/components/post-listing.tsx
vendored
|
@ -4,7 +4,10 @@ import { WebSocketService, UserService } from '../services';
|
||||||
import {
|
import {
|
||||||
Post,
|
Post,
|
||||||
CreatePostLikeForm,
|
CreatePostLikeForm,
|
||||||
PostForm as PostFormI,
|
DeletePostForm,
|
||||||
|
RemovePostForm,
|
||||||
|
LockPostForm,
|
||||||
|
StickyPostForm,
|
||||||
SavePostForm,
|
SavePostForm,
|
||||||
CommunityUser,
|
CommunityUser,
|
||||||
UserView,
|
UserView,
|
||||||
|
@ -33,7 +36,6 @@ import {
|
||||||
setupTippy,
|
setupTippy,
|
||||||
hostname,
|
hostname,
|
||||||
previewLines,
|
previewLines,
|
||||||
toast,
|
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { i18n } from '../i18next';
|
import { i18n } from '../i18next';
|
||||||
|
|
||||||
|
@ -1114,18 +1116,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteClick(i: PostListing) {
|
handleDeleteClick(i: PostListing) {
|
||||||
let deleteForm: PostFormI = {
|
let deleteForm: DeletePostForm = {
|
||||||
body: i.props.post.body,
|
|
||||||
community_id: i.props.post.community_id,
|
|
||||||
name: i.props.post.name,
|
|
||||||
url: i.props.post.url,
|
|
||||||
edit_id: i.props.post.id,
|
edit_id: i.props.post.id,
|
||||||
creator_id: i.props.post.creator_id,
|
|
||||||
deleted: !i.props.post.deleted,
|
deleted: !i.props.post.deleted,
|
||||||
nsfw: i.props.post.nsfw,
|
|
||||||
auth: null,
|
auth: null,
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.editPost(deleteForm);
|
WebSocketService.Instance.deletePost(deleteForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSavePostClick(i: PostListing) {
|
handleSavePostClick(i: PostListing) {
|
||||||
|
@ -1163,46 +1159,34 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
|
|
||||||
handleModRemoveSubmit(i: PostListing) {
|
handleModRemoveSubmit(i: PostListing) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let form: PostFormI = {
|
let form: RemovePostForm = {
|
||||||
name: i.props.post.name,
|
|
||||||
community_id: i.props.post.community_id,
|
|
||||||
edit_id: i.props.post.id,
|
edit_id: i.props.post.id,
|
||||||
creator_id: i.props.post.creator_id,
|
|
||||||
removed: !i.props.post.removed,
|
removed: !i.props.post.removed,
|
||||||
reason: i.state.removeReason,
|
reason: i.state.removeReason,
|
||||||
nsfw: i.props.post.nsfw,
|
|
||||||
auth: null,
|
auth: null,
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.editPost(form);
|
WebSocketService.Instance.removePost(form);
|
||||||
|
|
||||||
i.state.showRemoveDialog = false;
|
i.state.showRemoveDialog = false;
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModLock(i: PostListing) {
|
handleModLock(i: PostListing) {
|
||||||
let form: PostFormI = {
|
let form: LockPostForm = {
|
||||||
name: i.props.post.name,
|
|
||||||
community_id: i.props.post.community_id,
|
|
||||||
edit_id: i.props.post.id,
|
edit_id: i.props.post.id,
|
||||||
creator_id: i.props.post.creator_id,
|
|
||||||
nsfw: i.props.post.nsfw,
|
|
||||||
locked: !i.props.post.locked,
|
locked: !i.props.post.locked,
|
||||||
auth: null,
|
auth: null,
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.editPost(form);
|
WebSocketService.Instance.lockPost(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModSticky(i: PostListing) {
|
handleModSticky(i: PostListing) {
|
||||||
let form: PostFormI = {
|
let form: StickyPostForm = {
|
||||||
name: i.props.post.name,
|
|
||||||
community_id: i.props.post.community_id,
|
|
||||||
edit_id: i.props.post.id,
|
edit_id: i.props.post.id,
|
||||||
creator_id: i.props.post.creator_id,
|
|
||||||
nsfw: i.props.post.nsfw,
|
|
||||||
stickied: !i.props.post.stickied,
|
stickied: !i.props.post.stickied,
|
||||||
auth: null,
|
auth: null,
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.editPost(form);
|
WebSocketService.Instance.stickyPost(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModBanFromCommunityShow(i: PostListing) {
|
handleModBanFromCommunityShow(i: PostListing) {
|
||||||
|
|
8
ui/src/components/post.tsx
vendored
8
ui/src/components/post.tsx
vendored
|
@ -452,7 +452,13 @@ export class Post extends Component<any, PostState> {
|
||||||
let data = res.data as PostResponse;
|
let data = res.data as PostResponse;
|
||||||
createPostLikeRes(data, this.state.post);
|
createPostLikeRes(data, this.state.post);
|
||||||
this.setState(this.state);
|
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;
|
let data = res.data as PostResponse;
|
||||||
this.state.post = data.post;
|
this.state.post = data.post;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
40
ui/src/interfaces.ts
vendored
40
ui/src/interfaces.ts
vendored
|
@ -17,6 +17,10 @@ export enum UserOperation {
|
||||||
GetPosts,
|
GetPosts,
|
||||||
CreatePostLike,
|
CreatePostLike,
|
||||||
EditPost,
|
EditPost,
|
||||||
|
DeletePost,
|
||||||
|
RemovePost,
|
||||||
|
LockPost,
|
||||||
|
StickyPost,
|
||||||
SavePost,
|
SavePost,
|
||||||
EditCommunity,
|
EditCommunity,
|
||||||
DeleteCommunity,
|
DeleteCommunity,
|
||||||
|
@ -636,19 +640,37 @@ export interface PostForm {
|
||||||
name: string;
|
name: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
body?: string;
|
body?: string;
|
||||||
community_id: number;
|
community_id?: number;
|
||||||
updated?: number;
|
|
||||||
edit_id?: number;
|
edit_id?: number;
|
||||||
creator_id: number;
|
|
||||||
removed?: boolean;
|
|
||||||
deleted?: boolean;
|
|
||||||
nsfw: boolean;
|
nsfw: boolean;
|
||||||
locked?: boolean;
|
auth: string;
|
||||||
stickied?: boolean;
|
}
|
||||||
|
|
||||||
|
export interface DeletePostForm {
|
||||||
|
edit_id: number;
|
||||||
|
deleted: boolean;
|
||||||
|
auth: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RemovePostForm {
|
||||||
|
edit_id: number;
|
||||||
|
removed: boolean;
|
||||||
reason?: string;
|
reason?: string;
|
||||||
auth: 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 {
|
export interface PostFormParams {
|
||||||
name: string;
|
name: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
@ -914,6 +936,10 @@ export type MessageType =
|
||||||
| ListCommunitiesForm
|
| ListCommunitiesForm
|
||||||
| GetFollowedCommunitiesForm
|
| GetFollowedCommunitiesForm
|
||||||
| PostForm
|
| PostForm
|
||||||
|
| DeletePostForm
|
||||||
|
| RemovePostForm
|
||||||
|
| LockPostForm
|
||||||
|
| StickyPostForm
|
||||||
| GetPostForm
|
| GetPostForm
|
||||||
| GetPostsForm
|
| GetPostsForm
|
||||||
| GetCommunityForm
|
| GetCommunityForm
|
||||||
|
|
36
ui/src/services/WebSocketService.ts
vendored
36
ui/src/services/WebSocketService.ts
vendored
|
@ -7,6 +7,10 @@ import {
|
||||||
DeleteCommunityForm,
|
DeleteCommunityForm,
|
||||||
RemoveCommunityForm,
|
RemoveCommunityForm,
|
||||||
PostForm,
|
PostForm,
|
||||||
|
DeletePostForm,
|
||||||
|
RemovePostForm,
|
||||||
|
LockPostForm,
|
||||||
|
StickyPostForm,
|
||||||
SavePostForm,
|
SavePostForm,
|
||||||
CommentForm,
|
CommentForm,
|
||||||
DeleteCommentForm,
|
DeleteCommentForm,
|
||||||
|
@ -153,9 +157,9 @@ export class WebSocketService {
|
||||||
this.ws.send(this.wsSendWrapper(UserOperation.ListCategories, {}));
|
this.ws.send(this.wsSendWrapper(UserOperation.ListCategories, {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public createPost(postForm: PostForm) {
|
public createPost(form: PostForm) {
|
||||||
this.setAuth(postForm);
|
this.setAuth(form);
|
||||||
this.ws.send(this.wsSendWrapper(UserOperation.CreatePost, postForm));
|
this.ws.send(this.wsSendWrapper(UserOperation.CreatePost, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPost(form: GetPostForm) {
|
public getPost(form: GetPostForm) {
|
||||||
|
@ -218,9 +222,29 @@ export class WebSocketService {
|
||||||
this.ws.send(this.wsSendWrapper(UserOperation.CreatePostLike, form));
|
this.ws.send(this.wsSendWrapper(UserOperation.CreatePostLike, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
public editPost(postForm: PostForm) {
|
public editPost(form: PostForm) {
|
||||||
this.setAuth(postForm);
|
this.setAuth(form);
|
||||||
this.ws.send(this.wsSendWrapper(UserOperation.EditPost, postForm));
|
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) {
|
public savePost(form: SavePostForm) {
|
||||||
|
|
Loading…
Reference in a new issue