use crate::model::data::id::BaseId; use crate::model::processing::emoji::EmojiModel; use crate::model::processing::note::{NoteModel, NoteVisibilityFilterModel}; use crate::model::processing::user::UserModel; use crate::model::processing::{PackError, PackResult}; use crate::model::{PackType, PackingContext}; use crate::web::pagination::Pagination; use futures_util::{StreamExt, TryStreamExt}; use magnetar_calckey_model::ck; use magnetar_calckey_model::ck::sea_orm_active_enums::NotificationTypeEnum; use magnetar_calckey_model::note_model::NoteResolveOptions; use magnetar_calckey_model::notification_model::{NotificationData, NotificationResolveOptions}; use magnetar_calckey_model::user_model::UserResolveOptions; use magnetar_sdk::types::notification::{ NotificationAppExt, NotificationBase, NotificationNoteExt, NotificationReactionExt, NotificationType, NotificationUserExt, PackNotification, PackNotificationApp, PackNotificationFollow, PackNotificationFollowRequestAccepted, PackNotificationFollowRequestReceived, PackNotificationMention, PackNotificationPollEnd, PackNotificationQuote, PackNotificationReaction, PackNotificationRenote, PackNotificationReply, }; use magnetar_sdk::types::Id; use magnetar_sdk::{Packed, Required}; use std::sync::Arc; impl PackType<&NotificationType> for NotificationTypeEnum { fn extract(_: &PackingContext, value: &NotificationType) -> Self { use NotificationType as NT; use NotificationTypeEnum as NTE; match value { NT::Follow => NTE::Follow, NT::FollowRequestReceived => NTE::ReceiveFollowRequest, NT::FollowRequestAccepted => NTE::FollowRequestAccepted, NT::Mention => NTE::Mention, NT::Reply => NTE::Reply, NT::Renote => NTE::Renote, NT::Reaction => NTE::Reaction, NT::Quote => NTE::Quote, NT::PollEnd => NTE::PollEnded, NT::App => NTE::App, } } } impl PackType<&NotificationTypeEnum> for NotificationType { fn extract(_: &PackingContext, value: &NotificationTypeEnum) -> Self { use NotificationType as NT; use NotificationTypeEnum as NTE; match value { NTE::Follow => NT::Follow, NTE::ReceiveFollowRequest => NT::FollowRequestReceived, NTE::FollowRequestAccepted => NT::FollowRequestAccepted, NTE::Mention => NT::Mention, NTE::Reply => NT::Reply, NTE::Renote => NT::Renote, NTE::Reaction => NT::Reaction, NTE::Quote => NT::Quote, NTE::PollEnded => NT::PollEnd, NTE::App => NT::App, } } } pub struct NotificationModel; impl NotificationModel { async fn pack_notification_single( &self, ctx: &PackingContext, notification_data: &NotificationData, note_model: &NoteModel, user_model: &UserModel, emoji_model: &EmojiModel, ) -> PackResult { let notification_type = NotificationType::extract(ctx, ¬ification_data.notification.r#type); let id = Required(Id::from(¬ification_data.notification.id)); let base = Required(NotificationBase::extract( ctx, ¬ification_data.notification, )); let notifier = notification_data .notifier .as_ref() .ok_or_else(|| PackError::DataError("Missing notification user".to_string())); let note = notification_data .notification_note .as_ref() .ok_or_else(|| PackError::DataError("Missing notification note".to_string())); let access_token = notification_data .access_token .as_ref() .ok_or_else(|| PackError::DataError("Missing notification access token".to_string())); Ok(match notification_type { NotificationType::Follow => { PackNotification::Follow(PackNotificationFollow::pack_from(( id, base, Required(NotificationUserExt::extract( ctx, &user_model.base_from_existing(ctx, ¬ifier?).await?, )), ))) } NotificationType::FollowRequestReceived => PackNotification::FollowRequestReceived( PackNotificationFollowRequestReceived::pack_from(( id, base, Required(NotificationUserExt::extract( ctx, &user_model.base_from_existing(ctx, ¬ifier?).await?, )), )), ), NotificationType::FollowRequestAccepted => PackNotification::FollowRequestAccepted( PackNotificationFollowRequestAccepted::pack_from(( id, base, Required(NotificationUserExt::extract( ctx, &user_model.base_from_existing(ctx, ¬ifier?).await?, )), )), ), NotificationType::Mention => { PackNotification::Mention(PackNotificationMention::pack_from(( id, base, Required(NotificationNoteExt::extract( ctx, ¬e_model.pack_full_single(ctx, ¬e?).await?, )), ))) } NotificationType::Reply => PackNotification::Reply(PackNotificationReply::pack_from(( id, base, Required(NotificationNoteExt::extract( ctx, ¬e_model.pack_full_single(ctx, ¬e?).await?, )), ))), NotificationType::Renote => { PackNotification::Renote(PackNotificationRenote::pack_from(( id, base, Required(NotificationNoteExt::extract( ctx, ¬e_model.pack_full_single(ctx, ¬e?).await?, )), ))) } NotificationType::Reaction => { PackNotification::Reaction(PackNotificationReaction::pack_from(( id, base, Required(NotificationNoteExt::extract( ctx, ¬e_model.pack_full_single(ctx, ¬e?).await?, )), Required(NotificationReactionExt::extract( ctx, &emoji_model .resolve_reaction( ctx, notification_data .notification .reaction .as_deref() .ok_or_else(|| { PackError::DataError( "Missing notification reaction".to_string(), ) })?, ) .await?, )), Required(NotificationUserExt::extract( ctx, &user_model.base_from_existing(ctx, ¬ifier?).await?, )), ))) } NotificationType::Quote => PackNotification::Quote(PackNotificationQuote::pack_from(( id, base, Required(NotificationNoteExt::extract( ctx, ¬e_model.pack_full_single(ctx, ¬e?).await?, )), ))), NotificationType::PollEnd => { PackNotification::PollEnd(PackNotificationPollEnd::pack_from(( id, base, Required(NotificationNoteExt::extract( ctx, ¬e_model.pack_full_single(ctx, ¬e?).await?, )), ))) } NotificationType::App => PackNotification::App(PackNotificationApp::pack_from(( id, base, Required(NotificationAppExt::extract( ctx, (¬ification_data.notification, access_token?), )), ))), }) } pub async fn get_notifications( &self, ctx: &PackingContext, id: &str, notification_types: &[NotificationType], unread_only: bool, pagination: &mut Pagination, ) -> PackResult> { let user_resolve_options = UserResolveOptions { with_avatar: true, with_banner: false, with_profile: false, }; let self_id = ctx.self_user.as_deref().map(ck::user::Model::get_id); let notifications_raw = ctx .service .db .get_notification_resolver() .get( &NotificationResolveOptions { note_options: NoteResolveOptions { ids: None, visibility_filter: Arc::new( NoteVisibilityFilterModel.new_note_visibility_filter(Some(id)), ), time_range: None, limit: None, with_reply_target: true, with_renote_target: true, with_interactions_from: self_id.map(str::to_string), only_pins_from: None, user_options: user_resolve_options.clone(), }, user_options: user_resolve_options, }, id, ¬ification_types .iter() .map(|v| NotificationTypeEnum::extract(ctx, v)) .collect::>(), unread_only, &pagination.current, &mut pagination.prev, &mut pagination.next, pagination.limit.into(), ) .await?; let note_model = NoteModel { with_context: true, attachments: false, }; let user_model = UserModel; let emoji_model = EmojiModel; let fut_iter = notifications_raw .iter() .map(|n| self.pack_notification_single(ctx, n, ¬e_model, &user_model, &emoji_model)) .collect::>(); let processed = futures::stream::iter(fut_iter) .buffered(10) .err_into::() .try_collect::>() .await?; Ok(processed) } }