264 lines
8.4 KiB
Rust
264 lines
8.4 KiB
Rust
use crate::model::processing::notification::NotificationModel;
|
|
use crate::model::processing::user::{UserBorrowedData, UserModel, UserShapedData};
|
|
use crate::model::PackingContext;
|
|
use crate::service::MagnetarService;
|
|
use crate::web::auth::{AuthenticatedUser, MaybeUser};
|
|
use crate::web::pagination::Pagination;
|
|
use crate::web::{ApiError, ArgumentOutOfRange, ObjectNotFound};
|
|
use axum::extract::{Path, Query, State};
|
|
use axum::Json;
|
|
use itertools::Itertools;
|
|
use magnetar_common::util::lenient_parse_tag_decode;
|
|
use magnetar_sdk::endpoints::user::{
|
|
GetFollowRequestsSelf, GetFollowersById, GetFollowersSelf, GetFollowingById, GetFollowingSelf,
|
|
GetManyUsersById, GetNotifications, GetUserByAcct, GetUserById, GetUserSelf, ManyUsersByIdReq,
|
|
NotificationsReq,
|
|
};
|
|
use magnetar_sdk::endpoints::{Req, Res};
|
|
use magnetar_sdk::types::notification::NotificationType;
|
|
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
use strum::IntoEnumIterator;
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
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(),
|
|
profile: None,
|
|
avatar: None,
|
|
banner: None,
|
|
},
|
|
&req,
|
|
)
|
|
.await?;
|
|
Ok(Json(user))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
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,
|
|
profile: None,
|
|
avatar: None,
|
|
banner: None,
|
|
},
|
|
&req,
|
|
)
|
|
.await?;
|
|
Ok(Json(user))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
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.to_string() == 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.as_ref(), tag.host.as_ref())
|
|
.await?
|
|
.ok_or(ObjectNotFound(tag_str))?;
|
|
|
|
let user = UserModel
|
|
.foreign_full_from_base(
|
|
&ctx,
|
|
&UserBorrowedData {
|
|
user: &user_model,
|
|
profile: None,
|
|
avatar: None,
|
|
banner: None,
|
|
},
|
|
&req,
|
|
)
|
|
.await?;
|
|
Ok(Json(user))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
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,
|
|
profile: None,
|
|
avatar: None,
|
|
banner: None,
|
|
})
|
|
.map(|u| Box::new(u) as Box<dyn UserShapedData>)
|
|
.collect::<Vec<_>>();
|
|
|
|
let users_proc = user_model
|
|
.pack_many_base(&ctx, &user_data.iter().map(Box::as_ref).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))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
pub async fn handle_notifications(
|
|
Query(NotificationsReq {
|
|
ref exclude_types,
|
|
include_types,
|
|
unread_only,
|
|
}): Query<Req<GetNotifications>>,
|
|
State(service): State<Arc<MagnetarService>>,
|
|
AuthenticatedUser(user): AuthenticatedUser,
|
|
mut pagination: Pagination,
|
|
) -> Result<(Pagination, Json<Res<GetNotifications>>), ApiError> {
|
|
let notification_types = include_types
|
|
.unwrap_or_else(|| NotificationType::iter().collect::<Vec<_>>())
|
|
.iter()
|
|
.filter(|t| {
|
|
exclude_types.is_none() || !exclude_types.as_ref().is_some_and(|tt| tt.contains(t))
|
|
})
|
|
.copied()
|
|
.collect::<Vec<_>>();
|
|
|
|
let ctx = PackingContext::new(service, Some(user.clone())).await?;
|
|
let notification_model = NotificationModel;
|
|
let notifications = notification_model
|
|
.get_notifications(
|
|
&ctx,
|
|
&user.id,
|
|
¬ification_types,
|
|
unread_only.unwrap_or_default(),
|
|
&mut pagination,
|
|
)
|
|
.await?;
|
|
|
|
Ok((pagination, Json(notifications)))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
pub async fn handle_following_self(
|
|
Query(_): Query<Req<GetFollowingSelf>>,
|
|
State(service): State<Arc<MagnetarService>>,
|
|
AuthenticatedUser(user): AuthenticatedUser,
|
|
mut pagination: Pagination,
|
|
) -> Result<(Pagination, Json<Res<GetFollowingSelf>>), ApiError> {
|
|
let ctx = PackingContext::new(service, Some(user.clone())).await?;
|
|
let user_model = UserModel;
|
|
let users = user_model
|
|
.get_followees(&ctx, &user.id, &mut pagination)
|
|
.await?;
|
|
|
|
Ok((pagination, Json(users)))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
pub async fn handle_followers_self(
|
|
Query(_): Query<Req<GetFollowersSelf>>,
|
|
State(service): State<Arc<MagnetarService>>,
|
|
AuthenticatedUser(user): AuthenticatedUser,
|
|
mut pagination: Pagination,
|
|
) -> Result<(Pagination, Json<Res<GetFollowersSelf>>), ApiError> {
|
|
let ctx = PackingContext::new(service, Some(user.clone())).await?;
|
|
let user_model = UserModel;
|
|
let users = user_model
|
|
.get_followers(&ctx, &user.id, &mut pagination)
|
|
.await?;
|
|
|
|
Ok((pagination, Json(users)))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
pub async fn handle_following(
|
|
Query(_): Query<Req<GetFollowingById>>,
|
|
Path(id): Path<String>,
|
|
State(service): State<Arc<MagnetarService>>,
|
|
MaybeUser(user): MaybeUser,
|
|
mut pagination: Pagination,
|
|
) -> Result<(Pagination, Json<Res<GetFollowingById>>), ApiError> {
|
|
let ctx = PackingContext::new(service, user.clone()).await?;
|
|
let user_model = UserModel;
|
|
let users = user_model.get_followees(&ctx, &id, &mut pagination).await?;
|
|
|
|
Ok((pagination, Json(users)))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
pub async fn handle_followers(
|
|
Query(_): Query<Req<GetFollowersById>>,
|
|
Path(id): Path<String>,
|
|
State(service): State<Arc<MagnetarService>>,
|
|
MaybeUser(user): MaybeUser,
|
|
mut pagination: Pagination,
|
|
) -> Result<(Pagination, Json<Res<GetFollowingById>>), ApiError> {
|
|
let ctx = PackingContext::new(service, user.clone()).await?;
|
|
let user_model = UserModel;
|
|
let users = user_model.get_followers(&ctx, &id, &mut pagination).await?;
|
|
|
|
Ok((pagination, Json(users)))
|
|
}
|
|
|
|
#[tracing::instrument(err, skip_all)]
|
|
pub async fn handle_follow_requests_self(
|
|
Query(_): Query<Req<GetFollowRequestsSelf>>,
|
|
State(service): State<Arc<MagnetarService>>,
|
|
AuthenticatedUser(user): AuthenticatedUser,
|
|
mut pagination: Pagination,
|
|
) -> Result<(Pagination, Json<Res<GetFollowingById>>), ApiError> {
|
|
let ctx = PackingContext::new(service, Some(user.clone())).await?;
|
|
let user_model = UserModel;
|
|
let users = user_model
|
|
.get_follow_requests(&ctx, &user.id, &mut pagination)
|
|
.await?;
|
|
|
|
Ok((pagination, Json(users)))
|
|
}
|