summaryrefslogtreecommitdiffstats
path: root/server/src/api/post.rs
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2019-05-04 22:20:38 -0700
committerDessalines <tyhou13@gmx.com>2019-05-04 22:20:38 -0700
commit7fb6a0b1387d4c256061fd9402ac8405fcedcf83 (patch)
tree3b239ae2802cf2a1c1429144b75f295e341f8e9f /server/src/api/post.rs
parent1a884a83534accf800f228e050b8fcf9338f6e4b (diff)
Mostly done with reorg.
Diffstat (limited to 'server/src/api/post.rs')
-rw-r--r--server/src/api/post.rs469
1 files changed, 469 insertions, 0 deletions
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: Option<String>,
+ auth: String
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct SavePost {
+ post_id: i32,
+ save: bool,
+ auth: String
+}
+
+impl Perform<PostResponse> for Oper<CreatePost> {
+ fn perform(&self) -> Result<PostResponse, Error> {
+ let data: CreatePost = 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) ||
+ (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
+ return Err(APIError::err(self.op, "No slurs"))?
+ }
+
+ let user_id = claims.id;
+
+ // Check for a community ban
+ if CommunityUserBanView::get(&conn, user_id, data.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 post_form = PostForm {
+ name: data.name.to_owned(),
+ url: data.url.to_owned(),
+ body: data.body.to_owned(),
+ community_id: data.community_id,
+ creator_id: user_id,
+ removed: None,
+ deleted: None,
+ locked: None,
+ updated: None
+ };
+
+ let inserted_post = match Post::create(&conn, &post_form) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't create Post"))?
+ }
+ };
+
+ // They like their own post by default
+ let like_form = PostLikeForm {
+ post_id: inserted_post.id,
+ user_id: user_id,
+ score: 1
+ };
+
+ // Only add the like if the score isnt 0
+ let _inserted_like = match PostLike::like(&conn, &like_form) {
+ Ok(like) => like,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't like post."))?
+ }
+ };
+
+ // Refetch the view
+ let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't find Post"))?
+ }
+ };
+
+ Ok(
+ PostResponse {
+ op: self.op.to_string(),
+ post: post_view
+ }
+ )
+ }
+}
+
+impl Perform<GetPostResponse> for Oper<GetPost> {
+ fn perform(&self) -> Result<GetPostResponse, Error> {
+ let data: GetPost = 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 post_view = match PostView::read(&conn, data.id, user_id) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't find Post"))?
+ }
+ };
+
+ let comments = CommentView::list(&conn, &SortType::New, Some(data.id), None, None, user_id, false, None, Some(9999))?;
+
+ let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
+
+ let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id)?;
+
+ let admins = UserView::admins(&conn)?;
+
+ // Return the jwt
+ Ok(
+ GetPostResponse {
+ op: self.op.to_string(),
+ post: post_view,
+ comments: comments,
+ community: community,
+ moderators: moderators,
+ admins: admins,
+ }
+ )
+ }
+}
+
+
+impl Perform<GetPostsResponse> for Oper<GetPosts> {
+ fn perform(&self) -> Result<GetPostsResponse, Error> {
+ let data: GetPosts = 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 type_ = PostListingType::from_str(&data.type_)?;
+ let sort = SortType::from_str(&data.sort)?;
+
+ let posts = match PostView::list(&conn,
+ type_,
+ &sort,
+ data.community_id,
+ None,
+ None,
+ user_id,
+ false,
+ false,
+ data.page,
+ data.limit) {
+ Ok(posts) => posts,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't get posts"))?
+ }
+ };
+
+ // Return the jwt
+ Ok(
+ GetPostsResponse {
+ op: self.op.to_string(),
+ posts: posts
+ }
+ )
+ }
+}
+
+impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
+ fn perform(&self) -> Result<CreatePostLikeResponse, Error> {
+ let data: CreatePostLike = 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 = PostLikeForm {
+ post_id: data.post_id,
+ user_id: user_id,
+ score: data.score
+ };
+
+ // Remove any likes first
+ PostLike::remove(&conn, &like_form)?;
+
+ // Only add the like if the score isnt 0
+ if &like_form.score != &0 {
+ let _inserted_like = match PostLike::like(&conn, &like_form) {
+ Ok(like) => like,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't like post."))?
+ }
+ };
+ }
+
+ let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't find Post"))?
+ }
+ };
+
+ // just output the score
+ Ok(
+ CreatePostLikeResponse {
+ op: self.op.to_string(),
+ post: post_view
+ }
+ )
+ }
+}
+
+impl Perform<PostResponse> for Oper<EditPost> {
+ fn perform(&self) -> Result<PostResponse, Error> {
+ let data: EditPost = self.data;
+ if has_slurs(&data.name) ||
+ (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
+ 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;
+
+ // Verify its the creator or a mod or admin
+ let mut editors: Vec<i32> = vec![data.creator_id];
+ editors.append(
+ &mut CommunityModeratorView::for_community(&conn, data.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 post."))?
+ }
+
+ // Check for a community ban
+ if CommunityUserBanView::get(&conn, user_id, data.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 post_form = PostForm {
+ name: data.name.to_owned(),
+ url: data.url.to_owned(),
+ body: data.body.to_owned(),
+ creator_id: data.creator_id.to_owned(),
+ community_id: data.community_id,
+ removed: data.removed.to_owned(),
+ deleted: data.deleted.to_owned(),
+ locked: data.locked.to_owned(),
+ updated: Some(naive_now())
+ };
+
+ let _updated_post = match Post::update(&conn, data.edit_id, &post_form) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldn't update Post"))?
+ }
+ };
+
+ // Mod tables
+ if let Some(removed) = data.removed.to_owned() {
+ let form = ModRemovePostForm {
+ mod_user_id: user_id,
+ post_id: data.edit_id,
+ removed: Some(removed),
+ reason: data.reason.to_owned(),
+ };
+ ModRemovePost::create(&conn, &form)?;
+ }
+
+ if let Some(locked) = data.locked.to_owned() {
+ let form = ModLockPostForm {
+ mod_user_id: user_id,
+ post_id: data.edit_id,
+ locked: Some(locked),
+ };
+ ModLockPost::create(&conn, &form)?;
+ }
+
+ let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
+
+ Ok(
+ PostResponse {
+ op: self.op.to_string(),
+ post: post_view
+ }
+ )
+ }
+}
+
+impl Perform<PostResponse> for Oper<SavePost> {
+ fn perform(&self) -> Result<PostResponse, Error> {
+ let data: SavePost = 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 post_saved_form = PostSavedForm {
+ post_id: data.post_id,
+ user_id: user_id,
+ };
+
+ if data.save {
+ match PostSaved::save(&conn, &post_saved_form) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldnt do post save"))?
+ }
+ };
+ } else {
+ match PostSaved::unsave(&conn, &post_saved_form) {
+ Ok(post) => post,
+ Err(_e) => {
+ return Err(APIError::err(self.op, "Couldnt do post save"))?
+ }
+ };
+ }
+
+ let post_view = PostView::read(&conn, data.post_id, Some(user_id))?;
+
+ Ok(
+ PostResponse {
+ op: self.op.to_string(),
+ post: post_view
+ }
+ )
+ }
+}