tetratto/crates/app/src/routes/api/v1/stacks.rs

323 lines
9 KiB
Rust
Raw Normal View History

2025-06-15 11:52:44 -04:00
use crate::{get_user_from_token, routes::pages::PaginatedQuery, State};
use axum::{
extract::{Path, Query},
response::IntoResponse,
Extension, Json,
};
2025-05-08 22:18:04 -04:00
use axum_extra::extract::CookieJar;
2025-06-15 11:52:44 -04:00
use tetratto_core::model::{
oauth,
permissions::FinePermission,
stacks::{StackBlock, StackPrivacy, UserStack},
ApiReturn, Error,
};
2025-05-09 15:56:19 -04:00
use super::{
AddOrRemoveStackUser, CreateStack, UpdateStackMode, UpdateStackName, UpdateStackPrivacy,
UpdateStackSort,
};
2025-05-08 22:18:04 -04:00
pub async fn create_request(
jar: CookieJar,
Extension(data): Extension<State>,
Json(req): Json<CreateStack>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserCreateStacks) {
2025-05-08 22:18:04 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data
.create_stack(UserStack::new(req.name, user.id, Vec::new()))
.await
{
Ok(s) => Json(ApiReturn {
ok: true,
message: "Stack created".to_string(),
2025-05-09 02:44:42 +00:00
payload: s.id.to_string(),
2025-05-08 22:18:04 -04:00
}),
Err(e) => Json(e.into()),
}
}
pub async fn update_name_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Json(req): Json<UpdateStackName>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-08 22:18:04 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data.update_stack_name(id, &user, &req.name).await {
2025-05-08 22:18:04 -04:00
Ok(_) => Json(ApiReturn {
ok: true,
message: "Stack updated".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
pub async fn update_privacy_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Json(req): Json<UpdateStackPrivacy>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-08 22:18:04 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data.update_stack_privacy(id, &user, req.privacy).await {
2025-05-08 22:18:04 -04:00
Ok(_) => Json(ApiReturn {
ok: true,
message: "Stack updated".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
2025-05-09 15:56:19 -04:00
pub async fn update_mode_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Json(req): Json<UpdateStackMode>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-09 15:56:19 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data.update_stack_mode(id, &user, req.mode).await {
2025-05-09 15:56:19 -04:00
Ok(_) => Json(ApiReturn {
ok: true,
message: "Stack updated".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
pub async fn update_sort_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Json(req): Json<UpdateStackSort>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-09 15:56:19 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data.update_stack_sort(id, &user, req.sort).await {
2025-05-09 15:56:19 -04:00
Ok(_) => Json(ApiReturn {
ok: true,
message: "Stack updated".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
2025-05-08 22:18:04 -04:00
pub async fn add_user_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Json(req): Json<AddOrRemoveStackUser>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-08 22:18:04 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
let other_user = match data.get_user_by_username(&req.username).await {
Ok(c) => c,
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
};
// check block status
if data
.get_userblock_by_initiator_receiver(other_user.id, user.id)
.await
.is_ok()
{
return Json(Error::NotAllowed.into());
}
// add user
let mut stack = match data.get_stack_by_id(id).await {
Ok(s) => s,
Err(e) => return Json(e.into()),
};
stack.users.push(other_user.id);
match data.update_stack_users(id, &user, stack.users).await {
2025-05-08 22:18:04 -04:00
Ok(_) => Json(ApiReturn {
ok: true,
message: "User added".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
pub async fn remove_user_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Json(req): Json<AddOrRemoveStackUser>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-08 22:18:04 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
let mut stack = match data.get_stack_by_id(id).await {
Ok(s) => s,
Err(e) => return Json(e.into()),
};
let other_user = match data.get_user_by_username(&req.username).await {
Ok(c) => c,
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
};
stack
.users
.remove(match stack.users.iter().position(|x| x == &other_user.id) {
Some(idx) => idx,
None => return Json(Error::GeneralNotFound("user".to_string()).into()),
});
match data.update_stack_users(id, &user, stack.users).await {
2025-05-08 22:18:04 -04:00
Ok(_) => Json(ApiReturn {
ok: true,
message: "User removed".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
pub async fn delete_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageStacks) {
2025-05-08 22:18:04 -04:00
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data.delete_stack(id, &user).await {
Ok(_) => Json(ApiReturn {
ok: true,
message: "Stack deleted".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
2025-06-15 11:52:44 -04:00
pub async fn get_users_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
Query(props): Query<PaginatedQuery>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadProfiles) {
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
let stack = match data.get_stack_by_id(id).await {
Ok(s) => s,
Err(e) => return Json(e.into()),
};
if stack.privacy == StackPrivacy::Private
&& user.id != stack.owner
&& !user.permissions.check(FinePermission::MANAGE_STACKS)
{
return Json(Error::NotAllowed.into());
}
match data.get_stack_users(id, 12, props.page).await {
Ok(users) => Json(ApiReturn {
ok: true,
message: "Success".to_string(),
payload: Some({
let mut out = Vec::new();
for mut u in users.clone() {
u.clean();
out.push(u)
}
out
}),
}),
Err(e) => Json(e.into()),
}
}
pub async fn block_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadProfiles) {
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
match data.create_stackblock(StackBlock::new(user.id, id)).await {
Ok(_) => Json(ApiReturn {
ok: true,
message: "Success".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
pub async fn unblock_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadProfiles) {
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
let block = match data.get_stackblock_by_initiator_stack(user.id, id).await {
Ok(b) => b,
Err(e) => return Json(e.into()),
};
match data.delete_stackblock(block.id, user).await {
Ok(_) => Json(ApiReturn {
ok: true,
message: "Success".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}