diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d891697..c2df622 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -12,5 +12,5 @@ - [Contributing](contributing.md) - [Docker Development](contributing_docker_development.md) - [Local Development](contributing_local_development.md) - - [Websocket API](contributing_websocket_api.md) + - [Websocket/HTTP API](contributing_websocket_http_api.md) - [ActivityPub API Outline](contributing_apub_api_outline.md) diff --git a/docs/src/contributing_websocket_api.md b/docs/src/contributing_websocket_http_api.md similarity index 68% rename from docs/src/contributing_websocket_api.md rename to docs/src/contributing_websocket_http_api.md index 16383d5..9e87d4f 100644 --- a/docs/src/contributing_websocket_api.md +++ b/docs/src/contributing_websocket_http_api.md @@ -5,126 +5,171 @@ - [Data types](#data-types) - [Basic usage](#basic-usage) - * [WebSocket Endpoint](#websocket-endpoint) - * [Testing with Websocat](#testing-with-websocat) - * [Testing with the WebSocket JavaScript API](#testing-with-the-websocket-javascript-api) + * [WebSocket](#websocket) + + [Testing with Websocat](#testing-with-websocat) + + [Testing with the WebSocket JavaScript API](#testing-with-the-websocket-javascript-api) + * [HTTP](#http) + + [Testing with Curl](#testing-with-curl) + - [Get Example](#get-example) + - [Post Example](#post-example) - [Rate limits](#rate-limits) - [Errors](#errors) - [API documentation](#api-documentation) * [Sort Types](#sort-types) + * [Websocket vs HTTP](#websocket-vs-http) * [User / Authentication / Admin actions](#user--authentication--admin-actions) + [Login](#login) - [Request](#request) - [Response](#response) + - [HTTP](#http-1) + [Register](#register) - [Request](#request-1) - [Response](#response-1) + - [HTTP](#http-2) + [Get User Details](#get-user-details) - [Request](#request-2) - [Response](#response-2) + - [HTTP](#http-3) + [Save User Settings](#save-user-settings) - [Request](#request-3) - [Response](#response-3) + - [HTTP](#http-4) + [Get Replies / Inbox](#get-replies--inbox) - [Request](#request-4) - [Response](#response-4) + - [HTTP](#http-5) + [Get User Mentions](#get-user-mentions) - [Request](#request-5) - [Response](#response-5) - + [Mark All As Read](#mark-all-as-read) + - [HTTP](#http-6) + + [Edit User Mention](#edit-user-mention) - [Request](#request-6) - [Response](#response-6) - + [Delete Account](#delete-account) + - [HTTP](#http-7) + + [Mark All As Read](#mark-all-as-read) - [Request](#request-7) - [Response](#response-7) - + [Add admin](#add-admin) + - [HTTP](#http-8) + + [Delete Account](#delete-account) - [Request](#request-8) - [Response](#response-8) - + [Ban user](#ban-user) + - [HTTP](#http-9) + + [Add admin](#add-admin) - [Request](#request-9) - [Response](#response-9) - * [Site](#site) - + [List Categories](#list-categories) + - [HTTP](#http-10) + + [Ban user](#ban-user) - [Request](#request-10) - [Response](#response-10) - + [Search](#search) + - [HTTP](#http-11) + * [Site](#site) + + [List Categories](#list-categories) - [Request](#request-11) - [Response](#response-11) - + [Get Modlog](#get-modlog) + - [HTTP](#http-12) + + [Search](#search) - [Request](#request-12) - [Response](#response-12) - + [Create Site](#create-site) + - [HTTP](#http-13) + + [Get Modlog](#get-modlog) - [Request](#request-13) - [Response](#response-13) - + [Edit Site](#edit-site) + - [HTTP](#http-14) + + [Create Site](#create-site) - [Request](#request-14) - [Response](#response-14) - + [Get Site](#get-site) + - [HTTP](#http-15) + + [Edit Site](#edit-site) - [Request](#request-15) - [Response](#response-15) - + [Transfer Site](#transfer-site) + - [HTTP](#http-16) + + [Get Site](#get-site) - [Request](#request-16) - [Response](#response-16) - * [Community](#community) - + [Get Community](#get-community) + - [HTTP](#http-17) + + [Transfer Site](#transfer-site) - [Request](#request-17) - [Response](#response-17) - + [Create Community](#create-community) + - [HTTP](#http-18) + * [Community](#community) + + [Get Community](#get-community) - [Request](#request-18) - [Response](#response-18) - + [List Communities](#list-communities) + - [HTTP](#http-19) + + [Create Community](#create-community) - [Request](#request-19) - [Response](#response-19) - + [Ban from Community](#ban-from-community) + - [HTTP](#http-20) + + [List Communities](#list-communities) - [Request](#request-20) - [Response](#response-20) - + [Add Mod to Community](#add-mod-to-community) + - [HTTP](#http-21) + + [Ban from Community](#ban-from-community) - [Request](#request-21) - [Response](#response-21) - + [Edit Community](#edit-community) + - [HTTP](#http-22) + + [Add Mod to Community](#add-mod-to-community) - [Request](#request-22) - [Response](#response-22) - + [Follow Community](#follow-community) + - [HTTP](#http-23) + + [Edit Community](#edit-community) - [Request](#request-23) - [Response](#response-23) - + [Get Followed Communities](#get-followed-communities) + - [HTTP](#http-24) + + [Follow Community](#follow-community) - [Request](#request-24) - [Response](#response-24) - + [Transfer Community](#transfer-community) + - [HTTP](#http-25) + + [Get Followed Communities](#get-followed-communities) - [Request](#request-25) - [Response](#response-25) - * [Post](#post) - + [Create Post](#create-post) + - [HTTP](#http-26) + + [Transfer Community](#transfer-community) - [Request](#request-26) - [Response](#response-26) - + [Get Post](#get-post) + - [HTTP](#http-27) + * [Post](#post) + + [Create Post](#create-post) - [Request](#request-27) - [Response](#response-27) - + [Get Posts](#get-posts) + - [HTTP](#http-28) + + [Get Post](#get-post) - [Request](#request-28) - [Response](#response-28) - + [Create Post Like](#create-post-like) + - [HTTP](#http-29) + + [Get Posts](#get-posts) - [Request](#request-29) - [Response](#response-29) - + [Edit Post](#edit-post) + - [HTTP](#http-30) + + [Create Post Like](#create-post-like) - [Request](#request-30) - [Response](#response-30) - + [Save Post](#save-post) + - [HTTP](#http-31) + + [Edit Post](#edit-post) - [Request](#request-31) - [Response](#response-31) - * [Comment](#comment) - + [Create Comment](#create-comment) + - [HTTP](#http-32) + + [Save Post](#save-post) - [Request](#request-32) - [Response](#response-32) - + [Edit Comment](#edit-comment) + - [HTTP](#http-33) + * [Comment](#comment) + + [Create Comment](#create-comment) - [Request](#request-33) - [Response](#response-33) - + [Save Comment](#save-comment) + - [HTTP](#http-34) + + [Edit Comment](#edit-comment) - [Request](#request-34) - [Response](#response-34) - + [Create Comment Like](#create-comment-like) + - [HTTP](#http-35) + + [Save Comment](#save-comment) - [Request](#request-35) - [Response](#response-35) + - [HTTP](#http-36) + + [Create Comment Like](#create-comment-like) + - [Request](#request-36) + - [Response](#response-36) + - [HTTP](#http-37) * [RSS / Atom feeds](#rss--atom-feeds) + [All](#all) + [Community](#community-1) @@ -144,13 +189,13 @@ Request and response strings are in [JSON format](https://www.json.org). -### WebSocket Endpoint +### WebSocket Connect to ws://***host***/api/v1/ws to get started. If the ***`host`*** supports secure connections, you can use wss://***host***/api/v1/ws. -### Testing with Websocat +#### Testing with Websocat [Websocat link](https://github.com/vi/websocat) @@ -159,7 +204,7 @@ If the ***`host`*** supports secure connections, you can use wss://***host A simple test command: `{"op": "ListCategories"}` -### Testing with the WebSocket JavaScript API +#### Testing with the WebSocket JavaScript API [WebSocket JavaScript API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) ```javascript @@ -171,6 +216,32 @@ ws.onopen = function () { })); }; ``` +### HTTP + +Endpoints are at http://***host***/api/v1/***endpoint***. They'll be listed below for each action. + +#### Testing with Curl + +##### Get Example + +``` +curl /community/list?sort=Hot +``` + +##### Post Example + +``` +curl -i -H \ +"Content-Type: application/json" \ +-X POST \ +-d '{ + "comment_id": X, + "post_id": X, + "score": X, + "auth": "..." +}' \ +/comment/like +``` ## Rate limits @@ -201,6 +272,11 @@ These go wherever there is a `sort` field. The available sort types are: - `TopYear` - the most upvoted posts/communities of the current year. - `TopAll` - the most upvoted posts/communities on the current instance. +### Websocket vs HTTP + +- Below are the websocket JSON requests / responses. For HTTP, ignore all fields except those inside `data`. +- For example, an http login will be a `POST` `{username_or_email: X, password: X}` + ### User / Authentication / Admin actions #### Login @@ -220,13 +296,19 @@ The `jwt` string should be stored and used anywhere `auth` is called for. ##### Response ```rust { - op: String, - jwt: String + op: "Login", + data: { + jwt: String, + } } ``` +##### HTTP + +`POST /user/login` #### Register + Only the first user will be able to be the admin. ##### Request @@ -245,11 +327,17 @@ Only the first user will be able to be the admin. ##### Response ```rust { - op: String, - jwt: String + op: "Register", + data: { + jwt: String, + } } ``` +##### HTTP + +`POST /user/register` + #### Get User Details ##### Request ```rust @@ -270,14 +358,20 @@ Only the first user will be able to be the admin. ##### Response ```rust { - op: String, - user: UserView, - follows: Vec, - moderates: Vec, - comments: Vec, - posts: Vec, + op: "GetUserDetails", + data: { + user: UserView, + follows: Vec, + moderates: Vec, + comments: Vec, + posts: Vec, + } } ``` +##### HTTP + +`GET /user` + #### Save User Settings ##### Request ```rust @@ -295,10 +389,16 @@ Only the first user will be able to be the admin. ##### Response ```rust { - op: String, - jwt: String + op: "SaveUserSettings", + data: { + jwt: String + } } ``` +##### HTTP + +`PUT /save_user_settings` + #### Get Replies / Inbox ##### Request ```rust @@ -316,10 +416,16 @@ Only the first user will be able to be the admin. ##### Response ```rust { - op: String, - replies: Vec, + op: "GetReplies", + data: { + replies: Vec, + } } ``` +##### HTTP + +`GET /user/replies` + #### Get User Mentions ##### Request @@ -338,11 +444,42 @@ Only the first user will be able to be the admin. ##### Response ```rust { - op: String, - mentions: Vec, + op: "GetUserMentions", + data: { + mentions: Vec, + } } ``` +##### HTTP + +`GET /user/mentions` + +#### Edit User Mention +##### Request +```rust +{ + op: "EditUserMention", + data: { + user_mention_id: i32, + read: Option, + auth: String, + } +} +``` +##### Response +```rust +{ + op: "EditUserMention", + data: { + mention: UserMentionView, + } +} +``` +##### HTTP + +`PUT /user/mention` + #### Mark All As Read Marks all user replies and mentions as read. @@ -359,11 +496,17 @@ Marks all user replies and mentions as read. ##### Response ```rust { - op: String, - replies: Vec, + op: "MarkAllAsRead", + data: { + replies: Vec, + } } ``` +##### HTTP + +`POST /user/mark_all_as_read` + #### Delete Account *Permananently deletes your posts and comments* @@ -381,11 +524,17 @@ Marks all user replies and mentions as read. ##### Response ```rust { - op: String, - jwt: String, + op: "DeleteAccount", + data: { + jwt: String, + } } ``` +##### HTTP + +`POST /user/delete_account` + #### Add admin ##### Request ```rust @@ -401,10 +550,15 @@ Marks all user replies and mentions as read. ##### Response ```rust { - op: String, - admins: Vec, + op: "AddAdmin", + data: { + admins: Vec, + } } ``` +##### HTTP + +`POST /admin/add` #### Ban user ##### Request @@ -423,11 +577,16 @@ Marks all user replies and mentions as read. ##### Response ```rust { - op: String, - user: UserView, - banned: bool, + op: "BanUser", + data: { + user: UserView, + banned: bool, + } } ``` +##### HTTP + +`POST /user/ban` ### Site #### List Categories @@ -440,13 +599,19 @@ Marks all user replies and mentions as read. ##### Response ```rust { - op: String, - categories: Vec + op: "ListCategories", + data: { + categories: Vec + } } ``` +##### HTTP + +`GET /categories` #### Search -Search types are `Both, Comments, Posts`. + +Search types are `All, Comments, Posts, Communities, Users, Url` ##### Request ```rust @@ -459,17 +624,26 @@ Search types are `Both, Comments, Posts`. sort: String, page: Option, limit: Option, + auth?: Option, } } ``` ##### Response ```rust { - op: String, - comments: Vec, - posts: Vec, + op: "Search", + data: { + type_: String, + comments: Vec, + posts: Vec, + communities: Vec, + users: Vec, + } } ``` +##### HTTP + +`POST /search` #### Get Modlog ##### Request @@ -487,18 +661,24 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - removed_posts: Vec, - locked_posts: Vec, - removed_comments: Vec, - removed_communities: Vec, - banned_from_community: Vec, - banned: Vec, - added_to_community: Vec, - added: Vec, + op: "GetModlog", + data: { + removed_posts: Vec, + locked_posts: Vec, + removed_comments: Vec, + removed_communities: Vec, + banned_from_community: Vec, + banned: Vec, + added_to_community: Vec, + added: Vec, + } } ``` +##### HTTP + +`GET /modlog` + #### Create Site ##### Request ```rust @@ -514,11 +694,17 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - site: SiteView, + op: "CreateSite", + data: { + site: SiteView, + } } ``` +##### HTTP + +`POST /site` + #### Edit Site ##### Request ```rust @@ -534,10 +720,15 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - site: SiteView, + op: "EditSite", + data: { + site: SiteView, + } } ``` +##### HTTP + +`PUT /site` #### Get Site ##### Request @@ -549,12 +740,17 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - site: Option, - admins: Vec, - banned: Vec, + op: "GetSite", + data: { + site: Option, + admins: Vec, + banned: Vec, + } } ``` +##### HTTP + +`GET /site` #### Transfer Site ##### Request @@ -570,12 +766,17 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - site: Option, - admins: Vec, - banned: Vec, + op: "TransferSite", + data: { + site: Option, + admins: Vec, + banned: Vec, + } } ``` +##### HTTP + +`POST /site/transfer` ### Community #### Get Community @@ -593,12 +794,17 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - community: CommunityView, - moderators: Vec, - admins: Vec, + op: "GetCommunity", + data: { + community: CommunityView, + moderators: Vec, + admins: Vec, + } } ``` +##### HTTP + +`GET /community` #### Create Community ##### Request @@ -617,10 +823,15 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - community: CommunityView + op: "CreateCommunity", + data: { + community: CommunityView + } } ``` +##### HTTP + +`POST /community` #### List Communities ##### Request @@ -638,10 +849,15 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - communities: Vec + op: "ListCommunities", + data: { + communities: Vec + } } ``` +##### HTTP + +`GET /community/list` #### Ban from Community ##### Request @@ -661,11 +877,16 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - user: UserView, - banned: bool, + op: "BanFromCommunity", + data: { + user: UserView, + banned: bool, + } } ``` +##### HTTP + +`POST /community/ban_user` #### Add Mod to Community ##### Request @@ -683,10 +904,15 @@ Search types are `Both, Comments, Posts`. ##### Response ```rust { - op: String, - moderators: Vec, + op: "AddModToCommunity", + data: { + moderators: Vec, + } } ``` +##### HTTP + +`POST /community/mod` #### Edit Community Mods and admins can remove and lock a community, creators can delete it. @@ -712,10 +938,15 @@ Mods and admins can remove and lock a community, creators can delete it. ##### Response ```rust { - op: String, - community: CommunityView + op: "EditCommunity", + data: { + community: CommunityView + } } ``` +##### HTTP + +`PUT /community` #### Follow Community ##### Request @@ -732,10 +963,15 @@ Mods and admins can remove and lock a community, creators can delete it. ##### Response ```rust { - op: String, - community: CommunityView + op: "FollowCommunity", + data: { + community: CommunityView + } } ``` +##### HTTP + +`POST /community/follow` #### Get Followed Communities ##### Request @@ -750,10 +986,15 @@ Mods and admins can remove and lock a community, creators can delete it. ##### Response ```rust { - op: String, - communities: Vec + op: "GetFollowedCommunities", + data: { + communities: Vec + } } ``` +##### HTTP + +`GET /user/followed_communities` #### Transfer Community ##### Request @@ -770,12 +1011,17 @@ Mods and admins can remove and lock a community, creators can delete it. ##### Response ```rust { - op: String, - community: CommunityView, - moderators: Vec, - admins: Vec, + op: "TransferCommunity", + data: { + community: CommunityView, + moderators: Vec, + admins: Vec, + } } ``` +##### HTTP + +`POST /community/transfer` ### Post #### Create Post @@ -795,10 +1041,15 @@ Mods and admins can remove and lock a community, creators can delete it. ##### Response ```rust { - op: String, - post: PostView + op: "CreatePost", + data: { + post: PostView + } } ``` +##### HTTP + +`POST /post` #### Get Post ##### Request @@ -814,16 +1065,22 @@ Mods and admins can remove and lock a community, creators can delete it. ##### Response ```rust { - op: String, - post: PostView, - comments: Vec, - community: CommunityView, - moderators: Vec, - admins: Vec, + op: "GetPost", + data: { + post: PostView, + comments: Vec, + community: CommunityView, + moderators: Vec, + admins: Vec, + } } ``` +##### HTTP + +`GET /post` #### Get Posts + Post listing types are `All, Subscribed, Community` ##### Request @@ -843,12 +1100,18 @@ Post listing types are `All, Subscribed, Community` ##### Response ```rust { - op: String, - posts: Vec, + op: "GetPosts", + data: { + posts: Vec, + } } ``` +##### HTTP + +`GET /post/list` #### Create Post Like + `score` can be 0, -1, or 1 ##### Request @@ -865,12 +1128,18 @@ Post listing types are `All, Subscribed, Community` ##### Response ```rust { - op: String, - post: PostView + op: "CreatePostLike", + data: { + post: PostView + } } ``` +##### HTTP + +`POST /post/like` #### Edit Post + Mods and admins can remove and lock a post, creators can delete it. ##### Request @@ -895,11 +1164,17 @@ Mods and admins can remove and lock a post, creators can delete it. ##### Response ```rust { - op: String, - post: PostView + op: "EditPost", + data: { + post: PostView + } } ``` +##### HTTP + +`PUT /post` + #### Save Post ##### Request ```rust @@ -915,10 +1190,15 @@ Mods and admins can remove and lock a post, creators can delete it. ##### Response ```rust { - op: String, - post: PostView + op: "SavePost", + data: { + post: PostView + } } ``` +##### HTTP + +`POST /post/save` ### Comment #### Create Comment @@ -938,12 +1218,19 @@ Mods and admins can remove and lock a post, creators can delete it. ##### Response ```rust { - op: String, - comment: CommentView + op: "CreateComment", + data: { + comment: CommentView + } } ``` +##### HTTP + +`POST /comment` + #### Edit Comment + Mods and admins can remove a comment, creators can delete it. ##### Request @@ -967,10 +1254,15 @@ Mods and admins can remove a comment, creators can delete it. ##### Response ```rust { - op: String, - comment: CommentView + op: "EditComment", + data: { + comment: CommentView + } } ``` +##### HTTP + +`PUT /comment` #### Save Comment ##### Request @@ -987,12 +1279,18 @@ Mods and admins can remove a comment, creators can delete it. ##### Response ```rust { - op: String, - comment: CommentView + op: "SaveComment", + data: { + comment: CommentView + } } ``` +##### HTTP + +`POST /comment/save` #### Create Comment Like + `score` can be 0, -1, or 1 ##### Request @@ -1010,10 +1308,15 @@ Mods and admins can remove a comment, creators can delete it. ##### Response ```rust { - op: String, - comment: CommentView + op: "CreateCommentLike", + data: { + comment: CommentView + } } ``` +##### HTTP + +`POST /comment/like` ### RSS / Atom feeds diff --git a/server/.rustfmt.toml b/server/.rustfmt.toml index b1fce9c..684a7f8 100644 --- a/server/.rustfmt.toml +++ b/server/.rustfmt.toml @@ -1,2 +1,2 @@ tab_spaces = 2 -edition="2018" +edition="2018" \ No newline at end of file diff --git a/server/src/api/comment.rs b/server/src/api/comment.rs index 382afb5..8efb30f 100644 --- a/server/src/api/comment.rs +++ b/server/src/api/comment.rs @@ -35,7 +35,6 @@ pub struct SaveComment { #[derive(Serialize, Deserialize, Clone)] pub struct CommentResponse { - op: String, pub comment: CommentView, } @@ -53,7 +52,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -63,12 +62,12 @@ impl Perform for Oper { // 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, "community_ban").into()); + return Err(APIError::err("community_ban").into()); } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } let content_slurs_removed = remove_slurs(&data.content.to_owned()); @@ -86,7 +85,7 @@ impl Perform for Oper { let inserted_comment = match Comment::create(&conn, &comment_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_create_comment").into()), }; // Scan the comment for user mentions, add those rows @@ -193,13 +192,12 @@ impl Perform for Oper { let _inserted_like = match CommentLike::like(&conn, &like_form) { Ok(like) => like, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_like_comment").into()), }; let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?; Ok(CommentResponse { - op: self.op.to_string(), comment: comment_view, }) } @@ -211,7 +209,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -231,17 +229,17 @@ impl Perform for Oper { editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect()); if !editors.contains(&user_id) { - return Err(APIError::err(&self.op, "no_comment_edit_allowed").into()); + return Err(APIError::err("no_comment_edit_allowed").into()); } // Check for a community ban if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() { - return Err(APIError::err(&self.op, "community_ban").into()); + return Err(APIError::err("community_ban").into()); } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } } @@ -264,7 +262,7 @@ impl Perform for Oper { let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; // Scan the comment for user mentions, add those rows @@ -310,7 +308,6 @@ impl Perform for Oper { let comment_view = CommentView::read(&conn, data.edit_id, Some(user_id))?; Ok(CommentResponse { - op: self.op.to_string(), comment: comment_view, }) } @@ -322,7 +319,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -335,19 +332,18 @@ impl Perform for Oper { if data.save { match CommentSaved::save(&conn, &comment_saved_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_save_comment").into()), }; } else { match CommentSaved::unsave(&conn, &comment_saved_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_save_comment").into()), }; } let comment_view = CommentView::read(&conn, data.comment_id, Some(user_id))?; Ok(CommentResponse { - op: self.op.to_string(), comment: comment_view, }) } @@ -359,7 +355,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -368,19 +364,19 @@ impl Perform for Oper { if data.score == -1 { let site = SiteView::read(&conn)?; if !site.enable_downvotes { - return Err(APIError::err(&self.op, "downvotes_disabled").into()); + return Err(APIError::err("downvotes_disabled").into()); } } // 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, "community_ban").into()); + return Err(APIError::err("community_ban").into()); } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } let like_form = CommentLikeForm { @@ -398,7 +394,7 @@ impl Perform for Oper { if do_add { let _inserted_like = match CommentLike::like(&conn, &like_form) { Ok(like) => like, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_like_comment").into()), }; } @@ -406,7 +402,6 @@ impl Perform for Oper { 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 index 0bf846c..c765aa9 100644 --- a/server/src/api/community.rs +++ b/server/src/api/community.rs @@ -11,7 +11,6 @@ pub struct GetCommunity { #[derive(Serialize, Deserialize)] pub struct GetCommunityResponse { - op: String, community: CommunityView, moderators: Vec, admins: Vec, @@ -29,7 +28,6 @@ pub struct CreateCommunity { #[derive(Serialize, Deserialize, Clone)] pub struct CommunityResponse { - op: String, pub community: CommunityView, } @@ -43,7 +41,6 @@ pub struct ListCommunities { #[derive(Serialize, Deserialize)] pub struct ListCommunitiesResponse { - op: String, communities: Vec, } @@ -59,7 +56,6 @@ pub struct BanFromCommunity { #[derive(Serialize, Deserialize)] pub struct BanFromCommunityResponse { - op: String, user: UserView, banned: bool, } @@ -74,7 +70,6 @@ pub struct AddModToCommunity { #[derive(Serialize, Deserialize)] pub struct AddModToCommunityResponse { - op: String, moderators: Vec, } @@ -107,7 +102,6 @@ pub struct GetFollowedCommunities { #[derive(Serialize, Deserialize)] pub struct GetFollowedCommunitiesResponse { - op: String, communities: Vec, } @@ -141,19 +135,19 @@ impl Perform for Oper { data.name.to_owned().unwrap_or_else(|| "main".to_string()), ) { Ok(community) => community.id, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community").into()), + Err(_e) => return Err(APIError::err("couldnt_find_community").into()), } } }; let community_view = match CommunityView::read(&conn, community_id, user_id) { Ok(community) => community, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community").into()), + Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; let moderators = match CommunityModeratorView::for_community(&conn, community_id) { Ok(moderators) => moderators, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community").into()), + Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; let site_creator_id = Site::read(&conn, 1)?.creator_id; @@ -164,7 +158,6 @@ impl Perform for Oper { // Return the jwt Ok(GetCommunityResponse { - op: self.op.to_string(), community: community_view, moderators, admins, @@ -178,21 +171,21 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; 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").into()); + return Err(APIError::err("no_slurs").into()); } let user_id = claims.id; // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } // When you create a community, make sure the user becomes a moderator and a follower @@ -210,7 +203,7 @@ impl Perform for Oper { let inserted_community = match Community::create(&conn, &community_form) { Ok(community) => community, - Err(_e) => return Err(APIError::err(&self.op, "community_already_exists").into()), + Err(_e) => return Err(APIError::err("community_already_exists").into()), }; let community_moderator_form = CommunityModeratorForm { @@ -221,9 +214,7 @@ impl Perform for Oper { 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").into()) - } + Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()), }; let community_follower_form = CommunityFollowerForm { @@ -234,13 +225,12 @@ impl Perform for Oper { 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").into()), + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), }; let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?; Ok(CommunityResponse { - op: self.op.to_string(), community: community_view, }) } @@ -251,19 +241,19 @@ impl Perform for Oper { let data: &EditCommunity = &self.data; if has_slurs(&data.name) || has_slurs(&data.title) { - return Err(APIError::err(&self.op, "no_slurs").into()); + return Err(APIError::err("no_slurs").into()); } let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } // Verify its a mod @@ -276,7 +266,7 @@ impl Perform for Oper { ); editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect()); if !editors.contains(&user_id) { - return Err(APIError::err(&self.op, "no_community_edit_allowed").into()); + return Err(APIError::err("no_community_edit_allowed").into()); } let community_form = CommunityForm { @@ -293,7 +283,7 @@ impl Perform for Oper { let _updated_community = match Community::update(&conn, data.edit_id, &community_form) { Ok(community) => community, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_community").into()), + Err(_e) => return Err(APIError::err("couldnt_update_community").into()), }; // Mod tables @@ -315,7 +305,6 @@ impl Perform for Oper { let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?; Ok(CommunityResponse { - op: self.op.to_string(), community: community_view, }) } @@ -354,10 +343,7 @@ impl Perform for Oper { .list()?; // Return the jwt - Ok(ListCommunitiesResponse { - op: self.op.to_string(), - communities, - }) + Ok(ListCommunitiesResponse { communities }) } } @@ -367,7 +353,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -380,19 +366,18 @@ impl Perform for Oper { 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").into()), + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), }; } else { match CommunityFollower::ignore(&conn, &community_follower_form) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists").into()), + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), }; } let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?; Ok(CommunityResponse { - op: self.op.to_string(), community: community_view, }) } @@ -404,7 +389,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -412,14 +397,11 @@ impl Perform for Oper { let communities: Vec = match CommunityFollowerView::for_user(&conn, user_id) { Ok(communities) => communities, - Err(_e) => return Err(APIError::err(&self.op, "system_err_login").into()), + Err(_e) => return Err(APIError::err("system_err_login").into()), }; // Return the jwt - Ok(GetFollowedCommunitiesResponse { - op: self.op.to_string(), - communities, - }) + Ok(GetFollowedCommunitiesResponse { communities }) } } @@ -429,7 +411,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -442,12 +424,12 @@ impl Perform for Oper { if data.ban { match CommunityUserBan::ban(&conn, &community_user_ban_form) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "community_user_already_banned").into()), + Err(_e) => return Err(APIError::err("community_user_already_banned").into()), }; } else { match CommunityUserBan::unban(&conn, &community_user_ban_form) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "community_user_already_banned").into()), + Err(_e) => return Err(APIError::err("community_user_already_banned").into()), }; } @@ -470,7 +452,6 @@ impl Perform for Oper { let user_view = UserView::read(&conn, data.user_id)?; Ok(BanFromCommunityResponse { - op: self.op.to_string(), user: user_view, banned: data.ban, }) @@ -483,7 +464,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -496,16 +477,12 @@ impl Perform for Oper { 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").into()) - } + Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()), }; } else { match CommunityModerator::leave(&conn, &community_moderator_form) { Ok(user) => user, - Err(_e) => { - return Err(APIError::err(&self.op, "community_moderator_already_exists").into()) - } + Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()), }; } @@ -520,10 +497,7 @@ impl Perform for Oper { let moderators = CommunityModeratorView::for_community(&conn, data.community_id)?; - Ok(AddModToCommunityResponse { - op: self.op.to_string(), - moderators, - }) + Ok(AddModToCommunityResponse { moderators }) } } @@ -533,7 +507,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -548,7 +522,7 @@ impl Perform for Oper { // Make sure user is the creator, or an admin if user_id != read_community.creator_id && !admins.iter().map(|a| a.id).any(|x| x == user_id) { - return Err(APIError::err(&self.op, "not_an_admin").into()); + return Err(APIError::err("not_an_admin").into()); } let community_form = CommunityForm { @@ -565,7 +539,7 @@ impl Perform for Oper { let _updated_community = match Community::update(&conn, data.community_id, &community_form) { Ok(community) => community, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_community").into()), + Err(_e) => return Err(APIError::err("couldnt_update_community").into()), }; // You also have to re-do the community_moderator table, reordering it. @@ -588,9 +562,7 @@ impl Perform for Oper { 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").into()) - } + Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()), }; } @@ -605,17 +577,16 @@ impl Perform for Oper { let community_view = match CommunityView::read(&conn, data.community_id, Some(user_id)) { Ok(community) => community, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community").into()), + Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) { Ok(moderators) => moderators, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community").into()), + Err(_e) => return Err(APIError::err("couldnt_find_community").into()), }; // Return the jwt Ok(GetCommunityResponse { - op: self.op.to_string(), community: community_view, moderators, admins, diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 3b2466a..cb09d7f 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -28,76 +28,27 @@ pub mod post; pub mod site; pub mod user; -#[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, - GetUserMentions, - EditUserMention, - GetModlog, - BanFromCommunity, - AddModToCommunity, - CreateSite, - EditSite, - GetSite, - AddAdmin, - BanUser, - Search, - MarkAllAsRead, - SaveUserSettings, - TransferCommunity, - TransferSite, - DeleteAccount, - PasswordReset, - PasswordChange, - CreatePrivateMessage, - EditPrivateMessage, - GetPrivateMessages, -} - #[derive(Fail, Debug)] -#[fail(display = "{{\"op\":\"{}\", \"error\":\"{}\"}}", op, message)] +#[fail(display = "{{\"error\":\"{}\"}}", message)] pub struct APIError { - pub op: String, pub message: String, } impl APIError { - pub fn err(op: &UserOperation, msg: &str) -> Self { + pub fn err(msg: &str) -> Self { APIError { - op: op.to_string(), message: msg.to_string(), } } } pub struct Oper { - op: UserOperation, data: T, } impl Oper { - pub fn new(op: UserOperation, data: T) -> Oper { - Oper { op, data } + pub fn new(data: T) -> Oper { + Oper { data } } } diff --git a/server/src/api/post.rs b/server/src/api/post.rs index b0fcdd0..3f21145 100644 --- a/server/src/api/post.rs +++ b/server/src/api/post.rs @@ -14,7 +14,6 @@ pub struct CreatePost { #[derive(Serialize, Deserialize, Clone)] pub struct PostResponse { - op: String, pub post: PostView, } @@ -26,7 +25,6 @@ pub struct GetPost { #[derive(Serialize, Deserialize)] pub struct GetPostResponse { - op: String, post: PostView, comments: Vec, community: CommunityView, @@ -46,7 +44,6 @@ pub struct GetPosts { #[derive(Serialize, Deserialize)] pub struct GetPostsResponse { - op: String, posts: Vec, } @@ -59,7 +56,6 @@ pub struct CreatePostLike { #[derive(Serialize, Deserialize)] pub struct CreatePostLikeResponse { - op: String, post: PostView, } @@ -93,23 +89,23 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "no_slurs").into()); + return Err(APIError::err("no_slurs").into()); } 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, "community_ban").into()); + return Err(APIError::err("community_ban").into()); } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } let post_form = PostForm { @@ -128,7 +124,7 @@ impl Perform for Oper { let inserted_post = match Post::create(&conn, &post_form) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_post").into()), + Err(_e) => return Err(APIError::err("couldnt_create_post").into()), }; // They like their own post by default @@ -141,19 +137,16 @@ impl Perform for Oper { // 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, "couldnt_like_post").into()), + Err(_e) => return Err(APIError::err("couldnt_like_post").into()), }; // 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, "couldnt_find_post").into()), + Err(_e) => return Err(APIError::err("couldnt_find_post").into()), }; - Ok(PostResponse { - op: self.op.to_string(), - post: post_view, - }) + Ok(PostResponse { post: post_view }) } } @@ -174,7 +167,7 @@ impl Perform for Oper { let post_view = match PostView::read(&conn, data.id, user_id) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post").into()), + Err(_e) => return Err(APIError::err("couldnt_find_post").into()), }; let comments = CommentQueryBuilder::create(&conn) @@ -195,7 +188,6 @@ impl Perform for Oper { // Return the jwt Ok(GetPostResponse { - op: self.op.to_string(), post: post_view, comments, community, @@ -241,13 +233,10 @@ impl Perform for Oper { .list() { Ok(posts) => posts, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_get_posts").into()), + Err(_e) => return Err(APIError::err("couldnt_get_posts").into()), }; - Ok(GetPostsResponse { - op: self.op.to_string(), - posts, - }) + Ok(GetPostsResponse { posts }) } } @@ -257,7 +246,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -266,19 +255,19 @@ impl Perform for Oper { if data.score == -1 { let site = SiteView::read(&conn)?; if !site.enable_downvotes { - return Err(APIError::err(&self.op, "downvotes_disabled").into()); + return Err(APIError::err("downvotes_disabled").into()); } } // 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, "community_ban").into()); + return Err(APIError::err("community_ban").into()); } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } let like_form = PostLikeForm { @@ -295,20 +284,17 @@ impl Perform for Oper { if do_add { let _inserted_like = match PostLike::like(&conn, &like_form) { Ok(like) => like, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post").into()), + Err(_e) => return Err(APIError::err("couldnt_like_post").into()), }; } let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post").into()), + Err(_e) => return Err(APIError::err("couldnt_find_post").into()), }; // just output the score - Ok(CreatePostLikeResponse { - op: self.op.to_string(), - post: post_view, - }) + Ok(CreatePostLikeResponse { post: post_view }) } } @@ -316,12 +302,12 @@ impl Perform for Oper { fn perform(&self, conn: &PgConnection) -> Result { 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").into()); + return Err(APIError::err("no_slurs").into()); } let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -336,17 +322,17 @@ impl Perform for Oper { ); editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect()); if !editors.contains(&user_id) { - return Err(APIError::err(&self.op, "no_post_edit_allowed").into()); + return Err(APIError::err("no_post_edit_allowed").into()); } // Check for a community ban if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() { - return Err(APIError::err(&self.op, "community_ban").into()); + return Err(APIError::err("community_ban").into()); } // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } let post_form = PostForm { @@ -365,7 +351,7 @@ impl Perform for Oper { let _updated_post = match Post::update(&conn, data.edit_id, &post_form) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post").into()), + Err(_e) => return Err(APIError::err("couldnt_update_post").into()), }; // Mod tables @@ -399,10 +385,7 @@ impl Perform for Oper { let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?; - Ok(PostResponse { - op: self.op.to_string(), - post: post_view, - }) + Ok(PostResponse { post: post_view }) } } @@ -412,7 +395,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -425,20 +408,17 @@ impl Perform for Oper { if data.save { match PostSaved::save(&conn, &post_saved_form) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post").into()), + Err(_e) => return Err(APIError::err("couldnt_save_post").into()), }; } else { match PostSaved::unsave(&conn, &post_saved_form) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post").into()), + Err(_e) => return Err(APIError::err("couldnt_save_post").into()), }; } let post_view = PostView::read(&conn, data.post_id, Some(user_id))?; - Ok(PostResponse { - op: self.op.to_string(), - post: post_view, - }) + Ok(PostResponse { post: post_view }) } } diff --git a/server/src/api/site.rs b/server/src/api/site.rs index ce07724..a5faf34 100644 --- a/server/src/api/site.rs +++ b/server/src/api/site.rs @@ -7,7 +7,6 @@ pub struct ListCategories; #[derive(Serialize, Deserialize)] pub struct ListCategoriesResponse { - op: String, categories: Vec, } @@ -24,7 +23,6 @@ pub struct Search { #[derive(Serialize, Deserialize)] pub struct SearchResponse { - op: String, type_: String, comments: Vec, posts: Vec, @@ -42,7 +40,6 @@ pub struct GetModlog { #[derive(Serialize, Deserialize)] pub struct GetModlogResponse { - op: String, removed_posts: Vec, locked_posts: Vec, stickied_posts: Vec, @@ -79,13 +76,11 @@ pub struct GetSite; #[derive(Serialize, Deserialize)] pub struct SiteResponse { - op: String, site: SiteView, } #[derive(Serialize, Deserialize)] pub struct GetSiteResponse { - op: String, site: Option, admins: Vec, banned: Vec, @@ -105,10 +100,7 @@ impl Perform for Oper { let categories: Vec = Category::list_all(&conn)?; // Return the jwt - Ok(ListCategoriesResponse { - op: self.op.to_string(), - categories, - }) + Ok(ListCategoriesResponse { categories }) } } @@ -172,7 +164,6 @@ impl Perform for Oper { // Return the jwt Ok(GetModlogResponse { - op: self.op.to_string(), removed_posts, locked_posts, stickied_posts, @@ -192,20 +183,20 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; if has_slurs(&data.name) || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "no_slurs").into()); + return Err(APIError::err("no_slurs").into()); } let user_id = claims.id; // Make sure user is an admin if !UserView::read(&conn, user_id)?.admin { - return Err(APIError::err(&self.op, "not_an_admin").into()); + return Err(APIError::err("not_an_admin").into()); } let site_form = SiteForm { @@ -220,15 +211,12 @@ impl Perform for Oper { match Site::create(&conn, &site_form) { Ok(site) => site, - Err(_e) => return Err(APIError::err(&self.op, "site_already_exists").into()), + Err(_e) => return Err(APIError::err("site_already_exists").into()), }; let site_view = SiteView::read(&conn)?; - Ok(SiteResponse { - op: self.op.to_string(), - site: site_view, - }) + Ok(SiteResponse { site: site_view }) } } @@ -238,20 +226,20 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; if has_slurs(&data.name) || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { - return Err(APIError::err(&self.op, "no_slurs").into()); + return Err(APIError::err("no_slurs").into()); } let user_id = claims.id; // Make sure user is an admin if !UserView::read(&conn, user_id)?.admin { - return Err(APIError::err(&self.op, "not_an_admin").into()); + return Err(APIError::err("not_an_admin").into()); } let found_site = Site::read(&conn, 1)?; @@ -268,15 +256,12 @@ impl Perform for Oper { match Site::update(&conn, 1, &site_form) { Ok(site) => site, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_site").into()), + Err(_e) => return Err(APIError::err("couldnt_update_site").into()), }; let site_view = SiteView::read(&conn)?; - Ok(SiteResponse { - op: self.op.to_string(), - site: site_view, - }) + Ok(SiteResponse { site: site_view }) } } @@ -301,7 +286,6 @@ impl Perform for Oper { let banned = UserView::banned(&conn)?; Ok(GetSiteResponse { - op: self.op.to_string(), site: site_view, admins, banned, @@ -419,7 +403,6 @@ impl Perform for Oper { // Return the jwt Ok(SearchResponse { - op: self.op.to_string(), type_: data.type_.to_owned(), comments, posts, @@ -435,7 +418,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -444,7 +427,7 @@ impl Perform for Oper { // Make sure user is the creator if read_site.creator_id != user_id { - return Err(APIError::err(&self.op, "not_an_admin").into()); + return Err(APIError::err("not_an_admin").into()); } let site_form = SiteForm { @@ -459,7 +442,7 @@ impl Perform for Oper { match Site::update(&conn, 1, &site_form) { Ok(site) => site, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_site").into()), + Err(_e) => return Err(APIError::err("couldnt_update_site").into()), }; // Mod tables @@ -484,7 +467,6 @@ impl Perform for Oper { let banned = UserView::banned(&conn)?; Ok(GetSiteResponse { - op: self.op.to_string(), site: Some(site_view), admins, banned, diff --git a/server/src/api/user.rs b/server/src/api/user.rs index 046da6f..8d2db10 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -41,7 +41,6 @@ pub struct SaveUserSettings { #[derive(Serialize, Deserialize)] pub struct LoginResponse { - op: String, jwt: String, } @@ -59,7 +58,6 @@ pub struct GetUserDetails { #[derive(Serialize, Deserialize)] pub struct GetUserDetailsResponse { - op: String, user: UserView, follows: Vec, moderates: Vec, @@ -70,13 +68,11 @@ pub struct GetUserDetailsResponse { #[derive(Serialize, Deserialize)] pub struct GetRepliesResponse { - op: String, replies: Vec, } #[derive(Serialize, Deserialize)] pub struct GetUserMentionsResponse { - op: String, mentions: Vec, } @@ -94,7 +90,6 @@ pub struct AddAdmin { #[derive(Serialize, Deserialize)] pub struct AddAdminResponse { - op: String, admins: Vec, } @@ -109,7 +104,6 @@ pub struct BanUser { #[derive(Serialize, Deserialize)] pub struct BanUserResponse { - op: String, user: UserView, banned: bool, } @@ -141,7 +135,6 @@ pub struct EditUserMention { #[derive(Serialize, Deserialize, Clone)] pub struct UserMentionResponse { - op: String, mention: UserMentionView, } @@ -157,9 +150,7 @@ pub struct PasswordReset { } #[derive(Serialize, Deserialize, Clone)] -pub struct PasswordResetResponse { - op: String, -} +pub struct PasswordResetResponse {} #[derive(Serialize, Deserialize)] pub struct PasswordChange { @@ -194,13 +185,11 @@ pub struct GetPrivateMessages { #[derive(Serialize, Deserialize, Clone)] pub struct PrivateMessagesResponse { - op: String, messages: Vec, } #[derive(Serialize, Deserialize, Clone)] pub struct PrivateMessageResponse { - op: String, message: PrivateMessageView, } @@ -211,20 +200,17 @@ impl Perform for Oper { // Fetch that username / email let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email").into()), + Err(_e) => return Err(APIError::err("couldnt_find_that_username_or_email").into()), }; // Verify the password let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); if !valid { - return Err(APIError::err(&self.op, "password_incorrect").into()); + return Err(APIError::err("password_incorrect").into()); } // Return the jwt - Ok(LoginResponse { - op: self.op.to_string(), - jwt: user.jwt(), - }) + Ok(LoginResponse { jwt: user.jwt() }) } } @@ -235,22 +221,22 @@ impl Perform for Oper { // 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").into()); + return Err(APIError::err("registration_closed").into()); } } // Make sure passwords match if data.password != data.password_verify { - return Err(APIError::err(&self.op, "passwords_dont_match").into()); + return Err(APIError::err("passwords_dont_match").into()); } if has_slurs(&data.username) { - return Err(APIError::err(&self.op, "no_slurs").into()); + return Err(APIError::err("no_slurs").into()); } // Make sure there are no admins if data.admin && !UserView::admins(&conn)?.is_empty() { - return Err(APIError::err(&self.op, "admin_already_created").into()); + return Err(APIError::err("admin_already_created").into()); } // Register the new user @@ -286,7 +272,7 @@ impl Perform for Oper { "user_already_exists" }; - return Err(APIError::err(&self.op, err_type).into()); + return Err(APIError::err(err_type).into()); } }; @@ -318,7 +304,7 @@ impl Perform for Oper { 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").into()), + Err(_e) => return Err(APIError::err("community_follower_already_exists").into()), }; // If its an admin, add them as a mod and follower to main @@ -331,15 +317,12 @@ impl Perform for Oper { 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").into()) - } + Err(_e) => return Err(APIError::err("community_moderator_already_exists").into()), }; } // Return the jwt Ok(LoginResponse { - op: self.op.to_string(), jwt: inserted_user.jwt(), }) } @@ -351,7 +334,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -369,7 +352,7 @@ impl Perform for Oper { Some(new_password_verify) => { // Make sure passwords match if new_password != new_password_verify { - return Err(APIError::err(&self.op, "passwords_dont_match").into()); + return Err(APIError::err("passwords_dont_match").into()); } // Check the old password @@ -378,14 +361,14 @@ impl Perform for Oper { let valid: bool = verify(old_password, &read_user.password_encrypted).unwrap_or(false); if !valid { - return Err(APIError::err(&self.op, "password_incorrect").into()); + return Err(APIError::err("password_incorrect").into()); } User_::update_password(&conn, user_id, &new_password)?.password_encrypted } - None => return Err(APIError::err(&self.op, "password_incorrect").into()), + None => return Err(APIError::err("password_incorrect").into()), } } - None => return Err(APIError::err(&self.op, "passwords_dont_match").into()), + None => return Err(APIError::err("passwords_dont_match").into()), } } None => read_user.password_encrypted, @@ -422,13 +405,12 @@ impl Perform for Oper { "user_already_exists" }; - return Err(APIError::err(&self.op, err_type).into()); + return Err(APIError::err(err_type).into()); } }; // Return the jwt Ok(LoginResponse { - op: self.op.to_string(), jwt: updated_user.jwt(), }) } @@ -469,9 +451,7 @@ impl Perform for Oper { .unwrap_or_else(|| "admin".to_string()), ) { Ok(user) => user.id, - Err(_e) => { - return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email").into()) - } + Err(_e) => return Err(APIError::err("couldnt_find_that_username_or_email").into()), } } }; @@ -514,7 +494,6 @@ impl Perform for Oper { // Return the jwt Ok(GetUserDetailsResponse { - op: self.op.to_string(), user: user_view, follows, moderates, @@ -531,14 +510,14 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; // Make sure user is an admin if !UserView::read(&conn, user_id)?.admin { - return Err(APIError::err(&self.op, "not_an_admin").into()); + return Err(APIError::err("not_an_admin").into()); } let read_user = User_::read(&conn, data.user_id)?; @@ -566,7 +545,7 @@ impl Perform for Oper { match User_::update(&conn, data.user_id, &user_form) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user").into()), + Err(_e) => return Err(APIError::err("couldnt_update_user").into()), }; // Mod tables @@ -584,10 +563,7 @@ impl Perform for Oper { let creator_user = admins.remove(creator_index); admins.insert(0, creator_user); - Ok(AddAdminResponse { - op: self.op.to_string(), - admins, - }) + Ok(AddAdminResponse { admins }) } } @@ -597,14 +573,14 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; // Make sure user is an admin if !UserView::read(&conn, user_id)?.admin { - return Err(APIError::err(&self.op, "not_an_admin").into()); + return Err(APIError::err("not_an_admin").into()); } let read_user = User_::read(&conn, data.user_id)?; @@ -632,7 +608,7 @@ impl Perform for Oper { match User_::update(&conn, data.user_id, &user_form) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user").into()), + Err(_e) => return Err(APIError::err("couldnt_update_user").into()), }; // Mod tables @@ -654,7 +630,6 @@ impl Perform for Oper { let user_view = UserView::read(&conn, data.user_id)?; Ok(BanUserResponse { - op: self.op.to_string(), user: user_view, banned: data.ban, }) @@ -667,7 +642,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -681,10 +656,7 @@ impl Perform for Oper { .limit(data.limit) .list()?; - Ok(GetRepliesResponse { - op: self.op.to_string(), - replies, - }) + Ok(GetRepliesResponse { replies }) } } @@ -694,7 +666,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -708,10 +680,7 @@ impl Perform for Oper { .limit(data.limit) .list()?; - Ok(GetUserMentionsResponse { - op: self.op.to_string(), - mentions, - }) + Ok(GetUserMentionsResponse { mentions }) } } @@ -721,7 +690,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -737,13 +706,12 @@ impl Perform for Oper { let _updated_user_mention = match UserMention::update(&conn, user_mention.id, &user_mention_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; let user_mention_view = UserMentionView::read(&conn, user_mention.id, user_id)?; Ok(UserMentionResponse { - op: self.op.to_string(), mention: user_mention_view, }) } @@ -755,7 +723,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -780,7 +748,7 @@ impl Perform for Oper { let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; } @@ -801,7 +769,7 @@ impl Perform for Oper { let _updated_mention = match UserMention::update(&conn, mention.user_mention_id, &mention_form) { Ok(mention) => mention, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; } @@ -825,14 +793,11 @@ impl Perform for Oper { let _updated_message = match PrivateMessage::update(&conn, message.id, &private_message_form) { Ok(message) => message, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_private_message").into()), + Err(_e) => return Err(APIError::err("couldnt_update_private_message").into()), }; } - Ok(GetRepliesResponse { - op: self.op.to_string(), - replies: vec![], - }) + Ok(GetRepliesResponse { replies: vec![] }) } } @@ -842,7 +807,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -852,7 +817,7 @@ impl Perform for Oper { // Verify the password let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); if !valid { - return Err(APIError::err(&self.op, "password_incorrect").into()); + return Err(APIError::err("password_incorrect").into()); } // Comments @@ -875,7 +840,7 @@ impl Perform for Oper { let _updated_comment = match Comment::update(&conn, comment.id, &comment_form) { Ok(comment) => comment, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment").into()), + Err(_e) => return Err(APIError::err("couldnt_update_comment").into()), }; } @@ -903,12 +868,11 @@ impl Perform for Oper { let _updated_post = match Post::update(&conn, post.id, &post_form) { Ok(post) => post, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post").into()), + Err(_e) => return Err(APIError::err("couldnt_update_post").into()), }; } Ok(LoginResponse { - op: self.op.to_string(), jwt: data.auth.to_owned(), }) } @@ -921,7 +885,7 @@ impl Perform for Oper { // Fetch that email let user: User_ = match User_::find_by_email(&conn, &data.email) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email").into()), + Err(_e) => return Err(APIError::err("couldnt_find_that_username_or_email").into()), }; // Generate a random token @@ -938,12 +902,10 @@ impl Perform for Oper { let html = &format!("

Password Reset Request for {}


Click here to reset your password", user.name, hostname, &token); match send_email(subject, user_email, &user.name, html) { Ok(_o) => _o, - Err(_e) => return Err(APIError::err(&self.op, &_e).into()), + Err(_e) => return Err(APIError::err(&_e).into()), }; - Ok(PasswordResetResponse { - op: self.op.to_string(), - }) + Ok(PasswordResetResponse {}) } } @@ -956,18 +918,17 @@ impl Perform for Oper { // Make sure passwords match if data.password != data.password_verify { - return Err(APIError::err(&self.op, "passwords_dont_match").into()); + return Err(APIError::err("passwords_dont_match").into()); } // Update the user with the new password let updated_user = match User_::update_password(&conn, user_id, &data.password) { Ok(user) => user, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user").into()), + Err(_e) => return Err(APIError::err("couldnt_update_user").into()), }; // Return the jwt Ok(LoginResponse { - op: self.op.to_string(), jwt: updated_user.jwt(), }) } @@ -979,7 +940,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -988,7 +949,7 @@ impl Perform for Oper { // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } let content_slurs_removed = remove_slurs(&data.content.to_owned()); @@ -1005,7 +966,7 @@ impl Perform for Oper { let inserted_private_message = match PrivateMessage::create(&conn, &private_message_form) { Ok(private_message) => private_message, Err(_e) => { - return Err(APIError::err(&self.op, "couldnt_create_private_message").into()); + return Err(APIError::err("couldnt_create_private_message").into()); } }; @@ -1029,12 +990,9 @@ impl Perform for Oper { } } - let private_message_view = PrivateMessageView::read(&conn, inserted_private_message.id)?; + let message = PrivateMessageView::read(&conn, inserted_private_message.id)?; - Ok(PrivateMessageResponse { - op: self.op.to_string(), - message: private_message_view, - }) + Ok(PrivateMessageResponse { message }) } } @@ -1044,7 +1002,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -1053,14 +1011,14 @@ impl Perform for Oper { // Check for a site ban if UserView::read(&conn, user_id)?.banned { - return Err(APIError::err(&self.op, "site_ban").into()); + return Err(APIError::err("site_ban").into()); } // Check to make sure they are the creator (or the recipient marking as read if !(data.read.is_some() && orig_private_message.recipient_id.eq(&user_id) || orig_private_message.creator_id.eq(&user_id)) { - return Err(APIError::err(&self.op, "no_private_message_edit_allowed").into()); + return Err(APIError::err("no_private_message_edit_allowed").into()); } let content_slurs_removed = match &data.content { @@ -1084,15 +1042,12 @@ impl Perform for Oper { let _updated_private_message = match PrivateMessage::update(&conn, data.edit_id, &private_message_form) { Ok(private_message) => private_message, - Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_private_message").into()), + Err(_e) => return Err(APIError::err("couldnt_update_private_message").into()), }; - let private_message_view = PrivateMessageView::read(&conn, data.edit_id)?; + let message = PrivateMessageView::read(&conn, data.edit_id)?; - Ok(PrivateMessageResponse { - op: self.op.to_string(), - message: private_message_view, - }) + Ok(PrivateMessageResponse { message }) } } @@ -1102,7 +1057,7 @@ impl Perform for Oper { let claims = match Claims::decode(&data.auth) { Ok(claims) => claims.claims, - Err(_e) => return Err(APIError::err(&self.op, "not_logged_in").into()), + Err(_e) => return Err(APIError::err("not_logged_in").into()), }; let user_id = claims.id; @@ -1113,9 +1068,6 @@ impl Perform for Oper { .unread_only(data.unread_only) .list()?; - Ok(PrivateMessagesResponse { - op: self.op.to_string(), - messages, - }) + Ok(PrivateMessagesResponse { messages }) } } diff --git a/server/src/main.rs b/server/src/main.rs index 636182a..601c2e0 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -6,7 +6,7 @@ use actix::prelude::*; use actix_web::*; use diesel::r2d2::{ConnectionManager, Pool}; use diesel::PgConnection; -use lemmy_server::routes::{federation, feeds, index, nodeinfo, webfinger, websocket}; +use lemmy_server::routes::{api, federation, feeds, index, nodeinfo, webfinger, websocket}; use lemmy_server::settings::Settings; use lemmy_server::websocket::server::*; use std::io; @@ -44,6 +44,7 @@ async fn main() -> io::Result<()> { .data(pool.clone()) .data(server.clone()) // The routes + .configure(api::config) .configure(federation::config) .configure(feeds::config) .configure(index::config) diff --git a/server/src/routes/api.rs b/server/src/routes/api.rs new file mode 100644 index 0000000..5121d24 --- /dev/null +++ b/server/src/routes/api.rs @@ -0,0 +1,103 @@ +use crate::api::comment::*; +use crate::api::community::*; +use crate::api::post::*; +use crate::api::site::*; +use crate::api::user::*; +use crate::api::{Oper, Perform}; +use actix_web::{web, HttpResponse}; +use diesel::r2d2::{ConnectionManager, Pool}; +use diesel::PgConnection; +use failure::Error; +use serde::Serialize; + +type DbParam = web::Data>>; + +#[rustfmt::skip] +pub fn config(cfg: &mut web::ServiceConfig) { + cfg + // Site + .route("/api/v1/site", web::get().to(route_get::)) + .route("/api/v1/categories", web::get().to(route_get::)) + .route("/api/v1/modlog", web::get().to(route_get::)) + .route("/api/v1/search", web::get().to(route_get::)) + // Community + .route("/api/v1/community", web::post().to(route_post::)) + .route("/api/v1/community", web::get().to(route_get::)) + .route("/api/v1/community", web::put().to(route_post::)) + .route("/api/v1/community/list", web::get().to(route_get::)) + .route("/api/v1/community/follow", web::post().to(route_post::)) + // Post + .route("/api/v1/post", web::post().to(route_post::)) + .route("/api/v1/post", web::put().to(route_post::)) + .route("/api/v1/post", web::get().to(route_get::)) + .route("/api/v1/post/list", web::get().to(route_get::)) + .route("/api/v1/post/like", web::post().to(route_post::)) + .route("/api/v1/post/save", web::put().to(route_post::)) + // Comment + .route("/api/v1/comment", web::post().to(route_post::)) + .route("/api/v1/comment", web::put().to(route_post::)) + .route("/api/v1/comment/like", web::post().to(route_post::)) + .route("/api/v1/comment/save", web::put().to(route_post::)) + // User + .route("/api/v1/user", web::get().to(route_get::)) + .route("/api/v1/user/mention", web::get().to(route_get::)) + .route("/api/v1/user/mention", web::put().to(route_post::)) + .route("/api/v1/user/replies", web::get().to(route_get::)) + .route("/api/v1/user/followed_communities", web::get().to(route_get::)) + // Mod actions + .route("/api/v1/community/transfer", web::post().to(route_post::)) + .route("/api/v1/community/ban_user", web::post().to(route_post::)) + .route("/api/v1/community/mod", web::post().to(route_post::)) + // Admin actions + .route("/api/v1/site", web::post().to(route_post::)) + .route("/api/v1/site", web::put().to(route_post::)) + .route("/api/v1/site/transfer", web::post().to(route_post::)) + .route("/api/v1/admin/add", web::post().to(route_post::)) + .route("/api/v1/user/ban", web::post().to(route_post::)) + // User account actions + .route("/api/v1/user/login", web::post().to(route_post::)) + .route("/api/v1/user/register", web::post().to(route_post::)) + .route("/api/v1/user/delete_account", web::post().to(route_post::)) + .route("/api/v1/user/password_reset", web::post().to(route_post::)) + .route("/api/v1/user/password_change", web::post().to(route_post::)) + .route("/api/v1/user/mark_all_as_read", web::post().to(route_post::)) + .route("/api/v1/user/save_user_settings", web::put().to(route_post::)); +} + +fn perform(data: Request, db: DbParam) -> Result +where + Response: Serialize, + Oper: Perform, +{ + let conn = match db.get() { + Ok(c) => c, + Err(e) => return Err(format_err!("{}", e)), + }; + let oper: Oper = Oper::new(data); + let response = oper.perform(&conn); + Ok(HttpResponse::Ok().json(response?)) +} + +async fn route_get( + data: web::Query, + db: DbParam, +) -> Result +where + Data: Serialize, + Response: Serialize, + Oper: Perform, +{ + perform::(data.0, db) +} + +async fn route_post( + data: web::Json, + db: DbParam, +) -> Result +where + Data: Serialize, + Response: Serialize, + Oper: Perform, +{ + perform::(data.0, db) +} diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index 6556c8d..27d9ea1 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -1,3 +1,4 @@ +pub mod api; pub mod federation; pub mod feeds; pub mod index; diff --git a/server/src/websocket/mod.rs b/server/src/websocket/mod.rs index 74f47ad..021bcb4 100644 --- a/server/src/websocket/mod.rs +++ b/server/src/websocket/mod.rs @@ -1 +1,47 @@ pub mod server; + +#[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, + GetUserMentions, + EditUserMention, + GetModlog, + BanFromCommunity, + AddModToCommunity, + CreateSite, + EditSite, + GetSite, + AddAdmin, + BanUser, + Search, + MarkAllAsRead, + SaveUserSettings, + TransferCommunity, + TransferSite, + DeleteAccount, + PasswordReset, + PasswordChange, + CreatePrivateMessage, + EditPrivateMessage, + GetPrivateMessages, +} diff --git a/server/src/websocket/server.rs b/server/src/websocket/server.rs index 5efcb7b..b1d4f13 100644 --- a/server/src/websocket/server.rs +++ b/server/src/websocket/server.rs @@ -3,7 +3,7 @@ //! room through `ChatServer`. use actix::prelude::*; -use diesel::r2d2::{ConnectionManager, Pool}; +use diesel::r2d2::{ConnectionManager, Pool, PooledConnection}; use diesel::PgConnection; use failure::Error; use rand::{rngs::ThreadRng, Rng}; @@ -19,6 +19,7 @@ use crate::api::post::*; use crate::api::site::*; use crate::api::user::*; use crate::api::*; +use crate::websocket::UserOperation; use crate::Settings; /// Chat server sends this messages to session @@ -201,7 +202,6 @@ impl ChatServer { ); Err( APIError { - op: "Rate Limit".to_string(), message: format!("Too many requests. {} per {} seconds", rate, per), } .into(), @@ -295,11 +295,42 @@ impl Handler for ChatServer { } } +#[derive(Serialize)] +struct WebsocketResponse { + op: String, + data: T, +} + +fn to_json_string(op: &UserOperation, data: T) -> Result +where + T: Serialize, +{ + let response = WebsocketResponse { + op: op.to_string(), + data, + }; + Ok(serde_json::to_string(&response)?) +} + +fn do_user_operation<'a, Data, Response>( + op: UserOperation, + data: &str, + conn: &PooledConnection>, +) -> Result +where + for<'de> Data: Deserialize<'de> + 'a, + Response: Serialize, + Oper: Perform, +{ + let parsed_data: Data = serde_json::from_str(data)?; + let res = Oper::new(parsed_data).perform(&conn)?; + to_json_string(&op, &res) +} + fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result { let json: Value = serde_json::from_str(&msg.msg)?; let data = &json["data"].to_string(); let op = &json["op"].as_str().ok_or(APIError { - op: "Unknown op type".to_string(), message: "Unknown op type".to_string(), })?; @@ -307,261 +338,194 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result { - let login: Login = serde_json::from_str(data)?; - let res = Oper::new(user_operation, login).perform(&conn)?; - Ok(serde_json::to_string(&res)?) - } + UserOperation::Login => do_user_operation::(user_operation, data, &conn), UserOperation::Register => { - let register: Register = serde_json::from_str(data)?; - let res = Oper::new(user_operation, register).perform(&conn); - if res.is_ok() { - chat.check_rate_limit_register(msg.id)?; - } - Ok(serde_json::to_string(&res?)?) + chat.check_rate_limit_register(msg.id)?; + do_user_operation::(user_operation, data, &conn) } UserOperation::GetUserDetails => { - let get_user_details: GetUserDetails = serde_json::from_str(data)?; - let res = Oper::new(user_operation, get_user_details).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::SaveUserSettings => { - let save_user_settings: SaveUserSettings = serde_json::from_str(data)?; - let res = Oper::new(user_operation, save_user_settings).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::AddAdmin => { - let add_admin: AddAdmin = serde_json::from_str(data)?; - let res = Oper::new(user_operation, add_admin).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::BanUser => { - let ban_user: BanUser = serde_json::from_str(data)?; - let res = Oper::new(user_operation, ban_user).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::GetReplies => { - let get_replies: GetReplies = serde_json::from_str(data)?; - let res = Oper::new(user_operation, get_replies).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::GetUserMentions => { - let get_user_mentions: GetUserMentions = serde_json::from_str(data)?; - let res = Oper::new(user_operation, get_user_mentions).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::EditUserMention => { - let edit_user_mention: EditUserMention = serde_json::from_str(data)?; - let res = Oper::new(user_operation, edit_user_mention).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::MarkAllAsRead => { - let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?; - let res = Oper::new(user_operation, mark_all_as_read).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::GetCommunity => { - let get_community: GetCommunity = serde_json::from_str(data)?; - let res = Oper::new(user_operation, get_community).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::ListCommunities => { - let list_communities: ListCommunities = serde_json::from_str(data)?; - let res = Oper::new(user_operation, list_communities).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } 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(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::EditCommunity => { let edit_community: EditCommunity = serde_json::from_str(data)?; - let res = Oper::new(user_operation, edit_community).perform(&conn)?; + let res = Oper::new(edit_community).perform(&conn)?; 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)?; + let community_sent_str = to_json_string(&user_operation, &community_sent)?; chat.send_community_message(community_sent.community.id, &community_sent_str, msg.id)?; - Ok(serde_json::to_string(&res)?) + to_json_string(&user_operation, &res) } UserOperation::FollowCommunity => { - let follow_community: FollowCommunity = serde_json::from_str(data)?; - let res = Oper::new(user_operation, follow_community).perform(&conn)?; - 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(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } + UserOperation::GetFollowedCommunities => do_user_operation::< + GetFollowedCommunities, + GetFollowedCommunitiesResponse, + >(user_operation, data, &conn), UserOperation::BanFromCommunity => { let ban_from_community: BanFromCommunity = serde_json::from_str(data)?; let community_id = ban_from_community.community_id; - let res = Oper::new(user_operation, ban_from_community).perform(&conn)?; - let res_str = serde_json::to_string(&res)?; + let res = Oper::new(ban_from_community).perform(&conn)?; + let res_str = to_json_string(&user_operation, &res)?; chat.send_community_message(community_id, &res_str, msg.id)?; Ok(res_str) } UserOperation::AddModToCommunity => { let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?; let community_id = mod_add_to_community.community_id; - let res = Oper::new(user_operation, mod_add_to_community).perform(&conn)?; - let res_str = serde_json::to_string(&res)?; + let res = Oper::new(mod_add_to_community).perform(&conn)?; + let res_str = to_json_string(&user_operation, &res)?; chat.send_community_message(community_id, &res_str, msg.id)?; Ok(res_str) } UserOperation::ListCategories => { - let list_categories: ListCategories = ListCategories; - let res = Oper::new(user_operation, list_categories).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::CreatePost => { chat.check_rate_limit_post(msg.id)?; - let create_post: CreatePost = serde_json::from_str(data)?; - let res = Oper::new(user_operation, create_post).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::GetPost => { let get_post: GetPost = serde_json::from_str(data)?; chat.join_room(get_post.id, msg.id); - let res = Oper::new(user_operation, get_post).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + let res = Oper::new(get_post).perform(&conn)?; + to_json_string(&user_operation, &res) } UserOperation::GetPosts => { - let get_posts: GetPosts = serde_json::from_str(data)?; - let res = Oper::new(user_operation, get_posts).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::CreatePostLike => { chat.check_rate_limit_message(msg.id)?; - let create_post_like: CreatePostLike = serde_json::from_str(data)?; - let res = Oper::new(user_operation, create_post_like).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::EditPost => { let edit_post: EditPost = serde_json::from_str(data)?; - let res = Oper::new(user_operation, edit_post).perform(&conn)?; + let res = Oper::new(edit_post).perform(&conn)?; let mut post_sent = res.clone(); post_sent.post.my_vote = None; - let post_sent_str = serde_json::to_string(&post_sent)?; + let post_sent_str = to_json_string(&user_operation, &post_sent)?; chat.send_room_message(post_sent.post.id, &post_sent_str, msg.id); - Ok(serde_json::to_string(&res)?) + to_json_string(&user_operation, &res) } UserOperation::SavePost => { - let save_post: SavePost = serde_json::from_str(data)?; - let res = Oper::new(user_operation, save_post).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::CreateComment => { chat.check_rate_limit_message(msg.id)?; let create_comment: CreateComment = serde_json::from_str(data)?; let post_id = create_comment.post_id; - let res = Oper::new(user_operation, create_comment).perform(&conn)?; + let res = Oper::new(create_comment).perform(&conn)?; 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)?; + let comment_sent_str = to_json_string(&user_operation, &comment_sent)?; chat.send_room_message(post_id, &comment_sent_str, msg.id); - Ok(serde_json::to_string(&res)?) + to_json_string(&user_operation, &res) } UserOperation::EditComment => { let edit_comment: EditComment = serde_json::from_str(data)?; let post_id = edit_comment.post_id; - let res = Oper::new(user_operation, edit_comment).perform(&conn)?; + let res = Oper::new(edit_comment).perform(&conn)?; 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)?; + let comment_sent_str = to_json_string(&user_operation, &comment_sent)?; chat.send_room_message(post_id, &comment_sent_str, msg.id); - Ok(serde_json::to_string(&res)?) + to_json_string(&user_operation, &res) } UserOperation::SaveComment => { - let save_comment: SaveComment = serde_json::from_str(data)?; - let res = Oper::new(user_operation, save_comment).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::CreateCommentLike => { chat.check_rate_limit_message(msg.id)?; let create_comment_like: CreateCommentLike = serde_json::from_str(data)?; let post_id = create_comment_like.post_id; - let res = Oper::new(user_operation, create_comment_like).perform(&conn)?; + let res = Oper::new(create_comment_like).perform(&conn)?; 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)?; + let comment_sent_str = to_json_string(&user_operation, &comment_sent)?; chat.send_room_message(post_id, &comment_sent_str, msg.id); - Ok(serde_json::to_string(&res)?) + to_json_string(&user_operation, &res) } UserOperation::GetModlog => { - let get_modlog: GetModlog = serde_json::from_str(data)?; - let res = Oper::new(user_operation, get_modlog).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::CreateSite => { - let create_site: CreateSite = serde_json::from_str(data)?; - let res = Oper::new(user_operation, create_site).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::EditSite => { - let edit_site: EditSite = serde_json::from_str(data)?; - let res = Oper::new(user_operation, edit_site).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::GetSite => { let online: usize = chat.sessions.len(); let get_site: GetSite = serde_json::from_str(data)?; - let mut res = Oper::new(user_operation, get_site).perform(&conn)?; + let mut res = Oper::new(get_site).perform(&conn)?; res.online = online; - Ok(serde_json::to_string(&res)?) + to_json_string(&user_operation, &res) } UserOperation::Search => { - let search: Search = serde_json::from_str(data)?; - let res = Oper::new(user_operation, search).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::TransferCommunity => { - let transfer_community: TransferCommunity = serde_json::from_str(data)?; - let res = Oper::new(user_operation, transfer_community).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::TransferSite => { - let transfer_site: TransferSite = serde_json::from_str(data)?; - let res = Oper::new(user_operation, transfer_site).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::DeleteAccount => { - let delete_account: DeleteAccount = serde_json::from_str(data)?; - let res = Oper::new(user_operation, delete_account).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::PasswordReset => { - let password_reset: PasswordReset = serde_json::from_str(data)?; - let res = Oper::new(user_operation, password_reset).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::PasswordChange => { - let password_change: PasswordChange = serde_json::from_str(data)?; - let res = Oper::new(user_operation, password_change).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::CreatePrivateMessage => { chat.check_rate_limit_message(msg.id)?; - let create_private_message: CreatePrivateMessage = serde_json::from_str(data)?; - let res = Oper::new(user_operation, create_private_message).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::EditPrivateMessage => { - let edit_private_message: EditPrivateMessage = serde_json::from_str(data)?; - let res = Oper::new(user_operation, edit_private_message).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } UserOperation::GetPrivateMessages => { - let messages: GetPrivateMessages = serde_json::from_str(data)?; - let res = Oper::new(user_operation, messages).perform(&conn)?; - Ok(serde_json::to_string(&res)?) + do_user_operation::(user_operation, data, &conn) } } } diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 6fbdc5d..b8ea0a5 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -10,9 +10,9 @@ import { } from '../interfaces'; import { Subscription } from 'rxjs'; import { + wsJsonToRes, capitalizeFirstLetter, mentionDropdownFetchLimit, - msgOp, mdToHtml, randomStr, markdownHelpUrl, @@ -312,10 +312,10 @@ export class CommentForm extends Component { this.userSub = WebSocketService.Instance.subject.subscribe( msg => { - let op: UserOperation = msgOp(msg); - if (op == UserOperation.Search) { - let res: SearchResponse = msg; - let users = res.users.map(u => { + let res = wsJsonToRes(msg); + if (res.op == UserOperation.Search) { + let data = res.data as SearchResponse; + let users = data.users.map(u => { return { key: u.name }; }); cb(users); @@ -344,10 +344,10 @@ export class CommentForm extends Component { this.communitySub = WebSocketService.Instance.subject.subscribe( msg => { - let op: UserOperation = msgOp(msg); - if (op == UserOperation.Search) { - let res: SearchResponse = msg; - let communities = res.communities.map(u => { + let res = wsJsonToRes(msg); + if (res.op == UserOperation.Search) { + let data = res.data as SearchResponse; + let communities = data.communities.map(u => { return { key: u.name }; }); cb(communities); diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 129051f..867cfd8 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -10,9 +10,10 @@ import { FollowCommunityForm, ListCommunitiesForm, SortType, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp, toast } from '../utils'; +import { wsJsonToRes, toast } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -231,15 +232,15 @@ export class Communities extends Component { WebSocketService.Instance.listCommunities(listCommunitiesForm); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (op == UserOperation.ListCommunities) { - let res: ListCommunitiesResponse = msg; - this.state.communities = res.communities; + } else if (res.op == UserOperation.ListCommunities) { + let data = res.data as ListCommunitiesResponse; + this.state.communities = data.communities; this.state.communities.sort( (a, b) => b.number_of_subscribers - a.number_of_subscribers ); @@ -248,11 +249,11 @@ export class Communities extends Component { this.setState(this.state); let table = document.querySelector('#community_table'); Sortable.initTable(table); - } else if (op == UserOperation.FollowCommunity) { - let res: CommunityResponse = msg; - let found = this.state.communities.find(c => c.id == res.community.id); - found.subscribed = res.community.subscribed; - found.number_of_subscribers = res.community.number_of_subscribers; + } else if (res.op == UserOperation.FollowCommunity) { + let data = res.data as CommunityResponse; + let found = this.state.communities.find(c => c.id == data.community.id); + found.subscribed = data.community.subscribed; + found.number_of_subscribers = data.community.number_of_subscribers; this.setState(this.state); } } diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index ec58b01..4dc7bfc 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -8,9 +8,10 @@ import { ListCategoriesResponse, CommunityResponse, GetSiteResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp, capitalizeFirstLetter, toast } from '../utils'; +import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils'; import autosize from 'autosize'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -239,34 +240,34 @@ export class CommunityForm extends Component< i.props.onCancel(); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); console.log(msg); - if (msg.error) { + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; - } else if (op == UserOperation.ListCategories) { - let res: ListCategoriesResponse = msg; - this.state.categories = res.categories; + } else if (res.op == UserOperation.ListCategories) { + let data = res.data as ListCategoriesResponse; + this.state.categories = data.categories; if (!this.props.community) { - this.state.communityForm.category_id = res.categories[0].id; + this.state.communityForm.category_id = data.categories[0].id; } this.setState(this.state); - } else if (op == UserOperation.CreateCommunity) { - let res: CommunityResponse = msg; + } else if (res.op == UserOperation.CreateCommunity) { + let data = res.data as CommunityResponse; this.state.loading = false; - this.props.onCreate(res.community); + this.props.onCreate(data.community); } - // TODO is ths necessary - else if (op == UserOperation.EditCommunity) { - let res: CommunityResponse = msg; + // TODO is this necessary + else if (res.op == UserOperation.EditCommunity) { + let data = res.data as CommunityResponse; this.state.loading = false; - this.props.onEdit(res.community); - } else if (op == UserOperation.GetSite) { - let res: GetSiteResponse = msg; - this.state.enable_nsfw = res.site.enable_nsfw; + this.props.onEdit(data.community); + } else if (res.op == UserOperation.GetSite) { + let data = res.data as GetSiteResponse; + this.state.enable_nsfw = data.site.enable_nsfw; this.setState(this.state); } } diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index dfd4d6b..9d02dd8 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -14,13 +14,14 @@ import { ListingType, GetPostsResponse, CreatePostLikeResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { PostListings } from './post-listings'; import { SortSelect } from './sort-select'; import { Sidebar } from './sidebar'; import { - msgOp, + wsJsonToRes, routeSortTypeToEnum, fetchLimit, postRefetchSeconds, @@ -254,43 +255,43 @@ export class Community extends Component { WebSocketService.Instance.getPosts(getPostsForm); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.context.router.history.push('/'); return; - } else if (op == UserOperation.GetCommunity) { - let res: GetCommunityResponse = msg; - this.state.community = res.community; - this.state.moderators = res.moderators; - this.state.admins = res.admins; + } else if (res.op == UserOperation.GetCommunity) { + let data = res.data as GetCommunityResponse; + this.state.community = data.community; + this.state.moderators = data.moderators; + this.state.admins = data.admins; document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`; this.setState(this.state); this.keepFetchingPosts(); - } else if (op == UserOperation.EditCommunity) { - let res: CommunityResponse = msg; - this.state.community = res.community; + } else if (res.op == UserOperation.EditCommunity) { + let data = res.data as CommunityResponse; + this.state.community = data.community; this.setState(this.state); - } else if (op == UserOperation.FollowCommunity) { - let res: CommunityResponse = msg; - this.state.community.subscribed = res.community.subscribed; + } else if (res.op == UserOperation.FollowCommunity) { + let data = res.data as CommunityResponse; + this.state.community.subscribed = data.community.subscribed; this.state.community.number_of_subscribers = - res.community.number_of_subscribers; + data.community.number_of_subscribers; this.setState(this.state); - } else if (op == UserOperation.GetPosts) { - let res: GetPostsResponse = msg; - this.state.posts = res.posts; + } else if (res.op == UserOperation.GetPosts) { + let data = res.data as GetPostsResponse; + this.state.posts = data.posts; this.state.loading = false; this.setState(this.state); - } else if (op == UserOperation.CreatePostLike) { - let res: CreatePostLikeResponse = msg; - let found = this.state.posts.find(c => c.id == res.post.id); - found.my_vote = res.post.my_vote; - found.score = res.post.score; - found.upvotes = res.post.upvotes; - found.downvotes = res.post.downvotes; + } else if (res.op == UserOperation.CreatePostLike) { + let data = res.data as CreatePostLikeResponse; + let found = this.state.posts.find(c => c.id == data.post.id); + found.my_vote = data.post.my_vote; + found.score = data.post.score; + found.upvotes = data.post.upvotes; + found.downvotes = data.post.downvotes; this.setState(this.state); } } diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index bf09017..5c3ff6d 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -12,13 +12,14 @@ import { GetUserMentionsResponse, UserMentionResponse, CommentResponse, + WebSocketJsonResponse, PrivateMessage as PrivateMessageI, GetPrivateMessagesForm, PrivateMessagesResponse, PrivateMessageResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, fetchLimit, isCommentType, toast } from '../utils'; +import { wsJsonToRes, fetchLimit, isCommentType, toast } from '../utils'; import { CommentNodes } from './comment-nodes'; import { PrivateMessage } from './private-message'; import { SortSelect } from './sort-select'; @@ -320,122 +321,122 @@ export class Inbox extends Component { WebSocketService.Instance.markAllAsRead(); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (op == UserOperation.GetReplies) { - let res: GetRepliesResponse = msg; - this.state.replies = res.replies; + } else if (res.op == UserOperation.GetReplies) { + let data = res.data as GetRepliesResponse; + this.state.replies = data.replies; this.sendUnreadCount(); window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.GetUserMentions) { - let res: GetUserMentionsResponse = msg; - this.state.mentions = res.mentions; + } else if (res.op == UserOperation.GetUserMentions) { + let data = res.data as GetUserMentionsResponse; + this.state.mentions = data.mentions; this.sendUnreadCount(); window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.GetPrivateMessages) { - let res: PrivateMessagesResponse = msg; - this.state.messages = res.messages; + } else if (res.op == UserOperation.GetPrivateMessages) { + let data = res.data as PrivateMessagesResponse; + this.state.messages = data.messages; this.sendUnreadCount(); window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.EditPrivateMessage) { - let res: PrivateMessageResponse = msg; + } else if (res.op == UserOperation.EditPrivateMessage) { + let data = res.data as PrivateMessageResponse; let found: PrivateMessageI = this.state.messages.find( - m => m.id === res.message.id + m => m.id === data.message.id ); - found.content = res.message.content; - found.updated = res.message.updated; - found.deleted = res.message.deleted; + found.content = data.message.content; + found.updated = data.message.updated; + found.deleted = data.message.deleted; // If youre in the unread view, just remove it from the list - if (this.state.unreadOrAll == UnreadOrAll.Unread && res.message.read) { + if (this.state.unreadOrAll == UnreadOrAll.Unread && data.message.read) { this.state.messages = this.state.messages.filter( - r => r.id !== res.message.id + r => r.id !== data.message.id ); } else { - let found = this.state.messages.find(c => c.id == res.message.id); - found.read = res.message.read; + let found = this.state.messages.find(c => c.id == data.message.id); + found.read = data.message.read; } this.sendUnreadCount(); window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.MarkAllAsRead) { + } else if (res.op == UserOperation.MarkAllAsRead) { this.state.replies = []; this.state.mentions = []; this.state.messages = []; this.sendUnreadCount(); window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.EditComment) { - let res: CommentResponse = msg; + } else if (res.op == UserOperation.EditComment) { + let data = res.data as CommentResponse; - let found = this.state.replies.find(c => c.id == res.comment.id); - found.content = res.comment.content; - found.updated = res.comment.updated; - found.removed = res.comment.removed; - found.deleted = res.comment.deleted; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - found.score = res.comment.score; + let found = this.state.replies.find(c => c.id == data.comment.id); + found.content = data.comment.content; + found.updated = data.comment.updated; + found.removed = data.comment.removed; + found.deleted = data.comment.deleted; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + found.score = data.comment.score; // If youre in the unread view, just remove it from the list - if (this.state.unreadOrAll == UnreadOrAll.Unread && res.comment.read) { + if (this.state.unreadOrAll == UnreadOrAll.Unread && data.comment.read) { this.state.replies = this.state.replies.filter( - r => r.id !== res.comment.id + r => r.id !== data.comment.id ); } else { - let found = this.state.replies.find(c => c.id == res.comment.id); - found.read = res.comment.read; + let found = this.state.replies.find(c => c.id == data.comment.id); + found.read = data.comment.read; } this.sendUnreadCount(); this.setState(this.state); - } else if (op == UserOperation.EditUserMention) { - let res: UserMentionResponse = msg; + } else if (res.op == UserOperation.EditUserMention) { + let data = res.data as UserMentionResponse; - let found = this.state.mentions.find(c => c.id == res.mention.id); - found.content = res.mention.content; - found.updated = res.mention.updated; - found.removed = res.mention.removed; - found.deleted = res.mention.deleted; - found.upvotes = res.mention.upvotes; - found.downvotes = res.mention.downvotes; - found.score = res.mention.score; + let found = this.state.mentions.find(c => c.id == data.mention.id); + found.content = data.mention.content; + found.updated = data.mention.updated; + found.removed = data.mention.removed; + found.deleted = data.mention.deleted; + found.upvotes = data.mention.upvotes; + found.downvotes = data.mention.downvotes; + found.score = data.mention.score; // If youre in the unread view, just remove it from the list - if (this.state.unreadOrAll == UnreadOrAll.Unread && res.mention.read) { + if (this.state.unreadOrAll == UnreadOrAll.Unread && data.mention.read) { this.state.mentions = this.state.mentions.filter( - r => r.id !== res.mention.id + r => r.id !== data.mention.id ); } else { - let found = this.state.mentions.find(c => c.id == res.mention.id); - found.read = res.mention.read; + let found = this.state.mentions.find(c => c.id == data.mention.id); + found.read = data.mention.read; } this.sendUnreadCount(); this.setState(this.state); - } else if (op == UserOperation.CreateComment) { + } else if (res.op == UserOperation.CreateComment) { // let res: CommentResponse = msg; toast(i18n.t('reply_sent')); // this.state.replies.unshift(res.comment); // TODO do this right // this.setState(this.state); - } else if (op == UserOperation.SaveComment) { - let res: CommentResponse = msg; - let found = this.state.replies.find(c => c.id == res.comment.id); - found.saved = res.comment.saved; + } else if (res.op == UserOperation.SaveComment) { + let data = res.data as CommentResponse; + let found = this.state.replies.find(c => c.id == data.comment.id); + found.saved = data.comment.saved; this.setState(this.state); - } else if (op == UserOperation.CreateCommentLike) { - let res: CommentResponse = msg; + } else if (res.op == UserOperation.CreateCommentLike) { + let data = res.data as CommentResponse; let found: Comment = this.state.replies.find( - c => c.id === res.comment.id + c => c.id === data.comment.id ); - found.score = res.comment.score; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote; + found.score = data.comment.score; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + if (data.comment.my_vote !== null) found.my_vote = data.comment.my_vote; this.setState(this.state); } } diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx index 0c8350a..ac60ba7 100644 --- a/ui/src/components/login.tsx +++ b/ui/src/components/login.tsx @@ -8,9 +8,10 @@ import { UserOperation, PasswordResetForm, GetSiteResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, validEmail, toast } from '../utils'; +import { wsJsonToRes, validEmail, toast } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -292,32 +293,32 @@ export class Login extends Component { WebSocketService.Instance.passwordReset(resetForm); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); - if (msg.error) { + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.state = this.emptyState; this.setState(this.state); return; } else { - if (op == UserOperation.Login) { + if (res.op == UserOperation.Login) { + let data = res.data as LoginResponse; this.state = this.emptyState; this.setState(this.state); - let res: LoginResponse = msg; - UserService.Instance.login(res); + UserService.Instance.login(data); toast(i18n.t('logged_in')); this.props.history.push('/'); - } else if (op == UserOperation.Register) { + } else if (res.op == UserOperation.Register) { + let data = res.data as LoginResponse; this.state = this.emptyState; this.setState(this.state); - let res: LoginResponse = msg; - UserService.Instance.login(res); + UserService.Instance.login(data); this.props.history.push('/communities'); - } else if (op == UserOperation.PasswordReset) { + } else if (res.op == UserOperation.PasswordReset) { toast(i18n.t('reset_password_mail_sent')); - } else if (op == UserOperation.GetSite) { - let res: GetSiteResponse = msg; - this.state.enable_nsfw = res.site.enable_nsfw; + } else if (res.op == UserOperation.GetSite) { + let data = res.data as GetSiteResponse; + this.state.enable_nsfw = data.site.enable_nsfw; this.setState(this.state); document.title = `${i18n.t('login')} - ${ WebSocketService.Instance.site.name diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index b244ce6..9f16edb 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -17,6 +17,7 @@ import { CreatePostLikeResponse, Post, GetPostsForm, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { PostListings } from './post-listings'; @@ -24,7 +25,7 @@ import { SortSelect } from './sort-select'; import { ListingTypeSelect } from './listing-type-select'; import { SiteForm } from './site-form'; import { - msgOp, + wsJsonToRes, repoUrl, mdToHtml, fetchLimit, @@ -57,7 +58,6 @@ export class Main extends Component { subscribedCommunities: [], trendingCommunities: [], site: { - op: null, site: { id: null, name: null, @@ -563,50 +563,50 @@ export class Main extends Component { WebSocketService.Instance.getPosts(getPostsForm); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (op == UserOperation.GetFollowedCommunities) { - let res: GetFollowedCommunitiesResponse = msg; - this.state.subscribedCommunities = res.communities; + } else if (res.op == UserOperation.GetFollowedCommunities) { + let data = res.data as GetFollowedCommunitiesResponse; + this.state.subscribedCommunities = data.communities; this.setState(this.state); - } else if (op == UserOperation.ListCommunities) { - let res: ListCommunitiesResponse = msg; - this.state.trendingCommunities = res.communities; + } else if (res.op == UserOperation.ListCommunities) { + let data = res.data as ListCommunitiesResponse; + this.state.trendingCommunities = data.communities; this.setState(this.state); - } else if (op == UserOperation.GetSite) { - let res: GetSiteResponse = msg; + } else if (res.op == UserOperation.GetSite) { + let data = res.data as GetSiteResponse; // This means it hasn't been set up yet - if (!res.site) { + if (!data.site) { this.context.router.history.push('/setup'); } - this.state.site.admins = res.admins; - this.state.site.site = res.site; - this.state.site.banned = res.banned; - this.state.site.online = res.online; + this.state.site.admins = data.admins; + this.state.site.site = data.site; + this.state.site.banned = data.banned; + this.state.site.online = data.online; this.setState(this.state); document.title = `${WebSocketService.Instance.site.name}`; - } else if (op == UserOperation.EditSite) { - let res: SiteResponse = msg; - this.state.site.site = res.site; + } else if (res.op == UserOperation.EditSite) { + let data = res.data as SiteResponse; + this.state.site.site = data.site; this.state.showEditSite = false; this.setState(this.state); - } else if (op == UserOperation.GetPosts) { - let res: GetPostsResponse = msg; - this.state.posts = res.posts; + } else if (res.op == UserOperation.GetPosts) { + let data = res.data as GetPostsResponse; + this.state.posts = data.posts; this.state.loading = false; this.setState(this.state); - } else if (op == UserOperation.CreatePostLike) { - let res: CreatePostLikeResponse = msg; - let found = this.state.posts.find(c => c.id == res.post.id); - found.my_vote = res.post.my_vote; - found.score = res.post.score; - found.upvotes = res.post.upvotes; - found.downvotes = res.post.downvotes; + } else if (res.op == UserOperation.CreatePostLike) { + let data = res.data as CreatePostLikeResponse; + let found = this.state.posts.find(c => c.id == data.post.id); + found.my_vote = data.post.my_vote; + found.score = data.post.score; + found.upvotes = data.post.upvotes; + found.downvotes = data.post.downvotes; this.setState(this.state); } } diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx index 6c35bce..dd65109 100644 --- a/ui/src/components/modlog.tsx +++ b/ui/src/components/modlog.tsx @@ -17,7 +17,7 @@ import { ModAdd, } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp, addTypeInfo, fetchLimit, toast } from '../utils'; +import { wsJsonToRes, addTypeInfo, fetchLimit, toast } from '../utils'; import { MomentTime } from './moment-time'; import moment from 'moment'; import { i18n } from '../i18next'; @@ -422,17 +422,17 @@ export class Modlog extends Component { WebSocketService.Instance.getModlog(modlogForm); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (op == UserOperation.GetModlog) { - let res: GetModlogResponse = msg; + } else if (res.op == UserOperation.GetModlog) { + let data = res.data as GetModlogResponse; this.state.loading = false; window.scrollTo(0, 0); - this.setCombined(res); + this.setCombined(data); } } } diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 81124f7..849822a 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -15,9 +15,10 @@ import { GetSiteResponse, Comment, PrivateMessage, + WebSocketJsonResponse, } from '../interfaces'; import { - msgOp, + wsJsonToRes, pictshareAvatarThumbnail, showAvatars, fetchLimit, @@ -199,17 +200,17 @@ export class Navbar extends Component { i.setState(i.state); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); - if (msg.error) { - if (msg.error == 'not_logged_in') { + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); + if (res.error) { + if (res.error == 'not_logged_in') { UserService.Instance.logout(); location.reload(); } return; - } else if (op == UserOperation.GetReplies) { - let res: GetRepliesResponse = msg; - let unreadReplies = res.replies.filter(r => !r.read); + } else if (res.op == UserOperation.GetReplies) { + let data = res.data as GetRepliesResponse; + let unreadReplies = data.replies.filter(r => !r.read); if ( unreadReplies.length > 0 && this.state.fetchCount > 1 && @@ -221,9 +222,9 @@ export class Navbar extends Component { this.state.replies = unreadReplies; this.setState(this.state); this.sendUnreadCount(); - } else if (op == UserOperation.GetUserMentions) { - let res: GetUserMentionsResponse = msg; - let unreadMentions = res.mentions.filter(r => !r.read); + } else if (res.op == UserOperation.GetUserMentions) { + let data = res.data as GetUserMentionsResponse; + let unreadMentions = data.mentions.filter(r => !r.read); if ( unreadMentions.length > 0 && this.state.fetchCount > 1 && @@ -235,9 +236,9 @@ export class Navbar extends Component { this.state.mentions = unreadMentions; this.setState(this.state); this.sendUnreadCount(); - } else if (op == UserOperation.GetPrivateMessages) { - let res: PrivateMessagesResponse = msg; - let unreadMessages = res.messages.filter(r => !r.read); + } else if (res.op == UserOperation.GetPrivateMessages) { + let data = res.data as PrivateMessagesResponse; + let unreadMessages = data.messages.filter(r => !r.read); if ( unreadMessages.length > 0 && this.state.fetchCount > 1 && @@ -249,12 +250,12 @@ export class Navbar extends Component { this.state.messages = unreadMessages; this.setState(this.state); this.sendUnreadCount(); - } else if (op == UserOperation.GetSite) { - let res: GetSiteResponse = msg; + } else if (res.op == UserOperation.GetSite) { + let data = res.data as GetSiteResponse; - if (res.site) { - this.state.siteName = res.site.name; - WebSocketService.Instance.site = res.site; + if (data.site) { + this.state.siteName = data.site.name; + WebSocketService.Instance.site = data.site; this.setState(this.state); } } diff --git a/ui/src/components/password_change.tsx b/ui/src/components/password_change.tsx index 76b4fb0..10b6867 100644 --- a/ui/src/components/password_change.tsx +++ b/ui/src/components/password_change.tsx @@ -5,9 +5,10 @@ import { UserOperation, LoginResponse, PasswordChangeForm, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, capitalizeFirstLetter, toast } from '../utils'; +import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -133,19 +134,19 @@ export class PasswordChange extends Component { WebSocketService.Instance.passwordChange(i.state.passwordChangeForm); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); if (msg.error) { toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; } else { - if (op == UserOperation.PasswordChange) { + if (res.op == UserOperation.PasswordChange) { + let data = res.data as LoginResponse; this.state = this.emptyState; this.setState(this.state); - let res: LoginResponse = msg; - UserService.Instance.login(res); + UserService.Instance.login(data); this.props.history.push('/'); } } diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 97a4409..4406177 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -16,10 +16,11 @@ import { SearchType, SearchResponse, GetSiteResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { - msgOp, + wsJsonToRes, getPageTitle, validURL, capitalizeFirstLetter, @@ -458,47 +459,47 @@ export class PostForm extends Component { }); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); - if (msg.error) { + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; - } else if (op == UserOperation.ListCommunities) { - let res: ListCommunitiesResponse = msg; - this.state.communities = res.communities; + } else if (res.op == UserOperation.ListCommunities) { + let data = res.data as ListCommunitiesResponse; + this.state.communities = data.communities; if (this.props.post) { this.state.postForm.community_id = this.props.post.community_id; } else if (this.props.params && this.props.params.community) { - let foundCommunityId = res.communities.find( + let foundCommunityId = data.communities.find( r => r.name == this.props.params.community ).id; this.state.postForm.community_id = foundCommunityId; } else { - this.state.postForm.community_id = res.communities[0].id; + this.state.postForm.community_id = data.communities[0].id; } this.setState(this.state); - } else if (op == UserOperation.CreatePost) { + } else if (res.op == UserOperation.CreatePost) { + let data = res.data as PostResponse; this.state.loading = false; - let res: PostResponse = msg; - this.props.onCreate(res.post.id); - } else if (op == UserOperation.EditPost) { + this.props.onCreate(data.post.id); + } else if (res.op == UserOperation.EditPost) { + let data = res.data as PostResponse; this.state.loading = false; - let res: PostResponse = msg; - this.props.onEdit(res.post); - } else if (op == UserOperation.Search) { - let res: SearchResponse = msg; + this.props.onEdit(data.post); + } else if (res.op == UserOperation.Search) { + let data = res.data as SearchResponse; - if (res.type_ == SearchType[SearchType.Posts]) { - this.state.suggestedPosts = res.posts; - } else if (res.type_ == SearchType[SearchType.Url]) { - this.state.crossPosts = res.posts; + if (data.type_ == SearchType[SearchType.Posts]) { + this.state.suggestedPosts = data.posts; + } else if (data.type_ == SearchType[SearchType.Url]) { + this.state.crossPosts = data.posts; } this.setState(this.state); - } else if (op == UserOperation.GetSite) { - let res: GetSiteResponse = msg; - this.state.enable_nsfw = res.site.enable_nsfw; + } else if (res.op == UserOperation.GetSite) { + let data = res.data as GetSiteResponse; + this.state.enable_nsfw = data.site.enable_nsfw; this.setState(this.state); } } diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 308fce8..931ced2 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -26,9 +26,10 @@ import { SearchResponse, GetSiteResponse, GetCommunityResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, hotRank, toast } from '../utils'; +import { wsJsonToRes, hotRank, toast } from '../utils'; import { PostListing } from './post-listing'; import { PostListings } from './post-listings'; import { Sidebar } from './sidebar'; @@ -341,19 +342,19 @@ export class Post extends Component { ); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (op == UserOperation.GetPost) { - let res: GetPostResponse = msg; - this.state.post = res.post; - this.state.comments = res.comments; - this.state.community = res.community; - this.state.moderators = res.moderators; - this.state.admins = res.admins; + } else if (res.op == UserOperation.GetPost) { + let data = res.data as GetPostResponse; + this.state.post = data.post; + this.state.comments = data.comments; + this.state.community = data.community; + this.state.moderators = data.moderators; + this.state.admins = data.admins; this.state.loading = false; document.title = `${this.state.post.name} - ${WebSocketService.Instance.site.name}`; @@ -370,111 +371,111 @@ export class Post extends Component { } this.setState(this.state); - } else if (op == UserOperation.CreateComment) { - let res: CommentResponse = msg; - this.state.comments.unshift(res.comment); + } else if (res.op == UserOperation.CreateComment) { + let data = res.data as CommentResponse; + this.state.comments.unshift(data.comment); this.setState(this.state); - } else if (op == UserOperation.EditComment) { - let res: CommentResponse = msg; - let found = this.state.comments.find(c => c.id == res.comment.id); - found.content = res.comment.content; - found.updated = res.comment.updated; - found.removed = res.comment.removed; - found.deleted = res.comment.deleted; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - found.score = res.comment.score; - found.read = res.comment.read; + } else if (res.op == UserOperation.EditComment) { + let data = res.data as CommentResponse; + let found = this.state.comments.find(c => c.id == data.comment.id); + found.content = data.comment.content; + found.updated = data.comment.updated; + found.removed = data.comment.removed; + found.deleted = data.comment.deleted; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + found.score = data.comment.score; + found.read = data.comment.read; this.setState(this.state); - } else if (op == UserOperation.SaveComment) { - let res: CommentResponse = msg; - let found = this.state.comments.find(c => c.id == res.comment.id); - found.saved = res.comment.saved; + } else if (res.op == UserOperation.SaveComment) { + let data = res.data as CommentResponse; + let found = this.state.comments.find(c => c.id == data.comment.id); + found.saved = data.comment.saved; this.setState(this.state); - } else if (op == UserOperation.CreateCommentLike) { - let res: CommentResponse = msg; + } else if (res.op == UserOperation.CreateCommentLike) { + let data = res.data as CommentResponse; let found: Comment = this.state.comments.find( - c => c.id === res.comment.id + c => c.id === data.comment.id ); - found.score = res.comment.score; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - if (res.comment.my_vote !== null) { - found.my_vote = res.comment.my_vote; + found.score = data.comment.score; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + if (data.comment.my_vote !== null) { + found.my_vote = data.comment.my_vote; found.upvoteLoading = false; found.downvoteLoading = false; } this.setState(this.state); - } else if (op == UserOperation.CreatePostLike) { - let res: CreatePostLikeResponse = msg; - this.state.post.my_vote = res.post.my_vote; - this.state.post.score = res.post.score; - this.state.post.upvotes = res.post.upvotes; - this.state.post.downvotes = res.post.downvotes; - this.state.post.upvoteLoading = false; - this.state.post.downvoteLoading = false; + } else if (res.op == UserOperation.CreatePostLike) { + let data = res.data as CreatePostLikeResponse; + this.state.post.my_vote = data.post.my_vote; + this.state.post.score = data.post.score; + this.state.post.upvotes = data.post.upvotes; + this.state.post.downvotes = data.post.downvotes; this.setState(this.state); - } else if (op == UserOperation.EditPost) { - let res: PostResponse = msg; - this.state.post = res.post; + } else if (res.op == UserOperation.EditPost) { + let data = res.data as PostResponse; + this.state.post = data.post; this.setState(this.state); - } else if (op == UserOperation.SavePost) { - let res: PostResponse = msg; - this.state.post = res.post; + } else if (res.op == UserOperation.SavePost) { + let data = res.data as PostResponse; + this.state.post = data.post; this.setState(this.state); - } else if (op == UserOperation.EditCommunity) { - let res: CommunityResponse = msg; - this.state.community = res.community; - this.state.post.community_id = res.community.id; - this.state.post.community_name = res.community.name; + } else if (res.op == UserOperation.EditCommunity) { + let data = res.data as CommunityResponse; + this.state.community = data.community; + this.state.post.community_id = data.community.id; + this.state.post.community_name = data.community.name; this.setState(this.state); - } else if (op == UserOperation.FollowCommunity) { - let res: CommunityResponse = msg; - this.state.community.subscribed = res.community.subscribed; + } else if (res.op == UserOperation.FollowCommunity) { + let data = res.data as CommunityResponse; + this.state.community.subscribed = data.community.subscribed; this.state.community.number_of_subscribers = - res.community.number_of_subscribers; + data.community.number_of_subscribers; this.setState(this.state); - } else if (op == UserOperation.BanFromCommunity) { - let res: BanFromCommunityResponse = msg; + } else if (res.op == UserOperation.BanFromCommunity) { + let data = res.data as BanFromCommunityResponse; this.state.comments - .filter(c => c.creator_id == res.user.id) - .forEach(c => (c.banned_from_community = res.banned)); - if (this.state.post.creator_id == res.user.id) { - this.state.post.banned_from_community = res.banned; + .filter(c => c.creator_id == data.user.id) + .forEach(c => (c.banned_from_community = data.banned)); + if (this.state.post.creator_id == data.user.id) { + this.state.post.banned_from_community = data.banned; } this.setState(this.state); - } else if (op == UserOperation.AddModToCommunity) { - let res: AddModToCommunityResponse = msg; - this.state.moderators = res.moderators; + } else if (res.op == UserOperation.AddModToCommunity) { + let data = res.data as AddModToCommunityResponse; + this.state.moderators = data.moderators; this.setState(this.state); - } else if (op == UserOperation.BanUser) { - let res: BanUserResponse = msg; + } else if (res.op == UserOperation.BanUser) { + let data = res.data as BanUserResponse; this.state.comments - .filter(c => c.creator_id == res.user.id) - .forEach(c => (c.banned = res.banned)); - if (this.state.post.creator_id == res.user.id) { - this.state.post.banned = res.banned; + .filter(c => c.creator_id == data.user.id) + .forEach(c => (c.banned = data.banned)); + if (this.state.post.creator_id == data.user.id) { + this.state.post.banned = data.banned; } this.setState(this.state); - } else if (op == UserOperation.AddAdmin) { - let res: AddAdminResponse = msg; - this.state.admins = res.admins; + } else if (res.op == UserOperation.AddAdmin) { + let data = res.data as AddAdminResponse; + this.state.admins = data.admins; this.setState(this.state); - } else if (op == UserOperation.Search) { - let res: SearchResponse = msg; - this.state.crossPosts = res.posts.filter(p => p.id != this.state.post.id); + } else if (res.op == UserOperation.Search) { + let data = res.data as SearchResponse; + this.state.crossPosts = data.posts.filter( + p => p.id != this.state.post.id + ); this.setState(this.state); - } else if (op == UserOperation.TransferSite) { - let res: GetSiteResponse = msg; + } else if (res.op == UserOperation.TransferSite) { + let data = res.data as GetSiteResponse; - this.state.admins = res.admins; + this.state.admins = data.admins; this.setState(this.state); - } else if (op == UserOperation.TransferCommunity) { - let res: GetCommunityResponse = msg; - this.state.community = res.community; - this.state.moderators = res.moderators; - this.state.admins = res.admins; + } else if (res.op == UserOperation.TransferCommunity) { + let data = res.data as GetCommunityResponse; + this.state.community = data.community; + this.state.moderators = data.moderators; + this.state.admins = data.admins; this.setState(this.state); } } diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx index 96bd807..5ee1c1f 100644 --- a/ui/src/components/private-message-form.tsx +++ b/ui/src/components/private-message-form.tsx @@ -13,15 +13,16 @@ import { UserDetailsResponse, GetUserDetailsForm, SortType, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService } from '../services'; import { - msgOp, capitalizeFirstLetter, markdownHelpUrl, mdToHtml, showAvatars, pictshareAvatarThumbnail, + wsJsonToRes, toast, } from '../utils'; import autosize from 'autosize'; @@ -266,26 +267,26 @@ export class PrivateMessageForm extends Component< i.setState(i.state); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); - if (msg.error) { + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; - } else if (op == UserOperation.EditPrivateMessage) { + } else if (res.op == UserOperation.EditPrivateMessage) { + let data = res.data as PrivateMessageResponse; this.state.loading = false; - let res: PrivateMessageResponse = msg; - this.props.onEdit(res.message); - } else if (op == UserOperation.GetUserDetails) { - let res: UserDetailsResponse = msg; - this.state.recipient = res.user; - this.state.privateMessageForm.recipient_id = res.user.id; + this.props.onEdit(data.message); + } else if (res.op == UserOperation.GetUserDetails) { + let data = res.data as UserDetailsResponse; + this.state.recipient = data.user; + this.state.privateMessageForm.recipient_id = data.user.id; this.setState(this.state); - } else if (op == UserOperation.CreatePrivateMessage) { + } else if (res.op == UserOperation.CreatePrivateMessage) { + let data = res.data as PrivateMessageResponse; this.state.loading = false; - let res: PrivateMessageResponse = msg; - this.props.onCreate(res.message); + this.props.onCreate(data.message); this.setState(this.state); } } diff --git a/ui/src/components/search.tsx b/ui/src/components/search.tsx index d2280cb..18b5d34 100644 --- a/ui/src/components/search.tsx +++ b/ui/src/components/search.tsx @@ -14,10 +14,11 @@ import { SearchType, CreatePostLikeResponse, CommentResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService } from '../services'; import { - msgOp, + wsJsonToRes, fetchLimit, routeSearchTypeToEnum, routeSortTypeToEnum, @@ -48,7 +49,6 @@ export class Search extends Component { sort: this.getSortTypeFromProps(this.props), page: this.getPageFromProps(this.props), searchResponse: { - op: null, type_: null, posts: [], comments: [], @@ -401,7 +401,6 @@ export class Search extends Component { return (
{res && - res.op && res.posts.length == 0 && res.comments.length == 0 && res.communities.length == 0 && @@ -477,44 +476,44 @@ export class Search extends Component { ); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (op == UserOperation.Search) { - let res: SearchResponse = msg; - this.state.searchResponse = res; + } else if (res.op == UserOperation.Search) { + let data = res.data as SearchResponse; + this.state.searchResponse = data; this.state.loading = false; document.title = `${i18n.t('search')} - ${this.state.q} - ${ WebSocketService.Instance.site.name }`; window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.CreateCommentLike) { - let res: CommentResponse = msg; + } else if (res.op == UserOperation.CreateCommentLike) { + let data = res.data as CommentResponse; let found: Comment = this.state.searchResponse.comments.find( - c => c.id === res.comment.id + c => c.id === data.comment.id ); - found.score = res.comment.score; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - if (res.comment.my_vote !== null) { - found.my_vote = res.comment.my_vote; + found.score = data.comment.score; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + if (data.comment.my_vote !== null) { + found.my_vote = data.comment.my_vote; found.upvoteLoading = false; found.downvoteLoading = false; } this.setState(this.state); - } else if (op == UserOperation.CreatePostLike) { - let res: CreatePostLikeResponse = msg; + } else if (res.op == UserOperation.CreatePostLike) { + let data = res.data as CreatePostLikeResponse; let found = this.state.searchResponse.posts.find( - c => c.id == res.post.id + c => c.id == data.post.id ); - found.my_vote = res.post.my_vote; - found.score = res.post.score; - found.upvotes = res.post.upvotes; - found.downvotes = res.post.downvotes; + found.my_vote = data.post.my_vote; + found.score = data.post.score; + found.upvotes = data.post.upvotes; + found.downvotes = data.post.downvotes; this.setState(this.state); } } diff --git a/ui/src/components/setup.tsx b/ui/src/components/setup.tsx index d06a9a5..26475a3 100644 --- a/ui/src/components/setup.tsx +++ b/ui/src/components/setup.tsx @@ -1,9 +1,14 @@ import { Component, linkEvent } from 'inferno'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; -import { RegisterForm, LoginResponse, UserOperation } from '../interfaces'; +import { + RegisterForm, + LoginResponse, + UserOperation, + WebSocketJsonResponse, +} from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, toast } from '../utils'; +import { wsJsonToRes, toast } from '../utils'; import { SiteForm } from './site-form'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -181,21 +186,20 @@ export class Setup extends Component { i.setState(i.state); } - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); - if (msg.error) { + parseMessage(msg: WebSocketJsonResponse) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.state.userLoading = false; this.setState(this.state); return; - } else if (op == UserOperation.Register) { + } else if (res.op == UserOperation.Register) { + let data = res.data as LoginResponse; this.state.userLoading = false; this.state.doneRegisteringUser = true; - let res: LoginResponse = msg; - UserService.Instance.login(res); - console.log(res); + UserService.Instance.login(data); this.setState(this.state); - } else if (op == UserOperation.CreateSite) { + } else if (res.op == UserOperation.CreateSite) { this.props.history.push('/'); } } diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index 89bc478..09129d6 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -19,10 +19,11 @@ import { AddAdminResponse, DeleteAccountForm, CreatePostLikeResponse, + WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { - msgOp, + wsJsonToRes, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter, @@ -1012,27 +1013,27 @@ export class User extends Component { WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm); } - parseMessage(msg: any) { + parseMessage(msg: WebSocketJsonResponse) { console.log(msg); - let op: UserOperation = msgOp(msg); - if (msg.error) { + let res = wsJsonToRes(msg); + if (res.error) { toast(i18n.t(msg.error), 'danger'); this.state.deleteAccountLoading = false; this.state.avatarLoading = false; this.state.userSettingsLoading = false; - if (msg.error == 'couldnt_find_that_username_or_email') { + if (res.error == 'couldnt_find_that_username_or_email') { this.context.router.history.push('/'); } this.setState(this.state); return; - } else if (op == UserOperation.GetUserDetails) { - let res: UserDetailsResponse = msg; - this.state.user = res.user; - this.state.comments = res.comments; - this.state.follows = res.follows; - this.state.moderates = res.moderates; - this.state.posts = res.posts; - this.state.admins = res.admins; + } else if (res.op == UserOperation.GetUserDetails) { + let data = res.data as UserDetailsResponse; + this.state.user = data.user; + this.state.comments = data.comments; + this.state.follows = data.follows; + this.state.moderates = data.moderates; + this.state.posts = data.posts; + this.state.admins = data.admins; this.state.loading = false; if (this.isCurrentUser) { this.state.userSettingsForm.show_nsfw = @@ -1055,67 +1056,67 @@ export class User extends Component { document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`; window.scrollTo(0, 0); this.setState(this.state); - } else if (op == UserOperation.EditComment) { - let res: CommentResponse = msg; + } else if (res.op == UserOperation.EditComment) { + let data = res.data as CommentResponse; - let found = this.state.comments.find(c => c.id == res.comment.id); - found.content = res.comment.content; - found.updated = res.comment.updated; - found.removed = res.comment.removed; - found.deleted = res.comment.deleted; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - found.score = res.comment.score; + let found = this.state.comments.find(c => c.id == data.comment.id); + found.content = data.comment.content; + found.updated = data.comment.updated; + found.removed = data.comment.removed; + found.deleted = data.comment.deleted; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + found.score = data.comment.score; this.setState(this.state); - } else if (op == UserOperation.CreateComment) { + } else if (res.op == UserOperation.CreateComment) { // let res: CommentResponse = msg; toast(i18n.t('reply_sent')); // this.state.comments.unshift(res.comment); // TODO do this right // this.setState(this.state); - } else if (op == UserOperation.SaveComment) { - let res: CommentResponse = msg; - let found = this.state.comments.find(c => c.id == res.comment.id); - found.saved = res.comment.saved; + } else if (res.op == UserOperation.SaveComment) { + let data = res.data as CommentResponse; + let found = this.state.comments.find(c => c.id == data.comment.id); + found.saved = data.comment.saved; this.setState(this.state); - } else if (op == UserOperation.CreateCommentLike) { - let res: CommentResponse = msg; + } else if (res.op == UserOperation.CreateCommentLike) { + let data = res.data as CommentResponse; let found: Comment = this.state.comments.find( - c => c.id === res.comment.id + c => c.id === data.comment.id ); - found.score = res.comment.score; - found.upvotes = res.comment.upvotes; - found.downvotes = res.comment.downvotes; - if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote; + found.score = data.comment.score; + found.upvotes = data.comment.upvotes; + found.downvotes = data.comment.downvotes; + if (data.comment.my_vote !== null) found.my_vote = data.comment.my_vote; this.setState(this.state); - } else if (op == UserOperation.CreatePostLike) { - let res: CreatePostLikeResponse = msg; - let found = this.state.posts.find(c => c.id == res.post.id); - found.my_vote = res.post.my_vote; - found.score = res.post.score; - found.upvotes = res.post.upvotes; - found.downvotes = res.post.downvotes; + } else if (res.op == UserOperation.CreatePostLike) { + let data = res.data as CreatePostLikeResponse; + let found = this.state.posts.find(c => c.id == data.post.id); + found.my_vote = data.post.my_vote; + found.score = data.post.score; + found.upvotes = data.post.upvotes; + found.downvotes = data.post.downvotes; this.setState(this.state); - } else if (op == UserOperation.BanUser) { - let res: BanUserResponse = msg; + } else if (res.op == UserOperation.BanUser) { + let data = res.data as BanUserResponse; this.state.comments - .filter(c => c.creator_id == res.user.id) - .forEach(c => (c.banned = res.banned)); + .filter(c => c.creator_id == data.user.id) + .forEach(c => (c.banned = data.banned)); this.state.posts - .filter(c => c.creator_id == res.user.id) - .forEach(c => (c.banned = res.banned)); + .filter(c => c.creator_id == data.user.id) + .forEach(c => (c.banned = data.banned)); this.setState(this.state); - } else if (op == UserOperation.AddAdmin) { - let res: AddAdminResponse = msg; - this.state.admins = res.admins; + } else if (res.op == UserOperation.AddAdmin) { + let data = res.data as AddAdminResponse; + this.state.admins = data.admins; this.setState(this.state); - } else if (op == UserOperation.SaveUserSettings) { + } else if (res.op == UserOperation.SaveUserSettings) { + let data = res.data as LoginResponse; this.state = this.emptyState; this.state.userSettingsLoading = false; this.setState(this.state); - let res: LoginResponse = msg; - UserService.Instance.login(res); - } else if (op == UserOperation.DeleteAccount) { + UserService.Instance.login(data); + } else if (res.op == UserOperation.DeleteAccount) { this.state.deleteAccountLoading = false; this.state.deleteAccountShowConfirm = false; this.setState(this.state); diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index fc7d8cb..bd954d2 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -249,7 +249,6 @@ export interface FollowCommunityForm { } export interface GetFollowedCommunitiesResponse { - op: string; communities: Array; } @@ -264,7 +263,6 @@ export interface GetUserDetailsForm { } export interface UserDetailsResponse { - op: string; user: UserView; follows: Array; moderates: Array; @@ -282,7 +280,6 @@ export interface GetRepliesForm { } export interface GetRepliesResponse { - op: string; replies: Array; } @@ -295,7 +292,6 @@ export interface GetUserMentionsForm { } export interface GetUserMentionsResponse { - op: string; mentions: Array; } @@ -306,7 +302,6 @@ export interface EditUserMentionForm { } export interface UserMentionResponse { - op: string; mention: Comment; } @@ -320,7 +315,6 @@ export interface BanFromCommunityForm { } export interface BanFromCommunityResponse { - op: string; user: UserView; banned: boolean; } @@ -344,7 +338,6 @@ export interface TransferSiteForm { } export interface AddModToCommunityResponse { - op: string; moderators: Array; } @@ -356,7 +349,6 @@ export interface GetModlogForm { } export interface GetModlogResponse { - op: string; removed_posts: Array; locked_posts: Array; stickied_posts: Array; @@ -497,7 +489,6 @@ export interface RegisterForm { } export interface LoginResponse { - op: string; jwt: string; } @@ -533,14 +524,12 @@ export interface CommunityForm { } export interface GetCommunityResponse { - op: string; community: Community; moderators: Array; admins: Array; } export interface CommunityResponse { - op: string; community: Community; } @@ -552,12 +541,10 @@ export interface ListCommunitiesForm { } export interface ListCommunitiesResponse { - op: string; communities: Array; } export interface ListCategoriesResponse { - op: string; categories: Array; } @@ -586,7 +573,6 @@ export interface PostFormParams { } export interface GetPostResponse { - op: string; post: Post; comments: Array; community: Community; @@ -601,7 +587,6 @@ export interface SavePostForm { } export interface PostResponse { - op: string; post: Post; } @@ -625,7 +610,6 @@ export interface SaveCommentForm { } export interface CommentResponse { - op: string; comment: Comment; } @@ -651,7 +635,6 @@ export interface GetPostsForm { } export interface GetPostsResponse { - op: string; posts: Array; } @@ -662,7 +645,6 @@ export interface CreatePostLikeForm { } export interface CreatePostLikeResponse { - op: string; post: Post; } @@ -676,7 +658,6 @@ export interface SiteForm { } export interface GetSiteResponse { - op: string; site: Site; admins: Array; banned: Array; @@ -684,7 +665,6 @@ export interface GetSiteResponse { } export interface SiteResponse { - op: string; site: Site; } @@ -697,7 +677,6 @@ export interface BanUserForm { } export interface BanUserResponse { - op: string; user: UserView; banned: boolean; } @@ -709,7 +688,6 @@ export interface AddAdminForm { } export interface AddAdminResponse { - op: string; admins: Array; } @@ -724,7 +702,6 @@ export interface SearchForm { } export interface SearchResponse { - op: string; type_: string; posts?: Array; comments?: Array; @@ -740,9 +717,8 @@ export interface PasswordResetForm { email: string; } -export interface PasswordResetResponse { - op: string; -} +// export interface PasswordResetResponse { +// } export interface PasswordChangeForm { token: string; @@ -776,11 +752,43 @@ export interface GetPrivateMessagesForm { } export interface PrivateMessagesResponse { - op: string; messages: Array; } export interface PrivateMessageResponse { - op: string; message: PrivateMessage; } + +type ResponseType = + | SiteResponse + | GetFollowedCommunitiesResponse + | ListCommunitiesResponse + | GetPostsResponse + | CreatePostLikeResponse + | GetRepliesResponse + | GetUserMentionsResponse + | ListCategoriesResponse + | CommunityResponse + | CommentResponse + | UserMentionResponse + | LoginResponse + | GetModlogResponse + | SearchResponse + | BanFromCommunityResponse + | AddModToCommunityResponse + | BanUserResponse + | AddAdminResponse + | PrivateMessageResponse + | PrivateMessagesResponse; + +export interface WebSocketResponse { + op: UserOperation; + data: ResponseType; + error?: string; +} + +export interface WebSocketJsonResponse { + op: string; + data: ResponseType; + error?: string; +} diff --git a/ui/src/utils.ts b/ui/src/utils.ts index a3aab09..0e4cd9d 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -16,6 +16,8 @@ import { SortType, ListingType, SearchType, + WebSocketResponse, + WebSocketJsonResponse, } from './interfaces'; import { UserService } from './services/UserService'; import markdown_it from 'markdown-it'; @@ -40,9 +42,12 @@ export function randomStr() { .substr(2, 10); } -export function msgOp(msg: any): UserOperation { +export function wsJsonToRes(msg: WebSocketJsonResponse): WebSocketResponse { let opStr: string = msg.op; - return UserOperation[opStr]; + return { + op: UserOperation[opStr], + data: msg.data, + }; } export const md = new markdown_it({