420dedbc1e
- Add IM service modules: audit, channel roles, custom emojis, forum tags, integrations, invitations, repo links, slash commands, stages, voice, webhooks - Add PR service modules: review requests, templates - Add repo service modules: contributors, release assets, git extras (archive, branch rename, commit extras, diff/merge, tag, tree) - Add user service: social (follow/block) - Add internal auth service - Update existing service modules with expanded functionality - Remove deleted IM modules: articles, delivery trace, drafts, follows, messages, polls, presence, reactions, threads
131 lines
4.8 KiB
Rust
131 lines
4.8 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::error::AppError;
|
|
use crate::models::common::DigestFrequency;
|
|
use crate::models::users::UserNotifySetting;
|
|
use crate::service::UserService;
|
|
use crate::session::Session;
|
|
|
|
use super::util::parse_enum;
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
|
|
pub struct UpdateUserNotifySettingParams {
|
|
pub email_notifications: Option<bool>,
|
|
pub web_notifications: Option<bool>,
|
|
pub mention_notifications: Option<bool>,
|
|
pub review_notifications: Option<bool>,
|
|
pub security_notifications: Option<bool>,
|
|
pub marketing_emails: Option<bool>,
|
|
pub digest_frequency: Option<String>,
|
|
}
|
|
|
|
impl UserService {
|
|
pub async fn user_notify_setting(&self, ctx: &Session) -> Result<UserNotifySetting, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
self.ensure_user_notify_setting(user_uid).await
|
|
}
|
|
|
|
pub async fn user_update_notify_setting(
|
|
&self,
|
|
ctx: &Session,
|
|
params: UpdateUserNotifySettingParams,
|
|
) -> Result<UserNotifySetting, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let current = self.ensure_user_notify_setting(user_uid).await?;
|
|
let digest_frequency = parse_enum(
|
|
params.digest_frequency,
|
|
current.digest_frequency,
|
|
DigestFrequency::Unknown,
|
|
"digest_frequency",
|
|
)?;
|
|
|
|
sqlx::query_as::<_, UserNotifySetting>(
|
|
"UPDATE user_notify_setting SET email_notifications = $1, web_notifications = $2, \
|
|
mention_notifications = $3, review_notifications = $4, security_notifications = $5, \
|
|
marketing_emails = $6, digest_frequency = $7, updated_at = $8 WHERE user_id = $9 \
|
|
RETURNING user_id, email_notifications, web_notifications, mention_notifications, \
|
|
review_notifications, security_notifications, marketing_emails, digest_frequency, \
|
|
created_at, updated_at",
|
|
)
|
|
.bind(
|
|
params
|
|
.email_notifications
|
|
.unwrap_or(current.email_notifications),
|
|
)
|
|
.bind(
|
|
params
|
|
.web_notifications
|
|
.unwrap_or(current.web_notifications),
|
|
)
|
|
.bind(
|
|
params
|
|
.mention_notifications
|
|
.unwrap_or(current.mention_notifications),
|
|
)
|
|
.bind(
|
|
params
|
|
.review_notifications
|
|
.unwrap_or(current.review_notifications),
|
|
)
|
|
.bind(
|
|
params
|
|
.security_notifications
|
|
.unwrap_or(current.security_notifications),
|
|
)
|
|
.bind(params.marketing_emails.unwrap_or(current.marketing_emails))
|
|
.bind(digest_frequency)
|
|
.bind(chrono::Utc::now())
|
|
.bind(user_uid)
|
|
.fetch_one(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)
|
|
}
|
|
|
|
async fn ensure_user_notify_setting(
|
|
&self,
|
|
user_uid: uuid::Uuid,
|
|
) -> Result<UserNotifySetting, AppError> {
|
|
if let Some(setting) = self.find_user_notify_setting(user_uid).await? {
|
|
return Ok(setting);
|
|
}
|
|
let now = chrono::Utc::now();
|
|
sqlx::query(
|
|
"INSERT INTO user_notify_setting (user_id, email_notifications, web_notifications, \
|
|
mention_notifications, review_notifications, security_notifications, marketing_emails, \
|
|
digest_frequency, created_at, updated_at) \
|
|
VALUES ($1, true, true, true, true, true, false, 'realtime', $2, $2) ON CONFLICT (user_id) DO NOTHING",
|
|
)
|
|
.bind(user_uid)
|
|
.bind(now)
|
|
.execute(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?;
|
|
// Read from writer to avoid replication lag
|
|
sqlx::query_as::<_, UserNotifySetting>(
|
|
"SELECT user_id, email_notifications, web_notifications, mention_notifications, \
|
|
review_notifications, security_notifications, marketing_emails, digest_frequency, \
|
|
created_at, updated_at FROM user_notify_setting WHERE user_id = $1",
|
|
)
|
|
.bind(user_uid)
|
|
.fetch_optional(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?
|
|
.ok_or(AppError::UserNotFound)
|
|
}
|
|
|
|
async fn find_user_notify_setting(
|
|
&self,
|
|
user_uid: uuid::Uuid,
|
|
) -> Result<Option<UserNotifySetting>, AppError> {
|
|
sqlx::query_as::<_, UserNotifySetting>(
|
|
"SELECT user_id, email_notifications, web_notifications, mention_notifications, \
|
|
review_notifications, security_notifications, marketing_emails, digest_frequency, \
|
|
created_at, updated_at FROM user_notify_setting WHERE user_id = $1",
|
|
)
|
|
.bind(user_uid)
|
|
.fetch_optional(self.ctx.db.reader())
|
|
.await
|
|
.map_err(AppError::Database)
|
|
}
|
|
}
|