use std::str::FromStr; use actix_web::{get, web, Error, HttpRequest, HttpResponse}; use serde::Serialize; use sqlx::{prelude::FromRow, Pool, Postgres}; use crate::{api::v1::auth::check_access_token, utils::get_auth_header, Data}; use ::uuid::Uuid; use log::error; pub mod uuid; #[derive(Serialize, Clone, FromRow)] struct ChannelPermission { role_uuid: String, permissions: i32 } #[derive(Serialize, Clone)] pub struct Channel { uuid: String, name: String, description: Option, permissions: Vec } impl Channel { async fn fetch_all(pool: &Pool, guild_uuid: Uuid) -> Result, HttpResponse> { let row = sqlx::query_as(&format!("SELECT CAST(uuid AS VARCHAR), name, description FROM channels WHERE guild_uuid = '{}'", guild_uuid)) .fetch_all(pool) .await; if let Err(error) = row { error!("{}", error); return Err(HttpResponse::InternalServerError().finish()) } let channels: Vec<(String, String, Option)> = row.unwrap(); let futures = channels.iter().map(async |t| { let (uuid, name, description) = t.to_owned(); let row = sqlx::query_as(&format!("SELECT CAST(role_uuid AS VARCHAR), permissions FROM channel_permissions WHERE channel_uuid = '{}'", 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(), }) }); let channels = futures::future::join_all(futures).await; let channels: Result, HttpResponse> = channels.into_iter().collect(); 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")] pub async fn response(req: HttpRequest, path: web::Path<(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 = path.into_inner().0; 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!("{}_channels", guild_uuid)).await; if let Ok(cache_hit) = cache_result { return Ok(HttpResponse::Ok().content_type("application/json").body(cache_hit)) } let channels_result = Channel::fetch_all(&data.pool, guild_uuid).await; if let Err(error) = channels_result { return Ok(error) } 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)) }