mirror of
https://github.com/modrinth/code.git
synced 2026-08-27 18:14:49 +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,
|
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(
|
#[derive(
|
||||||
Debug, Serialize, Deserialize, ToSchema, Default, PartialEq, Component,
|
Debug, Serialize, Deserialize, ToSchema, Default, PartialEq, Component,
|
||||||
)]
|
)]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub mod medal;
|
|||||||
pub mod moderation;
|
pub mod moderation;
|
||||||
pub mod mural;
|
pub mod mural;
|
||||||
pub mod pats;
|
pub mod pats;
|
||||||
|
pub mod privacy;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod server_ping;
|
pub mod server_ping;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
@@ -32,6 +33,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
.wrap(default_cors())
|
.wrap(default_cors())
|
||||||
.configure(admin::config)
|
.configure(admin::config)
|
||||||
.configure(blocked_users::config)
|
.configure(blocked_users::config)
|
||||||
|
.configure(privacy::config)
|
||||||
.configure(session::config)
|
.configure(session::config)
|
||||||
.configure(flows::config)
|
.configure(flows::config)
|
||||||
.configure(pats::config)
|
.configure(pats::config)
|
||||||
@@ -68,6 +70,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
paths(
|
paths(
|
||||||
admin::count_download,
|
admin::count_download,
|
||||||
blocked_users::block_status,
|
blocked_users::block_status,
|
||||||
|
privacy::invite_privacy_status,
|
||||||
admin::force_reindex,
|
admin::force_reindex,
|
||||||
admin::force_reindex_project,
|
admin::force_reindex_project,
|
||||||
session::list,
|
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
|
.await
|
||||||
.wrap_internal_err("failed to fetch user preferences")?;
|
.wrap_internal_err("failed to fetch user preferences")?;
|
||||||
|
|
||||||
let preferences = preference_overrides
|
Ok(web::Json(UserPreferences::resolve(preference_overrides)))
|
||||||
.map(|overrides| {
|
|
||||||
let mut preferences = UserPreferences::default();
|
|
||||||
overrides.apply_to(&mut preferences);
|
|
||||||
preferences
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
Ok(web::Json(preferences))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
@@ -466,10 +458,7 @@ pub async fn edit_user_preferences(
|
|||||||
.await
|
.await
|
||||||
.wrap_internal_err("failed to fetch user preferences")?;
|
.wrap_internal_err("failed to fetch user preferences")?;
|
||||||
|
|
||||||
let mut preferences = UserPreferences::default();
|
let mut preferences = UserPreferences::resolve(stored);
|
||||||
if let Some(stored) = stored {
|
|
||||||
stored.apply_to(&mut preferences);
|
|
||||||
}
|
|
||||||
body.into_inner().apply_to(&mut preferences);
|
body.into_inner().apply_to(&mut preferences);
|
||||||
|
|
||||||
let overrides = preferences.into_diff_from(&UserPreferences::default());
|
let overrides = preferences.into_diff_from(&UserPreferences::default());
|
||||||
@@ -481,8 +470,7 @@ pub async fn edit_user_preferences(
|
|||||||
.await
|
.await
|
||||||
.wrap_internal_err("committing database transaction")?;
|
.wrap_internal_err("committing database transaction")?;
|
||||||
|
|
||||||
let mut preferences = UserPreferences::default();
|
let preferences = UserPreferences::resolve(Some(overrides));
|
||||||
overrides.apply_to(&mut preferences);
|
|
||||||
|
|
||||||
Ok(web::Json(preferences))
|
Ok(web::Json(preferences))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user