From 3f6b2be2cccedc4b743e8d80b84fde704980ea32 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sun, 8 Sep 2019 23:14:13 -0700 Subject: [PATCH] Adding stickied posts. - Fixes #245 --- .../down.sql | 50 +++++++ .../up.sql | 67 +++++++++ server/src/api/post.rs | 12 ++ server/src/api/site.rs | 9 ++ server/src/db/comment.rs | 1 + server/src/db/comment_view.rs | 1 + server/src/db/moderator.rs | 127 ++++++++++++------ server/src/db/moderator_views.rs | 59 ++++++++ server/src/db/post.rs | 4 + server/src/db/post_view.rs | 28 ++-- server/src/schema.rs | 14 ++ ui/src/components/modlog.tsx | 13 +- ui/src/components/post-listing.tsx | 19 +++ ui/src/interfaces.ts | 15 +++ ui/src/translations/en.ts | 3 + 15 files changed, 371 insertions(+), 51 deletions(-) create mode 100644 server/migrations/2019-09-09-042010_add_stickied_posts/down.sql create mode 100644 server/migrations/2019-09-09-042010_add_stickied_posts/up.sql diff --git a/server/migrations/2019-09-09-042010_add_stickied_posts/down.sql b/server/migrations/2019-09-09-042010_add_stickied_posts/down.sql new file mode 100644 index 000000000..fb8eac8fd --- /dev/null +++ b/server/migrations/2019-09-09-042010_add_stickied_posts/down.sql @@ -0,0 +1,50 @@ +drop view post_view; +drop view mod_sticky_post_view; +alter table post drop column stickied; + +drop table mod_sticky_post; + +create view post_view as +with all_post as +( + select + p.*, + (select u.banned from user_ u where p.creator_id = u.id) as banned, + (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, + (select name from user_ where p.creator_id = user_.id) as creator_name, + (select name from community where p.community_id = community.id) as community_name, + (select removed from community c where p.community_id = c.id) as community_removed, + (select deleted from community c where p.community_id = c.id) as community_deleted, + (select nsfw from community c where p.community_id = c.id) as community_nsfw, + (select count(*) from comment where comment.post_id = p.id) as number_of_comments, + coalesce(sum(pl.score), 0) as score, + count (case when pl.score = 1 then 1 else null end) as upvotes, + count (case when pl.score = -1 then 1 else null end) as downvotes, + hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank + from post p + left join post_like pl on p.id = pl.post_id + group by p.id +) + +select +ap.*, +u.id as user_id, +coalesce(pl.score, 0) as my_vote, +(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, +(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, +(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved +from user_ u +cross join all_post ap +left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id + +union all + +select +ap.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from all_post ap +; diff --git a/server/migrations/2019-09-09-042010_add_stickied_posts/up.sql b/server/migrations/2019-09-09-042010_add_stickied_posts/up.sql new file mode 100644 index 000000000..0848f86ca --- /dev/null +++ b/server/migrations/2019-09-09-042010_add_stickied_posts/up.sql @@ -0,0 +1,67 @@ +-- Add the column +alter table post add column stickied boolean default false not null; + +-- Add the mod table +create table mod_sticky_post ( + id serial primary key, + mod_user_id int references user_ on update cascade on delete cascade not null, + post_id int references post on update cascade on delete cascade not null, + stickied boolean default true, + when_ timestamp not null default now() +); + +-- Add mod view +create view mod_sticky_post_view as +select msp.*, +(select name from user_ u where msp.mod_user_id = u.id) as mod_user_name, +(select name from post p where msp.post_id = p.id) as post_name, +(select c.id from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_id, +(select c.name from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_name +from mod_sticky_post msp; + +-- Recreate the view +drop view post_view; +create view post_view as +with all_post as +( + select + p.*, + (select u.banned from user_ u where p.creator_id = u.id) as banned, + (select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community, + (select name from user_ where p.creator_id = user_.id) as creator_name, + (select name from community where p.community_id = community.id) as community_name, + (select removed from community c where p.community_id = c.id) as community_removed, + (select deleted from community c where p.community_id = c.id) as community_deleted, + (select nsfw from community c where p.community_id = c.id) as community_nsfw, + (select count(*) from comment where comment.post_id = p.id) as number_of_comments, + coalesce(sum(pl.score), 0) as score, + count (case when pl.score = 1 then 1 else null end) as upvotes, + count (case when pl.score = -1 then 1 else null end) as downvotes, + hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank + from post p + left join post_like pl on p.id = pl.post_id + group by p.id +) + +select +ap.*, +u.id as user_id, +coalesce(pl.score, 0) as my_vote, +(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed, +(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read, +(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved +from user_ u +cross join all_post ap +left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id + +union all + +select +ap.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from all_post ap +; diff --git a/server/src/api/post.rs b/server/src/api/post.rs index 5345b0e4e..d53d2064a 100644 --- a/server/src/api/post.rs +++ b/server/src/api/post.rs @@ -74,6 +74,7 @@ pub struct EditPost { deleted: Option, nsfw: bool, locked: Option, + stickied: Option, reason: Option, auth: String, } @@ -121,6 +122,7 @@ impl Perform for Oper { deleted: None, nsfw: data.nsfw, locked: None, + stickied: None, updated: None, }; @@ -365,6 +367,7 @@ impl Perform for Oper { deleted: data.deleted.to_owned(), nsfw: data.nsfw, locked: data.locked.to_owned(), + stickied: data.stickied.to_owned(), updated: Some(naive_now()), }; @@ -393,6 +396,15 @@ impl Perform for Oper { ModLockPost::create(&conn, &form)?; } + if let Some(stickied) = data.stickied.to_owned() { + let form = ModStickyPostForm { + mod_user_id: user_id, + post_id: data.edit_id, + stickied: Some(stickied), + }; + ModStickyPost::create(&conn, &form)?; + } + let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?; Ok(PostResponse { diff --git a/server/src/api/site.rs b/server/src/api/site.rs index bbc26dab3..b517568e6 100644 --- a/server/src/api/site.rs +++ b/server/src/api/site.rs @@ -43,6 +43,7 @@ pub struct GetModlogResponse { op: String, removed_posts: Vec, locked_posts: Vec, + stickied_posts: Vec, removed_comments: Vec, removed_communities: Vec, banned_from_community: Vec, @@ -122,6 +123,13 @@ impl Perform for Oper { data.page, data.limit, )?; + let stickied_posts = ModStickyPostView::list( + &conn, + data.community_id, + data.mod_user_id, + data.page, + data.limit, + )?; let removed_comments = ModRemoveCommentView::list( &conn, data.community_id, @@ -161,6 +169,7 @@ impl Perform for Oper { op: self.op.to_string(), removed_posts: removed_posts, locked_posts: locked_posts, + stickied_posts: stickied_posts, removed_comments: removed_comments, removed_communities: removed_communities, banned_from_community: banned_from_community, diff --git a/server/src/db/comment.rs b/server/src/db/comment.rs index ec00fab79..f62f8c536 100644 --- a/server/src/db/comment.rs +++ b/server/src/db/comment.rs @@ -205,6 +205,7 @@ mod tests { removed: None, deleted: None, locked: None, + stickied: None, updated: None, nsfw: false, }; diff --git a/server/src/db/comment_view.rs b/server/src/db/comment_view.rs index 81f7a6721..6c2e3f593 100644 --- a/server/src/db/comment_view.rs +++ b/server/src/db/comment_view.rs @@ -291,6 +291,7 @@ mod tests { removed: None, deleted: None, locked: None, + stickied: None, updated: None, nsfw: false, }; diff --git a/server/src/db/moderator.rs b/server/src/db/moderator.rs index d1e5cb725..117e3f553 100644 --- a/server/src/db/moderator.rs +++ b/server/src/db/moderator.rs @@ -1,7 +1,7 @@ use super::*; use crate::schema::{ mod_add, mod_add_community, mod_ban, mod_ban_from_community, mod_lock_post, mod_remove_comment, - mod_remove_community, mod_remove_post, + mod_remove_community, mod_remove_post, mod_sticky_post, }; #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] @@ -94,6 +94,50 @@ impl Crud for ModLockPost { } } +#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] +#[table_name = "mod_sticky_post"] +pub struct ModStickyPost { + pub id: i32, + pub mod_user_id: i32, + pub post_id: i32, + pub stickied: Option, + pub when_: chrono::NaiveDateTime, +} + +#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] +#[table_name = "mod_sticky_post"] +pub struct ModStickyPostForm { + pub mod_user_id: i32, + pub post_id: i32, + pub stickied: Option, +} + +impl Crud for ModStickyPost { + fn read(conn: &PgConnection, from_id: i32) -> Result { + use crate::schema::mod_sticky_post::dsl::*; + mod_sticky_post.find(from_id).first::(conn) + } + + fn delete(conn: &PgConnection, from_id: i32) -> Result { + use crate::schema::mod_sticky_post::dsl::*; + diesel::delete(mod_sticky_post.find(from_id)).execute(conn) + } + + fn create(conn: &PgConnection, form: &ModStickyPostForm) -> Result { + use crate::schema::mod_sticky_post::dsl::*; + insert_into(mod_sticky_post) + .values(form) + .get_result::(conn) + } + + fn update(conn: &PgConnection, from_id: i32, form: &ModStickyPostForm) -> Result { + use crate::schema::mod_sticky_post::dsl::*; + diesel::update(mod_sticky_post.find(from_id)) + .set(form) + .get_result::(conn) + } +} + #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[table_name = "mod_remove_comment"] pub struct ModRemoveComment { @@ -443,6 +487,7 @@ mod tests { removed: None, deleted: None, locked: None, + stickied: None, updated: None, nsfw: false, }; @@ -472,9 +517,8 @@ mod tests { removed: None, }; let inserted_mod_remove_post = ModRemovePost::create(&conn, &mod_remove_post_form).unwrap(); - let read_moderator_remove_post = - ModRemovePost::read(&conn, inserted_mod_remove_post.id).unwrap(); - let expected_moderator_remove_post = ModRemovePost { + let read_mod_remove_post = ModRemovePost::read(&conn, inserted_mod_remove_post.id).unwrap(); + let expected_mod_remove_post = ModRemovePost { id: inserted_mod_remove_post.id, post_id: inserted_post.id, mod_user_id: inserted_mod.id, @@ -491,8 +535,8 @@ mod tests { locked: None, }; let inserted_mod_lock_post = ModLockPost::create(&conn, &mod_lock_post_form).unwrap(); - let read_moderator_lock_post = ModLockPost::read(&conn, inserted_mod_lock_post.id).unwrap(); - let expected_moderator_lock_post = ModLockPost { + let read_mod_lock_post = ModLockPost::read(&conn, inserted_mod_lock_post.id).unwrap(); + let expected_mod_lock_post = ModLockPost { id: inserted_mod_lock_post.id, post_id: inserted_post.id, mod_user_id: inserted_mod.id, @@ -500,6 +544,23 @@ mod tests { when_: inserted_mod_lock_post.when_, }; + // sticky post + + let mod_sticky_post_form = ModStickyPostForm { + mod_user_id: inserted_mod.id, + post_id: inserted_post.id, + stickied: None, + }; + let inserted_mod_sticky_post = ModStickyPost::create(&conn, &mod_sticky_post_form).unwrap(); + let read_mod_sticky_post = ModStickyPost::read(&conn, inserted_mod_sticky_post.id).unwrap(); + let expected_mod_sticky_post = ModStickyPost { + id: inserted_mod_sticky_post.id, + post_id: inserted_post.id, + mod_user_id: inserted_mod.id, + stickied: Some(true), + when_: inserted_mod_sticky_post.when_, + }; + // comment let mod_remove_comment_form = ModRemoveCommentForm { @@ -510,9 +571,9 @@ mod tests { }; let inserted_mod_remove_comment = ModRemoveComment::create(&conn, &mod_remove_comment_form).unwrap(); - let read_moderator_remove_comment = + let read_mod_remove_comment = ModRemoveComment::read(&conn, inserted_mod_remove_comment.id).unwrap(); - let expected_moderator_remove_comment = ModRemoveComment { + let expected_mod_remove_comment = ModRemoveComment { id: inserted_mod_remove_comment.id, comment_id: inserted_comment.id, mod_user_id: inserted_mod.id, @@ -532,9 +593,9 @@ mod tests { }; let inserted_mod_remove_community = ModRemoveCommunity::create(&conn, &mod_remove_community_form).unwrap(); - let read_moderator_remove_community = + let read_mod_remove_community = ModRemoveCommunity::read(&conn, inserted_mod_remove_community.id).unwrap(); - let expected_moderator_remove_community = ModRemoveCommunity { + let expected_mod_remove_community = ModRemoveCommunity { id: inserted_mod_remove_community.id, community_id: inserted_community.id, mod_user_id: inserted_mod.id, @@ -556,9 +617,9 @@ mod tests { }; let inserted_mod_ban_from_community = ModBanFromCommunity::create(&conn, &mod_ban_from_community_form).unwrap(); - let read_moderator_ban_from_community = + let read_mod_ban_from_community = ModBanFromCommunity::read(&conn, inserted_mod_ban_from_community.id).unwrap(); - let expected_moderator_ban_from_community = ModBanFromCommunity { + let expected_mod_ban_from_community = ModBanFromCommunity { id: inserted_mod_ban_from_community.id, community_id: inserted_community.id, mod_user_id: inserted_mod.id, @@ -579,8 +640,8 @@ mod tests { expires: None, }; let inserted_mod_ban = ModBan::create(&conn, &mod_ban_form).unwrap(); - let read_moderator_ban = ModBan::read(&conn, inserted_mod_ban.id).unwrap(); - let expected_moderator_ban = ModBan { + let read_mod_ban = ModBan::read(&conn, inserted_mod_ban.id).unwrap(); + let expected_mod_ban = ModBan { id: inserted_mod_ban.id, mod_user_id: inserted_mod.id, other_user_id: inserted_user.id, @@ -600,9 +661,9 @@ mod tests { }; let inserted_mod_add_community = ModAddCommunity::create(&conn, &mod_add_community_form).unwrap(); - let read_moderator_add_community = + let read_mod_add_community = ModAddCommunity::read(&conn, inserted_mod_add_community.id).unwrap(); - let expected_moderator_add_community = ModAddCommunity { + let expected_mod_add_community = ModAddCommunity { id: inserted_mod_add_community.id, community_id: inserted_community.id, mod_user_id: inserted_mod.id, @@ -619,8 +680,8 @@ mod tests { removed: None, }; let inserted_mod_add = ModAdd::create(&conn, &mod_add_form).unwrap(); - let read_moderator_add = ModAdd::read(&conn, inserted_mod_add.id).unwrap(); - let expected_moderator_add = ModAdd { + let read_mod_add = ModAdd::read(&conn, inserted_mod_add.id).unwrap(); + let expected_mod_add = ModAdd { id: inserted_mod_add.id, mod_user_id: inserted_mod.id, other_user_id: inserted_user.id, @@ -630,6 +691,7 @@ mod tests { ModRemovePost::delete(&conn, inserted_mod_remove_post.id).unwrap(); ModLockPost::delete(&conn, inserted_mod_lock_post.id).unwrap(); + ModStickyPost::delete(&conn, inserted_mod_sticky_post.id).unwrap(); ModRemoveComment::delete(&conn, inserted_mod_remove_comment.id).unwrap(); ModRemoveCommunity::delete(&conn, inserted_mod_remove_community.id).unwrap(); ModBanFromCommunity::delete(&conn, inserted_mod_ban_from_community.id).unwrap(); @@ -643,25 +705,14 @@ mod tests { User_::delete(&conn, inserted_user.id).unwrap(); User_::delete(&conn, inserted_mod.id).unwrap(); - assert_eq!(expected_moderator_remove_post, read_moderator_remove_post); - assert_eq!(expected_moderator_lock_post, read_moderator_lock_post); - assert_eq!( - expected_moderator_remove_comment, - read_moderator_remove_comment - ); - assert_eq!( - expected_moderator_remove_community, - read_moderator_remove_community - ); - assert_eq!( - expected_moderator_ban_from_community, - read_moderator_ban_from_community - ); - assert_eq!(expected_moderator_ban, read_moderator_ban); - assert_eq!( - expected_moderator_add_community, - read_moderator_add_community - ); - assert_eq!(expected_moderator_add, read_moderator_add); + assert_eq!(expected_mod_remove_post, read_mod_remove_post); + assert_eq!(expected_mod_lock_post, read_mod_lock_post); + assert_eq!(expected_mod_sticky_post, read_mod_sticky_post); + assert_eq!(expected_mod_remove_comment, read_mod_remove_comment); + assert_eq!(expected_mod_remove_community, read_mod_remove_community); + assert_eq!(expected_mod_ban_from_community, read_mod_ban_from_community); + assert_eq!(expected_mod_ban, read_mod_ban); + assert_eq!(expected_mod_add_community, read_mod_add_community); + assert_eq!(expected_mod_add, read_mod_add); } } diff --git a/server/src/db/moderator_views.rs b/server/src/db/moderator_views.rs index b8143b504..0413e0b10 100644 --- a/server/src/db/moderator_views.rs +++ b/server/src/db/moderator_views.rs @@ -120,6 +120,65 @@ impl ModLockPostView { } } +table! { + mod_sticky_post_view (id) { + id -> Int4, + mod_user_id -> Int4, + post_id -> Int4, + stickied -> Nullable, + when_ -> Timestamp, + mod_user_name -> Varchar, + post_name -> Varchar, + community_id -> Int4, + community_name -> Varchar, + } +} + +#[derive( + Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone, +)] +#[table_name = "mod_sticky_post_view"] +pub struct ModStickyPostView { + pub id: i32, + pub mod_user_id: i32, + pub post_id: i32, + pub stickied: Option, + pub when_: chrono::NaiveDateTime, + pub mod_user_name: String, + pub post_name: String, + pub community_id: i32, + pub community_name: String, +} + +impl ModStickyPostView { + pub fn list( + conn: &PgConnection, + from_community_id: Option, + from_mod_user_id: Option, + page: Option, + limit: Option, + ) -> Result, Error> { + use super::moderator_views::mod_sticky_post_view::dsl::*; + let mut query = mod_sticky_post_view.into_boxed(); + + let (limit, offset) = limit_and_offset(page, limit); + + if let Some(from_community_id) = from_community_id { + query = query.filter(community_id.eq(from_community_id)); + }; + + if let Some(from_mod_user_id) = from_mod_user_id { + query = query.filter(mod_user_id.eq(from_mod_user_id)); + }; + + query + .limit(limit) + .offset(offset) + .order_by(when_.desc()) + .load::(conn) + } +} + table! { mod_remove_comment_view (id) { id -> Int4, diff --git a/server/src/db/post.rs b/server/src/db/post.rs index 54cc236b5..2ae8bf68f 100644 --- a/server/src/db/post.rs +++ b/server/src/db/post.rs @@ -16,6 +16,7 @@ pub struct Post { pub updated: Option, pub deleted: bool, pub nsfw: bool, + pub stickied: bool, } #[derive(Insertable, AsChangeset, Clone)] @@ -31,6 +32,7 @@ pub struct PostForm { pub updated: Option, pub deleted: Option, pub nsfw: bool, + pub stickied: Option, } impl Crud for Post { @@ -216,6 +218,7 @@ mod tests { removed: None, deleted: None, locked: None, + stickied: None, nsfw: false, updated: None, }; @@ -232,6 +235,7 @@ mod tests { published: inserted_post.published, removed: false, locked: false, + stickied: false, nsfw: false, deleted: false, updated: None, diff --git a/server/src/db/post_view.rs b/server/src/db/post_view.rs index 2008d16f1..6d06ce8ec 100644 --- a/server/src/db/post_view.rs +++ b/server/src/db/post_view.rs @@ -24,6 +24,7 @@ table! { nsfw -> Bool, banned -> Bool, banned_from_community -> Bool, + stickied -> Bool, creator_name -> Varchar, community_name -> Varchar, community_removed -> Bool, @@ -61,6 +62,7 @@ pub struct PostView { pub nsfw: bool, pub banned: bool, pub banned_from_community: bool, + pub stickied: bool, pub creator_name: String, pub community_name: String, pub community_removed: bool, @@ -100,10 +102,6 @@ impl PostView { let mut query = post_view.into_boxed(); - if let Some(for_community_id) = for_community_id { - query = query.filter(community_id.eq(for_community_id)); - }; - if let Some(for_creator_id) = for_creator_id { query = query.filter(creator_id.eq(for_creator_id)); }; @@ -116,6 +114,11 @@ impl PostView { query = query.filter(url.eq(url_search)); }; + if let Some(for_community_id) = for_community_id { + query = query.filter(community_id.eq(for_community_id)); + query = query.then_order_by(stickied.desc()); + }; + // TODO these are wrong, bc they'll only show saved for your logged in user, not theirs if saved_only { query = query.filter(saved.eq(true)); @@ -147,22 +150,22 @@ impl PostView { query = match sort { SortType::Hot => query - .order_by(hot_rank.desc()) + .then_order_by(hot_rank.desc()) .then_order_by(published.desc()), - SortType::New => query.order_by(published.desc()), - SortType::TopAll => query.order_by(score.desc()), + SortType::New => query.then_order_by(published.desc()), + SortType::TopAll => query.then_order_by(score.desc()), SortType::TopYear => query .filter(published.gt(now - 1.years())) - .order_by(score.desc()), + .then_order_by(score.desc()), SortType::TopMonth => query .filter(published.gt(now - 1.months())) - .order_by(score.desc()), + .then_order_by(score.desc()), SortType::TopWeek => query .filter(published.gt(now - 1.weeks())) - .order_by(score.desc()), + .then_order_by(score.desc()), SortType::TopDay => query .filter(published.gt(now - 1.days())) - .order_by(score.desc()), + .then_order_by(score.desc()), }; query = query @@ -249,6 +252,7 @@ mod tests { removed: None, deleted: None, locked: None, + stickied: None, updated: None, nsfw: false, }; @@ -293,6 +297,7 @@ mod tests { removed: false, deleted: false, locked: false, + stickied: false, community_name: community_name.to_owned(), community_removed: false, community_deleted: false, @@ -320,6 +325,7 @@ mod tests { removed: false, deleted: false, locked: false, + stickied: false, creator_id: inserted_user.id, creator_name: user_name.to_owned(), banned: false, diff --git a/server/src/schema.rs b/server/src/schema.rs index 2ea774ca0..0e1a33ef6 100644 --- a/server/src/schema.rs +++ b/server/src/schema.rs @@ -173,6 +173,16 @@ table! { } } +table! { + mod_sticky_post (id) { + id -> Int4, + mod_user_id -> Int4, + post_id -> Int4, + stickied -> Nullable, + when_ -> Timestamp, + } +} + table! { post (id) { id -> Int4, @@ -187,6 +197,7 @@ table! { updated -> Nullable, deleted -> Bool, nsfw -> Bool, + stickied -> Bool, } } @@ -279,6 +290,8 @@ joinable!(mod_remove_community -> community (community_id)); joinable!(mod_remove_community -> user_ (mod_user_id)); joinable!(mod_remove_post -> post (post_id)); joinable!(mod_remove_post -> user_ (mod_user_id)); +joinable!(mod_sticky_post -> post (post_id)); +joinable!(mod_sticky_post -> user_ (mod_user_id)); joinable!(post -> community (community_id)); joinable!(post -> user_ (creator_id)); joinable!(post_like -> post (post_id)); @@ -307,6 +320,7 @@ allow_tables_to_appear_in_same_query!( mod_remove_comment, mod_remove_community, mod_remove_post, + mod_sticky_post, post, post_like, post_read, diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx index ba1fe5a21..3af122a8e 100644 --- a/ui/src/components/modlog.tsx +++ b/ui/src/components/modlog.tsx @@ -2,14 +2,15 @@ import { Component, linkEvent } from 'inferno'; import { Link } from 'inferno-router'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, GetModlogForm, GetModlogResponse, ModRemovePost, ModLockPost, ModRemoveComment, ModRemoveCommunity, ModBanFromCommunity, ModBan, ModAddCommunity, ModAdd } from '../interfaces'; +import { UserOperation, GetModlogForm, GetModlogResponse, ModRemovePost, ModLockPost, ModStickyPost, ModRemoveComment, ModRemoveCommunity, ModBanFromCommunity, ModBan, ModAddCommunity, ModAdd } from '../interfaces'; import { WebSocketService } from '../services'; import { msgOp, addTypeInfo, fetchLimit } from '../utils'; import { MomentTime } from './moment-time'; import * as moment from 'moment'; +import { i18n } from '../i18next'; interface ModlogState { - combined: Array<{type_: string, data: ModRemovePost | ModLockPost | ModRemoveCommunity | ModAdd | ModBan}>, + combined: Array<{type_: string, data: ModRemovePost | ModLockPost | ModStickyPost | ModRemoveCommunity | ModAdd | ModBan}>, communityId?: number, communityName?: string, page: number; @@ -51,6 +52,7 @@ export class Modlog extends Component { setCombined(res: GetModlogResponse) { let removed_posts = addTypeInfo(res.removed_posts, "removed_posts"); let locked_posts = addTypeInfo(res.locked_posts, "locked_posts"); + let stickied_posts = addTypeInfo(res.stickied_posts, "stickied_posts"); let removed_comments = addTypeInfo(res.removed_comments, "removed_comments"); let removed_communities = addTypeInfo(res.removed_communities, "removed_communities"); let banned_from_community = addTypeInfo(res.banned_from_community, "banned_from_community"); @@ -61,6 +63,7 @@ export class Modlog extends Component { this.state.combined.push(...removed_posts); this.state.combined.push(...locked_posts); + this.state.combined.push(...stickied_posts); this.state.combined.push(...removed_comments); this.state.combined.push(...removed_communities); this.state.combined.push(...banned_from_community); @@ -99,6 +102,12 @@ export class Modlog extends Component { Post {(i.data as ModLockPost).post_name} } + {i.type_ == 'stickied_posts' && + <> + {(i.data as ModStickyPost).stickied? 'Stickied' : 'Unstickied'} + Post {(i.data as ModStickyPost).post_name} + + } {i.type_ == 'removed_comments' && <> {(i.data as ModRemoveComment).removed? 'Removed' : 'Restored'} diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 8234cc8a6..94cbef106 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -129,6 +129,9 @@ export class PostListing extends Component { {post.locked && # } + {post.stickied && + # + } {post.nsfw && # } @@ -202,6 +205,9 @@ export class PostListing extends Component {
  • {post.locked ? i18n.t('unlock') : i18n.t('lock')}
  • +
  • + {post.stickied ? i18n.t('unsticky') : i18n.t('sticky')} +
  • } {/* Mods can ban from community, and appoint as mods to community */} @@ -459,6 +465,19 @@ export class PostListing extends Component { WebSocketService.Instance.editPost(form); } + handleModSticky(i: PostListing) { + let form: PostFormI = { + name: i.props.post.name, + community_id: i.props.post.community_id, + 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); + } + handleModBanFromCommunityShow(i: PostListing) { i.state.showBanDialog = true; i.state.banType = BanType.Community; diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index f2675eb30..8c78d7d89 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -77,6 +77,7 @@ export interface Post { removed: boolean; deleted: boolean; locked: boolean; + stickied: boolean; nsfw: boolean; banned: boolean; banned_from_community: boolean; @@ -235,6 +236,7 @@ export interface GetModlogResponse { op: string; removed_posts: Array, locked_posts: Array, + stickied_posts: Array, removed_comments: Array, removed_communities: Array, banned_from_community: Array, @@ -268,6 +270,18 @@ export interface ModLockPost { community_name: string, } +export interface ModStickyPost { + id: number, + mod_user_id: number, + post_id: number, + stickied?: boolean, + when_: string, + mod_user_name: string, + post_name: string, + community_id: number, + community_name: string, +} + export interface ModRemoveComment { id: number, mod_user_id: number, @@ -425,6 +439,7 @@ export interface PostForm { deleted?: boolean; nsfw: boolean; locked?: boolean; + stickied?: boolean; reason?: string; auth: string; } diff --git a/ui/src/translations/en.ts b/ui/src/translations/en.ts index f89a98793..5ec036713 100644 --- a/ui/src/translations/en.ts +++ b/ui/src/translations/en.ts @@ -32,6 +32,8 @@ export const en = { view_source: 'view source', unlock: 'unlock', lock: 'lock', + sticky: 'sticky', + unsticky: 'unsticky', link: 'link', mod: 'mod', mods: 'mods', @@ -47,6 +49,7 @@ export const en = { remove: 'remove', removed: 'removed', locked: 'locked', + stickied: 'stickied', reason: 'Reason', mark_as_read: 'mark as read', mark_as_unread: 'mark as unread',