diff options
author | Dessalines <happydooby@gmail.com> | 2019-05-04 22:20:38 -0700 |
---|---|---|
committer | Dessalines <happydooby@gmail.com> | 2019-05-04 22:20:38 -0700 |
commit | fddcb43cdacb4b3df182deb621e280d64431db14 (patch) | |
tree | 7669da5b430bdf66406c6155403569f3da46f630 /server/src/websocket/server.rs | |
parent | 792301cab90261f7681d4066c34dbfb2faa14d53 (diff) |
Mostly done with reorg.
Diffstat (limited to 'server/src/websocket/server.rs')
-rw-r--r-- | server/src/websocket/server.rs | 2754 |
1 files changed, 172 insertions, 2582 deletions
diff --git a/server/src/websocket/server.rs b/server/src/websocket/server.rs index 07378d37..857c626a 100644 --- a/server/src/websocket/server.rs +++ b/server/src/websocket/server.rs @@ -7,41 +7,22 @@ use rand::{rngs::ThreadRng, Rng}; use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; use serde_json::{Value}; -use bcrypt::{verify}; use std::str::FromStr; -use diesel::PgConnection; use failure::Error; use std::time::{SystemTime}; -use {Crud, Joinable, Likeable, Followable, Bannable, Saveable, establish_connection, naive_now, naive_from_unix, SortType, SearchType, has_slurs, remove_slurs, Settings}; -use db::community::*; -use db::user::*; -use db::post::*; -use db::comment::*; -use db::post_view::*; -use db::comment_view::*; -use db::category::*; -use db::community_view::*; -use db::user_view::*; -use db::moderator_views::*; -use db::moderator::*; +use api::*; +use api::user::*; +use api::community::*; +use api::post::*; +use api::comment::*; +use api::site::*; const RATE_LIMIT_MESSAGES: i32 = 30; const RATE_LIMIT_PER_SECOND: i32 = 60; const RATE_LIMIT_REGISTER_MESSAGES: i32 = 1; const RATE_LIMIT_REGISTER_PER_SECOND: i32 = 60; -#[derive(EnumString,ToString,Debug)] -pub enum UserOperation { - Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead -} - -#[derive(Fail, Debug)] -#[fail(display = "{{\"op\":\"{}\", \"error\":\"{}\"}}", op, message)] -pub struct ErrorMessage { - op: String, - message: String -} /// Chat server sends this messages to session #[derive(Message)] @@ -87,414 +68,6 @@ impl actix::Message for StandardMessage { type Result = String; } -#[derive(Serialize, Deserialize)] -pub struct Login { - pub username_or_email: String, - pub password: String -} - -#[derive(Serialize, Deserialize)] -pub struct Register { - username: String, - email: Option<String>, - password: String, - password_verify: String, - admin: bool, - spam_timeri: i64, -} - -#[derive(Serialize, Deserialize)] -pub struct LoginResponse { - op: String, - jwt: String -} - -#[derive(Serialize, Deserialize)] -pub struct CreateCommunity { - name: String, - title: String, - description: Option<String>, - category_id: i32 , - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct CommunityResponse { - op: String, - community: CommunityView -} - -#[derive(Serialize, Deserialize)] -pub struct ListCommunities { - sort: String, - page: Option<i64>, - limit: Option<i64>, - auth: Option<String> -} - -#[derive(Serialize, Deserialize)] -pub struct ListCommunitiesResponse { - op: String, - communities: Vec<CommunityView> -} - -#[derive(Serialize, Deserialize)] -pub struct ListCategories; - -#[derive(Serialize, Deserialize)] -pub struct ListCategoriesResponse { - op: String, - categories: Vec<Category> -} - -#[derive(Serialize, Deserialize)] -pub struct CreatePost { - name: String, - url: Option<String>, - body: Option<String>, - community_id: i32, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct PostResponse { - op: String, - post: PostView -} - - -#[derive(Serialize, Deserialize)] -pub struct GetPost { - id: i32, - auth: Option<String> -} - -#[derive(Serialize, Deserialize)] -pub struct GetPostResponse { - op: String, - post: PostView, - comments: Vec<CommentView>, - community: CommunityView, - moderators: Vec<CommunityModeratorView>, - admins: Vec<UserView>, -} - -#[derive(Serialize, Deserialize)] -pub struct GetPosts { - type_: String, - sort: String, - page: Option<i64>, - limit: Option<i64>, - community_id: Option<i32>, - auth: Option<String> -} - -#[derive(Serialize, Deserialize)] -pub struct GetPostsResponse { - op: String, - posts: Vec<PostView>, -} - -#[derive(Serialize, Deserialize)] -pub struct GetCommunity { - id: Option<i32>, - name: Option<String>, - auth: Option<String> -} - -#[derive(Serialize, Deserialize)] -pub struct GetCommunityResponse { - op: String, - community: CommunityView, - moderators: Vec<CommunityModeratorView>, - admins: Vec<UserView>, -} - -#[derive(Serialize, Deserialize)] -pub struct CreateComment { - content: String, - parent_id: Option<i32>, - edit_id: Option<i32>, - post_id: i32, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct EditComment { - content: String, - parent_id: Option<i32>, - edit_id: i32, - creator_id: i32, - post_id: i32, - removed: Option<bool>, - deleted: Option<bool>, - reason: Option<String>, - read: Option<bool>, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct SaveComment { - comment_id: i32, - save: bool, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct CommentResponse { - op: String, - comment: CommentView -} - -#[derive(Serialize, Deserialize)] -pub struct CreateCommentLike { - comment_id: i32, - post_id: i32, - score: i16, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct CreatePostLike { - post_id: i32, - score: i16, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct CreatePostLikeResponse { - op: String, - post: PostView -} - - -#[derive(Serialize, Deserialize)] -pub struct EditPost { - edit_id: i32, - creator_id: i32, - community_id: i32, - name: String, - url: Option<String>, - body: Option<String>, - removed: Option<bool>, - deleted: Option<bool>, - locked: Option<bool>, - reason: Option<String>, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct SavePost { - post_id: i32, - save: bool, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct EditCommunity { - edit_id: i32, - name: String, - title: String, - description: Option<String>, - category_id: i32, - removed: Option<bool>, - deleted: Option<bool>, - reason: Option<String>, - expires: Option<i64>, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct FollowCommunity { - community_id: i32, - follow: bool, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct GetFollowedCommunities { - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct GetFollowedCommunitiesResponse { - op: String, - communities: Vec<CommunityFollowerView> -} - -#[derive(Serialize, Deserialize)] -pub struct GetUserDetails { - user_id: Option<i32>, - username: Option<String>, - sort: String, - page: Option<i64>, - limit: Option<i64>, - community_id: Option<i32>, - saved_only: bool, - auth: Option<String>, -} - -#[derive(Serialize, Deserialize)] -pub struct GetUserDetailsResponse { - op: String, - user: UserView, - follows: Vec<CommunityFollowerView>, - moderates: Vec<CommunityModeratorView>, - comments: Vec<CommentView>, - posts: Vec<PostView>, -} - -#[derive(Serialize, Deserialize)] -pub struct GetModlog { - mod_user_id: Option<i32>, - community_id: Option<i32>, - page: Option<i64>, - limit: Option<i64>, -} - -#[derive(Serialize, Deserialize)] -pub struct GetModlogResponse { - op: String, - removed_posts: Vec<ModRemovePostView>, - locked_posts: Vec<ModLockPostView>, - removed_comments: Vec<ModRemoveCommentView>, - removed_communities: Vec<ModRemoveCommunityView>, - banned_from_community: Vec<ModBanFromCommunityView>, - banned: Vec<ModBanView>, - added_to_community: Vec<ModAddCommunityView>, - added: Vec<ModAddView>, -} - -#[derive(Serialize, Deserialize)] -pub struct BanFromCommunity { - community_id: i32, - user_id: i32, - ban: bool, - reason: Option<String>, - expires: Option<i64>, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct BanFromCommunityResponse { - op: String, - user: UserView, - banned: bool, -} - - -#[derive(Serialize, Deserialize)] -pub struct AddModToCommunity { - community_id: i32, - user_id: i32, - added: bool, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct AddModToCommunityResponse { - op: String, - 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, -} - -#[derive(Serialize, Deserialize)] -pub struct GetReplies { - sort: String, - page: Option<i64>, - limit: Option<i64>, - unread_only: bool, - auth: String -} - -#[derive(Serialize, Deserialize)] -pub struct GetRepliesResponse { - op: String, - replies: Vec<ReplyView>, -} - -#[derive(Serialize, Deserialize)] -pub struct Search { - q: String, - type_: String, - community_id: Option<i32>, - sort: String, - page: Option<i64>, - limit: Option<i64>, -} - -#[derive(Serialize, Deserialize)] -pub struct SearchResponse { - op: String, - comments: Vec<CommentView>, - posts: Vec<PostView>, -} - -#[derive(Serialize, Deserialize)] -pub struct MarkAllAsRead { - auth: String -} - #[derive(Debug)] pub struct RateLimitBucket { last_checked: SystemTime, @@ -543,8 +116,25 @@ impl ChatServer { } } - fn send_community_message(&self, conn: &PgConnection, community_id: i32, message: &str, skip_id: usize) -> Result<(), Error> { - let posts = PostView::list(conn, + fn join_room(&self, room_id: i32, id: usize) { + // remove session from all rooms + for (_n, sessions) in &mut self.rooms { + sessions.remove(&id); + } + + // If the room doesn't exist yet + if self.rooms.get_mut(&room_id).is_none() { + self.rooms.insert(room_id, HashSet::new()); + } + + self.rooms.get_mut(&room_id).unwrap().insert(id); + } + + fn send_community_message(&self, community_id: i32, message: &str, skip_id: usize) -> Result<(), Error> { + use db::*; + use db::post_view::*; + let conn = establish_connection(); + let posts = PostView::list(&conn, PostListingType::Community, &SortType::New, Some(community_id), @@ -562,16 +152,16 @@ impl ChatServer { Ok(()) } - fn check_rate_limit_register(&mut self, addr: usize) -> Result<(), Error> { - self.check_rate_limit_full(addr, RATE_LIMIT_REGISTER_MESSAGES, RATE_LIMIT_REGISTER_PER_SECOND) + fn check_rate_limit_register(&mut self, id: usize) -> Result<(), Error> { + self.check_rate_limit_full(id, RATE_LIMIT_REGISTER_MESSAGES, RATE_LIMIT_REGISTER_PER_SECOND) } - fn check_rate_limit(&mut self, addr: usize) -> Result<(), Error> { - self.check_rate_limit_full(addr, RATE_LIMIT_MESSAGES, RATE_LIMIT_PER_SECOND) + fn check_rate_limit(&mut self, id: usize) -> Result<(), Error> { + self.check_rate_limit_full(id, RATE_LIMIT_MESSAGES, RATE_LIMIT_PER_SECOND) } - fn check_rate_limit_full(&mut self, addr: usize, rate: i32, per: i32) -> Result<(), Error> { - if let Some(info) = self.sessions.get(&addr) { + fn check_rate_limit_full(&mut self, id: usize, rate: i32, per: i32) -> Result<(), Error> { + if let Some(info) = self.sessions.get(&id) { if let Some(rate_limit) = self.rate_limits.get_mut(&info.ip) { // The initial value if rate_limit.allowance == -2f64 { @@ -588,7 +178,7 @@ impl ChatServer { if rate_limit.allowance < 1.0 { println!("Rate limited IP: {}, time_passed: {}, allowance: {}", &info.ip, time_passed, rate_limit.allowance); - Err(ErrorMessage { + Err(APIError { op: "Rate Limit".to_string(), message: format!("Too many requests. {} per {} seconds", rate, per), })? @@ -652,7 +242,6 @@ impl Handler<Connect> for ChatServer { } } - /// Handler for Disconnect message. impl Handler<Disconnect> for ChatServer { type Result = (); @@ -700,2192 +289,193 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str match user_operation { UserOperation::Login => { let login: Login = serde_json::from_str(data)?; - login.perform(chat, msg.id) + let res = Oper::new(user_operation, login).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::Register => { + chat.check_rate_limit_register(msg.id)?; let register: Register = serde_json::from_str(data)?; - register.perform(chat, msg.id) + let res = Oper::new(user_operation, register).perform()?; + Ok(serde_json::to_string(&res)?) }, - UserOperation::CreateCommunity => { - let create_community: CreateCommunity = serde_json::from_str(data)?; - create_community.perform(chat, msg.id) + UserOperation::GetUserDetails => { + let get_user_details: GetUserDetails = serde_json::from_str(data)?; + let res = Oper::new(user_operation, get_user_details).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::AddAdmin => { + let add_admin: AddAdmin = serde_json::from_str(data)?; + let res = Oper::new(user_operation, add_admin).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::BanUser => { + let ban_user: BanUser = serde_json::from_str(data)?; + let res = Oper::new(user_operation, ban_user).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::GetReplies => { + let get_replies: GetReplies = serde_json::from_str(data)?; + let res = Oper::new(user_operation, get_replies).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::MarkAllAsRead => { + let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?; + let res = Oper::new(user_operation, mark_all_as_read).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::GetCommunity => { + let get_community: GetCommunity = serde_json::from_str(data)?; + let res = Oper::new(user_operation, get_community).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::ListCommunities => { let list_communities: ListCommunities = serde_json::from_str(data)?; - list_communities.perform(chat, msg.id) + let res = Oper::new(user_operation, list_communities).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::CreateCommunity => { + chat.check_rate_limit_register(msg.id)?; + let create_community: CreateCommunity = serde_json::from_str(data)?; + let res = Oper::new(user_operation, create_community).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::EditCommunity => { + let edit_community: EditCommunity = serde_json::from_str(data)?; + let res = Oper::new(user_operation, edit_community).perform()?; + let mut community_sent: CommunityResponse = res.clone(); + community_sent.community.user_id = None; + community_sent.community.subscribed = None; + let community_sent_str = serde_json::to_string(&community_sent)?; + chat.send_community_message(edit_community.edit_id, &community_sent_str, msg.id)?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::FollowCommunity => { + let follow_community: FollowCommunity = serde_json::from_str(data)?; + let res = Oper::new(user_operation, follow_community).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::GetFollowedCommunities => { + let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?; + let res = Oper::new(user_operation, followed_communities).perform()?; + Ok(serde_json::to_string(&res)?) + }, + UserOperation::BanFromCommunity => { + let ban_from_community: BanFromCommunity = serde_json::from_str(data)?; + let res = Oper::new(user_operation, ban_from_community).perform()?; + let res_str = serde_json::to_string(&res)?; + chat.send_community_message(ban_from_community.community_id, &res_str, msg.id)?; + Ok(res_str) + }, + UserOperation::AddModToCommunity => { + let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?; + let res = Oper::new(user_operation, mod_add_to_community).perform()?; + let res_str = serde_json::to_string(&res)?; + chat.send_community_message(mod_add_to_community.community_id, &res_str, msg.id)?; + Ok(res_str) }, UserOperation::ListCategories => { let list_categories: ListCategories = ListCategories; - list_categories.perform(chat, msg.id) + let res = Oper::new(user_operation, list_categories).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::CreatePost => { + chat.check_rate_limit_register(msg.id)?; let create_post: CreatePost = serde_json::from_str(data)?; - create_post.perform(chat, msg.id) + let res = Oper::new(user_operation, create_post).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::GetPost => { let get_post: GetPost = serde_json::from_str(data)?; - get_post.perform(chat, msg.id) - }, - UserOperation::GetCommunity => { - let get_community: GetCommunity = serde_json::from_str(data)?; - get_community.perform(chat, msg.id) - }, - UserOperation::CreateComment => { - let create_comment: CreateComment = serde_json::from_str(data)?; - create_comment.perform(chat, msg.id) - }, - UserOperation::EditComment => { - let edit_comment: EditComment = serde_json::from_str(data)?; - edit_comment.perform(chat, msg.id) - }, - UserOperation::SaveComment => { - let save_post: SaveComment = serde_json::from_str(data)?; - save_post.perform(chat, msg.id) - }, - UserOperation::CreateCommentLike => { - let create_comment_like: CreateCommentLike = serde_json::from_str(data)?; - create_comment_like.perform(chat, msg.id) + chat.join_room(get_post.id, msg.id); + let res = Oper::new(user_operation, get_post).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::GetPosts => { let get_posts: GetPosts = serde_json::from_str(data)?; - get_posts.perform(chat, msg.id) + let res = Oper::new(user_operation, get_posts).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::CreatePostLike => { + chat.check_rate_limit(msg.id)?; let create_post_like: CreatePostLike = serde_json::from_str(data)?; - create_post_like.perform(chat, msg.id) + let res = Oper::new(user_operation, create_post_like).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::EditPost => { let edit_post: EditPost = serde_json::from_str(data)?; - edit_post.perform(chat, msg.id) + let res = Oper::new(user_operation, edit_post).perform()?; + let mut post_sent = res.clone(); + post_sent.post.my_vote = None; + let post_sent_str = serde_json::to_string(&post_sent)?; + chat.send_room_message(edit_post.edit_id, &post_sent_str, msg.id); + Ok(serde_json::to_string(&res)?) }, UserOperation::SavePost => { let save_post: SavePost = serde_json::from_str(data)?; - save_post.perform(chat, msg.id) + let res = Oper::new(user_operation, save_post).perform()?; + Ok(serde_json::to_string(&res)?) }, - UserOperation::EditCommunity => { - let edit_community: EditCommunity = serde_json::from_str(data)?; - edit_community.perform(chat, msg.id) + UserOperation::CreateComment => { + chat.check_rate_limit(msg.id)?; + let create_comment: CreateComment = serde_json::from_str(data)?; + let res = Oper::new(user_operation, create_comment).perform()?; + let mut comment_sent = res.clone(); + comment_sent.comment.my_vote = None; + comment_sent.comment.user_id = None; + let comment_sent_str = serde_json::to_string(&comment_sent)?; + chat.send_room_message(create_comment.post_id, &comment_sent_str, msg.id); + Ok(serde_json::to_string(&res)?) }, - UserOperation::FollowCommunity => { - let follow_community: FollowCommunity = serde_json::from_str(data)?; - follow_community.perform(chat, msg.id) + UserOperation::EditComment => { + let edit_comment: EditComment = serde_json::from_str(data)?; + let res = Oper::new(user_operation, edit_comment).perform()?; + let mut comment_sent = res.clone(); + comment_sent.comment.my_vote = None; + comment_sent.comment.user_id = None; + let comment_sent_str = serde_json::to_string(&comment_sent)?; + chat.send_room_message(edit_comment.post_id, &comment_sent_str, msg.id); + Ok(serde_json::to_string(&res)?) }, - UserOperation::GetFollowedCommunities => { - let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?; - followed_communities.perform(chat, msg.id) + UserOperation::SaveComment => { + let save_comment: SaveComment = serde_json::from_str(data)?; + let res = Oper::new(user_operation, save_comment).perform()?; + Ok(serde_json::to_string(&res)?) }, - UserOperation::GetUserDetails => { - let get_user_details: GetUserDetails = serde_json::from_str(data)?; - get_user_details.perform(chat, msg.id) + UserOperation::CreateCommentLike => { + chat.check_rate_limit(msg.id)?; + let create_comment_like: CreateCommentLike = serde_json::from_str(data)?; + let res = Oper::new(user_operation, create_comment_like).perform()?; + let mut comment_sent = res.clone(); + comment_sent.comment.my_vote = None; + comment_sent.comment.user_id = None; + let comment_sent_str = serde_json::to_string(&comment_sent)?; + chat.send_room_message(create_comment_like.post_id, &comment_sent_str, msg.id); + Ok(serde_json::to_string(&res)?) }, UserOperation::GetModlog => { let get_modlog: GetModlog = serde_json::from_str(data)?; - get_modlog.perform(chat, msg.id) - }, - UserOperation::BanFromCommunity => { - let ban_from_community: BanFromCommunity = serde_json::from_str(data)?; - ban_from_community.perform(chat, msg.id) - }, - UserOperation::AddModToCommunity => { - let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?; - mod_add_to_community.perform(chat, msg.id) + let res = Oper::new(user_operation, get_modlog).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::CreateSite => { let create_site: CreateSite = serde_json::from_str(data)?; - create_site.perform(chat, msg.id) + let res = Oper::new(user_operation, create_site).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::EditSite => { let edit_site: EditSite = serde_json::from_str(data)?; - edit_site.perform(chat, msg.id) + let res = Oper::new(user_operation, edit_site).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::GetSite => { let get_site: GetSite = serde_json::from_str(data)?; - get_site.perform(chat, msg.id) - }, - UserOperation::AddAdmin => { - let add_admin: AddAdmin = serde_json::from_str(data)?; - add_admin.perform(chat, msg.id) - }, - UserOperation::BanUser => { - let ban_user: BanUser = serde_json::from_str(data)?; - ban_user.perform(chat, msg.id) - }, - UserOperation::GetReplies => { - let get_replies: GetReplies = serde_json::from_str(data)?; - get_replies.perform(chat, msg.id) + let res = Oper::new(user_operation, get_site).perform()?; + Ok(serde_json::to_string(&res)?) }, UserOperation::Search => { let search: Search = serde_json::from_str(data)?; - search.perform(chat, msg.id) - }, - UserOperation::MarkAllAsRead => { - let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?; - mark_all_as_read.perform(chat, msg.id) + let res = Oper::new(user_operation, search).perform()?; + Ok(serde_json::to_string(&res)?) }, } } - -pub trait Perform { - fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error>; - fn op_type(&self) -> UserOperation; - fn error(&self, error_msg: &str) -> ErrorMessage { - ErrorMessage { - op: self.op_type().to_string(), - message: error_msg.to_string() - } - } -} - -impl Perform for Login { - - fn op_type(&self) -> UserOperation { - UserOperation::Login - } - - fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> { - - let conn = establish_connection(); - - // Fetch that username / email - let user: User_ = match User_::find_by_email_or_username(&conn, &self.username_or_email) { - Ok(user) => user, - Err(_e) => return Err(self.error("Couldn't find that username or email"))? - }; - - // Verify the password - let valid: bool = verify(&self.password, &user.password_encrypted).unwrap_or(false); - if !valid { - return Err(self.error("Password incorrect"))? - } - - // Return the jwt - Ok( - serde_json::to_string( - &LoginResponse { - op: self.op_type().to_string(), - jwt: user.jwt() - } - )? - ) - } - -} - -impl Perform for Register { - fn op_type(&self) -> UserOperation { - UserOperation::Register - } - fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> { - - let conn = establish_connection(); - - chat.check_rate_limit_register(addr)?; - - // Make sure passwords match - if &self.password != &self.password_verify { - return Err(self.error("Passwords do not match."))? - } - - if self.spam_timeri < 1142 { - return Err(self.error("Too fast"))? - } - - if has_slurs(&self.username) { - return Err(self.error("No slurs"))? - } - - // Make sure there are no admins - if self.admin && UserView::admins(&conn)?.len() > 0 { - return Err(self.error("Sorry, there's already an admin."))? - } - - // Register the new user - let user_form = UserForm { - name: self.username.to_owned(), - fedi_name: Settings::get().hostname.into(), - email: self.email.to_owned(), - password_encrypted: self.password.to_owned(), - preferred_username: None, - updated: None, - admin: self.admin, - banned: false, - }; - - // Create the user - let inserted_user = match User_::register(&conn, &user_form) { - Ok(user) => user, - Err(_e) => { - return Err(self.error("User already exists."))? - } - }; - - // Sign them up for main community no matter what - let community_follower_form = CommunityFollowerForm { - community_id: 1, - user_id: inserted_user.id, - }; - - let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) { - Ok(user) => user, - Err(_e) => { - return Err(self.error("Community follower already exists."))? - } - }; - - // If its an admin, add them as a mod and follower to main - if self.admin { - let community_moderator_form = CommunityModeratorForm { - community_id: 1, - user_id: inserted_user.id, - }; - - let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { - Ok(user) => user, - Err(_e) => { - return Err(self.error("Community moderator already exists."))? - } - }; - - } - - - // Return the jwt - Ok( - serde_json::to_string( - &LoginResponse { - op: self.op_type().to_string(), - jwt: inserted_user.jwt() - } - )? - ) - - } -} - -impl Perform for CreateCommunity { - fn op_type(&self) -> UserOperation { - UserOperation::CreateCommunity - } - - fn perform(&self, chat: &mut ChatServer, addr: usize) -> Result<String, Error> { - - let conn = establish_connection(); - - chat.check_rate_limit_register(addr)?; - - let claims = match Claims::decode(&self.auth) { - Ok(claims) => claims.claims, - Err(_e) => { - return Err(self.error("Not logged in."))? - } - }; - - if has_slurs(&self.name) || - has_slurs(&self.title) || - (self.description.is_some() && has_slurs(&self.description.to_owned().unwrap())) { - return Err(self.error("No slurs"))? - } - - let user_id = claims.id; - - // Check for a site ban - if UserView::read(&conn, user_id)?.banned { - return Err(self.error("You have been banned from the site"))? - } - - // When you create a community, make sure the user becomes a moderator and a follower - let community_form = CommunityForm { - name: self.name.to_owned(), - title: self.title.to_owned(), - description: self.description.to_owned(), - category_id: self.category_id, - creator_id: user_id, - removed: None, - deleted: None, - updated: None, - }; - - let inserted_community = match Community::create(&conn, &community_form) { - Ok(community) => community, - Err(_e) => { - return Err(self.error("Community already exists."))? - } - }; - - let community_moderator_form = CommunityModeratorForm { - community_id: inserted_community.id, - user_id: user_id - }; - - let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { - Ok(user) => user, - Err(_e) => { - return Err(self.error("Community moderator already exists."))? - } - }; - - let community_follower_form = CommunityFollowerForm { - community_id: inserted_community.id, - user_id: user_id - }; - - let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) { - Ok(user) => user, - Err(_e) => { - return Err(self.error("Community follower already exists."))? - } - }; - - let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?; - - Ok( - serde_json::to_string( - &CommunityResponse { - op: self.op_type().to_string(), - community: community_view - } - )? - ) - } -} - -impl Perform for ListCommunities { - fn op_type(&self) -> UserOperation { - UserOperation::ListCommunities - } - - fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> { - - let conn = establish_connection(); - - let user_id: Option<i32> = match &self.auth { - Some(auth) => { - match Claims::decode(&auth) { - Ok(claims) => { - let user_id = claims.claims.id; - Some(user_id) - } - Err(_e) => None - } - } - None => None - }; - - let sort = SortType::from_str(&self.sort)?; - - let communities: Vec<CommunityView> = CommunityView::list(&conn, user_id, sort, self.page, self.limit)?; - - // Return the jwt - Ok( - serde_json::to_string( - &ListCommunitiesResponse { - op: self.op_type().to_string(), - communities: communities - } - )? - ) - } -} - -impl Perform for ListCategories { - fn op_type(&self) -> UserOperation { - UserOperation::ListCategories - } - - fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> { - - let conn = establish_connection(); - - let categories: Vec<Category> = Category::list_all(&conn)?; - - // Return the jwt - Ok( - serde_json::to_string( - &ListCategoriesResponse { - op: self.op_type().to_str |