197 lines
6.2 KiB
Rust
197 lines
6.2 KiB
Rust
use crate::model_ext::{
|
|
AliasColumnExt, AliasSourceExt, AliasSuffixExt, CursorPaginationExt, EntityPrefixExt, MagIden,
|
|
ModelPagination, SelectColumnsExt,
|
|
};
|
|
use crate::note_model::data::NoteData;
|
|
use crate::note_model::{NoteResolveOptions, NoteResolver};
|
|
use crate::user_model::{UserData, UserResolveOptions, UserResolver};
|
|
use crate::{CalckeyDbError, CalckeyModel};
|
|
use chrono::{DateTime, Utc};
|
|
use ck::sea_orm_active_enums::NotificationTypeEnum;
|
|
use ck::{access_token, notification, user};
|
|
use ext_calckey_model_migration::{JoinType, SelectStatement};
|
|
use magnetar_sdk::types::SpanFilter;
|
|
use sea_orm::prelude::Expr;
|
|
use sea_orm::sea_query::{IntoCondition, Query};
|
|
use sea_orm::{ActiveEnum, Iden, IntoSimpleExpr, QueryTrait};
|
|
use sea_orm::{DbErr, EntityTrait, FromQueryResult, QueryFilter, QueryResult, QuerySelect};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct NotificationData {
|
|
pub notification: notification::Model,
|
|
pub access_token: Option<access_token::Model>,
|
|
pub notifier: Option<UserData>,
|
|
pub notification_note: Option<NoteData>,
|
|
}
|
|
|
|
impl FromQueryResult for NotificationData {
|
|
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
|
|
let prefix = if prefix.is_empty() {
|
|
notification::Entity.base_prefix()
|
|
} else {
|
|
MagIden::alias(prefix)
|
|
};
|
|
|
|
Ok(NotificationData {
|
|
notification: notification::Model::from_query_result(res, &prefix.to_string())?,
|
|
access_token: access_token::Model::from_query_result_optional(
|
|
res,
|
|
&prefix.join_str_as_str(ACCESS_TOKEN),
|
|
)?,
|
|
notification_note: NoteData::from_query_result_optional(
|
|
res,
|
|
&prefix.join_str_as_str(NOTIFICATION_NOTE),
|
|
)?,
|
|
notifier: UserData::from_query_result_optional(res, &prefix.join_str_as_str(NOTIFIER))?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ModelPagination for NotificationData {
|
|
fn id(&self) -> &str {
|
|
&self.notification.id
|
|
}
|
|
|
|
fn time(&self) -> DateTime<Utc> {
|
|
self.notification.created_at.into()
|
|
}
|
|
}
|
|
|
|
const NOTIFIER: &str = "notifier.";
|
|
const NOTIFICATION_NOTE: &str = "note.";
|
|
const ACCESS_TOKEN: &str = "access_token.";
|
|
|
|
pub struct NotificationResolveOptions {
|
|
pub note_options: NoteResolveOptions,
|
|
pub user_options: UserResolveOptions,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct NotificationResolver {
|
|
db: CalckeyModel,
|
|
note_resolver: NoteResolver,
|
|
user_resolver: UserResolver,
|
|
}
|
|
|
|
impl NotificationResolver {
|
|
pub(crate) fn new(
|
|
db: CalckeyModel,
|
|
user_resolver: UserResolver,
|
|
note_resolver: NoteResolver,
|
|
) -> Self {
|
|
Self {
|
|
db,
|
|
note_resolver,
|
|
user_resolver,
|
|
}
|
|
}
|
|
|
|
pub fn resolve(
|
|
&self,
|
|
q: &mut SelectStatement,
|
|
notification_tbl: &MagIden,
|
|
resolve_options: &NotificationResolveOptions,
|
|
note_resolver: &NoteResolver,
|
|
user_resolver: &UserResolver,
|
|
) {
|
|
q.add_aliased_columns::<notification::Entity>(¬ification_tbl);
|
|
|
|
let notifier_tbl = notification_tbl.join_str(NOTIFIER);
|
|
q.add_aliased_columns::<user::Entity>(¬ifier_tbl);
|
|
q.join_columns(
|
|
JoinType::LeftJoin,
|
|
notification::Relation::User2.with_from_alias(notification_tbl),
|
|
¬ifier_tbl,
|
|
);
|
|
user_resolver.resolve(q, ¬ifier_tbl, &resolve_options.user_options);
|
|
|
|
let token_tbl = notification_tbl.join_str(ACCESS_TOKEN);
|
|
q.add_aliased_columns::<access_token::Entity>(&token_tbl);
|
|
q.join_columns(
|
|
JoinType::LeftJoin,
|
|
notification::Relation::AccessToken.with_from_alias(notification_tbl),
|
|
&token_tbl,
|
|
);
|
|
|
|
let note_tbl = notification_tbl.join_str(NOTIFICATION_NOTE);
|
|
q.join_columns(
|
|
JoinType::LeftJoin,
|
|
notification::Relation::Note.with_from_alias(notification_tbl),
|
|
¬e_tbl,
|
|
);
|
|
note_resolver.attach_note(
|
|
q,
|
|
¬e_tbl,
|
|
1,
|
|
1,
|
|
&resolve_options.note_options,
|
|
&self.user_resolver,
|
|
);
|
|
}
|
|
|
|
pub async fn get(
|
|
&self,
|
|
resolve_options: &NotificationResolveOptions,
|
|
user_id: &str,
|
|
notification_types: &[NotificationTypeEnum],
|
|
unread_only: bool,
|
|
pagination: &SpanFilter,
|
|
prev: &mut Option<SpanFilter>,
|
|
next: &mut Option<SpanFilter>,
|
|
limit: u64,
|
|
) -> Result<Vec<NotificationData>, CalckeyDbError> {
|
|
let notification_tbl = notification::Entity.base_prefix();
|
|
|
|
let mut query = Query::select();
|
|
query.from_as(notification::Entity, notification_tbl.clone());
|
|
|
|
self.resolve(
|
|
&mut query,
|
|
¬ification_tbl,
|
|
&resolve_options,
|
|
&self.note_resolver,
|
|
&self.user_resolver,
|
|
);
|
|
|
|
let mut select = notification::Entity::find();
|
|
*QuerySelect::query(&mut select) = query;
|
|
|
|
let notifications = select
|
|
.filter(
|
|
notification_tbl
|
|
.col(notification::Column::NotifieeId)
|
|
.eq(user_id)
|
|
.and(
|
|
notification_tbl.col(notification::Column::Type).is_in(
|
|
notification_types
|
|
.iter()
|
|
.copied()
|
|
.map(Expr::val)
|
|
.map(|e| e.cast_as(NotificationTypeEnum::name())),
|
|
),
|
|
),
|
|
)
|
|
.apply_if(unread_only.then_some(()), |s, _| {
|
|
s.filter(
|
|
notification_tbl
|
|
.col(notification::Column::IsRead)
|
|
.not()
|
|
.into_condition(),
|
|
)
|
|
})
|
|
.get_paginated_model::<NotificationData, _, _>(
|
|
&self.db.0,
|
|
Some(notification_tbl),
|
|
(notification::Column::CreatedAt, notification::Column::Id),
|
|
pagination,
|
|
prev,
|
|
next,
|
|
limit,
|
|
)
|
|
.await?;
|
|
|
|
Ok(notifications)
|
|
}
|
|
}
|