From cf04146d2ff797316742c7c759d386aa1906b5ab Mon Sep 17 00:00:00 2001 From: Natty Date: Thu, 2 Nov 2023 00:22:04 +0100 Subject: [PATCH] Poll fetching --- ext_calckey_model/src/lib.rs | 1 + ext_calckey_model/src/poll.rs | 33 ++++++++++++++++++++++++++ magnetar_sdk/src/types/note.rs | 4 ++-- src/model/data/id.rs | 6 +++++ src/model/data/mod.rs | 1 + src/model/data/poll.rs | 27 ++++++++++++++++++++++ src/model/mod.rs | 8 ++----- src/model/processing/note.rs | 42 +++++++++++++++++++++++++++++----- 8 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 ext_calckey_model/src/poll.rs create mode 100644 src/model/data/poll.rs diff --git a/ext_calckey_model/src/lib.rs b/ext_calckey_model/src/lib.rs index 69d6b13..1afba36 100644 --- a/ext_calckey_model/src/lib.rs +++ b/ext_calckey_model/src/lib.rs @@ -1,5 +1,6 @@ pub mod emoji; pub mod note_model; +pub mod poll; pub use ck; use ck::*; diff --git a/ext_calckey_model/src/poll.rs b/ext_calckey_model/src/poll.rs new file mode 100644 index 0000000..42ef17a --- /dev/null +++ b/ext_calckey_model/src/poll.rs @@ -0,0 +1,33 @@ +use crate::{CalckeyDbError, CalckeyModel}; +use ck::{poll, poll_vote}; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; + +pub struct PollResolver(CalckeyModel); + +impl PollResolver { + pub fn new(db: CalckeyModel) -> Self { + PollResolver(db) + } + + pub async fn get_poll(&self, note_id: &str) -> Result, CalckeyDbError> { + Ok(poll::Entity::find() + .filter(poll::Column::NoteId.eq(note_id)) + .one(self.0.inner()) + .await?) + } + + pub async fn get_poll_votes_by( + &self, + note_id: &str, + user_id: &str, + ) -> Result, CalckeyDbError> { + Ok(poll_vote::Entity::find() + .filter( + poll_vote::Column::NoteId + .eq(note_id) + .and(poll_vote::Column::UserId.eq(user_id)), + ) + .all(self.0.inner()) + .await?) + } +} diff --git a/magnetar_sdk/src/types/note.rs b/magnetar_sdk/src/types/note.rs index 0efbf62..da569f3 100644 --- a/magnetar_sdk/src/types/note.rs +++ b/magnetar_sdk/src/types/note.rs @@ -33,13 +33,13 @@ pub enum NoteVisibility { pub struct PollChoice { pub title: String, pub votes_count: u64, - pub voted: bool, + pub voted: Option, } #[derive(Clone, Debug, Deserialize, Serialize, TS)] #[ts(export)] pub struct PollBase { - pub expires_at: DateTime, + pub expires_at: Option>, pub expired: bool, pub multiple_choice: bool, pub options: Vec, diff --git a/src/model/data/id.rs b/src/model/data/id.rs index fd1f0fa..7d983e2 100644 --- a/src/model/data/id.rs +++ b/src/model/data/id.rs @@ -17,3 +17,9 @@ macro_rules! impl_id { impl_id!(ck::emoji::Model); impl_id!(ck::user::Model); impl_id!(ck::note::Model); + +impl BaseId for ck::poll::Model { + fn get_id(&self) -> &str { + &self.note_id + } +} diff --git a/src/model/data/mod.rs b/src/model/data/mod.rs index aeb50c5..0b1c42c 100644 --- a/src/model/data/mod.rs +++ b/src/model/data/mod.rs @@ -2,4 +2,5 @@ pub mod drive; pub mod emoji; pub mod id; pub mod note; +pub mod poll; pub mod user; diff --git a/src/model/data/poll.rs b/src/model/data/poll.rs new file mode 100644 index 0000000..934a3b3 --- /dev/null +++ b/src/model/data/poll.rs @@ -0,0 +1,27 @@ +use crate::model::{PackType, PackingContext}; +use chrono::{DateTime, Utc}; +use magnetar_calckey_model::ck; +use magnetar_sdk::types::note::{PollBase, PollChoice}; + +pub type PollPackInput<'a> = (&'a ck::poll::Model, Option<&'a [ck::poll_vote::Model]>); + +impl PackType> for PollBase { + fn extract(_context: &PackingContext, (poll, votes): PollPackInput<'_>) -> Self { + PollBase { + expires_at: poll.expires_at.map(DateTime::::from), + expired: poll.expires_at.is_some_and(|e| e < Utc::now()), + multiple_choice: poll.multiple, + options: poll + .choices + .iter() + .zip(poll.votes.iter()) + .enumerate() + .map(|(i, (name, count))| PollChoice { + title: name.to_string(), + votes_count: *count as u64, + voted: votes.map(|v| v.iter().any(|v| v.choice as usize == i)), + }) + .collect(), + } + } +} diff --git a/src/model/mod.rs b/src/model/mod.rs index c83ae28..ca43dd6 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -85,12 +85,8 @@ impl PackingContext { return Ok(false); }; - self.is_relationship_between( - Either::Right(self_user.into()), - Either::Right(user.into()), - rel_type, - ) - .await + self.is_relationship_between(Either::Right(self_user), Either::Right(user), rel_type) + .await } async fn is_relationship_between( diff --git a/src/model/processing/note.rs b/src/model/processing/note.rs index 20eaa3f..270d269 100644 --- a/src/model/processing/note.rs +++ b/src/model/processing/note.rs @@ -13,6 +13,7 @@ use magnetar_calckey_model::emoji::EmojiTag; use magnetar_calckey_model::note_model::{ NoteData, NoteResolveOptions, NoteVisibilityFilterFactory, }; +use magnetar_calckey_model::poll::PollResolver; use magnetar_calckey_model::sea_orm::prelude::Expr; use magnetar_calckey_model::sea_orm::sea_query::{Alias, IntoIden, PgFunc, Query, SimpleExpr}; use magnetar_calckey_model::sea_orm::{ActiveEnum, ColumnTrait, IntoSimpleExpr}; @@ -23,7 +24,7 @@ use magnetar_sdk::types::drive::PackDriveFileBase; use magnetar_sdk::types::emoji::EmojiContext; use magnetar_sdk::types::note::{ NoteAttachmentExt, NoteBase, NoteDetailExt, NoteSelfContextExt, PackNoteBase, - PackNoteMaybeAttachments, PackNoteMaybeFull, Reaction, ReactionPair, + PackNoteMaybeAttachments, PackNoteMaybeFull, PackPollBase, PollBase, Reaction, ReactionPair, }; use magnetar_sdk::types::{Id, MmXml}; use magnetar_sdk::{mmm, Packed, Required}; @@ -368,15 +369,44 @@ impl NoteModel { Ok(None) } + async fn extract_poll( + &self, + ctx: &PackingContext, + as_user: Option<&ck::user::Model>, + note: &ck::note::Model, + ) -> PackResult> { + if !note.has_poll { + return Ok(None); + } + + let poll_resolver = PollResolver::new(ctx.service.db.clone()); + + let Some(poll) = poll_resolver.get_poll(¬e.id).await? else { + return Ok(None); + }; + + let votes = match as_user { + Some(u) => Some(poll_resolver.get_poll_votes_by(¬e.id, &u.id).await?), + None => None, + }; + + Ok(Some(PackPollBase::pack_from(( + Required(Id::from(poll.get_id())), + Required(PollBase::extract(ctx, (&poll, votes.as_deref()))), + )))) + } + async fn pack_single_attachments( &self, ctx: &PackingContext, drive_model: &DriveModel, + as_user: Option<&ck::user::Model>, note_data: &NoteData, ) -> PackResult { - let (PackNoteBase { id, note }, attachments_pack) = try_join!( + let (PackNoteBase { id, note }, attachments_pack, poll_pack) = try_join!( self.extract_base(ctx, note_data), self.extract_attachments(ctx, drive_model, ¬e_data.note), + self.extract_poll(ctx, as_user, ¬e_data.note) )?; Ok(PackNoteMaybeAttachments::pack_from(( @@ -388,7 +418,7 @@ impl NoteModel { ctx, NoteAttachmentSource { attachments: &attachments, - poll: None, // TODO + poll: poll_pack.as_ref(), }, ) }), @@ -428,7 +458,7 @@ impl NoteModel { let reply_target = async { match note.reply.as_ref() { Some(r) if self.with_context => self - .pack_single_attachments(ctx, &drive_model, r) + .pack_single_attachments(ctx, &drive_model, as_user, r) .await .map(Some), _ => Ok(None), @@ -438,7 +468,7 @@ impl NoteModel { let renote_target = async { match note.renote.as_ref() { Some(r) if self.with_context => self - .pack_single_attachments(ctx, &drive_model, r) + .pack_single_attachments(ctx, &drive_model, as_user, r) .await .map(Some), _ => Ok(None), @@ -455,7 +485,7 @@ impl NoteModel { reply_target_pack, renote_target_pack, ) = try_join!( - self.pack_single_attachments(ctx, &drive_model, ¬e), + self.pack_single_attachments(ctx, &drive_model, as_user, ¬e), reply_target, renote_target )?;