From 7ee500bf10e8d941690175b8e52bf18c4a6cb825 Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 7 May 2025 23:46:40 +0200 Subject: [PATCH 1/3] feat: add fetch_one() function to Channel struct --- src/api/v1/servers/uuid/channels/mod.rs | 37 +++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/api/v1/servers/uuid/channels/mod.rs b/src/api/v1/servers/uuid/channels/mod.rs index 163234b..242320d 100644 --- a/src/api/v1/servers/uuid/channels/mod.rs +++ b/src/api/v1/servers/uuid/channels/mod.rs @@ -9,14 +9,14 @@ use log::error; mod uuid; -#[derive(Serialize, FromRow)] +#[derive(Serialize, Clone, FromRow)] struct ChannelPermission { role_uuid: String, permissions: i32 } -#[derive(Serialize)] -struct Channel { +#[derive(Serialize, Clone)] +pub struct Channel { uuid: String, name: String, description: Option, @@ -64,6 +64,37 @@ impl Channel { Ok(channels?) } + + pub async fn fetch_one(pool: &Pool, guild_uuid: Uuid, channel_uuid: Uuid) -> Result { + let row = sqlx::query_as(&format!("SELECT CAST(uuid AS VARCHAR), name, description FROM channels WHERE guild_uuid = '{}' AND uuid = '{}'", guild_uuid, channel_uuid)) + .fetch_one(pool) + .await; + + if let Err(error) = row { + error!("{}", error); + + return Err(HttpResponse::InternalServerError().finish()) + } + + let (uuid, name, description): (String, String, Option) = row.unwrap(); + + let row = sqlx::query_as(&format!("SELECT CAST(uuid AS VARCHAR), name, description FROM channels WHERE guild_uuid = '{}' AND uuid = '{}'", guild_uuid, channel_uuid)) + .fetch_all(pool) + .await; + + if let Err(error) = row { + error!("{}", error); + + return Err(HttpResponse::InternalServerError().finish()) + } + + Ok(Self { + uuid, + name, + description, + permissions: row.unwrap(), + }) + } } #[get("{uuid}/channels")] From caee16005d6c20d434212ba018c06ec9058d3f34 Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 7 May 2025 23:46:55 +0200 Subject: [PATCH 2/3] feat: implement caching for channels endpoint --- src/api/v1/servers/uuid/channels/mod.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/api/v1/servers/uuid/channels/mod.rs b/src/api/v1/servers/uuid/channels/mod.rs index 242320d..6ecda6f 100644 --- a/src/api/v1/servers/uuid/channels/mod.rs +++ b/src/api/v1/servers/uuid/channels/mod.rs @@ -127,14 +127,28 @@ pub async fn response(req: HttpRequest, path: web::Path<(Uuid,)>, data: web::Dat return Ok(HttpResponse::InternalServerError().finish()) } - let member_uuid = Uuid::from_str(&row.unwrap()).unwrap(); + let _member_uuid = Uuid::from_str(&row.unwrap()).unwrap(); + let cache_result = data.get_cache_key(format!("{}_channels", guild_uuid)).await; - let channels = Channel::fetch_all(&data.pool, guild_uuid).await; + if let Ok(cache_hit) = cache_result { + return Ok(HttpResponse::Ok().content_type("application/json").body(cache_hit)) + } - if let Err(error) = channels { + let channels_result = Channel::fetch_all(&data.pool, guild_uuid).await; + + if let Err(error) = channels_result { return Ok(error) } - Ok(HttpResponse::Ok().json(channels.unwrap())) + let channels = channels_result.unwrap(); + + let cache_result = data.set_cache_key(format!("{}_channels", guild_uuid), channels.clone(), 1800).await; + + if let Err(error) = cache_result { + error!("{}", error); + return Ok(HttpResponse::InternalServerError().finish()); + } + + Ok(HttpResponse::Ok().json(channels)) } From c79451a8510af021e1cd490db51c28821eb37e83 Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 7 May 2025 23:47:07 +0200 Subject: [PATCH 3/3] feat: allow fetching a single channel --- src/api/v1/servers/uuid/channels/uuid/mod.rs | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/api/v1/servers/uuid/channels/uuid/mod.rs b/src/api/v1/servers/uuid/channels/uuid/mod.rs index 87a2b7b..028ac99 100644 --- a/src/api/v1/servers/uuid/channels/uuid/mod.rs +++ b/src/api/v1/servers/uuid/channels/uuid/mod.rs @@ -1 +1,64 @@ mod messages; +use std::str::FromStr; + +use actix_web::{get, web, Error, HttpRequest, HttpResponse}; +use crate::{api::v1::auth::check_access_token, utils::get_auth_header, Data}; +use ::uuid::Uuid; +use log::error; +use super::Channel; + +#[get("{uuid}/channels/{channel_uuid}")] +pub async fn response(req: HttpRequest, path: web::Path<(Uuid, Uuid)>, data: web::Data) -> Result { + let headers = req.headers(); + + let auth_header = get_auth_header(headers); + + if let Err(error) = auth_header { + return Ok(error) + } + + let (guild_uuid, channel_uuid) = path.into_inner(); + + let authorized = check_access_token(auth_header.unwrap(), &data.pool).await; + + if let Err(error) = authorized { + return Ok(error) + } + + let uuid = authorized.unwrap(); + + let row: Result = sqlx::query_scalar(&format!("SELECT CAST(uuid AS VARCHAR) FROM guild_members WHERE guild_uuid = '{}' AND user_uuid = '{}'", guild_uuid, uuid)) + .fetch_one(&data.pool) + .await; + + if let Err(error) = row { + error!("{}", error); + + return Ok(HttpResponse::InternalServerError().finish()) + } + + let _member_uuid = Uuid::from_str(&row.unwrap()).unwrap(); + + let cache_result = data.get_cache_key(format!("{}", channel_uuid)).await; + + if let Ok(cache_hit) = cache_result { + return Ok(HttpResponse::Ok().content_type("application/json").body(cache_hit)) + } + + let channel_result = Channel::fetch_one(&data.pool, guild_uuid, channel_uuid).await; + + if let Err(error) = channel_result { + return Ok(error) + } + + let channel = channel_result.unwrap(); + + let cache_result = data.set_cache_key(format!("{}", channel_uuid), channel.clone(), 60).await; + + if let Err(error) = cache_result { + error!("{}", error); + return Ok(HttpResponse::InternalServerError().finish()); + } + + Ok(HttpResponse::Ok().json(channel)) +}