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
140 lines
4.6 KiB
Rust
140 lines
4.6 KiB
Rust
use crate::error::AppError;
|
|
use crate::models::notifications::Notification;
|
|
use crate::service::NotificationService;
|
|
use crate::session::Session;
|
|
use chrono::Utc;
|
|
use uuid::Uuid;
|
|
|
|
use super::util::clamp_limit_offset;
|
|
|
|
impl NotificationService {
|
|
pub async fn list_notifications(
|
|
&self,
|
|
session: &Session,
|
|
unread_only: bool,
|
|
limit: i64,
|
|
offset: i64,
|
|
) -> Result<Vec<Notification>, AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
let (limit, offset) = clamp_limit_offset(limit, offset);
|
|
|
|
Notification::list_for_user(self.ctx.db.reader(), user_id, unread_only, limit, offset).await
|
|
}
|
|
|
|
pub async fn count_unread(&self, session: &Session) -> Result<i64, AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
Notification::count_unread(self.ctx.db.reader(), user_id).await
|
|
}
|
|
|
|
pub async fn mark_as_read(
|
|
&self,
|
|
session: &Session,
|
|
notification_id: Uuid,
|
|
) -> Result<Notification, AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
let now = Utc::now();
|
|
|
|
sqlx::query_as::<_, Notification>(
|
|
"UPDATE notification SET read_at = $1, updated_at = $2 \
|
|
WHERE id = $3 AND user_id = $4 AND deleted_at IS NULL \
|
|
RETURNING id, user_id, notification_type, target_type, target_id, title, body, \
|
|
action_url, action_text, read_at, dismissed_at, created_at, updated_at, deleted_at",
|
|
)
|
|
.bind(now)
|
|
.bind(now)
|
|
.bind(notification_id)
|
|
.bind(user_id)
|
|
.fetch_optional(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?
|
|
.ok_or(AppError::NotFound("notification not found".into()))
|
|
}
|
|
|
|
pub async fn mark_all_as_read(&self, session: &Session) -> Result<i64, AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
let now = Utc::now();
|
|
|
|
let result = sqlx::query(
|
|
"UPDATE notification SET read_at = $1, updated_at = $2 \
|
|
WHERE user_id = $3 AND deleted_at IS NULL AND read_at IS NULL",
|
|
)
|
|
.bind(now)
|
|
.bind(now)
|
|
.bind(user_id)
|
|
.execute(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?;
|
|
|
|
Ok(result.rows_affected() as i64)
|
|
}
|
|
|
|
pub async fn dismiss_notification(
|
|
&self,
|
|
session: &Session,
|
|
notification_id: Uuid,
|
|
) -> Result<Notification, AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
let now = Utc::now();
|
|
|
|
sqlx::query_as::<_, Notification>(
|
|
"UPDATE notification SET dismissed_at = $1, updated_at = $2 \
|
|
WHERE id = $3 AND user_id = $4 AND deleted_at IS NULL \
|
|
RETURNING id, user_id, notification_type, target_type, target_id, title, body, \
|
|
action_url, action_text, read_at, dismissed_at, created_at, updated_at, deleted_at",
|
|
)
|
|
.bind(now)
|
|
.bind(now)
|
|
.bind(notification_id)
|
|
.bind(user_id)
|
|
.fetch_optional(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?
|
|
.ok_or(AppError::NotFound("notification not found".into()))
|
|
}
|
|
|
|
pub async fn delete_notification(
|
|
&self,
|
|
session: &Session,
|
|
notification_id: Uuid,
|
|
) -> Result<(), AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
let now = Utc::now();
|
|
|
|
let result = sqlx::query(
|
|
"UPDATE notification SET deleted_at = $1, updated_at = $2 \
|
|
WHERE id = $3 AND user_id = $4 AND deleted_at IS NULL",
|
|
)
|
|
.bind(now)
|
|
.bind(now)
|
|
.bind(notification_id)
|
|
.bind(user_id)
|
|
.execute(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?;
|
|
|
|
if result.rows_affected() == 0 {
|
|
return Err(AppError::NotFound("notification not found".into()));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn clear_all_notifications(&self, session: &Session) -> Result<i64, AppError> {
|
|
let user_id = session.user().ok_or(AppError::Unauthorized)?;
|
|
let now = Utc::now();
|
|
|
|
let result = sqlx::query(
|
|
"UPDATE notification SET dismissed_at = $1, updated_at = $2 \
|
|
WHERE user_id = $3 AND deleted_at IS NULL AND dismissed_at IS NULL",
|
|
)
|
|
.bind(now)
|
|
.bind(now)
|
|
.bind(user_id)
|
|
.execute(self.ctx.db.writer())
|
|
.await
|
|
.map_err(AppError::Database)?;
|
|
|
|
Ok(result.rows_affected() as i64)
|
|
}
|
|
}
|