Skip to content
Clone
main
182 lines 5.7 KB Rust
use models::users::user_reports::{self, ReportStatus};
use models::users::{user_recent_mentions, user_saved_messages};
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder,
QuerySelect, Set,
};
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use utoipa::ToSchema;
use uuid::Uuid;
use crate::errors::UserError;
use crate::services::service::UserService;
use crate::share::page::{Page, PageQuery};
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct RecentMentionDto {
pub id: Uuid,
pub channel_id: Uuid,
pub message_id: Uuid,
pub created_at: OffsetDateTime,
}
impl From<user_recent_mentions::Model> for RecentMentionDto {
fn from(m: user_recent_mentions::Model) -> Self {
Self {
id: m.id,
channel_id: m.channel_id,
message_id: m.message_id,
created_at: m.created_at,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UserReportDto {
pub id: Uuid,
pub reported_id: i64,
pub reason: String,
pub evidence: Option<String>,
pub status: ReportStatus,
pub resolution_note: Option<String>,
pub created_at: OffsetDateTime,
pub updated_at: OffsetDateTime,
}
impl From<user_reports::Model> for UserReportDto {
fn from(m: user_reports::Model) -> Self {
Self {
id: m.id,
reported_id: m.reported_uid,
reason: m.reason,
evidence: m.evidence,
status: m.status,
resolution_note: m.resolution_note,
created_at: m.created_at,
updated_at: m.updated_at,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SavedMessageDto {
pub id: Uuid,
pub channel_id: Uuid,
pub message_id: Uuid,
pub saved_at: OffsetDateTime,
}
impl From<user_saved_messages::Model> for SavedMessageDto {
fn from(m: user_saved_messages::Model) -> Self {
Self {
id: m.id,
channel_id: m.channel_id,
message_id: m.message_id,
saved_at: m.saved_at,
}
}
}
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct SaveMessageCmd {
pub channel_id: Uuid,
pub message_id: Uuid,
}
impl UserService {
pub async fn recent_mentions(
&self,
uid: i64,
limit: Option<u64>,
) -> Result<Vec<RecentMentionDto>, UserError> {
let lim = limit.unwrap_or(50).clamp(1, 50);
let rows = user_recent_mentions::Entity::find()
.filter(user_recent_mentions::Column::UserId.eq(uid))
.order_by_desc(user_recent_mentions::Column::CreatedAt)
.limit(Some(lim))
.all(self.database.read())
.await?;
Ok(rows.into_iter().map(RecentMentionDto::from).collect())
}
pub async fn my_reports(
&self,
uid: i64,
q: PageQuery,
) -> Result<Page<UserReportDto>, UserError> {
let (limit, offset) = q.bounds()?;
let select =
user_reports::Entity::find().filter(user_reports::Column::ReporterUid.eq(Some(uid)));
let total = select.clone().count(self.database.read()).await?;
let rows = select
.order_by_desc(user_reports::Column::CreatedAt)
.limit(limit)
.offset(offset)
.all(self.database.read())
.await?;
let items = rows.into_iter().map(UserReportDto::from).collect();
Ok(Page::new(items, total, limit, offset))
}
pub async fn list_saved_messages(
&self,
uid: i64,
q: PageQuery,
) -> Result<Page<SavedMessageDto>, UserError> {
let (limit, offset) = q.bounds()?;
let select =
user_saved_messages::Entity::find().filter(user_saved_messages::Column::UserId.eq(uid));
let total = select.clone().count(self.database.read()).await?;
let rows = select
.order_by_desc(user_saved_messages::Column::SavedAt)
.limit(limit)
.offset(offset)
.all(self.database.read())
.await?;
let items = rows.into_iter().map(SavedMessageDto::from).collect();
Ok(Page::new(items, total, limit, offset))
}
#[tracing::instrument(name = "user.save_message", skip_all, fields(uid = %uid))]
pub async fn save_message(
&self,
uid: i64,
cmd: SaveMessageCmd,
) -> Result<SavedMessageDto, UserError> {
let existing = user_saved_messages::Entity::find()
.filter(user_saved_messages::Column::UserId.eq(uid))
.filter(user_saved_messages::Column::ChannelId.eq(cmd.channel_id))
.filter(user_saved_messages::Column::MessageId.eq(cmd.message_id))
.one(self.database.read())
.await?;
if let Some(row) = existing {
return Ok(SavedMessageDto::from(row));
}
let now = OffsetDateTime::now_utc();
let active = user_saved_messages::ActiveModel {
id: Set(Uuid::now_v7()),
user_id: Set(uid),
channel_id: Set(cmd.channel_id),
message_id: Set(cmd.message_id),
saved_at: Set(now),
};
let saved = active.insert(self.database.write()).await?;
Ok(SavedMessageDto::from(saved))
}
#[tracing::instrument(
name = "user.unsave_message",
skip_all,
fields(uid = %uid, message_id = %message_id)
)]
pub async fn unsave_message(&self, uid: i64, message_id: Uuid) -> Result<(), UserError> {
user_saved_messages::Entity::delete_many()
.filter(user_saved_messages::Column::UserId.eq(uid))
.filter(user_saved_messages::Column::MessageId.eq(message_id))
.exec(self.database.write())
.await?;
Ok(())
}
}