diff --git a/src/api/v1/servers/uuid/channels/uuid/messages.rs b/src/api/v1/servers/uuid/channels/uuid/messages.rs index 66ec80d..ae96048 100644 --- a/src/api/v1/servers/uuid/channels/uuid/messages.rs +++ b/src/api/v1/servers/uuid/channels/uuid/messages.rs @@ -1,3 +1,5 @@ +//! `/api/v1/servers/{uuid}/channels/{uuid}/messages` Endpoints related to channel messages + use crate::{ Data, api::v1::auth::check_access_token, @@ -15,6 +17,36 @@ struct MessageRequest { offset: i64, } +/// `GET /api/v1/servers/{uuid}/channels/{uuid}/messages` Returns user with the given UUID +/// +/// requires auth: yes +/// +/// requires relation: yes +/// +/// ### Request Example +/// ``` +/// json!({ +/// "amount": 100, +/// "offset": 0 +/// }) +/// ``` +/// +/// ### Response Example +/// ``` +/// json!({ +/// "uuid": "01971976-8618-74c0-b040-7ffbc44823f6", +/// "channel_uuid": "0196fcb1-e886-7de3-b685-0ee46def9a7b", +/// "user_uuid": "0196fc96-a822-76b0-b9bf-a9de232f54b7", +/// "message": "test", +/// "user": { +/// "uuid": "0196fc96-a822-76b0-b9bf-a9de232f54b7", +/// "username": "1234", +/// "display_name": null, +/// "avatar": "https://cdn.gorb.app/avatar/0196fc96-a822-76b0-b9bf-a9de232f54b7/avatar.jpg" +/// } +/// }); +/// ``` +/// #[get("{uuid}/channels/{channel_uuid}/messages")] pub async fn get( req: HttpRequest, @@ -46,7 +78,7 @@ pub async fn get( } let messages = channel - .fetch_messages(&mut conn, message_request.amount, message_request.offset) + .fetch_messages(&data, message_request.amount, message_request.offset) .await?; Ok(HttpResponse::Ok().json(messages)) diff --git a/src/api/v1/servers/uuid/channels/uuid/socket.rs b/src/api/v1/servers/uuid/channels/uuid/socket.rs index a90cb86..03dfdfc 100644 --- a/src/api/v1/servers/uuid/channels/uuid/socket.rs +++ b/src/api/v1/servers/uuid/channels/uuid/socket.rs @@ -15,7 +15,7 @@ use crate::{ }; #[get("{uuid}/channels/{channel_uuid}/socket")] -pub async fn echo( +pub async fn ws( req: HttpRequest, path: web::Path<(Uuid, Uuid)>, stream: web::Payload, @@ -84,7 +84,7 @@ pub async fn echo( let mut conn = data.cache_pool.get_multiplexed_tokio_connection().await?; let message = channel - .new_message(&mut data.pool.get().await?, uuid, text.to_string()) + .new_message(&data, uuid, text.to_string()) .await?; redis::cmd("PUBLISH") diff --git a/src/api/v1/servers/uuid/mod.rs b/src/api/v1/servers/uuid/mod.rs index 80b3068..aa82d11 100644 --- a/src/api/v1/servers/uuid/mod.rs +++ b/src/api/v1/servers/uuid/mod.rs @@ -26,7 +26,7 @@ pub fn web() -> Scope { .service(channels::uuid::get) .service(channels::uuid::delete) .service(channels::uuid::messages::get) - .service(channels::uuid::socket::echo) + .service(channels::uuid::socket::ws) // Roles .service(roles::get) .service(roles::create) diff --git a/src/api/v1/users/uuid.rs b/src/api/v1/users/uuid.rs index 27e3326..1e4b9e5 100644 --- a/src/api/v1/users/uuid.rs +++ b/src/api/v1/users/uuid.rs @@ -39,16 +39,7 @@ pub async fn get( check_access_token(auth_header, &mut conn).await?; - if let Ok(cache_hit) = data.get_cache_key(uuid.to_string()).await { - return Ok(HttpResponse::Ok() - .content_type("application/json") - .body(cache_hit)); - } - - let user = User::fetch_one(&mut conn, uuid).await?; - - data.set_cache_key(uuid.to_string(), user.clone(), 1800) - .await?; + let user = User::fetch_one(&data, uuid).await?; Ok(HttpResponse::Ok().json(user)) } diff --git a/src/structs.rs b/src/structs.rs index 019d553..1efa820 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -263,45 +263,53 @@ impl Channel { pub async fn fetch_messages( &self, - conn: &mut Conn, + data: &Data, amount: i64, offset: i64, ) -> Result, Error> { + let mut conn = data.pool.get().await?; + use messages::dsl; - let messages: Vec = load_or_empty( + let messages: Vec = load_or_empty( dsl::messages .filter(dsl::channel_uuid.eq(self.uuid)) - .select(Message::as_select()) + .select(MessageBuilder::as_select()) .limit(amount) .offset(offset) - .load(conn) + .load(&mut conn) .await, )?; - Ok(messages) + let message_futures = messages.iter().map(async move |b| { + b.build(data).await + }); + + futures::future::try_join_all(message_futures).await } pub async fn new_message( &self, - conn: &mut Conn, + data: &Data, user_uuid: Uuid, message: String, ) -> Result { let message_uuid = Uuid::now_v7(); - let message = Message { + let message = MessageBuilder { uuid: message_uuid, channel_uuid: self.uuid, user_uuid, message, }; + let mut conn = data.pool.get().await?; + insert_into(messages::table) .values(message.clone()) - .execute(conn) + .execute(&mut conn) .await?; - Ok(message) + message.build(data).await } } @@ -697,14 +705,37 @@ impl Member { } } -#[derive(Clone, Serialize, Queryable, Selectable, Insertable)] +#[derive(Clone, Queryable, Selectable, Insertable)] #[diesel(table_name = messages)] #[diesel(check_for_backend(diesel::pg::Pg))] +pub struct MessageBuilder { + uuid: Uuid, + channel_uuid: Uuid, + user_uuid: Uuid, + message: String, +} + +impl MessageBuilder { + pub async fn build(&self, data: &Data) -> Result { + let user = User::fetch_one(data, self.user_uuid).await?; + + Ok(Message { + uuid: self.uuid, + channel_uuid: self.channel_uuid, + user_uuid: self.user_uuid, + message: self.message.clone(), + user, + }) + } +} + +#[derive(Clone, Serialize)] pub struct Message { uuid: Uuid, channel_uuid: Uuid, user_uuid: Uuid, message: String, + user: User, } /// Server invite struct @@ -731,7 +762,7 @@ impl Invite { } } -#[derive(Serialize, Clone, Queryable, Selectable)] +#[derive(Deserialize, Serialize, Clone, Queryable, Selectable)] #[diesel(table_name = users)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct User { @@ -742,12 +773,21 @@ pub struct User { } impl User { - pub async fn fetch_one(conn: &mut Conn, user_uuid: Uuid) -> Result { + pub async fn fetch_one(data: &Data, user_uuid: Uuid) -> Result { + let mut conn = data.pool.get().await?; + + if let Ok(cache_hit) = data.get_cache_key(user_uuid.to_string()).await { + return Ok(serde_json::from_str(&cache_hit)?); + } + use users::dsl; let user: User = dsl::users .filter(dsl::uuid.eq(user_uuid)) .select(User::as_select()) - .get_result(conn) + .get_result(&mut conn) + .await?; + + data.set_cache_key(user_uuid.to_string(), user.clone(), 1800) .await?; Ok(user)