Add note processing for parents of renote posts and introduced better timeline filtering
ci/woodpecker/push/ociImagePush Pipeline is pending
Details
ci/woodpecker/push/ociImagePush Pipeline is pending
Details
This commit is contained in:
parent
152c4e6fc6
commit
bbc4f84ceb
|
@ -9,7 +9,7 @@ use sea_orm::{
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ck::{drive_file, note, note_reaction, user, user_note_pining};
|
||||
use magnetar_sdk::types::RangeFilter;
|
||||
use magnetar_sdk::types::{EndFilter, RangeFilter, SpanFilter, StartFilter};
|
||||
|
||||
use crate::{AliasSourceExt, CalckeyDbError, CalckeyModel};
|
||||
|
||||
|
@ -73,6 +73,12 @@ const RENOTE_INTERACTION_RENOTE: &str = "renote.interaction.renote.";
|
|||
const RENOTE_USER: &str = "renote.user.";
|
||||
const RENOTE_USER_AVATAR: &str = "renote.user.avatar.";
|
||||
const RENOTE_USER_BANNER: &str = "renote.user.banner.";
|
||||
const RENOTE_REPLY: &str = "renote.reply.";
|
||||
const RENOTE_REPLY_INTERACTION_REACTION: &str = "renote.reply.interaction.reaction.";
|
||||
const RENOTE_REPLY_INTERACTION_RENOTE: &str = "renote.reply.interaction.renote.";
|
||||
const RENOTE_REPLY_USER: &str = "renote.reply.user.";
|
||||
const RENOTE_REPLY_USER_AVATAR: &str = "renote.reply.user.avatar.";
|
||||
const RENOTE_REPLY_USER_BANNER: &str = "renote.reply.user.banner.";
|
||||
|
||||
impl FromQueryResult for NoteData {
|
||||
fn from_query_result(res: &QueryResult, _pre: &str) -> Result<Self, DbErr> {
|
||||
|
@ -99,6 +105,35 @@ impl FromQueryResult for NoteData {
|
|||
})
|
||||
.transpose()?;
|
||||
|
||||
let renote_reply = note::Model::from_query_result_optional(res, RENOTE_REPLY)?
|
||||
.map::<Result<_, DbErr>, _>(|r| {
|
||||
Ok(Box::new(NoteData {
|
||||
note: r,
|
||||
interaction_user_renote:
|
||||
sub_interaction_renote::Model::from_query_result_optional(
|
||||
res,
|
||||
RENOTE_REPLY_INTERACTION_RENOTE,
|
||||
)?,
|
||||
interaction_user_reaction:
|
||||
sub_interaction_reaction::Model::from_query_result_optional(
|
||||
res,
|
||||
RENOTE_REPLY_INTERACTION_REACTION,
|
||||
)?,
|
||||
user: user::Model::from_query_result(res, RENOTE_REPLY_USER)?,
|
||||
avatar: drive_file::Model::from_query_result_optional(
|
||||
res,
|
||||
RENOTE_REPLY_USER_AVATAR,
|
||||
)?,
|
||||
banner: drive_file::Model::from_query_result_optional(
|
||||
res,
|
||||
RENOTE_REPLY_USER_BANNER,
|
||||
)?,
|
||||
reply: None,
|
||||
renote: None,
|
||||
}))
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let renote = note::Model::from_query_result_optional(res, RENOTE)?
|
||||
.map::<Result<_, DbErr>, _>(|r| {
|
||||
Ok(Box::new(NoteData {
|
||||
|
@ -152,7 +187,8 @@ pub trait NoteVisibilityFilterFactory: Send + Sync {
|
|||
pub struct NoteResolveOptions {
|
||||
pub ids: Option<Vec<String>>,
|
||||
pub visibility_filter: Box<dyn NoteVisibilityFilterFactory>,
|
||||
pub time_range: Option<RangeFilter>,
|
||||
pub time_range: Option<SpanFilter>,
|
||||
pub limit: Option<u64>,
|
||||
pub with_user: bool,
|
||||
pub with_reply_target: bool,
|
||||
pub with_renote_target: bool,
|
||||
|
@ -284,15 +320,60 @@ lazy_static! {
|
|||
static ref ALIAS_RENOTE_USER: Alias = Alias::new(RENOTE_USER);
|
||||
static ref ALIAS_RENOTE_USER_AVATAR: Alias = Alias::new(RENOTE_USER_AVATAR);
|
||||
static ref ALIAS_RENOTE_USER_BANNER: Alias = Alias::new(RENOTE_USER_BANNER);
|
||||
static ref ALIAS_RENOTE_REPLY: Alias = Alias::new(RENOTE_REPLY);
|
||||
static ref ALIAS_RENOTE_REPLY_INTERACTION_RENOTE: Alias =
|
||||
Alias::new(RENOTE_REPLY_INTERACTION_RENOTE);
|
||||
static ref ALIAS_RENOTE_REPLY_INTERACTION_REACTION: Alias =
|
||||
Alias::new(RENOTE_REPLY_INTERACTION_REACTION);
|
||||
static ref ALIAS_RENOTE_REPLY_USER: Alias = Alias::new(RENOTE_REPLY_USER);
|
||||
static ref ALIAS_RENOTE_REPLY_USER_AVATAR: Alias = Alias::new(RENOTE_REPLY_USER_AVATAR);
|
||||
static ref ALIAS_RENOTE_REPLY_USER_BANNER: Alias = Alias::new(RENOTE_REPLY_USER_BANNER);
|
||||
}
|
||||
|
||||
fn range_into_expr(filter: &RangeFilter) -> SimpleExpr {
|
||||
fn range_into_expr(filter: &SpanFilter) -> Option<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),
|
||||
SpanFilter::Range(RangeFilter {
|
||||
time_start,
|
||||
time_end,
|
||||
id_start,
|
||||
id_end,
|
||||
}) => Some(
|
||||
Expr::tuple([
|
||||
Expr::col(note::Column::CreatedAt).into(),
|
||||
Expr::col(note::Column::Id).into(),
|
||||
])
|
||||
.between(
|
||||
Expr::tuple([
|
||||
Expr::value(time_start.clone()),
|
||||
Expr::value(id_start.clone()),
|
||||
]),
|
||||
Expr::tuple([Expr::value(time_end.clone()), Expr::value(id_end.clone())]),
|
||||
),
|
||||
),
|
||||
SpanFilter::Start(StartFilter {
|
||||
id_start,
|
||||
time_start,
|
||||
}) => Some(
|
||||
Expr::tuple([
|
||||
Expr::col(note::Column::CreatedAt).into(),
|
||||
Expr::col(note::Column::Id).into(),
|
||||
])
|
||||
.gt(Expr::tuple([
|
||||
Expr::value(time_start.clone()),
|
||||
Expr::value(id_start.clone()),
|
||||
])),
|
||||
),
|
||||
SpanFilter::End(EndFilter { id_end, time_end }) => Some(
|
||||
Expr::tuple([
|
||||
Expr::col(note::Column::CreatedAt).into(),
|
||||
Expr::col(note::Column::Id).into(),
|
||||
])
|
||||
.lt(Expr::tuple([
|
||||
Expr::value(time_end.clone()),
|
||||
Expr::value(id_end.clone()),
|
||||
])),
|
||||
),
|
||||
SpanFilter::None(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,7 +396,7 @@ impl NoteResolver {
|
|||
) -> Result<Option<NoteData>, 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 time_filter = options.time_range.as_ref().and_then(range_into_expr);
|
||||
let id_filter = options.ids.as_ref().map(ids_into_expr);
|
||||
|
||||
let notes = select
|
||||
|
@ -335,7 +416,7 @@ impl NoteResolver {
|
|||
) -> Result<Vec<NoteData>, 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 time_filter = options.time_range.as_ref().and_then(range_into_expr);
|
||||
let id_filter = options.ids.as_ref().map(ids_into_expr);
|
||||
|
||||
let notes = select
|
||||
|
@ -348,6 +429,7 @@ impl NoteResolver {
|
|||
user_note_pining::Column::CreatedAt,
|
||||
)))
|
||||
})
|
||||
.apply_if(options.limit, Select::<note::Entity>::limit)
|
||||
.into_model::<NoteData>()
|
||||
.all(self.db.inner())
|
||||
.await?;
|
||||
|
@ -418,6 +500,32 @@ impl NoteResolver {
|
|||
.add_aliased_columns(Some(RENOTE_USER_AVATAR), drive_file::Entity)
|
||||
.add_aliased_columns(Some(RENOTE_USER_BANNER), drive_file::Entity)
|
||||
}
|
||||
|
||||
if options.with_reply_target {
|
||||
select = select
|
||||
.add_aliased_columns(Some(RENOTE_REPLY), note::Entity)
|
||||
.add_aliased_columns(Some(RENOTE_REPLY_USER), user::Entity);
|
||||
|
||||
if let Some(user_id) = &options.with_interactions_from {
|
||||
select = select
|
||||
.add_sub_select_reaction(
|
||||
Some(RENOTE_REPLY),
|
||||
RENOTE_REPLY_INTERACTION_REACTION,
|
||||
user_id,
|
||||
)
|
||||
.add_sub_select_renote(
|
||||
Some(RENOTE_REPLY),
|
||||
RENOTE_REPLY_INTERACTION_RENOTE,
|
||||
user_id,
|
||||
);
|
||||
}
|
||||
|
||||
if options.with_user {
|
||||
select = select
|
||||
.add_aliased_columns(Some(RENOTE_REPLY_USER_AVATAR), drive_file::Entity)
|
||||
.add_aliased_columns(Some(RENOTE_REPLY_USER_BANNER), drive_file::Entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if options.with_reply_target {
|
||||
|
@ -446,6 +554,20 @@ impl NoteResolver {
|
|||
note::Relation::User.with_alias(ALIAS_RENOTE.clone()),
|
||||
ALIAS_RENOTE_USER.clone(),
|
||||
);
|
||||
|
||||
if options.with_reply_target {
|
||||
select = select
|
||||
.join_as(
|
||||
JoinType::LeftJoin,
|
||||
note::Relation::SelfRef2.with_alias(ALIAS_RENOTE.clone()),
|
||||
ALIAS_RENOTE_REPLY.clone(),
|
||||
)
|
||||
.join_as(
|
||||
JoinType::LeftJoin,
|
||||
note::Relation::User.with_alias(ALIAS_RENOTE_REPLY.clone()),
|
||||
ALIAS_RENOTE_REPLY_USER.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
select = select.join_as(
|
||||
|
@ -493,6 +615,20 @@ impl NoteResolver {
|
|||
user::Relation::DriveFile1.with_alias(ALIAS_RENOTE_USER.clone()),
|
||||
ALIAS_RENOTE_USER_BANNER.clone(),
|
||||
);
|
||||
|
||||
if options.with_reply_target {
|
||||
select = select
|
||||
.join_as(
|
||||
JoinType::LeftJoin,
|
||||
user::Relation::DriveFile2.with_alias(ALIAS_RENOTE_REPLY_USER.clone()),
|
||||
ALIAS_RENOTE_REPLY_USER_AVATAR.clone(),
|
||||
)
|
||||
.join_as(
|
||||
JoinType::LeftJoin,
|
||||
user::Relation::DriveFile1.with_alias(ALIAS_RENOTE_REPLY_USER.clone()),
|
||||
ALIAS_RENOTE_REPLY_USER_BANNER.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,3 +42,8 @@ export { DriveFolderParentExt } from "./types/DriveFolderParentExt";
|
|||
export { ImageMeta } from "./types/ImageMeta";
|
||||
export { InstanceTicker } from "./types/InstanceTicker";
|
||||
export { MovedTo } from "./types/MovedTo";
|
||||
export { RangeFilter } from "./types/RangeFilter";
|
||||
export { EndFilter } from "./types/EndFilter";
|
||||
export { StartFilter } from "./types/StartFilter";
|
||||
export { NoFilter } from "./types/NoFilter";
|
||||
export { TimelineType } from "./types/TimelineType";
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface EndFilter { time_end: string, id_end: string, }
|
|
@ -1,4 +1,5 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { NoteListFilter } from "./NoteListFilter";
|
||||
import type { SpanFilter } from "./SpanFilter";
|
||||
|
||||
export interface GetTimelineReq { limit?: bigint, filter?: NoteListFilter, }
|
||||
export interface GetTimelineReq { limit?: bigint, filter?: NoteListFilter, range?: SpanFilter, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type NoFilter = Record<string, never>;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface RangeFilter { time_start: string, time_end: string, id_start: string, id_end: string, }
|
|
@ -0,0 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { EndFilter } from "./EndFilter";
|
||||
import type { NoFilter } from "./NoFilter";
|
||||
import type { RangeFilter } from "./RangeFilter";
|
||||
import type { StartFilter } from "./StartFilter";
|
||||
|
||||
export type SpanFilter = RangeFilter | StartFilter | EndFilter | NoFilter;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface StartFilter { time_start: string, id_start: string, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type TimelineType = "home" | "timeline" | "recommended" | "hybrid" | "global";
|
|
@ -3,8 +3,8 @@ import type { GetTimelineReq } from "../GetTimelineReq";
|
|||
import type { PackNoteMaybeFull } from "../packed/PackNoteMaybeFull";
|
||||
|
||||
export const GetTimeline = {
|
||||
endpoint: "/timeline",
|
||||
pathParams: [] as [],
|
||||
endpoint: "/timeline/:timeline_type",
|
||||
pathParams: ["timeline_type"] as ["timeline_type"],
|
||||
method: "GET" as "GET" | "POST" | "PUT" | "DELETE" | "PATCH",
|
||||
request: undefined as unknown as GetTimelineReq,
|
||||
response: undefined as unknown as Array<PackNoteMaybeFull>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::endpoints::Endpoint;
|
||||
use crate::types::note::{NoteListFilter, PackNoteMaybeFull};
|
||||
use crate::types::SpanFilter;
|
||||
use crate::util_types::U64Range;
|
||||
use http::Method;
|
||||
use magnetar_sdk_macros::Endpoint;
|
||||
|
@ -14,6 +15,8 @@ pub struct GetTimelineReq {
|
|||
pub limit: Option<U64Range<1, 100>>,
|
||||
#[ts(optional)]
|
||||
pub filter: Option<NoteListFilter>,
|
||||
#[ts(optional)]
|
||||
pub range: Option<SpanFilter>,
|
||||
}
|
||||
|
||||
pub fn default_timeline_limit<const MIN: u64, const MAX: u64>() -> U64Range<MIN, MAX> {
|
||||
|
@ -22,7 +25,7 @@ pub fn default_timeline_limit<const MIN: u64, const MAX: u64>() -> U64Range<MIN,
|
|||
|
||||
#[derive(Endpoint)]
|
||||
#[endpoint(
|
||||
endpoint = "/timeline",
|
||||
endpoint = "/timeline/:timeline_type",
|
||||
method = Method::GET,
|
||||
request = "GetTimelineReq",
|
||||
response = "Vec<PackNoteMaybeFull>",
|
||||
|
|
|
@ -11,10 +11,40 @@ use std::ops::RangeInclusive;
|
|||
use ts_rs::TS;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
pub enum RangeFilter {
|
||||
TimeRange(RangeInclusive<DateTime<Utc>>),
|
||||
TimeStart(DateTime<Utc>),
|
||||
TimeEnd(DateTime<Utc>),
|
||||
#[ts(export)]
|
||||
pub struct RangeFilter {
|
||||
pub time_start: DateTime<Utc>,
|
||||
pub time_end: DateTime<Utc>,
|
||||
pub id_start: DateTime<Utc>,
|
||||
pub id_end: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
pub struct StartFilter {
|
||||
pub time_start: DateTime<Utc>,
|
||||
pub id_start: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
pub struct EndFilter {
|
||||
pub time_end: DateTime<Utc>,
|
||||
pub id_end: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
pub struct NoFilter {}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(untagged)]
|
||||
pub enum SpanFilter {
|
||||
Range(RangeFilter),
|
||||
Start(StartFilter),
|
||||
End(EndFilter),
|
||||
None(NoFilter),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
|
|
|
@ -97,8 +97,8 @@ pack!(
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
pub struct NoteDetailExt {
|
||||
pub parent_note: Option<Box<PackNoteMaybeAttachments>>,
|
||||
pub renoted_note: Option<Box<PackNoteMaybeAttachments>>,
|
||||
pub parent_note: Option<Box<PackNoteMaybeFull>>,
|
||||
pub renoted_note: Option<Box<PackNoteMaybeFull>>,
|
||||
}
|
||||
|
||||
pack!(
|
||||
|
|
|
@ -2,10 +2,12 @@ use serde::{Deserialize, Serialize};
|
|||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum TimelineType {
|
||||
Home,
|
||||
Timeline,
|
||||
Recommended,
|
||||
Hybrid,
|
||||
Global,
|
||||
Local,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use magnetar_calckey_model::ck;
|
||||
use magnetar_calckey_model::note_model::sub_interaction_renote;
|
||||
use magnetar_sdk::types::note::{
|
||||
NoteDetailExt, NoteSelfContextExt, PackNoteMaybeAttachments, PackPollBase, ReactionPair,
|
||||
NoteDetailExt, NoteSelfContextExt, PackNoteMaybeAttachments, PackNoteMaybeFull, PackPollBase,
|
||||
ReactionPair,
|
||||
};
|
||||
use magnetar_sdk::types::user::PackUserBase;
|
||||
use magnetar_sdk::types::{
|
||||
|
@ -83,8 +84,8 @@ impl PackType<&sub_interaction_renote::Model> for NoteSelfContextExt {
|
|||
}
|
||||
|
||||
pub struct NoteDetailSource<'a> {
|
||||
pub parent_note: Option<&'a PackNoteMaybeAttachments>,
|
||||
pub renoted_note: Option<&'a PackNoteMaybeAttachments>,
|
||||
pub parent_note: Option<&'a PackNoteMaybeFull>,
|
||||
pub renoted_note: Option<&'a PackNoteMaybeFull>,
|
||||
}
|
||||
|
||||
impl<'a> PackType<NoteDetailSource<'a>> for NoteDetailExt {
|
||||
|
|
|
@ -6,8 +6,8 @@ use crate::model::processing::{get_mm_token_emoji, PackError, PackResult};
|
|||
use crate::model::{PackType, PackingContext, UserRelationship};
|
||||
use compact_str::CompactString;
|
||||
use either::Either;
|
||||
use futures_util::future::try_join_all;
|
||||
use futures_util::{StreamExt, TryFutureExt, TryStreamExt};
|
||||
use futures_util::future::{try_join_all, BoxFuture};
|
||||
use futures_util::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};
|
||||
use magnetar_calckey_model::ck::sea_orm_active_enums::NoteVisibilityEnum;
|
||||
use magnetar_calckey_model::emoji::EmojiTag;
|
||||
use magnetar_calckey_model::note_model::{
|
||||
|
@ -429,65 +429,62 @@ impl NoteModel {
|
|||
)))
|
||||
}
|
||||
|
||||
async fn pack_full_single(
|
||||
&self,
|
||||
ctx: &PackingContext,
|
||||
note: NoteData,
|
||||
) -> PackResult<PackNoteMaybeFull> {
|
||||
let drive_model = DriveModel;
|
||||
fn pack_full_single<'a>(
|
||||
&'a self,
|
||||
ctx: &'a PackingContext,
|
||||
note: &'a NoteData,
|
||||
) -> BoxFuture<'a, PackResult<PackNoteMaybeFull>> {
|
||||
async move {
|
||||
let drive_model = DriveModel;
|
||||
|
||||
let reply_target = async {
|
||||
match note.reply.as_ref() {
|
||||
Some(r) if self.with_context => self
|
||||
.pack_single_attachments(ctx, &drive_model, r)
|
||||
.await
|
||||
.map(Some),
|
||||
_ => Ok(None),
|
||||
}
|
||||
};
|
||||
let reply_target = async {
|
||||
match note.reply.as_ref() {
|
||||
Some(r) if self.with_context => self.pack_full_single(ctx, r).await.map(Some),
|
||||
_ => Ok(None),
|
||||
}
|
||||
};
|
||||
|
||||
let renote_target = async {
|
||||
match note.renote.as_ref() {
|
||||
Some(r) if self.with_context => self
|
||||
.pack_single_attachments(ctx, &drive_model, r)
|
||||
.await
|
||||
.map(Some),
|
||||
_ => Ok(None),
|
||||
}
|
||||
};
|
||||
let renote_target = async {
|
||||
match note.renote.as_ref() {
|
||||
Some(r) if self.with_context => self.pack_full_single(ctx, r).await.map(Some),
|
||||
_ => Ok(None),
|
||||
}
|
||||
};
|
||||
|
||||
let (
|
||||
PackNoteMaybeAttachments {
|
||||
let (
|
||||
PackNoteMaybeAttachments {
|
||||
id,
|
||||
note,
|
||||
user_context,
|
||||
attachment,
|
||||
},
|
||||
reply_target_pack,
|
||||
renote_target_pack,
|
||||
) = try_join!(
|
||||
self.pack_single_attachments(ctx, &drive_model, ¬e),
|
||||
reply_target,
|
||||
renote_target
|
||||
)?;
|
||||
|
||||
let detail = self.with_context.then(|| {
|
||||
NoteDetailExt::extract(
|
||||
ctx,
|
||||
NoteDetailSource {
|
||||
parent_note: reply_target_pack.as_ref(),
|
||||
renoted_note: renote_target_pack.as_ref(),
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
Ok(PackNoteMaybeFull::pack_from((
|
||||
id,
|
||||
note,
|
||||
user_context,
|
||||
attachment,
|
||||
},
|
||||
reply_target_pack,
|
||||
renote_target_pack,
|
||||
) = try_join!(
|
||||
self.pack_single_attachments(ctx, &drive_model, ¬e),
|
||||
reply_target,
|
||||
renote_target
|
||||
)?;
|
||||
|
||||
let detail = self.with_context.then(|| {
|
||||
NoteDetailExt::extract(
|
||||
ctx,
|
||||
NoteDetailSource {
|
||||
parent_note: reply_target_pack.as_ref(),
|
||||
renoted_note: renote_target_pack.as_ref(),
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
Ok(PackNoteMaybeFull::pack_from((
|
||||
id,
|
||||
note,
|
||||
user_context,
|
||||
attachment,
|
||||
Optional(detail),
|
||||
)))
|
||||
Optional(detail),
|
||||
)))
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
pub async fn fetch_single(
|
||||
|
@ -503,6 +500,7 @@ impl NoteModel {
|
|||
ctx.self_user.as_deref().map(ck::user::Model::get_id),
|
||||
)),
|
||||
time_range: None,
|
||||
limit: None,
|
||||
with_user: self.with_context,
|
||||
with_reply_target: self.with_context,
|
||||
with_renote_target: self.with_context,
|
||||
|
@ -522,7 +520,7 @@ impl NoteModel {
|
|||
return Ok(None);
|
||||
};
|
||||
|
||||
Ok(Some(self.pack_full_single(ctx, note).await?))
|
||||
Ok(Some(self.pack_full_single(ctx, ¬e).await?))
|
||||
}
|
||||
|
||||
pub async fn fetch_pins(
|
||||
|
@ -538,6 +536,7 @@ impl NoteModel {
|
|||
ctx.self_user.as_deref().map(ck::user::Model::get_id),
|
||||
)),
|
||||
time_range: None,
|
||||
limit: None,
|
||||
with_user: self.with_context,
|
||||
with_reply_target: self.with_context,
|
||||
with_renote_target: self.with_context,
|
||||
|
@ -555,8 +554,9 @@ impl NoteModel {
|
|||
.await?;
|
||||
|
||||
let fut_iter = notes
|
||||
.into_iter()
|
||||
.map(|note| self.pack_full_single(ctx, note));
|
||||
.iter()
|
||||
.map(|note| self.pack_full_single(ctx, note))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let processed = futures::stream::iter(fut_iter)
|
||||
.buffered(10)
|
||||
|
|
Loading…
Reference in New Issue