Adding stickied posts.

- Fixes #245
This commit is contained in:
Dessalines 2019-09-08 23:14:13 -07:00
parent 0dfe703a34
commit 21d55af62d
15 changed files with 371 additions and 51 deletions

View file

@ -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
;

View file

@ -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
;

View file

@ -74,6 +74,7 @@ pub struct EditPost {
deleted: Option<bool>, deleted: Option<bool>,
nsfw: bool, nsfw: bool,
locked: Option<bool>, locked: Option<bool>,
stickied: Option<bool>,
reason: Option<String>, reason: Option<String>,
auth: String, auth: String,
} }
@ -121,6 +122,7 @@ impl Perform<PostResponse> for Oper<CreatePost> {
deleted: None, deleted: None,
nsfw: data.nsfw, nsfw: data.nsfw,
locked: None, locked: None,
stickied: None,
updated: None, updated: None,
}; };
@ -365,6 +367,7 @@ impl Perform<PostResponse> for Oper<EditPost> {
deleted: data.deleted.to_owned(), deleted: data.deleted.to_owned(),
nsfw: data.nsfw, nsfw: data.nsfw,
locked: data.locked.to_owned(), locked: data.locked.to_owned(),
stickied: data.stickied.to_owned(),
updated: Some(naive_now()), updated: Some(naive_now()),
}; };
@ -393,6 +396,15 @@ impl Perform<PostResponse> for Oper<EditPost> {
ModLockPost::create(&conn, &form)?; 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))?; let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
Ok(PostResponse { Ok(PostResponse {

View file

@ -43,6 +43,7 @@ pub struct GetModlogResponse {
op: String, op: String,
removed_posts: Vec<ModRemovePostView>, removed_posts: Vec<ModRemovePostView>,
locked_posts: Vec<ModLockPostView>, locked_posts: Vec<ModLockPostView>,
stickied_posts: Vec<ModStickyPostView>,
removed_comments: Vec<ModRemoveCommentView>, removed_comments: Vec<ModRemoveCommentView>,
removed_communities: Vec<ModRemoveCommunityView>, removed_communities: Vec<ModRemoveCommunityView>,
banned_from_community: Vec<ModBanFromCommunityView>, banned_from_community: Vec<ModBanFromCommunityView>,
@ -122,6 +123,13 @@ impl Perform<GetModlogResponse> for Oper<GetModlog> {
data.page, data.page,
data.limit, data.limit,
)?; )?;
let stickied_posts = ModStickyPostView::list(
&conn,
data.community_id,
data.mod_user_id,
data.page,
data.limit,
)?;
let removed_comments = ModRemoveCommentView::list( let removed_comments = ModRemoveCommentView::list(
&conn, &conn,
data.community_id, data.community_id,
@ -161,6 +169,7 @@ impl Perform<GetModlogResponse> for Oper<GetModlog> {
op: self.op.to_string(), op: self.op.to_string(),
removed_posts: removed_posts, removed_posts: removed_posts,
locked_posts: locked_posts, locked_posts: locked_posts,
stickied_posts: stickied_posts,
removed_comments: removed_comments, removed_comments: removed_comments,
removed_communities: removed_communities, removed_communities: removed_communities,
banned_from_community: banned_from_community, banned_from_community: banned_from_community,

View file

@ -205,6 +205,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
locked: None, locked: None,
stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
}; };

View file

@ -291,6 +291,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
locked: None, locked: None,
stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
}; };

View file

@ -1,7 +1,7 @@
use super::*; use super::*;
use crate::schema::{ use crate::schema::{
mod_add, mod_add_community, mod_ban, mod_ban_from_community, mod_lock_post, mod_remove_comment, 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)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
@ -94,6 +94,50 @@ impl Crud<ModLockPostForm> 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<bool>,
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<bool>,
}
impl Crud<ModStickyPostForm> for ModStickyPost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_sticky_post::dsl::*;
mod_sticky_post.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_sticky_post::dsl::*;
diesel::delete(mod_sticky_post.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModStickyPostForm) -> Result<Self, Error> {
use crate::schema::mod_sticky_post::dsl::*;
insert_into(mod_sticky_post)
.values(form)
.get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModStickyPostForm) -> Result<Self, Error> {
use crate::schema::mod_sticky_post::dsl::*;
diesel::update(mod_sticky_post.find(from_id))
.set(form)
.get_result::<Self>(conn)
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "mod_remove_comment"] #[table_name = "mod_remove_comment"]
pub struct ModRemoveComment { pub struct ModRemoveComment {
@ -443,6 +487,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
locked: None, locked: None,
stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
}; };
@ -472,9 +517,8 @@ mod tests {
removed: None, removed: None,
}; };
let inserted_mod_remove_post = ModRemovePost::create(&conn, &mod_remove_post_form).unwrap(); let inserted_mod_remove_post = ModRemovePost::create(&conn, &mod_remove_post_form).unwrap();
let read_moderator_remove_post = let read_mod_remove_post = ModRemovePost::read(&conn, inserted_mod_remove_post.id).unwrap();
ModRemovePost::read(&conn, inserted_mod_remove_post.id).unwrap(); let expected_mod_remove_post = ModRemovePost {
let expected_moderator_remove_post = ModRemovePost {
id: inserted_mod_remove_post.id, id: inserted_mod_remove_post.id,
post_id: inserted_post.id, post_id: inserted_post.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
@ -491,8 +535,8 @@ mod tests {
locked: None, locked: None,
}; };
let inserted_mod_lock_post = ModLockPost::create(&conn, &mod_lock_post_form).unwrap(); 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 read_mod_lock_post = ModLockPost::read(&conn, inserted_mod_lock_post.id).unwrap();
let expected_moderator_lock_post = ModLockPost { let expected_mod_lock_post = ModLockPost {
id: inserted_mod_lock_post.id, id: inserted_mod_lock_post.id,
post_id: inserted_post.id, post_id: inserted_post.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
@ -500,6 +544,23 @@ mod tests {
when_: inserted_mod_lock_post.when_, 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 // comment
let mod_remove_comment_form = ModRemoveCommentForm { let mod_remove_comment_form = ModRemoveCommentForm {
@ -510,9 +571,9 @@ mod tests {
}; };
let inserted_mod_remove_comment = let inserted_mod_remove_comment =
ModRemoveComment::create(&conn, &mod_remove_comment_form).unwrap(); 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(); 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, id: inserted_mod_remove_comment.id,
comment_id: inserted_comment.id, comment_id: inserted_comment.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
@ -532,9 +593,9 @@ mod tests {
}; };
let inserted_mod_remove_community = let inserted_mod_remove_community =
ModRemoveCommunity::create(&conn, &mod_remove_community_form).unwrap(); 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(); 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, id: inserted_mod_remove_community.id,
community_id: inserted_community.id, community_id: inserted_community.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
@ -556,9 +617,9 @@ mod tests {
}; };
let inserted_mod_ban_from_community = let inserted_mod_ban_from_community =
ModBanFromCommunity::create(&conn, &mod_ban_from_community_form).unwrap(); 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(); 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, id: inserted_mod_ban_from_community.id,
community_id: inserted_community.id, community_id: inserted_community.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
@ -579,8 +640,8 @@ mod tests {
expires: None, expires: None,
}; };
let inserted_mod_ban = ModBan::create(&conn, &mod_ban_form).unwrap(); let inserted_mod_ban = ModBan::create(&conn, &mod_ban_form).unwrap();
let read_moderator_ban = ModBan::read(&conn, inserted_mod_ban.id).unwrap(); let read_mod_ban = ModBan::read(&conn, inserted_mod_ban.id).unwrap();
let expected_moderator_ban = ModBan { let expected_mod_ban = ModBan {
id: inserted_mod_ban.id, id: inserted_mod_ban.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
other_user_id: inserted_user.id, other_user_id: inserted_user.id,
@ -600,9 +661,9 @@ mod tests {
}; };
let inserted_mod_add_community = let inserted_mod_add_community =
ModAddCommunity::create(&conn, &mod_add_community_form).unwrap(); 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(); 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, id: inserted_mod_add_community.id,
community_id: inserted_community.id, community_id: inserted_community.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
@ -619,8 +680,8 @@ mod tests {
removed: None, removed: None,
}; };
let inserted_mod_add = ModAdd::create(&conn, &mod_add_form).unwrap(); let inserted_mod_add = ModAdd::create(&conn, &mod_add_form).unwrap();
let read_moderator_add = ModAdd::read(&conn, inserted_mod_add.id).unwrap(); let read_mod_add = ModAdd::read(&conn, inserted_mod_add.id).unwrap();
let expected_moderator_add = ModAdd { let expected_mod_add = ModAdd {
id: inserted_mod_add.id, id: inserted_mod_add.id,
mod_user_id: inserted_mod.id, mod_user_id: inserted_mod.id,
other_user_id: inserted_user.id, other_user_id: inserted_user.id,
@ -630,6 +691,7 @@ mod tests {
ModRemovePost::delete(&conn, inserted_mod_remove_post.id).unwrap(); ModRemovePost::delete(&conn, inserted_mod_remove_post.id).unwrap();
ModLockPost::delete(&conn, inserted_mod_lock_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(); ModRemoveComment::delete(&conn, inserted_mod_remove_comment.id).unwrap();
ModRemoveCommunity::delete(&conn, inserted_mod_remove_community.id).unwrap(); ModRemoveCommunity::delete(&conn, inserted_mod_remove_community.id).unwrap();
ModBanFromCommunity::delete(&conn, inserted_mod_ban_from_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_user.id).unwrap();
User_::delete(&conn, inserted_mod.id).unwrap(); User_::delete(&conn, inserted_mod.id).unwrap();
assert_eq!(expected_moderator_remove_post, read_moderator_remove_post); assert_eq!(expected_mod_remove_post, read_mod_remove_post);
assert_eq!(expected_moderator_lock_post, read_moderator_lock_post); assert_eq!(expected_mod_lock_post, read_mod_lock_post);
assert_eq!( assert_eq!(expected_mod_sticky_post, read_mod_sticky_post);
expected_moderator_remove_comment, assert_eq!(expected_mod_remove_comment, read_mod_remove_comment);
read_moderator_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!( assert_eq!(expected_mod_ban, read_mod_ban);
expected_moderator_remove_community, assert_eq!(expected_mod_add_community, read_mod_add_community);
read_moderator_remove_community assert_eq!(expected_mod_add, read_mod_add);
);
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);
} }
} }

View file

@ -120,6 +120,65 @@ impl ModLockPostView {
} }
} }
table! {
mod_sticky_post_view (id) {
id -> Int4,
mod_user_id -> Int4,
post_id -> Int4,
stickied -> Nullable<Bool>,
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<bool>,
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<i32>,
from_mod_user_id: Option<i32>,
page: Option<i64>,
limit: Option<i64>,
) -> Result<Vec<Self>, 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::<Self>(conn)
}
}
table! { table! {
mod_remove_comment_view (id) { mod_remove_comment_view (id) {
id -> Int4, id -> Int4,

View file

@ -16,6 +16,7 @@ pub struct Post {
pub updated: Option<chrono::NaiveDateTime>, pub updated: Option<chrono::NaiveDateTime>,
pub deleted: bool, pub deleted: bool,
pub nsfw: bool, pub nsfw: bool,
pub stickied: bool,
} }
#[derive(Insertable, AsChangeset, Clone)] #[derive(Insertable, AsChangeset, Clone)]
@ -31,6 +32,7 @@ pub struct PostForm {
pub updated: Option<chrono::NaiveDateTime>, pub updated: Option<chrono::NaiveDateTime>,
pub deleted: Option<bool>, pub deleted: Option<bool>,
pub nsfw: bool, pub nsfw: bool,
pub stickied: Option<bool>,
} }
impl Crud<PostForm> for Post { impl Crud<PostForm> for Post {
@ -216,6 +218,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
locked: None, locked: None,
stickied: None,
nsfw: false, nsfw: false,
updated: None, updated: None,
}; };
@ -232,6 +235,7 @@ mod tests {
published: inserted_post.published, published: inserted_post.published,
removed: false, removed: false,
locked: false, locked: false,
stickied: false,
nsfw: false, nsfw: false,
deleted: false, deleted: false,
updated: None, updated: None,

View file

@ -24,6 +24,7 @@ table! {
nsfw -> Bool, nsfw -> Bool,
banned -> Bool, banned -> Bool,
banned_from_community -> Bool, banned_from_community -> Bool,
stickied -> Bool,
creator_name -> Varchar, creator_name -> Varchar,
community_name -> Varchar, community_name -> Varchar,
community_removed -> Bool, community_removed -> Bool,
@ -61,6 +62,7 @@ pub struct PostView {
pub nsfw: bool, pub nsfw: bool,
pub banned: bool, pub banned: bool,
pub banned_from_community: bool, pub banned_from_community: bool,
pub stickied: bool,
pub creator_name: String, pub creator_name: String,
pub community_name: String, pub community_name: String,
pub community_removed: bool, pub community_removed: bool,
@ -100,10 +102,6 @@ impl PostView {
let mut query = post_view.into_boxed(); 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 { if let Some(for_creator_id) = for_creator_id {
query = query.filter(creator_id.eq(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)); 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 // TODO these are wrong, bc they'll only show saved for your logged in user, not theirs
if saved_only { if saved_only {
query = query.filter(saved.eq(true)); query = query.filter(saved.eq(true));
@ -147,22 +150,22 @@ impl PostView {
query = match sort { query = match sort {
SortType::Hot => query SortType::Hot => query
.order_by(hot_rank.desc()) .then_order_by(hot_rank.desc())
.then_order_by(published.desc()), .then_order_by(published.desc()),
SortType::New => query.order_by(published.desc()), SortType::New => query.then_order_by(published.desc()),
SortType::TopAll => query.order_by(score.desc()), SortType::TopAll => query.then_order_by(score.desc()),
SortType::TopYear => query SortType::TopYear => query
.filter(published.gt(now - 1.years())) .filter(published.gt(now - 1.years()))
.order_by(score.desc()), .then_order_by(score.desc()),
SortType::TopMonth => query SortType::TopMonth => query
.filter(published.gt(now - 1.months())) .filter(published.gt(now - 1.months()))
.order_by(score.desc()), .then_order_by(score.desc()),
SortType::TopWeek => query SortType::TopWeek => query
.filter(published.gt(now - 1.weeks())) .filter(published.gt(now - 1.weeks()))
.order_by(score.desc()), .then_order_by(score.desc()),
SortType::TopDay => query SortType::TopDay => query
.filter(published.gt(now - 1.days())) .filter(published.gt(now - 1.days()))
.order_by(score.desc()), .then_order_by(score.desc()),
}; };
query = query query = query
@ -249,6 +252,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
locked: None, locked: None,
stickied: None,
updated: None, updated: None,
nsfw: false, nsfw: false,
}; };
@ -293,6 +297,7 @@ mod tests {
removed: false, removed: false,
deleted: false, deleted: false,
locked: false, locked: false,
stickied: false,
community_name: community_name.to_owned(), community_name: community_name.to_owned(),
community_removed: false, community_removed: false,
community_deleted: false, community_deleted: false,
@ -320,6 +325,7 @@ mod tests {
removed: false, removed: false,
deleted: false, deleted: false,
locked: false, locked: false,
stickied: false,
creator_id: inserted_user.id, creator_id: inserted_user.id,
creator_name: user_name.to_owned(), creator_name: user_name.to_owned(),
banned: false, banned: false,

View file

@ -173,6 +173,16 @@ table! {
} }
} }
table! {
mod_sticky_post (id) {
id -> Int4,
mod_user_id -> Int4,
post_id -> Int4,
stickied -> Nullable<Bool>,
when_ -> Timestamp,
}
}
table! { table! {
post (id) { post (id) {
id -> Int4, id -> Int4,
@ -187,6 +197,7 @@ table! {
updated -> Nullable<Timestamp>, updated -> Nullable<Timestamp>,
deleted -> Bool, deleted -> Bool,
nsfw -> 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_community -> user_ (mod_user_id));
joinable!(mod_remove_post -> post (post_id)); joinable!(mod_remove_post -> post (post_id));
joinable!(mod_remove_post -> user_ (mod_user_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 -> community (community_id));
joinable!(post -> user_ (creator_id)); joinable!(post -> user_ (creator_id));
joinable!(post_like -> post (post_id)); joinable!(post_like -> post (post_id));
@ -307,6 +320,7 @@ allow_tables_to_appear_in_same_query!(
mod_remove_comment, mod_remove_comment,
mod_remove_community, mod_remove_community,
mod_remove_post, mod_remove_post,
mod_sticky_post,
post, post,
post_like, post_like,
post_read, post_read,

View file

@ -2,14 +2,15 @@ import { Component, linkEvent } from 'inferno';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators'; 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 { WebSocketService } from '../services';
import { msgOp, addTypeInfo, fetchLimit } from '../utils'; import { msgOp, addTypeInfo, fetchLimit } from '../utils';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
import * as moment from 'moment'; import * as moment from 'moment';
import { i18n } from '../i18next';
interface ModlogState { 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, communityId?: number,
communityName?: string, communityName?: string,
page: number; page: number;
@ -51,6 +52,7 @@ export class Modlog extends Component<any, ModlogState> {
setCombined(res: GetModlogResponse) { setCombined(res: GetModlogResponse) {
let removed_posts = addTypeInfo(res.removed_posts, "removed_posts"); let removed_posts = addTypeInfo(res.removed_posts, "removed_posts");
let locked_posts = addTypeInfo(res.locked_posts, "locked_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_comments = addTypeInfo(res.removed_comments, "removed_comments");
let removed_communities = addTypeInfo(res.removed_communities, "removed_communities"); let removed_communities = addTypeInfo(res.removed_communities, "removed_communities");
let banned_from_community = addTypeInfo(res.banned_from_community, "banned_from_community"); let banned_from_community = addTypeInfo(res.banned_from_community, "banned_from_community");
@ -61,6 +63,7 @@ export class Modlog extends Component<any, ModlogState> {
this.state.combined.push(...removed_posts); this.state.combined.push(...removed_posts);
this.state.combined.push(...locked_posts); this.state.combined.push(...locked_posts);
this.state.combined.push(...stickied_posts);
this.state.combined.push(...removed_comments); this.state.combined.push(...removed_comments);
this.state.combined.push(...removed_communities); this.state.combined.push(...removed_communities);
this.state.combined.push(...banned_from_community); this.state.combined.push(...banned_from_community);
@ -99,6 +102,12 @@ export class Modlog extends Component<any, ModlogState> {
<span> Post <Link to={`/post/${(i.data as ModLockPost).post_id}`}>{(i.data as ModLockPost).post_name}</Link></span> <span> Post <Link to={`/post/${(i.data as ModLockPost).post_id}`}>{(i.data as ModLockPost).post_name}</Link></span>
</> </>
} }
{i.type_ == 'stickied_posts' &&
<>
{(i.data as ModStickyPost).stickied? 'Stickied' : 'Unstickied'}
<span> Post <Link to={`/post/${(i.data as ModStickyPost).post_id}`}>{(i.data as ModStickyPost).post_name}</Link></span>
</>
}
{i.type_ == 'removed_comments' && {i.type_ == 'removed_comments' &&
<> <>
{(i.data as ModRemoveComment).removed? 'Removed' : 'Restored'} {(i.data as ModRemoveComment).removed? 'Removed' : 'Restored'}

View file

@ -129,6 +129,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.locked && {post.locked &&
<small className="ml-2 text-muted font-italic"><T i18nKey="locked">#</T></small> <small className="ml-2 text-muted font-italic"><T i18nKey="locked">#</T></small>
} }
{post.stickied &&
<small className="ml-2 text-muted font-italic"><T i18nKey="stickied">#</T></small>
}
{post.nsfw && {post.nsfw &&
<small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small> <small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small>
} }
@ -202,6 +205,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<li className="list-inline-item"> <li className="list-inline-item">
<span class="pointer" onClick={linkEvent(this, this.handleModLock)}>{post.locked ? i18n.t('unlock') : i18n.t('lock')}</span> <span class="pointer" onClick={linkEvent(this, this.handleModLock)}>{post.locked ? i18n.t('unlock') : i18n.t('lock')}</span>
</li> </li>
<li className="list-inline-item">
<span class="pointer" onClick={linkEvent(this, this.handleModSticky)}>{post.stickied ? i18n.t('unsticky') : i18n.t('sticky')}</span>
</li>
</> </>
} }
{/* Mods can ban from community, and appoint as mods to community */} {/* Mods can ban from community, and appoint as mods to community */}
@ -459,6 +465,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
WebSocketService.Instance.editPost(form); 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) { handleModBanFromCommunityShow(i: PostListing) {
i.state.showBanDialog = true; i.state.showBanDialog = true;
i.state.banType = BanType.Community; i.state.banType = BanType.Community;

15
ui/src/interfaces.ts vendored
View file

@ -77,6 +77,7 @@ export interface Post {
removed: boolean; removed: boolean;
deleted: boolean; deleted: boolean;
locked: boolean; locked: boolean;
stickied: boolean;
nsfw: boolean; nsfw: boolean;
banned: boolean; banned: boolean;
banned_from_community: boolean; banned_from_community: boolean;
@ -235,6 +236,7 @@ export interface GetModlogResponse {
op: string; op: string;
removed_posts: Array<ModRemovePost>, removed_posts: Array<ModRemovePost>,
locked_posts: Array<ModLockPost>, locked_posts: Array<ModLockPost>,
stickied_posts: Array<ModStickyPost>,
removed_comments: Array<ModRemoveComment>, removed_comments: Array<ModRemoveComment>,
removed_communities: Array<ModRemoveCommunity>, removed_communities: Array<ModRemoveCommunity>,
banned_from_community: Array<ModBanFromCommunity>, banned_from_community: Array<ModBanFromCommunity>,
@ -268,6 +270,18 @@ export interface ModLockPost {
community_name: string, 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 { export interface ModRemoveComment {
id: number, id: number,
mod_user_id: number, mod_user_id: number,
@ -425,6 +439,7 @@ export interface PostForm {
deleted?: boolean; deleted?: boolean;
nsfw: boolean; nsfw: boolean;
locked?: boolean; locked?: boolean;
stickied?: boolean;
reason?: string; reason?: string;
auth: string; auth: string;
} }

View file

@ -32,6 +32,8 @@ export const en = {
view_source: 'view source', view_source: 'view source',
unlock: 'unlock', unlock: 'unlock',
lock: 'lock', lock: 'lock',
sticky: 'sticky',
unsticky: 'unsticky',
link: 'link', link: 'link',
mod: 'mod', mod: 'mod',
mods: 'mods', mods: 'mods',
@ -47,6 +49,7 @@ export const en = {
remove: 'remove', remove: 'remove',
removed: 'removed', removed: 'removed',
locked: 'locked', locked: 'locked',
stickied: 'stickied',
reason: 'Reason', reason: 'Reason',
mark_as_read: 'mark as read', mark_as_read: 'mark as read',
mark_as_unread: 'mark as unread', mark_as_unread: 'mark as unread',