summaryrefslogtreecommitdiff
path: root/src/api/chat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/chat.rs')
-rw-r--r--src/api/chat.rs324
1 files changed, 324 insertions, 0 deletions
diff --git a/src/api/chat.rs b/src/api/chat.rs
new file mode 100644
index 0000000..0f3b92e
--- /dev/null
+++ b/src/api/chat.rs
@@ -0,0 +1,324 @@
+use axum::{response::Response, Router, routing::{post, patch, delete}};
+use serde::Deserialize;
+use crate::{
+ public::docs::{EndpointDocumentation, EndpointMethod},
+ types::{
+ extract::{AuthorizedUser, Check, CheckResult, Database, Json},
+ http::ResponseCode,
+ chat::ChatRoom, user::User,
+ },
+};
+
+pub const CHAT_LIST: EndpointDocumentation = EndpointDocumentation {
+ uri: "/api/chat/list",
+ method: EndpointMethod::Post,
+ description: "Returns the rooms you are in",
+ body: None,
+ responses: &[
+ (201, "Returns rooms in a list"),
+ (400, "Body does not match parameters"),
+ (401, "Unauthorized"),
+ (500, "Failed to retrieve rooms"),
+ ],
+ cookie: Some("auth"),
+};
+
+async fn list (
+ AuthorizedUser(user): AuthorizedUser,
+ Database(db): Database
+) -> Response {
+ let Ok(rooms) = ChatRoom::from_user_id(&db, user.user_id) else {
+ return ResponseCode::InternalServerError.text("Failed to retrieve rooms")
+ };
+
+ let Ok(json) = serde_json::to_string(&rooms) else {
+ return ResponseCode::InternalServerError.text("Failed to retrieve rooms")
+ };
+
+ ResponseCode::Success.json(&json)
+}
+
+pub const CHAT_CREATE: EndpointDocumentation = EndpointDocumentation {
+ uri: "/api/chat/create",
+ method: EndpointMethod::Post,
+ description: "Creates a new room",
+ body: Some(
+ r#"
+ {
+ "name" : "Funny memes"
+ }
+ "#,
+ ),
+ responses: &[
+ (201, "Successfully created room"),
+ (400, "Body does not match parameters"),
+ (401, "Unauthorized"),
+ (500, "Failed to create room"),
+ ],
+ cookie: Some("auth"),
+};
+
+#[derive(Deserialize)]
+struct RoomCreateRequest {
+ name: String,
+}
+
+impl Check for RoomCreateRequest {
+ fn check(&self) -> CheckResult {
+ Self::assert_length(
+ &self.name,
+ 1,
+ 255,
+ "Room names must be between 1-255 characters long",
+ )?;
+ Ok(())
+ }
+}
+
+async fn create (
+ AuthorizedUser(user): AuthorizedUser,
+ Database(db): Database,
+ Json(body): Json<RoomCreateRequest>,
+) -> Response {
+ let Ok(post) = ChatRoom::new(&db, vec![user.user_id], body.name) else {
+ return ResponseCode::InternalServerError.text("Failed to create room")
+ };
+
+ let Ok(json) = serde_json::to_string(&post) else {
+ return ResponseCode::InternalServerError.text("Failed to create room")
+ };
+
+ ResponseCode::Created.json(&json)
+}
+
+pub const CHAT_ADD: EndpointDocumentation = EndpointDocumentation {
+ uri: "/api/chat/add",
+ method: EndpointMethod::Patch,
+ description: "Adds a user to a room",
+ body: Some(
+ r#"
+ {
+ "room_id": 69,
+ "email" : "joebide@house.gov"
+ }
+ "#,
+ ),
+ responses: &[
+ (201, "Successfully added user"),
+ (400, "Body does not match parameters"),
+ (401, "Unauthorized"),
+ (500, "Failed to add user"),
+ ],
+ cookie: Some("auth"),
+};
+
+#[derive(Deserialize)]
+struct AddUserRequest {
+ room_id: u64,
+ email: String,
+}
+
+impl Check for AddUserRequest {
+ fn check(&self) -> CheckResult {
+ Ok(())
+ }
+}
+
+async fn add (
+ AuthorizedUser(user): AuthorizedUser,
+ Database(db): Database,
+ Json(body): Json<AddUserRequest>,
+) -> Response {
+
+ let Ok(to_add) = User::from_email(&db, &body.email) else {
+ return ResponseCode::BadRequest.text("User does not exist")
+ };
+
+ let Ok(room) = ChatRoom::from_user_and_room_id(&db, user.user_id, body.room_id) else {
+ return ResponseCode::BadRequest.text("Room doesnt exist or you are not in it")
+ };
+
+ let Ok(success) = room.add_user(&db, to_add.user_id) else {
+ return ResponseCode::InternalServerError.text("Failed to add user")
+ };
+
+ if !success {
+ return ResponseCode::BadRequest.text("User is already in the room")
+ }
+
+ ResponseCode::Success.text("Successfully added user")
+}
+
+pub const CHAT_LEAVE: EndpointDocumentation = EndpointDocumentation {
+ uri: "/api/chat/leave",
+ method: EndpointMethod::Delete,
+ description: "Leaves a room",
+ body: Some(
+ r#"
+ {
+ "room_id": 69
+ }
+ "#,
+ ),
+ responses: &[
+ (201, "Successfully left room"),
+ (400, "Body does not match parameters"),
+ (401, "Unauthorized"),
+ (500, "Failed to leave a room"),
+ ],
+ cookie: Some("auth"),
+};
+
+#[derive(Deserialize)]
+struct LeaveRoomRequest {
+ room_id: u64,
+}
+
+impl Check for LeaveRoomRequest {
+ fn check(&self) -> CheckResult {
+ Ok(())
+ }
+}
+
+async fn leave (
+ AuthorizedUser(user): AuthorizedUser,
+ Database(db): Database,
+ Json(body): Json<LeaveRoomRequest>,
+) -> Response {
+
+ let Ok(room) = ChatRoom::from_user_and_room_id(&db, user.user_id, body.room_id) else {
+ return ResponseCode::BadRequest.text("Room doesnt exist or you are not in it")
+ };
+
+ let Ok(success) = room.remove_user(&db, user.user_id) else {
+ return ResponseCode::InternalServerError.text("Failed to leave room")
+ };
+
+ if !success {
+ return ResponseCode::BadRequest.text("You are currently not in this room (how did this happen?)")
+ }
+
+ ResponseCode::Success.text("Successfully left room")
+}
+
+pub const CHAT_SEND: EndpointDocumentation = EndpointDocumentation {
+ uri: "/api/chat/send",
+ method: EndpointMethod::Post,
+ description: "Send a message to a room",
+ body: Some(
+ r#"
+ {
+ "room_id": 420,
+ "content" : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ }
+ "#,
+ ),
+ responses: &[
+ (201, "Successfully sent message"),
+ (400, "Body does not match parameters"),
+ (401, "Unauthorized"),
+ (500, "Failed to send message"),
+ ],
+ cookie: Some("auth"),
+};
+
+#[derive(Deserialize)]
+struct SendMessageRequest {
+ room_id: u64,
+ content: String
+}
+
+impl Check for SendMessageRequest {
+ fn check(&self) -> CheckResult {
+ Self::assert_length(
+ &self.content,
+ 1,
+ 500,
+ "Messages must be between 1-500 length"
+ )?;
+ Ok(())
+ }
+}
+
+async fn send (
+ AuthorizedUser(user): AuthorizedUser,
+ Database(db): Database,
+ Json(body): Json<SendMessageRequest>,
+) -> Response {
+
+ let Ok(room) = ChatRoom::from_user_and_room_id(&db, user.user_id, body.room_id) else {
+ return ResponseCode::BadRequest.text("Room doesnt exist or you are not in it")
+ };
+
+ let Ok(_msg) = room.send_message(&db, user.user_id, body.content) else {
+ return ResponseCode::InternalServerError.text("Failed to send message")
+ };
+
+ ResponseCode::Created.text("Successfully sent message")
+}
+
+pub const CHAT_LOAD: EndpointDocumentation = EndpointDocumentation {
+ uri: "/api/chat/load",
+ method: EndpointMethod::Post,
+ description: "Get a page of historic room messages starting before given message id",
+ body: Some(
+ r#"
+ {
+ "room_id": 69,
+ "newest_msg": 400,
+ "page": 3
+ }
+ "#,
+ ),
+ responses: &[
+ (201, "Successfully sent message"),
+ (400, "Body does not match parameters"),
+ (401, "Unauthorized"),
+ (500, "Failed to send message"),
+ ],
+ cookie: Some("auth"),
+};
+
+#[derive(Deserialize)]
+struct LoadMessagesRequest {
+ room_id: u64,
+ newest_msg: u64,
+ page: u64
+}
+
+impl Check for LoadMessagesRequest {
+ fn check(&self) -> CheckResult {
+ Ok(())
+ }
+}
+
+async fn load (
+ AuthorizedUser(user): AuthorizedUser,
+ Database(db): Database,
+ Json(body): Json<LoadMessagesRequest>,
+) -> Response {
+
+ let Ok(room) = ChatRoom::from_user_and_room_id(&db, user.user_id, body.room_id) else {
+ return ResponseCode::BadRequest.text("Room doesnt exist or you are not in it")
+ };
+
+ let Ok(msgs) = room.load_old_chat_messagegs(&db, body.newest_msg, body.page) else {
+ return ResponseCode::InternalServerError.text("Failed to load messages")
+ };
+
+ let Ok(json) = serde_json::to_string(&msgs) else {
+ return ResponseCode::InternalServerError.text("Failed to load messages")
+ };
+
+ ResponseCode::Created.json(&json)
+}
+
+pub fn router() -> Router {
+ Router::new()
+ .route("/create", post(create))
+ .route("/list", post(list))
+ .route("/add", patch(add))
+ .route("/leave", delete(leave))
+ .route("/send", post(send))
+ .route("/load", post(load))
+}