refactor: rewrite entire codebase in axum instead of actix
Replaces actix with axum for web, allows us to use socket.io and gives us access to the tower ecosystem of middleware breaks compatibility with our current websocket implementation, needs to be reimplemented for socket.io
This commit is contained in:
parent
3647086adb
commit
324137ce8b
47 changed files with 1381 additions and 1129 deletions
|
@ -1,28 +1,40 @@
|
|||
//! `/api/v1/guilds` Guild related endpoints
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, Scope, get, post, web};
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
Json, Router,
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
routing::{get, post},
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
mod uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Guild, StartAmountQuery},
|
||||
utils::{get_auth_header, global_checks},
|
||||
utils::global_checks,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GuildInfo {
|
||||
pub struct GuildInfo {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub fn web() -> Scope {
|
||||
web::scope("/guilds")
|
||||
.service(post)
|
||||
.service(get)
|
||||
.service(uuid::web())
|
||||
pub fn router() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
.route("/", post(new))
|
||||
.route("/", get(get_guilds))
|
||||
.nest("/{uuid}", uuid::router())
|
||||
}
|
||||
|
||||
/// `POST /api/v1/guilds` Creates a new guild
|
||||
|
@ -49,23 +61,18 @@ pub fn web() -> Scope {
|
|||
/// });
|
||||
/// ```
|
||||
/// NOTE: UUIDs in this response are made using `uuidgen`, UUIDs made by the actual backend will be UUIDv7 and have extractable timestamps
|
||||
#[post("")]
|
||||
pub async fn post(
|
||||
req: HttpRequest,
|
||||
guild_info: web::Json<GuildInfo>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
pub async fn new(
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
Json(guild_info): Json<GuildInfo>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild = Guild::new(&mut conn, guild_info.name.clone(), uuid).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(guild))
|
||||
Ok((StatusCode::OK, Json(guild)))
|
||||
}
|
||||
|
||||
/// `GET /api/v1/servers` Fetches all guilds
|
||||
|
@ -115,25 +122,20 @@ pub async fn post(
|
|||
/// ]);
|
||||
/// ```
|
||||
/// NOTE: UUIDs in this response are made using `uuidgen`, UUIDs made by the actual backend will be UUIDv7 and have extractable timestamps
|
||||
#[get("")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
request_query: web::Query<StartAmountQuery>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
|
||||
pub async fn get_guilds(
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
Json(request_query): Json<StartAmountQuery>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let start = request_query.start.unwrap_or(0);
|
||||
|
||||
let amount = request_query.amount.unwrap_or(10);
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut data.pool.get().await?).await?;
|
||||
let uuid = check_access_token(auth.token(), &mut app_state.pool.get().await?).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
let guilds = Guild::fetch_amount(&data.pool, start, amount).await?;
|
||||
let guilds = Guild::fetch_amount(&app_state.pool, start, amount).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(guilds))
|
||||
Ok((StatusCode::OK, Json(guilds)))
|
||||
}
|
||||
|
|
|
@ -1,92 +1,92 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ::uuid::Uuid;
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Channel, Member, Permissions},
|
||||
utils::{get_auth_header, global_checks, order_by_is_above},
|
||||
utils::{global_checks, order_by_is_above},
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ChannelInfo {
|
||||
pub struct ChannelInfo {
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
}
|
||||
|
||||
#[get("{uuid}/channels")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
if let Ok(cache_hit) = data.get_cache_key(format!("{guild_uuid}_channels")).await {
|
||||
return Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(cache_hit));
|
||||
if let Ok(cache_hit) = app_state
|
||||
.get_cache_key(format!("{guild_uuid}_channels"))
|
||||
.await
|
||||
{
|
||||
return Ok((StatusCode::OK, Json(cache_hit)).into_response());
|
||||
}
|
||||
|
||||
let channels = Channel::fetch_all(&data.pool, guild_uuid).await?;
|
||||
let channels = Channel::fetch_all(&app_state.pool, guild_uuid).await?;
|
||||
|
||||
let channels_ordered = order_by_is_above(channels).await?;
|
||||
|
||||
data.set_cache_key(
|
||||
format!("{guild_uuid}_channels"),
|
||||
channels_ordered.clone(),
|
||||
1800,
|
||||
)
|
||||
.await?;
|
||||
app_state
|
||||
.set_cache_key(
|
||||
format!("{guild_uuid}_channels"),
|
||||
channels_ordered.clone(),
|
||||
1800,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(channels_ordered))
|
||||
Ok((StatusCode::OK, Json(channels_ordered)).into_response())
|
||||
}
|
||||
|
||||
#[post("{uuid}/channels")]
|
||||
pub async fn create(
|
||||
req: HttpRequest,
|
||||
channel_info: web::Json<ChannelInfo>,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
Json(channel_info): Json<ChannelInfo>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
let member = Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
member
|
||||
.check_permission(&data, Permissions::ManageChannel)
|
||||
.check_permission(&app_state, Permissions::ManageChannel)
|
||||
.await?;
|
||||
|
||||
let channel = Channel::new(
|
||||
data.clone(),
|
||||
&app_state,
|
||||
guild_uuid,
|
||||
channel_info.name.clone(),
|
||||
channel_info.description.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(channel))
|
||||
Ok((StatusCode::OK, Json(channel)))
|
||||
}
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
//! `/api/v1/guilds/{uuid}/icon` icon related endpoints, will probably be replaced by a multipart post to above endpoint
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, put, web};
|
||||
use futures_util::StreamExt as _;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Guild, Member, Permissions},
|
||||
utils::{get_auth_header, global_checks},
|
||||
};
|
||||
|
||||
/// `PUT /api/v1/guilds/{uuid}/icon` Icon upload
|
||||
///
|
||||
/// requires auth: no
|
||||
///
|
||||
/// put request expects a file and nothing else
|
||||
#[put("{uuid}/icon")]
|
||||
pub async fn upload(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
mut payload: web::Payload,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
|
||||
let member = Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
member
|
||||
.check_permission(&data, Permissions::ManageGuild)
|
||||
.await?;
|
||||
|
||||
let mut guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
||||
let mut bytes = web::BytesMut::new();
|
||||
while let Some(item) = payload.next().await {
|
||||
bytes.extend_from_slice(&item?);
|
||||
}
|
||||
|
||||
guild
|
||||
.set_icon(
|
||||
&data.bunny_storage,
|
||||
&mut conn,
|
||||
data.config.bunny.cdn_url.clone(),
|
||||
bytes,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
|
@ -1,37 +1,41 @@
|
|||
use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Guild, Member, Permissions},
|
||||
utils::{get_auth_header, global_checks},
|
||||
utils::global_checks,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct InviteRequest {
|
||||
pub struct InviteRequest {
|
||||
custom_id: Option<String>,
|
||||
}
|
||||
|
||||
#[get("{uuid}/invites")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
|
@ -39,32 +43,25 @@ pub async fn get(
|
|||
|
||||
let invites = guild.get_invites(&mut conn).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(invites))
|
||||
Ok((StatusCode::OK, Json(invites)))
|
||||
}
|
||||
|
||||
#[post("{uuid}/invites")]
|
||||
pub async fn create(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
invite_request: web::Json<InviteRequest>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
Json(invite_request): Json<InviteRequest>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
let member = Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
member
|
||||
.check_permission(&data, Permissions::CreateInvite)
|
||||
.check_permission(&app_state, Permissions::CreateInvite)
|
||||
.await?;
|
||||
|
||||
let guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
@ -73,5 +70,5 @@ pub async fn create(
|
|||
.create_invite(&mut conn, uuid, invite_request.custom_id.clone())
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(invite))
|
||||
Ok((StatusCode::OK, Json(invite)))
|
||||
}
|
||||
|
|
|
@ -1,36 +1,41 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ::uuid::Uuid;
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Me, Member},
|
||||
utils::{get_auth_header, global_checks},
|
||||
utils::global_checks,
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, web};
|
||||
|
||||
#[get("{uuid}/members")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let me = Me::get(&mut conn, uuid).await?;
|
||||
|
||||
let members = Member::fetch_all(&data, &me, guild_uuid).await?;
|
||||
let members = Member::fetch_all(&app_state, &me, guild_uuid).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(members))
|
||||
Ok((StatusCode::OK, Json(members)))
|
||||
}
|
||||
|
|
|
@ -1,40 +1,51 @@
|
|||
//! `/api/v1/guilds/{uuid}` Specific server endpoints
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, Scope, get, web};
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
Json, Router,
|
||||
extract::{Multipart, Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
routing::{get, patch, post},
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use uuid::Uuid;
|
||||
|
||||
mod channels;
|
||||
mod icon;
|
||||
mod invites;
|
||||
mod members;
|
||||
mod roles;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Guild, Member},
|
||||
utils::{get_auth_header, global_checks},
|
||||
objects::{Guild, Member, Permissions},
|
||||
utils::global_checks,
|
||||
};
|
||||
|
||||
pub fn web() -> Scope {
|
||||
web::scope("")
|
||||
pub fn router() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
// Servers
|
||||
.service(get)
|
||||
.route("/", get(get_guild))
|
||||
.route("/", patch(edit))
|
||||
// Channels
|
||||
.service(channels::get)
|
||||
.service(channels::create)
|
||||
.route("/channels", get(channels::get))
|
||||
.route("/channels", post(channels::create))
|
||||
// Roles
|
||||
.service(roles::get)
|
||||
.service(roles::create)
|
||||
.service(roles::uuid::get)
|
||||
.route("/roles", get(roles::get))
|
||||
.route("/roles", post(roles::create))
|
||||
.route("/roles/{role_uuid}", get(roles::uuid::get))
|
||||
// Invites
|
||||
.service(invites::get)
|
||||
.service(invites::create)
|
||||
// Icon
|
||||
.service(icon::upload)
|
||||
.route("/invites", get(invites::get))
|
||||
.route("/invites", post(invites::create))
|
||||
// Members
|
||||
.service(members::get)
|
||||
.route("/members", get(members::get))
|
||||
}
|
||||
|
||||
/// `GET /api/v1/guilds/{uuid}` DESCRIPTION
|
||||
|
@ -70,27 +81,69 @@ pub fn web() -> Scope {
|
|||
/// "member_count": 20
|
||||
/// });
|
||||
/// ```
|
||||
#[get("/{uuid}")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
pub async fn get_guild(
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
let guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(guild))
|
||||
Ok((StatusCode::OK, Json(guild)))
|
||||
}
|
||||
|
||||
/// `PATCH /api/v1/guilds/{uuid}` change guild settings
|
||||
///
|
||||
/// requires auth: yes
|
||||
pub async fn edit(
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
mut multipart: Multipart,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
let member = Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
member
|
||||
.check_permission(&app_state, Permissions::ManageGuild)
|
||||
.await?;
|
||||
|
||||
let mut guild = Guild::fetch_one(&mut conn, guild_uuid).await?;
|
||||
|
||||
let mut icon: Option<Bytes> = None;
|
||||
|
||||
while let Some(field) = multipart.next_field().await.unwrap() {
|
||||
let name = field
|
||||
.name()
|
||||
.ok_or(Error::BadRequest("Field has no name".to_string()))?;
|
||||
|
||||
if name == "icon" {
|
||||
icon = Some(field.bytes().await?);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(icon) = icon {
|
||||
guild
|
||||
.set_icon(
|
||||
&app_state.bunny_storage,
|
||||
&mut conn,
|
||||
app_state.config.bunny.cdn_url.clone(),
|
||||
icon,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
|
|
@ -1,82 +1,78 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, post, web};
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Member, Permissions, Role},
|
||||
utils::{get_auth_header, global_checks, order_by_is_above},
|
||||
utils::{global_checks, order_by_is_above},
|
||||
};
|
||||
|
||||
pub mod uuid;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RoleInfo {
|
||||
pub struct RoleInfo {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[get("{uuid}/roles")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
if let Ok(cache_hit) = data.get_cache_key(format!("{guild_uuid}_roles")).await {
|
||||
return Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(cache_hit));
|
||||
if let Ok(cache_hit) = app_state.get_cache_key(format!("{guild_uuid}_roles")).await {
|
||||
return Ok((StatusCode::OK, Json(cache_hit)).into_response());
|
||||
}
|
||||
|
||||
let roles = Role::fetch_all(&mut conn, guild_uuid).await?;
|
||||
|
||||
let roles_ordered = order_by_is_above(roles).await?;
|
||||
|
||||
data.set_cache_key(format!("{guild_uuid}_roles"), roles_ordered.clone(), 1800)
|
||||
app_state
|
||||
.set_cache_key(format!("{guild_uuid}_roles"), roles_ordered.clone(), 1800)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(roles_ordered))
|
||||
Ok((StatusCode::OK, Json(roles_ordered)).into_response())
|
||||
}
|
||||
|
||||
#[post("{uuid}/roles")]
|
||||
pub async fn create(
|
||||
req: HttpRequest,
|
||||
role_info: web::Json<RoleInfo>,
|
||||
path: web::Path<(Uuid,)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path(guild_uuid): Path<Uuid>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
Json(role_info): Json<RoleInfo>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let guild_uuid = path.into_inner().0;
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
let member = Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
member
|
||||
.check_permission(&data, Permissions::ManageRole)
|
||||
.check_permission(&app_state, Permissions::ManageRole)
|
||||
.await?;
|
||||
|
||||
let role = Role::new(&mut conn, guild_uuid, role_info.name.clone()).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(role))
|
||||
Ok((StatusCode::OK, Json(role)).into_response())
|
||||
}
|
||||
|
|
|
@ -1,43 +1,47 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ::uuid::Uuid;
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::{
|
||||
TypedHeader,
|
||||
headers::{Authorization, authorization::Bearer},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Data,
|
||||
AppState,
|
||||
api::v1::auth::check_access_token,
|
||||
error::Error,
|
||||
objects::{Member, Role},
|
||||
utils::{get_auth_header, global_checks},
|
||||
utils::global_checks,
|
||||
};
|
||||
use ::uuid::Uuid;
|
||||
use actix_web::{HttpRequest, HttpResponse, get, web};
|
||||
|
||||
#[get("{uuid}/roles/{role_uuid}")]
|
||||
pub async fn get(
|
||||
req: HttpRequest,
|
||||
path: web::Path<(Uuid, Uuid)>,
|
||||
data: web::Data<Data>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let headers = req.headers();
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
Path((guild_uuid, role_uuid)): Path<(Uuid, Uuid)>,
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
) -> Result<impl IntoResponse, Error> {
|
||||
let mut conn = app_state.pool.get().await?;
|
||||
|
||||
let auth_header = get_auth_header(headers)?;
|
||||
let uuid = check_access_token(auth.token(), &mut conn).await?;
|
||||
|
||||
let (guild_uuid, role_uuid) = path.into_inner();
|
||||
|
||||
let mut conn = data.pool.get().await?;
|
||||
|
||||
let uuid = check_access_token(auth_header, &mut conn).await?;
|
||||
|
||||
global_checks(&data, uuid).await?;
|
||||
global_checks(&app_state, uuid).await?;
|
||||
|
||||
Member::check_membership(&mut conn, uuid, guild_uuid).await?;
|
||||
|
||||
if let Ok(cache_hit) = data.get_cache_key(format!("{role_uuid}")).await {
|
||||
return Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(cache_hit));
|
||||
if let Ok(cache_hit) = app_state.get_cache_key(format!("{role_uuid}")).await {
|
||||
return Ok((StatusCode::OK, Json(cache_hit)).into_response());
|
||||
}
|
||||
|
||||
let role = Role::fetch_one(&mut conn, role_uuid).await?;
|
||||
|
||||
data.set_cache_key(format!("{role_uuid}"), role.clone(), 60)
|
||||
app_state
|
||||
.set_cache_key(format!("{role_uuid}"), role.clone(), 60)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(role))
|
||||
Ok((StatusCode::OK, Json(role)).into_response())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue