From fca8e6a0a9308340e88ad291c89c40e7d17f27be Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 11 Dec 2019 12:21:47 -0800 Subject: [PATCH] Adding some site oriented settings. - Adding option to close registration. Fixes #350 - Adding option to disable showing NSFW buttons. Fixes #364 - Adding option to disable downvotes. Fixes #239 --- .../down.sql | 16 +++++ .../2019-12-11-181820_add_site_fields/up.sql | 16 +++++ server/src/api/comment.rs | 8 +++ server/src/api/mod.rs | 2 + server/src/api/post.rs | 8 +++ server/src/api/site.rs | 15 ++++ server/src/api/user.rs | 7 ++ server/src/db/community.rs | 46 +------------ server/src/db/community_view.rs | 41 ----------- server/src/db/mod.rs | 2 + server/src/db/site.rs | 52 ++++++++++++++ server/src/db/site_view.rs | 48 +++++++++++++ server/src/feeds.rs | 2 +- server/src/lib.rs | 2 +- server/src/nodeinfo.rs | 2 +- server/src/schema.rs | 3 + ui/src/components/comment-node.tsx | 22 +++--- ui/src/components/community-form.tsx | 29 ++++---- ui/src/components/login.tsx | 28 ++++---- ui/src/components/post-form.tsx | 28 ++++---- ui/src/components/post-listing.tsx | 22 +++--- ui/src/components/site-form.tsx | 69 +++++++++++++++++++ ui/src/components/user.tsx | 34 ++++----- ui/src/interfaces.ts | 9 ++- ui/src/translations/en.ts | 5 ++ 25 files changed, 349 insertions(+), 167 deletions(-) create mode 100644 server/migrations/2019-12-11-181820_add_site_fields/down.sql create mode 100644 server/migrations/2019-12-11-181820_add_site_fields/up.sql create mode 100644 server/src/db/site.rs create mode 100644 server/src/db/site_view.rs diff --git a/server/migrations/2019-12-11-181820_add_site_fields/down.sql b/server/migrations/2019-12-11-181820_add_site_fields/down.sql new file mode 100644 index 000000000..72eedba45 --- /dev/null +++ b/server/migrations/2019-12-11-181820_add_site_fields/down.sql @@ -0,0 +1,16 @@ +-- Drop the columns +drop view site_view; +alter table site drop column enable_downvotes; +alter table site drop column open_registration; +alter table site drop column enable_nsfw; + +-- Rebuild the views + +create view site_view as +select *, +(select name from user_ u where s.creator_id = u.id) as creator_name, +(select count(*) from user_) as number_of_users, +(select count(*) from post) as number_of_posts, +(select count(*) from comment) as number_of_comments, +(select count(*) from community) as number_of_communities +from site s; diff --git a/server/migrations/2019-12-11-181820_add_site_fields/up.sql b/server/migrations/2019-12-11-181820_add_site_fields/up.sql new file mode 100644 index 000000000..e107b1ac3 --- /dev/null +++ b/server/migrations/2019-12-11-181820_add_site_fields/up.sql @@ -0,0 +1,16 @@ +-- Add the column +alter table site add column enable_downvotes boolean default true not null; +alter table site add column open_registration boolean default true not null; +alter table site add column enable_nsfw boolean default true not null; + +-- Reload the view +drop view site_view; + +create view site_view as +select *, +(select name from user_ u where s.creator_id = u.id) as creator_name, +(select count(*) from user_) as number_of_users, +(select count(*) from post) as number_of_posts, +(select count(*) from comment) as number_of_comments, +(select count(*) from community) as number_of_communities +from site s; diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs index eb5da62ba..9f9d46d30 100644 --- a/server/src/api/comment.rs +++ b/server/src/api/comment.rs @@ -298,6 +298,14 @@ impl Perform for Oper { let user_id = claims.id; + // Don't do a downvote if site has downvotes disabled + if data.score == -1 { + let site = SiteView::read(&conn)?; + if site.enable_downvotes == false { + return Err(APIError::err(&self.op, "downvotes_disabled"))?; + } + } + // Check for a community ban let post = Post::read(&conn, data.post_id)?; if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 2d5dec870..97a119000 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -8,6 +8,8 @@ use crate::db::moderator_views::*; use crate::db::password_reset_request::*; use crate::db::post::*; use crate::db::post_view::*; +use crate::db::site::*; +use crate::db::site_view::*; use crate::db::user::*; use crate::db::user_mention::*; use crate::db::user_mention_view::*; diff --git a/server/src/api/post.rs b/server/src/api/post.rs index 0b54840f4..4b2395a8a 100644 --- a/server/src/api/post.rs +++ b/server/src/api/post.rs @@ -265,6 +265,14 @@ impl Perform for Oper { let user_id = claims.id; + // Don't do a downvote if site has downvotes disabled + if data.score == -1 { + let site = SiteView::read(&conn)?; + if site.enable_downvotes == false { + return Err(APIError::err(&self.op, "downvotes_disabled"))?; + } + } + // Check for a community ban let post = Post::read(&conn, data.post_id)?; if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { diff --git a/server/src/api/site.rs b/server/src/api/site.rs index cb6edfd58..ec89e46cd 100644 --- a/server/src/api/site.rs +++ b/server/src/api/site.rs @@ -56,6 +56,9 @@ pub struct GetModlogResponse { pub struct CreateSite { name: String, description: Option, + enable_downvotes: bool, + open_registration: bool, + enable_nsfw: bool, auth: String, } @@ -63,6 +66,9 @@ pub struct CreateSite { pub struct EditSite { name: String, description: Option, + enable_downvotes: bool, + open_registration: bool, + enable_nsfw: bool, auth: String, } @@ -208,6 +214,9 @@ impl Perform for Oper { name: data.name.to_owned(), description: data.description.to_owned(), creator_id: user_id, + enable_downvotes: data.enable_downvotes, + open_registration: data.open_registration, + enable_nsfw: data.enable_nsfw, updated: None, }; @@ -255,6 +264,9 @@ impl Perform for Oper { description: data.description.to_owned(), creator_id: found_site.creator_id, updated: Some(naive_now()), + enable_downvotes: data.enable_downvotes, + open_registration: data.open_registration, + enable_nsfw: data.enable_nsfw, }; match Site::update(&conn, 1, &site_form) { @@ -431,6 +443,9 @@ impl Perform for Oper { description: read_site.description, creator_id: data.user_id, updated: Some(naive_now()), + enable_downvotes: read_site.enable_downvotes, + open_registration: read_site.open_registration, + enable_nsfw: read_site.enable_nsfw, }; match Site::update(&conn, 1, &site_form) { diff --git a/server/src/api/user.rs b/server/src/api/user.rs index 3047a0d3f..df38dc99e 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -193,6 +193,13 @@ impl Perform for Oper { let data: &Register = &self.data; let conn = establish_connection(); + // Make sure site has open registration + if let Ok(site) = SiteView::read(&conn) { + if !site.open_registration { + return Err(APIError::err(&self.op, "registration_closed"))?; + } + } + // Make sure passwords match if &data.password != &data.password_verify { return Err(APIError::err(&self.op, "passwords_dont_match"))?; diff --git a/server/src/db/community.rs b/server/src/db/community.rs index 954690751..57b962d13 100644 --- a/server/src/db/community.rs +++ b/server/src/db/community.rs @@ -1,5 +1,5 @@ use super::*; -use crate::schema::{community, community_follower, community_moderator, community_user_ban, site}; +use crate::schema::{community, community_follower, community_moderator, community_user_ban}; #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[table_name = "community"] @@ -202,50 +202,6 @@ impl Followable for CommunityFollower { } } -#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] -#[table_name = "site"] -pub struct Site { - pub id: i32, - pub name: String, - pub description: Option, - pub creator_id: i32, - pub published: chrono::NaiveDateTime, - pub updated: Option, -} - -#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] -#[table_name = "site"] -pub struct SiteForm { - pub name: String, - pub description: Option, - pub creator_id: i32, - pub updated: Option, -} - -impl Crud for Site { - fn read(conn: &PgConnection, _site_id: i32) -> Result { - use crate::schema::site::dsl::*; - site.first::(conn) - } - - fn delete(conn: &PgConnection, site_id: i32) -> Result { - use crate::schema::site::dsl::*; - diesel::delete(site.find(site_id)).execute(conn) - } - - fn create(conn: &PgConnection, new_site: &SiteForm) -> Result { - use crate::schema::site::dsl::*; - insert_into(site).values(new_site).get_result::(conn) - } - - fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result { - use crate::schema::site::dsl::*; - diesel::update(site.find(site_id)) - .set(new_site) - .get_result::(conn) - } -} - #[cfg(test)] mod tests { use super::super::user::*; diff --git a/server/src/db/community_view.rs b/server/src/db/community_view.rs index 04b68441a..157c4d912 100644 --- a/server/src/db/community_view.rs +++ b/server/src/db/community_view.rs @@ -59,22 +59,6 @@ table! { } } -table! { - site_view (id) { - id -> Int4, - name -> Varchar, - description -> Nullable, - creator_id -> Int4, - published -> Timestamp, - updated -> Nullable, - creator_name -> Varchar, - number_of_users -> BigInt, - number_of_posts -> BigInt, - number_of_comments -> BigInt, - number_of_communities -> BigInt, - } -} - #[derive( Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone, )] @@ -328,28 +312,3 @@ impl CommunityUserBanView { .first::(conn) } } - -#[derive( - Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone, -)] -#[table_name = "site_view"] -pub struct SiteView { - pub id: i32, - pub name: String, - pub description: Option, - pub creator_id: i32, - pub published: chrono::NaiveDateTime, - pub updated: Option, - pub creator_name: String, - pub number_of_users: i64, - pub number_of_posts: i64, - pub number_of_comments: i64, - pub number_of_communities: i64, -} - -impl SiteView { - pub fn read(conn: &PgConnection) -> Result { - use super::community_view::site_view::dsl::*; - site_view.first::(conn) - } -} diff --git a/server/src/db/mod.rs b/server/src/db/mod.rs index 3501fcda6..a7961f122 100644 --- a/server/src/db/mod.rs +++ b/server/src/db/mod.rs @@ -14,6 +14,8 @@ pub mod moderator_views; pub mod password_reset_request; pub mod post; pub mod post_view; +pub mod site; +pub mod site_view; pub mod user; pub mod user_mention; pub mod user_mention_view; diff --git a/server/src/db/site.rs b/server/src/db/site.rs new file mode 100644 index 000000000..3b8366d81 --- /dev/null +++ b/server/src/db/site.rs @@ -0,0 +1,52 @@ +use super::*; +use crate::schema::site; + +#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] +#[table_name = "site"] +pub struct Site { + pub id: i32, + pub name: String, + pub description: Option, + pub creator_id: i32, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub enable_downvotes: bool, + pub open_registration: bool, + pub enable_nsfw: bool, +} + +#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] +#[table_name = "site"] +pub struct SiteForm { + pub name: String, + pub description: Option, + pub creator_id: i32, + pub updated: Option, + pub enable_downvotes: bool, + pub open_registration: bool, + pub enable_nsfw: bool, +} + +impl Crud for Site { + fn read(conn: &PgConnection, _site_id: i32) -> Result { + use crate::schema::site::dsl::*; + site.first::(conn) + } + + fn delete(conn: &PgConnection, site_id: i32) -> Result { + use crate::schema::site::dsl::*; + diesel::delete(site.find(site_id)).execute(conn) + } + + fn create(conn: &PgConnection, new_site: &SiteForm) -> Result { + use crate::schema::site::dsl::*; + insert_into(site).values(new_site).get_result::(conn) + } + + fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result { + use crate::schema::site::dsl::*; + diesel::update(site.find(site_id)) + .set(new_site) + .get_result::(conn) + } +} diff --git a/server/src/db/site_view.rs b/server/src/db/site_view.rs new file mode 100644 index 000000000..40b1265f5 --- /dev/null +++ b/server/src/db/site_view.rs @@ -0,0 +1,48 @@ +use super::*; + +table! { + site_view (id) { + id -> Int4, + name -> Varchar, + description -> Nullable, + creator_id -> Int4, + published -> Timestamp, + updated -> Nullable, + enable_downvotes -> Bool, + open_registration -> Bool, + enable_nsfw -> Bool, + creator_name -> Varchar, + number_of_users -> BigInt, + number_of_posts -> BigInt, + number_of_comments -> BigInt, + number_of_communities -> BigInt, + } +} + +#[derive( + Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone, +)] +#[table_name = "site_view"] +pub struct SiteView { + pub id: i32, + pub name: String, + pub description: Option, + pub creator_id: i32, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub enable_downvotes: bool, + pub open_registration: bool, + pub enable_nsfw: bool, + pub creator_name: String, + pub number_of_users: i64, + pub number_of_posts: i64, + pub number_of_comments: i64, + pub number_of_communities: i64, +} + +impl SiteView { + pub fn read(conn: &PgConnection) -> Result { + use super::site_view::site_view::dsl::*; + site_view.first::(conn) + } +} diff --git a/server/src/feeds.rs b/server/src/feeds.rs index 810f6d596..a16116d45 100644 --- a/server/src/feeds.rs +++ b/server/src/feeds.rs @@ -3,8 +3,8 @@ extern crate rss; use super::*; use crate::db::comment_view::{ReplyQueryBuilder, ReplyView}; use crate::db::community::Community; -use crate::db::community_view::SiteView; use crate::db::post_view::{PostQueryBuilder, PostView}; +use crate::db::site_view::SiteView; use crate::db::user::User_; use crate::db::user_mention_view::{UserMentionQueryBuilder, UserMentionView}; use crate::db::{establish_connection, ListingType, SortType}; diff --git a/server/src/lib.rs b/server/src/lib.rs index 2568143d3..c2fa2189d 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -118,7 +118,7 @@ impl Settings { .unwrap_or("3600".to_string()) .parse() .unwrap(), - email_config: email_config, + email_config, } } fn api_endpoint(&self) -> String { diff --git a/server/src/nodeinfo.rs b/server/src/nodeinfo.rs index 69c86919c..f8135c7d0 100644 --- a/server/src/nodeinfo.rs +++ b/server/src/nodeinfo.rs @@ -1,5 +1,5 @@ -use crate::db::community_view::SiteView; use crate::db::establish_connection; +use crate::db::site_view::SiteView; use crate::version; use crate::Settings; use actix_web::body::Body; diff --git a/server/src/schema.rs b/server/src/schema.rs index bd73aabf5..118f5f4a6 100644 --- a/server/src/schema.rs +++ b/server/src/schema.rs @@ -246,6 +246,9 @@ table! { creator_id -> Int4, published -> Timestamp, updated -> Nullable, + enable_downvotes -> Bool, + open_registration -> Bool, + enable_nsfw -> Bool, } } diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index e3d821968..f408ef276 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -102,16 +102,18 @@ export class CommentNode extends Component {
{node.comment.score}
- + {WebSocketService.Instance.site.enable_downvotes && ( + + )} )}
-
-
-
- - + + {WebSocketService.Instance.site.enable_nsfw && ( +
+
+
+ + +
-
+ )}
-
-
-
- - + {WebSocketService.Instance.site.enable_nsfw && ( +
+
+
+ + +
-
+ )}
)} -
-
-
- - + {WebSocketService.Instance.site.enable_nsfw && ( +
+
+
+ + +
-
+ )}
{post.score}
- + {WebSocketService.Instance.site.enable_downvotes && ( + + )}
{post.url && isImage(post.url) && !post.nsfw && !post.community_nsfw && ( { private emptyState: SiteFormState = { siteForm: { + enable_downvotes: true, + open_registration: true, + enable_nsfw: true, name: null, }, loading: false, @@ -31,6 +34,9 @@ export class SiteForm extends Component { this.state.siteForm = { name: this.props.site.name, description: this.props.site.description, + enable_downvotes: this.props.site.enable_downvotes, + open_registration: this.props.site.open_registration, + enable_nsfw: this.props.site.enable_nsfw, }; } } @@ -77,6 +83,54 @@ export class SiteForm extends Component { />
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
-
-
-
- - + {WebSocketService.Instance.site.enable_nsfw && ( +
+
+
+ + +
-
+ )}