From 81d0c678d8f3b2c30bf030520f8b0268ae329971 Mon Sep 17 00:00:00 2001 From: Natty Date: Thu, 9 Nov 2023 21:35:55 +0100 Subject: [PATCH] Full user packing in the backend and Magnetar-filled preview cards in the frontend --- ext_calckey_model/src/lib.rs | 35 ++ ext_calckey_model/src/note_model.rs | 86 ++++- .../{MkMention.vue => MagMention.vue} | 19 +- .../{MkUserPreview.vue => MagUserPreview.vue} | 84 +++-- .../client/src/components/MkMoved.vue | 4 +- .../client/src/components/MkNoteSub.vue | 4 +- .../frontend/client/src/components/mfm.ts | 6 +- .../src/components/page/page.counter.vue | 1 - .../client/src/directives/user-preview.ts | 6 +- .../client/src/scripts-mag/mag-util.ts | 2 +- .../src/types/endpoints/GetUserByAcct.ts | 4 +- magnetar_sdk/src/endpoints/user.rs | 2 +- magnetar_sdk/src/types/emoji.rs | 17 + magnetar_sdk/src/types/user.rs | 8 +- src/api_v1/mod.rs | 2 - src/api_v1/note.rs | 2 +- src/api_v1/user.rs | 56 +-- src/model/data/user.rs | 25 +- src/model/mod.rs | 7 + src/model/processing/mod.rs | 2 + src/model/processing/note.rs | 126 +++++-- src/model/processing/user.rs | 343 +++++++++++++++++- 22 files changed, 655 insertions(+), 186 deletions(-) rename fe_calckey/frontend/client/src/components/{MkMention.vue => MagMention.vue} (80%) rename fe_calckey/frontend/client/src/components/{MkUserPreview.vue => MagUserPreview.vue} (84%) diff --git a/ext_calckey_model/src/lib.rs b/ext_calckey_model/src/lib.rs index da54175..dd000ad 100644 --- a/ext_calckey_model/src/lib.rs +++ b/ext_calckey_model/src/lib.rs @@ -114,6 +114,26 @@ impl CalckeyModel { .await?) } + pub async fn get_user_profile_by_id( + &self, + id: &str, + ) -> Result, CalckeyDbError> { + Ok(user_profile::Entity::find() + .filter(user_profile::Column::UserId.eq(id)) + .one(&self.0) + .await?) + } + + pub async fn get_user_security_keys_by_id( + &self, + id: &str, + ) -> Result, CalckeyDbError> { + Ok(user_security_key::Entity::find() + .filter(user_security_key::Column::UserId.eq(id)) + .all(&self.0) + .await?) + } + pub async fn get_many_users_by_id( &self, id: &[String], @@ -160,6 +180,21 @@ impl CalckeyModel { .await?) } + pub async fn get_follow_request_status( + &self, + from: &str, + to: &str, + ) -> Result, CalckeyDbError> { + Ok(follow_request::Entity::find() + .filter( + follow_request::Column::FollowerId + .eq(from) + .and(follow_request::Column::FolloweeId.eq(to)), + ) + .one(&self.0) + .await?) + } + pub async fn get_block_status( &self, from: &str, diff --git a/ext_calckey_model/src/note_model.rs b/ext_calckey_model/src/note_model.rs index 8dfa9e4..ba0dcee 100644 --- a/ext_calckey_model/src/note_model.rs +++ b/ext_calckey_model/src/note_model.rs @@ -1,12 +1,14 @@ use lazy_static::lazy_static; -use sea_orm::sea_query::{Alias, Asterisk, Expr, IntoIden, Query, SelectExpr, SimpleExpr}; +use sea_orm::sea_query::{ + Alias, Asterisk, Expr, IntoCondition, IntoIden, Query, SelectExpr, SimpleExpr, +}; use sea_orm::{ ColumnTrait, DbErr, EntityName, EntityTrait, FromQueryResult, Iden, Iterable, JoinType, - QueryFilter, QueryResult, QuerySelect, QueryTrait, RelationTrait, Select, + QueryFilter, QueryOrder, QueryResult, QuerySelect, QueryTrait, RelationTrait, Select, }; use serde::{Deserialize, Serialize}; -use ck::{drive_file, note, note_reaction, user}; +use ck::{drive_file, note, note_reaction, user, user_note_pining}; use magnetar_sdk::types::RangeFilter; use crate::{AliasSourceExt, CalckeyDbError, CalckeyModel}; @@ -53,6 +55,7 @@ pub struct NoteData { pub renote: Option>, } +const PIN: &str = "pin."; const INTERACTION_REACTION: &str = "interaction.reaction."; const INTERACTION_RENOTE: &str = "interaction.renote."; const USER: &str = "user."; @@ -154,6 +157,7 @@ pub struct NoteResolveOptions { pub with_reply_target: bool, pub with_renote_target: bool, pub with_interactions_from: Option, // User ID + pub only_pins_from: Option, // User ID } trait SelectColumnsExt { @@ -262,6 +266,7 @@ impl SelectColumnsExt for Select { } lazy_static! { + static ref ALIAS_PIN: Alias = Alias::new(PIN); static ref ALIAS_INTERACTION_RENOTE: Alias = Alias::new(INTERACTION_RENOTE); static ref ALIAS_INTERACTION_REACTION: Alias = Alias::new(INTERACTION_REACTION); static ref ALIAS_USER: Alias = Alias::new(USER); @@ -281,6 +286,24 @@ lazy_static! { static ref ALIAS_RENOTE_USER_BANNER: Alias = Alias::new(RENOTE_USER_BANNER); } +fn range_into_expr(filter: &RangeFilter) -> SimpleExpr { + match filter { + RangeFilter::TimeStart(start) => note::Column::CreatedAt.gte(*start), + RangeFilter::TimeRange(range) => { + note::Column::CreatedAt.between(*range.start(), *range.end()) + } + RangeFilter::TimeEnd(end) => note::Column::CreatedAt.lt(*end), + } +} + +fn ids_into_expr(ids: &Vec) -> SimpleExpr { + if ids.len() == 1 { + note::Column::Id.eq(&ids[0]) + } else { + note::Column::Id.is_in(ids) + } +} + impl NoteResolver { pub fn new(db: CalckeyModel) -> Self { NoteResolver { db } @@ -292,21 +315,8 @@ impl NoteResolver { ) -> Result, CalckeyDbError> { let select = self.resolve(options); let visibility_filter = options.visibility_filter.with_note_and_user_tables(None); - let time_filter = options.time_range.as_ref().map(|f| match f { - RangeFilter::TimeStart(start) => note::Column::CreatedAt.gte(*start), - RangeFilter::TimeRange(range) => { - note::Column::CreatedAt.between(*range.start(), *range.end()) - } - RangeFilter::TimeEnd(end) => note::Column::CreatedAt.lt(*end), - }); - - let id_filter = options.ids.as_ref().map(|ids| { - if ids.len() == 1 { - note::Column::Id.eq(&ids[0]) - } else { - note::Column::Id.is_in(ids) - } - }); + let time_filter = options.time_range.as_ref().map(range_into_expr); + let id_filter = options.ids.as_ref().map(ids_into_expr); let notes = select .filter(visibility_filter) @@ -319,9 +329,49 @@ impl NoteResolver { Ok(notes) } + pub async fn get_many( + &self, + options: &NoteResolveOptions, + ) -> Result, CalckeyDbError> { + let select = self.resolve(options); + let visibility_filter = options.visibility_filter.with_note_and_user_tables(None); + let time_filter = options.time_range.as_ref().map(range_into_expr); + let id_filter = options.ids.as_ref().map(ids_into_expr); + + let notes = select + .filter(visibility_filter) + .apply_if(id_filter, Select::::filter) + .apply_if(time_filter, Select::::filter) + .apply_if(options.only_pins_from.as_deref(), |s, _| { + s.order_by_desc(Expr::col(( + ALIAS_PIN.clone(), + user_note_pining::Column::CreatedAt, + ))) + }) + .into_model::() + .all(self.db.inner()) + .await?; + + Ok(notes) + } + pub fn resolve(&self, options: &NoteResolveOptions) -> Select { let mut select = note::Entity::find().add_aliased_columns(Some(USER), user::Entity); + if let Some(pins_user) = options.only_pins_from.clone() { + select = select.join_as( + JoinType::InnerJoin, + note::Relation::UserNotePining + .def() + .on_condition(move |left, _right| { + Expr::col((left, note::Column::UserId)) + .eq(&pins_user) + .into_condition() + }), + ALIAS_PIN.clone(), + ) + } + if let Some(user_id) = &options.with_interactions_from { select = select .add_sub_select_reaction(None, INTERACTION_REACTION, user_id) diff --git a/fe_calckey/frontend/client/src/components/MkMention.vue b/fe_calckey/frontend/client/src/components/MagMention.vue similarity index 80% rename from fe_calckey/frontend/client/src/components/MkMention.vue rename to fe_calckey/frontend/client/src/components/MagMention.vue index 1b3c9bc..209e308 100644 --- a/fe_calckey/frontend/client/src/components/MkMention.vue +++ b/fe_calckey/frontend/client/src/components/MagMention.vue @@ -1,7 +1,6 @@ diff --git a/fe_calckey/frontend/client/src/components/MkMoved.vue b/fe_calckey/frontend/client/src/components/MkMoved.vue index ad22cd7..553cf8f 100644 --- a/fe_calckey/frontend/client/src/components/MkMoved.vue +++ b/fe_calckey/frontend/client/src/components/MkMoved.vue @@ -5,12 +5,12 @@ style="margin-right: 8px" /> {{ i18n.ts.accountMoved }} - +