diff options
author | Dessalines <tyhou13@gmx.com> | 2019-05-04 22:20:38 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-05-04 22:20:38 -0700 |
commit | 7fb6a0b1387d4c256061fd9402ac8405fcedcf83 (patch) | |
tree | 3b239ae2802cf2a1c1429144b75f295e341f8e9f /server/src | |
parent | 1a884a83534accf800f228e050b8fcf9338f6e4b (diff) |
Mostly done with reorg.
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/api/comment.rs | 316 | ||||
-rw-r--r-- | server/src/api/community.rs | 559 | ||||
-rw-r--r-- | server/src/api/mod.rs | 60 | ||||
-rw-r--r-- | server/src/api/post.rs | 469 | ||||
-rw-r--r-- | server/src/api/site.rs | 336 | ||||
-rw-r--r-- | server/src/api/user.rs | 503 | ||||
-rw-r--r-- | server/src/db/category.rs | 13 | ||||
-rw-r--r-- | server/src/db/comment.rs | 6 | ||||
-rw-r--r-- | server/src/db/comment_view.rs | 7 | ||||
-rw-r--r-- | server/src/db/community.rs | 6 | ||||
-rw-r--r-- | server/src/db/community_view.rs | 6 | ||||
-rw-r--r-- | server/src/db/mod.rs | 72 | ||||
-rw-r--r-- | server/src/db/moderator.rs | 6 | ||||
-rw-r--r-- | server/src/db/moderator_views.rs | 6 | ||||
-rw-r--r-- | server/src/db/post.rs | 6 | ||||
-rw-r--r-- | server/src/db/post_view.rs | 7 | ||||
-rw-r--r-- | server/src/db/user.rs | 7 | ||||
-rw-r--r-- | server/src/db/user_view.rs | 5 | ||||
-rw-r--r-- | server/src/lib.rs | 83 | ||||
-rw-r--r-- | server/src/websocket/server.rs | 2754 |
20 files changed, 2506 insertions, 2721 deletions
diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs new file mode 100644 index 00000000..36a44b36 --- /dev/null +++ b/server/src/api/comment.rs @@ -0,0 +1,316 @@ +use super::*; + +#[derive(Serialize, Deserialize)] +pub struct CreateComment { + content: String, + parent_id: Option<i32>, + edit_id: Option<i32>, + pub post_id: i32, + auth: String +} + +#[derive(Serialize, Deserialize)] +pub struct EditComment { + content: String, + parent_id: Option<i32>, + edit_id: i32, + creator_id: i32, + pub 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, Clone)] +pub struct CommentResponse { + op: String, + pub comment: CommentView +} + +#[derive(Serialize, Deserialize)] +pub struct CreateCommentLike { + comment_id: i32, + pub post_id: i32, + score: i16, + auth: String +} + + +impl Perform<CommentResponse> for Oper<CreateComment> { + fn perform(&self) -> Result<CommentResponse, Error> { + let data: CreateComment = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + // Check for a community ban + let post = Post::read(&conn, data.post_id)?; + if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { + return Err(APIError::err(self.op, "You have been banned from this community"))? + } + + // Check for a site ban + if UserView::read(&conn, user_id)?.banned { + return Err(APIError::err(self.op, "You have been banned from the site"))? + } + + let content_slurs_removed = remove_slurs(&data.content.to_owned()); + + let comment_form = CommentForm { + content: content_slurs_removed, + parent_id: data.parent_id.to_owned(), + post_id: data.post_id, + creator_id: user_id, + removed: None, + deleted: None, + read: None, + updated: None + }; + + let inserted_comment = match Comment::create(&conn, &comment_form) { + Ok(comment) => comment, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't create Comment"))? + } + }; + + // You like your own comment by default + let like_form = CommentLikeForm { + comment_id: inserted_comment.id, + post_id: data.post_id, + user_id: user_id, + score: 1 + }; + + let _inserted_like = match CommentLike::like(&conn, &like_form) { + Ok(like) => like, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't like comment."))? + } + }; + + let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?; + + Ok( + CommentResponse { + op: self.op.to_string(), + comment: comment_view + } + ) + } +} + +impl Perform<CommentResponse> for Oper<EditComment> { + fn perform(&self) -> Result<CommentResponse, Error> { + let data: EditComment = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + let orig_comment = CommentView::read(&conn, data.edit_id, None)?; + + // You are allowed to mark the comment as read even if you're banned. + if data.read.is_none() { + + // Verify its the creator or a mod, or an admin + let mut editors: Vec<i32> = vec![data.creator_id]; + editors.append( + &mut CommunityModeratorView::for_community(&conn, orig_comment.community_id) + ? + .into_iter() + .map(|m| m.user_id) + .collect() + ); + editors.append( + &mut UserView::admins(&conn) + ? + .into_iter() + .map(|a| a.id) + .collect() + ); + + if !editors.contains(&user_id) { + return Err(APIError::err(self.op, "Not allowed to edit comment."))? + } + + // Check for a community ban + if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() { + return Err(APIError::err(self.op, "You have been banned from this community"))? + } + + // Check for a site ban + if UserView::read(&conn, user_id)?.banned { + return Err(APIError::err(self.op, "You have been banned from the site"))? + } + + } + + let content_slurs_removed = remove_slurs(&data.content.to_owned()); + + let comment_form = CommentForm { + content: content_slurs_removed, + parent_id: data.parent_id, + post_id: data.post_id, + creator_id: data.creator_id, + removed: data.removed.to_owned(), + deleted: data.deleted.to_owned(), + read: data.read.to_owned(), + updated: if data.read.is_some() { orig_comment.updated } else {Some(naive_now())} + }; + + let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) { + Ok(comment) => comment, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't update Comment"))? + } + }; + + // Mod tables + if let Some(removed) = data.removed.to_owned() { + let form = ModRemoveCommentForm { + mod_user_id: user_id, + comment_id: data.edit_id, + removed: Some(removed), + reason: data.reason.to_owned(), + }; + ModRemoveComment::create(&conn, &form)?; + } + + + let comment_view = CommentView::read(&conn, data.edit_id, Some(user_id))?; + + Ok( + CommentResponse { + op: self.op.to_string(), + comment: comment_view + } + ) + + } +} + +impl Perform<CommentResponse> for Oper<SaveComment> { + fn perform(&self) -> Result<CommentResponse, Error> { + let data: SaveComment = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + let comment_saved_form = CommentSavedForm { + comment_id: data.comment_id, + user_id: user_id, + }; + + if data.save { + match CommentSaved::save(&conn, &comment_saved_form) { + Ok(comment) => comment, + Err(_e) => { + return Err(APIError::err(self.op, "Couldnt do comment save"))? + } + }; + } else { + match CommentSaved::unsave(&conn, &comment_saved_form) { + Ok(comment) => comment, + Err(_e) => { + return Err(APIError::err(self.op, "Couldnt do comment save"))? + } + }; + } + + let comment_view = CommentView::read(&conn, data.comment_id, Some(user_id))?; + + Ok( + CommentResponse { + op: self.op.to_string(), + comment: comment_view + } + ) + } +} + +impl Perform<CommentResponse> for Oper<CreateCommentLike> { + fn perform(&self) -> Result<CommentResponse, Error> { + let data: CreateCommentLike = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + // Check for a community ban + let post = Post::read(&conn, data.post_id)?; + if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { + return Err(APIError::err(self.op, "You have been banned from this community"))? + } + + // Check for a site ban + if UserView::read(&conn, user_id)?.banned { + return Err(APIError::err(self.op, "You have been banned from the site"))? + } + + let like_form = CommentLikeForm { + comment_id: data.comment_id, + post_id: data.post_id, + user_id: user_id, + score: data.score + }; + + // Remove any likes first + CommentLike::remove(&conn, &like_form)?; + + // Only add the like if the score isnt 0 + if &like_form.score != &0 { + let _inserted_like = match CommentLike::like(&conn, &like_form) { + Ok(like) => like, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't like comment."))? + } + }; + } + + // Have to refetch the comment to get the current state + let liked_comment = CommentView::read(&conn, data.comment_id, Some(user_id))?; + + Ok( + CommentResponse { + op: self.op.to_string(), + comment: liked_comment + } + ) + } +} diff --git a/server/src/api/community.rs b/server/src/api/community.rs new file mode 100644 index 00000000..5059b17f --- /dev/null +++ b/server/src/api/community.rs @@ -0,0 +1,559 @@ +use super::*; +use std::str::FromStr; + +#[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 CreateCommunity { + name: String, + title: String, + description: Option<String>, + category_id: i32 , + auth: String +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct CommunityResponse { + op: String, + pub 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 BanFromCommunity { + pub 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 { + pub 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 EditCommunity { + pub 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> +} + +impl Perform<GetCommunityResponse> for Oper<GetCommunity> { + fn perform(&self) -> Result<GetCommunityResponse, Error> { + let data: GetCommunity = self.data; + let conn = establish_connection(); + + let user_id: Option<i32> = match &data.auth { + Some(auth) => { + match Claims::decode(&auth) { + Ok(claims) => { + let user_id = claims.claims.id; + Some(user_id) + } + Err(_e) => None + } + } + None => None + }; + + let community_id = match data.id { + Some(id) => id, + None => Community::read_from_name(&conn, data.name.to_owned().unwrap_or("main".to_string()))?.id + }; + + let community_view = match CommunityView::read(&conn, community_id, user_id) { + Ok(community) => community, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't find Community"))? + } + }; + + let moderators = match CommunityModeratorView::for_community(&conn, community_id) { + Ok(moderators) => moderators, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't find Community"))? + } + }; + + let admins = UserView::admins(&conn)?; + + // Return the jwt + Ok( + GetCommunityResponse { + op: self.op.to_string(), + community: community_view, + moderators: moderators, + admins: admins, + } + ) + } +} + +impl Perform<CommunityResponse> for Oper<CreateCommunity> { + fn perform(&self) -> Result<CommunityResponse, Error> { + let data: CreateCommunity = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + if has_slurs(&data.name) || + has_slurs(&data.title) || + (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { + return Err(APIError::err(self.op, "No slurs"))? + } + + let user_id = claims.id; + + // Check for a site ban + if UserView::read(&conn, user_id)?.banned { + return Err(APIError::err(self.op, "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: data.name.to_owned(), + title: data.title.to_owned(), + description: data.description.to_owned(), + category_id: data.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(APIError::err(self.op, "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(APIError::err(self.op, "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(APIError::err(self.op, "Community follower already exists."))? + } + }; + + let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?; + + Ok( + CommunityResponse { + op: self.op.to_string(), + community: community_view + } + ) + } +} + +impl Perform<CommunityResponse> for Oper<EditCommunity> { + fn perform(&self) -> Result<CommunityResponse, Error> { + let data: EditCommunity = self.data; + + if has_slurs(&data.name) || has_slurs(&data.title) { + return Err(APIError::err(self.op, "No slurs"))? + } + + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + // Check for a site ban + if UserView::read(&conn, user_id)?.banned { + return Err(APIError::err(self.op, "You have been banned from the site"))? + } + + // Verify its a mod + let mut editors: Vec<i32> = Vec::new(); + editors.append( + &mut CommunityModeratorView::for_community(&conn, data.edit_id) + ? + .into_iter() + .map(|m| m.user_id) + .collect() + ); + editors.append( + &mut UserView::admins(&conn) + ? + .into_iter() + .map(|a| a.id) + .collect() + ); + if !editors.contains(&user_id) { + return Err(APIError::err(self.op, "Not allowed to edit community"))? + } + + let community_form = CommunityForm { + name: data.name.to_owned(), + title: data.title.to_owned(), + description: data.description.to_owned(), + category_id: data.category_id.to_owned(), + creator_id: user_id, + removed: data.removed.to_owned(), + deleted: data.deleted.to_owned(), + updated: Some(naive_now()) + }; + + let _updated_community = match Community::update(&conn, data.edit_id, &community_form) { + Ok(community) => community, + Err(_e) => { + return Err(APIError::err(self.op, "Couldn't update Community"))? + } + }; + + // Mod tables + if let Some(removed) = data.removed.to_owned() { + let expires = match data.expires { + Some(time) => Some(naive_from_unix(time)), + None => None + }; + let form = ModRemoveCommunityForm { + mod_user_id: user_id, + community_id: data.edit_id, + removed: Some(removed), + reason: data.reason.to_owned(), + expires: expires + }; + ModRemoveCommunity::create(&conn, &form)?; + } + + let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?; + + Ok( + CommunityResponse { + op: self.op.to_string(), + community: community_view + } + ) + } +} + +impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> { + fn perform(&self) -> Result<ListCommunitiesResponse, Error> { + let data: ListCommunities = self.data; + let conn = establish_connection(); + + let user_id: Option<i32> = match &data.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(&data.sort)?; + + let communities: Vec<CommunityView> = CommunityView::list(&conn, user_id, sort, data.page, data.limit)?; + + // Return the jwt + Ok( + ListCommunitiesResponse { + op: self.op.to_string(), + communities: communities + } + ) + } +} + + +impl Perform<CommunityResponse> for Oper<FollowCommunity> { + fn perform(&self) -> Result<CommunityResponse, Error> { + let data: FollowCommunity = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + let community_follower_form = CommunityFollowerForm { + community_id: data.community_id, + user_id: user_id + }; + + if data.follow { + match CommunityFollower::follow(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => { + return Err(APIError::err(self.op, "Community follower already exists."))? + } + }; + } else { + match CommunityFollower::ignore(&conn, &community_follower_form) { + Ok(user) => user, + Err(_e) => { + return Err(APIError::err(self.op, "Community follower already exists."))? + } + }; + } + + let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?; + + Ok( + CommunityResponse { + op: self.op.to_string(), + community: community_view + } + ) + } +} + + +impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> { + fn perform(&self) -> Result<GetFollowedCommunitiesResponse, Error> { + let data: GetFollowedCommunities = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) { + Ok(communities) => communities, + Err(_e) => { + return Err(APIError::err(self.op, "System error, try logging out and back in."))? + } + }; + + // Return the jwt + Ok( + GetFollowedCommunitiesResponse { + op: self.op.to_string(), + communities: communities + } + ) + } +} + + +impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> { + fn perform(&self) -> Result<BanFromCommunityResponse, Error> { + let data: BanFromCommunity = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + let community_user_ban_form = CommunityUserBanForm { + community_id: data.community_id, + user_id: data.user_id, + }; + + if data.ban { + match CommunityUserBan::ban(&conn, &community_user_ban_form) { + Ok(user) => user, + Err(_e) => { + return Err(APIError::err(self.op, "Community user ban already exists"))? + } + }; + } else { + match CommunityUserBan::unban(&conn, &community_user_ban_form) { + Ok(user) => user, + Err(_e) => { + return Err(APIError::err(self.op, "Community user ban already exists"))? + } + }; + } + + // Mod tables + let expires = match data.expires { + Some(time) => Some(naive_from_unix(time)), + None => None + }; + + let form = ModBanFromCommunityForm { + mod_user_id: user_id, + other_user_id: data.user_id, + community_id: data.community_id, + reason: data.reason.to_owned(), + banned: Some(data.ban), + expires: expires, + }; + ModBanFromCommunity::create(&conn, &form)?; + + let user_view = UserView::read(&conn, data.user_id)?; + + Ok( + BanFromCommunityResponse { + op: self.op.to_string(), + user: user_view, + banned: data.ban + } + ) + } +} + +impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> { + fn perform(&self) -> Result<AddModToCommunityResponse, Error> { + let data: AddModToCommunity = self.data; + let conn = establish_connection(); + + let claims = match Claims::decode(&data.auth) { + Ok(claims) => claims.claims, + Err(_e) => { + return Err(APIError::err(self.op, "Not logged in."))? + } + }; + + let user_id = claims.id; + + let community_moderator_form = CommunityModeratorForm { + community_id: data.community_id, + user_id: data.user_id + }; + + if data.added { + match CommunityModerator::join(&conn, &community_moderator_form) { + Ok(user) => user, + Err(_e) => { + return Err(APIError::err(self.op, "Community moderator already exists."))? + } + }; + } else { + match CommunityModerator::leave(&conn, &community_moderator_form) { + Ok(user) => user, + Err(_e) => { + return Err(APIError::err(self.op, "Community moderator already exists."))? + } + }; + } + + // Mod tables + let form = ModAddCommunityForm { + mod_user_id: user_id, + other_user_id: data.user_id, + community_id: data.community_id, + removed: Some(!data.added), + }; + ModAddCommunity::create(&conn, &form)?; + + let moderators = CommunityModeratorView::for_community(&conn, data.community_id)?; + + Ok( + AddModToCommunityResponse { + op: self.op.to_string(), + moderators: moderators, + } + ) + } +} diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs new file mode 100644 index 00000000..4bf6f7fe --- /dev/null +++ b/server/src/api/mod.rs @@ -0,0 +1,60 @@ +use serde::{Deserialize, Serialize}; +use failure::Error; +use db::*; +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 {has_slurs, remove_slurs, Settings, naive_now, naive_from_unix}; + +pub mod user; +pub mod community; +pub mod post; +pub mod comment; +pub mod site; + +#[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 APIError { + op: String, + message: String, +} + +impl APIError { + pub fn err(op: UserOperation, msg: &str) -> Self { + APIError { + op: op.to_string(), + message: msg.to_string(), + } + } +} + +pub struct Oper<T> { + op: UserOperation, + data: T +} + +impl <T> Oper<T> { + pub fn new(op: UserOperation, data: T) -> Oper<T> { + Oper { + op: op, + data: data + } + } +} + +pub trait Perform<T> { + fn perform(&self) -> Result<T, Error> where T: Sized; +} diff --git a/server/src/api/post.rs b/server/src/api/post.rs new file mode 100644 index 00000000..e7bec69e --- /dev/null +++ b/server/src/api/post.rs @@ -0,0 +1,469 @@ +use super::*; +use std::str::FromStr; + +#[derive(Serialize, Deserialize)] +pub struct CreatePost { + name: String, + url: Option<String>, + body: Option<String>, + community_id: i32, + auth: String +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct PostResponse { + op: String, + pub post: PostView +} + + +#[derive(Serialize, Deserialize)] +pub struct GetPost { + pub 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 CreatePostLike { + post_id: i32, + score: i16, + auth: String +} + +#[derive(Serialize, Deserialize)] +pub struct CreatePostLikeResponse { + op: String, + post: PostView +} + + +#[derive(Serialize, Deserialize)] +pub struct EditPost { + pub 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: Opti |