mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 00:55:25 +00:00
feat(labrinth): check privacy route (#7195)
* feat(labrinth): check privacy endpoint * refactor(labrinth): remove duplicated code
This commit is contained in:
@@ -16,6 +16,16 @@ pub struct UserPreferences {
|
||||
pub social: SocialPreferences,
|
||||
}
|
||||
|
||||
impl UserPreferences {
|
||||
pub fn resolve(overrides: Option<PartialUserPreferences>) -> Self {
|
||||
let mut preferences = Self::default();
|
||||
if let Some(overrides) = overrides {
|
||||
overrides.apply_to(&mut preferences);
|
||||
}
|
||||
preferences
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Serialize, Deserialize, ToSchema, Default, PartialEq, Component,
|
||||
)]
|
||||
|
||||
@@ -15,6 +15,7 @@ pub mod medal;
|
||||
pub mod moderation;
|
||||
pub mod mural;
|
||||
pub mod pats;
|
||||
pub mod privacy;
|
||||
pub mod search;
|
||||
pub mod server_ping;
|
||||
pub mod session;
|
||||
@@ -32,6 +33,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
.wrap(default_cors())
|
||||
.configure(admin::config)
|
||||
.configure(blocked_users::config)
|
||||
.configure(privacy::config)
|
||||
.configure(session::config)
|
||||
.configure(flows::config)
|
||||
.configure(pats::config)
|
||||
@@ -68,6 +70,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
paths(
|
||||
admin::count_download,
|
||||
blocked_users::block_status,
|
||||
privacy::invite_privacy_status,
|
||||
admin::force_reindex,
|
||||
admin::force_reindex_project,
|
||||
session::list,
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
use crate::database::PgPool;
|
||||
use crate::database::models::blocked_user_item::DBBlockedUser;
|
||||
use crate::database::models::friend_item::DBFriend;
|
||||
use crate::database::models::user_item::DBUser;
|
||||
use crate::database::models::user_preferences_item::DBUserPreferences;
|
||||
use crate::models::v3::preferences::{InvitePrivacy, UserPreferences};
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::error::Context as _;
|
||||
use crate::util::guards::admin_key_guard;
|
||||
use actix_web::{get, web};
|
||||
use serde::Serialize;
|
||||
use xredis::RedisPool;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(invite_privacy_status);
|
||||
}
|
||||
|
||||
#[derive(Serialize, utoipa::ToSchema)]
|
||||
pub struct InvitePrivacyStatus {
|
||||
pub allowed: bool,
|
||||
}
|
||||
|
||||
#[derive(strum::EnumString)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
enum InviteType {
|
||||
SharedInstances,
|
||||
HostingAccess,
|
||||
}
|
||||
|
||||
/// Check whether `user_id` may send `target_id` an invite of the given type.
|
||||
#[utoipa::path(tag = "privacy", responses((status = OK, body = InvitePrivacyStatus)))]
|
||||
#[get(
|
||||
"/privacy/{invite_type}/{user_id}/{target_id}",
|
||||
guard = "admin_key_guard"
|
||||
)]
|
||||
pub async fn invite_privacy_status(
|
||||
info: web::Path<(String, String, String)>,
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
) -> Result<web::Json<InvitePrivacyStatus>, ApiError> {
|
||||
let (invite_type, user_id, target_id) = info.into_inner();
|
||||
|
||||
let invite_type = invite_type
|
||||
.parse::<InviteType>()
|
||||
.wrap_request_err("invalid invite_type")?;
|
||||
let (user, target) = futures::try_join!(
|
||||
DBUser::get(&user_id, &**pool, &redis),
|
||||
DBUser::get(&target_id, &**pool, &redis),
|
||||
)
|
||||
.wrap_internal_err("resolving user ids")?;
|
||||
|
||||
let user_id = user.wrap_not_found_err("user not found")?.id;
|
||||
let target_id = target.wrap_not_found_err("target not found")?.id;
|
||||
|
||||
let blocked = DBBlockedUser::is_blocked(target_id, user_id, &**pool)
|
||||
.await
|
||||
.wrap_internal_err("checking whether user is blocked")?;
|
||||
|
||||
let allowed = if blocked {
|
||||
false
|
||||
} else {
|
||||
let overrides = DBUserPreferences::get(target_id, &**pool)
|
||||
.await
|
||||
.wrap_internal_err("fetching user preferences")?;
|
||||
let preferences = UserPreferences::resolve(overrides);
|
||||
|
||||
let privacy = match invite_type {
|
||||
InviteType::SharedInstances => {
|
||||
preferences.social.shared_instances_privacy
|
||||
}
|
||||
InviteType::HostingAccess => {
|
||||
preferences.social.hosting_access_privacy
|
||||
}
|
||||
};
|
||||
|
||||
match privacy {
|
||||
InvitePrivacy::Everyone => true,
|
||||
InvitePrivacy::None => false,
|
||||
InvitePrivacy::Friends => {
|
||||
DBFriend::get_friend(user_id, target_id, &**pool)
|
||||
.await
|
||||
.wrap_internal_err("checking friendship status")?
|
||||
.is_some_and(|friend| friend.accepted)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(web::Json(InvitePrivacyStatus { allowed }))
|
||||
}
|
||||
@@ -409,15 +409,7 @@ pub async fn get_user_preferences(
|
||||
.await
|
||||
.wrap_internal_err("failed to fetch user preferences")?;
|
||||
|
||||
let preferences = preference_overrides
|
||||
.map(|overrides| {
|
||||
let mut preferences = UserPreferences::default();
|
||||
overrides.apply_to(&mut preferences);
|
||||
preferences
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(web::Json(preferences))
|
||||
Ok(web::Json(UserPreferences::resolve(preference_overrides)))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
@@ -466,10 +458,7 @@ pub async fn edit_user_preferences(
|
||||
.await
|
||||
.wrap_internal_err("failed to fetch user preferences")?;
|
||||
|
||||
let mut preferences = UserPreferences::default();
|
||||
if let Some(stored) = stored {
|
||||
stored.apply_to(&mut preferences);
|
||||
}
|
||||
let mut preferences = UserPreferences::resolve(stored);
|
||||
body.into_inner().apply_to(&mut preferences);
|
||||
|
||||
let overrides = preferences.into_diff_from(&UserPreferences::default());
|
||||
@@ -481,8 +470,7 @@ pub async fn edit_user_preferences(
|
||||
.await
|
||||
.wrap_internal_err("committing database transaction")?;
|
||||
|
||||
let mut preferences = UserPreferences::default();
|
||||
overrides.apply_to(&mut preferences);
|
||||
let preferences = UserPreferences::resolve(Some(overrides));
|
||||
|
||||
Ok(web::Json(preferences))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user