nsfw mostly done, except for settings page.
This commit is contained in:
parent
d8361f2e00
commit
b3d4a5c4ce
21 changed files with 423 additions and 99 deletions
|
@ -0,0 +1,80 @@
|
|||
drop view community_view;
|
||||
drop view post_view;
|
||||
alter table community drop column nsfw;
|
||||
alter table post drop column nsfw;
|
||||
alter table user_ drop column show_nsfw;
|
||||
|
||||
-- the views
|
||||
create view community_view as
|
||||
with all_community as
|
||||
(
|
||||
select *,
|
||||
(select name from user_ u where c.creator_id = u.id) as creator_name,
|
||||
(select name from category ct where c.category_id = ct.id) as category_name,
|
||||
(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
|
||||
(select count(*) from post p where p.community_id = c.id) as number_of_posts,
|
||||
(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments,
|
||||
hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank
|
||||
from community c
|
||||
)
|
||||
|
||||
select
|
||||
ac.*,
|
||||
u.id as user_id,
|
||||
(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed
|
||||
from user_ u
|
||||
cross join all_community ac
|
||||
|
||||
union all
|
||||
|
||||
select
|
||||
ac.*,
|
||||
null as user_id,
|
||||
null as subscribed
|
||||
from all_community ac
|
||||
;
|
||||
|
||||
|
||||
-- Post view
|
||||
create view post_view as
|
||||
with all_post as
|
||||
(
|
||||
select
|
||||
p.*,
|
||||
(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 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
|
||||
;
|
||||
|
79
server/migrations/2019-08-11-000918_add_nsfw_columns/up.sql
Normal file
79
server/migrations/2019-08-11-000918_add_nsfw_columns/up.sql
Normal file
|
@ -0,0 +1,79 @@
|
|||
alter table community add column nsfw boolean default false not null;
|
||||
alter table post add column nsfw boolean default false not null;
|
||||
alter table user_ add column show_nsfw boolean default false not null;
|
||||
|
||||
-- The views
|
||||
drop view community_view;
|
||||
create view community_view as
|
||||
with all_community as
|
||||
(
|
||||
select *,
|
||||
(select name from user_ u where c.creator_id = u.id) as creator_name,
|
||||
(select name from category ct where c.category_id = ct.id) as category_name,
|
||||
(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
|
||||
(select count(*) from post p where p.community_id = c.id) as number_of_posts,
|
||||
(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments,
|
||||
hot_rank((select count(*) from community_follower cf where cf.community_id = c.id), c.published) as hot_rank
|
||||
from community c
|
||||
)
|
||||
|
||||
select
|
||||
ac.*,
|
||||
u.id as user_id,
|
||||
(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.id = cf.community_id) as subscribed
|
||||
from user_ u
|
||||
cross join all_community ac
|
||||
|
||||
union all
|
||||
|
||||
select
|
||||
ac.*,
|
||||
null as user_id,
|
||||
null as subscribed
|
||||
from all_community ac
|
||||
;
|
||||
|
||||
-- Post view
|
||||
drop view post_view;
|
||||
create view post_view as
|
||||
with all_post as
|
||||
(
|
||||
select
|
||||
p.*,
|
||||
(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
|
||||
;
|
|
@ -23,6 +23,7 @@ pub struct CreateCommunity {
|
|||
title: String,
|
||||
description: Option<String>,
|
||||
category_id: i32,
|
||||
nsfw: bool,
|
||||
auth: String
|
||||
}
|
||||
|
||||
|
@ -86,6 +87,7 @@ pub struct EditCommunity {
|
|||
category_id: i32,
|
||||
removed: Option<bool>,
|
||||
deleted: Option<bool>,
|
||||
nsfw: bool,
|
||||
reason: Option<String>,
|
||||
expires: Option<i64>,
|
||||
auth: String
|
||||
|
@ -194,6 +196,7 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
|
|||
creator_id: user_id,
|
||||
removed: None,
|
||||
deleted: None,
|
||||
nsfw: data.nsfw,
|
||||
updated: None,
|
||||
};
|
||||
|
||||
|
@ -291,6 +294,7 @@ impl Perform<CommunityResponse> for Oper<EditCommunity> {
|
|||
creator_id: user_id,
|
||||
removed: data.removed.to_owned(),
|
||||
deleted: data.deleted.to_owned(),
|
||||
nsfw: data.nsfw,
|
||||
updated: Some(naive_now())
|
||||
};
|
||||
|
||||
|
@ -333,12 +337,11 @@ impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
|
|||
let data: &ListCommunities = &self.data;
|
||||
let conn = establish_connection();
|
||||
|
||||
let user_id: Option<i32> = match &data.auth {
|
||||
let user_claims: Option<Claims> = match &data.auth {
|
||||
Some(auth) => {
|
||||
match Claims::decode(&auth) {
|
||||
Ok(claims) => {
|
||||
let user_id = claims.claims.id;
|
||||
Some(user_id)
|
||||
Some(claims.claims)
|
||||
}
|
||||
Err(_e) => None
|
||||
}
|
||||
|
@ -346,9 +349,26 @@ impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
|
|||
None => None
|
||||
};
|
||||
|
||||
let user_id = match &user_claims {
|
||||
Some(claims) => Some(claims.id),
|
||||
None => None
|
||||
};
|
||||
|
||||
let show_nsfw = match &user_claims {
|
||||
Some(claims) => claims.show_nsfw,
|
||||
None => false
|
||||
};
|
||||
|
||||
let sort = SortType::from_str(&data.sort)?;
|
||||
|
||||
let communities: Vec<CommunityView> = CommunityView::list(&conn, &sort, user_id, None, data.page, data.limit)?;
|
||||
let communities: Vec<CommunityView> = CommunityView::list(
|
||||
&conn,
|
||||
&sort,
|
||||
user_id,
|
||||
show_nsfw,
|
||||
None,
|
||||
data.page,
|
||||
data.limit)?;
|
||||
|
||||
// Return the jwt
|
||||
Ok(
|
||||
|
|
|
@ -6,6 +6,7 @@ pub struct CreatePost {
|
|||
name: String,
|
||||
url: Option<String>,
|
||||
body: Option<String>,
|
||||
nsfw: bool,
|
||||
community_id: i32,
|
||||
auth: String
|
||||
}
|
||||
|
@ -73,6 +74,7 @@ pub struct EditPost {
|
|||
body: Option<String>,
|
||||
removed: Option<bool>,
|
||||
deleted: Option<bool>,
|
||||
nsfw: bool,
|
||||
locked: Option<bool>,
|
||||
reason: Option<String>,
|
||||
auth: String
|
||||
|
@ -123,6 +125,7 @@ impl Perform<PostResponse> for Oper<CreatePost> {
|
|||
creator_id: user_id,
|
||||
removed: None,
|
||||
deleted: None,
|
||||
nsfw: data.nsfw,
|
||||
locked: None,
|
||||
updated: None
|
||||
};
|
||||
|
@ -219,12 +222,11 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
|
|||
let data: &GetPosts = &self.data;
|
||||
let conn = establish_connection();
|
||||
|
||||
let user_id: Option<i32> = match &data.auth {
|
||||
let user_claims: Option<Claims> = match &data.auth {
|
||||
Some(auth) => {
|
||||
match Claims::decode(&auth) {
|
||||
Ok(claims) => {
|
||||
let user_id = claims.claims.id;
|
||||
Some(user_id)
|
||||
Some(claims.claims)
|
||||
}
|
||||
Err(_e) => None
|
||||
}
|
||||
|
@ -232,16 +234,28 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
|
|||
None => None
|
||||
};
|
||||
|
||||
let user_id = match &user_claims {
|
||||
Some(claims) => Some(claims.id),
|
||||
None => None
|
||||
};
|
||||
|
||||
let show_nsfw = match &user_claims {
|
||||
Some(claims) => claims.show_nsfw,
|
||||
None => false
|
||||
};
|
||||
|
||||
let type_ = PostListingType::from_str(&data.type_)?;
|
||||
let sort = SortType::from_str(&data.sort)?;
|
||||
|
||||
let posts = match PostView::list(&conn,
|
||||
let posts = match PostView::list(
|
||||
&conn,
|
||||
type_,
|
||||
&sort,
|
||||
data.community_id,
|
||||
None,
|
||||
None,
|
||||
user_id,
|
||||
show_nsfw,
|
||||
false,
|
||||
false,
|
||||
data.page,
|
||||
|
@ -252,7 +266,6 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
|
|||
}
|
||||
};
|
||||
|
||||
// Return the jwt
|
||||
Ok(
|
||||
GetPostsResponse {
|
||||
op: self.op.to_string(),
|
||||
|
@ -381,6 +394,7 @@ impl Perform<PostResponse> for Oper<EditPost> {
|
|||
community_id: data.community_id,
|
||||
removed: data.removed.to_owned(),
|
||||
deleted: data.deleted.to_owned(),
|
||||
nsfw: data.nsfw,
|
||||
locked: data.locked.to_owned(),
|
||||
updated: Some(naive_now())
|
||||
};
|
||||
|
|
|
@ -277,6 +277,8 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
let mut communities = Vec::new();
|
||||
let mut users = Vec::new();
|
||||
|
||||
// TODO no clean / non-nsfw searching rn
|
||||
|
||||
match type_ {
|
||||
SearchType::Posts => {
|
||||
posts = PostView::list(
|
||||
|
@ -287,6 +289,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
None,
|
||||
Some(data.q.to_owned()),
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
data.page,
|
||||
|
@ -309,6 +312,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
&conn,
|
||||
&sort,
|
||||
None,
|
||||
true,
|
||||
Some(data.q.to_owned()),
|
||||
data.page,
|
||||
data.limit)?;
|
||||
|
@ -330,6 +334,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
None,
|
||||
Some(data.q.to_owned()),
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
data.page,
|
||||
|
@ -348,6 +353,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
&conn,
|
||||
&sort,
|
||||
None,
|
||||
true,
|
||||
Some(data.q.to_owned()),
|
||||
data.page,
|
||||
data.limit)?;
|
||||
|
|
|
@ -15,6 +15,7 @@ pub struct Register {
|
|||
password: String,
|
||||
password_verify: String,
|
||||
admin: bool,
|
||||
show_nsfw: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -151,6 +152,7 @@ impl Perform<LoginResponse> for Oper<Register> {
|
|||
updated: None,
|
||||
admin: data.admin,
|
||||
banned: false,
|
||||
show_nsfw: data.show_nsfw,
|
||||
};
|
||||
|
||||
// Create the user
|
||||
|
@ -170,6 +172,7 @@ impl Perform<LoginResponse> for Oper<Register> {
|
|||
title: "The Default Community".to_string(),
|
||||
description: Some("The Default Community".to_string()),
|
||||
category_id: 1,
|
||||
nsfw: false,
|
||||
creator_id: inserted_user.id,
|
||||
removed: None,
|
||||
deleted: None,
|
||||
|
@ -224,12 +227,11 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
|||
let data: &GetUserDetails = &self.data;
|
||||
let conn = establish_connection();
|
||||
|
||||
let user_id: Option<i32> = match &data.auth {
|
||||
let user_claims: Option<Claims> = match &data.auth {
|
||||
Some(auth) => {
|
||||
match Claims::decode(&auth) {
|
||||
Ok(claims) => {
|
||||
let user_id = claims.claims.id;
|
||||
Some(user_id)
|
||||
Some(claims.claims)
|
||||
}
|
||||
Err(_e) => None
|
||||
}
|
||||
|
@ -237,6 +239,16 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
|||
None => None
|
||||
};
|
||||
|
||||
let user_id = match &user_claims {
|
||||
Some(claims) => Some(claims.id),
|
||||
None => None
|
||||
};
|
||||
|
||||
let show_nsfw = match &user_claims {
|
||||
Some(claims) => claims.show_nsfw,
|
||||
None => false
|
||||
};
|
||||
|
||||
//TODO add save
|
||||
let sort = SortType::from_str(&data.sort)?;
|
||||
|
||||
|
@ -249,32 +261,37 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
|||
|
||||
// If its saved only, you don't care what creator it was
|
||||
let posts = if data.saved_only {
|
||||
PostView::list(&conn,
|
||||
PostView::list(
|
||||
&conn,
|
||||
PostListingType::All,
|
||||
&sort,
|
||||
data.community_id,
|
||||
None,
|
||||
None,
|
||||
Some(user_details_id),
|
||||
show_nsfw,
|
||||
data.saved_only,
|
||||
false,
|
||||
data.page,
|
||||
data.limit)?
|
||||
} else {
|
||||
PostView::list(&conn,
|
||||
PostView::list(
|
||||
&conn,
|
||||
PostListingType::All,
|
||||
&sort,
|
||||
data.community_id,
|
||||
Some(user_details_id),
|
||||
None,
|
||||
user_id,
|
||||
show_nsfw,
|
||||
data.saved_only,
|
||||
false,
|
||||
data.page,
|
||||
data.limit)?
|
||||
};
|
||||
let comments = if data.saved_only {
|
||||
CommentView::list(&conn,
|
||||
CommentView::list(
|
||||
&conn,
|
||||
&sort,
|
||||
None,
|
||||
None,
|
||||
|
@ -284,7 +301,8 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
|||
data.page,
|
||||
data.limit)?
|
||||
} else {
|
||||
CommentView::list(&conn,
|
||||
CommentView::list(
|
||||
&conn,
|
||||
&sort,
|
||||
None,
|
||||
Some(user_details_id),
|
||||
|
@ -343,6 +361,7 @@ impl Perform<AddAdminResponse> for Oper<AddAdmin> {
|
|||
updated: Some(naive_now()),
|
||||
admin: data.added,
|
||||
banned: read_user.banned,
|
||||
show_nsfw: read_user.show_nsfw,
|
||||
};
|
||||
|
||||
match User_::update(&conn, data.user_id, &user_form) {
|
||||
|
@ -402,6 +421,7 @@ impl Perform<BanUserResponse> for Oper<BanUser> {
|
|||
updated: Some(naive_now()),
|
||||
admin: read_user.admin,
|
||||
banned: data.ban,
|
||||
show_nsfw: read_user.show_nsfw,
|
||||
};
|
||||
|
||||
match User_::update(&conn, data.user_id, &user_form) {
|
||||
|
|
|
@ -14,6 +14,7 @@ pub struct Community {
|
|||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: bool,
|
||||
pub nsfw: bool,
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
|
||||
|
@ -27,6 +28,7 @@ pub struct CommunityForm {
|
|||
pub removed: Option<bool>,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: Option<bool>,
|
||||
pub nsfw: bool,
|
||||
}
|
||||
|
||||
impl Crud<CommunityForm> for Community {
|
||||
|
@ -240,6 +242,7 @@ mod tests {
|
|||
title: "nada".to_owned(),
|
||||
description: None,
|
||||
category_id: 1,
|
||||
nsfw: false,
|
||||
removed: None,
|
||||
deleted: None,
|
||||
updated: None,
|
||||
|
@ -254,6 +257,7 @@ mod tests {
|
|||
title: "nada".to_owned(),
|
||||
description: None,
|
||||
category_id: 1,
|
||||
nsfw: false,
|
||||
removed: false,
|
||||
deleted: false,
|
||||
published: inserted_community.published,
|
||||
|
|
|
@ -12,6 +12,7 @@ table! {
|
|||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
deleted -> Bool,
|
||||
nsfw -> Bool,
|
||||
creator_name -> Varchar,
|
||||
category_name -> Varchar,
|
||||
number_of_subscribers -> BigInt,
|
||||
|
@ -84,6 +85,7 @@ pub struct CommunityView {
|
|||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: bool,
|
||||
pub nsfw: bool,
|
||||
pub creator_name: String,
|
||||
pub category_name: String,
|
||||
pub number_of_subscribers: i64,
|
||||
|
@ -112,9 +114,11 @@ impl CommunityView {
|
|||
query.first::<Self>(conn)
|
||||
}
|
||||
|
||||
pub fn list(conn: &PgConnection,
|
||||
pub fn list(
|
||||
conn: &PgConnection,
|
||||
sort: &SortType,
|
||||
from_user_id: Option<i32>,
|
||||
show_nsfw: bool,
|
||||
search_term: Option<String>,
|
||||
page: Option<i64>,
|
||||
limit: Option<i64>,
|
||||
|
@ -143,6 +147,10 @@ impl CommunityView {
|
|||
_ => ()
|
||||
};
|
||||
|
||||
if !show_nsfw {
|
||||
query = query.filter(nsfw.eq(false));
|
||||
};
|
||||
|
||||
query
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
|
|
|
@ -15,6 +15,7 @@ pub struct Post {
|
|||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: bool,
|
||||
pub nsfw: bool,
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset, Clone)]
|
||||
|
@ -29,6 +30,7 @@ pub struct PostForm {
|
|||
pub locked: Option<bool>,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: Option<bool>,
|
||||
pub nsfw: bool,
|
||||
}
|
||||
|
||||
impl Crud<PostForm> for Post {
|
||||
|
@ -210,6 +212,7 @@ mod tests {
|
|||
removed: None,
|
||||
deleted: None,
|
||||
locked: None,
|
||||
nsfw: false,
|
||||
updated: None
|
||||
};
|
||||
|
||||
|
@ -225,6 +228,7 @@ mod tests {
|
|||
published: inserted_post.published,
|
||||
removed: false,
|
||||
locked: false,
|
||||
nsfw: false,
|
||||
deleted: false,
|
||||
updated: None
|
||||
};
|
||||
|
|
|
@ -19,10 +19,12 @@ table! {
|
|||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
deleted -> Bool,
|
||||
nsfw -> Bool,
|
||||
creator_name -> Varchar,
|
||||
community_name -> Varchar,
|
||||
community_removed -> Bool,
|
||||
community_deleted -> Bool,
|
||||
community_nsfw -> Bool,
|
||||
number_of_comments -> BigInt,
|
||||
score -> BigInt,
|
||||
upvotes -> BigInt,
|
||||
|
@ -51,10 +53,12 @@ pub struct PostView {
|
|||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub deleted: bool,
|
||||
pub nsfw: bool,
|
||||
pub creator_name: String,
|
||||
pub community_name: String,
|
||||
pub community_removed: bool,
|
||||
pub community_deleted: bool,
|
||||
pub community_nsfw: bool,
|
||||
pub number_of_comments: i64,
|
||||
pub score: i64,
|
||||
pub upvotes: i64,
|
||||
|
@ -68,13 +72,15 @@ pub struct PostView {
|
|||
}
|
||||
|
||||
impl PostView {
|
||||
pub fn list(conn: &PgConnection,
|
||||
pub fn list(
|
||||
conn: &PgConnection,
|
||||
type_: PostListingType,
|
||||
sort: &SortType,
|
||||
for_community_id: Option<i32>,
|
||||
for_creator_id: Option<i32>,
|
||||
search_term: Option<String>,
|
||||
my_user_id: Option<i32>,
|
||||
show_nsfw: bool,
|
||||
saved_only: bool,
|
||||
unread_only: bool,
|
||||
page: Option<i64>,
|
||||
|
@ -121,6 +127,12 @@ impl PostView {
|
|||
query = query.filter(user_id.is_null());
|
||||
}
|
||||
|
||||
if !show_nsfw {
|
||||
query = query
|
||||
.filter(nsfw.eq(false))
|
||||
.filter(community_nsfw.eq(false));
|
||||
};
|
||||
|
||||
query = match sort {
|
||||
SortType::Hot => query.order_by(hot_rank.desc())
|
||||
.then_order_by(published.desc()),
|
||||
|
@ -266,6 +278,7 @@ mod tests {
|
|||
community_name: community_name.to_owned(),
|
||||
community_removed: false,
|
||||
community_deleted: false,
|
||||
community_nsfw: false,
|
||||
number_of_comments: 0,
|
||||
score: 1,
|
||||
upvotes: 1,
|
||||
|
@ -294,6 +307,7 @@ mod tests {
|
|||
community_name: community_name.to_owned(),
|
||||
community_removed: false,
|
||||
community_deleted: false,
|
||||
community_nsfw: false,
|
||||
number_of_comments: 0,
|
||||
score: 1,
|
||||
upvotes: 1,
|
||||
|
|
|
@ -18,7 +18,8 @@ pub struct User_ {
|
|||
pub admin: bool,
|
||||
pub banned: bool,
|
||||
pub published: chrono::NaiveDateTime,
|
||||
pub updated: Option<chrono::NaiveDateTime>
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub show_nsfw: bool,
|
||||
}
|
||||
|
||||
#[derive(Insertable, AsChangeset, Clone)]
|
||||
|
@ -31,7 +32,8 @@ pub struct UserForm {
|
|||
pub admin: bool,
|
||||
pub banned: bool,
|
||||
pub email: Option<String>,
|
||||
pub updated: Option<chrono::NaiveDateTime>
|
||||
pub updated: Option<chrono::NaiveDateTime>,
|
||||
pub show_nsfw: bool,
|
||||
}
|
||||
|
||||
impl Crud<UserForm> for User_ {
|
||||
|
@ -77,6 +79,7 @@ pub struct Claims {
|
|||
pub id: i32,
|
||||
pub username: String,
|
||||
pub iss: String,
|
||||
pub show_nsfw: bool,
|
||||
}
|
||||
|
||||
impl Claims {
|
||||
|
@ -96,6 +99,7 @@ impl User_ {
|
|||
id: self.id,
|
||||
username: self.name.to_owned(),
|
||||
iss: self.fedi_name.to_owned(),
|
||||
show_nsfw: self.show_nsfw,
|
||||
};
|
||||
encode(&Header::default(), &my_claims, Settings::get().jwt_secret.as_ref()).unwrap()
|
||||
}
|
||||
|
@ -133,7 +137,8 @@ mod tests {
|
|||
email: None,
|
||||
admin: false,
|
||||
banned: false,
|
||||
updated: None
|
||||
updated: None,
|
||||
show_nsfw: false,
|
||||
};
|
||||
|
||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||
|
@ -149,7 +154,8 @@ mod tests {
|
|||
admin: false,
|
||||
banned: false,
|
||||
published: inserted_user.published,
|
||||
updated: None
|
||||
updated: None,
|
||||
show_nsfw: false,
|
||||
};
|
||||
|
||||
let read_user = User_::read(&conn, inserted_user.id).unwrap();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![recursion_limit = "512"]
|
||||
#[macro_use] pub extern crate strum_macros;
|
||||
#[macro_use] pub extern crate lazy_static;
|
||||
#[macro_use] pub extern crate failure;
|
||||
|
|
|
@ -52,6 +52,7 @@ table! {
|
|||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
deleted -> Bool,
|
||||
nsfw -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,6 +186,7 @@ table! {
|
|||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
deleted -> Bool,
|
||||
nsfw -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,6 +242,7 @@ table! {
|
|||
banned -> Bool,
|
||||
published -> Timestamp,
|
||||
updated -> Nullable<Timestamp>,
|
||||
show_nsfw -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,8 @@ impl ChatServer {
|
|||
use crate::db::*;
|
||||
use crate::db::post_view::*;
|
||||
let conn = establish_connection();
|
||||
let posts = PostView::list(&conn,
|
||||
let posts = PostView::list(
|
||||
&conn,
|
||||
PostListingType::Community,
|
||||
&SortType::New,
|
||||
Some(*community_id),
|
||||
|
@ -143,6 +144,7 @@ impl ChatServer {
|
|||
None,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
Some(9999))?;
|
||||
for post in posts {
|
||||
|
|
|
@ -30,7 +30,8 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt
|
|||
communityForm: {
|
||||
name: null,
|
||||
title: null,
|
||||
category_id: null
|
||||
category_id: null,
|
||||
nsfw: false,
|
||||
},
|
||||
categories: [],
|
||||
loading: false
|
||||
|
@ -48,6 +49,7 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt
|
|||
category_id: this.props.community.category_id,
|
||||
description: this.props.community.description,
|
||||
edit_id: this.props.community.id,
|
||||
nsfw: this.props.community.nsfw,
|
||||
auth: null
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +105,14 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" checked={this.state.communityForm.nsfw} onChange={linkEvent(this, this.handleCommunityNsfwChange)}/>
|
||||
<label class="form-check-label"><T i18nKey="nsfw">#</T></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-secondary mr-2">
|
||||
|
@ -147,6 +157,11 @@ export class CommunityForm extends Component<CommunityFormProps, CommunityFormSt
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handleCommunityNsfwChange(i: CommunityForm, event: any) {
|
||||
i.state.communityForm.nsfw = event.target.checked;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handleCancel(i: CommunityForm) {
|
||||
i.props.onCancel();
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ export class Community extends Component<any, State> {
|
|||
number_of_comments: null,
|
||||
published: null,
|
||||
removed: null,
|
||||
nsfw: false,
|
||||
deleted: null,
|
||||
},
|
||||
moderators: [],
|
||||
|
@ -105,6 +106,9 @@ export class Community extends Component<any, State> {
|
|||
{this.state.community.removed &&
|
||||
<small className="ml-2 text-muted font-italic"><T i18nKey="removed">#</T></small>
|
||||
}
|
||||
{this.state.community.nsfw &&
|
||||
<small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small>
|
||||
}
|
||||
</h5>
|
||||
{this.selects()}
|
||||
<PostListings posts={this.state.posts} />
|
||||
|
|
|
@ -28,6 +28,7 @@ export class Login extends Component<any, State> {
|
|||
password: undefined,
|
||||
password_verify: undefined,
|
||||
admin: false,
|
||||
show_nsfw: false,
|
||||
},
|
||||
loginLoading: false,
|
||||
registerLoading: false,
|
||||
|
@ -125,11 +126,18 @@ export class Login extends Component<any, State> {
|
|||
<input type="password" value={this.state.registerForm.password_verify} onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)} class="form-control" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" checked={this.state.registerForm.show_nsfw} onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}/>
|
||||
<label class="form-check-label"><T i18nKey="show_nsfw">#</T></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<button type="submit" class="btn btn-secondary">{this.state.registerLoading ?
|
||||
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : i18n.t('sign_up')}</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -181,6 +189,11 @@ export class Login extends Component<any, State> {
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handleRegisterShowNsfwChange(i: Login, event: any) {
|
||||
i.state.registerForm.show_nsfw = event.target.checked;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: any) {
|
||||
let op: UserOperation = msgOp(msg);
|
||||
if (msg.error) {
|
||||
|
|
|
@ -31,6 +31,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
private emptyState: PostFormState = {
|
||||
postForm: {
|
||||
name: null,
|
||||
nsfw: false,
|
||||
auth: null,
|
||||
community_id: null,
|
||||
creator_id: (UserService.Instance.user) ? UserService.Instance.user.id : null,
|
||||
|
@ -54,6 +55,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
edit_id: this.props.post.id,
|
||||
creator_id: this.props.post.creator_id,
|
||||
url: this.props.post.url,
|
||||
nsfw: this.props.post.nsfw,
|
||||
auth: null
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +128,14 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" checked={this.state.postForm.nsfw} onChange={linkEvent(this, this.handlePostNsfwChange)}/>
|
||||
<label class="form-check-label"><T i18nKey="nsfw">#</T></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<button type="submit" class="btn btn-secondary mr-2">
|
||||
|
@ -196,6 +206,11 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handlePostNsfwChange(i: PostForm, event: any) {
|
||||
i.state.postForm.nsfw = event.target.checked;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handleCancel(i: PostForm) {
|
||||
i.props.onCancel();
|
||||
}
|
||||
|
|
|
@ -93,6 +93,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{post.locked &&
|
||||
<small className="ml-2 text-muted font-italic"><T i18nKey="locked">#</T></small>
|
||||
}
|
||||
{post.nsfw &&
|
||||
<small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small>
|
||||
}
|
||||
{ post.url && isImage(post.url) &&
|
||||
<>
|
||||
{ !this.state.imageExpanded
|
||||
|
@ -251,6 +254,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
edit_id: i.props.post.id,
|
||||
creator_id: i.props.post.creator_id,
|
||||
deleted: !i.props.post.deleted,
|
||||
nsfw: i.props.post.nsfw,
|
||||
auth: null
|
||||
};
|
||||
WebSocketService.Instance.editPost(deleteForm);
|
||||
|
@ -285,6 +289,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
creator_id: i.props.post.creator_id,
|
||||
removed: !i.props.post.removed,
|
||||
reason: i.state.removeReason,
|
||||
nsfw: i.props.post.nsfw,
|
||||
auth: null,
|
||||
};
|
||||
WebSocketService.Instance.editPost(form);
|
||||
|
@ -299,6 +304,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
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,
|
||||
locked: !i.props.post.locked,
|
||||
auth: null,
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@ export interface User {
|
|||
id: number;
|
||||
iss: string;
|
||||
username: string;
|
||||
show_nsfw: boolean;
|
||||
}
|
||||
|
||||
export interface UserView {
|
||||
|
@ -53,6 +54,7 @@ export interface Community {
|
|||
creator_id: number;
|
||||
removed: boolean;
|
||||
deleted: boolean;
|
||||
nsfw: boolean;
|
||||
published: string;
|
||||
updated?: string;
|
||||
creator_name: string;
|
||||
|
@ -74,11 +76,14 @@ export interface Post {
|
|||
removed: boolean;
|
||||
deleted: boolean;
|
||||
locked: boolean;
|
||||
nsfw: boolean;
|
||||
published: string;
|
||||
updated?: string;
|
||||
creator_name: string;
|
||||
community_name: string;
|
||||
community_removed: boolean;
|
||||
community_deleted: boolean;
|
||||
community_nsfw: boolean;
|
||||
number_of_comments: number;
|
||||
score: number;
|
||||
upvotes: number;
|
||||
|
@ -334,6 +339,7 @@ export interface RegisterForm {
|
|||
password: string;
|
||||
password_verify: string;
|
||||
admin: boolean;
|
||||
show_nsfw: boolean;
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
|
@ -351,6 +357,7 @@ export interface CommunityForm {
|
|||
edit_id?: number;
|
||||
removed?: boolean;
|
||||
deleted?: boolean;
|
||||
nsfw: boolean;
|
||||
reason?: string;
|
||||
expires?: number;
|
||||
auth?: string;
|
||||
|
@ -396,6 +403,7 @@ export interface PostForm {
|
|||
creator_id: number;
|
||||
removed?: boolean;
|
||||
deleted?: boolean;
|
||||
nsfw: boolean;
|
||||
locked?: boolean;
|
||||
reason?: string;
|
||||
auth: string;
|
||||
|
|
|
@ -112,6 +112,8 @@ export const en = {
|
|||
setup_admin: 'Set Up Site Administrator',
|
||||
your_site: 'your site',
|
||||
modified: 'modified',
|
||||
nsfw: 'NSFW',
|
||||
show_nsfw: 'Show NSFW content',
|
||||
sponsors: 'Sponsors',
|
||||
sponsors_of_lemmy: 'Sponsors of Lemmy',
|
||||
sponsor_message: 'Lemmy is free, <1>open-source</1> software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project. Thank you to the following people:',
|
||||
|
|
Loading…
Reference in a new issue