use db::sqlx; use model::users::UserPrivacyModel; use serde::{Deserialize, Serialize}; use session::Session; use crate::{AppService, error::AppError, session_user}; #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct UserPrivacyConfig { pub profile_visibility: String, pub email_visibility: String, pub activity_visibility: String, pub allow_search_indexing: bool, pub allow_direct_messages: bool, pub show_online_status: bool, } #[derive(Debug, Clone, Deserialize, utoipa::ToSchema)] pub struct UpdateUserPrivacyConfig { pub profile_visibility: Option, pub email_visibility: Option, pub activity_visibility: Option, pub allow_search_indexing: Option, pub allow_direct_messages: Option, pub show_online_status: Option, } impl AppService { pub async fn user_update_privacy_config( &self, ctx: &Session, params: UpdateUserPrivacyConfig, ) -> Result { let user_uid = session_user(ctx)?; let mut config = self.user_privacy_config(user_uid).await?; if let Some(profile_visibility) = params.profile_visibility { config.profile_visibility = profile_visibility; } if let Some(email_visibility) = params.email_visibility { config.email_visibility = email_visibility; } if let Some(activity_visibility) = params.activity_visibility { config.activity_visibility = activity_visibility; } if let Some(allow_search_indexing) = params.allow_search_indexing { config.allow_search_indexing = allow_search_indexing; } if let Some(allow_direct_messages) = params.allow_direct_messages { config.allow_direct_messages = allow_direct_messages; } if let Some(show_online_status) = params.show_online_status { config.show_online_status = show_online_status; } let now = chrono::Utc::now(); sqlx::query( "INSERT INTO user_privacy \ (\"user\", profile_visibility, email_visibility, activity_visibility, allow_search_indexing, allow_direct_messages, show_online_status, created_at, updated_at) \ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $8) \ ON CONFLICT (\"user\") DO UPDATE SET \ profile_visibility = EXCLUDED.profile_visibility, email_visibility = EXCLUDED.email_visibility, \ activity_visibility = EXCLUDED.activity_visibility, allow_search_indexing = EXCLUDED.allow_search_indexing, \ allow_direct_messages = EXCLUDED.allow_direct_messages, show_online_status = EXCLUDED.show_online_status, \ updated_at = EXCLUDED.updated_at", ) .bind(user_uid) .bind(&config.profile_visibility) .bind(&config.email_visibility) .bind(&config.activity_visibility) .bind(config.allow_search_indexing) .bind(config.allow_direct_messages) .bind(config.show_online_status) .bind(now) .execute(self.db.writer()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(config) } pub async fn user_privacy_config( &self, user_uid: uuid::Uuid, ) -> Result { let row = sqlx::query_as::<_, UserPrivacyModel>( "SELECT \"user\", profile_visibility, email_visibility, activity_visibility, allow_search_indexing, allow_direct_messages, show_online_status, created_at, updated_at \ FROM user_privacy WHERE \"user\" = $1", ) .bind(user_uid) .fetch_optional(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(row.map(Into::into).unwrap_or_default()) } } impl Default for UserPrivacyConfig { fn default() -> Self { Self { profile_visibility: "public".to_string(), email_visibility: "private".to_string(), activity_visibility: "public".to_string(), allow_search_indexing: true, allow_direct_messages: true, show_online_status: true, } } } impl From for UserPrivacyConfig { fn from(value: UserPrivacyModel) -> Self { Self { profile_visibility: value.profile_visibility, email_visibility: value.email_visibility, activity_visibility: value.activity_visibility, allow_search_indexing: value.allow_search_indexing, allow_direct_messages: value.allow_direct_messages, show_online_status: value.show_online_status, } } }