magnetar/src/api_v1/user.rs

147 lines
4.3 KiB
Rust

use crate::model::processing::user::{UserBorrowedData, UserModel};
use crate::model::processing::PackError;
use crate::model::PackingContext;
use crate::service::MagnetarService;
use crate::web::auth::{AuthenticatedUser, MaybeUser};
use crate::web::{ApiError, ArgumentOutOfRange, ObjectNotFound};
use axum::extract::{Path, Query, State};
use axum::Json;
use futures::StreamExt;
use futures_util::TryStreamExt;
use itertools::Itertools;
use magnetar_common::util::lenient_parse_tag_decode;
use magnetar_sdk::endpoints::user::{
GetFollowRequestsSelf, GetFollowersById, GetFollowersSelf, GetFollowingById, GetFollowingSelf,
GetManyUsersById, GetUserByAcct, GetUserById, GetUserSelf, ManyUsersByIdReq,
};
use magnetar_sdk::endpoints::{Req, Res};
use std::collections::HashMap;
use std::sync::Arc;
pub async fn handle_user_info_self(
Query(req): Query<Req<GetUserSelf>>,
State(service): State<Arc<MagnetarService>>,
AuthenticatedUser(user): AuthenticatedUser,
) -> Result<Json<Res<GetUserSelf>>, ApiError> {
let ctx = PackingContext::new(service, Some(user.clone())).await?;
let user = UserModel
.self_full_from_base(
&ctx,
&UserBorrowedData {
user: user.as_ref(),
avatar: None,
banner: None,
},
&req,
)
.await?;
Ok(Json(user))
}
pub async fn handle_user_info(
Path(id): Path<String>,
Query(req): Query<Req<GetUserById>>,
State(service): State<Arc<MagnetarService>>,
MaybeUser(self_user): MaybeUser,
) -> Result<Json<Res<GetUserById>>, ApiError> {
let ctx = PackingContext::new(service.clone(), self_user).await?;
let user_model = service
.db
.get_user_by_id(&id)
.await?
.ok_or(ObjectNotFound(id))?;
let user = UserModel
.foreign_full_from_base(
&ctx,
&UserBorrowedData {
user: &user_model,
avatar: None,
banner: None,
},
&req,
)
.await?;
Ok(Json(user))
}
pub async fn handle_user_info_by_acct(
Path(tag_str): Path<String>,
Query(req): Query<Req<GetUserByAcct>>,
State(service): State<Arc<MagnetarService>>,
MaybeUser(self_user): MaybeUser,
) -> Result<Json<Res<GetUserByAcct>>, ApiError> {
let mut tag = lenient_parse_tag_decode(&tag_str)?;
if matches!(&tag.host, Some(host) if host == &service.config.networking.host) {
tag.host = None;
}
let ctx = PackingContext::new(service.clone(), self_user).await?;
let user_model = service
.db
.get_user_by_tag(&tag.name, tag.host.as_deref())
.await?
.ok_or(ObjectNotFound(tag_str))?;
let user = UserModel
.foreign_full_from_base(
&ctx,
&UserBorrowedData {
user: &user_model,
avatar: None,
banner: None,
},
&req,
)
.await?;
Ok(Json(user))
}
pub async fn handle_user_by_id_many(
Query(ManyUsersByIdReq { id }): Query<Req<GetManyUsersById>>,
State(service): State<Arc<MagnetarService>>,
MaybeUser(user): MaybeUser,
) -> Result<Json<Res<GetManyUsersById>>, ApiError> {
if id.len() >= 100 {
return Err(ArgumentOutOfRange(stringify!(id).to_string()).into());
}
let users = service
.db
.get_many_users_by_id(&id.iter().cloned().sorted().dedup().collect::<Vec<_>>())
.await?;
let ctx = PackingContext::new(service, user.clone()).await?;
let user_model = UserModel;
let user_data = users
.iter()
.map(|user| UserBorrowedData {
user,
avatar: None,
banner: None,
})
.collect::<Vec<_>>();
let futures = user_data
.iter()
.map(|user| user_model.base_from_existing(&ctx, user))
.collect::<Vec<_>>();
let users_proc = futures::stream::iter(futures)
.buffered(20)
.err_into::<PackError>()
.try_collect::<Vec<_>>()
.await?
.into_iter()
.map(|u| (u.id.0.id.clone(), u))
.collect::<HashMap<_, _>>();
let users_ordered = id
.iter()
.map(|ident| users_proc.get(ident).cloned())
.collect::<Vec<_>>();
Ok(Json(users_ordered))
}