magnetar/src/model/processing/notification.rs

284 lines
11 KiB
Rust

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<PackNotification> {
let notification_type =
NotificationType::extract(ctx, &notification_data.notification.r#type);
let id = Required(Id::from(&notification_data.notification.id));
let base = Required(NotificationBase::extract(
ctx,
&notification_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, &notifier?).await?,
)),
)))
}
NotificationType::FollowRequestReceived => PackNotification::FollowRequestReceived(
PackNotificationFollowRequestReceived::pack_from((
id,
base,
Required(NotificationUserExt::extract(
ctx,
&user_model.base_from_existing(ctx, &notifier?).await?,
)),
)),
),
NotificationType::FollowRequestAccepted => PackNotification::FollowRequestAccepted(
PackNotificationFollowRequestAccepted::pack_from((
id,
base,
Required(NotificationUserExt::extract(
ctx,
&user_model.base_from_existing(ctx, &notifier?).await?,
)),
)),
),
NotificationType::Mention => {
PackNotification::Mention(PackNotificationMention::pack_from((
id,
base,
Required(NotificationNoteExt::extract(
ctx,
&note_model.pack_full_single(ctx, &note?).await?,
)),
)))
}
NotificationType::Reply => PackNotification::Reply(PackNotificationReply::pack_from((
id,
base,
Required(NotificationNoteExt::extract(
ctx,
&note_model.pack_full_single(ctx, &note?).await?,
)),
))),
NotificationType::Renote => {
PackNotification::Renote(PackNotificationRenote::pack_from((
id,
base,
Required(NotificationNoteExt::extract(
ctx,
&note_model.pack_full_single(ctx, &note?).await?,
)),
)))
}
NotificationType::Reaction => {
PackNotification::Reaction(PackNotificationReaction::pack_from((
id,
base,
Required(NotificationNoteExt::extract(
ctx,
&note_model.pack_full_single(ctx, &note?).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, &notifier?).await?,
)),
)))
}
NotificationType::Quote => PackNotification::Quote(PackNotificationQuote::pack_from((
id,
base,
Required(NotificationNoteExt::extract(
ctx,
&note_model.pack_full_single(ctx, &note?).await?,
)),
))),
NotificationType::PollEnd => {
PackNotification::PollEnd(PackNotificationPollEnd::pack_from((
id,
base,
Required(NotificationNoteExt::extract(
ctx,
&note_model.pack_full_single(ctx, &note?).await?,
)),
)))
}
NotificationType::App => PackNotification::App(PackNotificationApp::pack_from((
id,
base,
Required(NotificationAppExt::extract(
ctx,
(&notification_data.notification, access_token?),
)),
))),
})
}
pub async fn get_notifications(
&self,
ctx: &PackingContext,
id: &str,
notification_types: &[NotificationType],
unread_only: bool,
pagination: &mut Pagination,
) -> PackResult<Vec<PackNotification>> {
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,
&notification_types
.iter()
.map(|v| NotificationTypeEnum::extract(ctx, v))
.collect::<Vec<_>>(),
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, &note_model, &user_model, &emoji_model))
.collect::<Vec<_>>();
let processed = futures::stream::iter(fut_iter)
.buffered(10)
.err_into::<PackError>()
.try_collect::<Vec<_>>()
.await?;
Ok(processed)
}
}