diff options
38 files changed, 1114 insertions, 207 deletions
@@ -19,12 +19,11 @@ Made with [Rust](https://www.rust-lang.org), [Actix](https://actix.rs/), [Infern ## Features - TBD -- -the name -Lead singer from motorhead. -The old school video game. -The furry rodents. +## Why's it called Lemmy? +- Lead singer from [motorhead](https://invidio.us/watch?v=pWB5JZRGl0U). +- The old school [video game](https://en.wikipedia.org/wiki/Lemmings_(video_game)). +- The [furry rodents](http://sunchild.fpwc.org/lemming-the-little-giant-of-the-north/). Goals r/ censorship diff --git a/server/migrations/2019-02-26-002946_create_user/up.sql b/server/migrations/2019-02-26-002946_create_user/up.sql index 83112e9b..ea2c9234 100644 --- a/server/migrations/2019-02-26-002946_create_user/up.sql +++ b/server/migrations/2019-02-26-002946_create_user/up.sql @@ -6,8 +6,8 @@ create table user_ ( password_encrypted text not null, email text unique, icon bytea, - admin boolean default false, - banned boolean default false, + admin boolean default false not null, + banned boolean default false not null, published timestamp not null default now(), updated timestamp, unique(name, fedi_name) diff --git a/server/migrations/2019-02-27-170003_create_community/down.sql b/server/migrations/2019-02-27-170003_create_community/down.sql index d5bd3994..219588d8 100644 --- a/server/migrations/2019-02-27-170003_create_community/down.sql +++ b/server/migrations/2019-02-27-170003_create_community/down.sql @@ -1,3 +1,4 @@ +drop table site; drop table community_user_ban;; drop table community_moderator; drop table community_follower; diff --git a/server/migrations/2019-02-27-170003_create_community/up.sql b/server/migrations/2019-02-27-170003_create_community/up.sql index ad47adfe..2d6856b3 100644 --- a/server/migrations/2019-02-27-170003_create_community/up.sql +++ b/server/migrations/2019-02-27-170003_create_community/up.sql @@ -68,3 +68,12 @@ create table community_user_ban ( ); insert into community (name, title, category_id, creator_id) values ('main', 'The Default Community', 1, 1); + +create table site ( + id serial primary key, + name varchar(20) not null unique, + description text, + creator_id int references user_ on update cascade on delete cascade not null, + published timestamp not null default now(), + updated timestamp +); diff --git a/server/migrations/2019-04-03-155205_create_community_view/down.sql b/server/migrations/2019-04-03-155205_create_community_view/down.sql index 0c7a33c8..67d12f6f 100644 --- a/server/migrations/2019-04-03-155205_create_community_view/down.sql +++ b/server/migrations/2019-04-03-155205_create_community_view/down.sql @@ -2,3 +2,4 @@ drop view community_view; drop view community_moderator_view; drop view community_follower_view; drop view community_user_ban_view; +drop view site_view; diff --git a/server/migrations/2019-04-03-155205_create_community_view/up.sql b/server/migrations/2019-04-03-155205_create_community_view/up.sql index 510fd0f2..1b73af51 100644 --- a/server/migrations/2019-04-03-155205_create_community_view/up.sql +++ b/server/migrations/2019-04-03-155205_create_community_view/up.sql @@ -46,3 +46,11 @@ select *, (select name from user_ u where cm.user_id = u.id) as user_name, (select name from community c where cm.community_id = c.id) as community_name from community_user_ban cm; + +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 +from site s; diff --git a/server/src/actions/comment.rs b/server/src/actions/comment.rs index 2c5c570e..f6eee5f1 100644 --- a/server/src/actions/comment.rs +++ b/server/src/actions/comment.rs @@ -137,8 +137,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; diff --git a/server/src/actions/comment_view.rs b/server/src/actions/comment_view.rs index e1cc4117..d6d9e401 100644 --- a/server/src/actions/comment_view.rs +++ b/server/src/actions/comment_view.rs @@ -138,8 +138,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; diff --git a/server/src/actions/community.rs b/server/src/actions/community.rs index d179b9a2..ac331934 100644 --- a/server/src/actions/community.rs +++ b/server/src/actions/community.rs @@ -1,5 +1,5 @@ extern crate diesel; -use schema::{community, community_moderator, community_follower, community_user_ban}; +use schema::{community, community_moderator, community_follower, community_user_ban, site}; use diesel::*; use diesel::result::Error; use serde::{Deserialize, Serialize}; @@ -31,6 +31,34 @@ pub struct CommunityForm { pub updated: Option<chrono::NaiveDateTime> } +impl Crud<CommunityForm> for Community { + fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> { + use schema::community::dsl::*; + community.find(community_id) + .first::<Self>(conn) + } + + fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> { + use schema::community::dsl::*; + diesel::delete(community.find(community_id)) + .execute(conn) + } + + fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> { + use schema::community::dsl::*; + insert_into(community) + .values(new_community) + .get_result::<Self>(conn) + } + + fn update(conn: &PgConnection, community_id: i32, new_community: &CommunityForm) -> Result<Self, Error> { + use schema::community::dsl::*; + diesel::update(community.find(community_id)) + .set(new_community) + .get_result::<Self>(conn) + } +} + #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] #[belongs_to(Community)] #[table_name = "community_moderator"] @@ -48,6 +76,23 @@ pub struct CommunityModeratorForm { pub user_id: i32, } +impl Joinable<CommunityModeratorForm> for CommunityModerator { + fn join(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<Self, Error> { + use schema::community_moderator::dsl::*; + insert_into(community_moderator) + .values(community_user_form) + .get_result::<Self>(conn) + } + + fn leave(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<usize, Error> { + use schema::community_moderator::dsl::*; + diesel::delete(community_moderator + .filter(community_id.eq(community_user_form.community_id)) + .filter(user_id.eq(community_user_form.user_id))) + .execute(conn) + } +} + #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] #[belongs_to(Community)] #[table_name = "community_user_ban"] @@ -65,6 +110,23 @@ pub struct CommunityUserBanForm { pub user_id: i32, } +impl Bannable<CommunityUserBanForm> for CommunityUserBan { + fn ban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<Self, Error> { + use schema::community_user_ban::dsl::*; + insert_into(community_user_ban) + .values(community_user_ban_form) + .get_result::<Self>(conn) + } + + fn unban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<usize, Error> { + use schema::community_user_ban::dsl::*; + diesel::delete(community_user_ban + .filter(community_id.eq(community_user_ban_form.community_id)) + .filter(user_id.eq(community_user_ban_form.user_id))) + .execute(conn) + } +} + #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] #[belongs_to(Community)] #[table_name = "community_follower"] @@ -82,35 +144,6 @@ pub struct CommunityFollowerForm { pub user_id: i32, } - -impl Crud<CommunityForm> for Community { - fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> { - use schema::community::dsl::*; - community.find(community_id) - .first::<Self>(conn) - } - - fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> { - use schema::community::dsl::*; - diesel::delete(community.find(community_id)) - .execute(conn) - } - - fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> { - use schema::community::dsl::*; - insert_into(community) - .values(new_community) - .get_result::<Self>(conn) - } - - fn update(conn: &PgConnection, community_id: i32, new_community: &CommunityForm) -> Result<Self, Error> { - use schema::community::dsl::*; - diesel::update(community.find(community_id)) - .set(new_community) - .get_result::<Self>(conn) - } -} - impl Followable<CommunityFollowerForm> for CommunityFollower { fn follow(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<Self, Error> { use schema::community_follower::dsl::*; @@ -127,37 +160,50 @@ impl Followable<CommunityFollowerForm> for CommunityFollower { } } -impl Joinable<CommunityModeratorForm> for CommunityModerator { - fn join(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<Self, Error> { - use schema::community_moderator::dsl::*; - insert_into(community_moderator) - .values(community_user_form) - .get_result::<Self>(conn) +#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] +#[table_name="site"] +pub struct Site { + pub id: i32, + pub name: String, + pub description: Option<String>, + pub creator_id: i32, + pub published: chrono::NaiveDateTime, + pub updated: Option<chrono::NaiveDateTime> +} + +#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] +#[table_name="site"] +pub struct SiteForm { + pub name: String, + pub description: Option<String>, + pub creator_id: i32, + pub updated: Option<chrono::NaiveDateTime> +} + +impl Crud<SiteForm> for Site { + fn read(conn: &PgConnection, _site_id: i32) -> Result<Self, Error> { + use schema::site::dsl::*; + site.first::<Self>(conn) } - fn leave(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<usize, Error> { - use schema::community_moderator::dsl::*; - diesel::delete(community_moderator - .filter(community_id.eq(community_user_form.community_id)) - .filter(user_id.eq(community_user_form.user_id))) + fn delete(conn: &PgConnection, site_id: i32) -> Result<usize, Error> { + use schema::site::dsl::*; + diesel::delete(site.find(site_id)) .execute(conn) } -} -impl Bannable<CommunityUserBanForm> for CommunityUserBan { - fn ban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<Self, Error> { - use schema::community_user_ban::dsl::*; - insert_into(community_user_ban) - .values(community_user_ban_form) - .get_result::<Self>(conn) + fn create(conn: &PgConnection, new_site: &SiteForm) -> Result<Self, Error> { + use schema::site::dsl::*; + insert_into(site) + .values(new_site) + .get_result::<Self>(conn) } - fn unban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<usize, Error> { - use schema::community_user_ban::dsl::*; - diesel::delete(community_user_ban - .filter(community_id.eq(community_user_ban_form.community_id)) - .filter(user_id.eq(community_user_ban_form.user_id))) - .execute(conn) + fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result<Self, Error> { + use schema::site::dsl::*; + diesel::update(site.find(site_id)) + .set(new_site) + .get_result::<Self>(conn) } } @@ -177,8 +223,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; diff --git a/server/src/actions/community_view.rs b/server/src/actions/community_view.rs index 14f38302..078e7a6e 100644 --- a/server/src/actions/community_view.rs +++ b/server/src/actions/community_view.rs @@ -59,6 +59,21 @@ table! { } } +table! { + site_view (id) { + id -> Int4, + name -> Varchar, + description -> Nullable<Text>, + creator_id -> Int4, + published -> Timestamp, + updated -> Nullable<Timestamp>, + creator_name -> Varchar, + number_of_users -> BigInt, + number_of_posts -> BigInt, + number_of_comments -> BigInt, + } +} + #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[table_name="community_view"] pub struct CommunityView { @@ -204,3 +219,26 @@ impl CommunityUserBanView { .first::<Self>(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<String>, + pub creator_id: i32, + pub published: chrono::NaiveDateTime, + pub updated: Option<chrono::NaiveDateTime>, + pub creator_name: String, + pub number_of_users: i64, + pub number_of_posts: i64, + pub number_of_comments: i64, +} + +impl SiteView { + pub fn read(conn: &PgConnection) -> Result<Self, Error> { + use actions::community_view::site_view::dsl::*; + site_view.first::<Self>(conn) + } +} diff --git a/server/src/actions/moderator.rs b/server/src/actions/moderator.rs index 089c7ce5..a97b2120 100644 --- a/server/src/actions/moderator.rs +++ b/server/src/actions/moderator.rs @@ -415,8 +415,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; @@ -428,8 +428,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; diff --git a/server/src/actions/post.rs b/server/src/actions/post.rs index b811bf32..468b3a9b 100644 --- a/server/src/actions/post.rs +++ b/server/src/actions/post.rs @@ -119,8 +119,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; diff --git a/server/src/actions/post_view.rs b/server/src/actions/post_view.rs index 9b4395d3..0ebcf40d 100644 --- a/server/src/actions/post_view.rs +++ b/server/src/actions/post_view.rs @@ -165,8 +165,8 @@ mod tests { password_encrypted: "nope".into(), email: None, updated: None, - admin: None, - banned: None, + admin: false, + banned: false, }; let inserted_user = User_::create(&conn, &new_user).unwrap(); diff --git a/server/src/actions/user.rs b/server/src/actions/user.rs index 524fb66d..ea6f36e6 100644 --- a/server/src/actions/user.rs +++ b/server/src/actions/user.rs @@ -17,8 +17,8 @@ pub struct User_ { pub password_encrypted: String, pub email: Option<String>, pub icon: Option<Vec<u8>>, - pub admin: Option<bool>, - pub banned: Option<bool>, + pub admin: bool, + pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option<chrono::NaiveDateTime> } @@ -30,8 +30,8 @@ pub struct UserForm { pub fedi_name: String, pub preferred_username: Option<String>, pub password_encrypted: String, - pub admin: Option<bool>, - pub banned: Option<bool>, + pub admin: bool, + pub banned: bool, pub email: Option<String>, pub updated: Option<chrono::NaiveDateTime> } @@ -46,22 +46,26 @@ impl Crud<UserForm> for User_ { .execute(conn) } fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> { - let mut edited_user = form.clone(); - let password_hash = hash(&form.password_encrypted, DEFAULT_COST) - .expect("Couldn't hash password"); - edited_user.password_encrypted = password_hash; insert_into(user_) - .values(edited_user) + .values(form) .get_result::<Self>(conn) } fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> { + diesel::update(user_.find(user_id)) + .set(form) + .get_result::<Self>(conn) + } +} + +impl User_ { + pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> { let mut edited_user = form.clone(); let password_hash = hash(&form.password_encrypted, DEFAULT_COST) .expect("Couldn't hash password"); edited_user.password_encrypted = password_hash; - diesel::update(user_.find(user_id)) - .set(edited_user) - .get_result::<Self>(conn) + + Self::create(&conn, &edited_user) + } } @@ -126,8 +130,8 @@ mod tests { preferred_username: None, password_encrypted: "nope".into(), email: None, - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; @@ -138,11 +142,11 @@ mod tests { name: "thommy".into(), fedi_name: "rrf".into(), preferred_username: None, - password_encrypted: "$2y$12$YXpNpYsdfjmed.QlYLvw4OfTCgyKUnKHc/V8Dgcf9YcVKHPaYXYYy".into(), + password_encrypted: "nope".into(), email: None, icon: None, - admin: Some(false), - banned: Some(false), + admin: false, + banned: false, published: inserted_user.published, updated: None }; @@ -151,9 +155,9 @@ mod tests { let updated_user = User_::update(&conn, inserted_user.id, &new_user).unwrap(); let num_deleted = User_::delete(&conn, inserted_user.id).unwrap(); - assert_eq!(expected_user.id, read_user.id); - assert_eq!(expected_user.id, inserted_user.id); - assert_eq!(expected_user.id, updated_user.id); + assert_eq!(expected_user, read_user); + assert_eq!(expected_user, inserted_user); + assert_eq!(expected_user, updated_user); assert_eq!(1, num_deleted); } } diff --git a/server/src/actions/user_view.rs b/server/src/actions/user_view.rs index 4457e08a..a5187aee 100644 --- a/server/src/actions/user_view.rs +++ b/server/src/actions/user_view.rs @@ -8,8 +8,8 @@ table! { id -> Int4, name -> Varchar, fedi_name -> Varchar, - admin -> Nullable<Bool>, - banned -> Nullable<Bool>, + admin -> Bool, + banned -> Bool, published -> Timestamp, number_of_posts -> BigInt, post_score -> BigInt, @@ -24,8 +24,8 @@ pub struct UserView { pub id: i32, pub name: String, pub fedi_name: String, - pub admin: Option<bool>, - pub banned: Option<bool>, + pub admin: bool, + pub banned: bool, pub published: chrono::NaiveDateTime, pub number_of_posts: i64, pub post_score: i64, @@ -40,5 +40,17 @@ impl UserView { user_view.find(from_user_id) .first::<Self>(conn) } + + pub fn admins(conn: &PgConnection) -> Result<Vec<Self>, Error> { + use actions::user_view::user_view::dsl::*; + user_view.filter(admin.eq(true)) + .load::<Self>(conn) + } + + pub fn banned(conn: &PgConnection) -> Result<Vec<Self>, Error> { + use actions::user_view::user_view::dsl::*; + user_view.filter(banned.eq(true)) + .load::<Self>(conn) + } } diff --git a/server/src/apub.rs b/server/src/apub.rs index 9a535c0b..a9a417e2 100644 --- a/server/src/apub.rs +++ b/server/src/apub.rs @@ -44,8 +44,8 @@ mod tests { email: None, icon: None, published: naive_now(), - admin: None, - banned: None, + admin: false, + banned: false, updated: None }; diff --git a/server/src/schema.rs b/server/src/schema.rs index 873f32e8..f431610a 100644 --- a/server/src/schema.rs +++ b/server/src/schema.rs @@ -186,6 +186,17 @@ table! { } table! { + site (id) { + id -> Int4, + name -> Varchar, + description -> Nullable<Text>, + creator_id -> Int4, + published -> Timestamp, + updated -> Nullable<Timestamp>, + } +} + +table! { user_ (id) { id -> Int4, name -> Varchar, @@ -194,8 +205,8 @@ table! { password_encrypted -> Text, email -> Nullable<Text>, icon -> Nullable<Bytea>, - admin -> Nullable<Bool>, - banned -> Nullable<Bool>, + admin -> Bool, + banned -> Bool, published -> Timestamp, updated -> Nullable<Timestamp>, } @@ -236,6 +247,7 @@ joinable!(post -> community (community_id)); joinable!(post -> user_ (creator_id)); joinable!(post_like -> post (post_id)); joinable!(post_like -> user_ (user_id)); +joinable!(site -> user_ (creator_id)); joinable!(user_ban -> user_ (user_id)); allow_tables_to_appear_in_same_query!( @@ -256,6 +268,7 @@ allow_tables_to_appear_in_same_query!( mod_remove_post, post, post_like, + site, user_, user_ban, ); diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs index b3bdf78d..ef05f801 100644 --- a/server/src/websocket_server/server.rs +++ b/server/src/websocket_server/server.rs @@ -26,7 +26,7 @@ use actions::moderator::*; #[derive(EnumString,ToString,Debug)] pub enum UserOperation { - Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetModlog, BanFromCommunity, AddModToCommunity, + Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser } #[derive(Serialize, Deserialize)] @@ -88,7 +88,8 @@ pub struct Register { username: String, email: Option<String>, password: String, - password_verify: String + password_verify: String, + admin: bool, } #[derive(Serialize, Deserialize)] @@ -361,6 +362,67 @@ pub struct AddModToCommunityResponse { moderators: Vec<CommunityModeratorView>, } +#[derive(Serialize, Deserialize)] +pub struct CreateSite { + name: String, + description: Option<String>, + auth: String +} + +#[derive(Serialize, Deserialize)] +pub struct EditSite { + name: String, + description: Option<String>, + auth: String +} + +#[derive(Serialize, Deserialize)] +pub struct GetSite { +} + +#[derive(Serialize, Deserialize)] +pub struct SiteResponse { + op: String, + site: SiteView, +} + +#[derive(Serialize, Deserialize)] +pub struct GetSiteResponse { + op: String, + site: Option<SiteView>, + admins: Vec<UserView>, + banned: Vec<UserView>, +} + +#[derive(Serialize, Deserialize)] +pub struct AddAdmin { + user_id: i32, + added: bool, + auth: String +} + +#[derive(Serialize, Deserialize)] +pub struct AddAdminResponse { + op: String, + admins: Vec<UserView>, +} + +#[derive(Serialize, Deserialize)] +pub struct BanUser { + user_id: i32, + ban: bool, + reason: Option<String>, + expires: Option<i64>, + auth: String +} + +#[derive(Serialize, Deserialize)] +pub struct BanUserResponse { + op: String, + user: UserView, + banned: bool, +} + /// `ChatServer` manages chat rooms and responsible for coordinating chat /// session. implementation is super primitive pub struct ChatServer { @@ -563,6 +625,26 @@ impl Handler<StandardMessage> for ChatServer { let mod_add_to_community: AddModToCommunity = serde_json::from_str(data).unwrap(); mod_add_to_community.perform(self, msg.id) }, + UserOperation::CreateSite => { + let create_site: CreateSite = serde_json::from_str(data).unwrap(); + create_site.perform(self, msg.id) + }, + UserOperation::EditSite => { + let edit_site: EditSite = serde_json::from_str(data).unwrap(); + edit_site.perform(self, msg.id) + }, + UserOperation::GetSite => { + let get_site: GetSite = serde_json::from_str(data).unwrap(); + get_site.perform(self, msg.id) |