nsfw mostly done, except for settings page.

pull/198/head
Dessalines 2019-08-11 20:55:09 -07:00
parent c2cb36bfa4
commit 3246d5d670
21 changed files with 423 additions and 99 deletions

View File

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

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

View File

@ -22,7 +22,8 @@ pub struct CreateCommunity {
name: String,
title: String,
description: Option<String>,
category_id: i32 ,
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(

View File

@ -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())
};

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,
}
}

View File

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

View File

@ -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();
}

View File

@ -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} />

View File

@ -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) {

View File

@ -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();
}

View File

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

View File

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

View File

@ -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:',